【文章标题】: AceFTP3 算法分析
【文章作者】: Suyana
【作者邮箱】: Suyasha@163.com
【作者主页】: http://Suyana.3u.cn
【软件名称】: AceFTP3
【使用工具】: DeDe,OD
【作者声明】: 我只是一只小菜鸟,失误之处难免,敬望诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  用DeDe找到注册按钮的例程:
  0061D4B0        push    ebp
  ...
  0061D572        mov     eax, [ebp-4]
  0061D575        call    005EA4C8                  ; 计算注册码,进入
  0061D57A        lea     edx, [ebp-38]
  0061D57D        mov     eax, [ebp-8]
  0061D580        call    00409798                  ; 注册码转为大写
  0061D585        mov     edx, [ebp-38]             ; 假注册码
  0061D588        mov     eax, [ebp-10]             ; 真注册码
  0061D58B        call    00404898                  ;  ->System.@LStrCmp;这个就不用说了吧
  0061D590        jnz     short 0061D59C

说实话,这个软件的算法真有点烦。用peid查出三种算法:
BASE64 table :: 000A7830 :: 004A8430
CRC32 [poly] :: 000AB807 :: 004AC407
ZLIB deflate [long] :: 0028E508 :: 0068F908
好像都没有用在注册码方面,或许是有而偶不知道吧。~_~ 

来到005EA4C8:

