一、初步分析
使用PeiD的插件分析,显示用了类似AES对称加密算法,miracl函数库。
知道是 MIRACL库,可以通过下面指令判断相关运算函数:mov dword ptr [esi+eax*4+20h],XXh
发现程序中存在花指令,干扰IDA反编译,可以手动去花,逻辑比较清楚,不能F5的关系也不大。
在strings window搜索到“************%s*************”,马上定位到核心算法sub_403160。
在403165处使用基于时间的反调试,只要不在此处调试即可跳过。
sub_401078将每个字符与所在index异或所得,即为s[index]=s[index]
xor index,index从1开始计数,执行2个sub_401078后获得success和error字符串。
之后要求字符长度为23。假设sn=”123456abcdABCDEF7890abc”
00403213 cmp eax, 17h
0018FF10 31 32 33 34 35 36 61 62 63 64 4142 43 44 45 46 123456abcdABCDEF
0018FF20 37 38 39 30 61 62 63 00 7890abc.
00403241 call sub_401172:将输入sn[4-23]由2进制转变为字符
0018FEB4 0018FF13 debug007:0018FF13
0018FEB8 00495660 CrackMe.exe:unk_495660
0018FEBC 00000014
二、验证函数1
sub_40125D为验证函数1,需要返回1。
跟踪sub_402630发现:
获得2个字符常量
0018FDE0 00 00 00 00 00 00 00 00 00 00 000033 32 3B 47 ............32;G
0018FDF0 47 44 30 4B 4D 3C 4E 4F 4E 38 3B25 20 24 57 24 GD0KM
0018FE00 22 52 2E 2F 21 5C 2E 5A 2D 28 2711 67 17 10 10 "R./!\.Z-('.g...
0018FE10 60 67 63 1A 1A 1F 6F 19 6E 1A 1671 75 76 04 06 `gc...o.n..quv..
0018FE20 71 04 73 7A 01 0E 0B 78 08 0D 0F7400 00 00 00 q.sz...x...t....
0018FB90 CC CC CC CC36 66 62 37 3C 6262 3E 3F 3A 3A 3A 烫烫6fb7?:::
0018FBA0 39 39 38 72 20 73 75 77 26 72 7420 7C 29 2B 25 998r suw&rt |)+%
0018FBB0 79 7D 2B 12 18 40 16 40 40 1E 121D 4F 1A 4F 1A y}+..@.@@...O.O.
0018FBC0 1C 18 4B 02 03 07 51 01 02 06 550E 01 58 03 04 ..K...Q...U..X..
0018FBD0 5C 0B 07 7500 00 00 00 00 00 00 00 00 00 00 00 \..u............
经sub_401078处理后,两个字符常量分别变成”208CBB…5304”和” 7da39d…a585”
0018FDE0 00 00 00 00 00 00 00 00 00 00 0000 32 30 38 43 ............208C
0018FDF0 42 42 37 43 44 36 45 43 43 36 3435 31 36 44 30 BB7CD6ECC64516D0
0018FE00 37 44 39 37 38 46 35 46 30 36 3831 46 35 33 34 7D978F5F0681F534
0018FE10 45 41 44 32 33 35 44 35 43 34 3941 44 44 37 32 EAD235D5C49ADD72
0018FE20 44 32 44 42 38 34 30 44 35 33 3034 00 00 00 00 D2DB840D5304....
0018FB90 CC CC CC CC 37 64 61 33 39 64 6536 36 30 31 36 烫烫7da39de66016
0018FBA0 34 37 37 62 31 61 66 63 33 64 6338 65 33 30 39 477b1afc3dc8e309
0018FBB0 64 63 34 32 39 62 35 64 65 38 3535 66 30 64 36 dc429b5de855f0d6
0018FBC0 31 36 64 32 32 35 62 35 37 30 6236 38 62 38 38 16d225b570b68b88
0018FBD0 61 35 38 35 00 00 00 00 00 00 0000 00 00 00 00 a585............
通过mov dword ptr [esi+eax*4+20h],XXh指令判断sub_40D1E0为cinstr
00402AB9 call cinstr_40D1E0:将sn[4-23]由字符串转换为大数
0018FB30 00731530
0018FB34 00495660
00495660 33 34 33 35 33 36 36 31 36 32 3633 36 34 34 31 3435366162636441
00495670 34 32 34 33 34 34 34 35 34 36 3337 33 38 33 39 4243444546373839
00495680 33 30 36 31 36 32 36 33 00 00 0000 00 00 00 00 30616263........
返回
00731530 05 00 00 00 3C 15 73 00 00 00 000063 62 61 30 ....<.s.....cba0
00731540 39 38 37 46 45 44 43 42 41 64 6362 61 36 35 34 987FEDCBAdcba654
00402ACF call cinstr_40D1E0:将字符常量” 7da39d…a585”转换为大数
0018FB30 007317B0
0018FB34 0018FB94
0018FB90 B0 17 73 0037 64 61 33 39 6465 36 36 30 31 36 ..s.7da39de66016
0018FBA0 34 37 37 62 31 61 66 63 33 64 6338 65 33 30 39 477b1afc3dc8e309
0018FBB0 64 63 34 32 39 62 35 64 65 38 3535 66 30 64 36 dc429b5de855f0d6
0018FBC0 31 36 64 32 32 35 62 35 37 30 6236 38 62 38 38 16d225b570b68b88
0018FBD0 61 35 38 3500 00 00 00 00 00 00 00 00 00 00 00 a585............
返回
007317B0 08 00 00 00 BC 17 73 00 00 00 000085 A5 88 8B ......s.....叆 垕
007317C0 B6 70 B5 25 D2 16 D6 F0 55 E8 5D9B 42 DC 09 E3 秔 ....逐 U鑍 汢...
007317D0 C8 3D FC 1A 7B 47 16 60 E6 9D A37D00 00 00 00 ....{G.`鏉....
00402AE3 call cinstr_40D1E0:将3e9转换为大数
0018FB30 00731670
0018FB34 004860A0
004860A0 33 65 3900 31 32 33 35 3637 33 38 39 3A 3B 3C 3e9.123567389:;<
返回
00731670 01 00 00 00 7C 16 73 00 00 00 0000E9 0300 00 ....|.s.........
sub_40C110为powmod操作
00402B26 call powmod_40C110:w=xy mod z,返回值放到[6913F0]
0018FB28 00691530 //x=sn[4-23]
0018FB2C 00691670 //y=3e9
0018FB30 006917B0 //z=7da3…585
0018FB34 006913F0 //w=
返回
006913F0 08 00 00 00 FC 13 69 00 00 00 00 0064 B6 42 9A ......i.....d禕.
00691400 EA 09 FC B9 3D A9 1C 96 35 82 6185 87 77 15 C7 .. =....俛厙w..
00691410 A5 AB FD A8 EC 33 6A DF 99 C5 403A 00 00 00 00 カ ..j邫臔:....
00402B40 call sub_40B280:将[6913F0]的数值存储到[18FD24]
0018FB28 00000000
0018FB2C 006913F0
0018FB30 0018FD24 //存储返回值
0018FB34 00000000
返回
0018FD20 00 00 00 00 3A 40 C5 99 DF 6A 33EC A8 FD AB A5 ....:@艡遤 3歙.
0018FD30 C7 15 77 87 85 61 82 35 96 1C A93D B9 FC 09 EA ..w噮 a......裹..
0018FD40 9A 42 B6 64 00 00 00 00 00 00 0000 00 00 00 00 欱禿............
00402BA7 call sub_40100F:将二进制数转换为字符表示。
0018FB2C 0018FD24
0018FB30 0018FC5C //存储返回值,初始值为0
0018FB34 00000020
0018FD20 00 00 00 00 3A 40 C5 99 DF 6A 33EC A8 FD AB A5 ....:@艡遤 3歙.
0018FD30 C7 15 77 87 85 61 82 35 96 1C A93D B9 FC 09 EA ..w噮 a......裹..
0018FD40 9A 42 B6 64 00 00 00 00 00 00 0000 00 00 00 00 欱禿............
返回
0018FC50 00 00 00 00 00 00 00 00 00 00 0000 33 41 34 30 ............3A40
0018FC60 43 35 39 39 44 46 36 41 33 33 45 4341 38 46 44 C599DF6A33ECA8FD
0018FC70 41 42 41 35 43 37 31 35 37 37 3837 38 35 36 31 ABA5C71577878561
0018FC80 38 32 33 35 39 36 31 43 41 39 3344 42 39 46 43 8235961CA93DB9FC
0018FC90 30 39 45 41 39 41 34 32 42 36 3634 00 00 00 00 09EA9A42B664....
00402BBD call _strcmp:要求w=xy mod z返回值与”208CBB…5304”相等
0018FB30 0018FDEC
0018FB34 0018FC5C
0018FDE0 00 00 00 00 00 00 00 00 00 00 0000 32 30 38 43 ............208C
0018FDF0 42 42 37 43 44 36 45 43 43 36 3435 31 36 44 30 BB7CD6ECC64516D0
0018FE00 37 44 39 37 38 46 35 46 30 36 3831 46 35 33 34 7D978F5F0681F534
0018FE10 45 41 44 32 33 35 44 35 43 34 3941 44 44 37 32 EAD235D5C49ADD72
0018FE20 44 32 44 42 38 34 30 44 35 33 3034 00 00 00 00 D2DB840D5304....
0018FC50 00 00 00 00 00 00 00 00 00 00 0000 33 41 34 30 ............3A40
0018FC60 43 35 39 39 44 46 36 41 33 33 4543 41 38 46 44 C599DF6A33ECA8FD
0018FC70 41 42 41 35 43 37 31 35 37 37 3837 38 35 36 31 ABA5C71577878561
0018FC80 38 32 33 35 39 36 31 43 41 39 3344 42 39 46 43 8235961CA93DB9FC
0018FC90 30 39 45 41 39 41 34 32 42 36 3634 00 00 00 00 09EA9A42B664....
破解思路:
已知Y=(G^X)mod P和Y,X,P,求解G
将P因数分解(http://factordb.com)
P=0x7da39de66016477b1afc3dc8e309dc429b5de855f0d616d225b570b68b88a585
=56828191929550499896142468009756520490526164668720784286547535509684830643589
=208096057845685678782766058500526476379*273086345401562743300402731618892888991
=0x9C8DD7C90A888F7374BFE3C485448C5B*0xCD72845A310C5CC5FF08D546717DBB9F
=a*b
Phi(P)=(a-1)*(b-1)= 7DA39DE66016477B1AFC3DC8E309DC41315D8C32B5412A98B1ECB7AB94C65D8C
[if !supportLists]è [endif]G= 69616D6168616E64736F6D656775796861686131
[if !supportLists]è [endif]sn[4-23]= iamahandsomeguyhaha1
三、验证函数2
sub_402FC0:判断输入的是否为数字,如果是则返回1;否则返回0
验证函数2位于sub_40128F,执行AES加密,对sn[1-3]进行操作,要求返回1。
0018FEBC 0018FF0C //sn[1-3]
改变18F980开始的前3个字节为sn[1], sn[2], sn[3]+[495728]。如果不是explorer打开进程的,dword_495728=1;如果是explorer打开进程的,dword_495728=2。
继续分析发现,有一个反调试的函数sub_40100A(),在里面判断了当前进程的父进程是否为explorer.exe,如果不是就将dword_495728赋值为1(dword_495728后面会用到),如果是则创建一个新的CrackMe进程,然后将dword_495728赋值为2,但创建新的CrackMe进程后,原程序就崩溃了,新进程执行时,dword_495728还是会被赋值为1,这个反调试就没有起到效果,感觉这里是作者的代码写的出了问题,故这个函数可以不用管。
区分是否用explorer打开进程的?如果不是explorer打开进程的,dword_495728=1;如果是explorer打开进程的,dword_495728=2。需要用到此值。
跟踪程序,发现将sn[1] sn[2] sn[3]+[495728]与”1314000000000”拼接作为密钥,对”pediy”加密,要求加密结果为0x912CA2036A9A0656D17B6B552F157F8E
00402F1E call _strcmp:要求两者值相等
0018F930 0018FB28
0018F934 0018FBF0
0018FB20 00 00 00 00 00 00 00 00 39 31 3243 41 32 30 33 ........912CA203
0018FB30 36 41 39 41 30 36 35 36 44 31 3742 36 42 35 35 6A9A0656D17B6B55
0018FB40 32 46 31 35 37 46 38 45 00 00 0000 00 00 00 00 2F157F8E........
0018FBF0 35 34 42 35 42 41 46 41 30 31 4338 45 35 32 33 54B5BAFA01C8E523
0018FC00 37 35 36 38 46 43 31 34 42 30 3638 44 37 35 35 7568FC14B068D755
总结:
40d760: AES加密生成密钥
40dc40: AES加密生成密文
v11明文: "pediy"
==> 函数结束变为密文
v27: 密钥表
v4: 密钥16 * 8 = 128bit 5211314000000000
v19: 正确的密文
输入的前三个字符,作为AES密钥的一部分,使用ECB模式,加密字符串pediy(需要补0),其结果与912CA2036A9A0656D17B6B552F157F8E对比。
另一种解法:
只要对3位数字进行爆破则可推导出sn[1-3]。不用全部逆向出函数功能。
sub_402D60通过输入内容运算,返回值判断是否成功
因为三位数字最多也就1000种可能性,直接注入dll暴力算
#include <stdio.h>
#include <windows.h>
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
{
int(*sub_402D60)(char *a1);
*(uintptr_t*)&sub_402D60 = (uintptr_t)GetModuleHandleW(0) + 0x2D60;
char test[4] = { "000" };
for (; test[0] <= '9'; test[0]++) {
for (; test[1] <= '9'; test[1]++) {
for (; test[2] <= '9'; test[2]++) {
if (sub_402D60(test)) {
MessageBoxA(0, test, 0, 0);
break;
}
}
test[2] = '0';
}
test[1] = '0';
}
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
结果弹窗显示出来: 520,即sn[1-3]=520
综合验证函数1和验证函数2,得出
sn=520iamahandsomeguyhaha1