逆向ctf_2020湖湘杯Re_02

资源链接:https://pan.baidu.com/s/1Jux_GsX7wKUUxyxEy07-Kw 
   提取码:3uui 

一、基础分析

把拿到的题目解压,将easyre.exe文件放入exeinfope(PEID也行)中进行查壳识别:

清楚明了,没壳。首先,运行下easyre.exe文件看看什么效果:

从查壳过程可以看到是32为程序。接下来进行静态分析,放入IDA32位中看看:

 

发现没有明显的入口函数(main()),结合上一步在IDA中搜索Input your flag:字符串,得到:

找到关键地方后,尝试对代码进行F5反汇编操作,发现:

目前为止,就可以结合IDA静态调试配合上OD动态调试了。先打开OD找到地址0x40DA40处,F2下断点,F9执行到这里:

F8单步调试,结合IDA进行操作,发现执行到:

如图所示处,就会弹出一个框,叫你输入flag,所以可以在IDA中将40DA72出的函数进行重命名改为GetCharFlag,随便输入一段字符001后继续运行,(未避免篇幅过长各个函数内部操作就不详细说明,简述函数功能就好),直到:

可以看到,通过一个函数,函数返回值eax的值移动到了【local.2】中,而将这块地址中的数与0x18(24)进行比较,结合下方OD给出的Wrong Length字符床,可以推断出在地址40DA94处的函数作用为计算读入flag子字符串的长度,如果等于24则进行跳转正确代码段,反之输出Wrong length字符。修改IDA中地址为40DA94的函数名为GetFlagLength,而运行错误效果为:

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

本文实行第二种方案修改指令,之后F8继续运行,发现存在函数返回到了地址4048DA处,继续调试发现,这一段代码主要的功能是对输入字符的加密处理,效果为:

加密原理为:读取字符串当前轮数上的单个字符,先进行左移3位操作结果存入eax,之后获取当前轮数+1的字符进行右移5位的操作结果存入edx,在之后将eax和edx进行or(或)运算,将获取的结果取低字节放入地址中,最后将之前放入地址中的数据取出来又与当前轮数进行一次异或(xor)操作,再将结果作为最终结果放入地址保存。如此循环24次。图中地址404919处的判断就是对于循环轮数的判断,如果循环了24次了就进行跳转出循环。当跳出循环后继续F8执行,直到:

到达这一块地址处,详细阅读就会发现这是一块对比判断的汇编代码,可以发现在地址40D82E和40D834这两个地址处,分别取得字符为一个之前加密后的对应轮数得字符,一个取的是地址0x411000处的对应轮数字符,由此可以判断处,此处判断就是判断加密后的数据每一位数据字符与0x411000出的对应位字符是否相等,相等则表示输入字符串flag也就是正确的,反之通过jmp 跳转到40D851处继续执行就会exit退出程序了。当然这里退出实在一个循环中最后退出效果会输出一串字符 Wrong Flag。当所有字符都对上后就会有如下效果:

可以看出,出题的还真不省心,还需要MD5输入。所以知道原理了,将0x411000地址出的数据dump出来看看是什么:

2B 08 A9 C8 97 2F FF 8C 92 F0 A3 89 F7 26 07 A4 DA EA B3 91 EF DC 95 AB   

就是这段数据,当输入的字符串进行加密操作后,与之对比对应全部相等后就可以说明输入为正确的,在md5(输入)就是正确的flag了。

二、上面原理分析清楚了,接下来附上加密处理的代码:

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)

没错就是这么简单,调试半天就这么一点就是软件加密的核心。加密算法知道了接下来进行破解操作了。

三、破解的代码段附上

from z3 import *
flag = [BitVec('x%d'%i,8) for i in range(0x28)]
s = Solver()
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]&0xe0)>>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))

由于破解需要两个连续字符都要有关系,可能操作性太多,暴力破解比较麻烦,运用了z3进行解决,简单明了。

ea5yre_1s_50_ea5y_t0_y0u

ok!!!!! OVER 。。。。。。请批评指正!!!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值