【文章标题】: FosiX 2.3.10 注册算法分析
【文章作者】: WAKU
【作者邮箱】: wakuwakuwawaku@163.com
【软件名称】: FosiX
【软件大小】: 2.72MB
【下载地址】: http://www.hushpage.com/FoSi/Fosi_setup.zip
【加壳方式】: 无
【保护方式】: 无
【编写语言】: Delphi
【使用工具】: OD
【操作平台】: XP SP2
【软件介绍】: FosiX是一个磁盘清理工具,最大的特点是可以把磁盘
【作者声明】: 只是研究技术,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
    说明:此文中有一些我习惯使用的符号,先写出来以免大家误解
    注册码长度 > CL    其中>是赋值给的意思,即注册码的长度赋给CL
    运行原程序,未注册的版本有30天的试用限制,点击Help>Register,弹出注册窗口.随便输入一组:
    Name:  WAKU
    Key:  1234
    点击Process Registration,等了一会标题栏显示FosiX.exe Key and username doesn't match.PEID查无壳,OD载入,搜索字符串Key and username doesn't match,找到地址00556145,双击后,往上翻翻,看到这些:

  005560AE  |.  E8 498DFEFF   call    0053EDFC
  005560B3  |.  84C0          test    alal
  005560B5  |.  74 45         je      short 005560FC
  005560B7  |.  8D95 D8FDFFFF lea     edx, [ebp-228]
  005560BD  |.  A1 78925700   mov     eax, [579278]
  005560C2  |.  8B00          mov     eax, [eax]
  005560C4  |.  E8 F785F4FF   call    0049E6C0
  005560C9  |.  8B85 D8FDFFFF mov     eax, [ebp-228]
  005560CF  |.  8D95 DCFDFFFF lea     edx, [ebp-224]
  005560D5  |.  E8 3643EBFF   call    0040A410
  005560DA  |.  8D85 DCFDFFFF lea     eax, [ebp-224]
  005560E0  |.  BA 30625500   mov     edx, 00556230                    ;   Key and username valid
  005560E5  |.  E8 7EEDEAFF   call    00404E68
  005560EA  |.  8B95 DCFDFFFF mov     edx, [ebp-224]
  005560F0  |.  A1 98AE5700   mov     eax, [57AE98]
  005560F5  |.  E8 1E76F2FF   call    0047D718
  005560FA  |.  EB 63         jmp     short 0055615F
  005560FC  |>  BA 50625500   mov     edx, 00556250                    ;  Demo
  00556101  |.  8B83 00030000 mov     eax, [ebx+300]
  00556107  |.  E8 0C76F2FF   call    0047D718
  0055610C  |.  BA 60625500   mov     edx, 00556260                    ;  $2C926BA0
  00556111  |.  8B83 08030000 mov     eax, [ebx+308]
  00556117  |.  E8 FC75F2FF   call    0047D718
  0055611C  |.  8D95 D0FDFFFF lea     edx, [ebp-230]
  00556122  |.  A1 78925700   mov     eax, [579278]
  00556127  |.  8B00          mov     eax, [eax]
  00556129  |.  E8 9285F4FF   call    0049E6C0
  0055612E  |.  8B85 D0FDFFFF mov     eax, [ebp-230]
  00556134  |.  8D95 D4FDFFFF lea     edx, [ebp-22C]
  0055613A  |.  E8 D142EBFF   call    0040A410
  0055613F  |.  8D85 D4FDFFFF lea     eax, [ebp-22C]
  00556145  |.  BA 74625500   mov     edx, 00556274                    ;   Key and username doesn't match

