SRS Audio Sandbox破解纪实

  最近挺忙的,本来需要各种为前路做准备,无奈自己天生属于低血压型的人,偏偏就是提不起劲儿来干正事儿,却把大好的一天光阴全交代到SRS的分析工作上了。虽然说这多少算不务正业,不过由于本人有着严重的软件新版本强迫症,故这算是给自己的一个开脱理由吧。

  这款软件的破解工作展开比较容易,没有加壳,直接上工具分析之。首先请出OllyDBG来,通过查找字符串引用和查找API MessageBox引用的老法子,很容易就定位了大概的关键代码位置。

  找到关键位置后,顺手又记录了一下函数调用栈,然后打开了神器IDA。用IDA载入后,跳转到之前找到的关键代码RVA处,着手分析。说起来,我自己喜欢将动态和静态调试方法结合起来用,不如果不愿意太费神分析汇编代码,有时候直接看运行时结果便是最直观和省时的。载入后发觉之前判断的关键点实际上是CWinApp::ShowAppMessageBox函数,继续沿着刚才记录的函数运行时调用栈往上找,依次顺藤摸瓜:AfxMessageBox--->Sub44D240,这才到了SRS程序的代码领空,于是正是着手分析。(IDA这个静态分析功能实在是强大,它可以根据二进制代码特征判断出其是否是库函数代码。这大大节省了我的时间,应为对这类代码我只需要看SDK文档就行了,而不需要去分析其实际的代码行为)

  进一步根据线索判断(Sub44D240里包含了SendMessage、AfxMessageBox、GetWindowText等函数,足以说明该函数的关键作用),我锁定在了Sub44D240函数的Sub4430F0调用上,继续追踪到Sub442FF0上,继而是Sub44B9E0过程,最终到了Sub44BC30过程上。在该过程中,我同时追踪到了用户输入的ProductID以及Serial Number等信息,这进一步是我确认了我的判断。

  该过程具体代码如下:

