【软件名称】Photo Screensaver Maker V5.0.0
【破文作者】forever[RCT]
【编程语言】VC
【保护方式】RSA256
【使用工具】ida4.6,ollydbg1.1
【软件简介】一款幻灯屏幕保护程序制作软件,你可以用它来制作带照片、音乐和文本的屏保。支持的图片格式:jpg,gif,bmp,png,tif,tga,pcx。支持音频格式:mp3,midi和wav。可以为图片添加文本,并为图片设置各种转场过渡效果
【下载地址】http://www3.skycn.com/soft/22288.html
【破文正文】这个软件不错,使用简单,做出的屏保有很多特效。
            破解的基本步骤如下:
            1。用peid检测一下编程语言,并且顺便用插件查看一下使用算法。编程语言是VC++,检测到的算法是CRC。不过软件实际使用的算
               法却不是CRC。
            2。运行程序,看看注册过程能提供给我们什么信息。注册需要注册名和注册码,没有和硬件绑定。填入注册名,随便填一个注册码:
               12345678,弹出一个出错的对话框,给出提示信息:Invalid user name or register code。
            3。用ida载入主程序分析。分析完后在字符串列表里找到Invalid user name or register code这个字符串。来到引用该字符串的地
               方,如下:
===================================================================================================                
.text:0042B6D1                 push    1
.text:0042B6D3                 mov     ecx, esi
.text:0042B6D5                 call    CWnd::UpdateData(int)
.text:0042B6DA                 lea     edi, [esi+64h]
.text:0042B6DD                 push    0Ah
.text:0042B6DF                 mov     ecx, edi
.text:0042B6E1                 call    MFC42_6874
.text:0042B6E6                 push    0Dh
.text:0042B6E8                 mov     ecx, edi
.text:0042B6EA                 call    MFC42_6874
.text:0042B6EF                 push    9
.text:0042B6F1                 mov     ecx, edi
.text:0042B6F3                 call    MFC42_6874
.text:0042B6F8                 push    20h
.text:0042B6FA                 mov     ecx, edi
.text:0042B6FC                 call    MFC42_6874
.text:0042B701                 mov     eax, [edi]
.text:0042B703                 mov     ecx, [esi+60h]
.text:0042B706                 push    eax
.text:0042B707                 push    ecx
.text:0042B708                 call    sub_402752      //这里就是判断注册是否成功的函数了。成功返回1,失败返回0
.text:0042B70D                 add     esp, 8
.text:0042B710                 test    eax, eax
.text:0042B712                 jnz     short loc_42B73F
.text:0042B714                 push    40h
.text:0042B716                 push    offset aSorry   ; "Sorry"
.text:0042B71B                 push    offset aInvalidUserNam ; "Invalid user name or register code"
.text:0042B720                 mov     ecx, esi
.text:0042B722                 call    CWnd::MessageBoxA(char const *,char const *,uint)
.text:0042B727                 push    3F3h
.text:0042B72C                 mov     ecx, esi
.text:0042B72E                 call    CWnd::GetDlgItem(int)
.text:0042B733                 mov     ecx, eax
.text:0042B735                 call    CWnd::SetFocus(void)
.text:0042B73A                 jmp     loc_42B88C
.text:0042B73F
.text:0042B73F loc_42B73F:                            
.text:0042B73F                 mov     dword ptr [ebp+0C4h], 1
.text:0042B749                 mov     eax, [esi+60h]
.text:0042B74C                 push    eax
.text:0042B74D                 lea     ecx, [ebp+0CCh]
.text:0042B753                 call    CString::operator=(char const *)
.text:0042B758                 mov     eax, [esi+60h]
.text:0042B75B                 push    eax
.text:0042B75C                 lea     eax, [esp+218h]
.text:0042B763                 push    offset aLicenseToS ; "License to:%s"
.text:0042B768                 push    eax
.text:0042B769                 call    ds:sprintf
.text:0042B76F                 add     esp, 0Ch
.text:0042B772                 lea     ecx, [esp+214h]
.text:0042B779                 push    40h
.text:0042B77B                 push    offset aThankYou ; "Thank you"
.text:0042B780                 push    ecx
.text:0042B781                 mov     ecx, esi
.text:0042B783                 call    CWnd::MessageBoxA(char const *,char const *,uint)
.text:0042B788                 mov     eax, [esi+60h]
.text:0042B78B                 lea     edx, [esp+14h]
.text:0042B78F                 sub     edx, eax
.text:0042B791
.text:0042B791 loc_42B791:                          
.text:0042B791                 mov     cl, [eax]
.text:0042B793                 mov     [edx+eax], cl
.text:0042B796                 inc     eax
.text:0042B797                 test    cl, cl
.text:0042B799                 jnz     short loc_42B791
.text:0042B79B                 mov     edi, [edi]
.text:0042B79D                 lea     ecx, [esp+114h]
.text:0042B7A4                 sub     ecx, edi
.text:0042B7A6
.text:0042B7A6 loc_42B7A6:                            
.text:0042B7A6                 mov     al, [edi]
.text:0042B7A8                 mov     [ecx+edi], al
.text:0042B7AB                 inc     edi
.text:0042B7AC                 test    al, al
.text:0042B7AE                 jnz     short loc_42B7A6
.text:0042B7B0                 lea     ecx, [esp+0Ch]
.text:0042B7B4                 call    CString::CString(void)
.text:0042B7B9                 lea     edx, [esp+10h]
.text:0042B7BD                 mov     dword ptr [esp+31Ch], 0
.text:0042B7C8                 push    edx
.text:0042B7C9                 call    sub_401D5C
.text:0042B7CE                 add     esp, 4
.text:0042B7D1                 push    eax
.text:0042B7D2                 lea     ecx, [esp+10h]
.text:0042B7D6                 mov     byte ptr [esp+320h], 1
.text:0042B7DE                 call    CString::operator=(CString const &)
.text:0042B7E3                 lea     ecx, [esp+10h]
.text:0042B7E7                 mov     byte ptr [esp+31Ch], 0
.text:0042B7EF                 call    CString::~CString(void)
.text:0042B7F4                 lea     eax, [esp+0Ch]
.text:0042B7F8                 push    offset aDataRegdata_in ; "data\\regdata.ini" //注册信息保存到regdata.ini里
.text:0042B7FD                 lea     ecx, [esp+14h]
.text:0042B801                 push    eax
.text:0042B802                 push    ecx
.text:0042B803                 call    operator+(CString const &,char const *)
.text:0042B808                 push    eax
.text:0042B809                 lea     ecx, [esp+10h]
.text:0042B80D                 mov     byte ptr [esp+320h], 2
.text:0042B815                 call    CString::operator=(CString const &)
.text:0042B81A                 lea     ecx, [esp+10h]
.text:0042B81E                 mov     byte ptr [esp+31Ch], 0
.text:0042B826                 call    CString::~CString(void)
.text:0042B82B                 mov     edx, [esp+0Ch]
.text:0042B82F                 mov     edi, ds:WritePrivateProfileStringA
.text:0042B835                 lea     eax, [esp+14h]
.text:0042B839                 push    edx
.text:0042B83A                 push    eax
.text:0042B83B                 push    offset aUserName ; "User name"
.text:0042B840                 push    offset aRegister ; "Register"
.text:0042B845                 call    edi ; WritePrivateProfileStringA
.text:0042B847                 mov     ecx, [esp+0Ch]
.text:0042B84B                 lea     edx, [esp+114h]
.text:0042B852                 push    ecx
.text:0042B853                 push    edx
.text:0042B854                 push    offset aRegistrationCo ; "Registration code"
.text:0042B859                 push    offset aRegister ; "Register"
.text:0042B85E                 call    edi ; WritePrivateProfileStringA
.text:0042B860                 mov     eax, [ebp+0]
.text:0042B863                 mov     ecx, ebp

    让我们跟进函数402752,来到下面:
    看看下面这段函数,我猜测是RSA算法,并且是RSA256。猜算法并没有什么好的方法,大多是凭经验。
    这段函数我结合ollydbg来分析,并且用我修改的RsaKit来验证。:) 详细分析见注释:
    
