[ctf.show.reverse] 36D杯 tiny

程序极小,也不能运行也不能用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{}呢?!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值