Sub44BC30代码
  1  .text:0044BC30
  2  .text:0044BC30 ; =============== S U B R O U T I N E =======================================
  3  .text:0044BC30
  4  .text:0044BC30 ; Attributes: bp-based frame
  5  .text:0044BC30
  6  .text:0044BC30 check_PID_SN    proc near               ; CODE XREF: realCheckSN+182p
  7  .text:0044BC30
  8  .text:0044BC30 productId_segs_temp= dword ptr -14h
  9  .text:0044BC30 new_ProdectID   = dword ptr -10h
 10  .text:0044BC30 sn_lowerDWord   = dword ptr -4
 11  .text:0044BC30 SN              = dword ptr  8
 12  .text:0044BC30
 13  .text:0044BC30                 push    ebp
 14  .text:0044BC31                 mov     ebp, esp
 15  .text:0044BC33                 and     esp, 0FFFFFFF8h
 16  .text:0044BC36                 sub     esp, 14h
 17  .text:0044BC39                 push    ebx
 18  .text:0044BC3A                 push    esi
 19  .text:0044BC3B                 push    edi
 20  .text:0044BC3C                 push    14h             ; unsigned int
 21  .text:0044BC3E                 mov     ebx, eax        ; ebx指向ProductID首位置
 22  .text:0044BC40                 call    j_??2@YAPAXI@Z  ; operator new(uint)
 23  .text:0044BC45                 mov     esi, eax
 24  .text:0044BC47                 lea     eax, [esi+6]
 25  .text:0044BC4A                 push    eax
 26  .text:0044BC4B                 mov     eax, [ebp+SN]
 27  .text:0044BC4E                 lea     ecx, [esi+4]
 28  .text:0044BC51                 push    ecx
 29  .text:0044BC52                 lea     edx, [esi+2]
 30  .text:0044BC55                 push    edx
 31  .text:0044BC56                 push    esi             ; 新申请的14h的空间
 32  .text:0044BC57                 push    offset a4x4x4x4x ; "%4x-%4x-%4x-%4x"
 33  .text:0044BC5C                 push    eax             ; SN首地址
 34  .text:0044BC5D                 call    String2Integer  ; 将字符串SN转换为数组,比如
 35  .text:0044BC5D                                         ; “E6E9-24CB-2968-09BC”变为
 36  .text:0044BC5D                                         ; E9 E6 ...
 37  .text:0044BC62                 mov     ecx, [esi+4]    ; ECX为后半部分SN
 38  .text:0044BC65                 mov     edi, [esi]      ; EDI为前半部分SN
 39  .text:0044BC67                 push    esi             ; void *
 40  .text:0044BC68                 mov     [esp+40h+sn_lowerDWord], ecx
 41  .text:0044BC6C                 call    j__free
 42  .text:0044BC71                 lea     edx, [esp+40h+productId_segs_temp]
 43  .text:0044BC75                 push    edx
 44  .text:0044BC76                 push    offset a4x      ; "%4x"
 45  .text:0044BC7B                 push    ebx
 46  .text:0044BC7C                 call    String2Integer  ; 将ProductID第一段转换为Word
 47  .text:0044BC81                 mov     esi, [esp+4Ch+productId_segs_temp] ; esi储存productId_1
 48  .text:0044BC85                 lea     eax, [esp+4Ch+productId_segs_temp]
 49  .text:0044BC89                 push    eax
 50  .text:0044BC8A                 lea     ecx, [ebx+0Ah]
 51  .text:0044BC8D                 push    offset asc_48C804 ; "%x"
 52  .text:0044BC92                 push    ecx
 53  .text:0044BC93                 call    String2Integer
 54  .text:0044BC98                 mov     edx, [esp+58h+productId_segs_temp] ; EDX储存ProductId_2
 55  .text:0044BC9C                 add     esp, 38h
 56  .text:0044BC9F                 xor     eax, eax
 57  .text:0044BCA1                 push    eax
 58  .text:0044BCA2                 push    esi
 59  .text:0044BCA3                 push    eax
 60  .text:0044BCA4                 push    edx
 61  .text:0044BCA5                 call    __allmul
 62  .text:0044BCAA                 mov     esi, eax        ; product_1*product_2乘积的低word放入esi
 63  .text:0044BCAC                 lea     eax, [esp+20h+productId_segs_temp]
 64  .text:0044BCB0                 push    eax
 65  .text:0044BCB1                 lea     ecx, [ebx+14h]
 66  .text:0044BCB4                 push    offset asc_48C804 ; "%x"
 67  .text:0044BCB9                 push    ecx
 68  .text:0044BCBA                 mov     [esp+2Ch+new_ProdectID+4], edx
 69  .text:0044BCBE                 call    String2Integer
 70  .text:0044BCC3                 mov     edx, [esp+2Ch+new_ProdectID+4]
 71  .text:0044BCC7                 mov     eax, [esp+2Ch+productId_segs_temp] ; eax保存productId_3
 72  .text:0044BCCB                 add     esp, 0Ch
 73  .text:0044BCCE                 push    edx
 74  .text:0044BCCF                 push    esi
 75  .text:0044BCD0                 push    0
 76  .text:0044BCD2                 push    eax
 77  .text:0044BCD3                 call    __allmul
 78  .text:0044BCD8                 lea     ecx, [esp+20h+productId_segs_temp]
 79  .text:0044BCDC                 push    ecx
 80  .text:0044BCDD                 push    offset asc_48C804 ; "%x"
 81  .text:0044BCE2                 add     ebx, 1Eh
 82  .text:0044BCE5                 push    ebx
 83  .text:0044BCE6                 mov     esi, eax
 84  .text:0044BCE8                 mov     [esp+2Ch+new_ProdectID+4], edx
 85  .text:0044BCEC                 call    String2Integer
 86  .text:0044BCF1                 mov     edx, [esp+2Ch+new_ProdectID+4]
 87  .text:0044BCF5                 mov     eax, [esp+2Ch+productId_segs_temp]
 88  .text:0044BCF9                 add     esp, 0Ch
 89  .text:0044BCFC                 push    edx
 90  .text:0044BCFD                 push    esi
 91  .text:0044BCFE                 push    0
 92  .text:0044BD00                 push    eax
 93  .text:0044BD01                 call    __allmul        ; 结果edx高位,eax低位
 94  .text:0044BD06                 mov     esi, edx
 95  .text:0044BD08                 shr     esi, 10h
 96  .text:0044BD0B                 mov     [esp+20h+new_ProdectID], eax
 97  .text:0044BD0F                 mov     [esp+20h+new_ProdectID+4], edx
 98  .text:0044BD13                 xor     ebx, ebx
 99  .text:0044BD15                 mov     cl, 10h
