-
-
[原创]看雪2016 第十四题 CrackMe逆向分析
-
发表于: 2016-11-30 11:07 5304
-
OD打开crackme后在 GetWindowTextW下断,尝试输入注册码111111111111111111111111111断下,返回到程序空间后来到
004015FD |> \68 FF000000 push 0FF ; /Count = FF (255.)
00401602 |. 8D4424 4C lea eax, dword ptr [esp+4C] ; |
00401606 |. 50 push eax ; |Buffer
00401607 |. 68 E9030000 push 3E9 ; |ControlID = 3E9 (1001.)
0040160C |. FF35 106C4200 push dword ptr [426C10] ; |hWnd = 002604A6 ('Crack Me',class='CrackMe')
00401612 |. FF15 40B14100 call dword ptr [<&USER32.GetDlgItemTe>; \GetDlgItemTextW
00401618 |. 8D4C24 48 lea ecx, dword ptr [esp+48]
0040161C |. E8 AF050000 call 00401BD0
00401621 |> 8B8C24 4C0200>mov ecx, dword ptr [esp+24C] ; Cases 1 (WM_CREATE),110 (WM_INITDIALOG)
00401628 |. 33C0 xor eax, eax
0040162A |. 5E pop esi
call 00401BD0 这个函数就是主要算法,大致跑了一下发现注册码长度为0x27且前几个字符为acd_b,其中‘_’占位还不确定是什么。进一步发现前0x20个字符必须为a-d的字符。所以注册码改为acdabaabbbccbbbbbbaaadccccaddaaazzzzzzz
00401D16 . E8 A51A0000 call 004037C0 ;根据sn创建了一张表
00401D1B . E8 C01B0000 call 004038E0 ;根据上面的表创建了另外一张表
00401D20 . 8D95 90FDFFFF lea edx, dword ptr [ebp-270]
00401D26 . 8D8D 90FBFFFF lea ecx, dword ptr [ebp-470]
00401D2C . E8 1F1D0000 call 00403A50 ;用上面那张表解码sn
00401D31 . 66:83BD 0CFEF>cmp word ptr [ebp-1F4], 0 ;解码后长度必须为0x6c,且为0或1的字符
00401D39 . 0F85 65150000 jnz 004032A4
00401D3F . 66:83BD 0AFEF>cmp word ptr [ebp-1F6], 0
00401D47 . 0F84 57150000 je 004032A4
下面是解码后的sn,sn的第一个字节不解码
0019F660 30 00 31 00 30 00 30 00 31 00 31 00 31 00 30 00 0.1.0.0.1.1.1.0.
0019F670 31 00 31 00 31 00 31 00 31 00 30 00 31 00 30 00 1.1.1.1.1.0.1.0.
0019F680 31 00 30 00 30 00 31 00 30 00 31 00 31 00 30 00 1.0.0.1.0.1.1.0.
0019F690 31 00 30 00 31 00 30 00 31 00 30 00 31 00 30 00 1.0.1.0.1.0.1.0.
0019F6A0 31 00 30 00 31 00 31 00 31 00 31 00 31 00 31 00 1.0.1.1.1.1.1.1.
0019F6B0 30 00 30 00 30 00 31 00 30 00 31 00 30 00 31 00 0.0.0.1.0.1.0.1.
0019F6C0 30 00 31 00 31 00 31 00 30 00 30 00 0.1.1.1.0.0.
下面好多类似这样的
00401D73 . 8B3D 2CB04100 mov edi, dword ptr [<&KERNEL32.GetVe>; kernel32.GetVersion
00401D79 . 8985 34F2FFFF mov dword ptr [ebp-DCC], eax
00401D7F . C785 50F3FFFF>mov dword ptr [ebp-CB0], 0
00401D89 . FFD7 call edi ; <&KERNEL32.GetVersion>
00401D8B . 8B35 30B04100 mov esi, dword ptr [<&KERNEL32.LoadL>; kernel32.LoadLibraryW
00401D91 . 3C 06 cmp al, 6
00401D93 . 73 07 jnb short 00401D9C
00401D95 . 68 FC184200 push 004218FC ; UNICODE "apphelp_xp.dll"
00401D9A . EB 05 jmp short 00401DA1
00401D9C > 68 1C194200 push 0042191C ; UNICODE "apphelp.dll"
00401DA1 > FFD6 call esi
00401DA3 . 68 70194200 push 00421970 ; /ProcNameOrOrdinal = "SdbDeclareIndex"
00401DA8 . 50 push eax ; |hModule
00401DA9 . FF15 34B04100 call dword ptr [<&KERNEL32.GetProcAdd>; \GetProcAddress
我们先查一下这个API "SdbDeclareIndex" 是什么东东吧,发现是shim,以前没搞过,这里顺便学习一下。查阅MSDN了解各种API的功能及参数,对下面的破解很有效。
shim是为软件兼容及打补丁用的中间件,基于APP 和 API之间。了解这些后我们来看看crackme.exe的版本信息。
发现了一些奇怪的东西,好像同解码后的sn有关系。
开始使用IDA进行下一步分析。分析方式是通过MSDN把API信息补上,如下:
这里对时间设置了一下,TAG是TAG_TIME,代码是5001,所以sn的一部分应该是这个数字
经过OD动态跟踪发现
0012F7A4 31[0] 0.
0012F7B4 30[1] 30[4] 30[2] 30[5] 31[7] 31[3] 30[6] 0.0.1.1.1.1.1.
[]表示D几bit,正确组成5001的编码如下:
30 00 31 00 30 00 30 00 30 00 31 00 31 00 30 00
0.1.0.0.0.1.1.0.
下面比较有用的是TAG_COMPANY_NAME,正确的编码应该是版本信息中所显示的
TAG_COMPANY_NAME
0012F788 31 00 30 00 31 00 31 00 30 00 30 00 30 00 30 00 1.0.1.1.1.1.1.1.
0012F798 31 00 31 00 0.0.
31 00 30 00 31 00 31 00 30 00 30 00 30 00 30 00 31 00 31 00
10110000011
同样是版本信息中显示的
TAG_PRODUCT_NAME
0012F79E 30 00 31 00 31 00 31 00 31 00 30 00 31 00 30 00 0.1.1.1.1.0.1.0.
0012F7AE 31 00 31 00 1.1.
0111101011
TAG_PRODUCT_VERSION
应该是8, 4, 9, 3
0012F742 31 00 1.
0012F752 31 00 31 00 30 00 1.1.0.
正确的1000
0012F752 31 00 1.
0012F762 30 00 31 00 30 00 0.1.0.
正确的0100
0012F762 30 00 0.
0012F772 31 00 31 00 30 00 1.1.0.
正确的1001
0012F772 31 00 1.
0012F782 30 00 31 00 30 00 0.1.0.
正确的0011
TAG_BIN_FILE_VERSION
应该是8, 4, 9, 3
正确的
1110 + 6
1111 + b
1110 + 5
1110 + b
至此我们收集到了所有正确的 01 组合:
0012F748 31 00 31 00 31 00 30 00 31 00 30 00 30 00 30 00 1.1.1.0.1.0.0.0.
0012F758 31 00 31 00 31 00 31 00 30 00 31 00 30 00 30 00 1.1.1.1.0.1.0.0.
0012F768 31 00 31 00 31 00 30 00 31 00 30 00 30 00 31 00 1.1.1.0.1.0.0.1.
0012F778 31 00 31 00 31 00 30 00 30 00 30 00 31 00 31 00 1.1.1.0.0.0.1.1.
0012F788 31 00 30 00 31 00 31 00 30 00 30 00 30 00 30 00 1.0.1.1.0.0.0.0.
0012F798 30 00 31 00 31 00 30 00 31 00 31 00 31 00 31 00 0.1.1.0.1.1.1.1.
0012F7A8 30 00 31 00 30 00 31 00 31 00 30 00 31 00 30 00 0.1.0.1.1.0.1.0.
0012F7B8 30 00 30 00 31 00 31 00 30 00 30 00 0.0.1.1.0.0.
最后一位是 TAG_OS_PLATFORM,应该为 1,试出来的。如果编码sn后,解码时不对,调整最后一位即可。
是一个名称,应该跟shim的行为有关,查了一下为InjectDll,所以最后7个字符应该填充到相应位置上
0012EB94 0012F97C UNICODE "IuuuuuDuu"
InjectDll
0012F97C 49 00 73 00 6F 00 6A 00 68 00 79 00 44 00 71 00 I.s.o.j.h.y.D.q.
0012F98C 71 00 q.
正确的
s.o.j.h.y.q.q.
这个是注入的命令行,一个名称对应一个命令行,进一步验证上面的猜测。
关闭数据库,并且安装,启动新的crackme.exe,猜测新crackme进程会加载crackme.dll(毕竟上面是InjectDll),在crackme.dll中弹出"成功"对话框。
最后将结果编码成正确的sn。分析如下:
由于前几个字母必须为 acd_b 那么abcd对应的正确编码为(直接对应到我们逆出来01中)
a = 01 // 虽然没有a但是可以推出
b = 00
c = 11
d = 10
手动进行编码为
a
cddb
ccab
cdda
cdbc
dcbb
adcc
aadd
bca // 这里需要将 a -> b TAG_OS_PLATFORM,必须为1
sojhyqq
最终序列号为
acddbccabcddacdbcdcbbadccaaddbcasojhyqq
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]C++类成员指针调用 4320
- [原创]VMP3.2授权分析 53964
- [原创]看雪CTF2017 第十二题分析 5079
- [原创]看雪CTF2017 第十一题分析 6217
- [原创]看雪CTF2017 第十题分析 5832