Welcome My Friend

Source Insight4093

SourceInsight4093:

​ SourceInsight是比较强大的软件,如果觉得这个软件有用,请购买正版,发布这个纯属娱乐。

关于SourceInsight

​ Source Insight不仅是一个强大的程序编辑器,而且是面向项目开发的程序编辑器和代码浏览器,它拥有内置的对C/C++, C#和Java等程序的分析。能分析源代码并在工作的同时动态维护它自己的符号数据库,并自动显示有用的上下文信息。运行截图如下图所示:

SourceInsight

##过程

​ 先使用查壳工具PEID查壳,然后通过试运行sourceinsight查看会提示什么,然后决定使用什么方法来破解,一般来讲,输入注册码不正确跳出提示框,这样可以通过查找字符串进而找到关键算法,通过下面尝试,这样方法确实可行,但是并不能完全破解,只能绕过一个判断。商业软件毕竟是别的软件不一样的,sourceinsight有在线检查黑名单制度,而且相较于之前版本,黑名单检测地方在不断增多,找到黑名单检测处并且一一注释才能够最终完成破解。

###1.查壳

​ 先用PEID查壳,发现没有加壳,但是入口地址和偏移与之后在IDA里面看到的不一样,这是win7下的ASLR技术,ASLR技术是对缓冲区溢出的安全保护技术,对堆栈、共享库等映射随机化,这样提高安全,但是不利于我们分析,IDA动态调试的时候不能返回,相对OD显得不那么方便,但是IDA反汇编出来的地址就是没有随机化的地址,是最原始程序的地址,而OD是随机化的,所以通过参考IDA,并且尝试关闭win7下的ASLR服务,这样就可以使用OD进行动态调试,使用IDA反汇编查看源码,这样可以快随方便的找到关键判断,加速破解进度。下图为查壳结果:无壳

SourceInsight

###2.关闭ASLR

​ 如果想使用OD动态调试,那么必须要关闭ASLR服务,因为每次调试的断点,注释会随着动态地址变化而消逝,所以必须要关闭ASLR服务。下图为没关闭ASLR服务之前的OD加载地址与IDA加载地址效果图:可以明显看到OD的地址漂移。

SourceInsight

SourceInsight

​ 网上下载ASLR关闭工具进行关闭是不行的,后来Google上找到一篇帖子,介绍了方法,通过win+R,regedit,HKEY_LOCAL_MACHINE->SYSTEM->CurrentControlSet->Control->Session
Manager->Memory Management,右键,新建一个dword变量,命名为MoveImages,将其值置为0,重启电脑即可。如下图为修改注册表中的数值:

SourceInsight

​ 关闭ASLR后效果如下图,这样可以通过IDA找到关键处,OD动态调试辅助进行破解。

SourceInsight

###3.运行程序寻找突破口

​ 下图为未破解之前截图:

SourceInsight

SourceInsight

​ 第一个选项是导入注册码,第二选项是试用30天,第三个选项是导入license,如果不选的话,会直接退出程序。尝试输入错误的注册码看会提示是什么,

SourceInsight

​ 跳出一串字符如上图,然后通过IDA查找字符串,Shift+F12打开字符串界面,按下ctrl+f,然后输入上面提及的字符中not correct,搜索结果如下图:

SourceInsight

​ 第二条记录是刚刚输入不正确注册码跳出的界面的提示,双击进入,下图所示,可以看到,字符串和上面输入错的字符跳出来的提示语是一样的。可以看到第一句The serial number you entered is not correct. A serial number for下面有DATA XREF,后面跟了一个函数,鼠标放在上面会出现函数入口指令,双击进入

SourceInsight

​ 下图所示,双击进入的地方,这个地址就是这串字符压入栈的地方:

SourceInsight

​ IDA最强大的一面就是反汇编,接下来就是体现其强大的一面,按F5会将这段汇编指令尽量按照源码反汇编出来,按下F5以后效果如下图所示:

SourceInsight

SourceInsight

​ 可以看到上面的一个关键if判断,满足条件,就会进入到下一个if判断,两个if都满足的话,说明这个序列号是3.x版本的,第二个if如果不满足,则会进入else,见下图:

SourceInsight

