Mas0n
to be reverse engineer🐧
翻车鱼

SCTF 2021

SCTF 2021

3个oi选手出了4题逆向。

——wmx

今年最后一场CTF了。

除去oi部分,还是比较友好的。oi基础着实烂到家,做完课设和考试一定恶补。

CplusExceptionEncrypt

基于异常处理的伪随机控制流,没有去除符号

调试得到执行序列

[0x6591, 0x10a9, 0x5208]
https://cdn.shi1011.cn/2021/12/6844f460add2a302d313dfac6fdce80b.png?imageMogr2/format/webp/interlace/0/quality/90|watermark/2/text/wqlNYXMwbg/font/bXN5aGJkLnR0Zg/fontsize/14/fill/IzMzMzMzMw/dissolve/80/gravity/southeast/dx/5/dy/5

catch捕获异常

https://cdn.shi1011.cn/2021/12/dadcb51c0fec0fa8c41a2fea6eae0298.png?imageMogr2/format/webp/interlace/0/quality/90|watermark/2/text/wqlNYXMwbg/font/bXN5aGJkLnR0Zg/fontsize/14/fill/IzMzMzMzMw/dissolve/80/gravity/southeast/dx/5/dy/5

通过patch修改跳转后可以得到部分伪代码,加速分析。

分析指令

if ( control1 == 3 )// 0x10a9
          {
            _cxa_begin_catch(v4);
            v9 = add(sum1, i);
            v10 = shr5(v1);
            v11 = add(v10, k3_0);
            v12 = add(v1, sum1);
            v13 = shl4(v1);
            v14 = add(v13, k2_0);
            v15 = xor(v14, v12);
            v16 = xor(v15, v11);
            v0 += xor(v16, v9);

            v17 = add(sum2, i);
            v18 = shr5(v3);
            v19 = add(v18, k3_0);
            v20 = add(v3, sum2);
            v21 = shl4(v3);
            v22 = add(v21, k2_0);
            v23 = xor(v22, v20);
            v24 = xor(v23, v19);
            v2 += xor(v24, v17);
            _cxa_end_catch();
          }
          else if ( control1 == 4 )// 0x5208
          {
            _cxa_begin_catch(v4);
            v25 = add(sum1, i);
            v26 = shr5(v0);
            v27 = add(v26, k1_0);
            v28 = add(v0, sum1);
            v29 = shl4(v0);
            v30 = add(v29, k0_0);
            v31 = xor(v30, v28);
            v32 = xor(v31, v27);
            v1 += xor(v32, v25);
            v33 = add(sum2, i);
            v34 = shr5(v2);
            v35 = add(v34, k1_0);
            v36 = add(v2, sum1);
            v37 = shl4(v2);
            v38 = add(v37, k0_0);
            v39 = xor(v38, v36);
            v40 = xor(v39, v35);
            v3 += xor(v40, v33);
            _cxa_end_catch();
          }
          else // control1 == 0x6591
          {
            sum1 = add(sum1, delta);
            sum2 = add(sum2, delta);
            _cxa_end_catch();
          }

魔改TEA

#include <stdio.h>
#include <stdint.h>
#include <Windows.h>



void encrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], v2=v[2], v3=v[3], sum=0, i;           /* set up */
    uint32_t delta=0x73637466;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i < 32; i++) {                       /* basic cycle start */
        sum += delta;


        v0 += (v1 + sum) ^ ((v1 << 4) + k2) ^ ((v1 >> 5) + k3) ^ (sum + i);
        v2 += (v3 + sum) ^ ((v3 << 4) + k2) ^ ((v3 >> 5) + k3) ^ (sum+i);

        v1 += ((v0<<4) + k0) ^ (v0 + sum) ^ ((v0>>5) + k1) ^ (sum+i);
        v3 += ((v2<<4) + k0) ^ (v2 + sum) ^ ((v2>>5) + k1) ^ (sum+i);
    }                                              /* end cycle */

    v0 = v0 ^ 0x73;
    v1 = v1 ^ 0x63;
    v2 = v2 ^ 0x74;
    v3 = v3 ^ 0x66;

    v[0]=v0; v[1]=v1, v[2]=v2; v[3]=v3;
}

void decrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], v2=v[2], v3=v[3], sum=0;           /* set up */
    uint32_t delta=0x73637466;                     /* a key schedule constant */
    for (int j = 0; j < 32; ++j) sum += delta;

    v0 = v0 ^ 0x73;
    v1 = v1 ^ 0x63;
    v2 = v2 ^ 0x74;
    v3 = v3 ^ 0x66;

    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (int i=31; i>-1; i--) {                         /* basic cycle start */
        v1 -= ((v0<<4) + k0) ^ (v0 + sum) ^ ((v0>>5) + k1) ^ (sum+i);
        v3 -= ((v2<<4) + k0) ^ (v2 + sum) ^ ((v2>>5) + k1) ^ (sum+i);

        v0 -= (v1 + sum) ^ ((v1 << 4) + k2) ^ ((v1 >> 5) + k3) ^ (sum+i);
        v2 -= (v3 + sum) ^ ((v3 << 4) + k2) ^ ((v3 >> 5) + k3) ^ (sum+i);

        sum -= delta;
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1, v[2]=v2; v[3]=v3;
}

