攻防世界 Replace Reverse二星题

解题过程中,虽然解出来了,但是磕磕绊绊犯了一些错误,记录一下


分析过程

PE查壳

有一个upx壳,最下面给了脱壳提示: upx.exe -d Replace.exe

脱壳结束,丢到IDA里,SHIF+F12,查看字符串,看到一个可疑的"Well Done!\n",点进去看看,发现就是主函数,反汇编主函数

  • Buffer很明显是输入,且长度要<=37
  • 判断函数==1就成功,显然这就是关键

sub_401090函数(改了一点名称)

复制代码
 1 // 最后要输出1
 2 // a1是输入,a2是输入的长度且为35
 3 int __fastcall sub_401090(int a1, int a2)
 4 {
 5   int v4; // edx
 6   char char_v5; // al
 7   int high4; // esi
 8   int low4; // edi
 9   char char_v8; // al
10   int v9; // eax
11   char char_v10; // cl
12   int v11; // eax
13   int v12; // ecx
14 
15   if ( a2 != 35 )
16     return -1;
17   v4 = 0;
18   while ( 1 )
19   {
20     char_v5 = *(_BYTE *)(v4 + a1);
21     high4 = (char_v5 >> 4) % 16;                // 先右移4位,相当于把原来8位的高4位数移动到低4位,新高4位全都置零------再%16,相当于取出变换后新8位的低4位------也就是取出原来数的高4位
22     low4 = ((16 * char_v5) >> 4) % 16;          // 先*16,相当于左移4位,原来的低4位移动到高4位,新的低4位置零------再右移4位,相当于移回来了,不过高4位都是0------再%16,取出低4位------原就是取出原来数的低4位
23     char_v8 = byte_402150[2 * v4];
24     if ( char_v8 < 48 || char_v8 > 57 )
25       v9 = char_v8 - 87;
26     else
27       v9 = char_v8 - 48;
28     char_v10 = byte_402151[2 * v4];
29     v11 = 16 * v9;                              // v9*16,相当于左移4位------------为后面组成新的8位做准备,作为新数的高4位
30     if ( char_v10 < 48 || char_v10 > 57 )
31       v12 = char_v10 - 87;
32     else
33       v12 = char_v10 - 48;                      // 作为新数的低4位
34     if ( (unsigned __int8)byte_4021A0[16 * high4 + low4] != ((v11 + v12) ^ 25) )// 16 * high4 + low4------操作的目的是组成新的8位数------其实就是原来输入的数
35                                                 // ((v11 + v12) ^ 25)------将上面获得v11与v12组成新的数,与25异或
36                                                 // 最后进行比较,相等才能return 1
37       break;
38     if ( ++v4 >= 35 )
39       return 1;
40   }
41   return -1;
42 }

总而言之,从byte_402150取一个元素作为char_v8,变换后获得组成高位的v11;从byte_402151取一个元素作为char_v10,变换后获得组成低位的v12,最后组成一个新的数去异或

【异或后得到的值】要与 【将输入作为下标,从byte_4021A0中取出的数】 相等

byte_402150与byte_402151

!!在这里我就犯了一个错误,我还以为是我IDA又出现问题了....byte_402150数组的32h后面没有 0 表示结束,所以要继续往下读取,一直到出现 0 ,即byte_402150是50+byte_402151

复制代码
unsigned char ida_chars[] =
{
   50,97,  52,  57, 102,  54,  57,  99,  51,  56,  51, 
   57,  53,  99, 100, 101,  57,  54, 100,  54, 100, 
  101,  57,  54, 100,  54, 102,  52, 101,  48,  50, 
   53,  52,  56,  52,  57,  53,  52, 100,  54,  49, 
   57,  53,  52,  52,  56, 100, 101, 102,  54, 101, 
   50, 100,  97, 100,  54,  55,  55,  56,  54, 101, 
   50,  49, 100,  53,  97, 100,  97, 101,  54,   0, 
    0,   0,   0,   0,   0,   0,   0,   0,   0
};
unsigned char ida_chars[] =
{
   97,  52,  57, 102,  54,  57,  99,  51,  56,  51, 
   57,  53,  99, 100, 101,  57,  54, 100,  54, 100, 
  101,  57,  54, 100,  54, 102,  52, 101,  48,  50, 
   53,  52,  56,  52,  57,  53,  52, 100,  54,  49, 
   57,  53,  52,  52,  56, 100, 101, 102,  54, 101, 
   50, 100,  97, 100,  54,  55,  55,  56,  54, 101, 
   50,  49, 100,  53,  97, 100,  97, 101,  54,   0, 
    0,   0,   0,   0,   0,   0,   0,   0,   0
};