跳转很明显,只要005560AE处的CALL返回非0即可"Key and username valid"了,好我们在005560AE处下断,然后跟进CALL,看到这些:

  0053EDFC  /$  53            push    ebx
  0053EDFD  |.  56            push    esi
  0053EDFE  |.  57            push    edi
  0053EDFF  |.  83C4 B4       add     esp, -4C
  0053EE02  |.  8BF1          mov     esiecx
  0053EE04  |.  8D3C24        lea     edi, [esp]                       ;  ESP > EDI
  0053EE07  |.  33C9          xor     ecxecx
  0053EE09  |.  8A0E          mov     cl, [esi]                        ;  注册码长度 > CL
  0053EE0B  |.  80F9 09       cmp     cl, 9                            ;  长度和9比
  0053EE0E  |.  72 02         jb      short 0053EE12
  0053EE10  |.  B1 09         mov     cl, 9                            ;  如长度大于9,则截断为9位
  0053EE12  |>  880F          mov     [edi], cl
  0053EE14  |.  46            inc     esi
  0053EE15  |.  47            inc     edi
  0053EE16  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>;  把注册码长度和注册码COPY到EDI指向的内存
  0053EE18  |.  8BF2          mov     esiedx
  0053EE1A  |.  8D7C24 0A     lea     edi, [esp+A]
  0053EE1E  |.  33C9          xor     ecxecx
  0053EE20  |.  8A0E          mov     cl, [esi]                        ;  用户名长度 > CL
  0053EE22  |.  80F9 32       cmp     cl, 32                           ;  长度和32H比
  0053EE25  |.  72 02         jb      short 0053EE29
  0053EE27  |.  B1 32         mov     cl, 32                           ;  如长度大于32H,则截断为32H位
  0053EE29  |>  880F          mov     [edi], cl
  0053EE2B  |.  46            inc     esi
  0053EE2C  |.  47            inc     edi
  0053EE2D  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>;  把用户名长度和用户名COPY到EDI指向的内存
  0053EE2F  |.  8BF0          mov     esieax
  0053EE31  |.  33DB          xor     ebxebx
  0053EE33  |.  889E 55030000 mov     [esi+355], bl
  0053EE39  |.  8D4424 40     lea     eax, [esp+40]
  0053EE3D  |.  50            push    eax                              ; /Arg1
  0053EE3E  |.  8BCB          mov     ecxebx                         ; |
  0053EE40  |.  8D5424 0E     lea     edx, [esp+E]                     ; |
  0053EE44  |.  8BC6          mov     eaxesi                         ; |
  0053EE46  |.  E8 05FEFFFF   call    0053EC50                         ; \跟进
  0053EE4B  |.  8D4424 40     lea     eax, [esp+40]
  0053EE4F  |.  8BD4          mov     edxesp
  0053EE51  |.  33C9          xor     ecxecx
  0053EE53  |.  8A08          mov     cl, [eax]
  0053EE55  |.  41            inc     ecx
  0053EE56  |.  E8 A544ECFF   call    <比较真码和假码>
  0053EE5B  |.  0F94C0        sete    al
  0053EE5E  |.  84C0          test    alal
  0053EE60  |.  75 38         jnz     short 0053EE9A
  0053EE62  |.  B3 01         mov     bl, 1
  0053EE64  |.  889E 55030000 mov     [esi+355], bl
  0053EE6A  |.  8D4424 40     lea     eax, [esp+40]
  0053EE6E  |.  50            push    eax                              ; /Arg1
  0053EE6F  |.  8BCB          mov     ecxebx                         ; |
  0053EE71  |.  8D5424 0E     lea     edx, [esp+E]                     ; |
  0053EE75  |.  8BC6          mov     eaxesi                         ; |
  0053EE77  |.  E8 D4FDFFFF   call    0053EC50                         ; \和0053EE46处的CALL一样,不过计算出的注册码不可用
  0053EE7C  |.  8D4424 40     lea     eax, [esp+40]
  0053EE80  |.  8BD4          mov     edxesp
  0053EE82  |.  33C9          xor     ecxecx
  0053EE84  |.  8A08          mov     cl, [eax]
  0053EE86  |.  41            inc     ecx
  0053EE87  |.  E8 7444ECFF   call    <比较真码和假码>
  0053EE8C  |.  0F94C0        sete    al
  0053EE8F  |.  3C 01         cmp     al, 1
  0053EE91  |.  75 07         jnz     short 0053EE9A
  0053EE93  |.  C686 55030000>mov     byte ptr [esi+355], 1
  0053EE9A  |>  83C4 4C       add     esp, 4C
  0053EE9D  |.  5F            pop     edi
  0053EE9E  |.  5E            pop     esi
  0053EE9F  |.  5B            pop     ebx
  0053EEA0  \.  C3            retn

