• 标 题:我的破解心得(1) (3千字)
  • 作 者:chcw
  • 时 间:2001-3-13 17:49:55
  • 链 接:http://bbs.pediy.com

说明:这是我以前写的心得,贴在这里,请大家指正。

破解对象:
  IrfanView32

破解工具:
  W32Dasm 8.5(或更高版本)
  Hacker View 5.6(或更高版本)

破解者:
  chcw

IrfanView32是一个免费软件,程序作者没有花什么力气来对付Cracker,故较适合
初学Crack的人练习用。

1. 运行IrfanView32。
2. 选择About/Registration, 随便输一个name和code, 如
  name=chcw, code=9530109。
3. 一般来说,你的注册码当然是错误的(除非你的运气特别好,刚好给你碰对了)
  程序将显示一个消息框, 内容是"Incorrect registration!"。记下该信息后,
  退出IrfanView32。
4. 运行W32Dasm, 将I_view32.exe反汇编。
5. 反汇编结束后,选择W32Dasm菜单Refs/String Data References, 从列表框中
  找出字符串"Incorrect registration!", 选中后用鼠标双击,W32Dasm将把亮
  条定位在反汇编代码中访问到该字符串的代码行上。
6. 关闭字符串列表对话框,我们来看一下亮条处的代码:
                    ...    
:0041A733 E8C868FEFF              call 00401000
:0041A738 83C408                  add esp, 00000008
:0041A73B 85C0                    test eax, eax
:0041A73D 751B                    jne 0041A75A
                    ...                            
* Possible StringData Ref from Data Obj ->"Incorrect registration !"
                                  |
:0041A74F 68A0E24700              push 0047E2A0      <-亮条所在处
:0041A754 51                      push ecx
:0041A755 E9FEFDFFFF              jmp 0041A558

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041A73D(C)
                             
:0041A75A 8B354C754900            mov esi, dword ptr [0049754C]

  从亮条所在处往上找,可以发现在0041A73B处有一条test eax,eax语句,它
后面的jne语句是eax为非零值时,跳转到0041A75A处,正好跳过了对字符串
"Incorrect registration !"的引用。而在test语句前有一个call 00401000调
用。因此,00401000很可能就是一个对注册码进行检查的函数,当注册码合法时
返回非零值,否则返回零,并显示错误信息。将亮条移到:0041A733 call 00401000
语句处,亮条呈亮绿色。按工具栏上的"Call"按钮进入该子程序。在子程序ret
语句前有下面几条语句:

:00401280 3BE8                    cmp ebp, eax
        ...
:00401284 0F94C1                  sete cl
        ...    
:00401288 8BC1                    mov eax, ecx
        ...
:0040128E C3                      ret

  可见,如果猜想正确,那么我们只需要将00401284处的sete cl语句改为
setne cl,就可以使注册成功。

7. 在W32Dasm中,将亮条移到00401284的jne语句处,此时在W32Dasm反汇编窗口
的状态行中将显示@Offset 00000684h in File:I_view32.exe, 记下这个偏移地
址。
    
8. 将I_view32.exe备份,运行Hiew I_view32.exe,按F4键(Mode),选择Decode
模式,再按F5键(Goto), 输入偏移地址684,Hiew将定位到偏移684处:

.00401284 0F94C1          sete cl

9. 现在我们将这条语句改为setne cl,按F3键(Edit),输入0F95(setne的机器码)
将原先的0F94(sete的机器码)覆盖,此时我们可以看到机器码右部的汇编代码也发生
了相应的变化。再按F9键(Update),保存所作的修改,退出Hiew。

10. 运行I_view32.exe, 随便输入一个注册码(如Name="chcw",Code="9530109")选
择"OK",程序显示"Register Successful",再到About/About IrfanView中,可以看
到原先的registered to You字样改成了registerd to chcw。注册成功了!
    在修改过I_view32.exe之后,如果你输入了正确的注册码,程序反而会提示
"Incorrect registeration"。

