buu signal wp详解

张开发
2026/4/17 20:52:28 15 分钟阅读

分享文章

buu signal wp详解
这一道题目也确实写了好几个小时也看了很多师傅们的博客但感觉都不是很详细。在这里我给出我的详细思路供大家参考希望对各位师傅们入门vm逆向有帮助如有不足希望各位师傅们包容一、查壳使用exiinfo PE进行查壳发现是32位Gcc编译无壳拖入ida32进行反汇编二、主函数分析进入后按F5反汇编后如下三个函数1、_main函数点进入后发现是初始化2、qmemcpy将unk_403040处的数据写到v4处写入0x1C8长度的数据单击byte_403040后点击edit-array-OK后即可出现如下形式仅便于观察不改也可以我们可以先导出数据以便后续操作左上角菜单 edit—export_data后如下此后点击Export后即可导出可在同一目录查看txt文件.3、vm_operad函数也就是我们主要分析的函数了很明显v4,也就是上面的byte_403040是我们的操作码接下来我们进入vm_operad函数进行查看三、vm_operad函数分析代码如下int __cdecl vm_operad(int *a1, int a2) { int result; // eax char Str[200]; // [esp13h] [ebp-E5h] BYREF char v4; // [espDBh] [ebp-1Dh] int v5; // [espDCh] [ebp-1Ch] int v6; // [espE0h] [ebp-18h] int v7; // [espE4h] [ebp-14h] int v8; // [espE8h] [ebp-10h] int v9; // [espECh] [ebp-Ch] v9 0; v8 0; v7 0; v6 0; v5 0; while ( 1 ) { result v9; if ( v9 a2 ) return result; switch ( a1[v9] ) { case 1: Str[v6 100] v4; v9; v6; v8; break; case 2: v4 a1[v9 1] Str[v8]; v9 2; break; case 3: v4 Str[v8] - LOBYTE(a1[v9 1]); v9 2; break; case 4: v4 a1[v9 1] ^ Str[v8]; v9 2; break; case 5: v4 a1[v9 1] * Str[v8]; v9 2; break; case 6: v9; break; case 7: if ( Str[v7 100] ! a1[v9 1] ) { printf(what a shame...); exit(0); } v7; v9 2; break; case 8: Str[v5] v4; v9; v5; break; case 10: read(Str); v9; break; case 11: v4 Str[v8] - 1; v9; break; case 12: v4 Str[v8] 1; v9; break; default: continue; } } }在这里需要注意几个点1这里的a1是int类型的指针从函数名参数类型可得但是我们的byte_403040是单字节所以我们需要把它4个字节一个单位小端转变为int类型;2我们的操作数就是case 1~12中的中间变量v4是char类型的所以逆向的时候需要再操作后进行 0xff 进行取低位如果我们逆向中使用的中间变量是int类型的反而会出现负数因为我就卡到这里了。1、(1)接着我们分析函数先看case 10点进去后发现是获取输入存放在str数组中,长度为15:size_t __cdecl read(char *Str) { size_t result; // eax printf(string:); scanf(%s, Str); result strlen(Str); if ( result ! 15 ) { puts(WRONG!\n); exit(0); } return result; }(2)case 1 时是将v4写入我们的缓存也就是Str[v6 100]的地方此数组的前100作为临时运行区此后的作为缓存即输出区3case 2345后·对v4赋值str[v8]和操作数的运算a1[v91]我们此次遇见2345的是指令即a1[v9]那么紧接的就是我们的操作数至于为什么是因为我们的v92了)后面v92就是等于PC计数器加2PC计数器指向下一个执行的指令所以那么中间隔过去的就是我们的操作数即a1[v91])4case 6,11,12同上类似不过这里的操作数是1所以我们的v9也就是PC计数器只增加15case 7是 Str[v7 100] 与 a1[v9 1] 的比较如果相等通过所以这里的a1[v9 1]就是我们的密文cipher了我们可以待会再处理完机器码后再去得到6case 8是改变我们的输入str[ v8 ]为中间值很明显这是一个重要的改变待会我会通过正向分析来解密如何处理2、好了分析那么久逻辑我们还是不知道不过在这之前我们先把机器码写脚本跑出来vm_operad[10, 0, 0, 0, 4, 0, 0, 0, 16, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 32, 0, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 11, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, 33, 0, 0, 0, 1, 0, 0, 0, 11, 0, 0, 0, 8, 0, 0, 0, 11, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 81, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 36, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 8, 0, 0, 0, 11, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 37, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 54, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 65, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 32, 0, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 37, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 65, 0, 0, 0, 8, 0, 0, 0, 12, 0, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0, 34, 0, 0, 0, 7, 0, 0, 0, 63, 0, 0, 0, 7, 0, 0, 0, 52, 0, 0, 0, 7, 0, 0, 0, 50, 0, 0, 0, 7, 0, 0, 0, 114, 0, 0, 0, 7, 0, 0, 0, 51, 0, 0, 0, 7, 0, 0, 0, 24, 0, 0, 0, 7, 0, 0, 0, 167, 255, 255, 255, 7, 0, 0, 0, 49, 0, 0, 0, 7, 0, 0, 0, 241, 255, 255, 255, 7, 0, 0, 0, 40, 0, 0, 0, 7, 0, 0, 0, 132, 255, 255, 255, 7, 0, 0, 0, 193, 255, 255, 255, 7, 0, 0, 0, 30, 0, 0, 0, 7, 0, 0, 0, 122, 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, 0, 0, 0, 0] vm_t[] for i in range(0,len(vm_operad),4): b bytes(vm_operad[i:i 4]) vm_t.append(int.from_bytes(b, byteorderlittle, signedTrue)) #小端4字节转化为int #print(vm_t)跑出来结果如下[10, 4, 16, 8, 3, 5, 1,4, 32, 8, 5, 3, 1, 3, 2, 8, 11, 1, 12, 8, 4, 4, 1, 5, 3, 8, 3, 33, 1, 11, 8, 11, 1, 4, 9, 8, 3, 32, 1, 2, 81, 8, 4, 36, 1, 12, 8, 11, 1, 5, 2, 8, 2, 37, 1, 2, 54, 8, 4, 65, 1, 2, 32, 8, 5, 1, 1, 5, 3, 8, 2, 37, 1, 4, 9, 8, 3, 32, 1, 2, 65, 8, 12, 1, 7, 34, 7, 63, 7, 52, 7, 50, 7, 114, 7, 51, 7, 24, 7, -89, 7, 49, 7, -15, 7, 40, 7, -124, 7, -63, 7, 30, 7, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]在此处如果有人看到另一位师傅的博客说1是16个7是15个不要疑惑因为其中一个1是操作数而不是指令本身所以指令1还是15个分析后可以发现10输入后紧接着是一个8一个1这是个重要的地方接着发现7都是在后面每个7后面一个操作数这就是cipher;我们跑出cipher的值vm[] for each in vm_t: if each ! 0: vm.append(each) cipherlist() for i in range(len(vm)): if vm[i]7: cipher.append(vm[i1])结果cipher[34, 63, 52, 50, 114, 51, 24, -89, 49, -15, 40, -124, -63, 30, 122]3.接着我们分析运行逻辑就那我们操作码的取一部分分析以为都是81的循环上面的红色部分————case 4 v4 a1[v9 1] ^ Str[v8];v9 2;改变v[ 4 ]操作数就是 16str[ v8 ]是我们的第一个输入————-——case 8. Str[v5] v4;v9;v5;把我们的第一个输入改成v4然后v5加1打算改变下一个输入;——————case 3,5就是对v4的赋值自行分析——————case 1Str[v6 100] v4;v9;v6;v8;把v4写入缓存等待最后和cipher[ 0 ]比较到这里我们的逻辑很清晰了每一个8 1是一个循环我们逆向的思路也很清晰对操作码逆序后遇到1后他的下一个运算操作就是234561112cipher【 i ]就是v4,我们进行逆运算得到str[v8] 存到temp。但是这个【v8】不是我们的输入还记得case 8 吗改变了我们的str【8】所以我们继续运行遇到8后他的下一个运算操作我们逆运算后得到str[8]就是我们的输入接着就是循环了。这里我的方法是设定两个bool变量sign2和sign标志遇到1和8代码如下k是cipher的下标code_index是我们逆序后的指令下标在下一部分给出flag[] temp0 sign2False signFalse k0 cipher.reverse() for i in code_index: if ilen(vm): match vm[i]: case 1: sign2 True case 2: if sign2: temp(cipher[k]-vm[i1]) 0xff sign2False k 1 if sign: flag.append((temp-vm[i1]) 0xff) signFalse case 3: if sign2: temp (cipher[k] vm[i 1] 0xff) 0xff sign2 False k 1 if sign: flag.append((tempvm[i 1] 0xff) 0xff) signFalse case 4: if sign2: temp (cipher[k] ^ vm[i 1]) 0xff sign2 False k 1 if sign: flag.append((temp^vm[i 1]) 0xff) signFalse case 5: if sign2: temp(cipher[k]//vm[i 1]) 0xff sign2 False k 1 if sign: flag.append((temp//vm[i 1]) 0xff) signFalse case 8: signTrue case 11: if sign2: temp(cipher[k]1) 0xff sign2 False k 1 if sign: flag.append((temp1) 0xff) signFalse case 12: if sign2: temp(cipher[k]-1) 0xff sign2 False k 1 if sign: flag.append((temp-1) 0xff) signFalse case _: continue flag.reverse() f for each in flag: fchr(each) print(fflag{{{f}}})4、我们需要解决我们执行的指令都是哪些不然怎么逆序呢这里我给出的方法是正向执行一边记录下标即可代码如下code_indexlist() ################################## #在这里给出ip实际执行的指令 i0 while ilen(vm): match vm[i]: case 1: code_index.append(i) i1 case 2: code_index.append(i) i2 case 3: code_index.append(i) i2 case 4: code_index.append(i) i2 case 5: code_index.append(i) i2 case 6: code_index.append(i) i1 case 7: code_index.append(i) i2 case 8: code_index.append(i) i1 case 10: code_index.append(i) i1 case 11: code_index.append(i) i1 case 12: code_index.append(i) i1 case _: i1 continue code_index.reverse() ##################################四、结语最后给出完整代码vm_operad[10, 0, 0, 0, 4, 0, 0, 0, 16, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 32, 0, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 11, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, 33, 0, 0, 0, 1, 0, 0, 0, 11, 0, 0, 0, 8, 0, 0, 0, 11, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 81, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 36, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 8, 0, 0, 0, 11, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 37, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 54, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 65, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 32, 0, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 37, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 65, 0, 0, 0, 8, 0, 0, 0, 12, 0, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0, 34, 0, 0, 0, 7, 0, 0, 0, 63, 0, 0, 0, 7, 0, 0, 0, 52, 0, 0, 0, 7, 0, 0, 0, 50, 0, 0, 0, 7, 0, 0, 0, 114, 0, 0, 0, 7, 0, 0, 0, 51, 0, 0, 0, 7, 0, 0, 0, 24, 0, 0, 0, 7, 0, 0, 0, 167, 255, 255, 255, 7, 0, 0, 0, 49, 0, 0, 0, 7, 0, 0, 0, 241, 255, 255, 255, 7, 0, 0, 0, 40, 0, 0, 0, 7, 0, 0, 0, 132, 255, 255, 255, 7, 0, 0, 0, 193, 255, 255, 255, 7, 0, 0, 0, 30, 0, 0, 0, 7, 0, 0, 0, 122, 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, 0, 0, 0, 0] vm_t[] for i in range(0,len(vm_operad),4): b bytes(vm_operad[i:i 4]) vm_t.append(int.from_bytes(b, byteorderlittle, signedTrue)) #小端4字节转化为int #print(vm_t) ##################################### vm[] for each in vm_t: if each ! 0: vm.append(each) cipherlist() for i in range(len(vm)): if vm[i]7: cipher.append(vm[i1]) print(cipher) code_indexlist() ################################## #在这里给出ip实际执行的指令 i0 while ilen(vm): match vm[i]: case 1: code_index.append(i) i1 case 2: code_index.append(i) i2 case 3: code_index.append(i) i2 case 4: code_index.append(i) i2 case 5: code_index.append(i) i2 case 6: code_index.append(i) i1 case 7: code_index.append(i) i2 case 8: code_index.append(i) i1 case 10: code_index.append(i) i1 case 11: code_index.append(i) i1 case 12: code_index.append(i) i1 case _: i1 continue code_index.reverse() ################################## flag[] temp0 sign2False signFalse k0 cipher.reverse() for i in code_index: if ilen(vm): match vm[i]: case 1: sign2 True case 2: if sign2: temp(cipher[k]-vm[i1]) 0xff sign2False k 1 if sign: flag.append((temp-vm[i1]) 0xff) signFalse case 3: if sign2: temp (cipher[k] vm[i 1] 0xff) 0xff sign2 False k 1 if sign: flag.append((tempvm[i 1] 0xff) 0xff) signFalse case 4: if sign2: temp (cipher[k] ^ vm[i 1]) 0xff sign2 False k 1 if sign: flag.append((temp^vm[i 1]) 0xff) signFalse case 5: if sign2: temp(cipher[k]//vm[i 1]) 0xff sign2 False k 1 if sign: flag.append((temp//vm[i 1]) 0xff) signFalse case 8: signTrue case 11: if sign2: temp(cipher[k]1) 0xff sign2 False k 1 if sign: flag.append((temp1) 0xff) signFalse case 12: if sign2: temp(cipher[k]-1) 0xff sign2 False k 1 if sign: flag.append((temp-1) 0xff) signFalse case _: continue flag.reverse() f for each in flag: fchr(each) print(fflag{{{f}}})运行后结果 flag{757515121f3d478}我已经很详细地说了我的思路希望能帮到各位师傅谢谢

更多文章