一开始是写入注册表项(不过好像没执行到),这里就不贴出来了 ,来到:

  005EA625   .        lea     edx, [ebp-18]        ; 下面的这个是表
  005EA628   .        mov     eax,005EA810         ; ASCII "WBNMH234598764SXZKPTREWQCVBN238"
  005EA62D   .        call    00409798             ; SysUtils.UpperCase
  005EA632   .        lea     edx, [ebp-10]
  005EA635   .        mov     eax, [ebp-4]
  005EA638   .        call    00409798             ; SysUtils.UpperCase(AnsiString):AnsiString;
  005EA63D   .        xor     eax, eax             ; 用户名转大写
  005EA63F   .        mov     [ebp-20], eax
  005EA642   .        lea     eax, [ebp-14]
  005EA645   .        call    00404470             ;  System.@LStrClr(void;void);
  005EA64A   .        mov     eax, [ebp-4]
  005EA64D   .        call    0040474C             ;  System.@LStrLen(String):Integer;
  005EA652   .        mov     edi, eax
  005EA654   .        test    edi, edi
  005EA656   .        jle     short 005EA699
  005EA658   .        mov     esi, 1
  005EA65D   >        lea     eax, [ebp-34]
  005EA660   .        mov     edx, [ebp-10]        ;  用户名
  005EA663   .        mov     dl, [edx+esi-1]      ;  依次取用户名的ascii
  005EA667   .        call    00404658             ;  System.@LStrFromChar(String;String;Char);
  005EA66C   .        mov     eax, [ebp-34]
  005EA66F   .        mov     edx, [ebp-18]
  005EA672   .        call    00404A90             ;  System.@LStrPos;
  005EA677   .        test    eax, eax
  005EA679   .        jle     short 005EA695       ;  用户名的第n位不在表中
  005EA67B   .        lea     eax, [ebp-38]
  005EA67E   .        mov     edx, [ebp-10]
  005EA681   .        mov     dl, [edx+esi-1]
  005EA685   .        call    00404658             ;  System.@LStrFromChar(String;String;Char);
  005EA68A   .        mov     edx, [ebp-38]
  005EA68D   .        lea     eax, [ebp-14]        ;  把在表中的用户名连成字符串1
  005EA690   .        call    00404754             ;  System.@LStrCat;
  005EA695   >        inc     esi
  005EA696   .        dec     edi
  005EA697   .^       jnz     short 005EA65D
  005EA699   >        lea     eax, [ebp-10]
  005EA69C   .        mov     edx, [ebp-14]        ;  连成字符串1
  005EA69F   .        call    00404508             ;  System.@LStrLAsg(void;void;void;void);
  005EA6A4   .        mov     eax, [ebp-10]
  005EA6A7   .        call    0040474C             ;  System.@LStrLen(String):Integer;
  005EA6AC   .        cmp     eax, 18
  005EA6AF   .        jge     short 005EA6DF       ;  字符串1的长度>=18h时跳
  005EA6B1   .        mov     edi, 18
  005EA6B6   .        sub     edi, eax
  005EA6B8   .        test    edi, edi
  005EA6BA   .        jle     short 005EA6DF       ;  <=
  005EA6BC   .        mov     esi, 1
  005EA6C1   >        lea     eax, [ebp-3C]
  005EA6C4   .        mov     edx, [ebp-18]        ;  表
  005EA6C7   .        mov     dl, [edx+esi-1]      ;  表的第n位
  005EA6CB   .        call    00404658             ;  System.@LStrFromChar(String;String;Char);
  005EA6D0   .        mov     edx, [ebp-3C]
  005EA6D3   .        lea     eax, [ebp-10]
  005EA6D6   .        call    00404754             ;  System.@LStrCat;
  005EA6DB   .        inc     esi                  ;  字符串1和表连成长度为18h的字符串2
  005EA6DC   .        dec     edi
  005EA6DD   .^       jnz     short 005EA6C1
  005EA6DF   >        mov     eax, [ebp-10]        ;  得出的字符串2
  005EA6E2   .        call    0040474C             ;  System.@LStrLen(String):Integer;
  005EA6E7   .        cmp     eax, 18
  005EA6EA   .        jle     short   005EA702     ;  <=18跳
  005EA6EC   .        lea     eax, [ebp-10]
  005EA6EF   .        push    eax
  005EA6F0   .        mov     ecx, 18
  005EA6F5   .        mov     edx, 1
  005EA6FA   .        mov     eax, [ebp-10]
  005EA6FD   .        call    004049AC             ;  System.@LStrCopy;
  005EA702   >        lea     eax, [ebp-14]
  005EA705   .        call    00404470             ;  System.@LStrClr(void;void);
  005EA70A   .        mov     esi, 1
  005EA70F   >        mov     eax, [ebp-10]        ;  连成的字符串2
  005EA712   .        mov     bl, [eax+esi-1]      ;  依次取字符串2的ascii
  005EA716   .        lea     eax, [ebp-40]
  005EA719   .        mov     edx, ebx
  005EA71B   .        call    00404658             ;  System.@LStrFromChar(String;String;Char);
  005EA720   .        mov     eax, [ebp-40]
  005EA723   .        mov     edx, [ebp-18]        ;  表
  005EA726   .        call    00404A90             ;  System.@LStrPos;
  005EA72B   .        mov     ebx, eax             ;  该字符在表中的位置(以1开始,以0开始要加1)
  005EA72D   .        mov     eax, [ebp-18]        ;  表
  005EA730   .        call    0040474C             ;  System.@LStrLen(String):Integer;
  005EA735   .        push    eax                  ;  表的长度(1Fh)
  005EA736   .        mov     eax, ebx
  005EA738   .        imul    ebx                  ;  该字符在表中的位置*该字符在表中的位置
  005EA73A   .        sub     eax, ebx             ;  值再减去该字符在表中的位置
  005EA73C   .        add     eax, [ebp-20]        ;  上次运算出的余数+1,第一次为0
  005EA73F   .        pop     edx
  005EA740   .        mov     ecx, edx
  005EA742   .        cdq
  005EA743   .        idiv    ecx                  ;  除以表的长度
  005EA745   .        mov     ebx, edx             ;  edx=余数
  005EA747   .        inc     ebx                  ;  ebx=edx=余数+1
  005EA748   .        mov     [ebp-20], ebx        ;  写入[  0012f2e8]
  005EA74B   .        mov     eax, [ebp-18]        ;  表
  005EA74E   .        mov     bl, [eax+ebx-1]      ;  表的第ebx-1位
  005EA752   .        lea     eax, [ebp-44]
  005EA755   .        mov     edx, ebx             ;  edx=ebx=表的第ebx-1位的ascii码
  005EA757   .        call    00404658             ;  System.@LStrFromChar(String;String;Char);
  005EA75C   .        mov     edx, [ebp-44]
  005EA75F   .        lea     eax, [ebp-14]
  005EA762   .        call    00404754             ;  System.@LStrCat;
  005EA767   .        mov     eax, esi             ;  eax=esi=循环次数
  005EA769   .        mov     ecx, 6
  005EA76E   .        cdq
  005EA76F   .        idiv    ecx                  ;  循环次数除以6
  005EA771   .        test    edx, edx
  005EA773   .        jnz     short 005EA787       ;  不能整除跳过
  005EA775   .        cmp     esi, 18              ;  可以整除
  005EA778   .        jge     short 005EA787       ;  esi>=18跳
  005EA77A   .        lea     eax, [ebp-14]
  005EA77D   .        mov     edx,005EA838         ;  加上'-'
  005EA782   .        call    00404754             ;  System.@LStrCat;
  005EA787   >        inc     esi                  ;  上面这段函数就是每6位加上'-'
  005EA788   .        cmp     esi, 19
  005EA78B   .^       jnz     short 005EA70F
  005EA78D   .        mov     eax, [ebp-C]
  005EA790   .        mov     edx, [ebp-14]
  
  算法就出来了,简单说一下:
  ------------------------------------------------------------------------
  将用户名进行查表,把在表中的用户名连起来,再和表连成长度为18h的字符串。
  
  依次取该字符串的ascii码,查表,得到该字符在表中的位置:X,进行运算:
  
  (X*X-X)+(变量A)=Y
  
  edx=Y mod (表的长度1F),变量A <- (余数+1)
  
  用余数查表,连成字符串,每6位插入'-'
  --------------------------------------------------------------------------
  是不是很烦呀。赶紧,写注册机。^_^  
  ========================================================================
  注册码保存在X:\Documents and Settings\你的用户名\Application Data\Visicom Media\
  AceFTP,删掉Settings.cfg就可以了,但是你的配置也会被删除。
  ---------------------------------------------------------------
  Suyana                             -> 用户名
  
  WBNMH234598764SXZKPTREWQCVBN238    -> 表
  
  SNWBNMH234598764SXZKPTRE           -> 连成的字符串
  
  CWBH7C-SSBEB8-KB2QK8-HBM682        -> 注册码