可见用户名最长32H位,即50位,注册码最长9位,超出的部分都将忽略.
    另外,0053EE46和0053EE77的CALL都是call 0053EC50,也都会计算出一个注册码,不过经过测试,只有前一个CALL的注册码才是正确的,后一个虽然也提示valid,不过关掉注册窗口后还是未注册的.实际上如果前一个CALL的产生的真码和假码经过0053EE56处的CALL比较相等,后面的CALL根本不会执行.作者这样做的用意可能是迷惑cracker.好,让我们跟进0053EE46处的CALL,看到这些:

  0053EC50  /$  55            push    ebp                              
  0053EC51  |.  8BEC          mov     ebpesp
  0053EC53  |.  81C4 6CFFFFFF add     esp, -94
  0053EC59  |.  53            push    ebx
  0053EC5A  |.  56            push    esi
  0053EC5B  |.  57            push    edi
  0053EC5C  |.  8BF2          mov     esiedx
  0053EC5E  |.  8D7D C2       lea     edi, [ebp-3E]
  0053EC61  |.  51            push    ecx
  0053EC62  |.  33C9          xor     ecxecx
  0053EC64  |.  8A0E          mov     cl, [esi]
  0053EC66  |.  80F9 32       cmp     cl, 32
  0053EC69  |.  72 02         jb      short 0053EC6D
  0053EC6B  |.  B1 32         mov     cl, 32
  0053EC6D  |>  880F          mov     [edi], cl
  0053EC6F  |.  46            inc     esi
  0053EC70  |.  47            inc     edi
  0053EC71  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>;  如果你仔细的看过前面的注释,上面这段代码就不会陌生了
  0053EC73  |.  59            pop     ecx
  0053EC74  |.  884D FF       mov     [ebp-1], cl
  0053EC77  |.  8BD8          mov     ebxeax
  0053EC79  |.  33C0          xor     eaxeax
  0053EC7B  |.  8A45 C2       mov     al, [ebp-3E]
  0053EC7E  |.  40            inc     eax
  0053EC7F  |.  83F8 32       cmp     eax, 32
  0053EC82  |.  7F 0E         jg      short 0053EC92
  0053EC84  |.  8D5405 C2     lea     edx, [ebp+eax-3E]
  0053EC88  |>  C602 2C       /mov     byte ptr [edx], 2C
  0053EC8B  |.  40            |inc     eax
  0053EC8C  |.  42            |inc     edx
  0053EC8D  |.  83F8 33       |cmp     eax, 33
  0053EC90  |.^ 75 F6         \jnz     short 0053EC88                  ;  此循环在用户名后面补2CH,补齐为32H个字节
  0053EC92  |>  8D8D 6CFFFFFF lea     ecx, [ebp-94]
  0053EC98  |.  8B93 04020000 mov     edx, [ebx+204]                   ;  [EBX+204]固定为0D04E23E
  0053EC9E  |.  8BC3          mov     eaxebx
  0053ECA0  |.  E8 53FEFFFF   call    <16进制转换为字符串>                     ;  把EDX中的数值转换为字符串,前面加上$符号,然后放到ECX所指向的内存中
  0053ECA5  |.  8D95 6CFFFFFF lea     edx, [ebp-94]                    ;  [EBP-94]中的内容为$0D04E23E
  0053ECAB  |.  8D45 F5       lea     eax, [ebp-B]
  0053ECAE  |.  B1 09         mov     cl, 9
  0053ECB0  |.  E8 AB45ECFF   call    00403260
  0053ECB5  |.  B8 0A000000   mov     eax, 0A
  0053ECBA  |.  8D55 F5       lea     edx, [ebp-B]
  0053ECBD  |.  8DB5 7BFFFFFF lea     esi, [ebp-85]
  0053ECC3  |>  8A0A          /mov     cl, [edx]
  0053ECC5  |.  880E          |mov     [esi], cl
  0053ECC7  |.  46            |inc     esi
  0053ECC8  |.  42            |inc     edx
  0053ECC9  |.  48            |dec     eax
  0053ECCA  |.^ 75 F7         \jnz     short 0053ECC3                  ;  此循环把$0D04323E复制到ESI指向的内存
  0053ECCC  |.  B8 33000000   mov     eax, 33
  0053ECD1  |.  8D55 C2       lea     edx, [ebp-3E]
  0053ECD4  |.  8D75 85       lea     esi, [ebp-7B]
  0053ECD7  |>  8A0A          /mov     cl, [edx]
  0053ECD9  |.  880E          |mov     [esi], cl
  0053ECDB  |.  46            |inc     esi
  0053ECDC  |.  42            |inc     edx
  0053ECDD  |.  48            |dec     eax
  0053ECDE  |.^ 75 F7         \jnz     short 0053ECD7                  ;  此循环把用户名和补完2CH后的字符串复制到ESI指向的内存
  0053ECE0  |.  8D8D 6CFFFFFF lea     ecx, [ebp-94]
  0053ECE6  |.  8B93 08020000 mov     edx, [ebx+208]                   ;  [EBX+208]固定为9014FB17
  0053ECEC  |.  8BC3          mov     eaxebx
  0053ECEE  |.  E8 05FEFFFF   call    <16进制转换为字符串>                     ;  转换为$9014FB17
  0053ECF3  |.  8D95 6CFFFFFF lea     edx, [ebp-94]
  0053ECF9  |.  8D45 F5       lea     eax, [ebp-B]
  0053ECFC  |.  B1 09         mov     cl, 9
  0053ECFE  |.  E8 5D45ECFF   call    00403260
  0053ED03  |.  807D FF 00    cmp     byte ptr [ebp-1], 0
  0053ED07  |.  74 17         je      short 0053ED20                   ;  必跳
  0053ED09  |.  B8 0A000000   mov     eax, 0A
  0053ED0E  |.  8D55 F5       lea     edx, [ebp-B]
  0053ED11  |.  8D75 B8       lea     esi, [ebp-48]
  0053ED14  |>  8A0A          /mov     cl, [edx]
  0053ED16  |.  49            |dec     ecx
  0053ED17  |.  880E          |mov     [esi], cl
  0053ED19  |.  46            |inc     esi
  0053ED1A  |.  42            |inc     edx
  0053ED1B  |.  48            |dec     eax
  0053ED1C  |.^ 75 F6         \jnz     short 0053ED14
  0053ED1E  |.  EB 14         jmp     short 0053ED34
  0053ED20  |>  B8 0A000000   mov     eax, 0A
  0053ED25  |.  8D55 F5       lea     edx, [ebp-B]
  0053ED28  |.  8D75 B8       lea     esi, [ebp-48]
  0053ED2B  |>  8A0A          /mov     cl, [edx]
  0053ED2D  |.  880E          |mov     [esi], cl
  0053ED2F  |.  46            |inc     esi
  0053ED30  |.  42            |inc     edx
  0053ED31  |.  48            |dec     eax
  0053ED32  |.^ 75 F7         \jnz     short 0053ED2B                  ;  此循环把$9014FB17复制到ESI指向的内存
  0053ED34  |>  8B93 14030000 mov     edx, [ebx+314]
  0053ED3A  |.  8D8D 7BFFFFFF lea     ecx, [ebp-85]
  0053ED40  |.  8BC3          mov     eaxebx
  0053ED42  |.  E8 69FDFFFF   call    0053EAB0                         ;  进
  0053ED47  |.  8BD0          mov     edxeax
  0053ED49  |.  8D8D 6CFFFFFF lea     ecx, [ebp-94]
  0053ED4F  |.  8BC3          mov     eaxebx
  0053ED51  |.  E8 A2FDFFFF   call    <16进制转换为字符串>
  0053ED56  |.  8D95 6CFFFFFF lea     edx, [ebp-94]
  0053ED5C  |.  8B45 08       mov     eax, [ebp+8]
  0053ED5F  |.  B1 09         mov     cl, 9
  0053ED61  |.  E8 FA44ECFF   call    00403260
  0053ED66  |.  5F            pop     edi
  0053ED67  |.  5E            pop     esi
  0053ED68  |.  5B            pop     ebx
  0053ED69  |.  8BE5          mov     espebp
  0053ED6B  |.  5D            pop     ebp
  0053ED6C  \.  C2 0400       retn    4