byte_4021A0

选中全部,SHIF+E-->选中'C unsigned char array (decimal)',得到数组的值(上面也是这么得到的)

复制代码
unsigned char ida_chars[] =
{
   99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 
  103,  43, 254, 215, 171, 118, 202, 130, 201, 125, 
  250,  89,  71, 240, 173, 212, 162, 175, 156, 164, 
  114, 192, 183, 253, 147,  38,  54,  63, 247, 204, 
   52, 165, 229, 241, 113, 216,  49,  21,   4, 199, 
   35, 195,  24, 150,   5, 154,   7,  18, 128, 226, 
  235,  39, 178, 117,   9, 131,  44,  26,  27, 110, 
   90, 160,  82,  59, 214, 179,  41, 227,  47, 132, 
   83, 209,   0, 237,  32, 252, 177,  91, 106, 203, 
  190,  57,  74,  76,  88, 207, 208, 239, 170, 251, 
   67,  77,  51, 133,  69, 249,   2, 127,  80,  60, 
  159, 168,  81, 163,  64, 143, 146, 157,  56, 245, 
  188, 182, 218,  33,  16, 255, 243, 210, 205,  12, 
   19, 236,  95, 151,  68,  23, 196, 167, 126,  61, 
  100,  93,  25, 115,  96, 129,  79, 220,  34,  42, 
  144, 136,  70, 238, 184,  20, 222,  94,  11, 219, 
  224,  50,  58,  10,  73,   6,  36,  92, 194, 211, 
  172,  98, 145, 149, 228, 121, 231, 200,  55, 109, 
  141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 
  174,   8, 186, 120,  37,  46,  28, 166, 180, 198, 
  232, 221, 116,  31,  75, 189, 139, 138, 112,  62, 
  181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 
  134, 193,  29, 158, 225, 248, 152,  17, 105, 217, 
  142, 148, 155,  30, 135, 233, 206,  85,  40, 223, 
  140, 161, 137,  13, 191, 230,  66, 104,  65, 153, 
   45,  15, 176,  84, 187,  22
};

解题脚本(自己写的常规版本)

复制代码
 1 key1=[
 2     50,97,  52,  57, 102,  54,  57,  99,  51,  56,  51,
 3    57,  53,  99, 100, 101,  57,  54, 100,  54, 100,
 4   101,  57,  54, 100,  54, 102,  52, 101,  48,  50,
 5    53,  52,  56,  52,  57,  53,  52, 100,  54,  49,
 6    57,  53,  52,  52,  56, 100, 101, 102,  54, 101,
 7    50, 100,  97, 100,  54,  55,  55,  56,  54, 101,
 8    50,  49, 100,  53,  97, 100,  97, 101,  54
 9 ]
