TA的每日心情 | 奋斗 2017-1-16 20:03 |
---|
签到天数: 116 天 [LV.6]常住居民II
|
这是一个简单的CrackMe分析,大牛勿笑,欢迎指教。
这个CrackMe没有关键字符串提醒,没有敏感函数的调用,常规的查找字符串和对敏感函数下断点都行不通,只能另想办法。用IDA打开软件,在函数列表中看到一个函数UpDateData,于是眼前一亮。因为在MFC中,这个函数是用来更新控件数据的,所以就猜想这个CrackMe是通过这个函数来获取用户名和序列号,找到这个函数的调用位置,然后用OD加载CrackMe,找到UpDateData函数的调用位置,并下断点。按下F9运行,输入用户名和序列号,点击“确定”后,程序停在下面这个位置:
[AppleScript] 纯文本查看 复制代码 00401A09 . E8 1E070000 call <jmp.&MFC71.#6236_CWnd::UpdateData>
00401A0E . 68 A8394000 push 004039A8 ; /FileName = "Reg.dll"
00401A13 . FF15 34304000 call dword ptr [<&KERNEL32.LoadLibraryA>] ; \LoadLibraryA
这是通过UpDateData获取用户名和序列号,然后调用LoadLibraryA函数加载Reg.dll,然后取出用户名,代码如下:
[AppleScript] 纯文本查看 复制代码 ;获取用户名和序列号
00401A09 . E8 1E070000 call <jmp.&MFC71.#6236_CWnd::UpdateData>
;调用LoadLibraryA来加载Reg.dll
00401A0E . 68 A8394000 push 004039A8 ; /FileName = "Reg.dll"
00401A13 . FF15 34304000 call dword ptr [<&KERNEL32.LoadLibraryA>]
; \LoadLibraryA
00401A19 . 68 70394000 push 00403970
00401A1E . 8D4C24 18 lea ecx, dword ptr [esp+18]
;保存Reg.dll的句柄
00401A22 . 894424 24 mov dword ptr [esp+24], eax
;取出用户名
00401A6A . FF15 9C314000 call dword ptr [<&MFC71.#876_ATL::CSimpleStringT<char,1>; MFC71.7C158BCD
到这里,eax中已经存放了用户输入的用户名的首地址,接下来先将用户名存入前面定义的数组中,代码如下:
[AppleScript] 纯文本查看 复制代码 00401A70 . 8D6C24 24 lea ebp, dword ptr [esp+24]
00401A74 > 8A08 mov cl, byte ptr [eax]
00401A76 . 40 inc eax
00401A77 . 884D 00 mov byte ptr [ebp], cl
00401A7A . 45 inc ebp
00401A7B . 84C9 test cl, cl
00401A7D .^ 75 F5 jnz short 00401A74
然后取出用户名的前三个字节,通过一些算法来对其进行计算,代码如下:
[AppleScript] 纯文本查看 复制代码 00401A7F . 33ED xor ebp, ebp
;取出用户名的一个字节
00401A81 > 8A442C 24 mov al, byte ptr [esp+ebp+24]
;判断其是否为字符0,如果是则结束注册
00401A85 . 3C 30 cmp al, 30
00401A87 . 0F84 D1000000 je 00401B5E
;将al扩充为eax
00401A8D . 0FBEC0 movsx eax, al
00401A90 . 57 push edi
;将eax的最高位扩充到edx
00401A91 . 99 cdq
00401A92 . 56 push esi
00401A93 . 52 push edx
00401A94 . 50 push eax
;这个函数对输入的参数进行计算
00401A95 . E8 96070000 call 00402230
00401A9A . 45 inc ebp
;通过ebp来限制获取用户名的字节数
00401A9B . 83FD 03 cmp ebp, 3
;将用户名计算结果的低32位存入esi,高32位存入edi
00401A9E . 8BF0 mov esi, eax
00401AA0 . 8BFA mov edi, edx
00401AA2 .^ 7C DD jl short 00401A81
现在来看看00401A95 . E8 96070000 call 00402230这个函数里都做了些什么,代码如下:
[AppleScript] 纯文本查看 复制代码 ;获取第二个参数
00402230 /$ 8B4424 08 mov eax, dword ptr [esp+8]
;获取第四个参数
00402234 |. 8B4C24 10 mov ecx, dword ptr [esp+10]
;用第二个参数和第四个参数进行或运算
00402238 |. 0BC8 or ecx, eax
;获取第三个参数
0040223A |. 8B4C24 0C mov ecx, dword ptr [esp+C]
;如果或的结果部位0则跳转
0040223E |. 75 09 jnz short 00402249
;获取第一个参数
00402240 |. 8B4424 04 mov eax, dword ptr [esp+4]
;第一个参数与第三个参数相乘,结果低32位存eax,高32位存edx
00402244 |. F7E1 mul ecx
00402246 |. C2 1000 retn 10
;前面相或后结果不为0的计算
00402249 |> 53 push ebx
;用相或后的结果乘以第二个参数
0040224A |. F7E1 mul ecx
0040224C |. 8BD8 mov ebx, eax
;由于前面有个push ebx,所以这里esp+8是取出第一个参数
0040224E |. 8B4424 08 mov eax, dword ptr [esp+8]
;第一个参数乘以第四个参数,结果存与eax
00402252 |. F76424 14 mul dword ptr [esp+14]
;将所得的积与前面所得的积相加
00402256 |. 03D8 add ebx, eax
;取出第一个参数
00402258 |. 8B4424 08 mov eax, dword ptr [esp+8]
;ecx存放的是第三个参数,这里将第一个参数与第三个参数相乘
0040225C |. F7E1 mul ecx
;将所得结果与前面的和相加
0040225E |. 03D3 add edx, ebx
00402260 |. 5B pop ebx
00402261 \. C2 1000 retn 10
到这里,用户名前三个字节的计算已经结束,接下来是用户名长度的判断,代码如下:
[AppleScript] 纯文本查看 复制代码 ;取出用户名数组的第七个元素
00401AA4 . 8A4424 2A mov al, byte ptr [esp+2A]
;判断其是否为0,如果不为0则结束注册
00401AA8 . 84C0 test al, al
00401AAA . 0F85 AE000000 jnz 00401B5E
;取出用户名数组的第6个原素,如果为0则结束注册
00401AB0 . 8A4424 29 mov al, byte ptr [esp+29]
00401AB4 . 84C0 test al, al
00401AB6 . 0F84 A2000000 je 00401B5E
通过上面的两个判断可知,用户名的长度只能为6个字节。接下来是通过00401AC1 . E8 BA010000 call 00401C80这个函数来获取CPU信息的函数,这个函数代码如下:
[AppleScript] 纯文本查看 复制代码 ;实例化4个CString对象
00401CE1 |. FF15 A8314000 call dword ptr [<&MFC71.#310_ATL::CStringT<char,StrTraitMFC>; MFC71.7C173199
00401CE7 |. 8D4C24 0C lea ecx, dword ptr [esp+C]
00401CEB |. FF15 A8314000 call dword ptr [<&MFC71.#310_ATL::CStringT<char,StrTraitMFC>; MFC71.7C173199
00401CF1 |. 8D4C24 10 lea ecx, dword ptr [esp+10]
00401CF5 |. FF15 A8314000 call dword ptr [<&MFC71.#310_ATL::CStringT<char,StrTraitMFC>; MFC71.7C173199
00401CFB |. 8D4C24 14 lea ecx, dword ptr [esp+14]
00401CFF |. FF15 A8314000 call dword ptr [<&MFC71.#310_ATL::CStringT<char,StrTraitMFC>; MFC71.7C173199
00401D05 |. C64424 40 04 mov byte ptr [esp+40], 4
;获取CPU制造商信息信息
00401D0A |. 33C0 xor eax, eax
00401D0C |. 0FA2 cpuid
00401D0E |. 895C24 24 mov dword ptr [esp+24], ebx
00401D12 |. 895424 28 mov dword ptr [esp+28], edx
00401D16 |. 894C24 2C mov dword ptr [esp+2C], ecx
00401D1A |. 8D4C24 24 lea ecx, dword ptr [esp+24]
00401D1E |. 51 push ecx
00401D1F |. 8D5424 1C lea edx, dword ptr [esp+1C]
;将CPU制造商信息以字符串的形式存储与一个CString对象中
00401D23 |. 68 BC394000 push 004039BC ; ASCII "%s-"
00401D28 |. 52 push edx
00401D29 |. FF15 DC314000 call dword ptr [<&MFC71.#2322_ATL::CStringT<char,StrTraitMF>; MFC71.7C146A9D
00401D2F |. 83C4 0C add esp, 0C
;获取CPU序列号的高两个WORD
00401D32 |. B8 01000000 mov eax, 1
00401D37 |. 33D2 xor edx, edx
00401D39 |. 0FA2 cpuid
00401D3B |. 895424 1C mov dword ptr [esp+1C], edx
00401D3F |. 894424 20 mov dword ptr [esp+20], eax
00401D43 |. 8B4424 20 mov eax, dword ptr [esp+20]
00401D47 |. 8B4C24 1C mov ecx, dword ptr [esp+1C]
00401D4B |. 50 push eax
00401D4C |. 51 push ecx
00401D4D |. 8D5424 18 lea edx, dword ptr [esp+18]
;将CPU序列号转为十六进制,再将其格式化为字符串存入一个CString中
00401D51 |. 68 B0394000 push 004039B0 ; ASCII "%08X%08X"
00401D56 |. 52 push edx
00401D57 |. FF15 DC314000 call dword ptr [<&MFC71.#2322_ATL::CStringT<char,StrTraitMF>; MFC71.7C146A9D
00401D5D |. 83C4 10 add esp, 10
;获取CPU序列号的4个WORD
00401D60 |. B8 03000000 mov eax, 3
00401D65 |. 33C9 xor ecx, ecx
00401D67 |. 33D2 xor edx, edx
00401D69 |. 0FA2 cpuid
00401D6B |. 895424 1C mov dword ptr [esp+1C], edx
00401D6F |. 894C24 20 mov dword ptr [esp+20], ecx
00401D73 |. 8B4424 20 mov eax, dword ptr [esp+20]
00401D77 |. 8B4C24 1C mov ecx, dword ptr [esp+1C]
00401D7B |. 50 push eax
00401D7C |. 51 push ecx
00401D7D |. 8D5424 1C lea edx, dword ptr [esp+1C]
;将这4个WORD转为16进制,并格式化为字符串存入一个CString中
00401D81 |. 68 B0394000 push 004039B0 ; ASCII "%08X%08X"
00401D86 |. 52 push edx
00401D87 |. FF15 DC314000 call dword ptr [<&MFC71.#2322_ATL::CStringT<char,StrTraitMF>; MFC71.7C146A9D
00401D8D |. 8D4424 24 lea eax, dword ptr [esp+24]
00401D91 |. 50 push eax
00401D92 |. 8D4C24 24 lea ecx, dword ptr [esp+24]
00401D96 |. 51 push ecx
00401D97 |. 8D5424 34 lea edx, dword ptr [esp+34]
00401D9B |. 52 push edx
;这里将CPU序列号的两个字符串连成一个字符串
00401D9C |. E8 3FFEFFFF call 00401BE0
接下来通过00401ADC . E8 CFFDFFFF call 004018B0来对获取的CPU序列号进行计算,这个函数的实现过程如下:
[AppleScript] 纯文本查看 复制代码 00401903 |> /33F6 /xor esi, esi
;要获取的元素下标
00401905 |> |8D0437 |/lea eax, dword ptr [edi+esi]
00401908 |. |50 ||push eax
;源字符串的存放位置
00401909 |. |8D4C24 58 ||lea ecx, dword ptr [esp+58]
;这里调用的是GetAt函数,来获取相应位置的字符
0040190D |. |FF15 D4314000 ||call dword ptr [<&MFC71.#2451_ATL::CSimpleStringT<char,1>>; MFC71.7C1894E7
00401913 |. |8D4C24 0C ||lea ecx, dword ptr [esp+C]
00401917 |. |50 ||push eax
00401918 |. |FF15 D0314000 ||call dword ptr [<&MFC71.#782_ATL::CStringT<char,StrTraitM>; MFC71.7C18B1DF
0040191E |. |8D4C24 0C ||lea ecx, dword ptr [esp+C]
00401922 |. |51 ||push ecx
00401923 |. |8BCD ||mov ecx, ebp
;将字符存入CString对象中
00401925 |. |FF15 CC314000 ||call dword ptr [<&MFC71.#907_ATL::CStringT<char,StrTraitM>; MFC71.7C14E599
0040192B |. |46 ||inc esi
;每个CString对象存放8个字符
0040192C |. |83FE 08 ||cmp esi, 8
0040192F |.^|7C D4 |\jl short 00401905
00401931 |. |83C7 08 |add edi, 8
00401934 |. |83C5 04 |add ebp, 4
00401937 |. |83FF 20 |cmp edi, 20
0040193A |.^\7C C7 \jl short 00401903
接下来把CString中的字符串转为数字,代码如下:
00401942 |> /6A 10 /push 10
00401944 |. |51 |push ecx
00401945 |. |8BCC |mov ecx, esp
00401947 |. |896424 18 |mov dword ptr [esp+18], esp
0040194B |. |57 |push edi
0040194C |. |FF15 C8314000 |call dword ptr [<&MFC71.#297_ATL::CStringT<char,StrTraitMFC_D>; MFC71.7C14E575
;字符串转换成数字函数
00401952 |. |E8 79FDFFFF |call 004016D0
00401957 |. |83C4 08 |add esp, 8
;保存转换结果
0040195A |. |8944F4 24 |mov dword ptr [esp+esi*8+24], eax
0040195E |. |8954F4 28 |mov dword ptr [esp+esi*8+28], edx
00401962 |. |46 |inc esi
00401963 |. |83C7 04 |add edi, 4
00401966 |. |83FE 04 |cmp esi, 4
00401969 |.^\7C D7 \jl short 00401942
字符串转换为数字的函数代码如下:
[AppleScript] 纯文本查看 复制代码 ;获取要转换的字符串首
004016EE |. 8D4C24 3C lea ecx, dword ptr [esp+3C]
004016F2 |. 896C24 34 mov dword ptr [esp+34], ebp
;获取要转换的字符串长度
004016F6 |. FF15 C4314000 call dword ptr [<&MFC71.#2902_ATL::CSimpleStringT<char,1>::GetLength>] ; MFC71.7C146AB0
;如果字符串长度小于等于0,则结束转换
004016FC |. 3BC5 cmp eax, ebp
;保存要转换的次数
004016FE |. 894424 18 mov dword ptr [esp+18], eax
00401702 |. 896C24 1C mov dword ptr [esp+1C], ebp
00401706 |. 896C24 20 mov dword ptr [esp+20], ebp
0040170A |. 896C24 10 mov dword ptr [esp+10], ebp
0040170E |. 0F8E 0E010000 jle 00401822
00401714 |. 8B7C24 18 mov edi, dword ptr [esp+18]
00401718 |. 8D58 FF lea ebx, dword ptr [eax-1]
0040171B |. 895C24 14 mov dword ptr [esp+14], ebx
0040171F |. 90 nop
00401720 |> /8B4424 40 /mov eax, dword ptr [esp+40]
00401724 |. |50 |push eax
00401725 |. |55 |push ebp
;获取要转换的字符串地址
00401726 |. |8D4C24 44 |lea ecx, dword ptr [esp+44]
;获取要转换的字符
0040172A |. |FF15 C0314000 |call dword ptr [<&MFC71.#865_ATL::CSimpleStr>; MFC71.7C1894E7
00401730 |. |50 |push eax
;判断该字符是否为0~f之一,如果是则返回1,否则返回0
00401731 |. |E8 1AFFFFFF |call 00401650
00401736 |. |83C4 08 |add esp, 8
;如果返回0则说明该字符并非0~f之一,则直接结束
00401739 |. |85C0 |test eax, eax
0040173B |. |8D4C24 3C |lea ecx, dword ptr [esp+3C]
0040173F |. |0F84 02010000 |je 00401847
00401745 |. |55 |push ebp
;获取要检测的字符
00401746 |. |FF15 C0314000 |call dword ptr [<&MFC71.#865_ATL::CSimpleStr>; MFC71.7C1894E7
0040174C |. |0FBEC8 |movsx ecx, al
0040174F |. |51 |push ecx ; /c
;用isdugit函数来检测该字符是否为数字, 如果为数字则返回1,否则返回0
00401750 |. |FF15 F4324000 |call dword ptr [<&MSVCR71.isdigit>] ; \isdigit
00401756 |. |83C4 04 |add esp, 4
;如果是字符,则进入字符处理
00401759 |. |85C0 |test eax, eax
0040175B |. |8D4C24 3C |lea ecx, dword ptr [esp+3C]
0040175F |. |55 |push ebp
00401760 |. |74 0E |je short 00401770
;获取字符
00401762 |. |FF15 C0314000 |call dword ptr [<&MFC71.#865_ATL::CSimpleStr>; MFC71.7C1894E7
00401768 |. |0FBEF8 |movsx edi, al
;如果是数字,则直接用它的ascii码减去字符0的ascii码,然后跳到下面的处理部分
0040176B |. |83EF 30 |sub edi, 30
0040176E |. |EB 47 |jmp short 004017B7
;获取字符
00401770 |> |FF15 C0314000 |call dword ptr [<&MFC71.#865_ATL::CSimpleStr>; MFC71.7C1894E7
00401776 |. |0FBEC0 |movsx eax, al
;用该字符啊ascii码减去大写字母A的ascii码
00401779 |. |83C0 BF |add eax, -41 ; Switch (cases 41..66)
;大于f则不进行字符转数字的处理
0040177C |. |83F8 25 |cmp eax, 25
0040177F |. |77 36 |ja short 004017B7
00401781 |. |0FB690 841840>|movzx edx, byte ptr [eax+401884]
;这里用个switch语句来将字母转为相应的数字
00401788 |. |FF2495 681840>|jmp dword ptr [edx*4+401868]
;字母A或a则转为0x0A
0040178F |> |BF 0A000000 |mov edi, 0A ; Cases 41 ('A'),61 ('a') of switch 00401779
00401794 |. |EB 21 |jmp short 004017B7
;字母B或b则转为0x0B
00401796 |> |BF 0B000000 |mov edi, 0B ; Cases 42 ('B'),62 ('b') of switch 00401779
0040179B |. |EB 1A |jmp short 004017B7
;字母C或c则转为0x0C
0040179D |> |BF 0C000000 |mov edi, 0C ; Cases 43 ('C'),63 ('c') of switch 00401779
004017A2 |. |EB 13 |jmp short 004017B7
;字母D或d则转为0x0D
004017A4 |> |BF 0D000000 |mov edi, 0D ; Cases 44 ('D'),64 ('d') of switch 00401779
004017A9 |. |EB 0C |jmp short 004017B7
;字母E或e则转为0x0E
004017AB |> |BF 0E000000 |mov edi, 0E ; Cases 45 ('E'),65 ('e') of switch 00401779
004017B0 |. |EB 05 |jmp short 004017B7
;字母F或f则转为0x0F
004017B2 |> |BF 0F000000 |mov edi, 0F ; Cases 46 ('F'),66 ('f') of switch 00401779
004017B7 |> |33F6 |xor esi, esi ; Default case of switch 00401779
;ebx保存的是剩余为转换的字符个数,如果小于等于0,则说明字符已转换完毕
004017B9 |. |85DB |test ebx, ebx
004017BB |. |B9 01000000 |mov ecx, 1
004017C0 |. |7E 2A |jle short 004017EC
;eax存放的值为0x10
004017C2 |. |8B4424 40 |mov eax, dword ptr [esp+40]
004017C6 |. |99 |cdq
004017C7 |. |8BE8 |mov ebp, eax
004017C9 |. |895424 28 |mov dword ptr [esp+28], edx
004017CD |. |8D49 00 |lea ecx, dword ptr [ecx]
;下面这个循环用来确定字符在转换化后数字所处的位置
004017D0 |> |8B4424 28 |/mov eax, dword ptr [esp+28]
004017D4 |. |56 ||push esi
004017D5 |. |51 ||push ecx
004017D6 |. |50 ||push eax
004017D7 |. |55 ||push ebp
004017D8 |. |E8 530A0000 ||call 00402230
004017DD |. |4B ||dec ebx
004017DE |. |8BC8 ||mov ecx, eax
004017E0 |. |8BF2 ||mov esi, edx
004017E2 |.^|75 EC |\jnz short 004017D0
004017E4 |. |8B6C24 10 |mov ebp, dword ptr [esp+10]
004017E8 |. |8B5C24 14 |mov ebx, dword ptr [esp+14]
004017EC |> |56 |push esi
004017ED |. |8BC7 |mov eax, edi
004017EF |. |99 |cdq
004017F0 |. |51 |push ecx
004017F1 |. |52 |push edx
004017F2 |. |50 |push eax
;这里实现的是用字符串转化后的数字乘以它所处的位置,从而得到一个整数的某一位
004017F3 |. |E8 380A0000 |call 00402230
004017F8 |. |8B4C24 1C |mov ecx, dword ptr [esp+1C]
004017FC |. |8B7424 20 |mov esi, dword ptr [esp+20]
00401800 |. |03C8 |add ecx, eax
00401802 |. |8B4424 18 |mov eax, dword ptr [esp+18]
00401806 |. |13F2 |adc esi, edx
00401808 |. |45 |inc ebp
00401809 |. |4B |dec ebx
;判断转换是否结束
0040180A |. |3BE8 |cmp ebp, eax
;保存转换结果
0040180C |. |894C24 1C |mov dword ptr [esp+1C], ecx
00401810 |. |897424 20 |mov dword ptr [esp+20], esi
00401814 |. |896C24 10 |mov dword ptr [esp+10], ebp
00401818 |. |895C24 14 |mov dword ptr [esp+14], ebx
0040181C |.^\0F8C FEFEFFFF \jl 00401720
所有的字符串都转为数字之后,接下来就对它进行计算。转换的结果保存在一个长度为8的int型数组中,下面是计算部分的代码:
[AppleScript] 纯文本查看 复制代码 0040196B |. 8B4C24 40 mov ecx, dword ptr [esp+40]
0040196F |. 8B7C24 28 mov edi, dword ptr [esp+28]
00401973 |. 8B5424 3C mov edx, dword ptr [esp+3C]
00401977 |. 8B7424 24 mov esi, dword ptr [esp+24]
0040197B |. 8B6C24 38 mov ebp, dword ptr [esp+38]
0040197F |. 8B4424 34 mov eax, dword ptr [esp+34]
00401983 |. 33F9 xor edi, ecx
00401985 |. 8B4C24 30 mov ecx, dword ptr [esp+30]
00401989 |. 33F2 xor esi, edx
0040198B |. 8B5424 2C mov edx, dword ptr [esp+2C]
0040198F |. 33FD xor edi, ebp
00401991 |. 33F0 xor esi, eax
00401993 |. 33F9 xor edi, ecx
00401995 |. 8D4C24 0C lea ecx, dword ptr [esp+C]
00401999 |. 33F2 xor esi, edx
计算出结果后,将所得结果与用户名前三字节的计算结果相或,代码如下:
[AppleScript] 纯文本查看 复制代码 ;edx保存的是所得结果的高32位,eax保存的是所得结果的低32位,edi保存的是用户名前三字节结算结果的高32位,esi保存的是计算所得结果的低32位
00401AE1 . 0BFA or edi, edx
00401AE3 . 0BF0 or esi, eax
接下来将所得结果转化为字符串,代码如下:
[AppleScript] 纯文本查看 复制代码 00401AE5 . 57 push edi
00401AE6 . 56 push esi
00401AE7 . 8D4424 1C lea eax, dword ptr [esp+1C]
00401AEB . 68 A4394000 push 004039A4 ; ASCII "%x"
00401AF0 . 50 push eax
00401AF1 . FF15 DC314000 call dword ptr [<&MFC71.#2322_ATL::CStringT<char,StrTraitMFC_DLL<ch>; MFC71.7C146A9D
00401AF7 . 8B4C24 34 mov ecx, dword ptr [esp+34]
00401AFB . 83C4 14 add esp, 14
然后调用reg.dll中的加密函数,代码如下:
[AppleScript] 纯文本查看 复制代码 00401AFE . 68 98394000 push 00403998 ; /ProcNameOrOrdinal = "GetMD5Str"
00401B03 . 51 push ecx ; |hModule
00401B04 . FF15 38304000 call dword ptr [<&KERNEL32.GetProcAddress>] ; \GetProcAddress
00401B0A . 8D4C24 10 lea ecx, dword ptr [esp+10]
00401B0E . 8BF0 mov esi, eax
00401B10 . FF15 9C314000 call dword ptr [<&MFC71.#876_ATL::CSimpleStringT<char,1>::operator >; MFC71.7C158BCD
00401B16 . 50 push eax
;调用reg.dll中的GetMD5Str函数
00401B17 . FFD6 call esi
然后将所得结果存入一个CString对象中,并对这个字符串进行计算,计算方式与对CPU序列号的计算一样,代码如下:
[AppleScript] 纯文本查看 复制代码 00401B19 . 50 push eax
00401B1A . 8D4C24 18 lea ecx, dword ptr [esp+18]
00401B1E . FF15 D8314000 call dword ptr [<&MFC71.#784_ATL::CStringT<char,StrTraitM>; MFC71.7C14FF74
00401B24 . 51 push ecx
00401B25 . 8D5424 18 lea edx, dword ptr [esp+18]
00401B29 . 8BCC mov ecx, esp
00401B2B . 896424 20 mov dword ptr [esp+20], esp
00401B2F . 52 push edx
00401B30 . FF15 C8314000 call dword ptr [<&MFC71.#297_ATL::CStringT<char,StrTraitM>; MFC71.7C14E575
;对所生成的MD5字符串进行计算
00401B36 . E8 75FDFFFF call 004018B0
通过这次计算后,得到的结果就是这个CM所需要的序列号了,接下来就是序列号的比较,代码如下:
[AppleScript] 纯文本查看 复制代码 ;这里获取用户输入的序列号
00401B3B . 8B4B 78 mov ecx, dword ptr [ebx+78]
00401B3E . 83C4 04 add esp, 4
;eax中保存的是通过计算后所得的结果,如果用户输入的序列号与所得结果相等,则说明序列号是正确的,否则不正确
00401B41 . 3BC1 cmp eax, ecx
00401B43 . 75 0F jnz short 00401B54
00401B45 . 3B53 7C cmp edx, dword ptr [ebx+7C]
00401B48 . 75 0A jnz short 00401B54
分析终于完成了,长呼一口气,接下来就是注册机的代码了
[AppleScript] 纯文本查看 复制代码 /**
* @brief 序列号生成函数
* @per 修改历史
* @code
* 作者 修改时间 函数描述 版本号
* ------- ------------ -------------- ----------
* IceAmber 2013-04-14 计算序列号 v1.0
* @endcode
*/
void CCRACKME4KeygenDlg::OnBnClickedGenerate()
{
// TODO: 在此添加控件通知处理程序代码
int iNameCaculate = 0;
int iCpuCaculate = 0;
int iResult = 0;
EightInt iSerial = {0};
HMODULE lHandle = 0;
CString strDigest;
typedef char* (__stdcall *LPFNGETMD5)(CString);
LPFNGETMD5 lpfnRegister = NULL;
char *cDigestAddr;
//加载DLL
lHandle = LoadLibrary("Reg.dll");
if(NULL != lHandle)
{
iNameCaculate = DealName();
//获取CPUID
iCpuCaculate = GetCPUIDFunction();
iResult = iNameCaculate | iCpuCaculate;
strDigest.Format("%x",iResult);
lpfnRegister = (LPFNGETMD5)GetProcAddress(lHandle, "GetMD5Str");
if(NULL != lpfnRegister)
{
cDigestAddr = (*lpfnRegister)(strDigest);
strDigest.Format("%s",cDigestAddr);
iSerial = DealString(strDigest);
strDigest.Format("%d", iSerial.lEax);
}
}
SetDlgItemText(IDC_SERIAL, strDigest);
FreeLibrary(lHandle);
}
/**
* @brief 用户名计算函数
* @per 修改历史
* @code
* 作者 修改时间 函数描述 版本号
* ------- ------------ -------------- ----------
* IceAmber 2013-04-14 用户名计算函数 v1.0
* @endcode
*/
EightInt CCRACKME4KeygenDlg::NameCaculete(int iParam1, int iParam2, int iParam3, int iParam4)
{
EightInt lResult = {0};
int iEaxReg, iEcxReg;
iEaxReg = iParam2;
iEcxReg = iParam4;
if(0 == (iEaxReg | iEcxReg))
{
iEcxReg = iParam3;
iEaxReg = iParam1;
__asm
{
mov eax, iEaxReg
mov ecx, iEcxReg
mul ecx
mov lResult.lEax, eax
mov lResult.lEdx, edx
}
}
return lResult;
}
/**
* @brief 用户名处理函数
* @per 修改历史
* @code
* 作者 修改时间 函数描述 版本号
* ------- ------------ ------------------- ----------
* IceAmber 2013-04-14 计算用户名前三个字母 v1.0
* @endcode
*/
int CCRACKME4KeygenDlg::DealName(void)
{
int i = 0;
EightInt lRet = {0};
int iEdi = 0;
int iEsi = 2; //用来处理用户名前三个字母的密钥
int iEdx = 0;
int iEax = 0;
int iLenth = 0;
CString strName; //用户名
int iResult = 0; //用户名计算结果
//获取用户名
GetDlgItemText(IDC_NAME, strName);
iLenth = strName.GetLength(); //获取用户名长度
for(i = 0; i < iLenth / 2; i ++)
{
if('0' == strName[i]) //用户名不能有字符'0'
{
return 0;
}
iEax = (int)strName[i];
//获取前三个字母的计算结果
lRet = NameCaculete(iEax, iEdx, iEsi, iEdi);
iEax = (int)lRet.lEax;
iEdx = (int)lRet.lEdx;
iEsi = iEax;
iEdi = iEdx;
}
if(6 != iLenth) //用户名长度不为6则退出
{
return 0;
}
//因为edx的值为0
iResult = iEax;
return iResult;
}
/**
* @brief 获取CPUID函数
* @per 修改历史
* @code
* 作者 修改时间 函数描述 版本号
* ------- ------------ ------------- ----------
* IceAmber 2013-04-14 获取CPUID v1.0
* @endcode
*/
int CCRACKME4KeygenDlg::GetCPUIDFunction(void)
{
char cCpuID[16];
int iRecieve1, iRecieve2;
EightInt ret = {0};
int iResult = 0;
CString strCpuInfo1, strCpuInfo2, strCpuInfo3;
__asm
{
mov eax, 0
cpuid
mov dword ptr cCpuID, ebx
mov dword ptr cCpuID[4], edx
mov dword ptr cCpuID[8], ecx
mov dword ptr cCpuID[12], 0
}
__asm
{
mov eax, 1
xor edx, edx
cpuid
mov dword ptr iRecieve1, edx
mov dword ptr iRecieve2, eax
}
strCpuInfo2.Format("%08X%08X", iRecieve1, iRecieve2);
__asm
{
mov eax, 3
xor ecx, ecx
xor edx, edx
cpuid
mov dword ptr iRecieve1, edx
mov dword ptr iRecieve2, ecx
}
strCpuInfo3.Format("%08X%08X", iRecieve1, iRecieve2);
strCpuInfo = strCpuInfo2 + strCpuInfo3;
ret = DealString(strCpuInfo);
iResult = ret.lEax;
return iResult;
}
/**
* @brief 字符串处理函数
* @per 修改历史
* @code
* 作者 修改时间 函数描述 版本号
* ------- ------------ ------------- ----------
* IceAmber 2013-04-14 处理字符串 v1.0
* @endcode
*/
EightInt CCRACKME4KeygenDlg::DealString(CString strParam)
{
int i = 0;
int j = 0;
EightInt iRecieve[4] = {0};
EightInt iResult = {0};
char cNumber;
char cStr[9];
CString str[4];
//进行处理的字符串长度为32个字符
for (i = 0; i < 4; i ++)
{
for (j = 0; j < 8 ; j++)
{
cStr[j] = strParam[i*8+j];
}
cStr[j] = '\0';
str[i].Format("%8s", cStr);
}
for(i = 0; i < 4; i ++)
{
iRecieve[i] = CharChangeToNumber(str[i], 8, 16);
}
iRecieve[0].lEdx ^= iRecieve[3].lEdx;
iRecieve[0].lEax ^= iRecieve[3].lEax;
iRecieve[0].lEdx ^= iRecieve[2].lEdx;
iRecieve[0].lEax ^= iRecieve[2].lEax;
iRecieve[0].lEdx ^= iRecieve[1].lEdx;
iRecieve[0].lEax ^= iRecieve[1].lEax;
iResult = iRecieve[0];
return iResult;
}
/**
* @brief 将字符转成数字
* @param [in] str 要判断的字符串
* @param [in] iStrLen 字符串的长度
* @param [in] iJudgeTimes 字符的判断次数
* @per 修改历史
* @code
* 作者 修改时间 函数描述 版本号
* ------- ------------ ------------- ----------
* IceAmber 2013-04-21 处理字符串 v1.0
* @endcode
*/
EightInt CCRACKME4KeygenDlg::CharChangeToNumber(CString str, int iStrLen, int iJudgeTimes)
{
int i = 0;
int j = 0;
int iCounter = 0;
int iTimes = 0;
int iChange = 0;
int iRegister = 0;
int iEcx = 0;
int iEsi = 0; //用来处理用户名前三个字母的密钥
int iEdx = 0;
int iEax = 0;
int iRet = 0;
EightInt iResult = {0};
EightInt eightint = {0};
iCounter = iStrLen;
if(iStrLen <= 0)
{
return iResult;
}
for(i = 0; i < iStrLen; i ++)
{
iRet = CharJudge(iJudgeTimes, str[i]);
if(0 == iRet)
{
iResult.lEax = 0;
iResult.lEdx = 0;
break;
}
else
{
iChange = (int)str[i];
iRet = isdigit((int)str[i]);
if(0 == iRet)
{
//传入的是字母
iChange -= 65;
if(iChange <= 37)
{
if(iChange >= 32)
{
//小写字母
iChange -= 32;
}
switch (iChange)
{
case 0:
iRegister = 0x0a;
break;
case 1:
iRegister = 0x0b;
break;
case 2:
iRegister = 0x0c;
break;
case 3:
iRegister = 0x0d;
break;
case 4:
iRegister = 0x0e;
break;
case 5:
iRegister = 0x0f;
break;
default:
break;
}
}
}
else
{
iRegister = iChange - 0x30;
}
iEcx = 1;
if(iCounter > 0)
{
for(j = 0; j < iCounter - 1; j ++)
{
//获取前三个字母的计算结果
eightint = NameCaculete(iJudgeTimes, 0, iEcx, iEsi);
iEcx = (int)eightint.lEax;
iEsi = (int)eightint.lEdx;
}
}
eightint = NameCaculete(iRegister, 0, iEcx, iEsi);
iResult.lEax += eightint.lEax;
iResult.lEdx += eightint.lEdx;
iCounter --;
}
}
return iResult;
}
/**
* @brief 判断该字符是否为0~f
* @param [in] iJudgeNum 要判断的次数
* @param [in] cJudgeChar 要判断的字符
* @per 修改历史
* @code
* 作者 修改时间 函数描述 版本号
* ------- ------------ ------------- ----------
* IceAmber 2013-04-21 处理字符串 v1.0
* @endcode
*/
int CCRACKME4KeygenDlg::CharJudge(int iJudgeNum, char cJudgeChar)
{
int i = 0;
int iResult = 0;
char sJudgeStr[] = "00112233445566778899aAbBcCdDeEfF";
//如果计算的次数小于2或大于16,则返回0
if(iJudgeNum < 2 || iJudgeNum > 16)
{
return 0;
}
for(i = 0; i < iJudgeNum; i ++)
{
if((cJudgeChar == sJudgeStr[i * 2]) || (cJudgeChar == sJudgeStr[i * 2 + 1]))
{
//如果输入的字符为0~f之间则返回1
iResult = 1;
break;
}
}
return iResult;
}
这个CrackMe+注册机的分析就到此结束了,欢迎指教,让大家共同进步。 |
评分
-
查看全部评分
|