DASCTF复盘 (一)、RE -> CrackMe
Crackme
一、查壳

32位的MFC无壳程序
二、IDA静态分析
搜索字符串定位到这里

代码流程不难,大体上程序就是从文本编辑框中获取flag与key,然后对key进行md5摘要并作为密钥对flag进行AES加密,最后的结果与this指针偏移0x2E4的结果进行对比...
三、解决反调试
当我动态调试的时候,程序会莫名崩掉如图:

猜测此处为反调试
IDA搜索导入函数:

并没有搜到有关反调试的函数,猜测可能是动态加载dll
搜索有关thread的字符串

注意到字符串 ZwSetInformationThread 函数,交叉引用

这里即为反调试的地方,把这个函数patch掉或修改其第二个参数(这里我已经修改过了)...
再次动态调试,程序不再奔溃,反调试解决
获取this指针指向的值:
this+ 0xdc: 9f77c2a4 ac5c0a67 1321bbe1 e9972af6
this + 0x1e0: D59F8E94 B0E1DE6E 329518A0 C444AA94 DE7C8D44
this + 0x2e4: 5B9CEEB2 3BB7D734 F31B7514 C6B21FE8 DE334474 751B476A D4375188 FC67E660 DA0D5807 814353EA 7B52856C 8665AFB4
四、获取key
通过this指向的值直接爆破得到key
代码如下:
import hashlib gather = "123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM" def md5(i): m5 = hashlib.md5() m5.update(i.encode(encoding='utf-8')) return m5.hexdigest() def sha1(i): sh1 = hashlib.sha1() sh1.update(i.encode(encoding='utf-8')) return sh1.hexdigest() ans = 0 for a in gather: for b in gather: for c in gather: for d in gather: if ans == 2: exit(0) f = "" f += a +b +c +d if md5(f) == "9f77c2a4ac5c0a671321bbe1e9972af6": print(f) ans += 1 if(sha1(f) == "D59F8E94B0E1DE6E329518A0C444AA94DE7C8D44".lower()): print(f) ans += 1 #循环次数有点多,要跑上一会儿...

得到key: NocTuRne
五、获得flag

首先对Key进行md5加密

得到:5C53A4A41D52437A9FA1E9C26CA59090
然后,按理说应该以md5加密后的Key为密钥对this->0x2e4的值进行解密,但this->0x2e4对应的值是96位的,解不出明文。。。
这里,我们换一种思路
既然有 CryptEncrypt 函数,那一定也有 CryptDecrypt函数,我们直接对他进行解密!
代码如下:
#include<stdio.h> #include <windows.h> #include <windef.h> #include <wincrypt.h> int main() { BYTE pbData[16] = { 0x5c, 0x53, 0xa4, 0xa4, 0x1d, 0x52, 0x43, 0x7a, 0x9f, 0xa1, 0xe9, 0xc2, 0x6c, 0xa5, 0x90, 0x90 }; DWORD dwDataLen = 16; BYTE a3[0x104] ={ 0x5B, 0x9C, 0xEE, 0xB2, 0x3B, 0xB7, 0xD7, 0x34, 0xF3, 0x1B, 0x75, 0x14, 0xC6, 0xB2, 0x1F, 0xE8, 0xDE, 0x33, 0x44, 0x74, 0x75, 0x1B, 0x47, 0x6A, 0xD4, 0x37, 0x51, 0x88, 0xFC, 0x67, 0xE6, 0x60, 0xDA, 0x0D, 0x58, 0x07, 0x81, 0x43, 0x53, 0xEA, 0x7B, 0x52, 0x85, 0x6C, 0x86, 0x65, 0xAF, 0xB4}; DWORD pdwDataLen = 32; DWORD dwBufLen = 0x104; BOOL v6; // [esp+4h] [ebp-18h] HCRYPTKEY phKey; // [esp+Ch] [ebp-10h] BYREF HCRYPTPROV phProv; // [esp+10h] [ebp-Ch] BYREF HCRYPTHASH phHash; // [esp+14h] [ebp-8h] BYREF phProv = 0; phHash = 0; phKey = 0; v6 = CryptAcquireContextA(&phProv, 0, 0, 0x18u, 0xF0000000); if (v6) { v6 = CryptCreateHash(phProv, 0x8003u, 0, 0, &phHash); if (v6) { v6 = CryptHashData(phHash, pbData, dwDataLen, 0); if (v6) { // 128位AES加密 v6 = CryptDeriveKey(phProv, 0x660Eu, phHash, 1u, &phKey); if (v6) v6 = CryptDecrypt(phKey, 0, 1, 0, a3, &pdwDataLen); printf("%s\n", a3); } } } if (phKey) CryptDestroyKey(phKey); if (phHash) CryptDestroyHash(phHash); if (phProv) CryptReleaseContext(phProv, 0); getchar(); return v6; }
结果如下

六、拿到flag
flag即为:
DASCTF{H@sh_a^d_Aes_6y_W1nCrypt}

反思
这场比赛暴露了很多问题,我还是太菜了,安卓逆向仍然不太会,pyc逆向不够熟悉,x64脱壳没有思路。以前刷的题还是太少,而且简单。
以后要多刷攻防世界高分题了,大二了,不能再刷简单题糊弄自己玩了。
太菜了...
明天再去做做"奇怪的交易"
还要刷几道安卓逆向题
蓝桥杯国赛也必须提上日程了...

浙公网安备 33010602011771号