NCTF2024
NCTF 2024 Reverse WP
前言
这次也是擦边#6拿下奖金,组队的师傅们都十分强大,合力拿下。
Re这次摸了三题,剩一题安卓不太熟悉安卓逆向看了一眼就没做,但是赛后发现其实没那么难(。ezDOS 8086汇编题刚好撞上我GHCTF出的题,很熟悉直接秒了,偷摸了个一血。然后gogo这题的golang vm研究了挺久,拿下了三血,实际加密不是很复杂。总体下来这几题re出的都挺不错,收获也很多,对vm的题型也更加熟悉了。
ezDOS
分析
程序中间出现的花指令都直接nop去除,然后Apply patch到程序。
程序要求输入38长度字符串,然后进行一系列变种类RC4算法加密,然后与0x141地址的38字节数据进行比对。
使用dosbox动调,在FA代码处是对取出的al对输入的字符串进行xor加密。0x32是取出的异或值,0x31是输入的字符’1’。
直接debug一直循环执行这边,即可拿到对输入字符串异或的一系列异或值。
32 7d 59 7a f3 0d b3 7b 64 8c eb 28 c4 a4 50 30 a0 ed 27 6a e3 76 69 0c da 28 f8 08 ba a6 17 3e 12 59 45 06 4e f1
取出0x142地址的38字节,进行异或即可得到解密flag。
解密
flag
NCTF{Y0u+Ar3_Assemb1y_M4st3r_5d0b497e}
SafeProgram
分析
核心加密是一个SM4加密。
查看byte_14002A0D0数组交叉引用,发现在其他函数被访问过。
发现是在VEH异常Handler里面调用的,第一个AddVectoredExceptionHandler得直接nop,不然运行就直接退出。
然后在这个函数开头断点,使用ScyllaHide插件一键去除反调试,防止其他地方的反调试。
main函数可以看到要求输入格式为NCTF{…}的长度38字符串,然后运行到箭头函数会触发除0异常,然后就会触发VEH那个Handler导致那个byte数组被修改,需要提取的数据是被改后的。
动调时提取这三个数组数据,进行解密即可。
key是main函数两次memcpy那边的数据,结果如下。
解密
1 |
|
flag
NCTF{58cb925e0cd823c0d0b54fd06b820b7e}
gogo
分析
main_main函数可以看到是将输入分块通过channel进行协程通信。
在main_main函数附近有一个带VM名字的函数,里面就是接收main那边发送的数据,然后底下有个函数执行,是通过操作数进行调用VM函数计算。这边一系列计算函数也印证想法。
对每个vm的函数都下断点输出执行的指令以及操作数,方便分析整个加密流程,如main_XOR函数断点:
运行输入38个’1’(数据简单方便分析算法),可以得到一堆我们输出的伪代码计算过程,通过看到9e3779b9以及计算的特征,可以发现是XXTEA变种。
31313131就是我们输入的字符串的字节,不过是以4字节为单位进行运算。
通过分析可得知是将输入的flag分成两份,20字节为一组,分别进行两种变种XXTEA计算,Key也不一样,不过都在这里面可以找到Key。
可以根据伪代码计算流程进行还原成代码,基于标准XXTEA进行编写,中间可以对比标准算法发现异或Key的值在哪,以及根据加密计算的一些中间值来验证加密代码,最终加密值就可以根据伪代码尾部最终值来验证。(这边不具体赘述)
还原加密代码如下,基于标准XXTEA进行修改的:
1 |
|
在main_RET函数可以看到两组字符串的比对,都是20长度的比对,这两个数据就是加密后的flag了,提取出来分别进行解密即可。
解密
1 |
|
flag
NCTF{H4rd_VM_with_Gor0ut1n3_5fc4b0be7ad}
XLogin
分析
jadx加载发现代码中调用了Decstr函数来解密一些字符串,可以在libsimple.so里面找到DecStr函数实现。
具体解密字符串函数就是Base64换表解密后再异或上当前字符串长度值。
就可以解密得到这些实际字符串。
发现doCheck是在native里面,ida分析libnative.so,发现有个loadDex,应该是动态加载一个dex。
在loadDex下面就是doCheck函数实际实现。
通过特征可以发现是使用了3des加密,先猜测他没有魔改,毕竟那一坨代码没人想看。上面的ptr的两个数据(xmmword_1804和unk_1814共24字节数据)就是被加密的flag,3des加密后下面的while循环就是对加密后的数据与flag密文进行比对。
在apk的Assets里面会发现又有个libsimple.so,ida分析没有东西,直接拖入010发现存在一个dex结构头,前面的这64字节应该是没用的。
libnative.so里面loadDex跟到的函数验证了这个猜想,v13是Assets里的libsimple.so文件大小,减去了64,然后下面v17是读取起始指针,也加上了64,说明读取实际文件跳过了前64字节。
把前64字节去除,使用jadx分析。发现是Check函数,检测了username和password,和题目描述flag格式对应。username这边可以直接解密出来是X1c@dM1n1$t
,然后使用username的MD5值作为密钥去调用doCheck加密。
密钥:7d53ecd36a43d3d237e7dd633dcf8497
然后提取密文进行3des解密即可,然后这边有个端序问题卡了不少师傅一段时间,密文以及密钥都要以8字节位一组转换到大端序,才能解密,然后解密完的明文也要从大端序转回到小端序。
解密
解密完将明文以8字节一组倒序得到明文SafePWD~5y$x?YM+5U05Gm6=
flag
NCTF{X1c@dM1n1$t_SafePWD~5y$x?YM+5U05Gm6=}