-
-
[原创]看雪CTF 2016 第29题分析 29-weigou
-
发表于:
2016-12-31 15:45
5742
-
[原创]看雪CTF 2016 第29题分析 29-weigou
从我实际找注册码的角度,分析下第29题。
A1.拿到该题,首先分析其窗口过程函数DialogFunc,找到按钮”Check”的相应函数
如果String[8] != ’\0’,这提示”Err”,即注册码长度是8.
计算8字符的和,传参数到函数yboncke1sub_401B0A ,发现是一个switch循环,比较绕,无法发现到弹出”Good”的地方。
A2.陷入僵局的情况下,重启调试器X64Dbg,修改任意指令,如4012B7 cmp ax,69cmp ax68,F9后程序不能启动,报异常。怀疑是有防止篡改的功能,从程序头401000开始单步执行,sub_401039执行后异常.
1. 00401000 | 6A 00 | push 0
2. 00401002 | E8 43 0F 00 00 | call <crackerme.GetModuleHandleA>
3. 00401007 | A3 9C 3C 40 00 | mov dword ptr ds:[403C9C],eax
4. 0040100C | 6A 00 | push 0
5. 0040100E | 6A 00 | push 0
6. 00401010 | 6A 00 | push 0
7. 00401012 | E8 22 00 00 00 | call crackerme.401039
8. 00401017 | E8 64 0F 00 00 | call <crackerme.InitCommonControls
9. 0040101C | 6A 00 | push 0
10. 0040101E | 68 65 12 40 00 | push crackerme.401265
11. 00401023 | 6A 00 | push 0
12. 00401025 | 6A 65 | push 65
13. 00401027 | FF 35 9C 3C 40 00| push dword ptr ds:[403C9C]
14. 0040102D | E8 24 0F 00 00 | call <crackerme.DialogBoxParamA>
A3. Sub_401039先调用sub_401080,后比较内存,被篡改则触发异常。
A4. 观察sub_401080,从win32系统库user32.dll kernel.32.dll ntdll.dll 加载函数到全局变量。程序通过全局变量函数完成真正的注册码校验功能,看不到函数名,给静态分析造成不便。
A5. 任意选择一个全局变量,如dword_403BA8,查找引用,
0040150E | B8 A8 3B 40 00 | mov eax,crackerme.403BA8
00401513 | 80 38 00 | cmp byte ptr ds:[eax],0
00401516 | 74 2F | je crackerme.401547
00401518 | 66 8B 58 07 | mov bx,word ptr ds:[eax+7]//都是通过”+7”,”+9”找到真正的函数地址
0040151C | C1 E3 10 | shl ebx,10
0040151F | 66 03 58 09 | add bx,word ptr ds:[eax+9]
00401523 | 6A 00 | push 0
00401525 | 6A 00 | push 0
00401527 | 6A 00 | push 0
00401529 | 68 7C 19 40 00 | push crackerme.40197C
0040152E | 6A 00 | push 0
00401530 | 6A 00 | push 0
00401532 | FF D3 | call ebx //调用从 403BA8 转化来的函数
A6.调试器正常加载并运行程序的情况下,在内存中转到地址403BA8 ,
“86767534”(7686<<16 + 3475)=76863475,汇编页转到地址76863475,
提示“正确的表达式->kernel.CreateThread”,即dword_403BA8就表示函数CreateThread。
其他全局变量按此方法查找,可以找到GetDlgItemTextAdword_403B3A,WaitForMultipleObjectdword_403BBE,VirtualAllocdword_403C0B等关键全局变量的实际意义。
分析到这里,可以事半功倍了。^_^
A7.查找对GetDlgItemTextAdword_403B3A的引用,位于线程函数ybThread3sub_4016F0中。
输入的8字节字符串分别与0x66亦或,存入全局地址gByte1dword_403C85中,然后
SetEvent gEventArraydword_4032F1。
A8. 查找gEventArraydword_4032F1和gByte1dword_403C85引用。
位于ybThread5sub_4017F9中,先分配60字节的内存空间,异或方式填充字节,即弹出”Good”的代码。
A9.编写代码反推注册码。
根据弹出”Err”的代码:
00401350 | 6A 00 | push 0
00401352 | 68 B1 32 40 00 | push crackerme.4032B1 “Err"
00401357 | 68 B1 32 40 00 | push crackerme.4032B1 “Err"
0040135C | FF 35 ED 32 40 00| push dword ptr ds:[4032ED]
00401362 | E8 13 0C 00 00 | call <crackerme.MessageBoxA>
字符串”Good!”—> 004032B5 aGood db 'Good!',0 ,所以解密后的代码应该包含
char p[10]={0x68,0xB5,0x32,0x40,0x00,0x68,0xB5,0x32,0x40,0x00};考虑用KMP串匹配算法匹配。
输入字符与0x66异或,A0var_4+ A1var_8==0x32113442,用遍历 62*62*62*62中可能即可获得注册码,遍历过程如下:
A10.得到注册码的前4位,再推出后四位,如下可能:
KAhu skey
KQhu s沝y
Kahu sKey
Kqhu s{ey
验证后,正确注册码是 KAhuskey .
附件: 看雪CTF 2016 第29题分析 29-weigou .rar
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课