010Editor 破解
一、软件保护
软件无壳。
二、定位关键代码
输入注册信息,观察提示信息。
通过提示信息字符串,定位注册代码的位置。
提示信息前面有 jmp 进行跳转,说明存在分支 1,通过查找 jmp 之后的地址引用,确定分支判断的位置。
分支 1 的判断。
观察到分支 1 前有 jmp 指令会跳过分支判断,说明该分支 1 在其他分支里面(分支嵌套),同样查找在 jmp 后面地址的引用,定位上一层分支的位置。
分支 2(分支 1 上一层的分支 )
观察到分支 2 前有 jmp 指令会跳过分支判断,说明该分支在其他分支里面(分支嵌套),同样查找在 jmp 后面地址的引用,定位上一层分支的位置。
分支 3(分支 2 上一层的分支 )
同样当看到分支前有 jmp 指令,通过地址引用的方法向前回溯。
最终,回溯到函数入口处。
计算函数的 RVA。
RVA = VA - ImageBase = 00007FF6EB5C0520 - 00007FF6EB3B0000 = 210520H
通过 RVA 计算该函数在 IDA 中的地址。
在 IDA 打开 010Editor.exe,并跳转到 0000000140210520 位置处,对函数进行反编译。
反编译的代码
三、分析代码
观察代码,驱动注册成功的分支。即 v17 == 0xDB 的时候,进行成功注册流程。
查看 v17 的引用,发现有两处给 v17 赋值的地方,而且是同一个函数。
两处赋值的地方,一处在循环外,一处在循环内。
进入分支外的 sub_14036EFA0() 函数,确定返回 0xDB 的代码。
进入 sub_14036E4C0() 函数,查找返回 0x2D 的代码。
分析返回 0x2D 的流程
除了 switch-case 等于 0x9C 分支外,还有两处能跳转到 LABEL_26。
当 switch-case 等于 0xFC 或 0xAC 都能跳转到 LABEL_26。
分析 switch-case 的判断值的由来,查看引用没有发现赋值给判断值的语句。
switch-case 的判断值是一个在函数内的变量,所以可以确定该变量的赋值一定该函数内。
计算出 sub_14036E4C0() 函数的 RVA,定位该函数在 x64Dbg 里面的地址。
RVA = VA - PE.ImageBase = 14036E4C0 - 140000000 = 36E4C0H
VA = RVA + ImageBase = 36E4C0H + 7FF6EB3B0000H = 7FF6EB71E4C0H  跳转到 7FF6
EB71E4C0H 地址处,在函数入口初始化完毕之后下断点。
当断点触发后,找到 switch-case 的判断入口,并在 switch-case 的判断入口下断点。
dil 作为 switch-case 的判断值,由 ss:[rsp+63] 进行赋值。
在内存中对 000000EDD2955F73 地址空间下硬件写断点。
硬件写断点命令中,看 000000EDD2955F73 地址处的内存值,发现与输入的密码有点相识。
查看调用堆栈,看看是从那里过来的。发现从 00007FF6EB71E4C0() 函数的调用 call 010editor.7FF6EB3B5565() 函数过去的。
定位在 IDA 中的位置 = VA - ImageBase + PE.ImageBase
重定位 7FF6EB71E4C0() 函数 = 00007FF6EB71E4C0 - 00007FF6EB3B0000 + 140000000 = 00014036E4C0H 重定位 7FF6EB3B5565() 函数 = 7FF6EB3B5565 - 00007FF6EB3B0000 + 140000000 = 0001
40005565H
sub_140005565() 的第一个参数是 sub_14036E4C0() 函数第一个参数,应该是一个类对象指针。而第二个参数是一个函数内的变量,而且在调用 sub_140005565() 之前并没有赋值,所以很有可能是想通过 sub_140005565() 进行赋值,是一个传出参数。
在 00007FF6EB71E4C0() 函数的 00007FF6EB71E522 地址的 call 010editor.7FF6EB3B5565 指令和 00007FF6EB71E527 地址处下断点。
观察 call 010editor.7FF6EB3B5565 函数的输入参数。
第一个参数看不懂,第二个参数是一个栈空间的地址。
步过。观察返回值和第二个参数的栈空间的数据。发现第二个参数的栈空间数据就是数值形式的输入密码。
存储数值形式密码数组的定义
存储数值形式密码数组的使用
运行。命中在 switch-case 的判断入口下断点。switch-case 用于判断的是由密码的第 7 个和第 8 个的字符组成的一个数值。也就是说密码的第 7 个和第 8 个字符可能是 "9C"、"AC"、"FC"。
只有密码的第 7 个和第 8 个字符是 "9C" 和不是 "FC",才能返回 0x2D。
当密码的第 7 个和第 8 个字符是 "AC" 时,密码需要用到第 17、18、19、20 个字符。
而当密码的第 7 个和第 8 个字符是 "9C" 时,密码无需用到第 17、18、19、20 个字符。所以这里分析 "9C" 分支。
密码验证流程的分析:
0x0E <= sub_140004B06(aryPassword_6 ^ aryPassword_0)
sub_14000B041((aryPassword_5 ^ aryPassword_2) + ((aryPassword_7 ^ aryPassword_1) << 8)) <= 0x3E8
sub_140004A16() 的返回值要与密码的第 5、6、7、8 个字符组成的数值相等。
sub_140004B06() 和 sub_14000B041() 都是一些计算的函数。
在 QString::toUtf8() 和 sub_140004A16() 函数处下断点,观察传入函数的参数。
QString::toUtf8() 的第一个参数由 sub_14036E4C0() 函数的第一个参数加 8 的偏移组成,是一个 QString 类对象,存储的是用户名;第二个参数是一个栈空间的地址,而且未被使用和赋值过,应该是一个传出参数。QString::toUtf8() 函数是将字符串转换为 UTF-8 编码格式。
通过返回值和第二个参数可以看到转换后 UTF-8 格式的用户名。
分析 sub_140004A16() 函数的传入参数。第一个参数是 Ascii 形式的用户名数组,第二个参数是 1,第三个参数是 0 或者是 sub_140004A16() 函数第一个参数加 0x2C 的值,第四个参数是 sub_14000B041((aryPassword_5 ^ aryPassword_2) + ((aryPassword_7 ^ aryPassword_1) << 8)) 的返回值,而且小于 0x3E8。
进入 sub_140004A16(),里面没有调用其他函数,只用到了一个全局数组 dword_140B9A0A0。
__int64 __fastcall sub_14036D380(char *szUserName, int a2, char a3, char a4)
{
unsigned int v5; // ebp
__int64 nUserNameLength; // rax
__int64 nUserNameLength2; // r13
__int64 i; // rbx
unsigned __int8 v9; // r14
unsigned __int8 v10; // si
unsigned __int8 v11; // r15
unsigned __int8 v12; // di
int v13; // eax
_DWORD *v14; // r9
unsigned int v15; // er11
_DWORD *v16; // r10
int v17; // ebp
__int64 v18; // rcx
__int64 v19; // rax
v5 = 0;
nUserNameLength = -1i64;
do
++nUserNameLength;
while ( szUserName[nUserNameLength] );
nUserNameLength2 = nUserNameLength;
if ( nUserNameLength > 0 )
{
i = 0i64;
v9 = 0;
v10 = 15 * a4;
v11 = 0;
v12 = 17 * a3;
do
{
v13 = toupper(szUserName[i]);
v14 = &dword_140B9A0A0[v12];
v15 = v5 + dword_140B9A0A0[v13];
v16 = &dword_140B9A0A0[v10];
if ( a2 )
{
v17 = dword_140B9A0A0[(v13 + 13)];
v18 = (v13 + 47);
v19 = v9;
}
else
{
v17 = dword_140B9A0A0[(v13 + 63)];
v18 = (v13 + 23);
v19 = v11;
}
v12 += 9;
v10 += 13;
v9 += 19;
v11 += 7;
++i;
v5 = *v16 + *v14 + dword_140B9A0A0[v19] + dword_140B9A0A0[v18] * (v15 ^ v17);
}
while ( i < nUserNameLength2 );
}
return v5;
}
全局数组 dword_140B9A0A0
.data:0000000140B9A0A0 dword_140B9A0A0 dd 39CB44B8h, 23754F67h, 5F017211h, 3EBB24DAh, 351707C6h
.data:0000000140B9A0A0 dd 63F9774Bh, 17827288h, 0FE74821h, 5B5F670Fh, 48315AE8h
.data:0000000140B9A0A0 dd 785B7769h, 2B7A1547h, 38D11292h, 42A11B32h, 35332244h
.data:0000000140B9A0A0 dd 77437B60h, 1EAB3B10h, 53810000h, 1D0212AEh, 6F0377A8h
.data:0000000140B9A0A0 dd 43C03092h, 2D3C0A8Eh, 62950CBFh, 30F06FFAh, 34F710E0h
.data:0000000140B9A0A0 dd 28F417FBh, 350D2F95h, 5A361D5Ah, 15CC060Bh, 0AFD13CCh
.data:0000000140B9A0A0 dd 28603BCFh, 3371066Bh, 30CD14E4h, 175D3A67h, 6DD66A13h
.data:0000000140B9A0A0 dd 2D3409F9h, 581E7B82h, 76526B99h, 5C8D5188h, 2C857971h
.data:0000000140B9A0A0 dd 15F51FC0h, 68CC0D11h, 49F55E5Ch, 275E4364h, 2D1E0DBCh
.data:0000000140B9A0A0 dd 4CEE7CE3h, 32555840h, 112E2E08h, 6978065Ah, 72921406h
.data:0000000140B9A0A0 dd 314578E7h, 175621B7h, 40771DBFh, 3FC238D6h, 4A31128Ah
.data:0000000140B9A0A0 dd 2DAD036Eh, 41A069D6h, 25400192h, 0DD4667h, 6AFC1F4Fh
.data:0000000140B9A0A0 dd 571040CEh, 62FE66DFh, 41DB4B3Eh, 3582231Fh, 55F6079Ah
.data:0000000140B9A0A0 dd 1CA70644h, 1B1643D2h, 3F7228C9h, 5F141070h, 3E1474ABh
.data:0000000140B9A0A0 dd 444B256Eh, 537050D9h, 0F42094Bh, 2FD820E6h, 778B2E5Eh
.data:0000000140B9A0A0 dd 71176D02h, 7FEA7A69h, 5BB54628h, 19BA6C71h, 39763A99h
.data:0000000140B9A0A0 dd 178D54CDh, 1246E88h, 3313537Eh, 2B8E2D17h, 2A3D10BEh
.data:0000000140B9A0A0 dd 59D10582h, 37A163DBh, 30D6489Ah, 6A215C46h, 0E1C7A76h
.data:0000000140B9A0A0 dd 1FC760E7h, 79B80C65h, 27F459B4h, 799A7326h, 50BA1782h
.data:0000000140B9A0A0 dd 2A116D5Ch, 63866E1Bh, 3F920E3Ch, 55023490h, 55B56089h
.data:0000000140B9A0A0 dd 2C391FD1h, 2F8035C2h, 64FD2B7Ah, 4CE8759Ah, 518504F0h
.data:0000000140B9A0A0 dd 799501A8h, 3F5B2CADh, 38E60160h, 637641D8h, 33352A42h
.data:0000000140B9A0A0 dd 51A22C19h, 85C5851h, 32917ABh, 2B770AC7h, 30AC77B3h
.data:0000000140B9A0A0 dd 2BEC1907h, 35202D0h, 0FA933D3h, 61255DF3h, 22AD06BFh
.data:0000000140B9A0A0 dd 58B86971h, 5FCA0DE5h, 700D6456h, 56A973DBh, 5AB759FDh
.data:0000000140B9A0A0 dd 330E0BE2h, 5B3C0DDDh, 495D3C60h, 53BD59A6h, 4C5E6D91h
.data:0000000140B9A0A0 dd 49D9318Dh, 103D5079h, 61CE42E3h, 7ED5121Dh, 14E160EDh
.data:0000000140B9A0A0 dd 212D4EF2h, 270133F0h, 62435A96h, 1FA75E8Bh, 6F092FBEh
.data:0000000140B9A0A0 dd 4A000D49h, 57AE1C70h, 4E2477h, 561E7E72h, 468C0033h
.data:0000000140B9A0A0 dd 5DCC2402h, 78507AC6h, 58AF24C7h, 0DF62D34h, 358A4708h
.data:0000000140B9A0A0 dd 3CFB1E11h, 2B71451Ch, 77A75295h, 56890721h, 0FEF75F3h
.data:0000000140B9A0A0 dd 120F24F1h, 1990AE7h, 339C4452h, 27A15B8Eh, 0BA7276Dh
.data:0000000140B9A0A0 dd 60DC1B7Bh, 4F4B7F82h, 67DB7007h, 4F4A57D9h, 621252E8h
.data:0000000140B9A0A0 dd 20532CFCh, 6A390306h, 18800423h, 19F3778Ah, 462316F0h
.data:0000000140B9A0A0 dd 56AE0937h, 43C2675Ch, 65CA45FDh, 0D604FF2h, 0BFD22CBh
.data:0000000140B9A0A0 dd 3AFE643Bh, 3BF67FA6h, 44623579h, 184031F8h, 32174F97h
.data:0000000140B9A0A0 dd 4C6A092Ah, 5FB50261h, 1650174h, 33634AF1h, 712D18F4h
.data:0000000140B9A0A0 dd 6E997169h, 5DAB7AFEh, 7C2B2EE8h, 6EDB75B4h, 5F836FB6h
.data:0000000140B9A0A0 dd 3C2A6DD6h, 292D05C2h, 52244DBh, 149A5F4Fh, 5D486540h
.data:0000000140B9A0A0 dd 331D15EAh, 4F456920h, 483A699Fh, 3B450F05h, 3B207C6Ch
.data:0000000140B9A0A0 dd 749D70FEh, 417461F6h, 62B031F1h, 2750577Bh, 29131533h
.data:0000000140B9A0A0 dd 588C3808h, 1AEF3456h, 0F3C00ECh, 7DA74742h, 4B797A6Ch
.data:0000000140B9A0A0 dd 5EBB3287h, 786558B8h, 0ED4FF2h, 6269691Eh, 24A2255Fh
.data:0000000140B9A0A0 dd 62C11F7Eh, 2F8A7DCDh, 643B17FEh, 778318B8h, 253B60FEh
.data:0000000140B9A0A0 dd 34BB63A3h, 5B03214Fh, 5F1571F4h, 1A316E9Fh, 7ACF2704h
.data:0000000140B9A0A0 dd 28896838h, 18614677h, 1BF569EBh, 0BA85EC9h, 6ACA6B46h
.data:0000000140B9A0A0 dd 1E43422Ah, 514D5F0Eh, 413E018Ch, 307626E9h, 1ED1DFAh
.data:0000000140B9A0A0 dd 49F46F5Ah, 461B642Bh, 7D7007F2h, 13652657h, 6B160BC5h
.data:0000000140B9A0A0 dd 65E04849h, 1F526E1Ch, 5A0251B6h, 2BD73F69h, 2DBF7ACDh
.data:0000000140B9A0A0 dd 51E63E80h, 5CF2670Fh, 21CD0A03h, 5CFF0261h, 33AE061Eh
.data:0000000140B9A0A0 dd 3BB6345Fh, 5D814A75h, 257B5DF4h, 0A5C2C5Bh, 16A45527h
.data:0000000140B9A0A0 dd 16F23945h
三、注册机
由上诉分析可知,密码的长度是 16 个字符,其中 9 ~ 16 的字符可以由用户名通过 sub_140004A16() 函数反推生成,而 7、8 的字符是必须 "9C",而 3 和 4、 5 和 6 组成的数值必须满足 sub_14000B041((aryPassword_5 ^ aryPassword_2) + ((aryPassword_7 ^ aryPassword_1) << 8)) <= 0x3E8,而 1 和 2 组成的数值必须满足 0x0E <= sub_140004B06(aryPassword_6 ^ aryPassword_0)。
#include <iostream>
unsigned int dword_140B9A0A0[] = {
0x39CB44B8, 0x23754F67, 0x5F017211, 0x3EBB24DA, 0x351707C6, 0x63F9774B, 0x17827288, 0x0FE74821,
0x5B5F670F, 0x48315AE8, 0x785B7769, 0x2B7A1547, 0x38D11292, 0x42A11B32, 0x35332244, 0x77437B60,
0x1EAB3B10, 0x53810000, 0x1D0212AE, 0x6F0377A8, 0x43C03092, 0x2D3C0A8E, 0x62950CBF, 0x30F06FFA,
0x34F710E0, 0x28F417FB, 0x350D2F95, 0x5A361D5A, 0x15CC060B, 0x0AFD13CC, 0x28603BCF, 0x3371066B,
0x30CD14E4, 0x175D3A67, 0x6DD66A13, 0x2D3409F9, 0x581E7B82, 0x76526B99, 0x5C8D5188, 0x2C857971,
0x15F51FC0, 0x68CC0D11, 0x49F55E5C, 0x275E4364, 0x2D1E0DBC, 0x4CEE7CE3, 0x32555840, 0x112E2E08,
0x6978065A, 0x72921406, 0x314578E7, 0x175621B7, 0x40771DBF, 0x3FC238D6, 0x4A31128A, 0x2DAD036E,
0x41A069D6, 0x25400192, 0x00DD4667, 0x6AFC1F4F, 0x571040CE, 0x62FE66DF, 0x41DB4B3E, 0x3582231F,
0x55F6079A, 0x1CA70644, 0x1B1643D2, 0x3F7228C9, 0x5F141070, 0x3E1474AB, 0x444B256E, 0x537050D9,
0x0F42094B, 0x2FD820E6, 0x778B2E5E, 0x71176D02, 0x7FEA7A69, 0x5BB54628, 0x19BA6C71, 0x39763A99,
0x178D54CD, 0x01246E88, 0x3313537E, 0x2B8E2D17, 0x2A3D10BE, 0x59D10582, 0x37A163DB, 0x30D6489A,
0x6A215C46, 0x0E1C7A76, 0x1FC760E7, 0x79B80C65, 0x27F459B4, 0x799A7326, 0x50BA1782, 0x2A116D5C,
0x63866E1B, 0x3F920E3C, 0x55023490, 0x55B56089, 0x2C391FD1, 0x2F8035C2, 0x64FD2B7A, 0x4CE8759A,
0x518504F0, 0x799501A8, 0x3F5B2CAD, 0x38E60160, 0x637641D8, 0x33352A42, 0x51A22C19, 0x085C5851,
0x032917AB, 0x2B770AC7, 0x30AC77B3, 0x2BEC1907, 0x035202D0, 0x0FA933D3, 0x61255DF3, 0x22AD06BF,
0x58B86971, 0x5FCA0DE5, 0x700D6456, 0x56A973DB, 0x5AB759FD, 0x330E0BE2, 0x5B3C0DDD, 0x495D3C60,
0x53BD59A6, 0x4C5E6D91, 0x49D9318D, 0x103D5079, 0x61CE42E3, 0x7ED5121D, 0x14E160ED, 0x212D4EF2,
0x270133F0, 0x62435A96, 0x1FA75E8B, 0x6F092FBE, 0x4A000D49, 0x57AE1C70, 0x004E2477, 0x561E7E72,
0x468C0033, 0x5DCC2402, 0x78507AC6, 0x58AF24C7, 0x0DF62D34, 0x358A4708, 0x3CFB1E11, 0x2B71451C,
0x77A75295, 0x56890721, 0x0FEF75F3, 0x120F24F1, 0x01990AE7, 0x339C4452, 0x27A15B8E, 0x0BA7276D,
0x60DC1B7B, 0x4F4B7F82, 0x67DB7007, 0x4F4A57D9, 0x621252E8, 0x20532CFC, 0x6A390306, 0x18800423,
0x19F3778A, 0x462316F0, 0x56AE0937, 0x43C2675C, 0x65CA45FD, 0x0D604FF2, 0x0BFD22CB, 0x3AFE643B,
0x3BF67FA6, 0x44623579, 0x184031F8, 0x32174F97, 0x4C6A092A, 0x5FB50261, 0x01650174, 0x33634AF1,
0x712D18F4, 0x6E997169, 0x5DAB7AFE, 0x7C2B2EE8, 0x6EDB75B4, 0x5F836FB6, 0x3C2A6DD6, 0x292D05C2,
0x052244DB, 0x149A5F4F, 0x5D486540, 0x331D15EA, 0x4F456920, 0x483A699F, 0x3B450F05, 0x3B207C6C,
0x749D70FE, 0x417461F6, 0x62B031F1, 0x2750577B, 0x29131533, 0x588C3808, 0x1AEF3456, 0x0F3C00EC,
0x7DA74742, 0x4B797A6C, 0x5EBB3287, 0x786558B8, 0x00ED4FF2, 0x6269691E, 0x24A2255F, 0x62C11F7E,
0x2F8A7DCD, 0x643B17FE, 0x778318B8, 0x253B60FE, 0x34BB63A3, 0x5B03214F, 0x5F1571F4, 0x1A316E9F,
0x7ACF2704, 0x28896838, 0x18614677, 0x1BF569EB, 0x0BA85EC9, 0x6ACA6B46, 0x1E43422A, 0x514D5F0E,
0x413E018C, 0x307626E9, 0x01ED1DFA, 0x49F46F5A, 0x461B642B, 0x7D7007F2, 0x13652657, 0x6B160BC5,
0x65E04849, 0x1F526E1C, 0x5A0251B6, 0x2BD73F69, 0x2DBF7ACD, 0x51E63E80, 0x5CF2670F, 0x21CD0A03,
0x5CFF0261, 0x33AE061E, 0x3BB6345F, 0x5D814A75, 0x257B5DF4, 0x0A5C2C5B, 0x16A45527, 0x16F23945
};
__int64 __fastcall sub_14036D380(char* szUserName, int a2, char a3, char a4)
{
unsigned int v5; // ebp
__int64 nUserNameLength; // rax
__int64 nUserNameLength2; // r13
__int64 i; // rbx
unsigned __int8 v9; // r14
unsigned __int8 v10; // si
unsigned __int8 v11; // r15
unsigned __int8 v12; // di
int v13; // eax
//_DWORD* v14; // r9
unsigned int* v14; // r9
unsigned int v15; // er11
// _DWORD* v16; // r10
unsigned int* v16; // r10
int v17; // ebp
__int64 v18; // rcx
__int64 v19; // rax
v5 = 0;
nUserNameLength = -1i64;
do
++nUserNameLength;
while (szUserName[nUserNameLength]);
nUserNameLength2 = (int)nUserNameLength;
if ((int)nUserNameLength > 0)
{
i = 0i64;
v9 = 0;
v10 = 15 * a4;
v11 = 0;
v12 = 17 * a3;
do
{
v13 = toupper((unsigned __int8)szUserName[i]);
v14 = &dword_140B9A0A0[v12];
v15 = v5 + dword_140B9A0A0[v13];
v16 = &dword_140B9A0A0[v10];
if (a2)
{
v17 = dword_140B9A0A0[(unsigned __int8)(v13 + 13)];
v18 = (unsigned __int8)(v13 + 47);
v19 = v9;
}
else
{
v17 = dword_140B9A0A0[(unsigned __int8)(v13 + 63)];
v18 = (unsigned __int8)(v13 + 23);
v19 = v11;
}
v12 += 9;
v10 += 13;
v9 += 19;
v11 += 7;
++i;
v5 = *v16 + *v14 + dword_140B9A0A0[v19] + dword_140B9A0A0[v18] * (v15 ^ v17);
} while (i < nUserNameLength2);
}
return v5;
}
char __fastcall sub_14036D330(char a1)
{
return ((a1 ^ 0x18) + 61) ^ 0xA7;
}
__int64 __fastcall sub_14036D2A0(__int16 a1)
{
unsigned int v1; // er8
v1 = (unsigned __int16)((a1 ^ 0x7892) + 19760) ^ 0x3421;
if (v1 % 0xB)
return 0i64;
else
return (unsigned __int16)(v1 / 0xB);
}
int main()
{
char szUserName[] = "010Editor";
unsigned char aPassword[8] = { 0x11, 0x22, 0x33, 0x9C, 0x55, 0x66, 0x77, 0x88};
//unsigned char aPassword[10] = { 0x11, 0x22, 0x33, 0xAC, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA };
unsigned __int16 v19; // bx
int v20; // eax
unsigned int v21; // ecx
int v25; // eax
unsigned int field_28;
unsigned int field_30 = 0x3E8;
unsigned int i, j, k, nCount;
i = 0;
nCount = 0;
// // 假设 field_30 == 0x3E8,满足 sub_14000B041((aryPassword_5 ^ aryPassword_2) + ((aryPassword_7 ^ aryPassword_1) << 8)) <= 0x3E8
for (field_30 = 0x3E8; 0 < field_30; --field_30)
{
//v25 = sub_140004A16((__int64)szUserName, v4, v22, LODWORD(pInfo->field_30));
v25 = sub_14036D380(szUserName, 1, 0, field_30);
*(unsigned int*)(aPassword + 4) = v25; // [4 ~ 7]
// 枚举 1 和 2 字符组成的数值。
for (; i <= 0xFF; ++i)
{
aPassword[0] = i; // [0]
//HIDWORD(pInfo->field_28) = (unsigned __int8)sub_140004B06(aryPassword_6 ^ aryPassword_0);
//field_28 = (unsigned __int8)sub_14036D330(aPassword[6] ^ aPassword[0]);
field_28 = ((((aPassword[6] ^ aPassword[0]) ^ 0x18) + 61) ^ 0xA7) & 0xFF;
//v21 = HIDWORD(pInfo->field_28);
v21 = field_28;
if (2 <= v21 && 0xE <= field_28)
{
//printf("%x\r\n", aPassword[0]);
break;
}
}
// 枚举 3 和 4、 5 和 6 组成的数值。
for (j = 0; j <= 0xFF; ++j)
{
for (k = 0; k <= 0xFF; ++k)
{
aPassword[1] = j; // [1]
aPassword[2] = k; // [2]
//v19 = (unsigned __int8)(aryPassword_5 ^ aryPassword_2) + ((unsigned __int8)(aryPassword_7 ^ aryPassword_1) << 8);
v19 = (unsigned __int8)(aPassword[5] ^ aPassword[2]) + ((unsigned __int8)(aPassword[7] ^ aPassword[1]) << 8);
v20 = (unsigned __int16)sub_14036D2A0(v19);
if (v20 && field_30 == v20) // field_30 = (unsigned __int16)v20;
{
++nCount;
//printf("%02X%02X\r\n", aPassword[1], aPassword[1]);
printf("%04d %04X %02X%02X-%02X%02X-%02X%02X-%02X%02X\r\n", nCount, field_30, aPassword[0], aPassword[1], aPassword[2], aPassword[3], aPassword[4], aPassword[5], aPassword[6], aPassword[7]);
}
}
}
++i;
}
system("pause");
}
验证注册机生成的密码
四、网络验证
网络验证失败
在 sub_140210520() 函数中,通过字符串内容可以判断出 sub_14000695B() 用于网络验证。只有当 sub_14000695B() 函数返回值 大于 0 时,表示网络验证成功。
进入 sub_14000695B() 函数内,函数内部只有三处 return。sub_14000695B() 函数第一个参数为 0 时,返回 -1,第二参数为非零时,则返回 0。但是 sub_14000695B() 函数的第二个参数已经写死为 0 了。而且 sub_14000B3111() 函数的返回值一定是零。
在 sub_14000695B() 函数内调用 sub_14000B3111() 函数处下断点。观察传入参数,第二个参数是一个 URL,而第三个参数后面需要 free,应该是一个堆空间的指针。
进入 sub_14000B3111() 函数。
进入 sub_14000AC63() 函数
获取网络验证结果。
分析 sub_140002342() 函数
服务使用的 HTTPS/HTTP 进行的网络验证,使用 Fidder 看看数据包。
可以看到网络验证失败返回的信息是 "Invalid",而且没有 Id 信息。
这里可以改写本机的 DNS 配置,将 "127.0.0.1 www.sweetscape.com" 写入到hosts 文件,然后重新刷新 DNS 缓存 ipconfig /flushdns,然后重启电脑。
通过 python 编写一个简单 HTTP Server,返回的验证状态为 valid,并设置一个 Id。
from http.server import HTTPServer, BaseHTTPRequestHandler
class MyHttpRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
data = "<ss>valid</ss>\r\n<id>20221126</id>".encode('GBK')
nDataLength = len(data)
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.send_header('Content-Length', nDataLength.__str__())
self.end_headers()
self.wfile.write(data)
def run():
httpd = HTTPServer(('127.0.0.1', 80), MyHttpRequestHandler)
httpd.serve_forever()
if __name__ == '__main__':
run()
验证
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构