Happytown的第35个crackme分析 注册机 ,CrackMe,happytown,加密算法 2008年06月22日 星期日 下午 11:51 【文章标题】: 【原创】Happytown的第35个crackme分析 注册机 【文章作者】: ylp1332 【作者邮箱】: ylp1332@yahoo.com.cn 【作者主页】: n/a 【作者QQ号】: n/a 【软件名称】: CrackMe_0035.exe 【软件大小】: 220k 【下载地址】: 自己搜索下载 【加壳方式】: none 【保护方式】: md5,大数运算 【编写语言】: visual c 6 【使用工具】: peid,ida,ollydbg,vc6 【操作平台】: win32 【软件介绍】: 非商业软件 【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教! -------------------------------------------------------------------------------- 【详细过程】 『分析过程』 1、首先用PEiD 0.94检查,用visual c 6编译,没有加壳。 2、用PEiD的插件Krypto ANAlyzer检查,发现有MD5算法和大数运算。 3、用IDA载入,进行初步的静态分析。 分析结论: 使用了Miracl大数运算库; 使用了标准的MD5算法; 使用Windows API GetDlgItemTextA从控件中取得用户名、组织和注册码, 用户名和组织名至少要2个字符长,注册码必须都是16进制字符,且不能为空。 验证过程的反汇编代码如下: .text:00401110 .text:00401110 ; =============== S U B R O U T I N E ======================================= .text:00401110 .text:00401110 .text:00401110 ; int __cdecl OnCheck(HWND hDlg) .text:00401110 OnCheck proc near ; CODE XREF: DialogFunc 55 p .text:00401110 .text:00401110 var_2C4 = dword ptr -2C4h .text:00401110 md5_str_out = dword ptr -2C0h .text:00401110 var_2BB = dword ptr -2BBh .text:00401110 var_2B7 = dword ptr -2B7h .text:00401110 var_2B3 = word ptr -2B3h .text:00401110 var_2B1 = byte ptr -2B1h .text:00401110 md5_ctx = dword ptr -2B0h .text:00401110 Serial = dword ptr -258h .text:00401110 UserName = byte ptr -190h .text:00401110 Group = byte ptr -0C8h .text:00401110 hDlg = dword ptr 4 .text:00401110 .text:00401110 sub esp, 2C4h .text:00401116 push ebx .text:00401117 push esi .text:00401118 push edi .text:00401119 mov ecx, 49 .text:0040111E xor eax, eax .text:00401120 lea edi, [esp 141h] .text:00401127 mov [esp 2D0h UserName], 0 .text:0040112F mov [esp 2D0h Group], 0 .text:00401137 rep stosd .text:00401139 stosw .text:0040113B stosb .text:0040113C mov ecx, 49 .text:00401141 xor eax, eax .text:00401143 lea edi, [esp 209h] .text:0040114A mov byte ptr [esp 2D0h Serial], 0 .text:0040114F rep stosd .text:00401151 stosw .text:00401153 stosb .text:00401154 mov ecx, 49 .text:00401159 xor eax, eax .text:0040115B lea edi, [esp 2D0h Serial 1] .text:0040115F mov byte ptr [esp 2D0h md5_str_out], 0 .text:00401164 rep stosd .text:00401166 stosw .text:00401168 stosb .text:00401169 xor eax, eax ; 使 eax = 0 .text:0040116B mov [esp 2D0h md5_str_out 1], eax .text:0040116F mov [esp 2D0h var_2BB], eax .text:00401173 mov [esp 2D0h var_2B7], eax .text:00401177 mov [esp 2D0h var_2B3], ax .text:0040117C push eax .text:0040117D push 300h .text:00401182 mov [esp 2D8h var_2B1], al .text:00401186 call _mirsys ; mirsys(300h,0h) .text:0040118B mov esi, [esp 2D8h hDlg] .text:00401192 mov edi, ds:GetDlgItemTextA .text:00401198 add esp, 8 .text:0040119B lea ecx, [esp 2D0h UserName] .text:004011A2 mov ebx, eax .text:004011A4 push 0C9h ; nMaxCount .text:004011A9 push ecx ; lpString .text:004011AA push 3EDh ; nIDDlgItem .text:004011AF push esi ; hDlg .text:004011B0 call edi ; GetDlgItemTextA .text:004011B2 cmp eax, 2 ; 用户名不少于2个字符 .text:004011B5 jnb short loc_4011C3 .text:004011B7 .text:004011B7 loc_4011B7: ; CODE XREF: OnCheck 135 j .text:004011B7 pop edi .text:004011B8 pop esi .text:004011B9 xor eax, eax .text:004011BB pop ebx .text:004011BC add esp, 2C4h .text:004011C2 retn .text:004011C3 ; --------------------------------------------------------------------------- .text:004011C3 .text:004011C3 loc_4011C3: ; CODE XREF: OnCheck A5 j .text:004011C3 lea edx, [esp 2D0h Group] .text:004011CA push 0C9h ; nMaxCount .text:004011CF push edx ; lpString .text:004011D0 push 3EEh ; nIDDlgItem .text:004011D5 push esi ; hDlg .text:004011D6 call edi ; GetDlgItemTextA .text:004011D8 cmp eax, 2 ; 组织名不少于2个字符 .text:004011DB jnb short loc_4011E9 .text:004011DD pop edi .text:004011DE pop esi .text:004011DF xor eax, eax .text:004011E1 pop ebx .text:004011E2 add esp, 2C4h .text:004011E8 retn .text:004011E9 ; --------------------------------------------------------------------------- .text:004011E9 .text:004011E9 loc_4011E9: ; CODE XREF: OnCheck CB j .text:004011E9 lea eax, [esp 2D0h Serial] .text:004011ED push 0C9h ; nMaxCount .text:004011F2 push eax ; lpString .text:004011F3 push 3EFh ; nIDDlgItem .text:004011F8 push esi ; hDlg .text:004011F9 call edi ; GetDlgItemTextA .text:004011FB test eax, eax ; 注册码不能为空 .text:004011FD jnz short loc_401209 .text:004011FF pop edi .text:00401200 pop esi .text:00401201 pop ebx .text:00401202 add esp, 2C4h .text:00401208 retn .text:00401209 ; --------------------------------------------------------------------------- .text:00401209 .text:00401209 loc_401209: ; CODE XREF: OnCheck ED j .text:00401209 mov al, byte ptr [esp 2D0h Serial] ; 取注册码的第一个字符 .text:0040120D test al, al .text:0040120F jz short loc_401253 .text:00401211 lea esi, [esp 2D0h Serial] ; 取注册码 .text:00401215 .text:00401215 loc_401215: ; CODE XREF: OnCheck 141 j .text:00401215 cmp dword_414FDC, 1 ; 循环检查注册码的每一个字符看是否是16进制字符,否则退出 .text:0040121C jle short loc_401232 .text:0040121E xor ecx, ecx .text:00401220 push 80h ; int .text:00401225 mov cl, [esi] .text:00401227 push ecx ; int .text:00401228 call __isctype .text:0040122D add esp, 8 .text:00401230 jmp short loc_401243 .text:00401232 ; --------------------------------------------------------------------------- .text:00401232 .text:00401232 loc_401232: ; CODE XREF: OnCheck 10C j .text:00401232 mov eax, off_414DD0 .text:00401237 xor edx, edx .text:00401239 mov dl, [esi] .text:0040123B mov al, [eax edx*2] .text:0040123E and eax, 80h .text:00401243 .text:00401243 loc_401243: ; CODE XREF: OnCheck 120 j .text:00401243 test eax, eax .text:00401245 jz loc_4011B7 .text:0040124B mov al, [esi 1] .text:0040124E inc esi .text:0040124F test al, al .text:00401251 jnz short loc_401215 .text:00401253 .text:00401253 loc_401253: ; CODE XREF: OnCheck FF j .text:00401253 lea ecx, [esp 2D0h Group] ; 取组织名 .text:0040125A push ebp .text:0040125B push ecx ; char * .text:0040125C call __strrev ; 将组织名字符串逆转 .text:00401261 mov edi, eax .text:00401263 or ecx, 0FFFFFFFFh .text:00401266 xor eax, eax .text:00401268 lea edx, [esp 2D8h UserName] ; 取用户名 .text:0040126F repne scasb .text:00401271 not ecx .text:00401273 sub edi, ecx .text:00401275 mov esi, edi .text:00401277 mov ebp, ecx .text:00401279 mov edi, edx .text:0040127B or ecx, 0FFFFFFFFh .text:0040127E repne scasb .text:00401280 mov ecx, ebp .text:00401282 dec edi .text:00401283 shr ecx, 2 .text:00401286 rep movsd .text:00401288 mov ecx, ebp .text:0040128A lea eax, [esp 2D8h md5_ctx] .text:0040128E and ecx, 3 .text:00401291 push eax .text:00401292 rep movsb ; 用户名和组织名的逆连接起来 .text:00401294 call _MD5_Init .text:00401299 lea edi, [esp 2DCh UserName] .text:004012A0 or ecx, 0FFFFFFFFh .text:004012A3 xor eax, eax .text:004012A5 lea edx, [esp 2DCh md5_ctx] .text:004012A9 repne scasb .text:004012AB not ecx .text:004012AD dec ecx .text:004012AE push ecx .text:004012AF lea ecx, [esp 2E0h UserName] .text:004012B6 push ecx .text:004012B7 push edx .text:004012B8 call _MD5_Update .text:004012BD lea eax, [esp 2E8h md5_ctx] .text:004012C1 lea ecx, [esp 2E8h md5_str_out] .text:004012C5 push eax .text:004012C6 push ecx .text:004012C7 call _MD5_Final .text:004012CC push 0 .text:004012CE mov dword ptr [ebx 234h], 10h ; mip->IOBASE = 16; .text:004012D8 call _mirvar .text:004012DD push 0 .text:004012DF mov esi, eax .text:004012E1 call _mirvar .text:004012E6 push 0 .text:004012E8 mov edi, eax .text:004012EA call _mirvar .text:004012EF push 0 .text:004012F1 mov ebp, eax .text:004012F3 call _mirvar .text:004012F8 push offset a97944b587e4991 ; "97944B587E49910C2DFDD84BA062BC8917B3085"... .text:004012FD push ebp .text:004012FE mov ebx, eax .text:00401300 call _cinstr .text:00401305 push offset a10001 ; "10001" .text:0040130A push edi .text:0040130B call _cinstr .text:00401310 lea edx, [esp 310h md5_str_out] .text:00401314 push ebx .text:00401315 push edx .text:00401316 push 16 .text:00401318 call _bytes_to_big .text:0040131D add esp, 48h .text:00401320 lea eax, [esp 2D4h Serial] ; 取用户输入的注册码,然后转化为大数,与计算出来的注册码比较 .text:00401324 push eax .text:00401325 push esi .text:00401326 call _cinstr .text:0040132B push esi .text:0040132C push ebp .text:0040132D push edi .text:0040132E push esi .text:0040132F call _powmod .text:00401334 push ebx .text:00401335 push esi .text:00401336 call _compare ; 大数比较。相等则注册成功,否则失败 .text:0040133B mov [esp 2F4h var_2C4], eax .text:0040133F push esi .text:00401340 call _mirkill .text:00401345 push edi .text:00401346 call _mirkill .text:0040134B push ebp .text:0040134C call _mirkill .text:00401351 push ebx .text:00401352 call _mirkill .text:00401357 add esp, 30h .text:0040135A call _mirexit .text:0040135F mov ecx, [esp 2D4h var_2C4] .text:00401363 xor eax, eax .text:00401365 pop ebp .text:00401366 pop edi .text:00401367 test ecx, ecx .text:00401369 pop esi .text:0040136A pop ebx .text:0040136B setz al .text:0040136E add esp, 2C4h .text:00401374 retn .text:00401374 OnCheck endp .text:00401374 注册码验证过程: 1、将用户名字符串和组织名字符串的逆串连接起来,用标准MD5算法计算该字符串hash值,将该hash串转化为大数H。 2、将注册码转化为大数S,进行模幂运算S^e mod p = C 3、如果H = C,则注册成功。 其中 e=10001h,p=97944B587E49910C2DFDD84BA062BC8917B3085FFAB61ABF930A8396CDE8B9E3h 可以看出整个验证过程很简单。 生成注册码的过程: 1、将用户名字符串和组织名字符串的逆串连接起来,用标准MD5算法计算该字符串hash值,将该hash串转化为大数H。 2、令 e*d mod p-1 = 1,则 d = e^-1 mod p-1。用扩展Euclid算法求得e关于模p-1的乘法逆元d,则有 S = C^e mod p = H^e mod p 3、将大数S转化为字符串,即为所求的注册码。 以下是一组正确的注册码: name: ylp1332 group: hahik serial: 52575D6C6D8A32B11FF6F8215B93DBC9AE89ACCFFECFCF89B6D442A484F54278 以下是keygen的主要代码,不含md5算法实现。 在visual c 6 with sp6 下编译通过。 #include #include #include "miracl.h" #include "md5.h" #pragma comment ( lib, "miracl.lib" ) #define MAXLEN 50 int main(int argc, char **argv) { char usr_name[ MAXLEN ] = {0}; char grp_name[ MAXLEN ] = {0}; char ser_code[ MAXLEN ] = {0}; char hash_out[ MAXLEN ] = {0}; struct MD5Context md5_ctx; miracl *mip; big x,y,z,w; char buf[ MAXLEN ]; // Your Name here, at least 2 chars ! strcpy( usr_name, "ylp1332" ); // Your Group here, at least 2 chars ! strcpy( grp_name, "hahik" ); printf(" name: %s\n", usr_name ); printf(" group: %s\n", grp_name ); memset( buf, 0, MAXLEN ); strcpy( buf, usr_name ); strcat( buf, _strrev(grp_name) ); MD5Init( &md5_ctx ); MD5Update( &md5_ctx, buf, strlen(buf) ); MD5Final( hash_out, &md5_ctx ); mip = mirsys( 0x300, 0 ); mip->IOBASE = 0x10; x = mirvar( 0 ); y = mirvar( 0 ); z = mirvar( 0 ); w = mirvar( 0 ); bytes_to_big( 16, hash_out, x ); cinstr( y, "648A7A87920C9DE7244271CB87F0B5F980FCC19B58229E0F602AE3298E1EC5DD" ); cinstr( z, "97944B587E49910C2DFDD84BA062BC8917B3085FFAB61ABF930A8396CDE8B9E3" ); powmod( x, y, z, w ); cotstr( w, ser_code ); printf(" serial: %s\n", ser_code ); mirkill( x ); mirkill( y ); mirkill( z ); mirkill( w ); mirexit(); return 0; } -------------------------------------------------------------------------------- 【经验总结】 静态分析和动态调试相结合。 大数运算要熟悉正逆向推导过程。 |
|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )
GMT+8, 2024-9-30 03:23 , Processed in 0.285120 second(s), 12 queries , Gzip On, MemCache On.
Powered by Discuz! X3.5
© 2001-2023 Discuz! Team.