吾爱2025-Windows逆向高级题-5 考点:异步消息执行,变种tea展开、变种MD5、时间戳、Flag分段检查
解题过程 这一段是获取两个编辑框的内容,即uid和flag,然后flag要符合异或的那一系列条件,实际格式是flag{…}。
跟到这边发现有一系列函数,main_program里面的执行验证按钮后主流程,execute是main_program里面通过不同消息来执行不同命令的函数。(都是自命名的函数,仅代表个人想法)
execute函数 其他消息:将flag括号内数据进行unhex(如1122字符串直接转成0x11,0x22数据)
0x35消息:获取当前半小时整点时间戳数据。
0x55消息:通过利用变种MD5+Salt将解密完数据的前十六字节计算得到4字节数值。
0x25消息:unhex后数据进行解密(Decrypt函数)。
main_program函数 第一部分 获取flag括号内数据通过消息分发执行execute的unhex消息,然后再执行execute的Decrypt函数,解密unhex后的数据,将解密完的数据长度赋值给v12。
第二部分 将解密完数据的前16字节进行custom_MD5,得到4字节数据,然后判断解密后数据第17个字节开始四个字节是否和计算得到的4字节数据相等。
如果相等就再次判断v12,即解密后数据长度,判断是否等于20。
再调用execute的时间戳获取消息,得到8字节时间戳数据。
最后再检查解密后数据前8字节是否等于时间戳数据,以及第九个字节往后8字节是否等于编辑框输入的uid。
结论 输入的flag得是被和Decrypt相对于的加密函数进行加密后的数据,加密前格式:{半时整点时间戳(8字节),uid(8字节),Custom_MD5(前面十六字节)(4字节),0x04填充(四个字节)}
最后一部分填充会在下面Decrypt函数里面说明来由。
Decrypt函数(sub_7FF7FAC92C40) 要求unhex后数据长度要是8的倍数,且利用一系列计算得到v12这个数据,参与内部解密的Key生成,最后还要求解密完的数据符合一系列条件验证。
解密后数据条件验证 从这部分逻辑代码可以分析,他是将最后v8指向最后一个数据,然后v9赋值最后一个数据,然后v8循环递减,直到当前v8指向v8开始往前的第v9个指针结束,然后最后解密后数据长度=当前长度-v9。
已知解密后前面已经占用了20字节(时间戳+uid+md5),在main_program也已知解密后数据长度要等于20,所以可以知道这边v9必须等于4,所以v8等于4,最后这边一共占用4个字节,即{4,4,4,4},这样经过这边的验证最后的size才会等于20。
dec函数 将unhex后数据按8字节分块进行tea的解密,tea加密的Key由上一层传入的v12通过RC4得到,且每次解密Key都会变化(固定变化),直接动调就可以拿到几次解密用到的Key值。
下面一系列解密就是tea的解密,不过是展开,可以数出一共是12轮,且Delta直接可以通过两次sum的值相减得到(由于tea解密这边应该是加上sum,ida伪代码展示是减,但是实际计算后数值一样),B979379E就是tea解密用到的Delta。
所以就可以通过动调得到的几次Key和Delta写出tea的加密代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 uint32_t key1[] ={ 0xD7851B65 , 0x473457C1 , 0x1231F787 , 0x9ACD6D9A }; uint32_t key2[] ={ 0xB728E994 , 0x1746382E , 0xC52D865C , 0x10778A6E }; uint32_t key3[] ={ 0x7459F437 , 0x90D1E5D , 0x779375B2 , 0xEFCB8541 }; void tea_encrypt (uint32_t v[2 ], const uint32_t k[4 ]) { uint32_t v0 = v[0 ], v1 = v[1 ], sum = 0 ; uint32_t delta = 0xB979379E ; for (uint32_t i = 0 ; i < 12 ; i++) { sum += delta; v1 += ((v0 << 4 ) + k[2 ]) ^ (v0 + sum) ^ ((v0 >> 5 ) + k[3 ]); v0 += ((v1 << 4 ) + k[0 ]) ^ (v1 + sum) ^ ((v1 >> 5 ) + k[1 ]); } v[0 ] = v0; v[1 ] = v1; }
主解题流程 通过用c++实现这部分代码,获取时间戳数据(8字节)。
然后将uid转为8字节字节数据拼接到时间戳字节后面。
MD5值暂时填充4个0x00,将MD5值和4个0x04字节拼接上。
将完整数据进行tea_encrypt,再用flag{}包裹填入编辑框进行验证。
在MD5生成代码处,断点在箭头处,即可得到MD5四字节数据。
最终再重复上面步骤即可得到flag。
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 #include <iostream> #include <Windows.h> void tea_encrypt (uint32_t v[2 ], const uint32_t k[4 ]) { uint32_t v0 = v[0 ], v1 = v[1 ], sum = 0 ; uint32_t delta = 0xB979379E ; for (uint32_t i = 0 ; i < 12 ; i++) { sum += delta; v1 += ((v0 << 4 ) + k[2 ]) ^ (v0 + sum) ^ ((v0 >> 5 ) + k[3 ]); v0 += ((v1 << 4 ) + k[0 ]) ^ (v1 + sum) ^ ((v1 >> 5 ) + k[1 ]); } v[0 ] = v0; v[1 ] = v1; } int main () { uint32_t key1[] = { 0xD7851B65 , 0x473457C1 , 0x1231F787 , 0x9ACD6D9A }; uint32_t key2[] = { 0xB728E994 , 0x1746382E , 0xC52D865C , 0x10778A6E }; uint32_t key3[] = { 0x7459F437 , 0x90D1E5D , 0x779375B2 , 0xEFCB8541 }; uint8_t timestamp_bytes[8 ]{}; uint8_t uid[]{ 0x50 , 0x04 , 0x23 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 }; uint8_t md5_and_pad[]{ 0xD2 , 0x63 , 0xE4 , 0xE6 , 0x04 , 0x04 , 0x04 , 0x04 }; FILETIME time{}; DWORD64 timestamp{}; GetSystemTimeAsFileTime (&time); memcpy ((void *)(×tamp), (void *)(&time), 8 ); timestamp = 1800 * ((timestamp / 0x989680 - 0x2B6109100LL ) / 0x708 ); memcpy ((void *)(timestamp_bytes), (void *)(×tamp), 8 ); tea_encrypt ((uint32_t *)timestamp_bytes, (uint32_t *)key1); tea_encrypt ((uint32_t *)uid, (uint32_t *)key2); tea_encrypt ((uint32_t *)md5_and_pad, (uint32_t *)key3); printf ("flag{" ); for (int i = 0 ; i < 8 ; i++) { printf ("%02X" , timestamp_bytes[i]); } for (int i = 0 ; i < 8 ; i++) { printf ("%02X" , uid[i]); } for (int i = 0 ; i < 8 ; i++) { printf ("%02X" , md5_and_pad[i]); } printf ("}" ); return 0 ; }
心得 动调调试分析程序主体流程很重要,要先了解大概执行框架才能逐步往下层分析,且上层一些代码条件有助于下层的分析。
然后踩了一个严重的坑就是IDA伪代码里面的变量值和实际值一些情况下是不一样的,之前写题没在意那么多,这次很多地方都发现有这种问题,卡了我分析好久。所以关键代码段最好用汇编逐步分析,看实际数据的变化。