​ 可以明显看到,第67行,第二个if判断没有成立进入到这里就会显示上面提到的注册不成功的提示,而sub_40A8E0这个函数就是实现显示提示的功能,IDA查看sub_40A8E0这个函数非常方便,双击这个函数就会自动跳到这个函数,如下图,想要再回到之前的函数,点击左上角返回键即可。

SourceInsight

​ 上面代码可以看到是输出一串字符的,结合上面截图中的代码分析,传入的参数a1是序列号错误的提示字符串,代码中有调用其他的函数,就不一一展开说明。

​ 回到上上图中的代码中,只要代码不进入if判断,把显示提示序列号错误的字符跳过,那么很可能找到判断序列号是否正确的关键判断。(注:上上图中代码还有一部分没有截图展示出来,都是和这个if平行的判断,跳过了这个if,可以进入到下面的判断,下面判断中用到了替换查表的方法判断,表是代码中原有存在的,查看代码可以看文章末尾附录)

​ 通过上面的分析,关键call就是sub_50C8E0(&MultiByteStr,dword_66BAE8 + 1544, dword_66BAE8 + 1548, dword_66BAE8 + 1540, 1)这个函数,双击这个函数进入函数主体,下图可以看到函数中所有的代码:

SourceInsight

SourceInsight

​ 接下来分析这段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
int __cdecl sub_50C8E0(char *a1, int a2, int a3, int a4, int a5)//a1为输入的序列号,如果任一判断不成立return 0,那么之前的判断会直接跳到序列号失败的那个call
{
char v5; // al@7
char v6; // al@11
char v7; // al@13
char v8; // al@21
int v10; // [sp+4h] [bp-18h]@28
char v11; // [sp+8h] [bp-14h]@28
char v12; // [sp+17h] [bp-5h]@28

_strupr(a1);
if ( strlen(a1) != 19 )//看输入的序列号是否总共为19位,形式是xxxx-xxxx-xxxx-xxxx总共19位
return 0;
if ( a1[4] != 45 )//看第五位是不是字串’-’,也就是判断格式
return 0;
if ( a1[9] != 45 ) //看第十位是不是字串’-’,也就是判断格式
return 0;
if ( a1[14] != 45 ) //看第十五位是不是字串’-’,也就是判断格式,上面三个if判断
return 0;
if ( *a1 != 83 )//第一位字母不是‘‘S’’的话,return 0
return 0;
if ( a5 )//函数传参进来,值应该是1
{
v5 = a1[6];//将序列号的第7位给到变量
if ( v5 != 82 && v5 != 71 && v5 != 68 && v5 != 70 )//第7位如果不是‘R’,‘G’,‘D’,‘F’,其中的一个,那么就返回0,也就是第7位这里只能是‘R’,‘G’,‘D’,‘F’,其中的一位
return 0;
}
v6 = a1[1];//把序列号的第2位给到变量
if ( v6 < 48 || v6 > 57 )//如果第2位不是数字则直接return 0
return 0;
*(_DWORD *)a4 = v6 - 48;//第二位的十进制数给到变量a4
v7 = a1[2];//序列号的第三位给到变量
switch ( v7 )
{
case 84:
*(_DWORD *)a3 = 1;
break;
case 66:
*(_DWORD *)a3 = 3;
break;
case 83:
*(_DWORD *)a3 = 0;
break;
default:
if ( v7 != 85 )
return 0;
*(_DWORD *)a3 = 0;
break;
}//第三位的值很关键,得是B,S,T,U其中的几位
v8 = a1[3];//第四位给到变量,如果第四位是G,a2=1,如果是V,a2=2,如果不等于GV且不等于R,那么返回0
if ( v8 == 71 )
{
*(_DWORD *)a2 = 1;
}
else if ( v8 == 86 )
{
*(_DWORD *)a2 = 2;
}
else
{
if ( v8 != 82 )
return 0;
*(_DWORD *)a2 = 0;
}
if ( !a5 )//如果a5=0的话,那么直接返回1
return 1;
strcpy(&v11, a1);,//把a1给到v11
v12 = 0;
sub_50C0B0(&v11, 15, &unk_5F6F88, &v10);//可以看到第二个参数为15,这里其实传进去的是前15位,然后来算后4位,而这个算法就是非常关键的算法
if ( *(_DWORD *)(a1 + 15) == v10 )
return 1;
return 0;
}