100  .text:0044BD17                 call    __allshr        ; {edx,eax}==new_prodectID >> 10h
101  .text:0044BD1C                 mov     ecx, [esp+20h+new_ProdectID+4]
102  .text:0044BD20                 xor     edx, edx
103  .text:0044BD22                 push    1
104  .text:0044BD24                 and     eax, 0FFFF0000h
105  .text:0044BD29                 push    edx
106  .text:0044BD2A                 add     esi, eax
107  .text:0044BD2C                 adc     ebx, edx
108  .text:0044BD2E                 mov     edx, [esp+28h+new_ProdectID]
109  .text:0044BD32                 push    ecx
110  .text:0044BD33                 push    edx
111  .text:0044BD34                 call    __allmul        ; eax=0, edx为new_productID的低位
112  .text:0044BD39                 push    0
113  .text:0044BD3B                 add     esi, eax
114  .text:0044BD3D                 push    8475h
115  .text:0044BD42                 adc     ebx, edx
116  .text:0044BD44                 push    ebx
117  .text:0044BD45                 push    esi
118  .text:0044BD46                 call    __alldiv        ; {edx,eax} == {edx,esi} / 0x8475
119  .text:0044BD4B                 push    0
120  .text:0044BD4D                 push    0AE6000h
121  .text:0044BD52                 push    edx
122  .text:0044BD53                 push    eax
123  .text:0044BD54                 call    __allmul
124  .text:0044BD59                 add     eax, 91F2884Dh
125  .text:0044BD5E                 adc     edx, 2DCh
126  .text:0044BD64                 mov     cl, 0Ah
127  .text:0044BD66                 call    __allshr
128  .text:0044BD6B                 push    0
129  .text:0044BD6D                 push    2046h
130  .text:0044BD72                 push    edx
131  .text:0044BD73                 push    eax
132  .text:0044BD74                 call    __allmul
133  .text:0044BD79                 mov     ecx, 0FFFFFFFEh
134  .text:0044BD7E                 sub     ecx, eax
135  .text:0044BD80                 mov     eax, 0FFFFFFFFh
136  .text:0044BD85                 sbb     eax, edx
137  .text:0044BD87                 mov     edx, [esp+20h+sn_lowerDWord]
138  .text:0044BD8B                 shld    edx, edi, 1
139  .text:0044BD8F                 add     edi, edi
140  .text:0044BD91                 cmp     edi, ecx
141  .text:0044BD93                 jnz     short loc_44BDA5
142  .text:0044BD95                 cmp     edx, eax
143  .text:0044BD97                 jnz     short loc_44BDA5
144  .text:0044BD99                 mov     eax, 1
145  .text:0044BD9E                 pop     edi
146  .text:0044BD9F                 pop     esi
147  .text:0044BDA0                 pop     ebx
148  .text:0044BDA1                 mov     esp, ebp
149  .text:0044BDA3                 pop     ebp
150  .text:0044BDA4                 retn
151  .text:0044BDA5 ; ---------------------------------------------------------------------------
152  .text:0044BDA5
153  .text:0044BDA5 loc_44BDA5:                             ; CODE XREF: check_PID_SN+163j
154  .text:0044BDA5                                         ; check_PID_SN+167j
155  .text:0044BDA5                 pop     edi
156  .text:0044BDA6                 pop     esi
157  .text:0044BDA7                 xor     eax, eax
158  .text:0044BDA9                 pop     ebx
159  .text:0044BDAA                 mov     esp, ebp
160  .text:0044BDAC                 pop     ebp
161  .text:0044BDAD                 retn
162  .text:0044BDAD check_PID_SN    endp

 

基本思路

  通过分析,我了解到,其算法大概思路如下:首先,注册流程有效输入为Serial Number和Product ID,Registration No实际上没有参与注册的验证计算过程。SRS通过系统各种信息生成Product ID,然后用户需要提供与Product ID匹配的Serial Number方能注册。当然,Serial Number是需要你拿美刀换的。

  简而言之,SRS将Product ID作fp变换,得到一个64bit长的整数,并将用户输入的序列号做fs变换同样得到一个64bit长整数。为了使注册成功,需要满足:

fp(gen()) = fs(SerialNumber) 成立      (1)

  这其中,gen()的算法我们不需要管,因为其结果在界面Product ID框中已经显示了。我们需要找到fp和fs的实现算法,并顺利推出fs-1的实现。从而:

 SerialNumber = fs-1( fp(ProductID) )   (2)