-------------
注册机源码:
                .data
szFmt      db        '%s',0
szFmtS     db        '%s%c',0
table      db        'WBNMH234598764SXZKPTREWQCVBN238',0
...
                .code
;-----------在字符串中查找指定字符,返回位置------------
 LStrPos        proc uses edx ecx  lpstring,char
                xor ecx,ecx
                mov edx,lpstring
                .repeat
                        mov al,[edx]
                        .if al==byte ptr char
                                jmp brk
                        .endif
                        inc edx
                        inc ecx
                .until al==0
                push 0
                pop eax
                ret
        brk:
                inc ecx
                push ecx
                pop eax
                ret
 LStrPos endp
;----------------判断用户名是否有效-------------------
 isUserIsValid        proc uses edx ecx _addr
                mov edx,_addr
        aa:
                mov cl,[edx]
                or cl,cl
                je fa
                invoke LStrPos,addr table,cl
                .if eax
                        push 1
                        pop eax
                        ret
                .endif
                inc edx
                jmp aa
        fa:
                push 0
                pop eax
                ret                                      
 isUserIsValid endp
;---------------小写转大写---------------------------
 UpperCase      proc lpString
                push eax
                mov eax,lpString
        aa:
                mov     cl, [eax]
                cmp     cl, 61h
                jl      loo
                cmp     cl, 7Ah
                jg      loo
                sub     cl, 20h
                mov     [eax], cl
        loo:
                inc     eax
                cmp     byte ptr [eax], 0
                jnz     aa
                pop     eax
                ret
 UpperCase      endp
