攻防世界 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}