10 key2=[
11 97,  52,  57, 102,  54,  57,  99,  51,  56,  51,
12    57,  53,  99, 100, 101,  57,  54, 100,  54, 100,
13   101,  57,  54, 100,  54, 102,  52, 101,  48,  50,
14    53,  52,  56,  52,  57,  53,  52, 100,  54,  49,
15    57,  53,  52,  52,  56, 100, 101, 102,  54, 101,
16    50, 100,  97, 100,  54,  55,  55,  56,  54, 101,
17    50,  49, 100,  53,  97, 100,  97, 101,  54
18 ]
19 str=[
20 99, 124, 119, 123, 242, 107, 111, 197,  48,   1,
21   103,  43, 254, 215, 171, 118, 202, 130, 201, 125,
22   250,  89,  71, 240, 173, 212, 162, 175, 156, 164,
23   114, 192, 183, 253, 147,  38,  54,  63, 247, 204,
24    52, 165, 229, 241, 113, 216,  49,  21,   4, 199,
25    35, 195,  24, 150,   5, 154,   7,  18, 128, 226,
26   235,  39, 178, 117,   9, 131,  44,  26,  27, 110,
27    90, 160,  82,  59, 214, 179,  41, 227,  47, 132,
28    83, 209,   0, 237,  32, 252, 177,  91, 106, 203,
29   190,  57,  74,  76,  88, 207, 208, 239, 170, 251,
30    67,  77,  51, 133,  69, 249,   2, 127,  80,  60,
31   159, 168,  81, 163,  64, 143, 146, 157,  56, 245,
32   188, 182, 218,  33,  16, 255, 243, 210, 205,  12,
33    19, 236,  95, 151,  68,  23, 196, 167, 126,  61,
34   100,  93,  25, 115,  96, 129,  79, 220,  34,  42,
35   144, 136,  70, 238, 184,  20, 222,  94,  11, 219,
36   224,  50,  58,  10,  73,   6,  36,  92, 194, 211,
37   172,  98, 145, 149, 228, 121, 231, 200,  55, 109,
38   141, 213,  78, 169, 108,  86, 244, 234, 101, 122,
39   174,   8, 186, 120,  37,  46,  28, 166, 180, 198,
40   232, 221, 116,  31,  75, 189, 139, 138, 112,  62,
41   181, 102,  72,   3, 246,  14,  97,  53,  87, 185,
42   134, 193,  29, 158, 225, 248, 152,  17, 105, 217,
43   142, 148, 155,  30, 135, 233, 206,  85,  40, 223,
44   140, 161, 137,  13, 191, 230,  66, 104,  65, 153,
45    45,  15, 176,  84, 187,  22
46 ]
47 flag = ""
48 for i in range(35):
49     v8 = key1[2*i]
50     if v8 < 48 or v8 > 57:
51         v11 = 16 * (v8 - 87)
52     else:
53         v11 = 16 * (v8 - 48)
54     v10 = key2[2 * i]
55     if v10 < 48 or v10 > 57:
56         v12 = v10 - 87
57     else:
58         v12 = v10 - 48
59     v4=((v11 + v12) ^ 25)
60     flag += chr(str.index(v4))
61 
62 print(flag)

这里我犯了一个弱智错误

  • 最初写脚本的时候,想照着反汇编代码的思路去写,在后面写了一个 for j in range(len(str_data)): if str[i]==((v11 + v12) ^ 25):v4=((v11 + v12) ^ 25)
  • 结果导致运行没有报错,也没有结果
  • str[i]==((v11 + v12) ^ 25)这一行代码在每次循环中都会遍历str列表来查找是否存在相等的值,这会导致程序在执行时花费很长时间,因为它的时间复杂度是 O(n),其中 n 是str列表的长度。由于列表长度非常大,因此这种线性搜索的方法会非常慢,尤其是在内层循环中还嵌套了一个循环。这也解释了为什么代码没有输出也没有报错,因为它可能需要很长时间才能完成运行

解题脚本(枚举正向爆破)

这个版本是我参考别的大佬的wp时候学到的,记录一下

由于用了取余 % 运算,所以采用枚举正向爆破的方法,让flag中的每一个字符遍历常用的字符(ascii码表中32-126),带入加密算法,如果成功,就把这个flag存入

复制代码
list1=[50, 97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54]
list2=[97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54]
list3=[99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
v4=0
flag=""
for i in range(35):
    v8=list1[2*i]
    if v8 < 48 or v8 > 57:
        v9=v8 - 87
    else:
        v9=v8 - 48
    v10=list2[2*i]
    v11=16*v9
    if v10 <48 or v10 > 57:
        v12=v10-87
    else:
        v12=v10-48
    v4=((v11+v12)^25)
    for a in range(32,127):
        v5=a
        v6=(v5>>4)%16
        v7=((16*v5)>>4)%16
        if list3[16*v6+v7] == v4:
            flag+=chr(a)
print(flag)

flag

复制代码
flag{Th1s_1s_Simple_Rep1ac3_Enc0d3}