好友
阅读权限 35
听众
最后登录 1970-1-1
solly
发表于 2019-7-15 02:25
本帖最后由 solly 于 2019-7-15 23:58 编辑
160 个 CrackMe 之 159 - Torn@do.2 是一个加了壳的 CrackMe ,文件信息如下:
显示未知的壳,用 "scan /t" 重新扫描一下:
这次显示为 "EncryptPE" 了。而且其文件末尾为字符串“eEnCrypter! :) 2nd&mi”,没见过,只有手动脱壳 了。
节信息如下:
看起来与我原来脱过的 043 Ding Boy 的壳很象,也是很多节,并依次对下一节解码,也就是节名为 ".Stone" 的节,都是解码用的。
在 Windows 10 下OD载入 CrackMe,如下图所示:
往下拖可以看到 0x0041F096 有一个 jmp eax,我们直接选择在这一条指令上按 F4 , 然后再 F8 就会跳转到下一节的解码代码,与这一节基本一样,也是到 jmp eax 处 F4, 再F8跳转到下一节的解码代码,这个操作有多次,一直来到下面代码处,如下图,才来到 OEP:
上图的 0x00403560 才是 OEP,到这里我们就可以脱壳了。
再往下拖一下,可以找到 WinMain() 函数的调用,如下图:
如上图,call 00401DE0 就是调用 WinMain() 函数。
我们先脱壳,脱壳后,我们运行一下,报一个错误,运行不了,错误提示如下所示:
是一个 API 函数的问题,这个 API 函数是 DefWindowProcA(),我们需要手动修复这个问题,我们重新来到 OEP。用“管理员身份运行” ImportREC,如下图所示:
可以看到,最后一行的 Thunk 的 Valid 为 NO,点击旁边的 ”Show Invalid" 按钮,如下图显示:
其中那条 NtdllDefWindowProc_A 就是要手动修复的,鼠标左键双击这一行,弹出手动导入表编辑对话框,如下图所示:
我们先在 "Module" 下拉列表中,将 “ntdll.dll” 改成 "User32.dll",如下图所示:
然后在 Function 列表中找到“DefWindowProcA”这一行并选择,如上图所示,选好后按 “OK” 即可,这时显示如下图:
所有的函数都有效了,这时就是可以 "Fix Dump" 了,如下图所示,选择要修复的 Dump 文件即可。
这样操作后,就可以正常在 Windows 10 运行了,如果还不行,还可以用 LordPE 来 dump,不用 OD 的 dump 功能,如下图所示:
再按前面的方法修复,就应该可以在 Windows 10 下运行了。
脱壳后,OD 重新载入 F9 直接运行,来到其界面:
随便输入几个信息,点“ValIDA te”,没有动静,按3次后,“Validate” 按钮不可用了,提示变成了:"TRY AGAIN!",如下图所示:
通过前面所述,我们知道 WinMain() 函数入口在 0x00401DE0,我们浏览一下这个 WinMain()函数,可以看到这是一个标准的 Windows 窗口API应用的代码,最后面是消息循环处理。
从最前的4行代码,我们找到了 WndProc 的入口为 0x00401FD0,如下所示:
[Asm] 纯文本查看 复制代码
00401DE0 83EC 4C sub esp, 4C
00401DE3 C74424 00 30000000 mov dword ptr [esp], 30
00401DEB C74424 04 03000000 mov dword ptr [esp+4], 3
00401DF3 C74424 08 D01F4000 mov dword ptr [esp+8], 00401FD0
我们跟随立即数,来到 0x00401FD0,如下所示,是 WndProc() 的主处理代码:
[Asm] 纯文本查看 复制代码
00401FD0 8B4C24 08 mov ecx, dword ptr [esp+8] ; nMessage
00401FD4 56 push esi
00401FD5 83F9 01 cmp ecx, 1 ; WM_CREATE
00401FD8 74 2F je short 00402009
00401FDA 83F9 02 cmp ecx, 2 ; WM_DESTROY
00401FDD 0F84 84000000 je 00402067
00401FE3 81F9 11010000 cmp ecx, 111 ; WM_COMMAND
00401FE9 0F84 86000000 je 00402075
00401FEF 8B4424 14 mov eax, dword ptr [esp+14] ; lParam
00401FF3 8B5424 10 mov edx, dword ptr [esp+10] ; wParam
00401FF7 8B7424 08 mov esi, dword ptr [esp+8] ; hWnd
00401FFB 50 push eax ; 默认消息处理
00401FFC 52 push edx
00401FFD 51 push ecx
00401FFE 56 push esi
00401FFF FF15 D4E24000 call dword ptr [<&USER32.DefWindowProcA>] ; ntdll.NtdllDefWindowProc_A
00402005 5E pop esi
00402006 C2 1000 retn 10
最后那个 call User32.DefWindowProcA 就是我们前面修复的那个 API 调用。
我们再次跟随 WM_CREATE 消息处理的“je 00402009”,来到 0x00402009,如下所示:
[Asm] 纯文本查看 复制代码
00402009 8B4424 14 mov eax, dword ptr [esp+14]
0040200D 68 F4010000 push 1F4
00402012 68 88C14000 push 0040C188 ; ASCII "F:\Downloads\crack\[url=mailto:159_Torn@do.2]159_Torn@do.2[/url]"
00402017 6A 00 push 0
00402019 8B48 04 mov ecx, dword ptr [eax+4]
0040201C 890D F8BE4000 mov dword ptr [40BEF8], ecx
00402022 FF15 64E24000 call dword ptr [<&KERNEL32.GetModuleHandleA>] ; KERNEL32.GetModuleHandleA
00402028 50 push eax
00402029 FF15 68E24000 call dword ptr [<&KERNEL32.GetModuleFileNameA>] ; KERNEL32.GetModuleFileNameA
0040202F 85C0 test eax, eax
00402031 74 10 je short 00402043
00402033 B9 5C000000 mov ecx, 5C
00402038 3888 88C14000 cmp byte ptr [eax+40C188], cl
0040203E 74 03 je short 00402043
00402040 48 dec eax
00402041 ^ 75 F5 jnz short 00402038
00402043 8B7424 08 mov esi, dword ptr [esp+8]
00402047 6A 00 push 0 ; lParam == 0x00000000
00402049 C680 88C14000 00 mov byte ptr [eax+40C188], 0
00402050 68 77777777 push 77777777 ; wParam == 0x77777777
00402055 68 11010000 push 111 ; nMessage == WM_COMMAND
0040205A 56 push esi
0040205B FF15 E4E24000 call dword ptr [<&USER32.PostMessageA>] ; USER32.PostMessageA
00402061 33C0 xor eax, eax
00402063 5E pop esi
00402064 C2 1000 retn 10
可以看到,在处理 WM_CREATE 消息时,在最后,给窗口 Post 了一条自定义的 WM_COMMAND 消息。我们再次回到前面的 WndProc()框架函数,来到 WM_COMMAND 消息处理跳转 "je 00402075",跟随这个跳转,来到 WM_COMMAND 消息处理代码处:
[Asm] 纯文本查看 复制代码
00402075 817C24 10 77777777 cmp dword ptr [esp+10], 77777777
0040207D 75 21 jnz short 004020A0
0040207F 8B7424 08 mov esi, dword ptr [esp+8]
00402083 6A 00 push 0
00402085 68 B0204000 push 004020B0
0040208A A1 F8BE4000 mov eax, dword ptr [40BEF8]
0040208F 56 push esi
00402090 6A 65 push 65
00402092 50 push eax
00402093 FF15 E0E24000 call dword ptr [<&USER32.DialogBoxParamA>] ; USER32.DialogBoxParamA
00402099 56 push esi
0040209A FF15 F0E24000 call dword ptr [<&USER32.DestroyWindow>] ; USER32.DestroyWindow
004020A0 33C0 xor eax, eax
004020A2 5E pop esi
004020A3 C2 1000 retn 10
这个消息处理非常简单,就是只要wParam为自定义的 0x77777777 就显示 CrackMe 的主对话框,因此这里就是显示主界面的地方,我们也找到了 DlgProc() 的入口为 0x004020B0。
再次“跟随立即数”,来到 0x004020B0,对话框消息处理框架代码如下:
[Asm] 纯文本查看 复制代码
004020B0 8B4424 08 mov eax, dword ptr [esp+8]
004020B4 53 push ebx
004020B5 56 push esi
004020B6 83F8 02 cmp eax, 2 ; WM_DESTROY
004020B9 57 push edi
004020BA 0F84 C6000000 je 00402186
004020C0 3D 10010000 cmp eax, 110 ; WM_INITDIALOG
004020C5 74 13 je short 004020DA
004020C7 3D 11010000 cmp eax, 111 ; WM_COMMAND
004020CC 0F84 9D000000 je 0040216F
004020D2 33C0 xor eax, eax
004020D4 5F pop edi
004020D5 5E pop esi
004020D6 5B pop ebx
004020D7 C2 1000 retn 10
我们跟随 WM_INITDIALOG 消息处理跳转 "je 004020DA" 后,可以看到这样一段代码:
[Asm] 纯文本查看 复制代码
004020F6 6A 00 push 0 ; 0 - Disabled, 1 - Enabled
004020F8 8B35 A0E24000 mov esi, dword ptr [<&USER32.GetDlgItem>] ; USER32.GetDlgItem
004020FE 68 EC030000 push 3EC ; "Request" ID
00402103 53 push ebx ; hDlg
00402104 FFD6 call esi ; call GetDlgItem()
00402106 50 push eax ; Control hwnd
00402107 FF15 98E24000 call dword ptr [<&USER32.EnableWindow>] ; USER32.EnableWindow
这段代码就是在 CrackMe 启动时将 "Request" 按钮的状态改为 "Disabled" 状态的。
我们再回到 DlgProc(),跟随处理 WM_COMMAND 跳转 "je 0040216F",来到其处理框架代码:
[Asm] 纯文本查看 复制代码
0040216F 8B4424 18 mov eax, dword ptr [esp+18]
00402173 25 FFFF0000 and eax, 0FFFF
00402178 3D EB030000 cmp eax, 3EB ; Validate 按钮
0040217D 7F 1B jg short 0040219A
0040217F 74 54 je short 004021D5 ; 跳转去进行注册验证
00402181 83F8 02 cmp eax, 2 ; WM_CLOSE
00402184 74 37 je short 004021BD
00402186 A1 08BE4000 mov eax, dword ptr [40BE08]
0040218B 50 push eax
0040218C FF15 F4E14000 call dword ptr [<&GDI32.DeleteObject>] ; GDI32.DeleteObject
00402192 33C0 xor eax, eax
00402194 5F pop edi
00402195 5E pop esi
00402196 5B pop ebx
00402197 C2 1000 retn 10
可以看到,跟随 “ je 004021D5” 后就可以到达注册验证的代码了:
[Asm] 纯文本查看 复制代码
004021D5 > \8B5C24 10 mov ebx, dword ptr [esp+10] ; Case 3EB of switch 00402178
004021D9 . 53 push ebx
004021DA . E8 31F1FFFF call 00401310 ; 假的序列号验证,实际取用户名
004021DF . 83C4 04 add esp, 4
004021E2 . 8BF8 mov edi, eax ; eax ===> "solly"
004021E4 . B9 FFFFFFFF mov ecx, -1
004021E9 . 2BC0 sub eax, eax
004021EB . F2:AE repne scas byte ptr es:[edi]
004021ED . F7D1 not ecx
004021EF . 2BF9 sub edi, ecx
004021F1 . 8BC1 mov eax, ecx
004021F3 . C1E9 02 shr ecx, 2
004021F6 . 8BF7 mov esi, edi
004021F8 . BF 30BF4000 mov edi, 0040BF30 ; ASCII "solly"
004021FD . F3:A5 rep movs dword ptr es:[edi], dword ptr [esi]
004021FF . 8BC8 mov ecx, eax
00402201 . 53 push ebx
00402202 . 83E1 03 and ecx, 3
00402205 . F3:A4 rep movs byte ptr es:[edi], byte ptr [esi]
00402207 . E8 74F1FFFF call 00401380 ; 假的序列号验证,实际取公司名
0040220C . 83C4 04 add esp, 4
0040220F . 8BF8 mov edi, eax ; eax ===> "company"
00402211 . B9 FFFFFFFF mov ecx, -1
00402216 . 2BC0 sub eax, eax
00402218 . F2:AE repne scas byte ptr es:[edi]
0040221A . F7D1 not ecx
0040221C . 2BF9 sub edi, ecx
0040221E . 8BD1 mov edx, ecx
00402220 . C1E9 02 shr ecx, 2
00402223 . 8BF7 mov esi, edi
00402225 . BF E0BD4000 mov edi, 0040BDE0 ; ASCII "company"
0040222A . F3:A5 rep movs dword ptr es:[edi], dword ptr [esi]
0040222C . 8BCA mov ecx, edx
0040222E . 53 push ebx
0040222F . 83E1 03 and ecx, 3
00402232 . F3:A4 rep movs byte ptr es:[edi], byte ptr [esi]
00402234 . E8 B7F1FFFF call 004013F0 ; 假的序列号验证,实际取序列名
00402239 . 83C4 04 add esp, 4
0040223C . 8BF8 mov edi, eax ; eax ===> "78787878"
0040223E . B9 FFFFFFFF mov ecx, -1
00402243 . 2BC0 sub eax, eax
00402245 . F2:AE repne scas byte ptr es:[edi]
00402247 . F7D1 not ecx
00402249 . 2BF9 sub edi, ecx
0040224B . 8BD1 mov edx, ecx
0040224D . C1E9 02 shr ecx, 2
00402250 . 8BF7 mov esi, edi
00402252 . BF 28BE4000 mov edi, 0040BE28 ; ASCII "78787878"
00402257 . F3:A5 rep movs dword ptr es:[edi], dword ptr [esi]
00402259 . 8BCA mov ecx, edx
0040225B . 83E1 03 and ecx, 3
0040225E . F3:A4 rep movs byte ptr es:[edi], byte ptr [esi]
00402260 . 53 push ebx ; EBX == 0x00B50DE8
00402261 . 68 28BE4000 push 0040BE28 ; ASCII "78787878"
00402266 . 68 E0BD4000 push 0040BDE0 ; ASCII "company"
0040226B . 68 30BF4000 push 0040BF30 ; ASCII "solly"
00402270 . E8 7BFAFFFF call 00401CF0 ; 真正的注册码验证位置
00402275 . 83C4 10 add esp, 10
00402278 . 66:833D 20BE4000 28 cmp word ptr [40BE20], 28 ; 是否成功!
00402280 . 75 1E jnz short 004022A0 ; [40BE20] == 0x28 表示成功!
00402282 . 6A 00 push 0 ; /lParam = NULL
00402284 . A1 F8BE4000 mov eax, dword ptr [40BEF8] ; |
00402289 . 68 A0254000 push 004025A0 ; |DlgProc = [url=mailto:Torn@do_.004025A0]Torn@do_.004025A0[/url]
0040228E . 53 push ebx ; |hOwner
0040228F . 6A 68 push 68 ; |pTemplate = 68
00402291 . 50 push eax ; |hInst => NULL
00402292 . FF15 E0E24000 call dword ptr [<&user32.DialogBoxParamA> ; \DialogBoxParamA
00402298 . 33C0 xor eax, eax
0040229A . 5F pop edi
0040229B . 5E pop esi
0040229C . 5B pop ebx
0040229D . C2 1000 retn 10
004022A0 > 66:A1 74A04000 mov ax, word ptr [40A074]
004022A6 . 66:40 inc ax
004022A8 . 66:A3 74A04000 mov word ptr [40A074], ax
004022AE . 66:3D 0300 cmp ax, 3 ; 尝试3次
004022B2 . 75 32 jnz short 004022E6
004022B4 . 6A 00 push 0 ; /Enable = FALSE
004022B6 . 8B35 A0E24000 mov esi, dword ptr [<&user32.GetDlgItem> ; |USER32.GetDlgItem
004022BC . 68 EB030000 push 3EB ; |/ControlID = 3EB (1003.)
004022C1 . 53 push ebx ; ||hWnd
004022C2 . FFD6 call esi ; |\GetDlgItem
004022C4 . 50 push eax ; |hWnd
004022C5 . 8B3D 98E24000 mov edi, dword ptr [<&user32.EnableWindow> ; |USER32.EnableWindow
004022CB . FFD7 call edi ; \EnableWindow
004022CD . 68 68A04000 push 0040A068 ; /Text = "TRY AGAIN!"
004022D2 . 68 EE030000 push 3EE ; |ControlID = 3EE (1006.)
004022D7 . 53 push ebx ; |hWnd
004022D8 . FF15 F8E24000 call dword ptr [<&user32.SetDlgItemTextA> ; \SetDlgItemTextA
004022DE . 66:A1 74A04000 mov ax, word ptr [40A074]
004022E4 . EB 0C jmp short 004022F2
004022E6 > 8B3D 98E24000 mov edi, dword ptr [<&user32.EnableWindow> ; USER32.EnableWindow
004022EC . 8B35 A0E24000 mov esi, dword ptr [<&user32.GetDlgItem> ; USER32.GetDlgItem
004022F2 > 66:A3 74A04000 mov word ptr [40A074], ax
004022F8 . 66:3D 0300 cmp ax, 3 ; 尝试3次
004022FC . 7E 21 jle short 0040231F
004022FE . 6A 00 push 0
00402300 . 68 EB030000 push 3EB
00402305 . 53 push ebx
00402306 . FFD6 call esi
00402308 . 50 push eax
00402309 . FFD7 call edi
0040230B . 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
0040230D . 68 98A74000 push 0040A798 ; |Title = "Message from TORN@DO"
00402312 . 68 10A74000 push 0040A710 ; |Text = "You're using a window editing tool like THE CUSTOMISER!",LF,"You have had 3 chances for entering the right code!",LF,"Do you think that's fair?"
00402317 . 6A 00 push 0 ; |hOwner = NULL
00402319 . FF15 DCE24000 call dword ptr [<&user32.MessageBoxA>] ; \MessageBoxA
0040231F > 33C0 xor eax, eax
00402321 . 5F pop edi
00402322 . 5E pop esi
00402323 . 5B pop ebx
00402324 . C2 1000 retn 10
从上面的我的注释中,可以看到,前面三次都是没有用的验证,迷惑用的,实际用途只是取界面上输入的三个字符串。直正的验证是如下代码处:
[Asm] 纯文本查看 复制代码
00402260 . 53 push ebx ; EBX == 0x00B50DE8
00402261 . 68 28BE4000 push 0040BE28 ; ASCII "78787878"
00402266 . 68 E0BD4000 push 0040BDE0 ; ASCII "company"
0040226B . 68 30BF4000 push 0040BF30 ; ASCII "solly"
00402270 . E8 7BFAFFFF call 00401CF0 ; 真正的注册码验证位置
00402275 . 83C4 10 add esp, 10
00402278 . 66:833D 20BE4000 28 cmp word ptr [40BE20], 28 ; 是否成功!
00402280 . 75 1E jnz short 004022A0 ; [40BE20] == 0x28 表示成功!
上面的 call 00401CF0 才是真正的验证代码,其代码下:
[Asm] 纯文本查看 复制代码
00401CF0 /$ 53 push ebx
00401CF1 |. 56 push esi
00401CF2 |. 8B5C24 14 mov ebx, dword ptr [esp+14] ; 序列号
00401CF6 |. 57 push edi
00401CF7 |. 55 push ebp
00401CF8 |. 53 push ebx
00401CF9 |. E8 F2FCFFFF call 004019F0 ; strcmp(),判断是否空串
00401CFE |. 83C4 04 add esp, 4
00401D01 |. 53 push ebx ; ebx ===> SN
00401D02 |. E8 19FAFFFF call 00401720 ; sn[0]~sn[4],固定字符 "IDC40"
00401D07 |. 83C4 04 add esp, 4
00401D0A |. 83F8 01 cmp eax, 1
00401D0D |. 74 0E je short 00401D1D
00401D0F |. 66:C705 20BE4000 FFFF mov word ptr [40BE20], 0FFFF
00401D18 |. 5D pop ebp
00401D19 |. 5F pop edi
00401D1A |. 5E pop esi
00401D1B |. 5B pop ebx
00401D1C |. C3 retn
00401D1D |> 8B6C24 20 mov ebp, dword ptr [esp+20]
00401D21 |. 8B7C24 18 mov edi, dword ptr [esp+18]
00401D25 |. 8B7424 14 mov esi, dword ptr [esp+14]
00401D29 |. 55 push ebp
00401D2A |. 53 push ebx
00401D2B |. 57 push edi
00401D2C |. 56 push esi
00401D2D |. E8 EEFCFFFF call 00401A20 ; 无用校验
00401D32 |. 83C4 10 add esp, 10
00401D35 |. 53 push ebx
00401D36 |. E8 55FAFFFF call 00401790 ; sn[6]~sn[9],固定字符 "ETBL"
00401D3B |. 83C4 04 add esp, 4
00401D3E |. 83F8 01 cmp eax, 1
00401D41 |. 74 0E je short 00401D51
00401D43 |. 66:C705 20BE4000 FFFF mov word ptr [40BE20], 0FFFF
00401D4C |. 5D pop ebp
00401D4D |. 5F pop edi
00401D4E |. 5E pop esi
00401D4F |. 5B pop ebx
00401D50 |. C3 retn
00401D51 |> 53 push ebx
00401D52 |. E8 89FAFFFF call 004017E0 ; 序列号最后4字符,当前时间校验
00401D57 |. 83C4 04 add esp, 4
00401D5A |. 83F8 01 cmp eax, 1
00401D5D |. 74 0E je short 00401D6D
00401D5F |. 66:C705 20BE4000 FFFF mov word ptr [40BE20], 0FFFF
00401D68 |. 5D pop ebp
00401D69 |. 5F pop edi
00401D6A |. 5E pop esi
00401D6B |. 5B pop ebx
00401D6C |. C3 retn
00401D6D |> 55 push ebp
00401D6E |. 53 push ebx
00401D6F |. 57 push edi
00401D70 |. 56 push esi
00401D71 |. E8 FAFDFFFF call 00401B70 ; 无用校验
00401D76 |. 83C4 10 add esp, 10
00401D79 |. A1 80C34000 mov eax, dword ptr [40C380] ; FirstInstallDateTime转换成字符串后的长度
00401D7E |. 50 push eax
00401D7F |. 53 push ebx
00401D80 |. E8 EBFAFFFF call 00401870 ; 注册表FirstInstallDateTime验证,但由于的BUG,变成固定数字(1702505)的验证
00401D85 |. 83C4 08 add esp, 8
00401D88 |. 83F8 01 cmp eax, 1
00401D8B |. 74 0E je short 00401D9B
00401D8D |. 66:C705 20BE4000 FFFF mov word ptr [40BE20], 0FFFF
00401D96 |. 5D pop ebp
00401D97 |. 5F pop edi
00401D98 |. 5E pop esi
00401D99 |. 5B pop ebx
00401D9A |. C3 retn
00401D9B |> 55 push ebp
00401D9C |. 53 push ebx
00401D9D |. 57 push edi
00401D9E |. 56 push esi
00401D9F |. E8 8CFEFFFF call 00401C30 ; 无用校验
00401DA4 |. 83C4 10 add esp, 10
00401DA7 |. 53 push ebx ; ebx ===> sn
00401DA8 |. E8 63FBFFFF call 00401910 ; 注册信息验证,包括注册表的 RegisteredOwner、输入的用户名和公司名验证
00401DAD |. 83C4 04 add esp, 4
00401DB0 |. 83F8 01 cmp eax, 1
00401DB3 |. 74 0E je short 00401DC3
00401DB5 |. 66:C705 20BE4000 FFFF mov word ptr [40BE20], 0FFFF
00401DBE |. 5D pop ebp
00401DBF |. 5F pop edi
00401DC0 |. 5E pop esi
00401DC1 |. 5B pop ebx
00401DC2 |. C3 retn
00401DC3 |> 55 push ebp
00401DC4 |. E8 97F6FFFF call 00401460 ; 设置成功状态
00401DC9 |. 83C4 04 add esp, 4
00401DCC |. 5D pop ebp
00401DCD |. 5F pop edi
00401DCE |. 5E pop esi
00401DCF |. 5B pop ebx
00401DD0 \. C3 retn
这里説明一下,从上面代码中可以看到,有一个时间验证(call 004017E0),代码如下:
[Asm] 纯文本查看 复制代码
004017E0 /$ 83EC 04 sub esp, 4
004017E3 |. 33C9 xor ecx, ecx
004017E5 |. 8D4424 01 lea eax, dword ptr [esp+1]
004017E9 |. 56 push esi
004017EA |. 8B5424 0C mov edx, dword ptr [esp+C] ; edx ===> SN
004017EE |. 57 push edi
004017EF |. 8BFA mov edi, edx ; edi ===> SN
004017F1 |. 884C24 08 mov byte ptr [esp+8], cl
004017F5 |. 66:8908 mov word ptr [eax], cx
004017F8 |. 8848 02 mov byte ptr [eax+2], cl
004017FB |. B9 FFFFFFFF mov ecx, -1
00401800 |. 2BC0 sub eax, eax
00401802 |. F2:AE repne scas byte ptr es:[edi]
00401804 |. F7D1 not ecx ; ecx = len(sn)+1
00401806 |. 8BFA mov edi, edx
00401808 |. 2BC0 sub eax, eax
0040180A |. 8A4C11 FB mov cl, byte ptr [ecx+edx-5] ; sn[len-4]
0040180E |. 884C24 08 mov byte ptr [esp+8], cl
00401812 |. B9 FFFFFFFF mov ecx, -1
00401817 |. F2:AE repne scas byte ptr es:[edi]
00401819 |. F7D1 not ecx ; ecx = len(sn)+1
0040181B |. 8BFA mov edi, edx
0040181D |. 8A4411 FC mov al, byte ptr [ecx+edx-4] ; sn[len-3]
00401821 |. B9 FFFFFFFF mov ecx, -1
00401826 |. 884424 09 mov byte ptr [esp+9], al
0040182A |. 2BC0 sub eax, eax
0040182C |. F2:AE repne scas byte ptr es:[edi]
0040182E |. F7D1 not ecx ; ecx = len(sn)+1
00401830 |. 8BFA mov edi, edx
00401832 |. 2BC0 sub eax, eax
00401834 |. 8A4C11 FD mov cl, byte ptr [ecx+edx-3] ; sn[len-2]
00401838 |. 884C24 0A mov byte ptr [esp+A], cl
0040183C |. B9 FFFFFFFF mov ecx, -1
00401841 |. F2:AE repne scas byte ptr es:[edi]
00401843 |. F7D1 not ecx ; ecx = len(sn)+1
00401845 |. 8D4424 08 lea eax, dword ptr [esp+8]
00401849 |. 8A5411 FE mov dl, byte ptr [ecx+edx-2] ; sn[len-1]
0040184D |. 885424 0B mov byte ptr [esp+B], dl
00401851 |. 50 push eax
00401852 |. E8 291C0000 call 00403480 ; atoi(sn[len-4][len-3][len-2][len-1])
00401857 |. 83C4 04 add esp, 4
0040185A |. 8BF0 mov esi, eax ; esi = 0
0040185C |. E8 3FFEFFFF call 004016A0 ; GetLocalTime
00401861 |. 2BC6 sub eax, esi ; eax = 0x0000081C = 2076
00401863 |. 5F pop edi
00401864 |. 5E pop esi
00401865 |. 83F8 01 cmp eax, 1
00401868 |. 1BC0 sbb eax, eax
0040186A |. 83C4 04 add esp, 4
0040186D |. F7D8 neg eax
0040186F \. C3 retn
其中又有一个调用(call 004016A0),就是根据当前时间生成一段注册验证,对注册码最后4个数字进行验证:
[Asm] 纯文本查看 复制代码
004016A0 /$ 83EC 10 sub esp, 10
004016A3 |. 8D4424 00 lea eax, dword ptr [esp]
004016A7 |. 56 push esi
004016A8 |. 50 push eax ; /pLocaltime
004016A9 |. FF15 6CE24000 call dword ptr [<&kernel32.GetLocalTime>] ; \GetLocalTime
004016AF |. 33D2 xor edx, edx
004016B1 |. 33C0 xor eax, eax
004016B3 |. 66:8B5424 06 mov dx, word ptr [esp+6] ; 月份 7
004016B8 |. 33C9 xor ecx, ecx
004016BA |. 66:8B4424 0A mov ax, word ptr [esp+A] ; 日 6
004016BF |. 0FAFD0 imul edx, eax ; EDX = 0x2A
004016C2 |. 66:8B4C24 0E mov cx, word ptr [esp+E] ; 分钟,cx = 0x09
004016C7 |. 8B4424 0C mov eax, dword ptr [esp+C] ; eax = 0x00090003
004016CB |. 25 FFFF0000 and eax, 0FFFF ; 小时 eax = 3
004016D0 |. 0FAFC1 imul eax, ecx ; eax == 0x1B
004016D3 |. 0FBE0D 60BF4000 movsx ecx, byte ptr [40BF60] ; RegisteredOwner[0],注册表项字符串的第1个字符的 ASCII 值。
004016DA |. 03D0 add edx, eax ; edx = 0x2A + 0x1B
004016DC |. 8B4424 04 mov eax, dword ptr [esp+4] ; ax = 2019
004016E0 |. 2BD1 sub edx, ecx ; ecx == RegisteredOwner[0]
004016E2 |. 25 FFFF0000 and eax, 0FFFF
004016E7 |. 8D3402 lea esi, dword ptr [edx+eax] ; esi = edx + eax + 0x45 + 0x7E3 = 69 + 2019 = 2088
004016EA |. 56 push esi
004016EB |. E8 A0FBFFFF call 00401290 ; 检查 SoftICE (Win9x) 调试
004016F0 |. 83C4 04 add esp, 4
004016F3 |. 85C0 test eax, eax
004016F5 |. 74 06 je short 004016FD
004016F7 |. 81C6 43010000 add esi, 143
004016FD |> 56 push esi
004016FE |. E8 CDFBFFFF call 004012D0 ; 检查 SoftICE (NT) 调试
00401703 |. 83C4 04 add esp, 4
00401706 |. 85C0 test eax, eax
00401708 |. 74 06 je short 00401710
0040170A |. 81C6 71020000 add esi, 271
00401710 |> 8BC6 mov eax, esi
00401712 |. 5E pop esi
00401713 |. 83C4 10 add esp, 10
00401716 \. C3 retn
也就是説,其验证时间精准到了分钟,生成的序列号有效时间最多60秒,如果注册机生成序列号与你输入序列号不是在同一分钟数字时(不是指1分钟内)序列号就是无效的,也就是説当输入序列号时,只要秒钟跨过了第59秒,就得重新生成序列号。
注册码前面两段是固定的,由 call 00401720 和 call 00401790 实现的,比较简单,这里不对其进行分析。
call 00401870 是对注册表中的一个值进行验证,这样,序列号与具体机器有关,不是通用的了,必须要有注册机才能搞定注册。这个调用是处理注册表中 FirstInstallDateTime 这个值的,不过这个值只有在 Windows 9x 系统下才有,Win NT 系列,如 Windows 10 下就没有这个注册表项。另外 CrackMe 还要用到一个注册表项: RegisteredOwner,这个也只有在 Windows 9x 下才有。这个调用的主要代码如下(其前面有一段代码中没有用的,迷惑用的,不贴上来了):
[Asm] 纯文本查看 复制代码
00401870 /$ 83EC 64 sub esp, 64
00401873 |. 53 push ebx
00401874 |. 56 push esi
00401875 |. 57 push edi
00401876 |. 33DB xor ebx, ebx ; int i = 0;
00401878 |. 8D7C24 0D lea edi, dword ptr [esp+D]
0040187C |. 55 push ebp
0040187D |. 33C0 xor eax, eax
0040187F |. B9 18000000 mov ecx, 18
00401884 |. 885C24 10 mov byte ptr [esp+10], bl ; sn_time[0] = '\0'
00401888 |. F3:AB rep stos dword ptr es:[edi] ; len 0x63
0040188A |. 66:AB stos word ptr es:[edi]
0040188C |. AA stos byte ptr es:[edi]
0040188D |. 33F6 xor esi, esi ; int j = 0;
0040188F |. 8B6C24 7C mov ebp, dword ptr [esp+7C] ; FirstInstallDateTime 转换成字符串后的长度 len(FirstInstallDateTime) = 7
00401893 |. 3BE8 cmp ebp, eax
00401895 |. 74 24 je short 004018BB
00401897 |. 8B5424 78 mov edx, dword ptr [esp+78] ; edx ===> SN
0040189B |> 8BFA /mov edi, edx
0040189D |. B9 FFFFFFFF |mov ecx, -1
004018A2 |. 2BC0 |sub eax, eax
004018A4 |. F2:AE |repne scas byte ptr es:[edi]
004018A6 |. F7D1 |not ecx
004018A8 |. 49 |dec ecx ; len(sn)
004018A9 |. 46 |inc esi ; j ++
004018AA |. 2BCD |sub ecx, ebp ; len(sn) - len(company)
004018AC |. 03CB |add ecx, ebx ; c = len(sn) - len(company) + i
004018AE |. 43 |inc ebx ; i++
004018AF |. 3BF5 |cmp esi, ebp ; j<len(company)
004018B1 |. 8A4411 FB |mov al, byte ptr [ecx+edx-5] ; sn[c-5]
004018B5 |. 884434 0F |mov byte ptr [esp+esi+F], al
004018B9 |.^ 72 E0 \jb short 0040189B
004018BB |> 8D4424 10 lea eax, dword ptr [esp+10] ; sn_time == sn[installtime]段
004018BF |. 50 push eax
004018C0 |. E8 BB1B0000 call 00403480 ; atoi(FirstInstallTime) = 0x0019FA69 = 1702505
004018C5 |. 83C4 04 add esp, 4
004018C8 |. 8BF0 mov esi, eax
004018CA |. A1 FCBE4000 mov eax, dword ptr [40BEFC] ; [0x0040BEFC] == 0x0019FA74 == 1702516, FirstInstallTime
004018CF |. 894424 10 mov dword ptr [esp+10], eax ; eax == 1702516
004018D3 |. C74424 14 00000000 mov dword ptr [esp+14], 0
004018DB |. DF6C24 10 fild qword ptr [esp+10]
004018DF |. D9C0 fld st
004018E1 |. E8 731C0000 call 00403559 ; tanh(1702516) = 1.0000
004018E6 |. DC0D 20904000 fmul qword ptr [409020] ; 1.0 * 11.00
004018EC |. DEE9 fsubp st(1), st ; 1702516-11=1702505
004018EE |. E8 590D0000 call 0040264C
004018F3 |. 2BC6 sub eax, esi ; eax = 0x0019FA69 = 1702505
004018F5 |. 5D pop ebp
004018F6 |. 5F pop edi
004018F7 |. 83F8 01 cmp eax, 1
004018FA |. 1BC0 sbb eax, eax
004018FC |. 5E pop esi
004018FD |. F7D8 neg eax
004018FF |. 5B pop ebx
00401900 |. 83C4 64 add esp, 64
00401903 \. C3 retn
就是将 FirstInstallDateTime 进行简单计算后,与输入的序列号相关字段进行比较,相等即通过。
还有一个调用(call 00401910)就是对我们在界面上输入的用户名和公司名进行校验,当中还包括注册表项 RegisteredOwner 的验证,如下:
[Asm] 纯文本查看 复制代码
00401910 /$ 83EC 64 sub esp, 64
00401913 |. 33C0 xor eax, eax
00401915 |. B9 18000000 mov ecx, 18 ; ecx == 0x18 == 24
0040191A |. 56 push esi
0040191B |. C64424 04 00 mov byte ptr [esp+4], 0
00401920 |. 57 push edi
00401921 |. 8D7C24 09 lea edi, dword ptr [esp+9]
00401925 |. F3:AB rep stos dword ptr es:[edi]
00401927 |. 66:AB stos word ptr es:[edi]
00401929 |. BE 0C000000 mov esi, 0C ; int i = 12
0040192E |. B9 FFFFFFFF mov ecx, -1
00401933 |. AA stos byte ptr es:[edi]
00401934 |. 8B5424 70 mov edx, dword ptr [esp+70] ; edx ===> SN
00401938 |. 2BC0 sub eax, eax
0040193A |. 8BFA mov edi, edx ; edi ===> SN
0040193C |. F2:AE repne scas byte ptr es:[edi]
0040193E |. F7D1 not ecx
00401940 |. 49 dec ecx ; ecx = len(sn) = 0x21 = 33
00401941 |. 2B0D 80C34000 sub ecx, dword ptr [40C380] ; FirstInstallDateTime 转换成字符串后的长度
00401947 |. 83E9 05 sub ecx, 5 ; 5 (当前时间的长度 "-nnnn")
0040194A |. 3BCE cmp ecx, esi ; len(sn) - 12 <= 12
0040194C |. 76 24 jbe short 00401972
0040194E |> 8A4432 FF /mov al, byte ptr [edx+esi-1] ; sn[i-1]
00401952 |. 46 |inc esi ; i++
00401953 |. 8BFA |mov edi, edx ; edi ====> sn
00401955 |. B9 FFFFFFFF |mov ecx, -1
0040195A |. 884434 FB |mov byte ptr [esp+esi-5], al ; tmp[i-12] = sn[i-1]
0040195E |. 2BC0 |sub eax, eax
00401960 |. F2:AE |repne scas byte ptr es:[edi]
00401962 |. F7D1 |not ecx
00401964 |. 49 |dec ecx
00401965 |. 2B0D 80C34000 |sub ecx, dword ptr [40C380] ; FirstInstallDateTime 转换成字符串后的长度
0040196B |. 83E9 05 |sub ecx, 5 ; 5 (当前时间的长度 "-nnnn")
0040196E |. 3BCE |cmp ecx, esi
00401970 |.^ 77 DC \ja short 0040194E
00401972 |> 8D4424 08 lea eax, dword ptr [esp+8] ; eax ===> "398378258"
00401976 |. 50 push eax
00401977 |. E8 041B0000 call 00403480 ; atoi()
0040197C |. 83C4 04 add esp, 4
0040197F |. 8BF8 mov edi, eax ; eax == 0x17BEC512 == 398378258
00401981 |. E8 0AFCFFFF call 00401590 ; RegisteredOwner索引check
00401986 |. 8BF0 mov esi, eax ; eax == 0x14 == 20
00401988 |. E8 B3FBFFFF call 00401540 ; RegisteredOwner内容check
0040198D |. 33F0 xor esi, eax ; eax == 0x01BA == 442, esi = 0x01AE == 430
0040198F |. 68 E0BD4000 push 0040BDE0 ; ASCII "ite company"
00401994 |. 68 30BF4000 push 0040BF30 ; ASCII "solly88"
00401999 |. E8 42FCFFFF call 004015E0 ; 注册名和公司名 checkcode
0040199E |. 83C4 08 add esp, 8
004019A1 |. 03C6 add eax, esi ; long a = checkcode + regOwner_check
004019A3 |. 8D0CC0 lea ecx, dword ptr [eax+eax*8] ; ecx == a * 9
004019A6 |. 8D14C8 lea edx, dword ptr [eax+ecx*8] ; edx == a * 73
004019A9 |. 8D0C52 lea ecx, dword ptr [edx+edx*2] ; ecx == a * 219 = 778983
004019AC |. C1E1 02 shl ecx, 2 ; ecx == a * 876
004019AF |. 2BC8 sub ecx, eax ; ecx == a * 875
004019B1 |. C1E1 06 shl ecx, 6 ; ecx == a * 875*64 = a * 56000
004019B4 |. 2BC8 sub ecx, eax ; ecx == a * 55999
004019B6 |. 03C9 add ecx, ecx ; ecx == a * 111998
004019B8 |. 894C24 08 mov dword ptr [esp+8], ecx ; ecx == 0x17BEBFB6 = 398376886
004019BC |. C74424 0C 00000000 mov dword ptr [esp+C], 0
004019C4 |. DF6C24 08 fild qword ptr [esp+8]
004019C8 |. D9C0 fld st
004019CA |. D9FE fsin ; sin(398376886) = -0.6866350580165284495
004019CC |. DC0D 28904000 fmul qword ptr [409028] ; [0x00409029] = 1999.0000, sin()*1999 = -1372.5834809750404020
004019D2 |. DEE9 fsubp st(1), st ; st == 398378258.58348095420 = 398376886 - (-1372.5834809750404020)
004019D4 |. E8 730C0000 call 0040264C ; eax == 0x17BEC512 == 398378258
004019D9 |. 2BC7 sub eax, edi ; edi = atoi()
004019DB |. 5F pop edi
004019DC |. 5E pop esi
004019DD |. 83F8 01 cmp eax, 1
004019E0 |. 1BC0 sbb eax, eax
004019E2 |. 83C4 64 add esp, 64
004019E5 |. F7D8 neg eax
004019E7 \. C3 retn
其中,对用户名和公司名处理的调用(call 004015E0)如下所示:
[Asm] 纯文本查看 复制代码
004015E0 /$ 83EC 08 sub esp, 8
004015E3 |. 33D2 xor edx, edx ; long sum = 0;
004015E5 |. B9 FFFFFFFF mov ecx, -1
004015EA |. 53 push ebx
004015EB |. 66:BB 0100 mov bx, 1 ; int i = 1
004015EF |. 56 push esi
004015F0 |. 8B7424 14 mov esi, dword ptr [esp+14] ; esi ===> "solly"
004015F4 |. 57 push edi
004015F5 |. 8BFE mov edi, esi ; edi ===> "solly"
004015F7 |. 2BC0 sub eax, eax
004015F9 |. F2:AE repne scas byte ptr es:[edi]
004015FB |. F7D1 not ecx
004015FD |. 49 dec ecx ; ecx == 用户名长度
004015FE |. 83F9 01 cmp ecx, 1
00401601 |. 76 2F jbe short 00401632
00401603 |> 0FBFC3 /movsx eax, bx ; i
00401606 |. 0FBE4430 FF |movsx eax, byte ptr [eax+esi-1] ; eax == name[i-1]
0040160B |. 8BC8 |mov ecx, eax ; ecx == name[i-1]
0040160D |. C1E0 02 |shl eax, 2 ; eax == name[i-1] * 4
00401610 |. 66:43 |inc bx ; i++
00401612 |. 8BFE |mov edi, esi ; edi ===> "solly"
00401614 |. 8D04C0 |lea eax, dword ptr [eax+eax*8] ; eax == name[i-1] * 36, (4*8+4)
00401617 |. 8D0CC1 |lea ecx, dword ptr [ecx+eax*8] ; ecx == name[i-1] * 289, (36*8+1)
0040161A |. 8D04C9 |lea eax, dword ptr [ecx+ecx*8] ; eax == name[i-1] * 2601, (289*9)
0040161D |. B9 FFFFFFFF |mov ecx, -1
00401622 |. 03D0 |add edx, eax ; sum += eax;
00401624 |. 2BC0 |sub eax, eax
00401626 |. F2:AE |repne scas byte ptr es:[edi]
00401628 |. 0FBFC3 |movsx eax, bx ; i
0040162B |. F7D1 |not ecx
0040162D |. 49 |dec ecx ; len(solly)
0040162E |. 3BC8 |cmp ecx, eax ; i<len(name)
00401630 |.^ 77 D1 \ja short 00401603 ; sum = 0x00118ACA
00401632 |> 66:BB 0100 mov bx, 1 ; int i = 1
00401636 |. 8B7424 1C mov esi, dword ptr [esp+1C] ; esi ===> "company"
0040163A |. 8BFE mov edi, esi ; edi ===> "company"
0040163C |. B9 FFFFFFFF mov ecx, -1
00401641 |. 2BC0 sub eax, eax
00401643 |. F2:AE repne scas byte ptr es:[edi]
00401645 |. F7D1 not ecx
00401647 |. 49 dec ecx ; len(company)
00401648 |. 83F9 01 cmp ecx, 1
0040164B |. 76 21 jbe short 0040166E
0040164D |> 0FBFC3 /movsx eax, bx ; i
00401650 |. 66:43 |inc bx ; i++
00401652 |. 8BFE |mov edi, esi ; edi ===> "company"
00401654 |. 0FBE4C30 FF |movsx ecx, byte ptr [eax+esi-1] ; company[i-1]
00401659 |. 03D1 |add edx, ecx ; sum += company[i-1]
0040165B |. B9 FFFFFFFF |mov ecx, -1
00401660 |. 2BC0 |sub eax, eax
00401662 |. F2:AE |repne scas byte ptr es:[edi]
00401664 |. 0FBFC3 |movsx eax, bx ; i
00401667 |. F7D1 |not ecx
00401669 |. 49 |dec ecx ; len(company)
0040166A |. 3BC8 |cmp ecx, eax ; i<len(company)
0040166C |.^ 77 DF \ja short 0040164D ; sum == 0x00118D48
0040166E |> 8D0492 lea eax, dword ptr [edx+edx*4] ; eax = sum * 5
00401671 |. 8D0C42 lea ecx, dword ptr [edx+eax*2] ; ecx = sum * 11
00401674 |. 894C24 0C mov dword ptr [esp+C], ecx ; ecx == 0x00C11218 == 12653080
00401678 |. C74424 10 00000000 mov dword ptr [esp+10], 0
00401680 |. DF6C24 0C fild qword ptr [esp+C]
00401684 |. D9FA fsqrt ; sqrt(12653080) == 3557.1168100021682220
00401686 |. E8 C10F0000 call 0040264C ; eax == 0x0DE5 == 3557
0040168B |. 5F pop edi
0040168C |. 5E pop esi
0040168D |. 5B pop ebx
0040168E |. 83C4 08 add esp, 8
00401691 \. C3 retn
另外对 RegisteredOwner 的验证有两次,比较简单,见注册机,不在此分析。另外,前面时间验证中,也用到了 RegisteredOwner 字符串的第1个字符(RegisteredOwner[0])的 ASCII 码值。
因为其有对注册表项进行验证,所以其需要读取注册表中的数据,不过,其在读取 FirstInstallDateTime 有问题,并没有取得这个值,而是取得保存这个值的地址,将这个地址参与了序列号的计算,这段取注册表信息的代码如下:
[Asm] 纯文本查看 复制代码
00401E59 |. 68 F8A64000 push 0040A6F8 ; ASCII "FirstInstallDateTime"
00401E5E |. 68 CCA64000 push 0040A6CC ; ASCII "SOFTWARE\Microsoft\Windows\CurrentVersion"
00401E63 |. 68 02000080 push 80000002
00401E68 |. E8 43F6FFFF call 004014B0 ; 读注册表,返回结果是一个地址,存于 EAX 并返回。
00401E6D |. 83C4 0C add esp, 0C
00401E70 |. 8B2D B4E24000 mov ebp, dword ptr [<&user32.wsprintfA>] ; USER32.wsprintfA
00401E76 |. 50 push eax ; /<%lu>,这里有Bug,传入的不是读取的时间,而是指向时间的地址指针,固定为 0x0019FA74
00401E77 |. 68 C8A64000 push 0040A6C8 ; |Format = "%lu",此格式是将返回地址当作一个无符号长整数进行操作
00401E7C |. 68 90BF4000 push 0040BF90 ; |s = [url=mailto:Torn@do_.0040BF90]Torn@do_.0040BF90[/url]
00401E81 |. FFD5 call ebp ; \wsprintfA
00401E83 |. 83C4 0C add esp, 0C
00401E86 |. BF 90BF4000 mov edi, 0040BF90 ; ASCII "1702516"
00401E8B |. 68 90BF4000 push 0040BF90 ; ASCII "1702516"
00401E90 |. E8 EB150000 call 00403480 ; atoi(pointer)
00401E95 |. 83C4 04 add esp, 4
00401E98 |. B9 FFFFFFFF mov ecx, -1
00401E9D |. A3 FCBE4000 mov dword ptr [40BEFC], eax ; 保存 0x0019FA74,实际是一个地址指针,不是注册表的 FirstInstallDateTime
00401EA2 |. 2BC0 sub eax, eax
00401EA4 |. F2:AE repne scas byte ptr es:[edi]
00401EA6 |. F7D1 not ecx
00401EA8 |. 49 dec ecx ; 前面timestamp字符串的长度
00401EA9 |. 68 B8A64000 push 0040A6B8 ; ASCII "RegisteredOwner"
00401EAE |. 68 CCA64000 push 0040A6CC ; ASCII "SOFTWARE\Microsoft\Windows\CurrentVersion"
00401EB3 |. 890D 80C34000 mov dword ptr [40C380], ecx ; 保存时间字符串的长度
00401EB9 |. 68 02000080 push 80000002
00401EBE |. E8 EDF5FFFF call 004014B0 ; 读注册表
问题出在调用 wsprintf() 这个函数的参数,因为 Call 004014B0 这个函数读取注册表信息后,返回的是一个地址,而 wsprintf()中,引用的是这个地址,所以转换成字符串也是一个地址值,不是真正的 FirstInstallDateTime的值,如果要修改这个 Bug,可以进行以下修改,如下图所示:
将 0x00401E6D处的 add esp, 0C 改成 mov eax, [eax],然后在下面 0x00401E83 处的 add esp, 0C 改成 add esp, 18,这样堆栈也平衡了,Bug也消除了。
基本的注册验证过程分析到这里,用注册机生成注册码,并抓紧时间输入(粘贴),校验正确时,显示如下:
一定要注意时间,最好在当前分钟的前 0~30秒内生成序列号,后30秒来输入注册码并验证,不然可能序列号就过期了。
另外,在 Windows 10 之类的新版 Windows 下,缺少注册表项,需要导入以下信息,不然也通不过 CrackMe 的注册验证,64位系统 如下:
[HTML] 纯文本查看 复制代码
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion]
"FirstInstallDateTime"=hex:c1,b1,98,4c
"RegisteredOrganization"="ite"
"RegisteredOwner"="solly"
"ProductId"="51163-030-0389753-07447"
32位系统 如下:
[HTML] 纯文本查看 复制代码
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion]
"FirstInstallDateTime"=hex:c1,b1,98,4c
"RegisteredOrganization"="ite"
"RegisteredOwner"="solly"
"ProductId"="51163-030-0389753-07447"
当然,键值可以改成自己的,键名不能改动。
分析完毕,下面是注册机源码,使用 Dev-C++调试通过:
[Asm] 纯文本查看 复制代码
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <windows.h>
union CBData{
DWORD n;
byte buffer[256];
};
CBData readKey(HKEY hKey, char * path, char * key);
void getRegInfo();
void getPart1();
void getPart2();
long getRegTimeStamp(int index);
long getCheckRegOwner();
long getCheck(char * name, char * company, int index);
void getCurrDateTime(int index);
bool testSoftICE95();
bool testSoftICENT();
char sn[48];
CBData data;
long nFirstInstallDateTime = 0;
long nLenOfFirstInstallDateTime = 0;
char sFirstInstallDateTime[128];
char RegisteredOwner[128];
char RegisteredOrganization[128];
char ProductId[128];
int main(int argc, char** argv) {
memset(sn, 0, 48);
memset(sFirstInstallDateTime, 0, 128);
memset(RegisteredOwner, 0, 128);
memset(RegisteredOrganization, 0, 128);
memset(ProductId, 0, 128);
getRegInfo();
getPart1();
sn[5] = '-';
getPart2();
sn[10] = '-';
char name[] = "solly88";
char company[] = "ite company";
int n = getCheck(name, company, 11);
sn[10+n+1] = '-';
int m = getRegTimeStamp(10+n+2);
sn[10+n+2+m] = '-';
/// 最后4字节为当前时间检查
getCurrDateTime(10+n+3+m);
printf("\n SN = %s\n", sn);
return 0;
}
void getPart1() {
sn[1] = 0x0D ^ 0x49;
sn[2] = 0x07 ^ 0x44;
sn[3] = 0x0D ^ 0x39;
sn[0] = 0x1D ^ 0x54;
sn[4] = 0x09 ^ 0x39;
}
void getPart2() {
sn[7] = 0x06 ^ 0x52;
sn[8] = 0x07 ^ 0x45;
sn[9] = 0x1F ^ 0x53;
sn[6] = 0x11 ^ 0x54;
}
/**
***/
/// FirstInstallTime
long getRegTimeStamp(int index) {
/// 0040BF90: 1702516
//long a = 1702505;
////
//long FirstInstallDateTime = 1702516; /// 实际上是一个指向保存FirstInstallDateTime的内存地址 Win10
//long FirstInstallDateTime = 6617404; /// 实际上是一个指向保存FirstInstallDateTime的内存地址 Win98
//long FirstInstallDateTime = 6682940; /// 实际上是一个指向保存FirstInstallDateTime的内存地址 Win98_unpacked
long FirstInstallDateTime = nFirstInstallDateTime; /// 正常时是一个 Timestamp
long a = FirstInstallDateTime - tanh(FirstInstallDateTime) * 11.0; /// 当在win10下取的是地址时,这里是固定值 1702505
//char str_a[8];
sprintf(sFirstInstallDateTime, "%d", a);
long n = strlen(sFirstInstallDateTime);
for(int i=0; i<n; i++ ) {
sn[index + i] = sFirstInstallDateTime[i];
}
return n;
}
long getCheckRegOwner() { // Proc_00401590 和 Proc_00401540
long sum1 = 0;
long sum2 = 0;
long n = strlen(RegisteredOwner);
for(int i=1; i<n; i++) {
sum1 += i*2;
sum2 += RegisteredOwner[i-1];
}
//printf("check reg owner: %d - %d\n", sum1, sum2);
return sum1 ^ sum2;
}
long getCheck(char * name, char * company, int index) { /// Proc_004015E0
long checkbase = getCheckRegOwner();
long sum = 0;
int n = strlen(name);
for(int i=0; i<n-1; i++) {
sum += name[i] * 2601;
}
int m = strlen(company);
for(int i=0; i<m-1; i++) {
sum += company[i];
}
double x = sum * 11;
int code1 = (long)sqrt(x);
////
//printf("check code1: %d, %d\n", sum, code1);
long a = code1 + checkbase;
long c = a * 111998;
double y = c - sin(c) * 1999.0;
long code2 = (long)y;
//printf("check code2: %d\n", code2);
char code_str[12];
sprintf(code_str, "%d", code2);
int len = strlen(code_str);
for(int i=0; i<len; i++) {
sn[index+i] = code_str[i];
}
return len;
}
bool testSoftICE95() {
HANDLE h = CreateFile("\\\\.\\SICE",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if(h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
return true;
}
return false;
}
bool testSoftICENT() {
HANDLE h = CreateFile("\\\\.\\NTICE",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if(h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
return true;
}
return false;
}
/// Current date and time
void getCurrDateTime(int index) {
long a = RegisteredOwner[0];
time_t timer;
struct tm * st;
time(&timer);
st = localtime(&timer);
long t = (st->tm_year + 1900) + ((st->tm_mon + 1) * st->tm_mday - a) + st->tm_hour * st->tm_min;
///// SoftICE 检查,修正时间检查值(基本无用)
bool isExistsSICE95 = testSoftICE95();
bool isExistsSICENT = testSoftICENT();
if (isExistsSICE95) {
t += 0x143;
}
if (isExistsSICENT) {
t += 0x271;
}
char str_t[12];
itoa(t, str_t, 10);
sn[index] = str_t[0];
sn[index+1] = str_t[1];
sn[index+2] = str_t[2];
sn[index+3] = str_t[3];
///
//printf("time: %d-%d-%d %d:%d\n", st->tm_year+1900, st->tm_mon+1, st->tm_mday, st->tm_hour, st->tm_min) ;
}
CBData readKey(HKEY hKey, char * path, char * key) {
HKEY h = (HKEY)-1;
DWORD cbData;
DWORD regType = -1;
data.n = 1;
long s = RegOpenKeyEx(hKey, path, 0, KEY_READ, &h);
if( s != ERROR_SUCCESS) {
data.n = -1;
return data;
}
s = RegQueryValueEx(h, key, NULL, NULL, NULL, &cbData);
if(s == ERROR_SUCCESS) {
RegQueryValueEx(h, key, NULL, & regType, data.buffer, &cbData);
}
RegCloseKey(h);
return data;
}
void getRegInfo() {
char subKey[] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion";
char key1[] = "FirstInstallDateTime";
char key2[] = "RegisteredOwner";
char key3[] = "RegisteredOrganization";
char key4[] = "ProductId";
CBData cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key1);
nFirstInstallDateTime = cb.n;
struct tm * tm_reg = localtime((time_t *)&nFirstInstallDateTime);
sprintf(sFirstInstallDateTime, "%lu", nFirstInstallDateTime);
nLenOfFirstInstallDateTime = strlen(sFirstInstallDateTime);
printf(" DateTime: %d-%d-%d %d:%d:%d\n", tm_reg->tm_year + 1900, tm_reg->tm_mon + 1,
tm_reg->tm_mday, tm_reg->tm_hour, tm_reg->tm_min, tm_reg->tm_sec);
printf("Timestamp: %d, len=%d\n", nFirstInstallDateTime, nLenOfFirstInstallDateTime);
////
cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key2);
strcpy(RegisteredOwner, (char *)cb.buffer);
////
cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key3);
strcpy(RegisteredOrganization, (char *)cb.buffer);
////
cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key4);
strcpy(ProductId, (char *)cb.buffer);
printf(" ProductId: %s\n", ProductId);
printf(" RegisteredOwner: %s\n", RegisteredOwner);
printf("RegisteredOrganization: %s\n", RegisteredOrganization);
}
免费评分
查看全部评分