===================================================================================================
.text:0042AFF0 loc_42AFF0:                            
.text:0042AFF0                 push    0FFFFFFFFh
.text:0042AFF2                 push    offset loc_4C3349
.text:0042AFF7                 mov     eax, large fs:0
.text:0042AFFD                 push    eax
.text:0042AFFE                 mov     large fs:0, esp
.text:0042B005                 sub     esp, 94h
.text:0042B00B                 mov     eax, [esp+0A4h]
.text:0042B012                 push    ebx
.text:0042B013                 push    esi
.text:0042B014                 push    eax
.text:0042B015                 lea     ecx, [esp+10h]
.text:0042B019                 mov     dword ptr [esp+60h], 0FBF8A47h
.text:0042B021                 mov     dword ptr [esp+64h], 234E94C9h
.text:0042B029                 mov     dword ptr [esp+68h], 0E4475D85h
.text:0042B031                 mov     dword ptr [esp+6Ch], 0DBF030EEh
.text:0042B039                 mov     dword ptr [esp+70h], 323B9C06h
.text:0042B041                 mov     dword ptr [esp+74h], 0E3D3C333h
.text:0042B049                 mov     dword ptr [esp+78h], 0C9BF2B1Ah
.text:0042B051                 mov     dword ptr [esp+7Ch], 385AC5EEh   //这里是N
.text:0042B059                 call    CString::CString(char const *)   //用户名
.text:0042B05E                 mov     ecx, [esp+0B0h]
.text:0042B065                 mov     dword ptr [esp+0A4h], 0
.text:0042B070                 push    ecx
.text:0042B071                 lea     ecx, [esp+0Ch]
.text:0042B075                 call    CString::CString(char const *)   //注册码
.text:0042B07A                 mov     edx, [esp+0Ch]
.text:0042B07E                 mov     esi, ds:_mbscmp
.text:0042B084                 push    offset ValueName
.text:0042B089                 push    edx
.text:0042B08A                 mov     byte ptr [esp+0ACh], 1
.text:0042B092                 call    esi ; _mbscmp               //比较用户名是否为空
.text:0042B094                 add     esp, 8
.text:0042B097                 test    eax, eax
.text:0042B099                 jz      loc_42B2AE
.text:0042B09F                 mov     eax, [esp+8]
.text:0042B0A3                 push    offset ValueName
.text:0042B0A8                 push    eax
.text:0042B0A9                 call    esi ; _mbscmp               //比较注册码是否为空
.text:0042B0AB                 add     esp, 8
.text:0042B0AE                 test    eax, eax
.text:0042B0B0                 jz      loc_42B2AE
.text:0042B0B6                 push    edi
.text:0042B0B7                 push    0
.text:0042B0B9                 lea     ecx, [esp+44h]
.text:0042B0BD                 call    sub_4016D1                 //初始化大数1
.text:0042B0C2                 push    0
.text:0042B0C4                 lea     ecx, [esp+4Ch]
.text:0042B0C8                 mov     byte ptr [esp+0ACh], 2
.text:0042B0D0                 call    sub_4016D1                 //初始化大数2
.text:0042B0D5                 mov     bl, 3
.text:0042B0D7                 push    10001h
.text:0042B0DC                 lea     ecx, [esp+5Ch]
.text:0042B0E0                 mov     [esp+0ACh], bl
.text:0042B0E7                 call    sub_4016D1                 //初始化大数E(10001)
.text:0042B0EC                 lea     ecx, [esp+58h]             //我根据这个猜测是RSA
.text:0042B0F0                 mov     byte ptr [esp+0A8h], 4
.text:0042B0F8                 push    ecx
.text:0042B0F9                 lea     ecx, [esp+4Ch]
.text:0042B0FD                 call    sub_401D07                 //复制大数E到大数2
.text:0042B102                 lea     ecx, [esp+58h]
.text:0042B106                 mov     [esp+0A8h], bl
.text:0042B10D                 call    sub_401BC7
.text:0042B112                 lea     edx, [esp+60h]
.text:0042B116                 push    8
.text:0042B118                 push    edx
.text:0042B119                 lea     ecx, [esp+48h]
.text:0042B11D                 call    sub_40276B                 //大数1赋值为N
.text:0042B122                 mov     ecx, 8
.text:0042B127                 xor     eax, eax
.text:0042B129                 lea     edi, [esp+18h]             //这里32个字节清零,准备读入注册码
.text:0042B12D                 lea     edx, [esp+2Ch]
.text:0042B131                 rep stosd
.text:0042B133                 lea     eax, [esp+34h]
.text:0042B137                 lea     ecx, [esp+30h]
.text:0042B13B                 push    eax
.text:0042B13C                 push    ecx
.text:0042B13D                 lea     eax, [esp+30h]
.text:0042B141                 push    edx
.text:0042B142                 lea     ecx, [esp+30h]
.text:0042B146                 push    eax
.text:0042B147                 lea     edx, [esp+30h]
.text:0042B14B                 push    ecx
.text:0042B14C                 lea     eax, [esp+30h]
.text:0042B150                 push    edx
.text:0042B151                 mov     edx, [esp+24h]
.text:0042B155                 lea     ecx, [esp+30h]
.text:0042B159                 push    eax
.text:0042B15A                 push    ecx
.text:0042B15B                 push    offset a08lx08lx08lx08 ; "%08lX-%08lX-%08lX-%08lX-%08lX-%08lX-%08"...
.text:0042B160                 push    edx
.text:0042B161                 call    ds:sscanf                //读入注册码,从这里可以看出注册码的格式
.text:0042B167                 mov     eax, [esp+50h]           //第五组注册码
.text:0042B16B                 mov     ecx, [esp+4Ch]           //第四组注册码
.text:0042B16F                 mov     edi, [esp+48h]           //第三组注册码
.text:0042B173                 mov     edx, [esp+44h]           //第二组注册码
.text:0042B177                 add     eax, ecx                 //第五组加上第四组
.text:0042B179                 mov     ecx, [esp+5Ch]           //第八组注册码
.text:0042B17D                 add     eax, edi                 //和加上第三组
.text:0042B17F                 mov     edi, [esp+58h]           //第七组注册码
.text:0042B183                 add     eax, edx                 //和加上第二组
.text:0042B185                 mov     edx, [esp+54h]           //第六组注册码
.text:0042B189                 xor     ecx, eax                 //和异或上第八组注册码
.text:0042B18B                 mov     eax, [esp+40h]           //第一组注册码
.text:0042B18F                 add     esp, 28h
.text:0042B192                 add     edx, eax                 //第六组加上第一组
.text:0042B194                 mov     [esp+34h], ecx           //异或后的结果保存到原来第八组的位置(8=(5+4+3+2)xor8)
.text:0042B198                 xor     edi, edx                 //和异或上第七组
.text:0042B19A                 push    0
.text:0042B19C                 lea     ecx, [esp+3Ch]
.text:0042B1A0                 mov     [esp+34h], edi           //异或后的结果保存到原来第七组的位置(7=(1+6)xor7)
.text:0042B1A4                 call    sub_4016D1               //初始化大数3
.text:0042B1A9                 lea     ecx, [esp+18h]
.text:0042B1AD                 push    8
.text:0042B1AF                 push    ecx        
.text:0042B1B0                 lea     ecx, [esp+40h]
.text:0042B1B4                 mov     byte ptr [esp+0B0h], 5
.text:0042B1BC                 call    sub_40276B               //大数3读入处理后的注册码
.text:0042B1C1                 lea     edx, [esp+38h]
.text:0042B1C5                 lea     eax, [esp+50h]
.text:0042B1C9                 push    edx                      //大数3
.text:0042B1CA                 push    eax                      //用来保存结果
.text:0042B1CB                 lea     ecx, [esp+48h]
.text:0042B1CF                 call    loc_402A0E               //RSA运算
.text:0042B1D4                 mov     ecx, 8
.text:0042B1D9                 xor     eax, eax
.text:0042B1DB                 lea     edi, [esp+18h]
.text:0042B1DF                 push    8
.text:0042B1E1                 rep stosd                        //清零32个字节缓冲区
.text:0042B1E3                 lea     ecx, [esp+1Ch]
.text:0042B1E7                 mov     byte ptr [esp+0ACh], 6
.text:0042B1EF                 push    ecx
.text:0042B1F0                 lea     ecx, [esp+58h]
.text:0042B1F4                 call    sub_401C99               //输出RSA运算结果
.text:0042B1F9                 mov     ecx, 8 
.text:0042B1FE                 xor     eax, eax
.text:0042B200                 lea     edi, [esp+80h]
.text:0042B207                 rep stosd
.text:0042B209                 pop     edi
.text:0042B20A
.text:0042B20A loc_42B20A:                           
.text:0042B20A                 mov     dl, [esp+eax+17h]        //转换大小尾
.text:0042B20E                 mov     cl, [esp+eax+16h]
.text:0042B212                 mov     [esp+eax+7Ch], dl
.text:0042B216                 mov     edx, [esp+eax+14h]
.text:0042B21A                 mov     [esp+eax+7Dh], cl
.text:0042B21E                 mov     cl, [esp+eax+14h]
.text:0042B222                 shr     edx, 8
.text:0042B225                 mov     [esp+eax+7Eh], dl
.text:0042B229                 mov     [esp+eax+7Fh], cl
.text:0042B22D                 add     eax, 4
.text:0042B230                 cmp     eax, 20h
.text:0042B233                 jl      short loc_42B20A
.text:0042B235                 lea     edx, [esp+7Ch]
.text:0042B239                 lea     ecx, [esp+10h]
.text:0042B23D                 push    edx
.text:0042B23E                 call    CString::CString(char const *)
.text:0042B243                 mov     eax, [esp+10h]
.text:0042B247                 mov     ecx, [esp+0Ch]
.text:0042B24B                 push    eax                    //RSA结果
.text:0042B24C                 push    ecx                    //用户名
.text:0042B24D                 call    esi ; _mbscmp          //比较两个字符串是否相等
.text:0042B24F                 add     esp, 8
.text:0042B252                 lea     ecx, [esp+10h]
.text:0042B256                 test    eax, eax
.text:0042B258                 mov     byte ptr [esp+0A4h], 6
.text:0042B260                 jz      loc_42B2EC             //相等则返回1
.text:0042B266                 call    CString::~CString(void)
.text:0042B26B                 lea     ecx, [esp+4Ch]
.text:0042B26F                 mov     byte ptr [esp+0A4h], 5
.text:0042B277                 call    sub_401BC7
.text:0042B27C                 lea     ecx, [esp+34h]
.text:0042B280                 mov     [esp+0A4h], bl
.text:0042B287                 call    sub_401BC7
.text:0042B28C                 lea     ecx, [esp+44h]
.text:0042B290                 mov     byte ptr [esp+0A4h], 8
.text:0042B298                 call    sub_401BC7
.text:0042B29D                 lea     ecx, [esp+3Ch]
.text:0042B2A1                 mov     byte ptr [esp+0A4h], 1
.text:0042B2A9                 call    sub_401BC7
.text:0042B2AE
.text:0042B2AE loc_42B2AE:                             
.text:0042B2AE                                        
.text:0042B2AE                 lea     ecx, [esp+8]
.text:0042B2B2                 mov     byte ptr [esp+0A4h], 0
.text:0042B2BA                 call    CString::~CString(void)
.text:0042B2BF                 lea     ecx, [esp+0Ch]
.text:0042B2C3                 mov     dword ptr [esp+0A4h], 0FFFFFFFFh
.text:0042B2CE                 call    CString::~CString(void)
.text:0042B2D3                 pop     esi
.text:0042B2D4                 xor     eax, eax
.text:0042B2D6                 pop     ebx
.text:0042B2D7                 mov     ecx, [esp+94h]
.text:0042B2DE                 mov     large fs:0, ecx
.text:0042B2E5                 add     esp, 0A0h
.text:0042B2EB                 retn