​ 总结以上代码,首先是判断序列号的合法性,必须满足如下格式(其中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

SourceInsight

​ 可以看到是do-while循环四次来做的,而当中最关键的是byte_5F6E68[]这个预先存于内存中的表取值,双击byte_5F6E68[],可以看到表中的值,下图展示了一部分当中的值,

SourceInsight

​ 最后四个字节可以算出来,可以尝试穷举(直接遍历 byte_5F6E68[]中的字符即可),通过这样的方法来计算出最后四个字节,但是由于时间有限,没有尝试这种方法,直接利用OD单步调试算出,然后重新运行程序,输入序列号,如下图所示:call的50C0B0这个函数,计算最后四位

SourceInsight

​ 进入到50C0B0这个函数,如下图:

SourceInsight

​ 过程中没有做过多的指令分析,程序运行起来,第一次输入S4SV-UFWT-ZPR6-XXXX,鼠标选中循环之外的第一条语句,如上图橙色框。选中之后直接按F4运行到这一句,然后看下面堆栈区,就计算出来最后四位,这样重新运行程序,然后就可以输入正确的序列号,跳过这一条验证, 计算结果如下图所示:

SourceInsight

​ 图中已标出计算结果,寄存器EAX也有计算结果,寄存器EBP中存的是前15位,可以看到前十五S4SV-UFWT-ZPR6计算出来的最后四位是F336。下次输入S4SV-UFWT-ZPR6-F336即可跳过这个判断。输入序列号,

SourceInsight

SourceInsight

​ 过程中跳过了以上的判断,但是,没有激活成功,效果如下图所示:

SourceInsight

​ 这时遇到瓶颈了,在很长一段时间里,无法取得进展。IDA动态调试不是很方便,所以一直使用OD进行动态调试,进行寻找突破口。在经过一段时间寻找之后,在OD动态调试到以下函数时候,下图所示:

SourceInsight

​ 可以明显在堆栈区看到我键入的信息,并且能看到一个文件夹,但是当我打开文件夹时,里面不存在这个文件。无法找到这个文件,在经过很多次调试之后还是无果。只是键入序列号的话,无法激活,这时候,程序一直运行在一段地址之内,无法跳出,而屏幕上也一直显示正在激活请稍后,

SourceInsight

​ 但是就像文章开头分析一样,还有可以选使用试用30天和导入license的选项,导入license是需要选择文件夹的,这是伏笔。选择试用试一下,选择试用之后,C:\ProgramData\Source Insight\4.0这个文件夹下多了一个文件,si4.lic文件,这时候打开文件分析,格式大致如下:

SourceInsight

​ 清晰看到,之前填的用户名,组织,邮箱,时间在里面,下面signature字眼很关键,说明这里使用了数据签名,然后可能在某处存在进行核对,如果正确的话就激活成功。将系统状态还原至还未试用的版本,通过多次调试,查阅资料之后,发现程序使用的Windows Cryptography APIs进行签名:在调试的时候发现调用了这个系统API,系统API怎么计算的具体怎么计算没有跟踪。OD动态跟踪之后,系统调用API如下图所示:

SourceInsight

​ 通过网上查阅,“签名”和“签名验证”是通过公钥体系来实现的,所以程序中一定存在公钥,在不断寻找之后,在地址0063F648处,发现了公钥,如下图所示:

SourceInsight

​ 找到公钥之后,只要找到什么地方对公钥试用,以及签名最后在哪里比对,可能最终完成破解,继续选择键入序列号, 这时候程序依然处于上面那一段地址内循环,此时放弃了键入序列号破解程序的想法。文中一开始提到的三个方法,只剩最后一个导入license没用了,在使用试用版本发现si4.lic文件中格式之后,自己造了一个license文件,放入C:\ProgramData\Source
Insight\4.0文件夹中,然后选择导入license,如下图:

SourceInsight

​ 选择license文件导入,导入之后,先会进入判断序列号是否正确的断点,序列号是通过之前计算出来的,所以不会有问题。如下图:

SourceInsight

​ 在检查完序列号之后,会一一对license文件中所有值进行一一计算验证,一路继续F7F8调试,在调试很久之后,发现很关键的字眼,如下图:

SourceInsight

​ 上图中两个Asc码很显眼,可能接下来的重要数据就在这里,继续调试。再往下发现一处正在读入license中签名的值,如下图:

SourceInsight

​ 再往下是继续将si4中数据进行读入并进行存储,这里只截取其中两处展示,如下图:

​ 将除签名之外所有的数据读入:

SourceInsight

​ 将signature存在堆栈:

SourceInsight

​ 再往下调试,出现了非常非常非常重要的函数,经过对license文件的计算,这个函数的返回值决定了是否能成功激活,如下图:

SourceInsight

​ 进入函数主体进行分析,如下图:

SourceInsight

​ 可以明显看到导入公钥了,这里计算非常关键,此时借助IDA反汇编查看代码,分析思路然后再次回到OD去调试尝试,这样两个工具相结合加快了破解的进展。

SourceInsight

​ 图中展示借用公钥计算,然后返回结果,总共可以返回的结果有472、473、474、475、472、200.代码贴出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int __cdecl sub_50C3D0(BYTE *pbData, DWORD dwDataLen, BYTE *pbSignature, DWORD dwSigLen)
{
int result; // eax@2
BOOL v5; // esi@11
HCRYPTHASH hHash; // [sp+0h] [bp-818h]@1
HCRYPTPROV phProv; // [sp+4h] [bp-814h]@1
struct _CERT_PUBLIC_KEY_INFO *pvStructInfo; // [sp+8h] [bp-810h]@3
HCRYPTKEY phKey; // [sp+Ch] [bp-80Ch]@1
DWORD pcbBinary; // [sp+10h] [bp-808h]@1
DWORD pcbStructInfo; // [sp+14h] [bp-804h]@3
BYTE pbBinary; // [sp+18h] [bp-800h]@1

hHash = 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) )
{
if ( CryptAcquireContextW(&phProv, 0, 0, 1u, 0xF0000000) )
{
if ( CryptImportPublicKeyInfo(phProv, 1u, pvStructInfo, &phKey)
&& (LocalFree(pvStructInfo), CryptCreateHash(phProv, 0x8004u, 0, 0, &hHash)) )
{
if ( CryptHashData(hHash, pbData, dwDataLen, 0) )
{
v5 = CryptVerifySignatureW(hHash, pbSignature, dwSigLen, phKey, 0, 0);
CryptDestroyHash(hHash);
CryptReleaseContext(phProv, 0);
result = v5 != 0 ? 200 : 462;
}
else
{
result = 475;
}
}
else
{
result = 474;
}
}
else
{
result = 473;
}
}
else
{
result = 472;
}
return result;
}

