版权说明:本文作者为Chcw, 未经作者同意,不得转载此文。
破解程序:
IrfanView32
破解工具:
Extract 1.0
Sourcer 7.0
Visual C++ 5.0
在我的破解心得(3)中,我们采用手工调试的方法获得了Name="chcw"时对应的注册码
Code="283226906"。更进一步,我们希望能够编写一个注册码生成器,使得对应于不同的
用户姓名,可以生成相应的正确注册码。我们知道,不少程序的注册检验函数都可以表示
为以下的流程:
user_name = get_username() /*
获取用户输入的姓名 */
user_regcode = get_userregcode() /*
获取用户输入的注册码 */
regcode = compute_regcode(user_name) /*
对用户姓名做复杂的计算,得到一个合法的
注册码 */
if (!isequal(usr_regcode, regcode)) /*
将上述合法的注册码与用户输入的注册码比较,
register_error()
若不相同则认为注册非法 */
通常,如果我们要实现一个注册码生成器,必须了解整个注册检验过程中compute_regcode()
部分的工作机制,然后用编码实现与之相类似的效果。显然,这种方法费时费力,而且只对
当前所破解的软件有效,意义不大。
其实,我们完全可以不必了解compute_regcode()的内部机制,只需要直接将应用程序中
compute_regcode部分反汇编拷贝到注册码生成器中,然后重新编译即可。这种方法不仅减少
了编写注册机的工作量,而且由于这部分代码是源于应用程序的,因此一般不会出错。
仍以IrfanView32为例,在破解心得(3)中,我们已经知道函数00401000子程序是注册检验
函数,该函数在00401275处的ds:edx是指向合法注册码的一个指针。显然在从程序入口到
00401275处是生成注册码的部分。下面我们将把它反编译并加入到我们的注册机中:
1.IrfanView32的程序文件I_View32.exe很大,无法直接用Sourcer进行反汇编,因此需要先用
一个叫Extract的工具对它进行处理。Extract是"Undocumented Windows"一书所附带的一个
程序,其功能是将二进制程序的一部分截取出来。
由于我们所要返汇编的函数为00401000,用W32Dasm可以得到它在执行程序I_view32.exe
中的偏移地址为0x400,函数00401000同时还调用了0046C700等子函数,我们就大致取截取
长度为0x70000,使之能将函数00401000和0046C700同时包含进来。
输入命令 Extract I_view32.exe 0x400 0x70000 Tmp.bin 将生成一个二进制文件Tmp.bin。
2.用Sourcer打开Tmp.bin, 将反汇编的File Format设置为.asm文件,将编译的平台设置为
386 Protected,并在Analysis Option中打开Default to USE32选项。设置完所有参数后,
按'G',反汇编Tmp.bin,生成Tmp.asm文件。
3.在Visual C++中建立一个工程,类型为Win32 Console Application,并在工程中添加一个KeyMaker.C
的源程序文件。
4.在KeyMaker.C文件中构造一个新函数makekey(),打开文件Tmp.asm,将函数00401000(以
start::为启始标志)中的语句复制到makekey()函数中,并加上__asm外套,如下所示:
__declspec(naked) void makekey()
{
__asm {
mov eax,dword ptr
[esp+8] ; 函数00401000的第一条语句
...
retn
; 函数00401000的返回语句
}
}
其中__declspec(naked)是用来去除MakeKey()函数的标准堆栈框的。
5.在函数00401000中还调用了其他几个函数, 其中call sub_763就是对函数0045F770的调用,在破解心
得(3)中我们已经知道,在00401000函数中对0045F770函数的两处调用并没有什么意义。因此可以直接
将其该改为nop语句(这里必须保证堆栈的正确性), 如下所示:
call sub_763 改为->
nop
...
...
call sub_999
call sub_999
...
...
call sub_763 改为->
nop
6.接下来,我们需要处理sub_999函数,在KeyMaker.C文件中构造一个新函数func1(),将函数sub_999的语
句复制到func1()内,并将makekey()中对sub_999的调用作相应的改动:
__declspec(naked) void func1()
{
__asm {
mov ecx,dword
ptr [esp+0Ch] ; 函数sub_999的第一条语句
...
retn
; 函数sub_999的返回语句
}
}
__declspec(naked) void makekey()
{
__asm {
...
call func1() ;
函数MakeKey()中对函数sub_999的调用语句
...
}
}
7.同理也可以对func1()函数中进一步调用的其他函数作相应的处理。
8.到现在为止,我们已经将IrfanView32中的注册码生成部分复制到makekey()函数中了,接下来我们
需要考虑makekey()函数的环境处理,即正确的输入和输出。从上一节我们知道,makekey()函数的
输入参数是用户输入的注册码和注册名,因此在调用该函数之前,应该在栈中压入正确的参数:
char usrcode[32]="9530109";
char name[32]="chcw";
__asm {
lea eax,dword ptr usrcode
push eax
; 将用户输入的注册码字符串地址压栈
lea eax,dword ptr name
push eax
; 将用户输入的姓名字符串的地址压栈
call makekey()
; 调用函数makekey()
add esp, 8h
}
当然,在调用完makekey()之后,应当调整堆栈指针。
9.makekey()函数的输出应该是正确的注册码,在上文中,我们已经说过,在:00401275处执行push edx
语句时的ds:edx指向正确注册码的地址。由于这个注册码是在堆栈中生成的,在调用完函数makekey()
并退栈之后将不复存在, 因此为了使主程序能够得到完整的注册码,必须将其保存下来:
我们首先声明一个全局变量regcode, 用它来保存注册码的值:
char regcode[256];
然后,在00401275处的语句之后加上一端代码,将ds:edx所指的注册码复制到regcode中:
push edx
; 原字符串地址压栈
lea eax, dword
ptr regcode
push eax
; 目标字符串regcode地址压栈
call strcpy
; 调用strcpy函数进行复制
add esp,8
; 调整栈指针
通过这种方法,我们就成功的将00401000函数(makekey()函数)生成的临时注册码保存在regcode
中了。
9.最后,我们可以在调用00401000函数(makekey()函数)的主程序main()中加上一些输入输出语句,使程
序更为完善。
附:IrfanView32的注册码生成器KeyMaker.C
-------------------------- KeyMaker.C ----------------------------------
#include <string.h>
#include <stdio.h>
char regcode[256]="";
__declspec(naked) void func2()
{
__asm {
mov eax,dword ptr
[esp+10h]
push ebx
push ebp
push esi
mov esi,dword ptr
[esp+14h]
push edi
test eax,eax
jz short loc_9308
; Jump if zero
mov edi,dword ptr
[esp+14h]
mov byte ptr [esi],2Dh
; '-'
inc esi
neg edi
jmp short loc_9309
loc_9308:
mov edi,dword ptr
[esp+14h]
loc_9309:
mov ebp,dword ptr
[esp+1Ch]
mov ebx,esi
loc_9310:
mov eax,edi
xor edx,edx
; Zero register
div ebp
; ax,dx rem=dx:ax/reg
mov eax,edi
mov ecx,edx
xor edx,edx
; Zero register
div ebp
; ax,dx rem=dx:ax/reg
cmp ecx,9
mov edi,eax
jbe short loc_9311
; Jump if below or =
add cl,57h
; 'W'
jmp short loc_9312
loc_9311:
add cl,30h
; '0'
loc_9312:
mov [esi],cl
inc esi
test edi,edi
ja loc_9310
; Jump if above
mov byte ptr [esi],0
dec esi
loc_9313:
mov cl,[ebx]
mov al,[esi]
mov [esi],cl
mov [ebx],al
dec esi
inc ebx
cmp ebx,esi
jb loc_9313
; Jump if below
pop edi
pop esi
pop ebp
pop ebx
retn
}
}
__declspec(naked) void func1()
{
__asm {
mov ecx,dword ptr [esp+0Ch]
mov edx,dword ptr
[esp+4]
cmp ecx,0Ah
push esi
jnz short loc_9314
; Jump if not zero
test edx,edx
jge short loc_9314
; Jump if > or =
mov esi,dword ptr
[esp+0Ch]
mov eax,1
push eax
push ecx
push esi
push edx
call func2
add esp,10h
mov eax,esi
pop esi
retn
loc_9314:
mov esi,dword ptr
[esp+0Ch]
xor eax,eax
; Zero register
push eax
push ecx
push esi
push edx
call func2
add esp,10h
mov eax,esi
pop esi
retn
}
}
__declspec(naked) void makekey()
{
__asm {
mov eax,dword ptr
[esp+8]
sub esp,14h
push ebx
push ebp
push esi
push edi
push eax
xor ebx,ebx
; Zero register
nop
mov esi,dword ptr
[esp+2Ch]
mov ebp,eax
mov edi,esi
or ecx,0FFFFFFFFh
xor eax,eax
; Zero register
add esp,4
xor edx,edx
; Zero register
repne scasb
; Rep zf=0+cx >0 Scan
es:[di] for al
not ecx
dec ecx
test ecx,ecx
jle short loc_4
; Jump if < or =
loc_3:
movsx ecx,byte ptr
[edx][esi] ; Mov w/sign extend
add ebx,ecx
mov edi,esi
or ecx,0FFFFFFFFh
xor eax,eax
; Zero register
inc edx
repne scasb
; Rep zf=0+cx >0 Scan
es:[di] for al
not ecx
dec ecx
cmp edx,ecx
jl loc_3
; Jump if <
loc_4:
mov eax,104h
push dword ptr 0Ah
sub eax,ebx
cdq
; dword to quad word
xor eax,edx
sub eax,edx
add eax,14Ch
mov edx,eax
shl edx,3
; Shift w/zeros fill
sub edx,eax
lea ecx,[eax][edx*4]
; Load effective addr
lea edx,dword ptr
[esp+14h] ; Load effective addr
push edx
lea esi,[eax][ecx*2]
; Load effective addr
shl esi,3
; Shift w/zeros fill
push esi
call func1
add esp,0Ch
cmp esi,0F423Fh
ja loc_5
; Jump if above
mov cl,byte ptr
[esp+14h]
mov al,byte ptr
[esp+15h]
mov dl,byte ptr
[esp+13h]
mov byte ptr [esp+16h],cl
mov cl,byte ptr
[esp+11h]
mov byte ptr [esp+18h],al
mov al,byte ptr
[esp+12h]
mov byte ptr [esp+12h],cl
mov ecx,dword ptr
[esp+18h]
mov byte ptr [esp+13h],al
and ecx,0FFh
mov byte ptr [esp+15h],dl
mov edx,dword ptr
[esp+14h]
lea eax,[ecx][ecx*4]
; Load effective addr
and edx,0FFh
shl eax,3
; Shift w/zeros fill
sub eax,ecx
mov ecx,edx
shl ecx,5
; Shift w/zeros fill
sub ecx,edx
lea edx,[ecx][ecx*2]
; Load effective addr
sub eax,edx
cdq
; dword to quad word
mov ecx,eax
xor ecx,edx
sub ecx,edx
lea eax,[ecx][ecx*4]
; Load effective addr
shl eax,3
; Shift w/zeros fill
sub eax,ecx
mov ecx,9
cdq
; dword to quad word
idiv ecx
; ax,dx rem=dx:ax/reg
mov eax,dword ptr
[esp+13h]
and eax,0FFh
add edx,30h
mov byte ptr [esp+17h],dl
lea edx,[eax][eax*2]
; Load effective addr
shl edx,4
; Shift w/zeros fill
sub edx,eax
mov eax,dword ptr
[esp+15h]
and eax,0FFh
lea ecx,[eax][eax*8]
; Load effective addr
lea eax,[eax][ecx*4]
; Load effective addr
lea eax,[edx][eax*2]
; Load effective addr
cdq
; dword to quad word
xor eax,edx
sub eax,edx
lea ecx,[eax][eax*8]
; Load effective addr
lea eax,[eax][ecx*4]
; Load effective addr
mov ecx,9
shl eax,1
; Shift w/zeros fill
cdq
; dword to quad word
idiv ecx
; ax,dx rem=dx:ax/reg
mov ecx,dword ptr
[esp+10h]
and ecx,0FFh
lea eax,[ecx][ecx*2]
; Load effective addr
lea eax,[eax][eax*8]
; Load effective addr
shl eax,1
; Shift w/zeros fill
sub eax,ecx
add edx,30h
mov byte ptr [esp+14h],dl
mov edx,dword ptr
[esp+11h]
and edx,0FFh
mov ecx,edx
shl ecx,3
; Shift w/zeros fill
sub ecx,edx
lea edx,[ecx][ecx*4]
; Load effective addr
sub eax,edx
cdq
; dword to quad word
mov ecx,eax
xor ecx,edx
sub ecx,edx
lea eax,[ecx][ecx*2]
; Load effective addr
lea eax,[eax][eax*8]
; Load effective addr
shl eax,1
; Shift w/zeros fill
sub eax,ecx
jmp loc_6
loc_5:
mov al,byte ptr
[esp+15h]
mov dl,byte ptr
[esp+16h]
mov cl,byte ptr
[esp+14h]
mov byte ptr [esp+16h],al
mov al,byte ptr
[esp+11h]
mov byte ptr [esp+18h],dl
mov dl,byte ptr
[esp+12h]
mov byte ptr [esp+15h],cl
mov ecx,dword ptr
[esp+16h]
mov byte ptr [esp+12h],al
mov eax,dword ptr
[esp+18h]
and ecx,0FFh
and eax,0FFh
mov byte ptr [esp+13h],dl
mov edx,ecx
lea eax,[eax][eax*8]
; Load effective addr
shl edx,6
; Shift w/zeros fill
shl eax,2
; Shift w/zeros fill
sub edx,ecx
mov ecx,9
sub eax,edx
cdq
; dword to quad word
xor eax,edx
sub eax,edx
lea eax,[eax][eax*8]
; Load effective addr
shl eax,2
; Shift w/zeros fill
cdq
; dword to quad word
idiv ecx
; ax,dx rem=dx:ax/reg
mov eax,dword ptr
[esp+13h]
and eax,0FFh
add edx,30h
mov byte ptr [esp+17h],dl
lea edx,[eax][eax*4]
; Load effective addr
shl edx,3
; Shift w/zeros fill
sub edx,eax
mov eax,dword ptr
[esp+14h]
and eax,0FFh
add eax,20h
mov ecx,eax
shl ecx,3
; Shift w/zeros fill
sub ecx,eax
lea eax,[eax][ecx*4]
; Load effective addr
lea eax,[eax][eax*2]
; Load effective addr
lea eax,[eax][edx*2]
; Load effective addr
cdq
; dword to quad word
xor eax,edx
sub eax,edx
mov ecx,eax
shl ecx,3
; Shift w/zeros fill
sub ecx,eax
lea eax,[eax][ecx*4]
; Load effective addr
mov ecx,9
lea eax,[eax][eax*2]
; Load effective addr
cdq
; dword to quad word
idiv ecx
; ax,dx rem=dx:ax/reg
mov eax,dword ptr
[esp+10h]
and eax,0FFh
add dl,30h
; '0'
mov byte ptr [esp+14h],dl
mov edx,eax
shl edx,3
; Shift w/zeros fill
sub edx,eax
lea eax,[eax][edx*4]
; Load effective addr
mov edx,dword ptr
[esp+11h]
and edx,0FFh
mov ecx,edx
shl ecx,4
; Shift w/zeros fill
add ecx,edx
shl eax,1
; Shift w/zeros fill
lea ecx,[ecx][ecx*4]
; Load effective addr
sub eax,ecx
cdq
; dword to quad word
xor eax,edx
sub eax,edx
mov edx,eax
shl edx,3
; Shift w/zeros fill
sub edx,eax
lea eax,[eax][edx*4]
; Load effective addr
shl eax,1
; Shift w/zeros fill
loc_6:
cdq
; dword to quad word
mov ecx,9
mov byte ptr [esp+19h],0
idiv ecx
; ax,dx rem=dx:ax/reg
add edx,30h
mov byte ptr [esp+11h],dl
lea edx,dword ptr
[esp+10h] ; Load effective addr
push edx
push edx
lea eax, dword ptr regcode
push eax
call strcpy
add esp,8
add esp,4
xor ecx,ecx
; Zero register
cmp ebp,eax
pop edi
pop esi
sete cl
; Set byte if equal
pop ebp
mov eax,edx
pop ebx
add esp,14h
retn
}
}
void main()
{
char usrcode[32]="9530109";
char name[32]="chcw";
printf("KeyMaker for IrfanView32\n");
printf("Written By Mr. Chcw\n");
printf("Please enter your name:");
gets(name);
__asm {
lea eax,dword ptr usrcode
push eax
lea eax,dword ptr name
push eax
call makekey
add esp, 8h
}
printf("The register code is: %s\n", regcode);
}
----------------------- End of File KeyMaker.C -------------------------