赞
踩
程序极小,也不能运行也不能用ida,还有个提示 echo $?
用010打开,发现0x20后是一段代码。用pwntools的反编译功能直接反编译
- a = open('tiny','rb').read()[0x20:]
- print(a)
-
- from pwn import *
- context.arch='i386'
-
- print(disasm(a))
-
- '''
- 0: 5b pop ebx
- 1: 5b pop ebx
- 2: 5b pop ebx
- 3: 31 c9 xor ecx, ecx
- 5: 51 push ecx
- 6: 41 inc ecx
- 7: 41 inc ecx
- 8: eb 04 jmp 0xe
- a: 20 00 ...
- c: 01 00 ...
- e: 58 pop eax
- f: 68 07 52 f4 8a push 0x8af45207
- 14: 68 63 9a 3f 09 push 0x93f9a63
- 19: 8b 7c 8b fc mov edi, DWORD PTR [ebx+ecx*4-0x4] ;传入的flag 后半个,前半个,循环右移3位后与栈顶两个异或后为0
- 1d: c1 cf 03 ror edi, 0x3 ;第一次为 0x5d99429 和 0x93f9a63
- 20: 68 29 94 d9 05 push 0x5d99429 ;第二次为 0x5d99429 和 0x8af45207
- 25: 5a pop edx
- 26: 5e pop esi
- 27: 31 fe xor esi, edi
- 29: 31 f2 xor edx, esi
- 2b: 09 d0 or eax, edx
- 2d: e2 ea loop 0x19
- 2f: 31 db xor ebx, ebx
- 31: 85 c0 test eax, eax
- 33: 0f 95 c3 setne bl
- 36: 31 c0 xor eax, eax
- 38: 40 inc eax
- 39: cd 80 int 0x80
- '''

应了这个比赛的名字:36D里边到底是啥,全靠猜。
开头有ELF但是是32还是64呢?反编译后全是eXX,而且从栈里取数据,应该是32位。
题目的hint是echo $? 在unix系统里表示返回值这里0x36开始将eax清0再加1然后返回,所以结果一定是1,这个提示也就没用了。所以第一个猜想:0x36,0x38没用应该删掉
然后回到开头先是弹了3个到ebx,然后会用到从[ebx+ecx*4-4]里读数据,这个ebx到底是啥,这是第二个猜想:指向输入的flag的指针。 一般逆向都是输入flag然后验证
有了这两个猜想就可以看程序了
先是压两个数到栈,然后进行循环ecx是循环计数器先设置为2,每次loop会减1到0退出
从ebx+X读入一个数字然后循环右移3位 存在edi
再压入一个数然后弹出两个到edx,esi
把edx,esi,edi作异或运算,然后or到eax,eax是返回值,前面猜的是确定flag是否正确的返回值,那么根据unix类的规则,返回值0表示正确,由于eax是或运算,所以它一开始是0,然后两次循环都应该是0,也就是说输入的值循环右移后存在edi的值与栈顶两个值的异或结果相同。
再来看栈的情况,第一次是0x8af45207,0x93f9a63,0x5d99429(循环里后压入的) 也就是后两个的异或与输入值右移3位后相同
0x93f9a63^0x5d99429 == flag[1]>>>3
第二次栈里只有0x8af45207,0x5d99429(循环里后压入的)
0x8af45207^0x5d99429 == flag[0]>>>3
由于python在数字没有固定长度,所以也就没有循环右移指令,只能手工处理
- a = (0x93f9a63^0x5d99429)
- a = (a<<3 | a>>29)& 0xffffffff
- print(bytes.fromhex(hex(a)[2:])[::-1])
-
- a = (0x8af45207^0x5d99429)
- a = (a<<3 | a>>29)& 0xffffffff
- print(bytes.fromhex(hex(a)[2:])[::-1])
-
- #flag{t1nyPr0g}
最后一个问题,36D杯为啥用flag{}包起来而不是36D{}呢?!
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。