2024ciscn_RE_wp
asm_re
Arm汇编审计
当时虽然汇编指令没看懂,但是操作大概是能顺下来的。
找到加密过程和密文就行。
加密过程在loc_100003D00处

大概就是说(((W8*0x50)+20)^0x4D)+30这样一个加密过程。
然后根据W8找到密文的位置。

这里因为是用双字节去存储的,所以要提取双字节数字,注意小端序。
EXP:
1 | x=[8151, 8631, 7751, 8231, 9959, 4311, 4391, 8199, 4551, 7751, 4119, 4119, 4599, 8199, 4151, 4359, 7959, 4311, 4119, 4119, 8039, 4119, 4551, 4551, 4119, 8151, 7959, 4359, 3911, 4391, 4151, 7751, 4151, 8151, 4359, 8151, 4359, 10119] |
gdb_debug
动静结合
1 | __int64 __fastcall main(int a1, char **a2, char **a3) |
大致浏览一下,加密逻辑简单,但是有随机函数rand(),一般来说都是伪随机,我们需要通过动调来找出rand() 的值。
先找到srand(), 看看是不是固定seed。

很明显是一个固定值,那接下来就是动调出三个rand的值。

这里固定格式为flag{}且总长度为38,随便构造一个输入符合格式的就行flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}
先找第一个rand()的值,找到rand()的位置,下断

这里我们首先要明确,为什莫要求出来rand()的值,首先我们是不知道flag的,也就是说我们无法正推出rand的值,反推的话,我们就需要知道v20也就是rand()值与密文v28的异或,从而来推出我们最终的flag。
我们肯定是要从v28来入手,我们知道的是自己输入的flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}这一串字符,动调出v28的结果,我们就能直接算出此处rand()的值。
EXP:
1 | x=b"flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}" |
第二个rand,这里其实知不知道rand的值的问题不大,因为我们最终要的是ptr的结果。

这里的ptr相当于从0到0x25根据v18 = rand() % (k + 1)的值打乱顺序了,所以变化在ptr上,不需要知道这里的rand()值。所以rand的值不知道也没事,可以直接动调找到ptr的结果。
需要注意的是这里ptr是由malloc来分配的地址,分配的地址位置是随机的,找的时候注意别找错就行。
ptr=[0x12, 0x0E, 0x1B, 0x1E, 0x11, 0x05, 0x07, 0x01, 0x10, 0x22,
0x06, 0x17, 0x16, 0x08, 0x19, 0x13, 0x04, 0x0F, 0x02, 0x0D,
0x25, 0x0C, 0x03, 0x15, 0x1C, 0x14, 0x0B, 0x1A, 0x18, 0x09,
0x1D, 0x23, 0x1F, 0x20, 0x24, 0x0A, 0x00, 0x21]
然后下边v28是经过了一个打乱,最后的值赋给了v31,这里知道就好。

来找第三个rand(),

这里可以跟rand1一样,用异或直接得到rand()的值。调试出v12,和v31的值就行,注意这里必须要rand的值,跟第一个rand的理解一样。
Exp:
1 | v31=[0x06, 0x4A, 0x5B, 0x14, 0xC4, 0x77, 0xDF, 0x63, 0xB5, 0x82, |

这里s1,s2做比较,那s2就是密文,已经给出,这个s1是byte_55C59C2010A0的值
跟进提取出来,然后这两个值进行异或得出v31的值,
到这里就通了,逆过程推回去就好。
EXP:
1 | v32=[ 0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73, |
