RE jocker 因为sp有负数,ida无法反编译出main伪代码,可以用ALT+K在两个sp错误的地方修改sp为0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 .text :00401788 loc_401788: .text :00401788 lea eax, [ebp+var_96].text :0040178 E mov [esp+4 ], eax.text :00401792 mov dword ptr [esp], offset a40s .text :00401799 call _scanf.text :0040179 E lea eax, [ebp+var_96].text :004017 A4 mov [esp], eax .text :004017 A7 call _strlen.text :004017 AC mov [ebp+var_10], eax.text :004017 AF cmp [ebp+var_10], 18 h.text :004017 B3 jz short loc_4017CD.text :004017 B5 mov dword ptr [esp], offset aWrong .text :004017 BC call _puts.text :004017 C1 mov dword ptr [esp], 0 .text :004017 C8 call _exit
经过输入并判断长度后进入wrong函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 char *__cdecl wrong (char *a1) { char *result; signed int i; for ( i = 0 ; i <= 23 ; ++i ) { if ( i & 1 ) { result = &a1[i]; a1[i] -= i; } else { result = &a1[i]; a1[i] ^= i; } } return result; }
再进入omg函数对一堆byte进行比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 int __cdecl omg (char *a1) { int result; int v2[24 ]; int i; int v4; v4 = 1 ; qmemcpy(v2, &dword_4030C0, sizeof (v2)); for ( i = 0 ; i <= 23 ; ++i ) { if ( a1[i] != v2[i] ) v4 = 0 ; } if ( v4 == 1 ) result = puts ("hahahaha_do_you_find_me?" ); else result = puts ("wrong ~~ But seems a little program" ); return result; } .data:004030 C0 dword_4030C0 dd 66 h, 6B h, 63 h, 64 h, 7F h, 61 h, 67 h, 64 h, 3B h, 56 h, 6B h; 0 .data:004030 C0 ; DATA XREF: omg(char *)+16 ↑o .data:004030 C0 dd 61 h, 7B h, 26 h, 3B h, 50 h, 63 h, 5F h, 4 Dh, 5 Ah, 71 h, 0 Ch; 11 .data:004030 C0 dd 37 h, 66 h, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ; 22
这里得到一个假的flag
flag{fak3_alw35_sp_me!!}
当时高兴半天,感觉终于做出来一题,提交了半天发现后面还有函数
这里对encrypt 和 final函数进行解密,这里应该也是导致sp错误的原因,我们动态调试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 00401500 | 55 | push ebp | 00401501 | 89 E5 | mov ebp,esp | 00401503 | 57 | push edi | 00401504 | 56 | push esi | 00401505 | 53 | push ebx | 00401506 | 83 EC 7 C | sub esp,7C | 00401509 | C745 E0 01000000 | mov dword ptr ss:[ebp-20 ],1 | 00401510 | 8 D45 94 | lea eax,dword ptr ss:[ebp-6C] | 00401513 | BB 40304000 | mov ebx,jocker.403040 | 00401518 | BA 13000000 | mov edx,13 | 0040151 D | 89C7 | mov edi,eax | 0040151F | 89 DE | mov esi,ebx | 00401521 | 89D1 | mov ecx,edx | 00401523 | F3 :A5 | rep movsd | 00401525 | C745 E4 00000000 | mov dword ptr ss:[ebp-1 C],0 | 0040152C | EB 49 | jmp jocker.401577 | 0040152 E | 8B55 E4 | mov edx,dword ptr ss:[ebp-1 C] | 00401531 | 8 B45 08 | mov eax,dword ptr ss:[ebp+8] | 00401534 | 01D0 | add eax,edx | 00401536 | 0 FB610 | movzx edx,byte ptr ds:[eax] | 00401539 | 8B45 E4 | mov eax,dword ptr ss:[ebp-1 C] | 0040153C | 05 12404000 | add eax,jocker.404012 | 404012 :"hahahaha_do_you_find_me?" 00401541 | 0FB600 | movzx eax,byte ptr ds:[eax] | 00401544 | 31 D0 | xor eax,edx | 00401546 | 0FBED0 | movsx edx,al | 00401549 | 8 B45 E4 | mov eax,dword ptr ss:[ebp-1C] | 0040154 C | 8B4485 94 | mov eax,dword ptr ss:[ebp+eax*4 -6 C] | 00401550 | 39 C2 | cmp edx,eax | 00401552 | 74 1F | je jocker.401573 | 00401554 | C70424 00404000 | mov dword ptr ss:[esp],jocker.404000 | 404000 :"wrong ~" 0040155 B | E8 E0130000 | call <JMP.&puts> | 00401560 | C745 E0 00000000 | mov dword ptr ss:[ebp-20],0 | 00401567 | C70424 00000000 | mov dword ptr ss:[esp],0 | 0040156E | E8 AD130000 | call <JMP.&exit> | 00401573 | 8345 E4 01 | add dword ptr ss:[ebp-1 C],1 | 00401577 | 837 D E4 12 | cmp dword ptr ss:[ebp-1C],12 | 0040157 B | 7E B1 | jle jocker.40152 E | 0040157D | 837 D E0 01 | cmp dword ptr ss:[ebp-20],1 | 00401581 | 75 0C | jne jocker.40158 F | 00401583 | C70424 08404000 | mov dword ptr ss:[esp],jocker.404008 | 404008 :"come here" 0040158 A | E8 B1130000 | call <JMP.&puts> | 0040158F | 8 B45 E0 | mov eax,dword ptr ss:[ebp-20] | 00401592 | 83C4 7C | add esp,7 C | 00401595 | 5 B | pop ebx | 00401596 | 5E | pop esi | 00401597 | 5 F | pop edi | 00401598 | 5D | pop ebp | 00401599 | C3 | ret |
大概意思是输入的字符串前19个字符和hahahaha_do_you_find_me?进行异或然后和[0Eh, 0Dh, 9, 6, 13h, 5, 58h, 56h, 3Eh, 6, 0Ch, 3Ch,1Fh, 57h, 14h, 6Bh, 57h, 59h, 0Dh]比较
这里得到flag的前19位flag{d07abccf8a410c
最后这个函数当时怎么也没搞懂,应该是%tp&:和flag{进行比较,但是只比较了第一个(如果我没看错的话),’}’和’:’异或得到’G’,用这个去异或%tp&得到b37a},完整flag:flag{d07abccf8a410cb37a}
修改sp后main函数的伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 int __cdecl main (int argc, const char **argv, const char **envp) { char v4; char v5; DWORD flOldProtect; size_t v7; int i; __main(); puts ("please input you flag:" ); if ( VirtualProtect(encrypt, 0xC8 u, 4u , &flOldProtect) == 0 ) exit (1 ); scanf ("%40s" , &v4); v7 = strlen (&v4); if ( v7 != 24 ) { puts ("Wrong!" ); exit (0 ); } strcpy (&v5, &v4); wrong(&v4); omg(&v4); for ( i = 0 ; i <= 186 ; ++i ) *((_BYTE *)encrypt + i) ^= 0x41 u; if ( encrypt(&v5) != 0 ) finally(&v5); return 0 ; }
使用idapython脚本解密函数查看伪代码 1 2 3 4 5 6 en = 0x00401500 for i in range(0xbb ): addr = en + i byte = get_bytes(addr,1 ) byte = ord(byte)^0x41 patch_byte(addr,byte)
点击ida中的File->Script file…加载此脚本
然后在encrypto函数中使用U快捷键undefined掉原来所有数据,再使用P快捷键重新生成函数。
当然也可以用ida动态调试后查看伪代码
signal 方法一 看了一些师傅的wp说这个是伪虚拟机的逆向,让本菜鸡不禁想问 啥是虚拟机???
vm_operad函数里的switch我看着都头疼,比赛时就没有仔细看,其实从后往前分析逻辑还是比较简单的
当case 7时会进行判断,我们可以看到a1后半段的数据都是7后面再跟一个数,也就是v4经过一段加密然后和这个数比较,v4是在case 1时被赋值的,根据a1的一堆数据我们可以发现,我们的输入的每个字符会在1之前的几个case进行加密,从7后面的数据往前推就可以得到正确的输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 v3[0 ] = (0x22 +5 ) ^ 0x10 v3[1 ] = int(0x3f /3 ) ^ 0x20 v3[2 ] = 0x37 v3[3 ] = (0x32 ^4 ) -1 v3[4 ] = int((0x72 +0x21 )/3 ) v3[5 ] = 0x35 v3[6 ] = (0x18 +0x20 ) ^ 9 v3[7 ] = (0xa7 ^ 0x24 ) - 0x51 v3[8 ] = 0x31 v3[9 ] = int((0xf1 -0x25 )/2 ) v3[10 ] = (0x28 ^ 0x41 ) -0x36 v3[11 ] = 0x84 - 0x20 v3[12 ] = int((0xc1 -0x25 )/3 ) v3[13 ] = (0x1e +0x20 ) ^ 9 v3[14 ] = (0x7a -1 )-0x41
如何快速得到那一堆数据呢
先将其转换为array 再点击Edit->Export data 或者快捷键shift+e
方法二 符号执行 使用ida插件ponce https://github.com/illera88/Ponce
在scanf后下断点 将我们的输入符号化
在ida7.0下没有复现成功,所以换了ida6.8 需要注意的是 在hex dump中无法symbolize memory 但是可以在反汇编视图中进行这个操作
之后修改eip的值为0x4016FE防止程序退出,然后继续F9执行,重复上图的操作,得到剩下的值
使用angr
1 2 3 4 5 6 7 8 9 10 import angrp = angr.Project('./signal.exe' ) state = p.factory.entry_state() simgr = p.factory.simgr(state) simgr.explore(find=0x004017A5 ,avoid=0x004016E6 ) flag = simgr.found[0 ].posix.dumps(0 )[:15 ] print(flag)
pwn boom2 先开一下开了什么保护
1 2 3 4 5 Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
运行一下,提示输出code
丢到ida里面,代码都在main函数里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 printf ("MC execution system\nInput your code> " , 0L L, a2, a1);read(0 , buf, 0x120 uLL); v3 += 0x8000 ; v37 = v3; --v3; *v3 = 0x1E LL; --v3; *v3 = 0xD LL; v4 = v3; --v3; *v3 = v5 - 1 ; --v3; *v3 = v6 + 8 ; v36 = v3 - 1 ; *v36 = (signed __int64)v4; v39 = 0L L;
这段代码之后是一堆while(1),比赛的时候看到这一堆while(1),直接把ida关掉了。。
其实这就是一个庞大的switch结构,也就是vm pwn,从输入里读取opcode。
第一个while读取opcode并限制只能输入30个code,随后的每一个while都是一个handler
对于vm类的题,搞清楚变量的含义是十分重要的
我们大概可以把这个当作一个栈结构,v36当作栈顶,v37当作栈底
[bp-4]处保存了真实的栈地址,我们可以尝试利用它去做文章,通过main函数的返回地址__libc_start_main+240 leak libc,将one_gadget覆盖到main函数返回地址
大概写一下每个handler的功能,凑合看吧。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 v38 = v37+[buf+1] 1 v38 = [buf+1] 6 [v36-1] = v37----v37 = v36-1----sp = sp-[buf+1] 8 v37 = *v37---sp = v37+2-----[buf+1] = [v37+1]----- 9 v38 = (dword)v38 10 v38 = (byte)v38 11 **v36 = v38----v36+=8 12 **v36byte = v38----v36+=4 13 v36-=8---[v36] = v38 14 v38 |= [v36]---v36+=8 15 v38 ^= [v36]---v36+=8 16 v38 &= [v36]---v36+=8 17 v38 = [v36]==v38---v36+=8 18 v38 = [v36]!=v38---v36+=8 19 v38 = [v36] < v38---v36+=8 20 v38 = [v36] > v38---v36+=8 21 v38 = [v36] <= v38---v36+=8 22 v38 = [v36] >= v38---v36+=8 23 v38 = [v36] << v38---v36+=8 24 v38 = [v36] >> v38---v36+=8 25 v38 += [v36]---v36+=8 26 v38 = [v36] - v38---v36+=8 27 v38 *= [v36] ---v36+=8 28 v38 = [v36] // v38---v36+=8 29 v38 = [v36] % v38---v36+=8 30 quit
构造opcode:
16(v38=0)—1 0xe8—26(v38 = ret)—13—13—13—9—13—1 libc.sym[“__libc_start_main”] + 240—26—13—1 one_gadget—25(v38 = one_gadget)—11—30
reference https://www.cnblogs.com/jentleTao/p/
https://www.52pojie.cn/thread-1176826-1-1.html
https://blog.csdn.net/Breeze_CAT/article/details/106078982
Author:
Sivona
License:
Copyright (c) 2020 CC-BY-NC-4.0 LICENSE
Slogan:
Enforce justice on behalf of Heaven.