大家自行利用【函数断点】或【堆栈查看分析法】 或者其他的手段,定位到程序的关键位置.
代码:
004011CA . 8A4424 4C mov al, byte ptr [esp+4C] ; 将用户名的第一个字节复制给al 004011CE . 84C0 test al, al ; 检测是否输入了用户名 004011D0 . 74 76 je short 00401248 004011D2 . 83FB 05 cmp ebx, 5 ; 将侧用户名的长度是否小于5 004011D5 . 7C 71 jl short 00401248 004011D7 . 8D5424 4C lea edx, dword ptr [esp+4C] ; 提取输入的注册名【edx】 004011DB . 53 push ebx ; 用户名长度入栈 004011DC . 8D8424 A00000>lea eax, dword ptr [esp+A0] ; 提取输入的序列号【eax】 004011E3 . 52 push edx ; 用户名 004011E4 . 50 push eax ; 序列号 004011E5 . E8 56010000 call 00401340 ; 用户名与注册码的检测过程【算法过程】 004011EA . 8B3D BC404000 mov edi, dword ptr [<&USER32.GetDlgItem>] ; USER32.GetDlgItem 004011F0 . 83C4 0C add esp, 0C ; 平衡堆栈 004011F3 . 85C0 test eax, eax 004011F5 . 74 37 je short 0040122E ; 关键跳---【决定注册是否成功】
这里的call就是注册码的计算过程,我们写注册机就是利用这个算法过程.
代码:
================================================= 用户名与序列号的算法过程如下: 00401340 /$ 55 push ebp ; 【算法过程】用户名与注册码的检测过程 00401341 |. 8B6C24 0C mov ebp, dword ptr [esp+C] 00401345 |. 56 push esi 00401346 |. 57 push edi 00401347 |. 8B7C24 18 mov edi, dword ptr [esp+18] ; 【for(i=3,j=0,i<len,i++,j++)】 0040134B |. B9 03000000 mov ecx, 3 ; i=3,ecx作为变量i使用 00401350 |. 33F6 xor esi, esi ; code=0 00401352 |. 33C0 xor eax, eax ; j=0,eax作为j使用 00401354 |. 3BF9 cmp edi, ecx ; i<len 吗 00401356 |. 7E 21 jle short 00401379 00401358 |. 53 push ebx ; 注意这一句与401378呼应 00401359 |> 83F8 07 /cmp eax, 7 ; j>7,j=0 0040135C |. 7E 02 |jle short 00401360 0040135E |. 33C0 |xor eax, eax ; 防止处理中文时符号扩展 00401360 |> 33D2 |xor edx, edx ; 清零 00401362 |. 33DB |xor ebx, ebx 00401364 |. 8A1429 |mov dl, byte ptr [ecx+ebp] ; name[i] 00401367 |. 8A98 30504000 |mov bl, byte ptr [eax+405030] ; Table[j],00405030地址处放的是数据表 0040136D |. 0FAFD3 |imul edx, ebx ; edx=name[i]*Table[j] 00401370 |. 03F2 |add esi, edx ; code +=edx 00401372 |. 41 |inc ecx ; i++ 00401373 |. 40 |inc eax ; j++ 00401374 |. 3BCF |cmp ecx, edi ; i<len 00401376 |.^ 7C E1 \jl short 00401359 00401378 |. 5B pop ebx 00401379 |> 56 push esi ; /code 0040137A |. 68 78504000 push 00405078 ; |Format = "%ld" 0040137F |. 55 push ebp ; |name 00401380 |. FF15 9C404000 call dword ptr [<&USER32.wsprintfA>] ; \wsprintfA 00401386 |. 8B4424 1C mov eax, dword ptr [esp+1C] ; 将参数从堆中传给eax【序列号Code的指针】 0040138A |. 83C4 0C add esp, 0C 0040138D |. 55 push ebp ; /ebp指向真正的序列号 0040138E |. 50 push eax ; |eax指向输入的序列号 0040138F |. FF15 04404000 call dword ptr [<&KERNEL32.lstrcmpA>] ; \lstrcmpA 00401395 |. F7D8 neg eax 00401397 |. 1BC0 sbb eax, eax 00401399 |. 5F pop edi 0040139A |. 5E pop esi 0040139B |. 40 inc eax 0040139C |. 5D pop ebp 0040139D \. C3 retn
代码:
.const .data szHomePage db "http://www.pediy.com",0 szEmail db "mailto:Gall@163.com",0 szErrMess db "输入的序列号不正确!",0 dataTemp db 0CH,0AH,13H,09H,0CH,0BH,0AH,08H szBuffer db 50 dup(0) szFmt db "%ld",0 .code mov ebp,eax ; eax指向的是第一个文本框 invoke lstrlen,ebp ; 获取输入的字符的长度 mov edi,eax ; lstrlen返回的是输入的注册名的长度 mov ecx,3H ; 注意这里的数值后面需要加H标记 xor esi,esi xor eax,eax x2: mov ebx,edi ; ebx中存放的是注册名的长度 cmp eax,7H jle x1 xor eax,eax ; 上面有一句push ebx x1: xor edx,edx xor ebx,ebx mov dl,byte ptr [ecx+ebp] mov bl,byte ptr [eax+dataTemp] imul edx,ebx add esi,edx inc ecx inc eax cmp ecx,edi jl x2 invoke wsprintf,addr szBuffer,addr szFmt,esi lea eax,szBuffer