int main() {
    uint32_t v[8] = {
            0xfb935ba5, 0x2c889844, 0x7e225322, 0xbbccf30a,0x4f937cdb, 0x16c5566a, 0xf755e04d, 0xf60a2799,
    };
    uint32_t k[4] = {
            0x636C6557, 0x5F656D6F, 0x735F6F74, 0x21667463
    };

    decrypt(v, k);
    decrypt(v+4, k);
    for (int i = 0; i < 8; ++i) {
        printf("0x%x, ", v[i]);
    }
    return 0;
}

而后是魔改AES,找到个符号几乎一样的

openluopworld/aes_128

修改点

// first AddRoundKey
    for ( i = 0; i < AES_BLOCK_SIZE; ++i ) {
        *(ciphertext+i) = *(plaintext+i) ^ *roundkeys++ ^ 0x66;
    }
···
// SubBytes
    for (i = 0; i < AES_BLOCK_SIZE; ++i) {
        *(tmp+i) = INV_SBOX[*(ciphertext+i)];
    }
···
// shift_rows
inv_shift_rows(tmp);

修改decrypt

void aes_decrypt_128(const uint8_t *roundkeys, const uint8_t *ciphertext, uint8_t *plaintext) {

    uint8_t tmp[16];
    uint8_t t, u, v;
    uint8_t i, j;

    roundkeys += 160;

    // first round
    for ( i = 0; i < AES_BLOCK_SIZE; ++i ) {
        *(plaintext+i) = *(ciphertext+i) ^ *(roundkeys+i);
    }
    roundkeys -= 16;
    inv_shift_rows(plaintext);
    for (i = 0; i < AES_BLOCK_SIZE; ++i) {
        *(plaintext+i) = INV_SBOX[*(plaintext+i)];
    }

    for (j = 1; j < AES_ROUNDS; ++j) {
        
        // Inverse AddRoundKey
        for ( i = 0; i < AES_BLOCK_SIZE; ++i ) {
            *(tmp+i) = *(plaintext+i) ^ *(roundkeys+i);
        }
        
        /*
         * Inverse MixColumns
         * [0e 0b 0d 09]   [s0  s4  s8  s12]
         * [09 0e 0b 0d] . [s1  s5  s9  s13]
         * [0d 09 0e 0b]   [s2  s6  s10 s14]
         * [0b 0d 09 0e]   [s3  s7  s11 s15]
         */
        for (i = 0; i < AES_BLOCK_SIZE; i+=4) {
            t = tmp[i] ^ tmp[i+1] ^ tmp[i+2] ^ tmp[i+3];
            plaintext[i]   = t ^ tmp[i]   ^ mul2(tmp[i]   ^ tmp[i+1]);
            plaintext[i+1] = t ^ tmp[i+1] ^ mul2(tmp[i+1] ^ tmp[i+2]);
            plaintext[i+2] = t ^ tmp[i+2] ^ mul2(tmp[i+2] ^ tmp[i+3]);
            plaintext[i+3] = t ^ tmp[i+3] ^ mul2(tmp[i+3] ^ tmp[i]);
            u = mul2(mul2(tmp[i]   ^ tmp[i+2]));
            v = mul2(mul2(tmp[i+1] ^ tmp[i+3]));
            t = mul2(u ^ v);
            plaintext[i]   ^= t ^ u;
            plaintext[i+1] ^= t ^ v;
            plaintext[i+2] ^= t ^ u;
            plaintext[i+3] ^= t ^ v;
        }
        
        // Inverse ShiftRows
        shift_rows(plaintext); // patch
        
        // Inverse SubBytes
        for (i = 0; i < AES_BLOCK_SIZE; ++i) {
            *(plaintext+i) = SBOX[*(plaintext+i)];  // patch
        }

        roundkeys -= 16;

    }

    // last AddRoundKey
    for ( i = 0; i < AES_BLOCK_SIZE; ++i ) {
        *(plaintext+i) ^= *(roundkeys+i) ^ 0x66; // patch
    }

}

godness dance

没看懂……

首先是check了一下输入的字符和个数

https://cdn.shi1011.cn/2021/12/f8f4ea7f38d12347426748cc57d05ba5.png?imageMogr2/format/webp/interlace/0/quality/90|watermark/2/text/wqlNYXMwbg/font/bXN5aGJkLnR0Zg/fontsize/14/fill/IzMzMzMzMw/dissolve/80/gravity/southeast/dx/5/dy/5
cout = [0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001]

hasv = []
for i in range(26):
    hasv += [chr(ord('a') + i)] * cout[i]
print(len(hasv), hasv)

黑盒测一下,带了几组数据

'abcdefghiijklmnopqrstuuvwxyz'
[0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 0x00000018, 0x00000019, 0x0000001A, 0x0000001B, 0x0000001C]

