本帖最后由 lakshmi 于 2018-3-20 08:33 编辑
0x1 写在前面
由于最近准备向各位大牛们看齐,学习学习Linux源码,需要用到source insight ,因此就在网上找破解版的si,这个帖子已经给出了破解版 https://www.52pojie.cn/thread-580580-1-1.html
但是需要修改二进制文件,作为一个怀疑整个世界的渣,写了这么一篇帖子(不过最后本渣也还是修改了二进制文件),仅供学习交流!!!
准备环境:
Windows 7 32 bit
百度上Source Insight 4.0 (Version 4.00.0086 built on 2017-04-27) (官网最新版是 4.00.0089),查看了一下破解过程相同
IDA 7.0
52破解专版OllDbg
UltraEdit32
0x2 破解过程
首先,查看PE文件,发现没有加壳,运行起来,提示需要输入注册码,如下图所示:
点击下一步,然后随意输入注册码,点击确定,如下提示:
有提示,那就按套路出牌, 用IDA打开文件,C:\Program Files\Source Insight 4.0\sourceinsight4.exe,搜索字符串:
[C++] 纯文本查看 复制代码 int __cdecl register_function(int a1, int a2, int a3)
{
。。。。。。。。。。。。。。。。
if ( !check_register(&str_input, dword_1361930 + 0x608, dword_1361930 + 0x60C, dword_1361930 + 0x604, 1) ) {
Error_SerialNumber(
"The serial number you entered is not correct.\n\nPlease check the number and re-enter it.",
v11,
v12,
*(int *)v13,
v14,
v15,
v16,
v17,
v18);
sub_1106A20(a1, 30);
sub_1104660();
if ( ++dword_13619CC >= sub_114D9A0(1) + 3 )
{
dword_13619CC = 0;
sub_114C530();
Sleep(0x1B58u);
sub_114C580();
return 0;
}
return 0;
}
dword_13619CC = 0;
if ( *(_DWORD *)(dword_1361930 + 0x604) != HIBYTE(dword_13446B0) )
{
Error_SerialNumber(
"The serial number you entered is for a different version of Source Insight.\n"
"\n"
"This version requires a version 4.x serial number.",
v11,
v12,
*(int *)v13,
v14,
v15,
v16,
v17,
v18);
sub_1106A20(a1, 30);
sub_1104660();
return 0;
}
if ( *(_DWORD *)(dword_1361930 + 0x60C) == 3 )
{
Error_SerialNumber(
"The serial number cannot be used with the 'release' version of Source Insight.",
v11,
v12,
*(int *)v13,
v14,
v15,
v16,
v17,
v18);
sub_1104660();
return 0;
}
if ( !sub_120AF10(&str_input) )
return 0;
if ( sub_120C670(dword_1361930 + 0x504) )
{
sub_11122A0("Upgrade License was validated: %s", dword_1361930 + 1284, v11, v12, *(int *)v13, v14, v15, v16, v17);
}
else
{
Error_SerialNumber(
"Sorry, but we could not validate your previous license. Please make sure you have the correct serial number for ve"
"rsion 3.x.\n"
"\n"
"If your old version of Source Insight is running, you can see the serial number by selecting Help > About Source I"
"nsight. Otherwise, the serial number was typically provided in an email activation message when you purchased the old license.",
v11,
v12,
*(int *)v13,
v14,
v15,
v16,
v17,
v18);
sub_1106A20(a1, 30);
sub_1104660();
sub_11121C0("Upgrade License could not be validated", v4, v5, v6, v7, v12, *(int *)v13, v14, v15);
}
return 0;
}
只有当 check_register(&str_input, dword_1361930 + 0x608, dword_1361930 + 0x60C, dword_1361930 + 0x604, 1) 返回值非0时表示验证成功, 接着查看这个该函数:
[C++] 纯文本查看 复制代码 BOOL __cdecl check_register(char *sn, int a2, int a3, int a4, int one)
{
BOOL result; // eax
char v6; // al
char v7; // al
char v8; // al
char v9; // al
int v10; // [esp+4h] [ebp-18h]
char v11; // [esp+8h] [ebp-14h]
char v12; // [esp+17h] [ebp-5h] _strupr(sn);
if ( strlen(sn) != 0x13 || sn[4] != '-' || sn[9] != '-' || sn[0xE] != '-' || *sn != 'S' )// format: SXXX-XXX-XXXX-XXXX
return 0;
if ( one )
{
v6 = sn[6];
if ( v6 != 'R' && v6 != 'G' && v6 != 'D' && v6 != 'F' )// SXXX-X(R|G|D|F)XX-XXXX-XXXX
return 0;
}
v7 = sn[1];
if ( v7 < '0' || v7 > '9' ) // S(0-9)XX-X(R|G|D|F)XX-XXXX-XXXX
return 0;
*(_DWORD *)a4 = v7 - '0';
v8 = sn[2];
switch ( v8 ) // S(0-9)(T|B|S|U)X-X(R|G|D|F)XX-XXXX-XXXX
{
case 'T':
*(_DWORD *)a3 = 1;
break;
case 'B':
*(_DWORD *)a3 = 3;
break;
case 'S':
*(_DWORD *)a3 = 0;
break;
case 'U':
*(_DWORD *)a3 = 0;
break;
default:
return 0;
}
v9 = sn[3];
if ( v9 != 'G' )
{
if ( v9 == 'V' )
{
*(_DWORD *)a2 = 2;
goto LABEL_28;
}
if ( v9 == 'R' )
{
*(_DWORD *)a2 = 0;
goto LABEL_28;
}
return 0;
}
*(_DWORD *)a2 = 1;
LABEL_28:
result = 0;
if ( !split_key_compute_function(sn + 5, 4u, 0)// split_key_compute_function(XX, 4u, 0) == 0
&& !split_key_compute_function(sn + 10, 4u, 0)
&& !split_key_compute_function(sn + 0xF, 4u, 0) )
{
if ( !one
|| (strcpy(&v11, sn),
v12 = 0,
compute_last_four_byte(&v11, 0xFu, (int)byte_12F4A48, (int)&v10),
*(_DWORD *)(sn + 0xF) == v10) )
{
result = 1;
}
}
return result;
}
简单介绍上边的函数,首先是判断序列号的合法性,必须满足如下格式(其中X表示未知字符):
S(0-9)(T|B|S|U)X-X(R|G|D|F)XX-XXXX-XXXX
其中第二位,根据版本要求必须是4,第三位中T 表示 试用版,B表示Beta版,S表示Standard版,U未知。因此按照本软件的要求,序列号格式应该如下:
S4SX-X(R|G|D|F)XX-XXXX-XXXX
接着通过split_key_compute_function对序列号中按“-”分开的四位分别验证,其返回值必须是0,这个函数很好绕过,只要满足这4个字节中的第一个字节是字符即可满足(没什么作用 ),因此在最新版中已经将这块给省掉了。
接着是
[C++] 纯文本查看 复制代码 compute_last_four_byte(&v11, 0xFu, (int)byte_12F4A48, (int)&v10),
*(_DWORD *)(sn + 0xF) == v10) )
compute_last_four_byte函数的作用是利用替换查表的方法,将sn中的前15个字节计算出一个四字节的数,这个四字节的数就是sn的最后4字节,具体代码如下:
[C++] 纯文本查看 复制代码 BYTE char_table[26] = { 'K', 'V', '9', '6', 'G', 'M', 'J', 'Y', 'H', '7', 'Q', 'F', '5', 'T', 'C', 'W', '4', 'U', '3', 'X', 'Z', 'P', 'R', 'S', 'D', 'N'};
BYTE byte_table[256] = {
0x23, 0xDD, 0x78, 0xB5, 0x33, 0x6F, 0xD4, 0xF9, 0xA6, 0xE8, 0xCC, 0x7C, 0x9F, 0xB3, 0x22, 0xDA,
0x32, 0xDF, 0x71, 0xB7, 0x61, 0x3D, 0x6B, 0x57, 0xD7, 0xA1, 0x34, 0x38, 0xF2, 0xE1, 0xF3, 0xB8,
0x1A, 0x80, 0xF5, 0xFE, 0x91, 0x01, 0x3C, 0x73, 0x93, 0x48, 0xA0, 0xE0, 0x94, 0xAA, 0x39, 0x8F,
0x58, 0xE2, 0x31, 0x0B, 0xBB, 0xCE, 0x4C, 0xD2, 0x56, 0xC2, 0x5E, 0x27, 0xB6, 0xFB, 0x65, 0xAE,
0x55, 0x60, 0xBD, 0x10, 0x86, 0xF7, 0xC1, 0x88, 0x12, 0xED, 0x67, 0xC4, 0x74, 0x30, 0x1B, 0xBC,
0x9A, 0xB0, 0xEF, 0x36, 0xC5, 0x72, 0x5B, 0x7E, 0x54, 0x2C, 0x0F, 0xF6, 0xA9, 0x85, 0x2A, 0xB1,
0x37, 0xF1, 0x2F, 0x4E, 0xE7, 0x6A, 0x75, 0xA8, 0x26, 0xEB, 0x3F, 0x6C, 0x69, 0x20, 0x87, 0x62,
0x8D, 0x68, 0xA5, 0xFA, 0x3A, 0x04, 0x21, 0x1F, 0xAC, 0x05, 0xA4, 0x76, 0x11, 0x70, 0x9E, 0x46,
0x24, 0x5D, 0xC6, 0xE4, 0x95, 0x82, 0x1C, 0xBA, 0x59, 0x09, 0xD9, 0x44, 0x98, 0x92, 0x07, 0xAF,
0xA7, 0x41, 0x96, 0x90, 0xB4, 0x42, 0x63, 0x99, 0xD0, 0x4D, 0x97, 0xBE, 0x40, 0xCF, 0x84, 0xE5,
0x1D, 0x5A, 0x0C, 0x7F, 0xC7, 0xEA, 0xEE, 0xEC, 0x00, 0xD5, 0x49, 0x2D, 0x51, 0xAD, 0xB9, 0x89,
0x77, 0x52, 0x3E, 0x8C, 0xE6, 0xFF, 0x15, 0xDE, 0x6D, 0x14, 0xA2, 0xCD, 0xA3, 0xD6, 0x17, 0x81,
0xC8, 0x45, 0x4B, 0x35, 0x0A, 0x0D, 0xFC, 0x9D, 0x16, 0x3B, 0xD3, 0x7D, 0xD1, 0xF4, 0xFD, 0xCA,
0x25, 0x06, 0x6E, 0xF8, 0x5F, 0xBF, 0x8A, 0x7B, 0x50, 0xD8, 0x79, 0x9C, 0xAB, 0x43, 0x53, 0xCB,
0x8E, 0x4F, 0xE3, 0xC9, 0x8B, 0xDC, 0x5C, 0xC0, 0x1E, 0x9B, 0x18, 0x02, 0x47, 0x03, 0x2B, 0x0E,
0x66, 0x4A, 0xB2, 0xF0, 0xE9, 0x19, 0x29, 0x7A, 0xC3, 0x08, 0x83, 0xDB, 0x64, 0x13, 0x2E, 0x28 };
int compute_last_four_byte(BYTE *keystr,DWORD key_length, int table, int retvalue)
{
unsigned int value_index; // esi
BYTE v5; // cl
unsigned int iIndex; // eax
int result; // eax
value_index = 0;
do
{
v5 = *(BYTE *)((BYTE)(value_index + *keystr) + table);
for (iIndex = 1; iIndex< key_length; ++iIndex)
v5 = *(BYTE *)((v5 ^ (char)keystr[iIndex]) + table);
result = retvalue;
*(BYTE *)(++value_index + retvalue - 1) = char_table[v5 % 26];
} while (value_index < 4);
return result;
}
既然后四字节可以算出来,那么此处的破解思路就是,按照格式S4SX-X(R|G|D|F)XX-XXXX-XXXX要求,固定前如下字节 S4SV-UFWT-ZPRX-,那么通过穷举X(此处为了缩小范围,直接遍历char_table中的字符即可),来计算出最后四个字节,在选出满足要求的序列号即可,代码如下:
[C++] 纯文本查看 复制代码 int _tmain(int argc, _TCHAR* argv[])
{
int res;
CHAR serial_number[0x1f] = { 'S', '4', 'S', 'V', '-', 'U', 'F', 'W', 'T', '-', 'Z', 'P', 'R', 0x0, '-', 0x0, 0x0, 0x0, 0x0, 0x0 };
for (DWORD dwIndex = 0; dwIndex < 26; dwIndex++)
{
serial_number[13] = char_table[dwIndex];
compute_last_four_byte((BYTE *)serial_number, 0xf, (int)byte_table, (int)&res);
memcpy(serial_number + 0xf, (BYTE *)&res, 4);
if (serial_number[0xf] >= 0x41)
printf("%s\n", serial_number);
}
}
结果如下:
任选一组,调试发现成功绕过,但是此处还是没有完全破解成功,因为,source insight 需要一个license文件,文件保存在C:\programdata\source insigth\4.0\si4.lic中,格式如下(根据试用版获取到):
[XML] 纯文本查看 复制代码 <!--
Source Insight 4.x License File
DO NOT EDIT THIS FILE. Doing so will render it unusable.
This license was created for:
lakshmi
52pojie
[url=mailto:XXX@XX.com]XXX@XX.com[/url]
-->
<SourceInsightLicense>
<Header
Value="1"
/>
<LicenseProperties
LicensedUser="lakshmi"
ActId="9980973922"
HWID="XXXXXXXXX"
Serial="S4SV-UFWT-ZPR6-F336"
Organization="52pojie"
Email="XXX@XX.com"
Type="Standard"
Version="4"
MinorVersion="0"
Date="2018-03-12 00:00:00"
Expiration="2028-09-12 00:00:00"
/>
<Signature
Value="az2bGw1ks1ftqXzf/tVrq071RbJqclxWljohEAcOwvx3pimSMZa/isSdpIRM5vXsTt/ZVeD62r8SlzvNlt/5C6XzPTMKvik+fzOakeM8zQNSCmJ/W1MQ9WgXZyiQpp3VnZgkrO3Ut/YHRWCe4zPJjcPJZ7tXf62Lvxx5MO29uEqHCvc8ZHUGg0wafuYooRoeUWzLneTisGDnfAy3UTaH3oxdqwlMFbDa10sVEEbW2WTzZFxL826r4lAGmH9MUCiu/3R/tpvrYlyWRv+29kQoqGlkwQUV4B1iL6Dyp5bC17JSYpChsjdm9JkoEg6HRsA3WtdQBRecA65Jyhr8XbMPFg=="
/>
</SourceInsightLicense>
source insight 会根据自带公钥,对license文件中的 除了Signature中的数据进行签名,并与变换后的Signature值进行比较,具体怎么变换没有去跟踪,反正臣妾都破不了签名,最后还是手贱地选择了修改二进制文件
[C++] 纯文本查看 复制代码 int __cdecl sub_50B440(BYTE *pbData, DWORD dwDataLen, BYTE *pbSignature, DWORD dwSigLen)
{
BOOL v5; // esi
HCRYPTHASH phHash; // [esp+0h] [ebp-818h]
HCRYPTPROV phProv; // [esp+4h] [ebp-814h]
struct _CERT_PUBLIC_KEY_INFO *pvStructInfo; // [esp+8h] [ebp-810h]
HCRYPTKEY phKey; // [esp+Ch] [ebp-80Ch]
DWORD pcbBinary; // [esp+10h] [ebp-808h]
DWORD pcbStructInfo; // [esp+14h] [ebp-804h]
BYTE pbBinary; // [esp+18h] [ebp-800h]
phHash = 0;
phKey = 0;
pcbBinary = 2048;
phProv = 0;
if ( !CryptStringToBinaryA(pszString, 0, 0, &pbBinary, &pcbBinary, 0, 0)
|| !CryptDecodeObjectEx(1u, (LPCSTR)8, &pbBinary, pcbBinary, 0x8000u, 0, &pvStructInfo, &pcbStructInfo) )
{
return 472;
}
if ( !CryptAcquireContextW(&phProv, 0, 0, 1u, 0xF0000000) )
return 473;
if ( !CryptImportPublicKeyInfo(phProv, 1u, pvStructInfo, &phKey) )
return 474;
LocalFree(pvStructInfo);
if ( !CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash) )
return 474;
if ( !CryptHashData(phHash, pbData, dwDataLen, 0) )
return 475;
v5 = CryptVerifySignatureW(phHash, pbSignature, dwSigLen, phKey, 0, 0);
CryptDestroyHash(phHash);
CryptReleaseContext(phProv, 0);
return v5 != 0 ? 0xC8 : 0x1CE;
}
让函数最终直接返回0xC8即可
最终效果如下:
|