11月1号~11月2号两天和队友参加了SSCTF,我主要做了一下里面Reverse相关的题目。SSCTF里面逆向相关的题目全是Windows下的CrackMe程序,除了Web分类里面夹杂了一个病毒分析题目外。总的来说不是很难,不过中间有个CrackMe是易语言写的,直接没有接触过这种题,就觉得有点棘手了,不过看了别人的writeup之后觉得还是非常简单的。
0×01. CrackMe1
通过IDA进行静态分析,可以很快找到关键函数位于00401000,F5得到伪代码,大致如下:
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 | bool __cdecl fnCheckLogin(const char *szUsername, const char *szPassword) { const char *v2; // esi@1 unsigned int v3; // kr04_4@1 int v4; // ebp@1 bool result; // al@2 int v6; // eax@3 int *v7; // edi@4 const char v8; // bl@5 const char *v9; // edi@6 int v10; // ecx@6 bool v11; // zf@6 v2 = szUsername; v3 = strlen(szUsername) + 1; v4 = v3 - 1; if ( v3 - 1 == strlen(szPassword) ) // Username和Password长度要一致 { v6 = 0; if ( v4 > 0 ) { v7 = &dword_408030; // xor key do { v8 = *(_BYTE *)v7 ^ szPassword[v6]; ++v7; szPassword[v6++] = v8; } while ( v6 < v4 ); } v9 = szPassword; v10 = v3 - 1; v11 = 1; do { if ( !v10 ) break; v11 = *v2++ == *v9++; --v10; } while ( v11 ); result = v11; } else { result = 0; } return result; } |
就是一个简单的XOR操作,在dword_408030处定义了一个数组,里面存储了XOR的KEY,提取出来就可以写keygen了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/env python # -*- coding:utf-8 -*- import sys import hashlib def crack(username): key = [1, 2, 3, 4, 1, 5, 1, 5, 1, 3, 6, 5, 4, 8, 5, 3, 1, 2, 3, 4, 5, 3, 5, 7, 2, 3, 2, 4, 8, 2, 5, 6, 4] pwd = [] for i in xrange(0, len(username)): pwd.append(chr(ord(username[i]) ^ key[i])) return "".join(pwd) def main(): username = "Wins0n" pwd = crack(username) print pwd print hashlib.md5(pwd).hexdigest().upper() if __name__ == "__main__": main() # 3FFCD172BE3572F485CA19C3227B1081 |
0×02. CrackMe2
此题参考“一朵紫桔桦”的Writeup。易语言写的,不太会搞~~这个CrackMe有一些反调试措施,所以如果在OD里直接退出了,就多试几次。
OD载入程序后,Alt+M打开Memory map窗口,在CrackMe的.data上面下一个断点。然后运行程序,程序会在krnln模块中断下,F8单步几次执行完第一个jmp指令就回到Crackme的空间了。
回到Crackme的空间后进行字符串查找,就可以看到敏感的字符串了,对引用这几个字符串的位置都设置断点,然后进行跟踪分析。
程序会判断注册码的长度是否为32:
输入一个32位的注册码进行测试,继续跟踪,在下面的位置可以找到明文注册码:
Wins0n对应的注册码为027d88ee0aa1836843632a275c9b6214
0×03. CrackMe3
对话框过程函数DialogFunc伪代码分析:
函数功能为记录鼠标左键以及鼠标右键点击序列(左键点击为L,右键点击为R),点击次数即为dwClickCount,点击序列即为pbData,则将pbData + dwClickCount – 0×30作为参数传入sub_401C40函数。另外使用PEiD的Krypto ANALyzer可以看到程序使用了MD5算法,sub_401C40函数的伪代码如下:
函数sub_401B90计算传入参数的MD5值并存入Caption位置,这个就是Flag。对传入的序列以8位一个分组进行计算,共6个分组,产生“查水表”对应的HEX值。
Flag: D27789EFCA409B6B6EE297D412334A65
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 | #!/usr/bin/env python # -*- coding:utf-8 -*- import sys import hashlib import itertools def crackSingle(map, val): dst = 0 for i in xrange(0, 8): dst = (dst * 2) & 0xFF if map[i] == 'R': dst = (dst + 1) & 0xFF return dst == val def genMaps(): map = ['L', 'R'] return list(itertools.product(map, repeat=8)) def crack(): maps = genMaps() vals = [0xB2, 0xE9, 0xCB, 0xAE, 0xB1, 0xED] serial = [] for val in vals: for map in maps: if crackSingle(map, val): serial.extend(map) break return "".join(serial) if __name__ == "__main__": serial = crack() print "Flag: %s" % (hashlib.md5(serial).hexdigest().upper()) print "Clicks: %s" % ('L'*12 + serial) # flag = D27789EFCA409B6B6EE297D412334A65 # serial = RLRRLLRLRRRLRLLRRRLLRLRRRLRLRRRLRLRRLLLRRRRLRRLR |
0×04. CrackMe4
PEiD查壳,提示FSG 2.0 -> bart/xt [Overlay],下载FSG脱壳器对程序进行脱壳,对脱壳后的程序进行测试,提示“数据已经损坏”。将原始程序的Overlay数据附加到脱壳后的文件的末尾,即从文件偏移0×955处至末尾的数据为Overlay数据,添加数据到脱壳后的文件后即可进行正常的密码验证操作。
第一层密码的验证过程如下:
1. 读取文件末尾的316字节数据,并判断最后的16字节组成的字符串是否为seclover.com;
2. 使用seclover.com作为key对这316字节的数据进行XOR操作;
3. 使用HOWMP拼接密码计算MD5值,然后对MD5再次进行MD5运算;
4. 判断MD5值与数据偏移264处的MD5值是否一致;
5. 解密后的MD5为09B2F924C20C5CA427EED2C5B98BEFBF;
6. 提示密码为6位数字,所以进行枚举即可,得到密码为564987;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/bin/env python # -*- coding:utf-8 -*- import hashlib def crack(val): for i in xrange(0, 1000000): msg = "HOWMP%06d" % i msg = hashlib.md5(msg).hexdigest().upper() msg = hashlib.md5(msg).hexdigest().upper() if msg == val: return "%06d" % i return None def main(): print crack("09B2F924C20C5CA427EED2C5B98BEFBF") if __name__ == "__main__": main() # 564987 |
释放的文件仍然使用FSG 2.0 -> bart/xt [Overlay]加密,所以可以用同样的方法进行解密。第二层密码的校验方法和第一层是一样的,MD5校验正确后释放logo.gif文件。MD5值为:12A73DEB50334C0B446937B3E31A322D。虽然密码只有六位,但是可能的情况太多了,暴力破解断时间不可行。观察末尾解密后的316字节的数据,发现会创建一个gif文件,同时可以知道文件加密后的数据为316字节数据之前的0x128C字节的数据,而解密的方法即为使用密码对其进行XOR操作。根据GIF文件格式,其头部标志为GIF89a,那么我们可以计算出key为w!q&cs。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #!/usr/bin/env python # -*- coding:utf-8 -*- import hashlib def getkey(): src = [0x30, 0x68, 0x37, 0x1E, 0x5A, 0x12] dst = [0x47, 0x49, 0x46, 0x38, 0x39, 0x61] # GIF98a key = [] n = len(src) for i in xrange(0, n): key.append(chr(src[i]^dst[i])) return "".join(key) def main(): key = getkey() print key if __name__ == "__main__": main() # key = w!q&cs |
输入key即可得到解密的logo.gif文件。
0×05. CrackMe5
直接运行程序时工作正常,而在OD中调试时遇到int 3指令(00401640函数),对其进行静态分析时发现在OnInitDialog中注册了一个全局异常处理函数。TopLevelExceptionFilter中穿插了大量的花指令,尝试对TopLevelExceptionFilter(004012F0)的代码进行手工恢复。函数004012F0的主要逻辑为判断触发异常时Eip处的字节是否为0xCC,如果是则跳转到下一个字节,根据当前字节计算出一个偏移值作为增量添加给Eip,最后Eip增加1,继续执行代码。将提取出来的反汇编代码整理成一个cpp文件:
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 | unsigned int calc(unsigned char arg) { int res = 0; __asm { push ebx // ebx = 0 mov ebx, 1 // 0xCC mov cl, arg // 参数值 mov al, cl shl al, 6 shr cl, 2 add al, cl xor al, 0Dh mov cl, al shr cl, 5 shl al, 3 add cl, al add cl, 11h mov al, cl shl al, 5 shr cl, 3 add al, cl xor al, 51h mov cl, al shl cl, 7 shr al, 1 add cl, al sub cl, 6Fh and ecx, 0FFh and ecx, 80000007h jns flag_C dec ecx or ecx, 0FFFFFFF8h inc ecx flag_C: add ebx, ecx // ebx = ebx + ecx inc ebx // ebx = ebx + 1 mov res, ebx // save result pop ebx } return res; } |
从进程空间中提取[00401640, 00402591]区间内的数据并保存,对文件中的花指令进行清理,将原始程序文件偏移0×1640处开始的3922字节替换为处理后的数据。之后就可以使用IDA对Patch后的文件进行分析,并将00401640设置为函数,就可以使用F5得到伪代码。最后编写keygen:
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 97 98 99 100 101 102 | #include <stdio.h> #include <string.h> typedef /*unsigned*/ char _BYTE; typedef /*unsigned*/ int _DWORD; unsigned int hash_name(char* msg) { int v1; // ebx@1 void *v2; // edi@1 int result; // eax@3 int v4; // eax@4 int v5; // ecx@4 int v6; // edx@5 int v7; // ebx@5 int v8; // eax@6 int v9; // edx@7 int v10; // ebx@7 int v11; // eax@8 int v12; // edx@9 int v13; // ebx@9 int v14; // edx@10 int v15; // ecx@10 unsigned int v16; // ebx@10 int v17; // esi@10 int v18; // eax@10 int v19; // eax@11 int v20; // [sp+Ch] [bp-8h]@1 int v21; // [sp+10h] [bp-4h]@1 v1 = 121314; v20 = (_DWORD)msg; v21 = strlen(msg); v5 = -1 - v20; v4 = v21 + v20 + 1; do { v6 = *(_BYTE *)(v4-- - 2); v7 = 123 * (v6 + v1); *(_BYTE *)v4 = v7; v1 = v7 ^ 0x14AC453A; *(_BYTE *)v4 += v1; } while ( v5 + v4 > 0 ); v8 = v21 + v20 + 1; do { v9 = *(_BYTE *)(v8-- - 2); v10 = 123 * (v9 + v1); *(_BYTE *)v8 = v10; v1 = v10 & 0xA454A546; *(_BYTE *)v8 += v1; } while ( v8 + v5 > 0 ); v11 = v21 + v20 + 1; do { v12 = *(_BYTE *)(v11-- - 2); v13 = 123 * (v12 + v1); *(_BYTE *)v11 = v13; v1 = v13 | 0x15472137; *(_BYTE *)v11 += v1; } while ( v11 + v5 > 0 ); v16 = v1 % 0x15011Fu; return v16; } // reverse but has a bug...000000 unsigned int hash_pwd(char* msg) { int v14, v15, v16, v17, v18, v19; v18 = (_DWORD)msg; v15 = 0; v14 = strlen(msg) + v18 + 1; v17 = -1 - v18; do { v19 = *(_BYTE *)(v14-- - 2); v15 = v19 + 10 * v15 - 48; *(_BYTE *)v14 = v15; } while ( v14 + v17 > 0 ); return v15; } int main(int argc, char** argv) { char buffer[256] = {0}; printf("Username: "); while (EOF != scanf("%s", buffer)) { int user = hash_name(buffer); sprintf(buffer, "%d", user); printf("hash(username)=%s\n", buffer); //printf("%d\n", hash_pwd(buffer)); printf("%s\n", strrev(buffer)); } return 0; } |
0×06. U盘病毒
使用7z打开img文件,得到两个文件。
exe为一个游戏,autorun.inf提示信息:
你真厉害都到这了,看看这个游戏你肯定会喜欢的,但是据说这个游戏是被加了后门的,找到后门操作的文件的内容,取文件内容的16位md5值作为key!祝你好运....... |
使用7z打开exe游戏文件,得到三个文件。
其中1.exe为后门文件,2.exe为真正的游戏文件。分析1.exe,发现它会在当前目录创建一个test.txt文件,创建的文件内容为:WdubQ4IGEzAG54NfATJTNhI4TLIvPvENyTLLWb3YCNBeK5wad5XCgrSQNOih1F。对这个内容进行16位MD5值:A4620BA0298017B2。
0×07. 排名
本文地址: 程序人生 >> SSCTF逆向部分Writeup
作者:代码疯子(Wins0n) 本站内容如无声明均属原创,转载请保留作者信息与原文链接,谢谢!