11. 有人也许会想,能不能将调用检测函数00401000之后的语句0041A73D jne 0041A75A
改为je或jmps语句,从而达到相同的效果呢?回答是否定的。的确,很多软件都可以在
检测函数之外的跳转处Patch,而且这样做一般来说更为安全,但是IrfanView32却是例外。
IrfanView32相当狡猾,它在程序启动时、注册时和显示About IrfanView32对话框时都会
反复调用00401000函数检验注册的正确性。所以直接改动检测函数也许更为合理一些。

  • 标 题:我的破解心得(2) (2千字)
  • 作 者:chcw
  • 时 间:2001-3-13 17:54:50

破解对象:
  IrfanView32
破解者:
  chcw

  在上一节中,我们已经知道,只要将执行程序I_view32.exe在Offset=0x685处
的字节从0x94改为0x95即可破解IrfanView32。在这一节,我们将介绍如何为
IrfanView32写一个Patcher,它在执行时自动完成上述的修改任务。

--------------------- Patcher.c -----------------------

#include <stdio.h>
#include <stdlib.h>

void main()
{
    unsigned char patch=0x95;
        long offset=0x00000685;
    FILE *fp;
    
    printf("Crack for IrfanView32\n");
    printf("Written by Mr. Chcw\n");
    
        if ((fp=fopen("I_view32.exe", "r+"))==NULL) {
        printf("Error: Cannot find file I_view32.exe\n");
        exit(1);
    }
    
        fseek(fp,offset,SEEK_SET);
    fputc(patch,fp);
    
    printf("Patch successful\n");
}        

--------------------- End of Patcher.c ------------------

  Patcher.c程序先将可执行文件I_view32.exe读入,然后通过偏移地址定位
到要Patch的地方,再用机器码0x95改写该处的字节,就完成了Patch过程。
  当然,在实际应用中,待Patch的程序因版本的不同可能会产生Patch地址的
偏差或Patch代码的偏差,我们需要在Patch之前检查待Patch的程序的版本(如
根据程序的大小)和Patch处原机器码是否正确,以保证不会Patch错误。
  下面是一个改进的Patcher1.c程序:

----------------------- Patcher1.c ------------------------

#include <stdio.h>
#include <io.h>
#include <stdlib.h>

void main()
{
    const long filesize=614912;    //614,912 bytes
    const unsigned char oldcode=0x94;
    
    unsigned char patchcode=0x95;
    long offset=0x00000685;
    FILE *fp;
    
    printf("Crack for IrfanView32\n");
    printf("Written by Mr. Chcw\n");
    
    if ((fp=fopen("I_view32.exe", "r+"))==NULL) {
        printf("Error: Cannot find file I_view32.exe\n");
        exit(1);
    }
    else if (filelength(fileno(fp))!=filesize) {
        printf("Error: Incorrect IrfanView32 version, cannot patch it\n");
        exit(2);
    }    
    
    fseek(fp,offset,SEEK_SET);
    if (fgetc(fp)!=oldcode) {
        printf("Error: The file I_view32.exe is corrupted\n");            
        exit(3);
    }        
    
    fseek(fp,offset,SEEK_SET);
    fputc(patchcode,fp);
    fclose(fp);

    printf("Patch successful\n");
}        
    
-------------------- End of Patcher1.c --------------------

  • 标 题:我的破解心得(3) (3千字)
  • 作 者:chcw
  • 时 间:2001-3-13 17:56:30

破解对象:
  IrfanView32

破解者:
  chcw

  在上两节中,我们介绍了通过修补IrfanView32程序来破解其注册检验的方法。
修补程序(或称Patch)是Crack中常用的一种方法,它的缺点也是显而易见的,主要
有以下几点:
  1. 不少程序在运行时会检查自身的完整性(如Win Command32),如果发现自身被
    修改过,就会立即报错退出,Patch方法对这类程序就无计可施了(除非把程
    序检查完整性的部分也给Patch掉)。
  2. 有些程序在通过编译优化后,可能不只在一处调用Patch过的代码,因此Patch
    此类程序一般要相当小心,对Patch点的选取是关键。如果Patch不好的化,在
    程序运行时,可能会产生许多莫名其妙的错误。     
  3. 有些查毒程序(如MSAV),在扫描硬盘上的程序文件时,同时会生成这些文件
    的校验码,以备日后检查文件完整性用。因此,如果我们Patch了一个受查毒
    程序校验和保护的程序,查毒程序可能会认为该程序被病毒感染。
  4. Patch程序常以执行文件方式提供,容易传播病毒。
  5. Patch程序对错误的执行文件版本进行Patch后,会导致无法预料的结果。

  另一种常用的Crack方法是直接获取程序的合法注册码或是序列号,然后通过正常的
