0x00 日常查壳
无壳64位
0x01 去平坦化
标准的平坦化控制流,装去平坦的可以参考我的之前写的一篇(晚点移植过来)
https://blog.csdn.net/weixin_50166464/article/details/121635877
1 2 3 4 5
| workon env1
python deflat.py -f /home/p0z/Desktop/hardCpp --addr 0x4007E0
|
0x02 去平坦后混淆
去平坦化后,可以发现很奇怪,可以发现这些判断是进不去的,具体随我思路看
这个x和y都是.bss段,意思就是未初始化的全局变量,那么就是为0,于是上面那图的很多判断都进不去
可以看下这篇文章讲data和bss段的详细介绍,https://zhuanlan.zhihu.com/p/28659560
每段都是类似这样的,jnz肯定会执行,于是我们的去混淆就是,每当碰到标识为ds:x的时候
- 然后把下面的jnz改成jmp (这样就是直接跳转不用判断)
- 再把jnz后的那条指令jmp nop掉(不nop掉也行)
还要注意一下这边的jnz指令是 0F 85
参考这篇文章:https://codeantenna.com/a/juuDUaGf62
(针对ida7.0之后的脚本)
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
| st = 0x4007E0 end = 0x401154
def patch_nop(start, end): for i in range(start, end): ida_bytes.patch_byte(i, 0x90)
def next_instr(addr): return addr + idc.get_item_size(addr)
addr = st while (addr < end): next = next_instr(addr) if "ds:x" in idc.GetDisasm(addr): while (True): addr = next next = next_instr(addr) if "jnz" in idc.GetDisasm(addr): dest = idc.get_operand_value(addr, 0) ida_bytes.patch_byte(addr, 0xE9) ida_bytes.patch_byte(addr + 5, 0x90) offset = dest - (addr + 5) ida_bytes.patch_dword(addr + 1, offset) print("patch bcf: 0x%x" % addr) addr = next patch_nop(next, next + 3) break else: addr = next
|
然后就成功去掉了!
0x03 正式分析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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| int __cdecl main(int argc, const char **argv, const char **envp) { char v3; char v4; char v5; char v6; char v8[8]; char v9[8]; char v10[8]; char v11[8]; char t0[8]; char v13[7]; char t1; int i; int v16; int v17; int v18; char s; char v20[23]; char v21[8]; char v22[8]; char v23[8]; char v24[4]; int v25; const char **v26; int v27; int v28; int v29; bool v30;
v28 = 0; v27 = argc; v26 = argv; v25 = time(0LL); puts("func(?)=\"01abfc750a0c942167651c40d088531d\"?"); s = getchar(); fgets(v20, 21, stdin); v18 = time(0LL); v17 = v18 - v25; v29 = v18 - v25; v16 = strlen(&s); v30 = v16 != 21; for ( i = 1; i < 21; ++i ) { do { t1 = v17 ^ *(&s + i); v13[0] = ret_a2((__int64)v23, t1); t0[0] = ret_a22((__int64)v21, *(&s + v17 + i - 1)); v3 = MOD(t0, 7); t1 = ADD((__int64)v13, v3); v11[0] = ret_a222((__int64)v24, t1); v10[0] = ret_a222((__int64)v24, *(&s + v17 + i - 1)); v4 = XOR(v10, 18); v9[0] = ret_a2222((__int64)v22, v4); v5 = MUL(v9, 3); v8[0] = ret_a2((__int64)v23, v5); v6 = ADD((__int64)v8, 2); t1 = XOR(v11, v6); } while ( enc[i - 1] != t1 ); } puts("You win"); return 0; }
|
还要关于我的ubuntu动调报错
这篇文章解决了我的缺少库问题
https://askubuntu.com/questions/1219027/problem-with-shared-library-libc-so-1-on-kubuntu-18-04
1
| sudo apt install libc++-dev
|
可以打个草稿跟一下就会比较容易
0x04 GetFlag!
关于flag[0]就是关于一开始的提示,要不然无法解出
EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from base64 import encode
ef = [0xF3, 0x2E, 0x18, 0x36, 0xE1, 0x4C, 0x22, 0xD1, 0xF9, 0x8C, 0x40, 0x76, 0xF4, 0x0E, 0x00, 0x05, 0xA3, 0x90, 0x0E, 0xA5] f = [0 for i in range(21)] f[0] = ord('#')
for i in range(1, 21): f[i] = ((ef[i - 1] ^ ((f[i - 1] ^ 18) * 3 + 2) & 0xFF ) - (f[i - 1] % 7)) print(chr(f[i]) , end="")
|
GetFlag!(总算脱离了1分题)