​ 经过多次尝试,发现只有当返回值为200(十六进制为0xC8)的时候,软件这时候被激活,但是过程想要让它直接运行到使其直接返回C8是有困难的,所以这里直接将值改为0xC8。如下图:

SourceInsight

​ 运行结果可以看到已经激活,结果如下图:

SourceInsight

​ 点击确定之后,在help->about Source Insight中,可以看到已经激活的信息,并且激活的信息也与license中一致。

SourceInsight

###4.后续

​ 程序破解完了会有黑名单检测,如下图

SourceInsight

​ 上图中会在C:\Users\liyuf\AppData\Local\Source
Insight\4.0中出现一个.dat文件,这个文件记录了你是黑名单,然后再打开Source Insight会发现下图所示:

SourceInsight

​ 细心点可以发现,这与之前键入注册码提示的错误不一样的地方是,没有下两行的选项了,为了应对黑名单检测,总共需要修改四处地方:

1)

0050E393 85C0 TEST EAX, EAX

==>

0050E393 31C0 XOR EAX, EAX

2)

0050E645 85C0 TEST EAX, EAX

==>

0050E645 31C0 XOR EAX, EAX

3)

0050DF68 76 69 JBE SHORT 0050DFD3

==>

0050DF68 EB 69 JMP SHORT 0050DFD3

4)

0050F1BB 85C0 TEST EAX, EAX

==>

0050F1BB 31C0 XOR EAX, EAX

​ 修改完之后保存:

SourceInsight

​ 再次打开程序,界面如下:

SourceInsight

###附录