'defghiijklmnopqrstuuvwxyzabc'

[0x00000000, 0x0000001A, 0x0000001B, 0x0000001C, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 0x00000018, 0x00000019]

看起来是码表映射

cmpData = [0x00000000, 0x00000002, 0x0000001A, 0x00000011, 0x0000001C, 0x00000018, 0x0000000B, 0x00000015, 0x0000000A, 0x00000010, 0x00000014, 0x00000013, 0x00000012, 0x00000003, 0x00000008, 0x00000006, 0x0000000C, 0x00000009, 0x0000000E, 0x0000000D, 0x00000016, 0x00000004, 0x0000001B, 0x0000000F, 0x00000017, 0x00000001, 0x00000019, 0x00000007, 0x00000005]

maps = {}
for i in range(1, 29):
    maps[i] = hasv[i-1]
print(maps)

eneded = [0] * 29
for i in range(1, 29):
    eneded[cmpData[i]] = i

print(eneded)
ends = eneded[1:]
print("".join([maps[ends[i]] for i in range(28)]))

SycGame

逆完发现是个PPC,寄了,20*20推4个箱子,oi队友做了。就不挂分析过程了,挂一个生成地图的脚本凑字数

text = """
1451 1801 101 1301 1979 571 457 2393 2677 1031 2617 1987 757 1721 1811 2953 1861 2729 2437 2549 1409 113 2791 2029 2633 127 2437 2671 1931 1097 1787 487 137 1997 1951 2141 2729 2657 1571 2347 647 1129 1327 1597 101 331 1553 1993 101 1039 1487 1511 1201 1297 643 809 1481 167 503 509 1409 2459 1091 1567 1433 2878 1671 729 2 333 2060 607 2194 2129 2437 883 2593 997 47 2713 2243 1583 1259 541 476 -1 2429 391 1385 799 2311 769 81 198 2633 173 1848 421 1429 653 109 2207 1447 911 1291 366 -1 1211 1149 -1 2520 897 2139 2175 2598 516 221 215 2711 541 2927 1993 1483 1487 2671 400 671 -1 864 1754 1504 2090 1325 2303 1532 736 -3 1678 1648 109 1213 2801 1583 2141 158 -3 1024 2930 590 -3 560 1195 -3 142 2690 2607 128 120 2978 2269 2441 421 1063 2081 2382 1927 1026 234 2696 1461 2458 2122 249 2590 866 354 8 266 814 2711 953 1733 1109 71 1072 2720 597 1178 334 2044 2462 872 2631 1274 841 326 1835 2315 1762 50 1531 1933 2423 599 2094 1956 1526 117 185 1815 -2 2926 1209 1315 524 1857 2923 1687 1453 2726 2459 2689 331 941 1907 2579 387 1781 1454 2580 1359 136 596 1854 1814 2364 2056 2183 1977 1601 2699 2341 1171 1181 2980 2344 100 2829 2275 326 1391 2725 90 1676 2865 1205 128 1160 2409 193 563 1171 709 752 959 1680 2420 771 2378 2189 803 2216 224 1968 2599 24 1395 2771 2632 1811 839 373 1314 1713 24 1929 716 36 1398 1781 613 2839 914 2694 1877 1850 55 1190 643 2969 2131 821 1619 2685 732 886 1742 1862 2304 2832 599 1418 1344 425 2585 2983 114 199 659 587 59 1453 2437 1087 497 938 1918 2938 2997 1495 2276 2157 856 1378 445 1511 1549 2731 383 1693 263 1049 2909 1321 2851 2160 1941 63 1235 2241 339 1667 984 2138 1402 1217 823 421 2311 311 1721 269 1879 977 59 347 1851 278 1852 179 443 2622 788 1469 1901 1163 1657 653 571 379 271 643 2203 1367 271 2141 2803 1171 2777 2141 1619 1523 1617 577 2719 2677 1033 2531 1231 1237
""".split(" ")
primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107,
          109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
          233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
          367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491,
          499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
          643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787,
          797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
          947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063,
          1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201,
          1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319,
          1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471,
          1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597,
          1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723,
          1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873,
          1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011,
          2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141,
          2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293,
          2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417,
          2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591,
          2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711,
          2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843,
          2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999]

s2v = lambda a: str(abs(a)) if a < 0 else "-" if a not in primes else "X"

maps = [[s2v(int(text[20 * v2 + v1], 10)) for v1 in range(20)] for v2 in range(20)]
print(maps)

print("\n".join([" ".join(s) for s in maps]))

本文链接:https://blog.shi1011.cn/ctf/2029
本文采用 CC BY-NC-SA 4.0 Unported 协议进行许可

Mas0n

文章作者

发表回复

textsms
account_circle
email

翻车鱼

SCTF 2021
3个oi选手出了4题逆向。——wmx 今年最后一场CTF了。 除去oi部分,还是比较友好的。oi基础着实烂到家,做完课设和考试一定恶补。 CplusExceptionEncrypt 基于异常处理的伪随机…
扫描二维码继续阅读
2021-12-28