-
-
[原创]APISpy v2.5 Crack过程分享
-
发表于: 2009-1-7 21:57 6778
-
【文章标题】: APISpy v2.5 Crack过程分享
【文章作者】: 秋风寒
【软件名称】: APISpy v2.5
【软件大小】: 69k
【下载地址】: 自己搜索下载
【加壳方式】: Petite 1.2 -> (c)1998 Ian Luck (h) *
【保护方式】: 注册码
【编写语言】: VC++6.0
【使用工具】: OD, PEid
【软件介绍】: 能够监控应用程序执行API函数。
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
最近使用到了该软件,每次启动都提示注册,保存结果时,只能保存前10条,很是郁闷,决定拿他开个刀,练练手。
1、用PEid查看,显示是Petite 1.2 -> (c)1998 Ian Luck (h) * 加的壳, 用Peid的通用脱壳插件脱壳后,再次用Peid
查看,显示为VC++6.0编写的,呵呵,我的最爱啊。
2、执行脱壳后的程序,程序能正常运行,但是OD载入后,点注册对话框,填了注册信息后,按确定,OD报内存不可读错误,
然后程序退出,怀疑有反调试。
3、决定代壳调试试试。
4、OD载入源程序,填注册码,确定,发现一切正常,开来没有凡调试。
5、查找当前模块中的名称,然后在GetDlgItemTextA, GetWindowTextA的每个参考上下断点,
然后填注册码,确定后停在下面这个函数处(在这里可能需要在CPU窗口单击右键,选择分析->分析代码,来让代码显示正常),
004051D0 /$ 8B4424 08 mov eax, dword ptr [esp+8]
004051D4 |. 53 push ebx
004051D5 |. 56 push esi
004051D6 |. 83F8 01 cmp eax, 1
004051D9 |. 57 push edi
004051DA |. 0F85 81000000 jnz 00405261
004051E0 |. 8B7424 10 mov esi, dword ptr [esp+10]
004051E4 |. 8B1D D0914000 mov ebx, dword ptr [<&USER32.GetDlgI>; USER32.GetDlgItemTextA
004051EA |. 6A 4E push 4E ; /Count = 4E (78.)
004051EC |. 68 C0C34000 push 0040C3C0 ; |Buffer = apis32.0040C3C0
004051F1 |. 68 F1030000 push 3F1 ; |ControlID = 3F1 (1009.)
004051F6 |. 56 push esi ; |hWnd
004051F7 |. FFD3 call ebx ; \GetDlgItemTextA ;断在这里
004051F9 |. 85C0 test eax, eax
004051FB |. 74 76 je short 00405273 ;检查注册码长度
004051FD |. BF C0C34000 mov edi, 0040C3C0 ; ASCII "qiufenghan"
00405202 |. 83C9 FF or ecx, FFFFFFFF
00405205 |. 33C0 xor eax, eax
00405207 |. F2:AE repne scas byte ptr es:[edi]
00405209 |. F7D1 not ecx
0040520B |. 49 dec ecx
0040520C |. 51 push ecx
0040520D |. 68 C0C34000 push 0040C3C0 ; ASCII "qiufenghan"
00405212 |. 68 88A64000 push 0040A688 ; ASCII "UserKey"
00405217 |. E8 D4010000 call 004053F0 ; 把注册码保存在注册表中,键名为UserKey
0040521C |. 83C4 0C add esp, 0C
0040521F |. 6A 4E push 4E
00405221 |. 68 C0C34000 push 0040C3C0 ; ASCII "qiufenghan"
00405226 |. 68 F0030000 push 3F0
0040522B |. 56 push esi
0040522C |. FFD3 call ebx
0040522E |. 85C0 test eax, eax ; 检测用户名长度
00405230 |. 74 41 je short 00405273
00405232 |. BF C0C34000 mov edi, 0040C3C0 ; ASCII "qiufenghan"
00405237 |. 83C9 FF or ecx, FFFFFFFF
0040523A |. 33C0 xor eax, eax
0040523C |. F2:AE repne scas byte ptr es:[edi]
0040523E |. F7D1 not ecx
00405240 |. 49 dec ecx
00405241 |. 51 push ecx
00405242 |. 68 C0C34000 push 0040C3C0 ; ASCII "qiufenghan"
00405247 |. 68 78A64000 push 0040A678 ; ASCII "UserName"
0040524C |. E8 9F010000 call 004053F0 ; 把用户名保存在注册表理,键名为UserName
00405251 |. 83C4 0C add esp, 0C
00405254 |. 6A 01 push 1 ; /Result = 1
00405256 |. 56 push esi ; |hWnd
00405257 |. FF15 68914000 call dword ptr [<&USER32.EndDialog>] ; \EndDialog
0040525D |. 5F pop edi
0040525E |. 5E pop esi
0040525F |. 5B pop ebx
00405260 |. C3 retn
00405261 |> 83F8 02 cmp eax, 2
00405264 |. 75 0D jnz short 00405273
00405266 |. 8B4424 10 mov eax, dword ptr [esp+10]
0040526A |. 6A 00 push 0 ; /Result = 0
0040526C |. 50 push eax ; |hWnd
0040526D |. FF15 68914000 call dword ptr [<&USER32.EndDialog>] ; \EndDialog
00405273 |> 5F pop edi
00405274 |. 5E pop esi
00405275 |. 5B pop ebx
00405276 \. C3 retn
这时发现把用户把注册信息保存在注册表中后关闭了对话框,然后跟踪开始进入事件处理循环,把代码跟丢了。
不过既然知道注册信息存在注册表里,呵呵就容易多了。找出注册算法的很重要的一步就是找到注册信息是怎么存放的。
在继续处理以前我们先来看看函数 004053F0的内容, 很显然是个写注册表的功能。
004053F0 /$ 56 push esi
004053F1 |. 68 20B74000 push 0040B720 ; /pHandle = apis32.0040B720
004053F6 |. 68 3F000F00 push 0F003F ; |Access = KEY_ALL_ACCESS
004053FB |. 6A 00 push 0 ; |Reserved = 0
004053FD |. 68 90A64000 push 0040A690 ; |Subkey = "SOFTWARE\APIS32"
00405402 |. 68 02000080 push 80000002 ; |hKey = HKEY_LOCAL_MACHINE
00405407 |. FF15 08904000 call dword ptr [<&ADVAPI32.RegOpenKey>; \RegOpenKeyExA
0040540D |. 85C0 test eax, eax
0040540F |. 74 32 je short 00405443
00405411 |. 68 24B74000 push 0040B724 ; /pDisposition = apis32.0040B724
00405416 |. 68 20B74000 push 0040B720 ; |pHandle = apis32.0040B720
0040541B |. 6A 00 push 0 ; |pSecurity = NULL
0040541D |. 68 3F000F00 push 0F003F ; |Access = KEY_ALL_ACCESS
00405422 |. 6A 00 push 0 ; |Options = REG_OPTION_NON_VOLATILE
00405424 |. 68 90A64000 push 0040A690 ; |Class = "SOFTWARE\APIS32"
00405429 |. 6A 00 push 0 ; |Reserved = 0
0040542B |. 68 90A64000 push 0040A690 ; |Subkey = "SOFTWARE\APIS32"
00405430 |. 68 02000080 push 80000002 ; |hKey = HKEY_LOCAL_MACHINE
00405435 |. FF15 10904000 call dword ptr [<&ADVAPI32.RegCreateK>; \RegCreateKeyExA
0040543B |. 85C0 test eax, eax
0040543D |. 74 04 je short 00405443
0040543F |. 33C0 xor eax, eax
00405441 |. 5E pop esi
00405442 |. C3 retn
00405443 |> 8B7424 10 mov esi, dword ptr [esp+10]
00405447 |. 8B4424 0C mov eax, dword ptr [esp+C]
0040544B |. 8B4C24 08 mov ecx, dword ptr [esp+8]
0040544F |. 8B15 20B74000 mov edx, dword ptr [40B720]
00405455 |. 56 push esi ; /BufSize
00405456 |. 50 push eax ; |Buffer
00405457 |. 6A 00 push 0 ; |ValueType = REG_NONE
00405459 |. 6A 00 push 0 ; |Reserved = 0
0040545B |. 51 push ecx ; |ValueName
0040545C |. 52 push edx ; |hKey => 88
0040545D |. FF15 0C904000 call dword ptr [<&ADVAPI32.RegSetValu>; \RegSetValueExA
00405463 |. A1 20B74000 mov eax, dword ptr [40B720]
00405468 |. 50 push eax ; /hKey => 00000088 (window)
00405469 |. FF15 00904000 call dword ptr [<&ADVAPI32.RegCloseKe>; \RegCloseKey
0040546F |. 8BC6 mov eax, esi
00405471 |. 5E pop esi
00405472 \. C3 retn
6、为了一劳永逸的找到注册算法,决定不再在填写注册码的对话框的地方下功夫,因为有些程序是在填写的时候只
做验证部分,在启动的时候做全部验证。
这次用OD载入脱壳后的程序,先在RegQueryValueExA上下断点。
当参数ValueName的值为userCode时停下(可以对RegQueryValueExA下条件断点),连续按Ctrl+F9《按3次》直到程序返回到
00402460 |. 68 2000CC00 push 0CC0020 ; /ROP = SRCCOPY
00402465 |. 6A 00 push 0 ; |YSrc = 0
00402467 |. 6A 00 push 0 ; |XSrc = 0
00402469 |. 8B55 DC mov edx, dword ptr [ebp-24] ; |
0040246C |. 52 push edx ; |hSrcDC
0040246D |. 8B45 F0 mov eax, dword ptr [ebp-10] ; |
00402470 |. 50 push eax ; |Height
00402471 |. 8B4D EC mov ecx, dword ptr [ebp-14] ; |
00402474 |. 51 push ecx ; |Width
00402475 |. 8B55 08 mov edx, dword ptr [ebp+8] ; |
00402478 |. 8B42 04 mov eax, dword ptr [edx+4] ; |
0040247B |. 50 push eax ; |YDest
0040247C |. 8B4D 08 mov ecx, dword ptr [ebp+8] ; |
0040247F |. 8B11 mov edx, dword ptr [ecx] ; |
00402481 |. 52 push edx ; |XDest
00402482 |. 8B45 E0 mov eax, dword ptr [ebp-20] ; |
00402485 |. 50 push eax ; |hDestDC
00402486 |. FF15 28904000 call dword ptr [<&GDI32.BitBlt>] ; \BitBlt
0040248C |. E8 AF2B0000 call 00405040 ; 判断是否注册
;连续按CTRL+F9程序回到这里,感觉这里可能就要做最后的跳转了
00402491 |. EB 01 jmp short 00402494 ; <<==
00402493 | B8 db B8
00402494 |> 0AC0 or al, al
;其实这段函数要被执行3次,如果这里只是改标志寄存器的位置,然后step by来查看,在后面执行sleep后
;会再次跟进Window消息处理过程中,如果你在此处没有下断点,按F9执行后,程序还是报注册失败。
00402496 |. 74 02 je short 0040249A ; 爆破点
00402498 |. EB 09 jmp short 004024A3
0040249A |> C745 D0 D4A04>mov dword ptr [ebp-30], 0040A0D4 ; unregistered
004024A1 |. EB 61 jmp short 00402504
004024A3 |> BF 4CA04000 mov edi, 0040A04C ; registered to
004024A8 |. BA 20BD4000 mov edx, 0040BD20 ; this copy of apis32 is\n\nu n r e g i s t e r e d\n\nregistration info can be found in file reginfo.txt
004024AD |. 83C9 FF or ecx, FFFFFFFF
004024B0 |. 33C0 xor eax, eax
004024B2 |. F2:AE repne scas byte ptr es:[edi]
004024B4 |. F7D1 not ecx
004024B6 |. 2BF9 sub edi, ecx
004024B8 |. 8BF7 mov esi, edi
004024BA |. 8BC1 mov eax, ecx
004024BC |. 8BFA mov edi, edx
004024BE |. C1E9 02 shr ecx, 2
004024C1 |. F3:A5 rep movs dword ptr es:[edi], dword p>
004024C3 |. 8BC8 mov ecx, eax
004024C5 |. 83E1 03 and ecx, 3
004024C8 |. F3:A4 rep movs byte ptr es:[edi], byte ptr>
004024CA |. BF C0C34000 mov edi, offset <用户名> ; a
004024CF |. BA 20BD4000 mov edx, 0040BD20 ; this copy of apis32 is\n\nu n r e g i s t e r e d\n\nregistration info can be found in file reginfo.txt
004024D4 |. 83C9 FF or ecx, FFFFFFFF
004024D7 |. 33C0 xor eax, eax
004024D9 |. F2:AE repne scas byte ptr es:[edi]
004024DB |. F7D1 not ecx
004024DD |. 2BF9 sub edi, ecx
004024DF |. 8BF7 mov esi, edi
004024E1 |. 8BD9 mov ebx, ecx
004024E3 |. 8BFA mov edi, edx
004024E5 |. 83C9 FF or ecx, FFFFFFFF
004024E8 |. 33C0 xor eax, eax
004024EA |. F2:AE repne scas byte ptr es:[edi]
004024EC |. 83C7 FF add edi, -1
004024EF |. 8BCB mov ecx, ebx
004024F1 |. C1E9 02 shr ecx, 2
004024F4 |. F3:A5 rep movs dword ptr es:[edi], dword p>
004024F6 |. 8BCB mov ecx, ebx
004024F8 |. 83E1 03 and ecx, 3
004024FB |. F3:A4 rep movs byte ptr es:[edi], byte ptr>
004024FD |. C745 D0 20BD4>mov dword ptr [ebp-30], 0040BD20 ; this copy of apis32 is\n\nu n r e g i s t e r e d\n\nregistration info can be found in file reginfo.txt
00402504 |> 6A 00 push 0 ; /Alignment = TA_LEFT|TA_TOP
00402506 |. 8B45 E0 mov eax, dword ptr [ebp-20] ; |
00402509 |. 50 push eax ; |hDC
0040250A |. FF15 30904000 call dword ptr [<&GDI32.SetTextAlign>>; \SetTextAlign
7、先在我们看看00405040函数,来找到注册算法。
00405040 /$ 51 push ecx
00405041 |. 53 push ebx
00405042 |. 55 push ebp
00405043 |. 56 push esi
00405044 |. 57 push edi
00405045 |. 6A 50 push 50
00405047 |. 68 40B74000 push offset <序列号> ; b
0040504C |. 68 88A64000 push 0040A688 ; userkey
00405051 |. E8 1A030000 call 00405370
00405056 |. 83C4 0C add esp, 0C
00405059 |. 83F8 10 cmp eax, 10 ; 注册码长度为>=16
0040505C |. 7D 08 jge short 00405066
0040505E |. 33C0 xor eax, eax
00405060 |. 5F pop edi
00405061 |. 5E pop esi
00405062 |. 5D pop ebp
00405063 |. 5B pop ebx
00405064 |. 59 pop ecx
00405065 |. C3 retn
00405066 |> 6A 2F push 2F
00405068 |. 68 C0C34000 push offset <用户名> ; a
0040506D |. 68 78A64000 push 0040A678 ; username
00405072 |. E8 F9020000 call 00405370
00405077 |. 83C4 0C add esp, 0C
0040507A |. 83F8 05 cmp eax, 5 ; 用户名长度>=5
0040507D |. 7D 08 jge short 00405087
0040507F |. 33C0 xor eax, eax
00405081 |. 5F pop edi
00405082 |. 5E pop esi
00405083 |. 5D pop ebp
00405084 |. 5B pop ebx
00405085 |. 59 pop ecx
00405086 |. C3 retn
;把注册码拷贝到一个另一个全局缓冲区中,我们称之为code_buf2,原来的称之为code_buf1
00405087 |> BF 40B74000 mov edi, offset <序列号> ; b
0040508C |. 83C9 FF or ecx, FFFFFFFF
0040508F |. 33C0 xor eax, eax
00405091 |. C605 51B74000>mov byte ptr [40B751], 0
00405098 |. F2:AE repne scas byte ptr es:[edi]
0040509A |. F7D1 not ecx
0040509C |. 2BF9 sub edi, ecx
0040509E |. 8BC1 mov eax, ecx
004050A0 |. 8BF7 mov esi, edi
004050A2 |. BF 54B74000 mov edi, 0040B754
004050A7 |. C1E9 02 shr ecx, 2
004050AA |. F3:A5 rep movs dword ptr es:[edi], dword p>
004050AC |. 8BC8 mov ecx, eax
004050AE |. 33C0 xor eax, eax
004050B0 |. 83E1 03 and ecx, 3
004050B3 |. F3:A4 rep movs byte ptr es:[edi], byte ptr>
;删除code_buf2中第9个字母
004050B5 |. BF 49B74000 mov edi, 0040B749 ; ASCII "AE7201C"
004050BA |. 83C9 FF or ecx, FFFFFFFF
004050BD |. F2:AE repne scas byte ptr es:[edi]
004050BF |. F7D1 not ecx
004050C1 |. 2BF9 sub edi, ecx
004050C3 |. 8BD1 mov edx, ecx
004050C5 |. 8BF7 mov esi, edi
004050C7 |. BF 5CB74000 mov edi, 0040B75C
004050CC |. C1E9 02 shr ecx, 2
004050CF |. F3:A5 rep movs dword ptr es:[edi], dword p>
004050D1 |. 8BCA mov ecx, edx
004050D3 |. 83E1 03 and ecx, 3
004050D6 |. 32DB xor bl, bl
004050D8 |. F3:A4 rep movs byte ptr es:[edi], byte ptr>;
004050DA |. BE 41B74000 mov esi, 0040B741 ;code_buf1
004050DF |. BF 54B74000 mov edi, 0040B754 ;code_buf2
;要求注册码去掉第9个字母后的字符为大写字母或数字,然后两个一起当一个16进制字节来处理,
;处理结果为8个字节,依次保存在code_buf1中
004050E4 |> 57 /push edi ; for(int i=0; i<8; i++) {esi[i] = strToex[edi] ^ (50h + i);}
004050E5 |. E8 E6010000 |call <StrtoHex>
004050EA |. 8ACB |mov cl, bl
004050EC |. 83C4 04 |add esp, 4
004050EF |. 80C1 50 |add cl, 50
004050F2 |. 83C7 02 |add edi, 2
004050F5 |. 32C1 |xor al, cl
004050F7 |. FEC3 |inc bl
004050F9 |. 8846 FF |mov byte ptr [esi-1], al
004050FC |. C606 00 |mov byte ptr [esi], 0
004050FF |. 46 |inc esi
00405100 |. 80FB 08 |cmp bl, 8
00405103 |.^ 72 DF \jb short 004050E4
00405105 |. 68 54B74000 push 0040B754 ; code_buf2
0040510A |. 68 40B74000 push offset <序列号> ; b
0040510F |. E8 EC010000 call 00405300 ;另一个处理序列号的函数,我们后面载分析
; 把用户名保存复制到一个全局缓冲区中,我们称之为name_buf2, 如果用户名长度<8,则两个用户名接起来
; 取前8个字母
00405114 |. BF C0C34000 mov edi, offset <用户名> ; a
00405119 |. 83C9 FF or ecx, FFFFFFFF
0040511C |. 33C0 xor eax, eax
0040511E |. 83C4 08 add esp, 8
00405121 |. F2:AE repne scas byte ptr es:[edi]
00405123 |. F7D1 not ecx
00405125 |. 2BF9 sub edi, ecx
00405127 |. 33ED xor ebp, ebp
00405129 |. 8BD1 mov edx, ecx
0040512B |. 8BF7 mov esi, edi
0040512D |. BF 5EB74000 mov edi, 0040B75E ; ASCII "qiufenghan"
00405132 |. C1E9 02 shr ecx, 2
00405135 |. F3:A5 rep movs dword ptr es:[edi], dword p>
00405137 |. 8BCA mov ecx, edx
00405139 |. 83E1 03 and ecx, 3
0040513C |. F3:A4 rep movs byte ptr es:[edi], byte ptr>
0040513E |. BF C0C34000 mov edi, offset <用户名> ; a
00405143 |. 83C9 FF or ecx, FFFFFFFF
00405146 |. F2:AE repne scas byte ptr es:[edi]
00405148 |. F7D1 not ecx
0040514A |. 49 dec ecx
0040514B |. 80F9 08 cmp cl, 8
0040514E |. 884C24 10 mov byte ptr [esp+10], cl
00405152 |. 73 30 jnb short 00405184 ; 用户名长度是否等于8
00405154 |. 8B5424 10 mov edx, dword ptr [esp+10]
00405158 |. BF C0C34000 mov edi, offset <用户名> ; a
0040515D |. 81E2 FF000000 and edx, 0FF
00405163 |. 83C9 FF or ecx, FFFFFFFF
00405166 |. 81C2 5EB74000 add edx, 0040B75E ; ASCII "qiufenghan"
0040516C |. F2:AE repne scas byte ptr es:[edi]
0040516E |. F7D1 not ecx
00405170 |. 2BF9 sub edi, ecx
00405172 |. 8BC1 mov eax, ecx
00405174 |. 8BF7 mov esi, edi
00405176 |. 8BFA mov edi, edx
00405178 |. C1E9 02 shr ecx, 2
0040517B |. F3:A5 rep movs dword ptr es:[edi], dword p>
0040517D |. 8BC8 mov ecx, eax
0040517F |. 83E1 03 and ecx, 3
00405182 |. F3:A4 rep movs byte ptr es:[edi], byte ptr>; 如果用户名长读小于8,则连接用户名。
00405184 |> C605 66B74000>mov byte ptr [40B766], 0 ; 取用户名的前8个字母
;for(i=0; i<8; i++)
;{
; if(code_buf2[i] >= 0x20)
; ebx += code_buf2[i] ^ name_buf2[i]; //route1
; else
; ebx += code_buf2[i] | name_buf2[i]; //route2
;}
; 后面我们知道,要ebx等于0才算注册成功。ebx的值为8个字节的和,不可能溢出
; 所以只能每个加数为0才可以
; 因为用户名中不可能有为0的字节,所以只要进入路径2中的值不可能为0,
; 所以循环只能完全执行路径一,因为只有两个相同的数异或为0,所以用户名中只能有小写
; 字母(字节值大于20h的字母)。其实就是说此时code_buf2的值就是用户名
0040518B |. B9 54B74000 mov ecx, 0040B754 ;code_buf2
00405190 |. BE 08000000 mov esi, 8
00405195 |> 8A01 /mov al, byte ptr [ecx]
00405197 |. 3C 20 |cmp al, 20
00405199 |. 73 0E |jnb short 004051A9
0040519B |. 33D2 |xor edx, edx
0040519D |. 25 FF000000 |and eax, 0FF
004051A2 |. 8A51 0A |mov dl, byte ptr [ecx+A]
004051A5 |. 0BD0 |or edx, eax
004051A7 |. EB 0C |jmp short 004051B5
004051A9 |> 33D2 |xor edx, edx
004051AB |. 25 FF000000 |and eax, 0FF
004051B0 |. 8A51 0A |mov dl, byte ptr [ecx+A]
004051B3 |. 33D0 |xor edx, eax
004051B5 |> 03EA |add ebp, edx
004051B7 |. 41 |inc ecx
004051B8 |. 4E |dec esi
004051B9 |.^ 75 DA \jnz short 00405195
;如果ebp为0,则认为注册成功
004051BB |. 33C0 xor eax, eax
004051BD |. 5F pop edi
004051BE |. 85ED test ebp, ebp
004051C0 |. 5E pop esi
004051C1 |. 5D pop ebp
004051C2 0F94C0 sete al
004051C5 |. 5B pop ebx
004051C6 |. 59 pop ecx
004051C7 \. C3 retn
8、先在我们看看函数00405300做什么事
00405300 /$ 53 push ebx
00405301 |. 55 push ebp
00405302 |. 8B6C24 10 mov ebp, dword ptr [esp+10] ; arg2
00405306 |. 56 push esi
00405307 |. 57 push edi
00405308 |. 8B7C24 14 mov edi, dword ptr [esp+14] ; arg1
0040530C |. 33C9 xor ecx, ecx
0040530E |. 2BFD sub edi, ebp
00405310 |. 897C24 18 mov dword ptr [esp+18], edi ; arg2
00405314 |. EB 04 jmp short 0040531A
00405316 |> 8B7C24 18 /mov edi, dword ptr [esp+18]
0040531A |> 8D3429 lea esi, dword ptr [ecx+ebp]
0040531D |. 33D2 |xor edx, edx
0040531F |. B8 01000000 |mov eax, 1
00405324 |. C74424 14 070>|mov dword ptr [esp+14], 7 ; arg1
0040532C |. 8A1437 |mov dl, byte ptr [edi+esi]
0040532F |. 8BFA |mov edi, edx
;求一个数的7次方%0x8899的结果
00405331 |> 8BD7 |/mov edx, edi
00405333 |. 0FAFC2 ||imul eax, edx
00405336 |. 3D 99880000 ||cmp eax, 8899
0040533B |. 7E 0A ||jle short 00405347
0040533D |. 99 ||cdq
0040533E |. BB 99880000 ||mov ebx, 8899
00405343 |. F7FB ||idiv ebx
00405345 |. 8BC2 ||mov eax, edx
00405347 |> 8B5424 14 ||mov edx, dword ptr [esp+14]
0040534B |. 4A ||dec edx
0040534C |. 895424 14 ||mov dword ptr [esp+14], edx
00405350 |.^ 75 DF |\jnz short 00405331
00405352 |. 99 |cdq
00405353 |. BF BB000000 |mov edi, 0BB
00405358 |. F7FF |idiv edi
0040535A |. 41 |inc ecx
0040535B |. 83F9 08 |cmp ecx, 8
0040535E |. 8816 |mov byte ptr [esi], dl
00405360 |. C60429 00 |mov byte ptr [ecx+ebp], 0
00405364 |.^ 7C B0 \jl short 00405316
00405366 |. 5F pop edi
00405367 |. 5E pop esi
00405368 |. 5D pop ebp
00405369 |. 5B pop ebx
0040536A \. C3 retn
该函数实际是把参数1中的每个字节的7次方模0x8899的结果再模0xbb的结果保存在参数2中相应的位置。
9、我们再来看看程序中的StrToHex的实现
004052D0 >/$ 8B4C24 04 mov ecx, dword ptr [esp+4]
004052D4 |. 8A01 mov al, byte ptr [ecx]
004052D6 |. 3C 39 cmp al, 39
004052D8 |. 7E 04 jle short 004052DE
004052DA |. 04 C9 add al, 0C9
004052DC |. EB 02 jmp short 004052E0
004052DE |> 04 D0 add al, 0D0
004052E0 |> 8A49 01 mov cl, byte ptr [ecx+1]
004052E3 |. 80F9 39 cmp cl, 39
004052E6 |. 7E 09 jle short 004052F1
004052E8 |. C0E0 04 shl al, 4
004052EB |. 80E9 37 sub cl, 37
004052EE |. 0AC1 or al, cl
004052F0 |. C3 retn
004052F1 |> C0E0 04 shl al, 4
004052F4 |. 80E9 30 sub cl, 30
004052F7 |. 0AC1 or al, cl
004052F9 \. C3 retn
可见这个函数功能并不完善,它要求str只能是数字或大写字母
10、先在注册算法清楚了
a、用户名需要大于等于5各字节,序列号为17个以上字节
b、用户名小于8个字符时,需要连接自己组成长于8个字符的串,用户名只使用前8个字符。我们称为name。
c、注册码的第9个字符将被抛弃。
d、把注册码当作16进制数串恢复为8个字节值,多余的抛弃。我们称为code,
e、(pow(code[i] ^ (0x50 + i), 7) % 0x8899 ) % 0xBB == name[i]
11、一个注册机参考实现如下:
int APIs32KeyGen(char* name)
{
int len = strlen(name);
if(len< 5)
{
printf("用户名长度必须大于4.\n");
return 1;
}
char* lName = new char[len * 2 + 1];
if(lName == NULL)
{
printf("内存不足.\n");
return 1;
}
//TODO check是否全为小写字母
::strcpy(lName, name);
::strcpy(lName + len, name);
lName[len * 2] = '\0';
unsigned char res[8];
bool find = true;
for(int n=0; n <8; n++)
{
find = false;
for(unsigned char i=2; i<=0xFF; i++)
{
unsigned int k = 1;
for(int m=0; m<7; m++)
{
k *= i;
if(k > 0x8899)
{
k %= 0x8899;
}
}
if((k % 0xBB) == lName[n])
{
res[n] = i ^ (0x50 + n);
find = true;
break;
}
}
if(find == false)
{
break;
}
}
if(find)
{
printf("用户名%s的注册码为:", name);
char buf[18];
::sprintf(buf, "%02x%02x%02x%02x=%02x%02x%02x%02x", res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7]);
::strupr(buf);
printf("%s", buf);
}
else
{
printf("未能为用户名%s找到注册码", name);
}
printf("\n");
delete [] lName;
return 0;
}
12、终于完成了。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2009年01月07日 下午 07:36:12