注册过程完成注册,这种方法可以避免对执行程序本身进行修改,因而不会有Patch方
法的那些问题;它的缺点是工作量较大,破解者往往需要理解整个注册检验函数的工作
机理。
  还是以IrfanView32为例,在上一节中,我们已经知道:0041A733  call 00401000语
句很可能就是程序检验注册码的子程序,在这一节中,我们将分析子程序00401000,并
从中获取IrfanView32的注册码。

1. 用WinICE载入I_view32.exe。
2. 按Ctrl D,回到IrfanView32窗口。选择About/Registration,打开注册窗口。
3. 按Ctrl D, 回到WinICE窗口,键入命令BPX MessageBoxA,对消息框设置断点。再键入X
  命令,回到注册窗口。
4. 在注册窗口中输入注册码Name=chcw,Code=9530109, 按OK命令键,触发我们刚才设置的
  断点,进入WinICE窗口。
5. 用BC *命令清除原先的断点。然后键入命令BPX CS:0041A733,在调用00401000子程序的
  语句处设置新的断点。键入X命令,回到IrfanView32窗口。
6. 再次输入注册码,按OK后,触发断点。执行亮带停留在0137:0041A733 call 00401000语
  句处,检查该程序的调用,发现参数1为串"chcw"的地址,参数2为串"9530109"的地址,
  这就进一步证实了00401000子程序是注册检验函数的猜想。
7. 按F8,进入该子程序调用。其中有不少子程序调用语句和循环,先不去管它们,不断按
  F10,跳过(Step Out)这些语句,最后到达00401000子程序的返回语句附近:
        :00401280 cmp ebp, eax
            ...
                :00401284 sete cl
            ...
        :00401288 mov eax, ecx
              ...
        :0040128E ret
  这几条语句是处理子程序00401000的返回值用的(大部分函数的返回值都放在eax中),
  其效果相当于c语言中的return (%epb==%eax);在上两节中,我们知道,当子程序
  00401000返回值eax不为零时,注册成功。因此,在对用户输入的姓名和注册码进行一定
  的运算之后,只要满足%ebp==%eax,注册就算成功了。记下在语句cmp ebp, eax处的ebp
  和eax的值,ebp=00916AFD, eax=10E1B31A。
8. 键入X命令后,回到IrfanView32窗口,再次输入注册码,进入子程序00401000, 设置断点
      EPR cs:00401000 cs:00401280 R if ((ebp==00916AFD) || (eax==10E1B31A))
  该断点是用来查找从cs:00401000到00401280的语句中,将ebp设置为00916AFD或将eax设
  置为10E1B31A的第一条语句。键入X命令后,中断被触发,相继找到ebp=00916AFD是
  :0040100E处 call 0045F770子程序调用的返回值。eax=10E1B31A是
  :00401276处 call 0045F770子程序调用的返回值。在这两处分别设置一次性断点。发现
  对子程序0045F770子程序的两次调用的参数分别为字符串"9530109"和"283226906"。既
  然两次调用的函数都是0045F770,那么只要我们将原先的注册码"9530109"改为"283226906"
  ,调用后的返回值ebp和eax就是相等的,注册也就会成功。
  因而得到IrfanView32的注册码为Name="chcw", Code="283226906"。

小结:
  00401000是IrfanView32的注册检验函数,该函数首先将用户姓名("chcw")作某种转化后
  得到数字代码("283226906"),然后将该代码和用户输入的注册码("9530109")分别通过函
  数0045F770进行变换,最后通过比较两者的变换值是否相等来判断注册是否成功。奇怪的
  是,IrfanView32在第二步中对数字代码和注册码进行变换时所用的函数都是0045F770。
  我们知道,对于函数,当x1=x2时,必有f(x1)=f(x2),所以无论函数0045F770作了何种变
  换,我们只要使注册码和通过姓名计算出的数字代码相同,就可以确保注册的成功。

  • 标 题:我的破解心得(4) (13千字)
  • 作 者:chcw
  • 时 间:2001-3-13 18:01:26

版权说明:本文作者为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  -------------------------