bxm 发表于 2007-6-21 23:51:46

友锋图像处理系统5.7注册算法分析

【文章标题】: 友锋图像处理系统5.7注册算法分析
【文章作者】: bxm
【作者邮箱】: [email protected]
【软件名称】: 友锋图像处理系统
【下载地址】: 自己搜索下载
【编写语言】: Borland Delphi 6.0 - 7.0
【使用工具】: OD,winhex,计算器
【操作平台】: winxp_sp2
--------------------------------------------------------------------------------
【详细过程】
    应一个朋友之要求破解这个软件,顺便把破文发出来,有错误之处,请各位批评指正。

    拿到软件,试运行,发现有两种注册方式,一是通过网络下载注册码,二是从文件中读取注册码。决定从文件验证入手。
    注册文件名不固定,扩展名为.dat。用记事本建了个bxm.dat,输入1234567890十个字符,然后读入注册文件,确定以后发现没什么反应,好像假死一样,决定用OD调试。
    既然是文件验证,就下个断点bp ReadFile,断下后,Alt+F9返回程序领空。
00403276|.6A 00         push    0                              ; /pOverlapped = NULL
00403278|.50            push    eax                              ; |pBytesRead
00403279|.FF73 08       push    dword ptr                 ; |BytesToRead
0040327C|.52            push    edx                              ; |Buffer
0040327D|.FF33          push    dword ptr                   ; |hFile
0040327F|.E8 B0E0FFFF   call    <jmp.&kernel32.ReadFile>         ; \ReadFile
00403284|.5A            pop   edx
00403285|.48            dec   eax
00403286|.75 13         jnz   short 0040329B                   ;如果文件不存在,跳。
00403288|.3B53 08       cmp   edx, dword ptr          ;文件大小与0x328比较
0040328B|.74 18         je      short 004032A5                   ;相等,跳
0040328D|.B8 64000000   mov   eax, 64
00403292|.EB 0C         jmp   short 004032A0
00403294|>B8 67000000   mov   eax, 67
00403299|.EB 05         jmp   short 004032A0
0040329B|>E8 14E1FFFF   call    <jmp.&kernel32.GetLastError>   ; [GetLastError
004032A0|>E8 17F7FFFF   call    004029BC
004032A5|>5B            pop   ebx
004032A6\.C3            retn

由上可知,文件必须为0x328字节。重新建个0x328大小的文件,004032A6返回到如下地址。
005D3B22|.E8 75EEE2FF   call    0040299C
005D3B27|.8D85 B4FEFFFF lea   eax, dword ptr
005D3B2D|.E8 4AF5E2FF   call    0040307C
005D3B32|.E8 65EEE2FF   call    0040299C
005D3B37|.66:81BD B0FEF>cmp   word ptr , 300          ;检查注册文件的第805、806字节是否为0x0003
005D3B40|.0F84 99000000 je      005D3BDF                         ;如果相等,说明版本正确,否则弹出版本不符对话框

强行跳过此处。

005D3BDF|> \8D85 68FBFFFF lea   eax, dword ptr
005D3BE5|.8D95 90FBFFFF lea   edx, dword ptr       ;注册文件的第5个字节地址入EDX
005D3BEB|.E8 4810E3FF   call    00404C38                        ;根据注册文件内容截取一些数据作为注册用户名,比较复杂,懒得跟了
005D3BF0|.8B85 68FBFFFF mov   eax, dword ptr
005D3BF6|.8D95 6CFBFFFF lea   edx, dword ptr
005D3BFC|.E8 7BF4FFFF   call    005D307C                        ;加密用户名,懒得跟了
005D3C01|.8B8D 6CFBFFFF mov   ecx, dword ptr
005D3C07|.BA 483E5D00   mov   edx, 005D3E48                   ;value
005D3C0C|.B8 583E5D00   mov   eax, 005D3E58                   ;user
005D3C11|.E8 5E92F7FF   call    0054CE74                        ;在HKEY_CURRENT_USER\Software\友锋图像处理系统\User下写入Value的值为加密后用户名
005D3C16|.8B8D 8CFBFFFF mov   ecx, dword ptr
005D3C1C|.BA 683E5D00   mov   edx, 005D3E68                   ;order
005D3C21|.B8 783E5D00   mov   eax, 005D3E78                   ;ASCII "Application"
005D3C26|.E8 6D93F7FF   call    0054CF98                        ;在HKEY_CURRENT_USER\Software\友锋图像处理系统\Application下写入Order的值为注册文件的第1至4字节所转换成的字符串
005D3C2B|.8D85 60FBFFFF lea   eax, dword ptr
005D3C31|.8D95 90FBFFFF lea   edx, dword ptr
005D3C37|.E8 FC0FE3FF   call    00404C38
005D3C3C|.8B85 60FBFFFF mov   eax, dword ptr
005D3C42|.8D95 64FBFFFF lea   edx, dword ptr
005D3C48|.E8 2FF4FFFF   call    005D307C
005D3C4D|.8B8D 64FBFFFF mov   ecx, dword ptr
005D3C53|.BA 8C3E5D00   mov   edx, 005D3E8C                   ;ASCII "Hint"
005D3C58|.B8 783E5D00   mov   eax, 005D3E78                   ;ASCII "Application"
005D3C5D|.E8 1292F7FF   call    0054CE74                        ;写入Hint的值为加密后的用户名
005D3C62|.33C9          xor   ecx, ecx
005D3C64|.8A8D AFFBFFFF mov   cl, byte ptr           ;注册文件的第36字节入cl
005D3C6A|.BA 9C3E5D00   mov   edx, 005D3E9C                   ;ASCII "Setx"
005D3C6F|.B8 783E5D00   mov   eax, 005D3E78                   ;ASCII "Application"
005D3C74|.E8 1F93F7FF   call    0054CF98                        ;写入Setx的值为cl所转换成的十进制字符串
005D3C79|.B2 01         mov   dl, 1
005D3C7B|.A1 8C1C4400   mov   eax, dword ptr
005D3C80|.E8 07E1E6FF   call    00441D8C
005D3C85|.8BD8          mov   ebx, eax
005D3C87|.BA 01000080   mov   edx, 80000001
005D3C8C|.8BC3          mov   eax, ebx
005D3C8E|.E8 99E1E6FF   call    00441E2C
005D3C93|.B1 01         mov   cl, 1
005D3C95|.BA AC3E5D00   mov   edx, 005D3EAC
005D3C9A|.8BC3          mov   eax, ebx
005D3C9C|.E8 CBE2E6FF   call    00441F6C
005D3CA1|.68 FF000000   push    0FF                           ; /Arg1 = 000000FF
005D3CA6|.8D8D B0FBFFFF lea   ecx, dword ptr       ; |
005D3CAC|.BA DC3E5D00   mov   edx, 005D3EDC                   ; |ASCII "Set1"
005D3CB1|.8BC3          mov   eax, ebx                        ; |
005D3CB3|.E8 28E5E6FF   call    004421E0                        ; \写入Set1的值为注册文件的第37字节以后的255字节
005D3CB8|.68 FF000000   push    0FF                           ; /Arg1 = 000000FF
005D3CBD|.8D8D B0FCFFFF lea   ecx, dword ptr       ; |
005D3CC3|.BA EC3E5D00   mov   edx, 005D3EEC                   ; |ASCII "Set2"
005D3CC8|.8BC3          mov   eax, ebx                        ; |
005D3CCA|.E8 11E5E6FF   call    004421E0                        ; \写入Set2的值为注册文件的第292字节以后的255字节
005D3CCF|.68 FF000000   push    0FF                           ; /Arg1 = 000000FF
005D3CD4|.8D8D B0FDFFFF lea   ecx, dword ptr       ; |
005D3CDA|.BA FC3E5D00   mov   edx, 005D3EFC                   ; |ASCII "Set3"
005D3CDF|.8BC3          mov   eax, ebx                        ; |
005D3CE1|.E8 FAE4E6FF   call    004421E0                        ; \写入Set3的值为注册文件的第37字节以后的545字节
005D3CE6|.8BC3          mov   eax, ebx
005D3CE8|.E8 0FE1E6FF   call    00441DFC
005D3CED|.B1 01         mov   cl, 1
005D3CEF|.BA 0C3F5D00   mov   edx, 005D3F0C
005D3CF4|.8BC3          mov   eax, ebx
005D3CF6|.E8 71E2E6FF   call    00441F6C
005D3CFB|.8D85 5CFBFFFF lea   eax, dword ptr
005D3D01|.8D95 90FBFFFF lea   edx, dword ptr
005D3D07|.E8 2C0FE3FF   call    00404C38
005D3D0C|.8B8D 5CFBFFFF mov   ecx, dword ptr
005D3D12|.BA 583E5D00   mov   edx, 005D3E58                   ;ASCII "User"
005D3D17|.8BC3          mov   eax, ebx
005D3D19|.E8 0AE4E6FF   call    00442128
005D3D1E|.BA 2C3F5D00   mov   edx, 005D3F2C                   ;ASCII "State"
005D3D23|.8BC3          mov   eax, ebx
005D3D25|.E8 0AE6E6FF   call    00442334
005D3D2A|.84C0          test    al, al
005D3D2C|.74 0C         je      short 005D3D3A
005D3D2E|.BA 2C3F5D00   mov   edx, 005D3F2C                   ;ASCII "State"
005D3D33|.8BC3          mov   eax, ebx
005D3D35|.E8 56E3E6FF   call    00442090
005D3D3A|>8BC3          mov   eax, ebx
005D3D3C|.E8 BBE0E6FF   call    00441DFC
005D3D41|.8BC3          mov   eax, ebx
005D3D43|.E8 78FEE2FF   call    00403BC0
005D3D48|.6A 40         push    40
005D3D4A|.8D95 58FBFFFF lea   edx, dword ptr
005D3D50|.A1 D4066B00   mov   eax, dword ptr
005D3D55|.8B00          mov   eax, dword ptr
005D3D57|.E8 A430ECFF   call    00496E00
005D3D5C|.8B85 58FBFFFF mov   eax, dword ptr
005D3D62|.E8 2D11E3FF   call    00404E94
005D3D67|.50            push    eax
005D3D68|.68 343F5D00   push    005D3F34
005D3D6D|.8BC6          mov   eax, esi
005D3D6F|.E8 447FEAFF   call    0047BCB8
005D3D74|.50            push    eax                           ; |hOwner
005D3D75|.E8 FE3CE3FF   call    <jmp.&user32.MessageBoxA>       ; \弹出重启验证对话框

==============================================
重启后,下断点bpx regopenkeyExA,断下后一步步找到关键处。
00649E62   .C645 FB 9E    mov   byte ptr , 9E            ;置初值0x9E
00649E66   .8B45 F0       mov   eax, dword ptr          ;Order入EAX
00649E69   .E8 26AEDBFF   call    00404C94                        ;EAX返回Order的长度
00649E6E   .85C0          test    eax, eax
00649E70   .7E 13         jle   short 00649E85
00649E72   .BB 01000000   mov   ebx, 1
00649E77   >8B55 F0       mov   edx, dword ptr
00649E7A   .8A541A FF   mov   dl, byte ptr       ;dl为Order的每一位
00649E7E   .3055 FB       xor   byte ptr , dl            ;dl异或,的初始值为0x9E
00649E81   .43            inc   ebx
00649E82   .48            dec   eax
00649E83   .^ 75 F2         jnz   short 00649E77                  ;最终得A6(我的结果)

此段代码相当于以下C程序:
for(i=0;i<10;i++)//temp为
        temp^=Order;
=============================================
00649E85   > \C645 FA 9E    mov   byte ptr , 9E
00649E89   .8B45 F4       mov   eax, dword ptr           ;注册用户名入EAX
00649E8C   .E8 03AEDBFF   call    00404C94                        ;EAX返回注册用户名的长度
00649E91   .85C0          test    eax, eax
00649E93   .7E 13         jle   short 00649EA8
00649E95   .BB 01000000   mov   ebx, 1
00649E9A   >8B55 F4       mov   edx, dword ptr
00649E9D   .8A541A FF   mov   dl, byte ptr       ;用户名的每一位入dl
00649EA1   .3055 FA       xor   byte ptr , dl            ;dl异或,的初始值为0x9E
00649EA4   .43            inc   ebx
00649EA5   .48            dec   eax
00649EA6   .^ 75 F2         jnz   short 00649E9A                  ;最终得A8

此段代码相当于以下C程序:
for(i=0;i<54;i++)//temp为,name为用户名
        temp^=name;
========================================
00649EA8   > \8D45 F4       lea   eax, dword ptr
00649EAB   .E8 24ABDBFF   call    004049D4
00649EB0   .BB 01000000   mov   ebx, 1                        ;ebx置初值1
00649EB5   .8DBD E0FEFFFF lea   edi, dword ptr
00649EBB   .8DB5 E0FCFFFF lea   esi, dword ptr       ;set3入ESI
00649EC1   .8D85 E0FDFFFF lea   eax, dword ptr       ;set2入EAX
00649EC7   .8945 E0       mov   dword ptr , eax
00649ECA   >8BC3          mov   eax, ebx
00649ECC   .B9 03000000   mov   ecx, 3
00649ED1   .99            cdq
00649ED2   .F7F9          idiv    ecx
00649ED4   .83EA 01       sub   edx, 1                        ;Switch (cases 0..2)
00649ED7   .72 07         jb      short 00649EE0
00649ED9   .74 0E         je      short 00649EE9
00649EDB   .4A            dec   edx
00649EDC   .74 19         je      short 00649EF7
00649EDE   .EB 1F         jmp   short 00649EFF
00649EE0   >8A07          mov   al, byte ptr             ;set1的第n位(循环次数位)入al; Case 0 of switch 00649ED4
00649EE2   .3245 FB       xor   al, byte ptr             ;al异或
00649EE5   .3006          xor   byte ptr , al            ;set3的第n位异或al
00649EE7   .EB 16         jmp   short 00649EFF
00649EE9   >8A06          mov   al, byte ptr             ;set3的第1位入al; Case 1 of switch 00649ED4
00649EEB   .3245 FA       xor   al, byte ptr             ;al与异或
00649EEE   .8B55 E0       mov   edx, dword ptr
00649EF1   .3202          xor   al, byte ptr             ;al与set2的第1位异或
00649EF3   .8806          mov   byte ptr , al            ;结果保存在set3的第1位
00649EF5   .EB 08         jmp   short 00649EFF
00649EF7   >8A45 FB       mov   al, byte ptr             ;入al; Case 2 of switch 00649ED4
00649EFA   .3245 FA       xor   al, byte ptr             ;al异或
00649EFD   .3006          xor   byte ptr , al            ;set3异或al
00649EFF   >8D85 D8FCFFFF lea   eax, dword ptr       ;Default case of switch 00649ED4
00649F05   .8A16          mov   dl, byte ptr             ;set3的第n位(循环次数位)入dl
00649F07   .E8 B0ACDBFF   call    00404BBC
00649F0C   .8B95 D8FCFFFF mov   edx, dword ptr
00649F12   .8D45 F4       lea   eax, dword ptr
00649F15   .E8 82ADDBFF   call    00404C9C                        ;结果复制到新位置
00649F1A   .43            inc   ebx
00649F1B   .FF45 E0       inc   dword ptr             ;set2+1
00649F1E   .46            inc   esi                           ;set3+1
00649F1F   .47            inc   edi                           ;set1+1
00649F20   .81FB FB000000 cmp   ebx, 0FB
00649F26   .^ 75 A2         jnz   short 00649ECA

此段代码相当于以下C程序:
for(i=0;i<30;i++)
        switch(i%3)
        {
                case 0:
                        al=set3;
                        al^=temp;
                        al^=set2;
                        set3=al;
                        break;
                case 1:
                        al=temp;
                        al^=temp;
                        set3^=al;
                        break;
                case 2:
                        al=set1;
                        al^=temp;
                        set3^=al;

        }
至此,set3中以存放了运算后的注册码,在下面的程序中将和机器码有多处比较,代码就不贴了。


附注册机的C++代码,以VC6中编译通过。
void CYouFeng_keygenDlg::OnButton1()
{
        // TODO: Add your control notification handler code here
unsigned char Order[]="875770417";
unsigned chartemp={0x9e,0x9e,0x9e};
unsigned char name={0x62, 0x78, 0x6D, 0x00, 0x30, 0x41, 0x42, 0x43, 0x44, 0x45,
0x46, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x30, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x31, 0x32, 0x33,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x30,0};
//name为未加密的用户名信息


unsigned char user="FCE6F39EAEDFDCDDDADBD8AFACADAAABA8A9A6A7AEDFDCDDDADBD8AFACADAAABA8A9A6A7AEDFDCDDDADBD8AFACADAAABA8A9A6A7AE";
//user为加密后的用户名

unsigned char set1="111111111111111111111111111111";
unsigned char set2="222222222222222222222222222222";
unsigned int set3;
unsigned char set3_2;
char set4;   //set4为机器码


UpdateData(true);
strcpy(set4,m_Edit);
int i;
for(i=0;i<10;i++)//temp为
        temp^=Order;

for(i=0;i<54;i++)//temp为
        temp^=name;

for(i=0;i<30;i++)
        switch(i%3)
        {
                case 0:
                        set3=set4^temp^set2;
                        break;
                case 1:
                        set3=temp^temp^set4;
                        break;
                case 2:
                        set3=temp^set4^set1;
        }

    for(i=0;i<31;i++)
    {
          set3_2=set3;
    }

    HKEY   hk;   
    RegOpenKey(HKEY_CURRENT_USER,"Software\\友锋图像处理系统",&hk);
    RegCreateKey(HKEY_CURRENT_USER,   "Software\\友锋图像处理系统\\Application",   &hk);
    RegSetValueEx(hk,"Order",   0,   REG_SZ,   Order,   9);   
    RegSetValueEx(hk,"Set1",   0,   REG_BINARY,   set1,   30);   
    RegSetValueEx(hk,"Set2",   0,   REG_BINARY,   set2,   30);   
    RegSetValueEx(hk,"Hint",   0,   REG_SZ,   user,   107);   
    RegSetValueEx(hk,"Set3",   0,   REG_BINARY,   set3_2,   30);   
    RegCloseKey(hk);   
   
    RegOpenKey(HKEY_CURRENT_USER,"Software\\友锋图像处理系统",&hk);   
    RegCreateKey(HKEY_CURRENT_USER,   "Software\\友锋图像处理系统\\User",   &hk);
    RegSetValueEx(hk,"Value",   0,   REG_SZ,   user,   107);   
    RegCloseKey(hk);   
        MessageBox("破解成功!","恭喜",MB_OK);
        UpdateData(false);       
}

--------------------------------------------------------------------------------
                                                       2007年06月21日 23:54:04

wan 发表于 2007-6-22 12:02:59

好文!学习一下KEYFILE的

kangroo 发表于 2007-6-22 22:29:46

LZ 后面部分怎么用斜体字啊 ,看的很不舒服啊 ,分析的不错 ,学习了

Nisy 发表于 2007-6-26 08:17:07

好文章,又学习了一篇,这下可以看懂了,感谢 bxm 兄弟的分析.

菜儿 发表于 2007-6-26 08:33:15

感谢 bxm 兄弟的好文章,学习了.....

易之侠 发表于 2007-6-26 09:01:30

真的不错,学习了。

laomu 发表于 2007-9-27 11:35:12

好东西。。。:loveliness:

724876383 发表于 2010-7-30 12:16:55

好好学习,天天向上!

不灭上帝 发表于 2010-8-8 08:45:51

好东西。下了顶下。
页: [1]
查看完整版本: 友锋图像处理系统5.7注册算法分析