到此,整理一下思路.首先把用户名用2CH(2CH就是逗号)补齐为32H长,比如用户名WAKU,就在后面补32H-4个逗号,设为字符串B.然后用了两个常量,0D04323E和9014FB17,分别把它们转换成$0D0432E3和$9014FB17的字符串形式,设为字符串A和C,然后把A、B和C连接起来成为ABC.
    要注意的是Delphi的字符串有一个特点,就是在字符串前面会用一个字节表示字符串的长度,向上面的WAKU前面就有一个04,$0D04323E和$9014FB17前面分别有一个09.这样ABC的全貌就是这样的:
    (09)$0D04323E(04)WAKU,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(09)$9014FB17
    括号内是由于ASCII表示不出来,所以我用数字表示了.
    好,0053ED42处的CALL就是真码的计算过程了,让我们跟进看看:

  0053EAB0  /$  53            push    ebx
  0053EAB1  |.  56            push    esi
  0053EAB2  |.  57            push    edi
  0053EAB3  |.  83C4 B8       add     esp, -48
  0053EAB6  |.  8BF1          mov     esiecx
  0053EAB8  |.  8D3C24        lea     edi, [esp]
  0053EABB  |.  B9 11000000   mov     ecx, 11
  0053EAC0  |.  F3:A5         rep     movs dword ptr es:[edi], dword ptr [esi]     ;  复制ABC到EDI
  0053EAC2  |.  66:A5         movs    word ptr es:[edi], word ptr [esi]
  0053EAC4  |.  A4            movs    byte ptr es:[edi], byte ptr [esi]
  0053EAC5  |.  B1 47         mov     cl, 47                                       ;  CL计数为47H
  0053EAC7  |.  8BC4          mov     eaxesp
  0053EAC9  |>  8BDA          /mov     ebxedx                                    ;  EDX初始为00ABCDEF
  0053EACB  |.  C1EB 08       |shr     ebx, 8
  0053EACE  |.  81E3 FFFFFF00 |and     ebx, 0FFFFFF
  0053EAD4  |.  0FB630        |movzx   esibyte ptr [eax]                         ;  ABC依次 > ESI
  0053EAD7  |.  33D6          |xor     edxesi
  0053EAD9  |.  81E2 FF000000 |and     edx, 0FF
  0053EADF  |.  8B1495 085657>|mov     edx, [edx*4+575608]                         ;  从575608处开始查表
  0053EAE6  |.  33DA          |xor     ebxedx
  0053EAE8  |.  8BD3          |mov     edxebx
  0053EAEA  |.  40            |inc     eax
  0053EAEB  |.  FEC9          |dec     cl
  0053EAED  |.^ 75 DA         \jnz     short 0053EAC9
  0053EAEF  |.  8BC2          mov     eaxedx                                     ;  计算的结果 > EAX(EAX就离真码不远了^_^)
  0053EAF1  |.  83C4 48       add     esp, 48
  0053EAF4  |.  5F            pop     edi
  0053EAF5  |.  5E            pop     esi
  0053EAF6  |.  5B            pop     ebx
  0053EAF7  \.  C3            retn

主要的计算过程就在那一个循环里,代码很简单,都是一些基本的运算,就不详细讲了.
    在0053EAD9的AND EDX, 0FF后,EDX的范围只能为0~FFH,所以575608处的表有256个双字的值.弄清这点对做注册机有帮助.最后把计算结果放到EAX中返回.
    
    从CALL中返回后,还是把EAX中的值转换为字符串,前面再加上$符号就是最终的注册码了.
  
    Name:  WAKU
    Key:  $D53AE353
    
 完.
--------------------------------------------------------------------------------