acafeel 发表于 2007-11-10 16:14:01

一款图象处理软件 PhoXo v6.0 的注册算法分析 + 注册机源代码

一款图象处理软件 PhoXo v6.0 的注册算法分析 + 注册机源代码


一款感觉还不错的图象处理软件,分析了下,简单写出来。

软件在未注册的状态下,每次启动时会弹出一个NAG提示对话框;先打开注册窗口,输入注册名:aCaFeeL,输入注册码:12345678,点击OK按钮,程序提示下次启动时检查。

故确定软件用的是重启验证的方式,将PhoXo.exe文件拖入OD中后,下断点: bp MessageBoxExA,按F9键运行程序,此时程序被中断下来:

>>>>>>
77D5055C >/$8BFF               mov   edi, edi                   ; 被断在了这里
77D5055E|.55               push    ebp
77D5055F|.8BEC               mov   ebp, esp
77D50561|.6A FF            push    -1
77D50563|.FF75 18            push    dword ptr
77D50566|.FF75 14            push    dword ptr
77D50569|.FF75 10            push    dword ptr
77D5056C|.FF75 0C            push    dword ptr
77D5056F|.FF75 08            push    dword ptr
77D50572|.E8 4D5A0100      call    USER32.MessageBoxTimeoutA
77D50577|.5D               pop   ebp
77D50578\.C2 1400            retn    14
>>>>>>



再按ALT+F9建后,弹出NAG对话框,点击‘OK’按钮后,便回到了PhoXo的领空:

>>>>>>
0055B883|> \53               push    ebx                        ; /Style
0055B884|.57               push    edi                        ; |Title
0055B885|.FF75 08            push    dword ptr           ; |Text
0055B888|.FF75 F4            push    dword ptr           ; |hOwner
0055B88B|.FF15 B4E55700      call    dword ptr [<&USER32.Messag>; \MessageBoxA
0055B891|.85F6               test    esi, esi                   ; 回到了这里!
0055B893|.8BF8               mov   edi, eax
0055B895|.74 05            je      short PhoXo.0055B89C
0055B897|.8B45 F8            mov   eax, dword ptr
0055B89A|.8906               mov   dword ptr , eax
0055B89C|>837D FC 00         cmp   dword ptr , 0
0055B8A0      74 0B            je      short PhoXo.0055B8AD
0055B8A2|.6A 01            push    1                        ; /Enable = TRUE
0055B8A4|.FF75 FC            push    dword ptr           ; |hWnd
0055B8A7|.FF15 C0E75700      call    dword ptr [<&USER32.Enable>; \EnableWindow
0055B8AD|>8B4D F0            mov   ecx, dword ptr
0055B8B0|.6A 01            push    1
0055B8B2|.E8 F4FEFFFF      call    PhoXo.0055B7AB
0055B8B7|.8BC7               mov   eax, edi
0055B8B9|.5F               pop   edi
0055B8BA|.5E               pop   esi
0055B8BB|.5B               pop   ebx
0055B8BC|.C9               leave
0055B8BD\.C2 0C00            retn    0C
>>>>>>



F8键走完上面这个子call后,在继续分析,便来到了这里:

>>>>>>
0040B001   .51               push    ecx
0040B002   .52               push    edx
0040B003   .C68424 58010000 18 mov   byte ptr , 18
0040B00B   .E8 D0510200      call    PhoXo.004301E0
0040B010   .8B4424 2C          mov   eax, dword ptr     ;注册码 -> eax
0040B014   .83C4 08            add   esp, 8
0040B017   .85C0               test    eax, eax
0040B019   .75 05            jnz   short PhoXo.0040B020
0040B01B   .B8 D0F35700      mov   eax, PhoXo.0057F3D0
0040B020   >8B4C24 28          mov   ecx, dword ptr     ;注册码长度 -> ecx
0040B024   .51               push    ecx
0040B025   .50               push    eax
0040B026   .E8 D54F0200      call    PhoXo.00430000             ;注册算法,F7键进入分析:
0040B02B   .83C4 08            add   esp, 8
0040B02E   .8D4C24 20          lea   ecx, dword ptr
0040B032   .8AD8               mov   bl, al
0040B034   .C68424 50010000 17 mov   byte ptr , 17
0040B03C   .6A 01            push    1
0040B03E   .E8 AD5D0000      call    PhoXo.00410DF0
0040B043   .6A 01            push    1
0040B045   .8D4C24 34          lea   ecx, dword ptr
0040B049   .C68424 54010000 13 mov   byte ptr , 13
0040B051   .E8 9A5D0000      call    PhoXo.00410DF0
0040B056   .84DB               test    bl, bl                     ;bl = 0 ?
0040B058      75 0E            jnz   short PhoXo.0040B068       ;关键跳,bl<>0,一跳便OK了
0040B05A   .6A FF            push    -1
0040B05C   .6A 00            push    0
0040B05E   .68 81270000      push    2781
0040B063   .E8 90081500      call    PhoXo.0055B8F8             ;弹出NAG对话框
0040B068   >8D4C24 40          lea   ecx, dword ptr     ;停留在了这里,向上分析▲
0040B06C   .C68424 50010000 12 mov   byte ptr , 12
0040B074   .E8 DEC31500      call    PhoXo.00567457
0040B079   .8D9424 EC000000    lea   edx, dword ptr
>>>>>>



毫无疑问,注册成功与否,便是看 0040B056 这里的bl是否为0了,不为0才注册成功,要分析算法,自然要进入 0040B026 地址的:

0040B026   .E8 D54F0200      call    PhoXo.00430000

在这里F2键下断,用OD重新载入程序后,F9键运行,便断在了这里,按F7建进入该子程序后:

>>>>>>
00430000/$64:A1 00000000   mov   eax, dword ptr fs:      ;注册算法,开始:
00430006|.6A FF            push    -1
00430008|.68 601A5700      push    PhoXo.00571A60
0043000D|.8B5424 0C          mov   edx, dword ptr    ;注册码 -> edx
00430011|.50               push    eax
00430012|.64:8925 00000000   mov   dword ptr fs:, esp
00430019|.83EC 40            sub   esp, 40
0043001C|.56               push    esi
0043001D|.33F6               xor   esi, esi                   ;esi 清零
0043001F|.3BD6               cmp   edx, esi                   ;edx 与 esi 比较
00430021|.0F84 A1010000      je      PhoXo.004301C8             ;注册码为空,则跳
00430027|.837C24 58 0B       cmp   dword ptr , 0B   ;注册码长度与 $0B 比较
0043002C|.0F85 96010000      jnz   PhoXo.004301C8             ;不等则跳走
00430032|.807A 05 2D         cmp   byte ptr , 2D       ;注册码第6位的ASCII码与 $2D 比较
00430036|.0F85 8C010000      jnz   PhoXo.004301C8             ;不同则跳走
0043003C|.53               push    ebx
0043003D|.57               push    edi
0043003E|.B9 08000000      mov   ecx, 8                     ;ecx := 8;
00430043|.33C0               xor   eax, eax                   ;eax 清零
00430045|.8D7C24 2C          lea   edi, dword ptr
00430049|.F3:AB            rep   stos dword ptr es:
0043004B|.8B02               mov   eax, dword ptr        ;注册码1-4位 -> eax
0043004D      8B4A 04            mov   ecx, dword ptr    ;注册码5-8位 -> ecx
00430050|.894424 2C          mov   dword ptr , eax
00430054|.66:8B42 08         mov   ax, word ptr        ;注册码9,10位 -> ax
00430058|.894C24 30          mov   dword ptr , ecx
0043005C|.8A4A 0A            mov   cl, byte ptr        ;注册码11位 -> cl
0043005F|.66:894424 34       mov   word ptr , ax
00430064|.884C24 36          mov   byte ptr , cl
00430068|.33C0               xor   eax, eax                   ;eax 清零
0043006A|>83F8 03            /cmp   eax, 3                  ;eax 与 $3 比较
0043006D|.75 13            |jnz   short PhoXo.00430082      ;不相等,跳
0043006F|.8A5424 35          |mov   dl, byte ptr    ;注册码第10位 -> dl
00430073|.8A4C24 2F          |mov   cl, byte ptr    ;注册码第4位 -> cl
00430077|.80EA 30            |sub   dl, 30                  ;dl := dl - $30;
0043007A|.02CA               |add   cl, dl                  ;cl := cl + dl;
0043007C|.884C24 2F          |mov   byte ptr , cl   ;重新写回 注册码第4位
00430080|.EB 11            |jmp   short PhoXo.00430093
00430082|>8A4C04 32          |mov   cl, byte ptr ;注册码第7,8,9,11位依次 -> cl
00430086|.8A5C04 2C          |mov   bl, byte ptr ;注册码第1,2,3,5位依次 -> bl
0043008A|.2ACB               |sub   cl, bl                  ;cl := cl - bl;
0043008C|.80C1 30            |add   cl, 30                  ;cl := cl + $30;
0043008F|.884C04 2C          |mov   byte ptr , cl ;依次重新写回 注册码第1,2,3,5位
00430093|>40               |inc   eax                     ;eax := eax + 1;
00430094|.83F8 05            |cmp   eax, 5                  ;eax 与 5 比较
00430097|.^ 7C D1            \jl      short PhoXo.0043006A      ;小于5,继续循环
00430099|.BF F4EB5C00      mov   edi, PhoXo.005CEBF4      ;PhoXo -> edi
0043009E|.83C9 FF            or      ecx, FFFFFFFF
004300A1|.33C0               xor   eax, eax                   ;eax 清零
004300A3|.8A5424 5C          mov   dl, byte ptr
004300A7|.F2:AE            repne   scas byte ptr es:
004300A9|.F7D1               not   ecx                        ;取反
004300AB|.49               dec   ecx                        ;ecx := ecx -1;
004300AC|.C64424 31 00       mov   byte ptr , 0       ;新生成的字符串的6位 设置为0
004300B1|.51               push    ecx
004300B2|.68 F4EB5C00      push    PhoXo.005CEBF4             ;PhoXo
004300B7|.8D4C24 24          lea   ecx, dword ptr     ;'PhoXo' -> ecx
004300BB|.885424 24          mov   byte ptr , dl
004300BF|.897424 28          mov   dword ptr , esi
004300C3|.897424 2C          mov   dword ptr , esi
004300C7|.897424 30          mov   dword ptr , esi
004300CB|.E8 F00BFEFF      call    PhoXo.00410CC0
004300D0|.8A4424 5C          mov   al, byte ptr
004300D4|.8D7C24 2C          lea   edi, dword ptr     ;取新生成的字符串的前5位 -> edi
004300D8|.884424 0C          mov   byte ptr , al
004300DC|.83C9 FF            or      ecx, FFFFFFFF
004300DF|.33C0               xor   eax, eax                   ;eax 清零
004300E1|.897424 54          mov   dword ptr , esi
004300E5|.F2:AE            repne   scas byte ptr es:
004300E7|.F7D1               not   ecx                        ;取反
004300E9|.49               dec   ecx                        ;ecx := ecx -1;
004300EA|.897424 10          mov   dword ptr , esi
004300EE|.51               push    ecx
004300EF|.8D4C24 30          lea   ecx, dword ptr     ;取新生成的字符串的前5位 -> ecx
004300F3|.51               push    ecx
004300F4|.8D4C24 14          lea   ecx, dword ptr
004300F8|.897424 1C          mov   dword ptr , esi
004300FC|.897424 20          mov   dword ptr , esi
00430100|.E8 BB0BFEFF      call    PhoXo.00410CC0
00430105|.8B4424 20          mov   eax, dword ptr     ;'PhoXo' -> eax
00430109|.3BC6               cmp   eax, esi                   ;比较是否为空
0043010B|.75 05            jnz   short PhoXo.00430112       ;不为空字符串,跳
0043010D|.B8 D0F35700      mov   eax, PhoXo.0057F3D0
00430112|>8B5424 14          mov   edx, dword ptr
00430116|.8B5C24 24          mov   ebx, dword ptr
0043011A|.3BD3               cmp   edx, ebx
0043011C|.8BCA               mov   ecx, edx
0043011E|.72 02            jb      short PhoXo.00430122
00430120|.8BCB               mov   ecx, ebx
00430122|>55               push    ebp
00430123|.8B6C24 14          mov   ebp, dword ptr     ;取新生成的字符串的前5位 -> ebp
00430127|.8BF8               mov   edi, eax                   ;'PhoXo' -> edi
00430129|.8BF5               mov   esi, ebp                   ;取新生成的字符串的前5位 -> esi
0043012B|.33C0               xor   eax, eax
0043012D|.F3:A6            repe    cmps byte ptr es:, by>;取新生成的字符串的前5位 = 'PhoXo' ??
0043012F      74 05            je      short PhoXo.00430136       ;相等,则成功,跳!
00430131|.1BC0               sbb   eax, eax
00430133|.83D8 FF            sbb   eax, -1
00430136|>33F6               xor   esi, esi
>>>>>>



通过上面的分析,我们知道了其注册算法的方式为:

读入注册名和注册码,注册码的长度应该为11位,且第6位必须为‘-’字符;

即是:
将:【注册码第 7位的ASCII值 - 注册码第1位的ASCII值 + $30】的结果 重新写回 注册码的第1位;
将:【注册码第 8位的ASCII值 - 注册码第2位的ASCII值 + $30】的结果 重新写回 注册码的第2位;
将:【注册码第 9位的ASCII值 - 注册码第3位的ASCII值 + $30】的结果 重新写回 注册码的第3位;
将:【注册码第10位的ASCII值 + 注册码第4位的ASCII值 - $30】的结果 重新写回 注册码的第4位;
将:【注册码第11位的ASCII值 - 注册码第5位的ASCII值 + $30】的结果 重新写回 注册码的第5位;

然后这个新生成的11位长度的字符串,取该新字符串的前5位(即上面运算的5个结果),与字符串 PhoXo 比较,只要两者相等,便注册成功了!

比如,输入假注册码:12345-789AB 后,经过上面的运算,便得到了 666E=-789AB 这个新字符串,取这个新字符串的前5位:666E=,然后与字符串PhoXo比较,看是否相同,相同,便注册成功了!



其注册算法转换成用 Delphi + KOL/MCK 写的代码即是如下形式:(已写成为一个string函数格式,方便你的调用和修改,嘿嘿 :)


function PhoXo_sn(codechk: string): string;   //PhoXo v6.0 软件的算法函数
var
i, bl, cl, dl : integer;
begin
for i:=1 to 5 do    //还原 PhoXo v6.0 软件本身的算法
    begin
      if (i=4)
      then begin
             dl := ord(codechk);//注册码第10位
             cl := ord(codechk);    //注册码第 4位
             dl := dl - $30;
             cl := cl + dl;
             codechk := chr(cl);
         end
      else begin
             cl := ord(codechk);//注册码第7,8,9,11位依次
             bl := ord(codechk);    //注册码第1,2,3, 5位依次
             cl := cl - bl;
             cl := cl + $30;
             codechk := chr(cl);
         end;
end;
Result := codechk;
end;



而根据上面的算法,也就可以写出一个可用的注册机了;
用 Delphi + KOL/MCK 写的代码即是如下形式:(已写成为一个string函数格式,方便你的调用和修改,嘿嘿 :)


function PhoXo_keygen(RegName : string): string;//PhoXo v6.0 注册机算法
var
i : integer;
begin
if RegName = ''
then begin
         showmessage('InPut Your Name, First!');
         exit;
       end
else Regname := 'PhoXo-' +
                   chr(ord($61 + random(26)))+
                   chr(ord($61 + random(26)))+
                   chr(ord($61 + random(26)))+
                   chr(ord($41 + random(26)))+
                   chr(ord($61 + random(26)));
for i:=1 to 5 do
    begin
      case i of   //注册码第7,8,9,10,11位依次和字符串PhoXo运算
      1: Regname := chr($30 + ord(Regname) - ord('P'));
      2: Regname := chr($30 + ord(Regname) - ord('h'));
      3: Regname := chr($30 + ord(Regname) - ord('o'));
      4: Regname := chr($30 - ord(Regname) + ord('X'));
      5: Regname := chr($30 + ord(Regname) - ord('o'));
      end;
    end;
Result := Regname;
end;



上面的注册机算法在多台机器上使用不同注册名通过验证,但没有时间再优化它了,应该不存在bug的问题;

软件输入的注册信息保存在 register.ini 文件中,其格式为: 注册名长度 00 00 00 注册名 注册码长度 00 00 00 注册码



放上几组可用的Key:

注册名:aCaFeeL

注册码:QB(6)-qzgRh         或者
      J6222-jnqVq         或者
      MA814-mywWs         或者
      L=9=9-luxKx         或者
      T-546-tetTu         或者
      R+246-rcqTu         或者
      焎症-!注册         或者
      搼z忖-成功!


好的,就到这里结束吧!分析难免有不当之处,还望大家给我指出来!

lgjxj 发表于 2007-11-10 18:31:36

抢先顶贴 , 保存一下该可以学到很多东西的, 嗯

acafeel 发表于 2007-11-16 14:13:44

原帖由 lgjxj 于 2007-11-10 18:31 发表 https://www.chinapyg.com/images/common/back.gif
抢先顶贴 , 保存一下该可以学到很多东西的, 嗯
KAN大哥,不许过分谦虚哈~

fengasdf 发表于 2007-11-19 17:07:32

学习逆向工程ing...

sdprtf 发表于 2007-11-21 17:09:45

好东西,谢谢楼主

sdprtf 发表于 2007-11-22 09:39:10

可以学到很多东西的

clh1979cmh 发表于 2007-11-22 10:55:43

好东西!!!!继续吧
页: [1]
查看完整版本: 一款图象处理软件 PhoXo v6.0 的注册算法分析 + 注册机源代码