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吧。

 

你可能感兴趣的:(SAN)