业精于勤,学习Win32逆向课程已有月余,为增功力,故研究po jie此SourceInsight4程序。论坛中有多位大佬写过SI4 po jie文章,此文自不可与之相较,只求叙述清楚几个po jie的关键点。
学必有师,笔者师从科锐钱老师。师者,技艺精湛自不再话下,诲人不倦耐心教导着实难能可贵,在此拜谢。
本文po jie的是当前最新版本Source Insight 4.0.118,总结po jie过程有以下三个部分:
除此之外,笔者也看了一些大佬的文章,提到有黑名单检查,因为没遇到这个逻辑,本着能用就行的原则,所以这里的po jie中没有涉及,后面如果遇到再研究也不迟。
文中用到的所有代码可点击右侧超链接,在 Github上查看
IDA6.8、x32dbg
官网 下载sourceinsight40118-setup.exe
因为本文主要是研究自签名license并替换程序中公钥的po jie方法,比较麻烦,纯粹是为了学习目的。如果对这种方法不感兴趣,这部分内容就提供另一种简单的po jie方法:修改 sourceinsight4.exe 二进制文件中的两个字节完成po jie
这部分内容分4个小节:
1.1 节 讲述如何定位到验证序列号的代码
1.2 节 中逆向还原验证序列号格式的函数,并按照格式构造出正式版序列号
1.3 节 中逆向还原本地校验序列号的函数,构造出可通过本地校验的序列号
1.4 节 本地验证序列号
安装程序后,打开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 继续判断验证结果。代码如下所示:
详细分析上面步骤中提到的 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个字符必须相同
代码如下所示:
步骤1.2中提到Serial Number的验证规则之一是:序列号的前12个字符经过函数 sub_510320 转换后得到4个字符,与序列号的最后4个字符相同。
以下便是是 sub_510320 汇编代码分析以及据此还原的C代码,将此函数命名为 Get4charBySNPre12char
因为 Get4charBySNPre12char 函数是通过SerialNumber的前12个字符生成后4个字符,所以可以将构造的前12个字符传入此函数,计算出一个可用的SerialNumber的后4个字符,代码如上,最终得到一个Standard正式版序列号:S4SG-KRGM-YD7Q-RCFY
将构造的序列号输入到序列号验证窗口中,点击“Next >”,验证通过,弹出“个人信息窗口”。
输入姓名、组织、邮箱信息,再点击“Next >”,弹窗“信息确认窗口”。
再点击“Next >”,先提示“正在激活许可”,接着又弹出了一个错误窗口,如下图:
通过定位字符串找到处理上述流程的函数 sub_514740,该函数首先检查是否联网,
如果联网了,则会通过网络校验SerailNumer,验证失败就会弹出上面的错误信息;
如果没有联网,则会跳转到生成临时license文件的函数 sub_513780 ,该函数会在 C:\ProgramData\Source Insight\4.0 目录生成 si4.lic 文件,允许程序单次运行,相当于一次性许可证,重启程序之后,这个许可也会失效。
据此猜测,既然生成了许可证文件,那么程序启动时就应该会去读 si4.lic 文件进行验证,打开监控软件便可看到对该文件进行了操作,如下图所示。至此,完成SerialNumber验证的分析,并构造出可用的序列号,接下来就分析 si4.lic 文件的加载及验证签名过程。
这部分内容分3个小节:
2.1 节 根据读文件的API跟踪程序调用流程,还原出程序启动验证RSA签名的流程
2.2 节 讲述最简单的po jie方法,只需修改两个字节就可以po jie 程序
2.3 节 讲述自己签名license文件的po jie方法,相比 2.2 节 的方法要麻烦很多,但是学到了RSA签名校验的知识以及CryptoAPI编程
在 1.4 节 分析的最后提到,程序启动后会加载 si4.lic 许可证文件,并且会调用 CreateFileMapping API将文件内容映射到内存,所以对这个函数下API断点,就可以定位到读许可证的代码。而且读完许可证之后,就是验证许可证签名的代码。
程序中只有一处调用了这个API,结合动态调试,总结出调用关系如下所示:
调用关系看起来还是有些复杂,这里强调重要的三个函数作用,其中后两个函数需要还原成C语言代码, 以便验证自己签名的数据是否正确:
在 2.1 节 的调用流程中提到,sub_512CF0 函数是签名校验的入口函数,如果此函数返回值等于0C8h,则表示校验通过;如果返回值不等于0C8h,则会弹出验证错误窗口,汇编代码如下面所示。
在.text:005141A8处检查校验结果,成功就跳转到 loc_5141D4,失败则会执行错误流程。
所以,可以将此处的比较跳转 jz 改为无条件跳转 jmp,修改二进制就是将 74 改为 EB,这样就过掉了校验签名。
上面分析调用流程时,已经提到 :
sub_402E00 函数,会把 si4.lic 文件中的字符串签名解码为0x100字节大小的二进制签名数据,命名该函数为 Base64Decode;
sub_510640 函数,会用程序中自带的2048位非对称加密的公钥,以 si4.lic文件中 Signature 标签之前的数据作为校验数据,与二进制签名数据作比对,命名该函数为 VerifySignature
先粗略描述一下服务器签名以及本地验证签名的过程:
si4.lic 文件内容如下:
这个是还原 sub_402E00 汇编代码的函数,该函数将 si4.lic 文件中的 Signature字符串签名数据解码为二进制签名数据。
这个是还原 sub_510640 汇编代码的函数,该函数完成签名校验。
自签名许可证分为两个部分,
第一部分:签名数据
第二部分:校验签名
调用上面的 Base64Decode 和 VerifySignature 函数,校验我们自己签名的数据是否正确。
代码如下,完整代码可点击右侧超链接,在 Github上查看
完成步骤2的po jie之后,启动程序,可以正常运行。但是程序运行2分钟左右之后,会再次弹出需要激活的窗口,所以猜测:程序启动先验证本地许可证,之后又联网验证,验证失败则会再弹出需要激活窗口。
基于此猜测,在导入表中查找网络发包相关API,看到有 HttpSendRequestW API,在调试器中下API断点,成功断下后,看到 lpOptional 参数中包含有Serial Number,如下图所示:
分析调用关系可知,每次程序启动,都会在 sub_514290 函数中创建在线检查序列号的线程,该线程的启动函数地址是 sub_513470。所以,可以将该函数入口处代码修改为 ret,直接结束该线程。参考下面的代码,就是修改 .text:00513470 地址处的 83 改为C3。
.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
.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' ; ptr_szSN[6] == 'F'
.text:00510BAF jnz loc_510C86
.text:00510BB5
.text:00510BB5 loc_510BB5: ; CODE XREF: sub_510B50+4Cj
.text:00510BB5 ; sub_510B50+53j ...
.text:00510BB5 mov al, [esi+1]
.text:00510BB8 cmp al, '0' ; ptr_szSN[1] >= '0'
.text:00510BBA jl loc_510C86
.text:00510BC0 cmp al, '9' ; ptr_szSN[1] <= '9'
.text:00510BC2 jg loc_510C86
.text:00510BC8 mov edx, [esp+1Ch+ptr_nVersionFlag]
.text:00510BCC movsx eax, al
.text:00510BCF sub eax, '0'
.text:00510BD2 mov [edx], eax
.text:00510BD4 mov al, [esi+2]
.text:00510BD7 cmp al, 'T' ; ptr_szSN[2] == 'T', Trial license
.text:00510BD9 jnz short IF_BEGIN
.text:00510BDB mov eax, [esp+1Ch+ptr_nLicTypeFlag]
.text:00510BDF mov dword ptr [eax], 1
.text:00510BE5 jmp short ELSE_END
.text:00510BE7 ; ---------------------------------------------------------------------------
.text:00510BE7
.text:00510BE7 IF_BEGIN: ; CODE XREF: sub_510B50+89j
.text:00510BE7 cmp al, 'B' ; ptr_szSN[2] == 'B', Bete license, cannot be used with the release version
.text:00510BE9 jnz short ELSE_IF
.text:00510BEB mov edx, [esp+1Ch+ptr_nLicTypeFlag]
.text:00510BEF mov dword ptr [edx], 3
.text:00510BF5 jmp short ELSE_END
.text:00510BF7 ; ---------------------------------------------------------------------------
.text:00510BF7
.text:00510BF7 ELSE_IF: ; CODE XREF: sub_510B50+99j
.text:00510BF7 cmp al, 'S' ; ptr_szSN[2] == 'S', Standard license
.text:00510BF9 jnz short ELSE_IF_
.text:00510BFB mov eax, [esp+1Ch+ptr_nLicTypeFlag]
.text:00510BFF mov dword ptr [eax], 0
.text:00510C05 jmp short ELSE_END
.text:00510C07 ; ---------------------------------------------------------------------------
.text:00510C07
.text:00510C07 ELSE_IF_: ; CODE XREF: sub_510B50+A9j
.text:00510C07 cmp al, 'U' ; ptr_szSN[2] == 'U', Upgrade License
.text:00510C09 jnz short loc_510A56
.text:00510C0B mov edx, [esp+1Ch+ptr_nLicTypeFlag]
.text:00510C0F mov dword ptr [edx], 0
.text:00510C15
.text:00510C15 ELSE_END: ; CODE XREF: sub_510B50+95j
.text:00510C15 ; SI_ValidateSNFmt+A5j ...
.text:00510C15 mov al, [esi+3]
.text:00510C18 cmp al, 'G' ; ptr_szSN[3] == 'G'
.text:00510C1A jnz short IF_BEGIN2
.text:00510C1C mov eax, [esp+1Ch+ptr_nSN[3]Flag]
.text:00510C20 mov dword ptr [eax], 1
.text:00510C26 jmp short ELSE_END2
.text:00510C28 ; ---------------------------------------------------------------------------
.text:00510C28
.text:00510C28 IF_BEGIN2: ; CODE XREF: sub_510B50+CAj
.text:00510C28 cmp al, 'V' ; ptr_szSN[3] == 'V'
.text:00510C2A jnz short ELSE_IF2
.text:00510C2C mov edx, [esp+1Ch+ptr_nSN[3]Flag]
.text:00510C30 mov dword ptr [edx], 2
.text:00510C36 jmp short ELSE_END2
.text:00510C38 ; ---------------------------------------------------------------------------
.text:00510C38
.text:00510C38 ELSE_IF2: ; CODE XREF: sub_510B50+DAj
.text:00510C38 cmp al, 'R' ; ptr_szSN[3] == 'R'
.text:00510C3A jnz short loc_510C86
.text:00510C3C mov eax, [esp+1Ch+ptr_nSN[3]Flag]
.text:00510C40 mov dword ptr [eax], 0
.text:00510C46
.text:00510C46 ELSE_END2: ; CODE XREF: sub_510B50+D6j
.text:00510C46 ; sub_510B50+E6j
.text:00510C46 test ecx, ecx
.text:00510C48 jz short loc_510C7C
.text:00510C4A lea ecx, [esp+1Ch+szSNTemp]
.text:00510C4E push esi ; char *
.text:00510C4F push ecx ; char *
.text:00510C50 call _strcpy
.text:00510C55 lea edx, [esp+24h+ary4char]
.text:00510C59 push edx
.text:00510C5A push offset ary256Chars
.text:00510C5F lea eax, [esp+2Ch+szSNTemp]
.text:00510C63 push 0Fh
.text:00510C65 push eax
.text:00510C66 mov [esp+34h+szSNTemp+0Fh], 0
.text:00510C6B call sub_510320 ; 通过SerialNumber前12个字符计算出最后4个字符,并与输入的SerialNumber最后4个字符做比较
.text:00510C70 mov ecx, [esi+0Fh]
.text:00510C73 add esp, 18h
.text:00510C76 cmp ecx, [esp+1Ch+ary4char] ; 比较计算出的最后4个字符是否与输入的SerialNumber最后4个字符相同
.text:00510C7A jnz short loc_510C86
.text:00510C7C
.text:00510C7C loc_510C7C: ; CODE XREF: sub_510B50+F8j
.text:00510C7C mov eax, 1
.text:00510C81 pop esi
.text:00510C82 add esp, 18h
.text:00510C85 retn
.text:00510C86 ; ---------------------------------------------------------------------------
.text:00510C86
.text:00510C86 loc_510C86: ; CODE XREF: sub_510B50+1Aj
.text:00510C86 ; sub_510B50+25j ...
.text:00510C86 xor eax, eax
.text:00510C88 pop esi
.text:00510C89 add esp, 18h
.text:00510C8C retn
.text:00510C8C sub_510B50 endp
.text:00510320 sub_510320 proc near ; CODE XREF: sub_510390+73p
.text:00510320 ; sub_510B50+11Bp ...
.text:00510320
.text:00510320 ptr_szSN = dword ptr 4
.text:00510320 nSNLen = dword ptr 8
.text:00510320 ary256char = dword ptr 0Ch
.text:00510320 ptr_4charsResult= dword ptr 10h
.text:00510320
.text:00510320 push ebx
.text:00510321 mov ebx, [esp+4+nSNLen]
.text:00510325 push ebp
.text:00510326 mov ebp, [esp+8+ptr_szSN]
.text:0051032A push esi
.text:0051032B push edi
.text:0051032C mov edi, [esp+10h+ary256char]
.text:00510330 xor esi, esi
.text:00510332
.text:00510332 DO_BEGIN: ; CODE XREF: sub_510320+5Ej
.text:00510332 movsx eax, byte ptr [ebp+0]
.text:00510336 add eax, esi
.text:00510338 and eax, 0FFh
.text:0051033D mov cl, [eax+edi]
.text:00510340 mov eax, 1
.text:00510345 cmp ebx, eax
.text:00510347 jbe short loc_510361
.text:00510349 lea esp, [esp+0]
.text:00510350
.text:00510350 _DO_BEGIN: ; CODE XREF: sub_510320+3Fj
.text:00510350 movsx edx, byte ptr [eax+ebp]
.text:00510354 movzx ecx, cl
.text:00510357 xor edx, ecx
.text:00510359 mov cl, [edx+edi]
.text:0051035C inc eax
.text:0051035D cmp eax, ebx
.text:0051035F jb short _DO_BEGIN
.text:00510361
.text:00510361 _DO_END: ; CODE XREF: sub_510320+27j
.text:00510361 movzx eax, cl
.text:00510364 cdq
.text:00510365 mov ecx, 1Ah
.text:0051036A idiv ecx
.text:0051036C mov eax, [esp+10h+ptr_4charsResult]
.text:00510370 inc esi
.text:00510371 mov dl, byte ptr ds:sz26Chars[edx] ; "KV96GMJYH7QF5TCW4U3XZPRSDN"
.text:00510377 mov [esi+eax-1], dl
.text:0051037B cmp esi, 4
.text:0051037E jb short DO_BEGIN
.text:00510380 pop edi
.text:00510381 pop esi
.text:00510382 pop ebp
.text:00510383 pop ebx
.text:00510384 retn
.text:00510384 sub_510320 endp
//还原为C代码
char g_sz26Chars[] = { "KV96GMJYH7QF5TCW4U3XZPRSDN" };
void Get4charBySNPre12char(char* szSN, int nSNLen, char* ary256Chars, char* pResult) {
for (int i = 0; i < 4; i++) {
char cl = ary256Chars[(szSN[0] + i) & 0xFF];
for (int j = 1; j < nSNLen; j++) {
cl = ary256Chars[szSN[j] ^ (unsigned char)cl];
}
*(pResult + i) = g_sz26Chars[((unsigned char)cl % 0x1A)];
}
}
//构造一个可用的Serial Number
char g_ary256Chars[] = { 0x23, 0xDD, 0x78... }; //这里是一个256大小的char数组
void main() {
char szSN[] = { "S4SG-KRGM-YD7Q-XXXX" };
Get4charBySNPre12char(szSN, 15, g_ary256Chars, &szSN[15]);
printf("%s\r\n", szSN); //S4SG-KRGM-YD7Q-RCFY
}
.text:0045B460 WinMain
.text:0045B6CD call sub_515000
.text:00515032 |- call sub_514ED0
.text:00514EF3 |- call sub_417E40 检查C:\ProgramData\Source Insight\4.0\si4.lic文件是否存在
.text:00514F03 |- call sub_5140E0 校验lic文件的函数,如果si4.lic文件存在,则执行校验
.text:005140FD |- call sub_5127A0 加载si4.lic,校验字段值,保存校验结果。成功返回0xC8
.text:005127EA | |- call sub_511150
.text:00511156 | | |- call sub_45A770 加载si4.lic文件
.text:0045A779 | | |- call sub_45A290
.text:0045A2E7 | | |- call sub_41B290
.text:0041B2B2 | | |- call sub_4567F0
.text:00456898 | | | |- call ds:CreateFileMappingW
.text:0041B2D9 | | |- call ds:MapViewOfFile
.text:00512806 | |- call sub_510570 校验并存储<Type>值,与"Trial"、"Beta"、"Standard"相比较,设置校验结果
.text:00512875 | |- call sub_510570 校验并存储<LicensedUser>值,不存在则结束,返回失败标志
.text:005128FA | |- call sub_510570 校验并存储<Serial>值,不存在则结束,返回失败标志
.text:00512927 | |- call sub_510570 校验并存储<ActId>值,如果值等于"Deferred",设置标志位,表明si4.lic是断网激活时生成的一次性许可证
.text:00514102 |- cmp eax, 0C8h 判断 sub_5127A0 返回值,失败则弹出错误窗口
.text:00514133 |- mov eax, [esi] 判断如果是“一次性许可证”,则函数返回False
.text:0051419B |- call sub_512CF0 加载si4.lic,校验签名。成功返回0xC8
.text:00512D39 |- call sub_45A770 加载si4.lic文件
.text:00512D59 |- call sub_457D80 遍历si4.lic中的数据,查找<Signature>标签
.text:00512D6B |- call sub_458520 找到<Signature>后,获取它的值
.text:00512DEB |- call sub_402E00 Base64解码Signature字符串值,得到二进制签名数据
.text:00512E08 |- call sub_510640 CryptoAPI校验签名。成功返回0xC8
//还原成伪代码
InfoObj *g_infoObj;
int WinMain()
{
g_infoObj->sub_515000();
}
//校验si4.lic中签名的函数
int sub_512CF0()
{
sub_45A770(); //加载si4.lic文件
sub_457D80(); //遍历si4.lic中的数据,查找<Signature>键值对
sub_458520(); //从<Signature>键值对中,获取Value值
sub_402E00(); //Base64解码Signature值,得到二进制签名数据
sub_510640(); //使用CryptoAPI校验 RSA签名,校验成功返回C8
}
class InfoObj{
int mLicenseType; //offset:+0 许可证类型:Trial/Beta/Standard
//InfoObj的构造函数
sub_512BF0() {
}
sub_515000() {
this.sub_514ED0();
}
sub_514ED0() {
//检查C:\ProgramData\Source Insight\4.0\si4.lic文件是否存在
boolean success = sub_417E40();
if(success)
{
//如果si4.lic文件存在,则执行校验
this.sub_5140E0();
}
}
sub_5140E0() {
//加载si4.lic,校验字段值,保存校验结果
int loadLicResult = this.sub_5127A0();
if(loadLicResult != 0xC8) {
//弹出错误窗口
return false;
}
//检查是否是一次性许可
if(mLicenseType == 2) {
//弹出错误窗口
return false;
}
//加载si4.lic,校验签名
if(sub_512CF0() != 0xC8) {
//弹出错误窗口
return false;
}
}
//读si4.lic文件,校验并保存字段值
sub_5127A0(){
sub_511150(); //加载si4.lic文件,这个函数里调用了 sub_45A770 CreateFileMappingW API
sub_510570("Type"); //获取<Type>值,与"Trial"、"Beta"、"Standard"相比较,设置校验结果
sub_510570("Serial"); //获取<Serial>值,不存在则结束,返回失败标志
sub_510570("ActId"); //获取<ActId>值,如果值等于"Deferred",设置mLicenseType=2,表明si4.lic是断网激活时生成的一次性许可证
...
}
};
.text:0051419B E8 50 EB+ call sub_512CF0
.text:005141A0 83 C4 08 add esp, 8
.text:005141A3 3D C8 00+ cmp eax, 0C8h
.text:005141A8 74 2A jz short loc_5141D4
.text:005141AA
.text:005141AA loc_5141AA: ; CODE XREF: .text:00514179j
.text:005141AA ; .text:0051418Bj
.text:005141AA 83 BC 24+ cmp dword ptr [esp+108h], 0
.text:005141B2 74 0D jz short loc_5141C1
.text:005141B4 50 push eax
.text:005141B5 8B CE mov ecx, esi
.text:005141B7 E8 D4 CB+ call sub_510D90
.text:005141BC E8 2F E9+ call sub_412AF0
.text:005141C1
.text:005141C1 loc_5141C1: ; CODE XREF: .text:005141B2j
.text:005141C1 8B CE mov ecx, esi
.text:005141C3 E8 08 CF+ call sub_5110D0
.text:005141C8 33 C0 xor eax, eax
.text:005141CA 5E pop esi
.text:005141CB 81 C4 00+ add esp, 100h
.text:005141D1 C2 04 00 retn 4
.text:005141D4 ; ---------------------------------------------------------------------------
.text:005141D4
.text:005141D4 loc_5141D4: ; CODE XREF: .text:00514184j
.text:005141D4 ; .text:005141A8j
<!--
Source Insight 4.x License File
DO NOT EDIT THIS FILE. Doing so will render it unusable.
This license was created for:
xxx
51asm
xxx@xxx.com
-->
<SourceInsightLicense>
<Header
Value="1"
/>
<LicenseProperties
LicensedUser="51asm"
ActId="9930152826"
HWID="ZM6QWPSW-MNFUHVF5"
Serial="S4SG-KRGM-YD7Q-RCFY"
Organization=""
Email="xxx@xxx.com"
Type="Standard"
Version="4"
MinorVersion="0"
Date="2020-08-15"
Expiration="2030-08-15"
/>
<Signature
Value="TMNEF2MnPkl3+gLskqe8+X1Yq6ZiqFBMddeWJWC9ttGxxSBRHDMX9QCJowo5ffHqURy5/dhSJ5rDsqxMAK5h30WXcjJcP8D2Cc0P0igilnKX9gFoX/FaBMnDbQMTD6bq4UbV6lxiFXxmTVW8/Xt1rA1b7nMzdp1apkAquyPQizglC471Jo1JMeehEuVeLAe38cENDDQVQtV28u9AGyTaCrA6IIOIsJSrWeldmW8VHbTkmD4bt87OdTDt/oN3+sDcV8idMm02eGCX2/HQ/Ef0ozGQK1BoljDEJtGXlhzzKputxWK/O36WPPrE5iuiFNmfrqewH3NMhoEWszhFxapuHg=="
/>
</SourceInsightLicense>
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!