【文章标题】: 友锋图像处理系统5.7注册算法分析+注册机源代码
【文章作者】: bxm
【作者邮箱】: bxm78@163.com
【软件名称】: 友锋图像处理系统
【下载地址】: 自己搜索下载
【编写语言】: 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 [ebx+8]                ; |BytesToRead
  0040327C  |.  52            push    edx                              ; |Buffer
  0040327D  |.  FF33          push    dword ptr [ebx]                  ; |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 [ebx+8]           ;  文件大小与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 [ebp-14C]
  005D3B2D  |.  E8 4AF5E2FF   call    0040307C
  005D3B32  |.  E8 65EEE2FF   call    0040299C
  005D3B37  |.  66:81BD B0FEF>cmp     word ptr [ebp-150], 300          ;  检查注册文件的第805、806字节是否为0x0003
  005D3B40  |.  0F84 99000000 je      005D3BDF                         ;  如果相等,说明版本正确,否则弹出版本不符对话框
  
  强行跳过此处。
  
  005D3BDF  |> \8D85 68FBFFFF lea     eax, dword ptr [ebp-498]
  005D3BE5  |.  8D95 90FBFFFF lea     edx, dword ptr [ebp-470]        ;  注册文件的第5个字节地址入EDX
  005D3BEB  |.  E8 4810E3FF   call    00404C38                        ;  根据注册文件内容截取一些数据作为注册用户名,比较复杂,懒得跟了
  005D3BF0  |.  8B85 68FBFFFF mov     eax, dword ptr [ebp-498]
  005D3BF6  |.  8D95 6CFBFFFF lea     edx, dword ptr [ebp-494]
  005D3BFC  |.  E8 7BF4FFFF   call    005D307C                        ;  加密用户名,懒得跟了
  005D3C01  |.  8B8D 6CFBFFFF mov     ecx, dword ptr [ebp-494]
  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 [ebp-474]
  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 [ebp-4A0]
  005D3C31  |.  8D95 90FBFFFF lea     edx, dword ptr [ebp-470]
  005D3C37  |.  E8 FC0FE3FF   call    00404C38
  005D3C3C  |.  8B85 60FBFFFF mov     eax, dword ptr [ebp-4A0]
  005D3C42  |.  8D95 64FBFFFF lea     edx, dword ptr [ebp-49C]
  005D3C48  |.  E8 2FF4FFFF   call    005D307C
  005D3C4D  |.  8B8D 64FBFFFF mov     ecx, dword ptr [ebp-49C]
  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 [ebp-451]          ;  注册文件的第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 [441C8C]
  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 [ebp-450]        ; |
  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 [ebp-350]        ; |
  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 [ebp-250]        ; |
  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 [ebp-4A4]
  005D3D01  |.  8D95 90FBFFFF lea     edx, dword ptr [ebp-470]
  005D3D07  |.  E8 2C0FE3FF   call    00404C38
  005D3D0C  |.  8B8D 5CFBFFFF mov     ecx, dword ptr [ebp-4A4]
  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 [ebp-4A8]
  005D3D50  |.  A1 D4066B00   mov     eax, dword ptr [6B06D4]
  005D3D55  |.  8B00          mov     eax, dword ptr [eax]
  005D3D57  |.  E8 A430ECFF   call    00496E00
  005D3D5C  |.  8B85 58FBFFFF mov     eax, dword ptr [ebp-4A8]
  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 [ebp-5], 9E            ;  [ebp-5]置初值0x9E
  00649E66   .  8B45 F0       mov     eax, dword ptr [ebp-10]         ;  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 [ebp-10]
  00649E7A   .  8A541A FF     mov     dl, byte ptr [edx+ebx-1]        ;  dl为Order的每一位
  00649E7E   .  3055 FB       xor     byte ptr [ebp-5], dl            ;  dl异或[ebp-5],[ebp-5]的初始值为0x9E
  00649E81   .  43            inc     ebx
  00649E82   .  48            dec     eax
  00649E83   .^ 75 F2         jnz     short 00649E77                  ;  最终[ebp-5]得A6(我的结果)
  
  此段代码相当于以下C程序:
  for(i=0;i<10;i++)  //temp[0]为[ebp-5]
    temp[0]^=Order[i];
  =============================================
  00649E85   > \C645 FA 9E    mov     byte ptr [ebp-6], 9E
  00649E89   .  8B45 F4       mov     eax, dword ptr [ebp-C]          ;  注册用户名入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 [ebp-C]
  00649E9D   .  8A541A FF     mov     dl, byte ptr [edx+ebx-1]        ;  用户名的每一位入dl
  00649EA1   .  3055 FA       xor     byte ptr [ebp-6], dl            ;  dl异或[ebp-6],[ebp-6]的初始值为0x9E
  00649EA4   .  43            inc     ebx
  00649EA5   .  48            dec     eax
  00649EA6   .^ 75 F2         jnz     short 00649E9A                  ;  最终[ebp-6]得A8
  
  此段代码相当于以下C程序:
  for(i=0;i<54;i++)  //temp[1]为[ebp-6],name为用户名
    temp[1]^=name[i];
  ========================================
  00649EA8   > \8D45 F4       lea     eax, dword ptr [ebp-C]
  00649EAB   .  E8 24ABDBFF   call    004049D4
  00649EB0   .  BB 01000000   mov     ebx, 1                          ;  ebx置初值1
  00649EB5   .  8DBD E0FEFFFF lea     edi, dword ptr [ebp-120]
  00649EBB   .  8DB5 E0FCFFFF lea     esi, dword ptr [ebp-320]        ;  set3入ESI
  00649EC1   .  8D85 E0FDFFFF lea     eax, dword ptr [ebp-220]        ;  set2入EAX
  00649EC7   .  8945 E0       mov     dword ptr [ebp-20], 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 [edi]              ;  set1的第n位(循环次数位)入al; Case 0 of switch 00649ED4
  00649EE2   .  3245 FB       xor     al, byte ptr [ebp-5]            ;  al异或[ebp-5]
  00649EE5   .  3006          xor     byte ptr [esi], al              ;  set3的第n位异或al
  00649EE7   .  EB 16         jmp     short 00649EFF
  00649EE9   >  8A06          mov     al, byte ptr [esi]              ;  set3的第1位入al; Case 1 of switch 00649ED4
  00649EEB   .  3245 FA       xor     al, byte ptr [ebp-6]            ;  al与[ebp-6]异或
  00649EEE   .  8B55 E0       mov     edx, dword ptr [ebp-20]
  00649EF1   .  3202          xor     al, byte ptr [edx]              ;  al与set2的第1位异或
  00649EF3   .  8806          mov     byte ptr [esi], al              ;  结果保存在set3的第1位
  00649EF5   .  EB 08         jmp     short 00649EFF
  00649EF7   >  8A45 FB       mov     al, byte ptr [ebp-5]            ;  [ebp-5]入al; Case 2 of switch 00649ED4
  00649EFA   .  3245 FA       xor     al, byte ptr [ebp-6]            ;  al异或[ebp-6]
  00649EFD   .  3006          xor     byte ptr [esi], al              ;  set3异或al
  00649EFF   >  8D85 D8FCFFFF lea     eax, dword ptr [ebp-328]        ;  Default case of switch 00649ED4
  00649F05   .  8A16          mov     dl, byte ptr [esi]              ;  set3的第n位(循环次数位)入dl
  00649F07   .  E8 B0ACDBFF   call    00404BBC
  00649F0C   .  8B95 D8FCFFFF mov     edx, dword ptr [ebp-328]
  00649F12   .  8D45 F4       lea     eax, dword ptr [ebp-C]
  00649F15   .  E8 82ADDBFF   call    00404C9C                        ;  结果复制到新位置
  00649F1A   .  43            inc     ebx
  00649F1B   .  FF45 E0       inc     dword ptr [ebp-20]              ;  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[i];
        al^=temp[1];
        al^=set2[i];
        set3[i]=al;
        break;
      case 1:
        al=temp[0];
        al^=temp[1];
        set3[i]^=al;
        break;
      case 2:
        al=set1[i];
        al^=temp[0];
        set3[i]^=al;
  
    }
  至此,set3中以存放了运算后的注册码,在下面的程序中将和机器码有多处比较,代码就不贴了。
  
  
  附注册机的C++代码,以VC6中编译通过。
  void CYouFeng_keygenDlg::OnButton1() 
  {
    // TODO: Add your control notification handler code here
  unsigned char Order[]="875770417";
  unsigned char  temp[3]={0x9e,0x9e,0x9e};
  unsigned char name[54]={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[108]="FCE6F39EAEDFDCDDDADBD8AFACADAAABA8A9A6A7AEDFDCDDDADBD8AFACADAAABA8A9A6A7AEDFDCDDDADBD8AFACADAAABA8A9A6A7AE";
  //user为加密后的用户名
  
  unsigned char set1[31]="111111111111111111111111111111";
  unsigned char set2[31]="222222222222222222222222222222";
  unsigned int set3[31];
  unsigned char set3_2[31];
  char set4[31];     //set4为机器码
  
  
  UpdateData(true);
  strcpy(set4,m_Edit);
  int i;
  for(i=0;i<10;i++)  //temp[0]为[ebp-5]
    temp[0]^=Order[i];
  
  for(i=0;i<54;i++)  //temp[1]为[ebp-6]
    temp[1]^=name[i];
  
  for(i=0;i<30;i++)
    switch(i%3)
    {
      case 0:
        set3[i]=set4[i]^temp[1]^set2[i];
        break;
      case 1:
        set3[i]=temp[0]^temp[1]^set4[i];
        break;
      case 2:
        set3[i]=temp[0]^set4[i]^set1[i];
    }
  
    for(i=0;i<31;i++)
    {
      set3_2[i]=set3[i];
    }
  
    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:44:20