De1CTF 2019 (一)
Last updated on January 27, 2024 am
Cplusplus,RE_sign
Cplusplus
总体分析
程序的输入和关键比较函数都比较明显,直接看关键的函数

在这个函数里面里面,出现了三次sub_140005a90
这个函数,这个函数经过一点🤏时间的调试后,发现就是字符串转16进制,并且限定输入只能是数字而不能是字符。

这里用了三次这个函数,也就是把输入转了三次,猜测到这里就是把flag分成三段,类似这样111_111_111
,这里下划线就是分隔符。
分隔符
然后再接着看这个sub_140006910
,直接对着F5的代码调试的时候总会有奇奇怪怪的事情,应该IDA没有很好识别,所以转去看汇编,值得注意的是这里有两个挺关键的比较函数,位与21行和23行。

将断点下在这里,动态调试会得到这样的汇编

这里的al
就是之前提及的分隔符,[rsi+18h]
就是这个分隔符,如果不在这里加分隔符那么上面的loc_14000599c
就会直接退出。查看[rsi+18]
就可以得到这个分隔符,下面的汇编也是如此。总之现在得到了两个分隔符分别是@和#,那么输入的形式就是111@111#111
第一部分
经过第一个格式check后,进入第二个内容check,也就是检查每个部分的flag是否正确。
先看第一部分flag的检查

这里的v45
就是第一部分flag的16进制,即输入78
那么v45=4E
,就是78=0x4e
。这个函数会首先限制输入小于0x6f
,然后走一个十分复杂的算法,看其他WP说这是梅森旋转算法,不懂。但可以找到一个很关键的比较语句

不管中间算法怎样复杂,这里肯定是不能exit
的,而且输入范围也比较小,那么就可以考虑爆破。这里爆破的基本思路就是不断改变输入的值,然后通过if语句。
爆破可以考虑以下两种手段,
- 直接dump源码
- 从源程序patch
这里用patch源程序方式。
先在IDA中找到对应位置
这里是与0x6f比较

x64dbg打开,注意这里rbx
寄存器存放的就是第一部分flag值的内存地址

这里是if判断语句

x64dbg打开,rbx
寄存器仍没有发生变化。

那么就可以通过rbx寄存器爆破flag,具体patch如下


其余部分不变,然后在140002b07
下一条语句处下断点然后运行,程序断下后再查看rbx
寄存器内存对应值即可。最终也就是爆破得到第一部分flag为78
第二部分
这里的flag就比较简单了,就是数组的简单索引

得到第二部分是20637
第三部分
这部分只有一条语句,不过IDA识别有问题,直接看汇编就好

这里[rbp+0x0E0h+var_58]
就是0x22h
,只是之前那个梅森算法的输出,[rbp+0x0E0h+var_58+4]
是第三部分flag。

所以这里很明确
flag_3 % 0x22 =0xc
flag_3 / 0x22 = 3
那么flag_3 = 3 * 0x22 + 0xc = 114
所以flag就是78@20637#114
RE_sign
主程序逻辑比较明显
大意就是输入flag,然后经过sub_401233
进行加密,中间进行一些运算然后去到33行的if判读语句进行判断。经过简单调试可以发现,sub_401233
高度疑似是一个变表的base64操作,中间21行至31行不会对输入进行操作。
现在就需要跟进sub_401233
进行分析。
sub_401233
函数很长,很多if、while等语句,逐一分析不太现实。程序中存在原base64的字符串表,并且在这个函数中有所引用,可以基本推测变表是基于原表进行变化。
往下审计过程中会发现有一个特殊的判断语句if (i > 63)
,而base的表正是64为长度,推测这里可能是生成变表,于是打个断点,看看会得到什么
在if处下断点,在Hex View中可以发现新的特殊的字符串
然后打断点跳出循环
点击v221变量去它的地址处,找附近有没有可能的base64字符串
找到类似的字符串0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm+/
,经过验证,这个就是变表后的base64表。
继续往后分析进入到于flag比较的地方,这里面也挺多操作,但是可以从后往前看。
首先很显然不能进入else
里面,否则会返回0值,而要返回1则需要v34==49
,推测是比较成功的密文字符数量,继续往前倒推可以看到71行的if判断语句,这里这是涉及到break
操作,而想要进入到这个if语句判断,前面还有一个if需要满足
这里的v5是经过变表base64后的字符串,其长度需要为48,那么原始字符串就需要是33~36个字节。
进入sub_402160
查看
这里又用到了原始的base64表,并且还用到了加密了的base64输入,猜测这里是返回加密的字符在原表中的索引,经过调试发现确实如此,而原始判断左边v19则是密文。
至此加密逻辑就已经很清晰了,首先进行变表的base64加密,变表为0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm+/
,再把加密字符在原base64表中的索引作为最后的密文,那么解密就很简单了,
先得到加密的base64密文
1 |
|
再base64解密即可
de1ctf{E_L4nguag3_1s_K3KeK3_N4Ji4}