;--------------------计算长度----------------------                
 GetStrLen      proc uses edx ecx  _addr
                xor ecx,ecx
                mov edx,_addr
                .repeat
                        inc ecx
                        inc edx
                        mov al,[edx]
                .until al==0
                mov eax,ecx
                ret                                      
 GetStrLen endp
;--------------------计算注册码的函数--------------------------------
_GetSN  proc uses ebx ecx edx edi esi hWnd
        local szBufUser[128]:byte,szBuffer[256]:byte,szBuf1[128]:byte
        local incYushu,szBuf2[128]:byte
        
        mov incYushu,0
        invoke RtlZeroMemory,addr szBufUser,sizeof szBufUser
        invoke GetDlgItemText,hWnd,1000,addr szBufUser,128
        .if !eax
                invoke SetDlgItemText,hWnd,1001,addr szTip
                ret
        .endif
        mov edi,eax
        invoke UpperCase,addr szBufUser                    ;小写转大写
        invoke isUserIsValid,addr szBufUser                ;判断用户名是否有效
        .if !eax
                invoke SetDlgItemText,hWnd,1001,addr szTip
                ret
        .endif
        invoke RtlZeroMemory,addr szBuf1,sizeof szBuf1
        invoke RtlZeroMemory,addr szBuf2,sizeof szBuf2
        invoke RtlZeroMemory,addr szBuffer,sizeof szBuffer
        mov    esi, 1
    @@:
        lea     edx,szBufUser                 ; 用户名
        mov     dl, [edx+esi-1]               ; 用户名第一位
        invoke  LStrPos,addr table,dl
        test    eax, eax
        jle     xx
        invoke  wsprintf,addr szBuf1,addr szFmtS,addr szBuf1,dl
    xx:
        inc     esi
        dec     edi
        jnz     @B

        lea     edi,table
        lea     edx,szBuf1
        invoke  GetStrLen,addr szBuf1
        mov     esi,eax
    @@:
        mov     cl,byte ptr [edi]
        mov     [edx+esi],cl
        inc     edi
        inc     esi
        .if esi<18h
                jmp @B
        .endif

        mov     esi, 1
    @aceftp3_  005EA70F:
        lea     eax, szBuf1
        mov     bl, [eax+esi-1]                ; 依次取字符串2的ascii
        invoke  LStrPos,addr table,bl
        
        mov     ebx, eax                       ; 该字符在表中的位置(以1开始,以0开始要加1)
        invoke  GetStrLen,addr table           ; 表的长度
        push    eax                
        mov     eax, ebx
        imul    ebx                            ; 该字符在表中的位置*该字符在表中的位置
        sub     eax, ebx                       ; 值再减去该字符在表中的位置
        add     eax, incYushu                  ; 0,1,2,(上次运行出的余数+1)
        pop     edx
        mov     ecx, edx
        cdq
        idiv    ecx                            ; 除以表的长度
        mov     ebx, edx                       ; edx=余数
        inc     ebx                            ; ebx=edx=余数+1
        mov     incYushu, ebx
        lea     eax,table                      ; 表
        mov     bl, [eax+ebx-1]                ; 表的第ebx-1位
        invoke  wsprintf,addr szBuf2,addr szFmtS,addr szBuf2,bl
        mov     eax, esi                       ; eax=esi=循环次数
        mov     ecx, 6
        cdq
        idiv    ecx                            ; 除以6
        test    edx, edx
        jnz     @aceftp3_  005EA787            ; 不能整除
        cmp     esi, 018h                      ; 可以整除
        jge     @aceftp3_  005EA787            ; esi>=18跳
        invoke  wsprintf,addr szBuf2,addr szFmtS,addr szBuf2,'-'
    @aceftp3_  005EA787:
        inc     esi
        cmp     esi, 019h
        jnz     @aceftp3_  005EA70F
        
        ; 显示注册码---------------------                
        invoke wsprintf,addr szBuffer,addr szFmt,addr szBuf2
        invoke SetDlgItemText,hWnd,1001,addr szBuffer
        ret
 _GetSN    endp

--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!