附上sub_50F5A0()函数代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
int __cdecl sub_50F5A0(int a1, int a2, int a3)
{
int result; // eax@10
int v4; // ST28_4@17
int v5; // ST2C_4@17
int v6; // ST30_4@17
int v7; // ST34_4@17
HWND v8; // esi@22
void *v9; // eax@22
void *v10; // eax@22
int v11; // [sp+0h] [bp-128h]@0
int v12; // [sp+4h] [bp-124h]@7
int v13; // [sp+8h] [bp-120h]@7
int v14; // [sp+Ch] [bp-11Ch]@7
int v15; // [sp+10h] [bp-118h]@7
int v16; // [sp+14h] [bp-114h]@7
int v17; // [sp+18h] [bp-110h]@7
int v18; // [sp+1Ch] [bp-10Ch]@7
CHAR MultiByteStr; // [sp+28h] [bp-100h]@5

if ( !a2 )
{
v8 = (HWND)sub_406770(a1, 30);
v9 = (void *)sub_404310();
sub_41B2E0(v9, 0, (int)&v12);
strcpy((char *)&v13, "Courier New");
v10 = (void *)sub_41B860(0, &v12);
dword_66BB80 = v10;
if ( v10 )
SendMessageW(v8, 0x30u, (WPARAM)v10, 1);
return 0;
}
if ( a2 == 1 )
{
if ( dword_66BB80 )
{
DeleteObject(dword_66BB80);
dword_66BB80 = 0;
}
sub_4064D0(a1, 30, &MultiByteStr);
sub_4454A0(&MultiByteStr);
_strupr(&MultiByteStr);
sub_406300(a1, 30, &MultiByteStr);
return 0;
}
if ( a2 != 2 || a3 != 1 )
return 0;
sub_4064D0(a1, 30, &MultiByteStr);
sub_4454A0(&MultiByteStr);
_strupr(&MultiByteStr);
sub_406300(a1, 30, &MultiByteStr);
if ( !sub_50C8E0(&MultiByteStr, dword_66BAE8 + 1544, dword_66BAE8 + 1548, dword_66BAE8 + 1540, 1) )
{
if ( sub_55C580(&MultiByteStr) )
sub_40A8E0(
"The serial number you entered is for version 3.x of Source Insight.\n"
"\n"
"This version requires a version 4.x serial number.",
v11,
v12,
v13,
v14,
v15,
v16,
v17,
v18);
else
sub_40A8E0(
"The serial number you entered is not correct. A serial number for Source Insight version 4.x is required.\n"
"\n"
"Please check the number and re-enter it.",
v11,
v12,
v13,
v14,
v15,
v16,
v17,
v18);
sub_406A30(a1, 30);
sub_4046B0();
if ( ++dword_66BB84 >= sub_44E310(1) + 3 )
{
dword_66BB84 = 0;
sub_44CEB0();
Sleep(0x1B58u);
sub_44CF00();
return 0;
}
return 0;
}
dword_66BB84 = 0;
if ( *(_DWORD *)(dword_66BAE8 + 1540) != BYTE3(dword_646848) )
{
sub_40A8E0(
"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,
v13,
v14,
v15,
v16,
v17,
v18);
sub_406A30(a1, 30);
sub_4046B0();
return 0;
}
if ( *(_DWORD *)(dword_66BAE8 + 1548) == 3 )
{
sub_40A8E0(
"The serial number cannot be used with the 'release' version of Source Insight.",
v11,
v12,
v13,
v14,
v15,
v16,
v17,
v18);
sub_4046B0();
return 0;
}
if ( !sub_50CA20(&MultiByteStr) )
return 0;
if ( sub_50E180(dword_66BAE8 + 1284) )
{
sub_412390("Upgrade License was validated: %s", dword_66BAE8 + 1284, v11, v12, v13, v14, v15, v16, v17);
result = 0;
}
else
{
sub_40A8E0(
"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,
v13,
v14,
v15,
v16,
v17,
v18);
sub_406A30(a1, 30);
sub_4046B0();
sub_4122B0("Upgrade License could not be validated", v4, v5, v6, v7, v12, v13, v14, v15);
result = 0;
}
return result;
}

参考链接:

https://www.52pojie.cn/thread-713308-1-4.html

https://bbs.pediy.com/thread-215669-1.htm

https://www.52pojie.cn/thread-580580-1-1.html

-------------本文结束-------------

文章作者: Summary
文章链接: http://noblestaspiration.net/2018/07/18/Source-Insight4093/
版权声明:博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议,转载请注明出处!

想要分我一杯羹吗