Product ID变换算法描述

  我们首先描述fp的实现。fp基本上是由我不知道原理的各种数值变换组成,为了精确表述,我直接用C语言描述:

Product ID变换函数描述
 1 __int64 getProductID(char* id){
 2     __int64 temp = 1;
 3     DWORD elem;
 4 
 5     for(int i = 0; i < 4; i++){
 6         sscanf(id + (i * 5), "%x", &elem);
 7         temp *= elem;
 8     }
 9 
10     //高地位变换
11     DWORD lowerDWord = temp; 
12     DWORD upperDWord = temp >> 0x20;
13     WORD lower = upperDWord;
14     WORD upper = upperDWord >> 0x10;
15     upperDWord = lower;
16     upperDWord <<= 0x10;
17     upperDWord |= upper;
18     
19     temp = lowerDWord;
20     temp <<= 0x20;
21     temp |= upperDWord;
22     
23 
24     temp /= 0x8475;
25     temp *= 0xAE6000;
26     temp += 0x2DC91F2884D;
27     temp >>= 0xA;
28     temp *= 0x2046;
29     temp = 0xfffffffffffffffe - temp;
30 
31     return temp;
32 }

 

Serial Number变换算法描述  

  接下来描述fs函数的实现。我们称变换后的Product ID为TransPID,并且LowerDW和HighDW表示一个64bit整数的低双字和高双字,shld表示对应汇编指令的函数,TransSerialNumberHighDW和TransSerialNumberLowDW分别表示变换后的序列号高双字和低双字。则有:

  TransSerialNumberHighDW(SerialNumber) = shld(UpperDW(SerialNumber), LowerDW(SerialNumber), 1);   (3)

  TransSerialNumberLowDW(SerialNumber) = LowerDW(SerialNumber) + LowerDW(SerialNumber);      (4)

  fs(SerialNumber) =   TransSerialNumberHighDW<< 32 | TransSerialNumberLowDW;            (5)

 

Serial Number逆向变换算法描述

  了解了fs的实现,我们接下来需要着手研究实现fs-1的思路。由于fs高双字和低双字分别由不同的方式变换的(3)、(4),所以我们需要分别求出SerialNumber的高低双字。得到Serial Number的低双字很简单,由(4)可知,我们只要将LowerDW(fp(ProductID))除以2就行。但需注意的是,整个双字值域中,LowerDW(fp(ProductID)) / 2 + (2<<31)同样能满足条件(由于溢出导致的相等),这点很重要!

  再来考虑高位的算法。我们需要把HighDW(fp(ProductID))往右移一位,这是左边补入的一位可以任意。这时需要注意,考虑到shld性质,有以下两种情况:

①如果HighDW(fp(ProductID))最低位是1则需要LowerDW(SerialNumber)的最高位为1

②如果HighDW(fp(ProductID))最低位是0则需要LowerDW(SerialNumber)的最高位为0

  考虑到LowerDW(fp(ProductID)) / 2和LowerDW(fp(ProductID)) / 2 + (2<<31)均可满足条件,若是情况①则选取后者,因为此时可保证LowerDW(SerialNumber)的最高位为1。同理,若是情况②则需选择前者。

  该算法的C语言描述如下:

SerialNumber逆变换算法
 1 void getSerialNumber(__int64 productId, char* buffer){
 2     DWORD upper = productId >> 0x20;
 3     DWORD lower = productId;
 4     assert((lower & 1) == 0); //lower = snLower + snLower因此lower必须为偶数
 5 
 6 
 7 
 8     DWORD snUpper = upper >> 1;
 9 
10     DWORD snLower =0;
11     if((upper & 1) == 1){
12         snLower = lower / 2;
13         snLower += (1<<31);
14     }else{
15         snLower = lower / 2;
16     }
17 
18     DWORDLONG sn = snUpper;
19     sn <<= 0x20;
20     sn |= snLower;
21 
22     WORD *p = (WORD*)&sn;
23     sprintf(buffer, "%04x-%04x-%04x-%04x", p[0], p[1], p[2], p[3]);
24 }

 

小结

  IDA很强大,Crack很费时间,收获的免费SRS使用权和投入的大量时间不成正比。结论:以后还是尽量少搞Crack吧。

 

posted on 2012-06-22 22:37  死亡的飞翔  阅读(2132)  评论(6编辑  收藏  举报

导航