这里po jie的是当前最新版本Source Insight 4.0.118,总结po jie过程有以下三个部分:
除此之外,笔者也看到其他人的一些文章,提到有黑名单检查,因为没遇到这个逻辑,程序暂时也能用,所以这里的破解中没有涉及,后面如果遇到再研究也不迟。
文中用到的所有代码可点击右侧超链接,在 Github上查看
IDA6.8、x32dbg
官网 下载sourceinsight40118-setup.exe,也可使用文后附件
这部分内容讲述简单po jie程序的方法,因为本文主要是研究自签名license并替换程序中公钥的po jie方法,比较麻烦,纯粹是为了学习目的。如果对这种方法不感兴趣,这部分内容就提供另一种简单的po jie方法:修改 sourceinsight4.exe 二进制文件中的两个字节完成po jie
这部分内容分4个小节:
1.1 节 讲述如何定位到验证序列号的代码
1.2 节 中逆向还原验证序列号格式的函数,并按照格式构造出正式版序列号
1.3 节 中逆向还原本地校验序列号的函数,构造出可通过本地校验的序列号
1.4 节 本地验证序列号成功后,在线验证序列号失败,从而引出 第 2 节 的分析
安装程序后,打开sourceinsight4.exe程序会看到选择license文件的界面,如下图:
选择第一项“输入serial number”,点击“Next >”继续,显示输入Serial Number的对话框,并且提示 Serial Number 的格式“S4XX-XXXX-XXXX-XXXX”。按照格式输入一个,点击"Next>",会弹出“无效的Serial Number”警告,如下图:
在IDA中搜索弹窗警告中的文本“The serial number …”,找到引用此字符串的地址是 .text:00513A69。
分析*.text:00513A69*此位置上下文代码,可以看出 .text:00513A45 call sub_510B50 是Serial Number的验证函数,若验证失败(返回结果0),则会再判断是否是3.x版本的Serail Number,不是则弹出上图中的警告;若验证成功则跳转到 loc_513ACB 继续判断验证结果。代码如下所示:
.text:00513A25 mov eax, dword_673488
.text:00513A2A push 1 ; int
.text:00513A2C lea ecx, [eax+604h]
.text:00513A32 push ecx ; int
.text:00513A33 lea edx, [eax+60Ch]
.text:00513A39 push edx ; int
.text:00513A3A add eax, 608h
.text:00513A3F push eax ; int
.text:00513A40 lea eax, [esp+158h+MultiByteStr]
.text:00513A44 push eax ; char *
.text:00513A45 call sub_510B50 ; 验证Serial Number是否正确
.text:00513A4A add esp, 34h
.text:00513A4D test eax, eax ; eax = 0, 弹出错误窗口并返回
.text:00513A4D ; eax!= 0, 继续验证Serial Number格式
.text:00513A4F jnz short loc_513ACB
.text:00513A51 lea ecx, [esp+128h+MultiByteStr]
.text:00513A55 push ecx
.text:00513A56 call sub_561CB0
.text:00513A5B add esp, 4
.text:00513A5E test eax, eax
.text:00513A60 jz short loc_513A69
.text:00513A62 push offset aTheSerialNumbe ; "The serial number you entered is for ve"...
.text:00513A67 jmp short loc_513A6E
.text:00513A69 ; ---------------------------------------------------------------------------
.text:00513A69
.text:00513A69 loc_513A69: ; CODE XREF: sub_5139C0+A0j
.text:00513A69 push offset aTheSerialNum_0 ; "The serial number you entered is not co"...
.text:00513A6E
.text:00513A6E loc_513A6E: ; CODE XREF: sub_5139C0+A7j
.text:00513A6E call sub_40AC20
.text:00513A73 add esp, 4
... ...
.text:00513ACA retn
.text:00513ACB ; ---------------------------------------------------------------------------
.text:00513ACB
.text:00513ACB loc_513ACB: ; CODE XREF: sub_5139C0+8Fj
... ...
.text:00513AE1 cmp [eax+604h], edx
.text:00513AE7 jz short loc_513B0D
.text:00513AE9 push offset aTheSerialNum_1 ; "The serial number you entered is for a "...
.text:00513AEE call sub_40AC20
... ...
.text:00513B0C retn
详细分析上面步骤中提到的 sub_510B50 处的序列号验证函数,总结出Serial Number的验证规则如下:
SerailNumber字符串长度必须为19(16个字符加上3个分隔符)
SerailNumber[0]必须等’S’
SerailNumber[1]是’0’-‘9’
SerailNumber[2]等于’T’表示Trial license试用许可,等于’B’表示Beta license测试许可,等于’S’表示Standard license标准许可,等于’U’表示Upgrade license升级许可
SerailNumber[3]等于 ‘G’、‘V’、‘R’ 其中之一
SerailNumber[6]等于 ‘R’、‘G’、‘D’、‘F’ 其中之一
SerialNumber的前12个字符经过函数 .text:00510C6B call sub_510320 转换后得到4个字符,与SerialNumber的最后4个字符必须相同
代码如下所示:
.text:00510B50 ; int __cdecl sub_510B50(char *, int, int, int, int)
.text:00510B50 sub_510B50 proc near ; CODE XREF: .text:005129C4p
.text:00510B50 ; sub_5139C0+85p
.text:00510B50
.text:00510B50 ary4char = dword ptr -18h
.text:00510B50 szSNTemp = byte ptr -14h
.text:00510B50 ptr_szSN = dword ptr 4
.text:00510B50
.text:00510B50 ptr_nSN[3]Flag = dword ptr 8
.text:00510B50 ptr_nLicTypeFlag= dword ptr 0Ch
.text:00510B50 ptr_nVersionFlag= dword ptr 10h
.text:00510B50 arg_10 = dword ptr 14h
.text:00510B50
.text:00510B50 sub esp, 18h
.text:00510B53 push esi
.text:00510B54 mov esi, [esp+1Ch+ptr_szSN]
.text:00510B58 push esi ; char *
.text:00510B59 call __strupr
.text:00510B5E push esi ; char *
.text:00510B5F call _strlen
.text:00510B64 add esp, 8
.text:00510B67 cmp eax, 13h ; strlen(ptr_szSN) == 13h
.text:00510B6A jnz loc_510C86
.text:00510B70 mov al, '-'
.text:00510B72 cmp [esi+4], al ; ptr_szSN[4] = '-'
.text:00510B75 jnz loc_510C86
.text:00510B7B cmp [esi+9], al ; ptr_szSN[9] = '-'
.text:00510B7E jnz loc_510C86
.text:00510B84 cmp [esi+0Eh], al ; ptr_szSN[14] = '-'
.text:00510B87 jnz loc_510C86
.text:00510B8D cmp byte ptr [esi], 'S' ; ptr_szSN[0] = 'S'
.text:00510B90 jnz loc_510C86
.text:00510B96 mov ecx, [esp+1Ch+arg_10]
.text:00510B9A test ecx, ecx
.text:00510B9C jz short loc_510BB5
.text:00510B9E mov al, [esi+6]
.text:00510BA1 cmp al, 'R' ; ptr_szSN[6] == 'R'
.text:00510BA3 jz short loc_510BB5
.text:00510BA5 cmp al, 'G' ; ptr_szSN[6] == 'G'
.text:00510BA7 jz short loc_510BB5
.text:00510BA9 cmp al, 'D' ; ptr_szSN[6] == 'D'
.text:00510BAB jz short loc_510BB5
.text:00510BAD cmp al, 'F' ;