湖湘杯2020 easyre wp

很久没有写题解博客了,最近忙着学习深度学习= =,湖湘杯这道题还是不错的,可以锻炼一下自己动态调试的能力,所以刚好在练习的过程中记录一下,方便以后回顾:

首先拿到文件,查壳发现无壳,运行一下大概就是先判断长度,再判断是否是正确flag:

长度错误就输出wrong length并退出。

拿到ida里看一下,发现没有很明显的入口函数,查找字符串找到input your flag:,找到主函数位置

f5看一下,发现没办法反编译,所以我们就直接上动态调试吧:

在0x40DA40下断点(f2),f8单步调试,发现到0x40DA72停住,进行输入:

先随便输入点东西,如’111‘,然后继续调试,到下图这一步,发现将eax的值和0x18进行比对,可以推断出0x40D920函数的作用就是获取输入的flag的长度,然后和24进行比较:

发现下面是je跳转,为了能够实现无条件跳转,我们对这条汇编进行一些修改

方法有两个:一、修改寄存器中的标志寄存器值,由于是je汇编指令,判断z标志位,双击就可以修改;二、修改汇编代码,将je汇编代码改为jmp实现无条件跳转。

这里我使用的是第二种方法,直接修改汇编指令:

继续调试发现函数返回到0x4048DA处,

这里就是整个程序的主要加密处:

(图中地址404919处的判断就是对于循环轮数的判断,如果循环了24次了就进行跳转出循环。)

最后一位数据操作如图:

将加密写成代码的话其实就是这样:

tmp = a[0] &0xe0
for i in range(len(a)-1):
    a[i] = ((a[i]<<3)|(a[i+1]>>5))&0xff
    a[i] = a[i] ^i
a[23] = (a[23]<<3)|(tmp>>5)

执行24次后继续调试,程序来到了这一代码段,因为上面已经对数据进行了一些操作,所以初步猜测这里很有可能是对比flag阶段:

可以看到是将操作后的数据与0x411000处的字符进行比较,那我们就去把0x411000处的字符dump出来:

基本的逻辑清楚之后,就可以进行暴力破解了:

(由于每两个字符之间都有联系,暴力破解的时候会比较麻烦,看了其他师傅博客,使用的是z3进行解决,指路

exp

from z3 import *

s = Solver()
flag = [BitVec('x%d'%i,8) for i in range(0x18)]

b = [0x2B, 0x08, 0xA9, 0xC8, 0x97, 0x2F, 0xFF, 0x8C, 0x92, 0xF0, 
  0xA3, 0x89, 0xF7, 0x26, 0x07, 0xA4, 0xDA, 0xEA, 0xB3, 0x91, 
  0xEF, 0xDC, 0x95, 0xAB]

for i in range(23):
    s.add(((flag[i]<<3|flag[i+1]>>5)&0xff) ^i == b[i])
s.add((flag[23]<<3|flag[0]>>5)&0xff == b[23])

if s.check() == sat:
    m = s.model()
    Str = [chr(m[flag[i]].as_long().real) for i in range(24)]
    print("".join(Str))

再将结果md5一下就是flag了:

看了wp之后感觉这题其实逻辑挺清晰的(但是我当时并没做出来= =,tcl)可以作为学习动态调试的例题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值