===================================================================================================
    总结:1。预处理注册码。
             注册码分为8组,第8组 = (5,4,3,2组之和)异或 第8组
                            第7组 = (1,6组之和)异或 第7组
                            
          2。RSA256运算
             N : 385AC5EEC9BF2B1AE3D3C333323B9C06DBF030EEE4475D85234E94C90FBF8A47
             E : 10001
             
          3。变换RSA256运算结果     
             把形如12 34 56 78 90 ab cd ef 的形式转换为78 56 34 12 ef cd ab 90的形式
             
          4。变换后的结果和用户名比较,相等则注册成功,不等则失败。

    
    注册算法是上面的逆运算,分解一个256位的N在我的机器上大概半小时的时间,注册算法就不给出了。感兴趣的可以自己做一下。
===================================================================================================
       [全文完]

  • 标 题: 答复
  • 作 者:ForEver
  • 时 间:2006-01-15 10:02

难得你对这个感兴趣,这样吧。我公开注册机源代码给你参考一下。大数库用的是afanty的BigInt,在看雪主页有下载。

void CPhotoScreensaverMakerDlg::OnButton1() 
{
  CString iN = "385AC5EEC9BF2B1AE3D3C333323B9C06DBF030EEE4475D85234E94C90FBF8A47"; 
  CString iD = "F9816C36FF24564487CF5BBF9FF82BA1F5D47F0BBA287F2B0A1DDB78B11CF09";
  CString name,code;

    char tmp[32],tmp1[3],tmp2[65];
    CBigInt N,D,scr,r;
  int i,len;
    unsigned long x1,x2,x3,x4,x5,x6,x7,x8;
  char *dummy;
  char mycode[72];
  char c;
  UpdateData();
    len = m_name.GetLength();
  if(len > 15)
  {
    MessageBox("The length of the name must less then 15!","notice",MB_OK);
        return;
  }
    memset(tmp,0,32);
  strcpy(tmp,m_name);
  for(i = 0; i < 8; i++)
  {
    c = tmp[i*4];
    tmp[i*4] = tmp[i*4+3];
    tmp[i*4+3] = c;
    c = tmp[i*4+1];
    tmp[i*4+1] = tmp[i*4+2];
    tmp[i*4+2] = c;
  }
    for(i = 0; i < 32; i ++)
  {
    memset(tmp1,0,3);
    sprintf(tmp1,"%02X",tmp[31-i]);
    name = name + tmp1;
    }

  N.Get(iN);
  D.Get(iD);
  scr.Get(name);
    r.Mov(scr.RsaTrans(D,N));
  r.Put(code);
  if((code.GetLength() % 2) != 0)
  {
    code = "0" + code;
  }
  memset(tmp2,'0',64);
  tmp2[64] = 0;
  strncpy(tmp2,code,64);
    
    code = tmp2;

    x8 = strtoul(code.Mid(0,8),&dummy,16);
  x7 = strtoul(code.Mid(8,8),&dummy,16);
  x6 = strtoul(code.Mid(16,8),&dummy,16);
  x5 = strtoul(code.Mid(24,8),&dummy,16);
  x4 = strtoul(code.Mid(32,8),&dummy,16);
  x3 = strtoul(code.Mid(40,8),&dummy,16);
  x2 = strtoul(code.Mid(48,8),&dummy,16);
  x1 = strtoul(code.Mid(56,8),&dummy,16);
  x8 = (x2+x3+x4+x5) ^ x8;
  x7 = (x1+x6) ^ x7;
    memset(mycode,0,72);
    sprintf(mycode,"%08X-%08X-%08X-%08X-%08X-%08X-%08X-%08X",x1,x2,x3,x4,x5,x6,x7,x8);
  m_code = mycode;
  UpdateData(false);
}