EasyUEFI 离线注册分析
离线注册分析
仅做离线分析,文件版本5.3.0.2
目录
一、注册码分析
0、 通过字符信息、窗口事件、调用栈等信息定位到CUpgradeDlg
1、分析CUpgradeDlg metaClass 并根据虚表定位构造函数,
metaClass :
.text:00673220 CUpgradeDlg_mate_673220 proc near ; DATA XREF: .rdata:006759C4↓o
.text:00673220 000 6A 0C push 0Ch
.text:00673222 004 6A 04 push 4
.text:00673224 008 68 10 96 81 00 push offset CUpgradeDlg_map_819610
.text:00673229 00C 68 74 86 8D 00 push offset parent_metaClass_8D8674
.text:0067322E 010 68 60 80 44 00 push offset CUpgradeDlg_manufacture_448060
.text:00673233 014 68 28 E8 87 00 push offset aCupgradedlg ; "CUpgradeDlg"
.text:00673238 018 B9 90 DA 8F 00 mov ecx, offset dword_8FDA90
.text:0067323D 018 E8 5C 28 F1 FF call FX__FXMetaClass__metaClass_585A9E ; const FXchar* name,FXObject *(fac)(),const FXMetaClass* base,const void* ass,FXuint nass,FXuint assz
.text:00673242 000 68 C0 48 67 00 push offset sub_6748C0 ; void (__cdecl *)()
.text:00673247 004 E8 FC C4 F6 FF call _atexit
.text:0067324C 004 59 pop ecx
.text:0067324D 000 C3 retn
.text:0067324D CUpgradeDlg_mate_673220 endp
2、构造函数分析,获取控件id组成
得到Register 注册按钮id为0x40
3、进而分析CUpgradeDlg_map_819610 定位控件事件
register_CUpgradeDlg_21_id40_448DE0
激活码格式XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXX (输入时自动‘-’拼接)
int __thiscall register_CUpgradeDlg_21_id40_448DE0(CUpgradeDlg *this, int a2, int a3, int a4)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
v43 = a2;
v44 = a4;
email = (char *)this->email_98;
memset(rsa_publick_dec, 0, sizeof(rsa_publick_dec));
memset(appversion, 0, sizeof(appversion));
ver2[0] = 0;
ver1 = 0;
sub_408680(email, (int)&s_email); // support@hasleo.com
v50 = 0;
sub_408680((char *)this->CLicenseInputTextField_9C, (int)&s_license);
LOBYTE(v50) = 1;
memset(ws_email_1, 0, 0x100);
memset(ws_license, 0, 0x6C);
v7 = AppVersion_44FF00(appversion);
v8 = v6;
v40 = v6;
if ( !(_WORD)v6 )
{
v9 = fxstring_580929((void **)&s_email);
fxstring_5805EF((void **)&s_email, v9);
if ( !*((_DWORD *)s_email + 0xFFFFFFFF) )
{
v10 = GetLastError() + 0xD001F000000000i64;
v8 = HIDWORD(v10);
v7 = v10;
v35 = v10;
v34 = 0xD1;
LABEL_57:
v40 = v8;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", v34, v35);
goto LABEL_58;
}
v11 = fxstring_580929((void **)&s_license);
fxstring_5805EF((void **)&s_license, v11);
if ( !*((_DWORD *)s_license + 0xFFFFFFFF) )
{
v12 = GetLastError() + 0xD701F100000000i64;
v8 = HIDWORD(v12);
v7 = v12;
v35 = v12;
v34 = 0xD8;
goto LABEL_57;
}
if ( !s_email
|| v37 == (_BYTE *)0xFFFFFF2C
|| MultiByteToWideChar(0xFDE9u, 0, s_email, 0xFFFFFFFF, ws_email_1, 0x80) <= 0 )
{
v13 = GetLastError() + 0xDE000E00000000i64;
v8 = HIDWORD(v13);
v7 = v13;
v35 = v13;
v34 = 0xDF;
goto LABEL_57;
}
if ( !s_license
|| v37 == (_BYTE *)0xFFFFFF9C
|| MultiByteToWideChar(0xFDE9u, 0, s_license, 0xFFFFFFFF, ws_license, 0x36) <= 0 )
{
v14 = GetLastError() + 0xE4000E00000000i64;
v8 = HIDWORD(v14);
v7 = v14;
v35 = v14;
v34 = 0xE5;
goto LABEL_57;
}
license_format_455420((int)ws_license, ws_license);
++this->field_A4;
v7 = check_rsa_pubk_dec_47D1D0(ws_email_1, ws_license, rsa_publick_dec);
v8 = v15;
v40 = v15;
if ( (_WORD)v15 )
{
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", 0xEE, v7, v15);
goto LABEL_58;
}
v7 = sub_47D430(rsa_publick_dec, ver2, &ver1);
v8 = v16;
v40 = v16;
if ( (_WORD)v16 )
{
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", 0xF4, v7, v16);
goto LABEL_58;
}
if ( ver2[0] != 1 || rsa_publick_dec[1] != 1 )
{
v32 = GetLastError() + 0xF901F100000000i64;// Invalid license key.
v8 = HIDWORD(v32);
v7 = v32;
v35 = v32;
v34 = 0xFA;
goto LABEL_57;
}
if ( (unsigned __int8)(ver1 - 1) > 5u || ver1 == 6 || ver1 == 5 )
{
v31 = GetLastError() + 0x10001F100000000i64;
v8 = HIDWORD(v31);
v7 = v31;
v35 = v31;
v34 = 0x101;
goto LABEL_57;
}
if ( rsa_publick_dec[3] || (v17 = rsa_publick_dec[8] & 0xF, (rsa_publick_dec[8] & 0xF) != 0) && v17 != 1 && v17 != 2 )
{
v30 = GetLastError() + 0x10701F100000000i64;
v8 = HIDWORD(v30);
v7 = v30;
v35 = v30;
v34 = 0x108;
goto LABEL_57;
}
// "5.3.0.2"
if ( appversion[0] > (unsigned int)(unsigned __int8)rsa_publick_dec[2] && (ver1 == 4 || ver1 == 2) )
{
v18 = GetLastError() + 0x11001F100000000i64;
v8 = HIDWORD(v18);
v7 = v18;
v35 = v18;
v34 = 0x111;
goto LABEL_57;
}
if ( (ver1 == 3 || ver1 == 1)
&& v17 == 2
&& rsa_publick_dec[0x11]
&& _time64(0) >= *(_DWORD *)&rsa_publick_dec[4] + 2678400 * (unsigned int)(unsigned __int8)rsa_publick_dec[0x11] )// rsa_publick_dec[0x11] 月
{
v19 = GetLastError() + 0x11B01F100000000i64;
v8 = HIDWORD(v19);
v7 = v19;
v35 = v19;
v34 = 0x11C;
goto LABEL_57;
}
unknowclass_4500E0 = get_unknowclass_4500E0();
v21 = do_net_check_4502D0((int)ws_license, unknowclass_4500E0, 0) & 0xFFF;// net_check
if ( v21 <= 9 )
{
if ( v21 == 9 || !v21 ) // 9 时离线
{
this->Active_status_B4 = v21;
fxstring_5805EF((void **)&this->s_email_A8, (void **)&s_email);// [esp+20]:"support@hasleo.com"
fxstring_5805EF((void **)&this->s_license_AC, (void **)&s_license);
v36 = v44;
this->ver1_B0 = (unsigned __int8)ver1;
v22 = sub_585C8E(this, v43, a3, v36);
LABEL_42:
v23 = v22;
LOBYTE(v50) = 0;
FX::FXString::~FXString((void **)&s_license);
v50 = 0xFFFFFFFF;
FX::FXString::~FXString((void **)&s_email);
return v23;
}
goto LABEL_51;
}
if ( v21 > 0xE )
{
if ( v21 == 0xF )
{
v29 = GetLastError() + 0x13D01F300000000i64;// Your license has expired, please renew it to continue using this software.
v8 = HIDWORD(v29);
v7 = v29;
v35 = v29;
v34 = 0x13E;
goto LABEL_57;
}
if ( v21 != 0xFFF )
goto LABEL_51;
}
else
{
if ( v21 == 0xE )
{
v26 = GetLastError() + 0x13701F500000000i64;// The license key has been disabled.
v8 = HIDWORD(v26);
v7 = v26;
v35 = v26;
v34 = 0x138;
goto LABEL_57;
}
if ( v21 != 0xA )
{
if ( v21 == 0xD )
{
v25 = GetLastError() + 0x13101F400000000i64;// The license key has exceeded the number of activations allowed.
v8 = HIDWORD(v25);
v7 = v25;
v35 = v25;
v34 = 0x132;
goto LABEL_57;
}
LABEL_51:
v27 = GetLastError() + 0x14301F600000000i64;// Activation failed.
v8 = HIDWORD(v27);
v7 = v27;
v35 = v27;
v34 = 0x144;
goto LABEL_57;
}
}
v28 = GetLastError() + 0x12601F100000000i64;
v8 = HIDWORD(v28);
v7 = v28;
v35 = v28;
v34 = 0x127;
goto LABEL_57;
}
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", 0xC9, v7, v6);
LABEL_58:
v46 = 0;
v33 = (unsigned __int16)(((unsigned __int64)GetLastError() + 0x1F100000000i64) >> 0x20);
if ( v46 || v33 != (unsigned __int16)v40 )
{
if ( (unsigned __int16)v40 | v46 )
error_402CA0(this, this->FXApp_90, v7, v8, 0);
}
else
{
error_402CA0(this, this->FXApp_90, v7, v8, 0);
if ( this->field_A4 >= 3u )
{
v22 = sub_585CAD(this, v43, a3, v44);
goto LABEL_42;
}
}
LOBYTE(v50) = 0;
FX::FXString::~FXString((void **)&s_license);
v50 = 0xFFFFFFFF;
FX::FXString::~FXString((void **)&s_email);
return 1;
}
check_rsa_pubk_dec_47D1D0
对注册码进行自定义base32解码,再进行RSA公钥解密
自定义字符表为ABCDEFGHJKLMNPQRSTUVWXYZ23456789
rsa解密后为0x1e字节,最后一位为crc8校验值
int __usercall check_rsa_pubk_dec_47D1D0@<eax>(
const unsigned __int16 *ws_email_1@<edx>,
const wchar_t *ws_license@<ecx>,
char *rsa_enc)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
memset(str_license, 0, 0x31);
v21 = 0;
memset(dec, 0, sizeof(dec));
v5 = wcslen(ws_email_1);
if ( ws_license && wcslen(ws_license) == 48 && ws_email_1 && v5 )
{
str_email = (char *)malloc(v5 + 1);
v7 = str_email;
if ( str_email )
{
if ( v5 == wcstombs(str_email, ws_email_1, v5 + 1) )
{
_strupr(v7);
if ( wcstombs(str_license, ws_license, 49u) == 48 )
{
_strupr(str_license);
v8 = custom_base32_decode_47D0A0(dec, str_license);
if ( (_WORD)v12 )
{
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x2A0, v8, v12);
}
else
{
v8 = rsa_dec_47CEF0(dec, rsa_enc);
if ( v13 )
{
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", v18, 0x2A7, v8);
}
else
{
v14 = rsa_enc[0x1D];
rsa_enc[0x1D] = 0;
if ( v14 != (unsigned __int8)CRC8_47D7E0(0, (unsigned __int8 *)rsa_enc) )
{
v15 = GetLastError() + 0x2AF01F100000000i64;
v8 = v15;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x2B0, v15);
}
v7 = *(char **)dec;
}
}
}
else
{
v11 = GetLastError() + 0x297000E00000000i64;
v8 = v11;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x298, v11);
}
}
else
{
v10 = GetLastError() + 0x28F000E00000000i64;
v8 = v10;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x290, v10);
}
}
else
{
v9 = GetLastError() + 0x289000300000000i64;
v8 = v9;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x28A, v9);
}
if ( v7 )
free(v7);
}
else
{
v17 = GetLastError() + 0x28101F100000000i64;
v8 = v17;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x282, v17);
}
return v8;
}
rsa_dec_47CEF0
int __thiscall rsa_dec_47CEF0(char *data, char *out)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
v2 = 0;
memset(rsa_PUBLICkey, 0, 0x1000u);
qmemcpy(
rsa_PUBLICkey,
"-----BEGIN RSA PUBLIC KEY-----\n"
"MCYCHwC9s2qhNcaeKtlin3VtwnU9Vv4x/j0wBPS43F/8eKMCAwEAAQ==\n"
"-----END RSA PUBLIC KEY-----\n",
0x75u);
v3 = BIO_new_mem_buf(rsa_PUBLICkey, 0x75);
v4 = v3;
if ( v3 )
{
bio_SSL_SESSION = PEM_read_bio_SSL_SESSION(v3, 0, 0, 0);
v7 = bio_SSL_SESSION;
if ( bio_SSL_SESSION )
{
// static int RSA_eay_public_encrypt(int flen, const unsigned char *from,
// unsigned char *to, RSA *rsa, int padding)
if ( RSA_eay_public_decrypt_602D40(0x1E, (int)data, (int)out, (int)bio_SSL_SESSION, 3) < 0 )
{
v9 = GetLastError() + 0x13D000200000000i64;
v2 = v9;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x13E, v9);
}
}
else
{
v8 = GetLastError() + 0x135007200000000i64;
v2 = v8;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x136, v8);
}
BIO_free_all(v4);
if ( v7 )
RSA_free(v7);
}
else
{
v5 = GetLastError() + 0x12D000300000000i64;
v2 = v5;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x12E, v5);
}
CRYPTO_cleanup_all_ex_data();
return v2;
}
校验注册码信息
/*
if (license_info[8]&0xf)!=0:
if (license_info[8]&0xf)==1 or (license_info[8]&0xf)==2:
ver2=license_info[0]
ver1=license_info[0x10]
else:
error
else:
ver2=license_info[0]&0x1f
ver1=license_info[0]>>5
*/
v7 = sub_47D430(rsa_publick_dec, ver2, &ver1);
v8 = v16;
v40 = v16;
if ( (_WORD)v16 )
{
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", 0xF4, v7, v16);
goto LABEL_58;
}
//ver2==1 license_info[1]==1
if ( ver2[0] != 1 || rsa_publick_dec[1] != 1 )
{
v32 = GetLastError() + 0xF901F100000000i64;// Invalid license key.
v8 = HIDWORD(v32);
v7 = v32;
v35 = v32;
v34 = 0xFA;
goto LABEL_57;
}
//ver1<5
if ( (unsigned __int8)(ver1 - 1) > 5u || ver1 == 6 || ver1 == 5 )
{
v31 = GetLastError() + 0x10001F100000000i64;
v8 = HIDWORD(v31);
v7 = v31;
v35 = v31;
v34 = 0x101;
goto LABEL_57;
}
//license_info[3]==0
//(license_info[8] & 0xF)==0 or 1 or 2
if ( rsa_publick_dec[3] || (v17 = rsa_publick_dec[8] & 0xF, (rsa_publick_dec[8] & 0xF) != 0) && v17 != 1 && v17 != 2 )
{
v30 = GetLastError() + 0x10701F100000000i64;
v8 = HIDWORD(v30);
v7 = v30;
v35 = v30;
v34 = 0x108;
goto LABEL_57;
}
// "5.3.0.2"
//5<=license_info[2]
//ver1!=2 ver1!=4
if ( appversion[0] > (unsigned int)(unsigned __int8)rsa_publick_dec[2] && (ver1 == 4 || ver1 == 2) )
{
v18 = GetLastError() + 0x11001F100000000i64;
v8 = HIDWORD(v18);
v7 = v18;
v35 = v18;
v34 = 0x111;
goto LABEL_57;
}
/*
(ver1!=1 and ver1!=3) ||
(license_info[8] & 0xF)!=2 ||
license_info[0x11]==0 ||
(time(2)>license_info[4] + 2678400 *license_info[0x11])
*/
if ( (ver1 == 3 || ver1 == 1)
&& v17 == 2
&& rsa_publick_dec[0x11]
&& _time64(0) >= *(_DWORD *)&rsa_publick_dec[4] + 2678400 * (unsigned int)(unsigned __int8)rsa_publick_dec[0x11] )// rsa_publick_dec[0x11] 月
{
v19 = GetLastError() + 0x11B01F100000000i64;
v8 = HIDWORD(v19);
v7 = v19;
v35 = v19;
v34 = 0x11C;
goto LABEL_57;
}
unknowclass_4500E0 = get_unknowclass_4500E0();
v21 = do_net_check_4502D0((int)ws_license, unknowclass_4500E0, 0) & 0xFFF;// net_check
if ( v21 <= 9 )
{
if ( v21 == 9 || !v21 ) // 9 时离线
{
this->Active_status_B4 = v21;
fxstring_5805EF((void **)&this->s_email_A8, (void **)&s_email);// [esp+20]:"support@hasleo.com"
fxstring_5805EF((void **)&this->s_license_AC, (void **)&s_license);
v36 = v44;
this->ver1_B0 = (unsigned __int8)ver1;
v22 = sub_585C8E(this, v43, a3, v36);
LABEL_42:
v23 = v22;
LOBYTE(v50) = 0;
FX::FXString::~FXString((void **)&s_license);
v50 = 0xFFFFFFFF;
FX::FXString::~FXString((void **)&s_email);
return v23;
}
goto LABEL_51;
}
sub_47D430
int __fastcall sub_47D430(char *rsa_publick_dec, char *ver2, char *ver1)
{
int result; // eax
__int64 v4; // kr00_8
result = 0;
if ( (*((_WORD *)rsa_publick_dec + 4) & 0xF) != 0 )
{
// +8 低4bit 不等于0时,值应为1或2
if ( (*((_WORD *)rsa_publick_dec + 4) & 0xF) == 1 )
{
*ver2 = *rsa_publick_dec;
*ver1 = rsa_publick_dec[0x10];
}
else if ( (*((_WORD *)rsa_publick_dec + 4) & 0xF) == 2 )
{
*ver2 = *rsa_publick_dec;
*ver1 = rsa_publick_dec[0x10];
}
else
{
v4 = GetLastError() + 0x33301F100000000i64;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x334, v4);
return v4;
}
}
else
{
// 取首字节 5bit
*ver2 = *rsa_publick_dec & 0x1F;
// (首字节>>5)
*ver1 = (unsigned __int8)*rsa_publick_dec >> 5;
}
return result;
}
二、离线激活码分析
定位COfflineActiveDlg控件事件
ok_440920
int __thiscall ok_440920(COfflineActiveDlg *this, int a2, int a3, int a4)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
License_Code_98 = (char *)this->License_Code_98;
v30 = a2;
v29 = a4;
sub_408680(License_Code_98, (int)&License_Code);
v34 = 0;
sub_408680((char *)this->Machine_Code_A0, (int)Machine_Code);
LOBYTE(v34) = 1;
sub_408680((char *)this->FXTextField_Activation_Code_A8, (int)&Activation_Code);
LOBYTE(v34) = 2;
memset(ws_License_Code, 0, sizeof(ws_License_Code));
memset(ws_Activation_Code, 0, 0x100);
v6 = fxstring_580929((void **)&License_Code);
fxstring_5805EF((void **)&License_Code, v6);
if ( *((_DWORD *)License_Code + 0xFFFFFFFF) )
{
v10 = fxstring_580929(Machine_Code);
fxstring_5805EF(Machine_Code, v10);
if ( *((_DWORD *)Machine_Code[0] + 0xFFFFFFFF) )
{
v12 = fxstring_580929((void **)&Activation_Code);
fxstring_5805EF((void **)&Activation_Code, v12);
if ( *((_DWORD *)Activation_Code + 0xFFFFFFFF) )
{
if ( License_Code
&& &v24 != (int *)0xFFFFFFCC
&& MultiByteToWideChar(0xFDE9u, 0, License_Code, 0xFFFFFFFF, ws_License_Code, 0x80) > 0 )
{
if ( tows_43F490(Activation_Code, ws_Activation_Code) > 0 )
{
++this->field_B4;
unknowclass_4500E0 = get_unknowclass_4500E0();
if ( (unline_check_450320(ws_License_Code, ws_Activation_Code, unknowclass_4500E0) & 0xFFF) == 0 )
{
v19 = sub_585C8E((CUpgradeDlg *)this, a2, a3, v29);
goto LABEL_23;
}
v17 = GetLastError() + 0x11A01F700000000i64;// "Activation code is incorrect."
v7 = HIDWORD(v17);
v8 = v17;
v23 = v17;
v22 = 0x11B;
}
else
{
v15 = GetLastError() + 0x111000E00000000i64;// "The specified string is invalid."
v7 = HIDWORD(v15);
v8 = v15;
v23 = v15;
v22 = 0x112;
}
}
else
{
v14 = GetLastError() + 0x10A000E00000000i64;
v7 = HIDWORD(v14);
v8 = v14;
v23 = v14;
v22 = 0x10B;
}
}
else
{
v13 = GetLastError() + 0x103000D00000000i64;// "The specified string is an empty string."
v7 = HIDWORD(v13);
v8 = v13;
v23 = v13;
v22 = 0x104;
}
}
else
{
v11 = GetLastError() + 0xFC000D00000000i64;
v7 = HIDWORD(v11);
v8 = v11;
v23 = v11;
v22 = 0xFD;
}
}
else
{
v9 = GetLastError() + 0xF5000D00000000i64;
v7 = HIDWORD(v9);
v8 = v9;
v23 = v9;
v22 = 0xF6;
}
v28 = v7;
log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\OfflineActiveDlg.cpp", v22, v23);
v31 = 0;
v18 = (unsigned __int16)(((unsigned __int64)GetLastError() + 0x1F700000000i64) >> 0x20);
if ( v31 || v18 != (unsigned __int16)v7 )
{
if ( (unsigned __int16)v28 | v31 )
error_402CA0(this, this->FXApp_90, v8, v7, 0);
goto LABEL_21;
}
error_402CA0(this, this->FXApp_90, v8, v7, 0);
if ( this->field_B4 < 3u )
{
LABEL_21:
LOBYTE(v34) = 1;
FX::FXString::~FXString((void **)&Activation_Code);
LOBYTE(v34) = 0;
FX::FXString::~FXString(Machine_Code);
v34 = 0xFFFFFFFF;
FX::FXString::~FXString((void **)&License_Code);
return 1;
}
v19 = sub_585CAD(this, v30, a3, v29);
LABEL_23:
v21 = v19;
LOBYTE(v34) = 1;
FX::FXString::~FXString((void **)&Activation_Code);
LOBYTE(v34) = 0;
FX::FXString::~FXString(Machine_Code);
v34 = 0xFFFFFFFF;
FX::FXString::~FXString((void **)&License_Code);
return v21;
}
unline_check_450320
// ws_License_Code, ws_Activation_Code
int __usercall unline_check_450320@<eax>(
wchar_t *ws_License_Code@<edx>, // 注册码
wchar_t *ws_Activation_Code@<ecx>, // 激活码
UnknowClass *a3@<esi>)
{
int result; // eax
int v5; // edi
result = 0x7601001;
if ( !a3->CActiveOnline_obj_8FDCF4 || !ws_License_Code || !ws_Activation_Code )
return result;
result = a3->CActiveOnline_obj_8FDCF4->vftable_0->Init_490DD0(// CActiveOnline_vft+0xc
(int)a3->CActiveOnline_obj_8FDCF4,
L"EasyUEFI",
ws_License_Code,
1);
if ( (result & 0xFFF) != 0 )
return result;
v5 = a3->CActiveOnline_obj_8FDCF4->vftable_0->sub_491730(
(_DWORD *)a3->CActiveOnline_obj_8FDCF4,
ws_Activation_Code,
wcslen(ws_Activation_Code));
a3->CActiveOnline_obj_8FDCF4->vftable_0->sub_490EE0((_DWORD *)a3->CActiveOnline_obj_8FDCF4);
return v5;
}
Init_490DD0
int __thiscall Init_490DD0(CActiveOnline *this, const wchar_t *productname, const wchar_t *ws_License_Code, int a4)
{
int v5; // esi
const wchar_t *v6; // eax
DWORD LastError; // eax
if ( this->dword8 )
{
v5 = 0x3901004;
}
else
{
v6 = productname;
if ( productname )
{
while ( *v6++ )
;
if ( v6 - (productname + 1) )
{
if ( ws_License_Code )
{
if ( wcslen(ws_License_Code) >= 48 )
{
this->gapC = a4;
sub_490D20(this);
v5 = transform_498770(&this->vec_char_Activation_Code_table_50);
if ( (v5 & 0xFFF) == 0 )
{
std::wstring::operator+=((std::wstring *)&this->productname_E8, productname);
std::wstring::operator+=((std::wstring *)&this->ws_License_Code_104, ws_License_Code);
remove_bar_4994B0((std::wstring *)&this->ws_License_Code_104);
this->dword8 = 1;
}
}
else
{
v5 = 0x3D01002;
}
}
else
{
v5 = 0x3C01002;
}
}
else
{
v5 = 0x3B01002;
}
}
else
{
v5 = 0x3A01002;
}
}
if ( (v5 & 0xFFF) != 0 )
{
LastError = GetLastError();
flog_496C40(L"[A] Init failed! uReturn = %x SysErr = %d", v5, LastError);
}
else
{
flog_496C40(L"[A] Init success.");
}
return v5;
}
校验激活码sub_491730
1、激活码根据字母表进行替换
2、根据‘|’进行分隔成4部分
3、
第1部分hex字符串为“8000”或“8001"
第2部分为license_md5[8:8+8]
第3部分为machine_code_md5[8:8+8]
第4部分为machine_code机器码
// local variable allocation has failed, the output may be wrong!
CActiveOnline *__thiscall sub_491730(CActiveOnline *this, void *Activation_Code, int Activation_Code_size)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
v27 = this;
tf_active_code._Myres = 7;
tf_active_code._Mysize = 0;
tf_active_code.u._Buf[0] = 0;
v61 = 6;
part1._Myres = 7;
part1._Mysize = 0;
part1.u._Buf[0] = 0;
part2._Myres = 7;
part2._Mysize = 0;
part2.u._Buf[0] = 0;
part3._Myres = 7;
part3._Mysize = 0;
part3.u._Buf[0] = 0;
part4._Myres = 7;
part4._Mysize = 0;
part4.u._Buf[0] = 0;
memset(plicense, 0, sizeof(plicense));
v45 = 0;
*(_DWORD *)v46 = 0;
v47 = 0;
v53 = 0;
*(_DWORD *)_Ptr = 0;
v55 = 0;
v56 = 0;
*(_DWORD *)v57 = 0;
v58 = 0;
v59 = 0;
v49 = 0;
*(_DWORD *)v50 = 0;
v51 = 0;
p2 = 0;
pmachine_code = 0;
p3 = 0;
v42 = 0xF;
v41 = 0;
LOBYTE(v40) = 0;
v37 = 0xF;
v36 = 0;
LOBYTE(v35) = 0;
v28 = operator new(1u);
LOBYTE(v61) = 7;
if ( this->dword8 )
{
if ( Activation_Code )
{
if ( Activation_Code_size )
{
wstring_43D4C0(&tf_active_code, Activation_Code, wcslen((const unsigned __int16 *)Activation_Code));
//激活码根据字母表进行替换
v26 = (CActiveOnline *)vec_498A40(
&this->vec_char_Activation_Code_table_50,
(int)&tf_active_code,
(int)&tf_active_code);
if ( ((unsigned __int16)v26 & 0xFFF) == 0 )
{
p_part3 = &part3;
v26 = (CActiveOnline *)&v24;
std::wstring::wstring((std_wstring_d *)&v24, (const std::wstring *)&tf_active_code);
//根据‘|’进行分隔成4部分
v26 = (CActiveOnline *)split_492500(&part4, &part2, &part1, (std_wstring_d)v24, p_part3);
if ( ((unsigned __int16)v26 & 0xFFF) == 0 )
{
BUF = (union std_wstring_union *)part1.u._Ptr;
if ( part1._Myres < 8 )
BUF = &part1.u;
//第一部分hex字符串为8000h或8001h
v5 = wcstol(BUF->_Buf, 0, 0x10) - 0x8000;
if ( v5 > 17 )
v26 = (CActiveOnline *)0x2E401001;
else
v26 = (CActiveOnline *)sub_4926A0(v5);// case 0:case 1: result = 0;
if ( ((unsigned __int16)v26 & 0xFFF) == 0 )
{
v6 = v27;
p_wstring_debug_machine_code_120 = &v27->wstring_debug_machine_code_120;
//第4部分为机器码
if ( compare_495110(&v27->wstring_debug_machine_code_120, &part4) )
{
if ( part2._Mysize == 8 || part3._Mysize == 8 )
{
Ptr = (union std_wstring_union *)part2.u._Ptr;
if ( part2._Myres < 8 )
Ptr = &part2.u;
WideCharToMultiByte(0, 0, Ptr->_Buf, 0xFFFFFFFF, &p2, 0xA, 0, 0);
p_u = (union std_wstring_union *)part3.u._Ptr;
if ( part3._Myres < 8 )
p_u = &part3.u;
WideCharToMultiByte(0, 0, p_u->_Buf, 0xFFFFFFFF, &p3, 0xA, 0, 0);
if ( v6->ws_License_Code_104._Myres < 8 )
v10 = v6->ws_License_Code_104.u._Buf;
else
v10 = v6->ws_License_Code_104.u._Ptr;
WideCharToMultiByte(0, 0, v10, 0xFFFFFFFF, plicense, 0x40, 0, 0);
if ( p_wstring_debug_machine_code_120->_Myres < 8 )
v11 = p_wstring_debug_machine_code_120->u._Buf;
else
v11 = p_wstring_debug_machine_code_120->u._Ptr;
WideCharToMultiByte(0, 0, v11, 0xFFFFFFFF, &pmachine_code, 0x18, 0, 0);
temp_str = (int)&v24.u._Ptr;
std::string::string((std::string *)&v24.u, plicense);
v12 = (const std::string *)md5_4986F0(&twstr, *(std_string_d *)v24.u._Buf);
LOBYTE(v61) = 8;
std::string::assign((std::string *)lic_md5, v12, 0, 0xFFFFFFFF);
LOBYTE(v61) = 7;
std::string::~string((int)&twstr);
temp_str = (int)&v24.u._Ptr;
std::string::string((std::string *)&v24.u, &pmachine_code);
v13 = (const std::string *)md5_4986F0(&twstr, *(std_string_d *)v24.u._Buf);
LOBYTE(v61) = 9;
std::string::assign((std::string *)v34, v13, 0, 0xFFFFFFFF);
LOBYTE(v61) = 7;
std::string::~string((int)&twstr);
v14 = (std_wstring_d *)std::string::substr(
(std::basic_string<char,std::char_traits<char>,glitch::core::SAllocator<char,0> > *)lic_md5,
(std::basic_string<char,std::char_traits<char>,glitch::core::SAllocator<char,0> > *)&twstr,
8u,
8u);
if ( v14->_Myres < 0x10 )
v15 = &v14->u;
else
v15 = (union std_wstring_union *)v14->u._Ptr;
v16 = strcmp((const char *)v15, &p2);// 第2部分为license_md5[8:8+8]
std::string::~string((int)&twstr);
if ( v16 )
{
v26 = (CActiveOnline *)0x14B01003;
}
else
{
v20 = (std_wstring_d *)std::string::substr(
(std::basic_string<char,std::char_traits<char>,glitch::core::SAllocator<char,0> > *)v34,
(std::basic_string<char,std::char_traits<char>,glitch::core::SAllocator<char,0> > *)&twstr,
8u,
8u);
if ( v20->_Myres < 0x10 )
v21 = &v20->u;
else
v21 = (union std_wstring_union *)v20->u._Ptr;
v22 = strcmp((const char *)v21, &p3);// 第3部分为machine_code_md5[8:8+8]
std::string::~string((int)&twstr);
if ( v22 )
v26 = (CActiveOnline *)0x14C01003;
}
}
else
{
v26 = (CActiveOnline *)0x14401003;
}
}
else
{
v26 = (CActiveOnline *)0x1420100B;
}
}
}
}
}
else
{
v26 = (CActiveOnline *)0x12801002;
}
}
else
{
v26 = (CActiveOnline *)0x12701002;
}
}
else
{
v26 = (CActiveOnline *)0x12501004;
}
sub_48F3B0((CActiveOnline *)&v27->wstring_www_com_6C);
v17 = v26;
v18 = (union std_wstring_union *)part1.u._Ptr;
if ( ((unsigned __int16)v26 & 0xFFF) != 0 )
{
if ( part1._Myres < 8 )
v18 = &part1.u;
p_part3 = (std_wstring_d *)v18;
LastError = GetLastError();
flog_496C40(L"[A] AutoActive failed! uReturn = %x SysErr = %d wsStatus = %s", v17, LastError);
}
else
{
if ( part1._Myres < 8 )
v18 = &part1.u;
flog_496C40(L"[A] AutoActive success. wsStatus = %s", v18);
}
operator delete(v28);
if ( v37 >= 0x10 )
operator delete(v35);
v37 = 0xF;
v36 = 0;
LOBYTE(v35) = 0;
if ( v42 >= 0x10 )
operator delete(v40);
v42 = 0xF;
v41 = 0;
LOBYTE(v40) = 0;
if ( part4._Myres >= 8 )
operator delete(part4.u._Ptr);
part4._Myres = 7;
part4._Mysize = 0;
part4.u._Buf[0] = 0;
if ( part3._Myres >= 8 )
operator delete(part3.u._Ptr);
part3._Myres = 7;
part3._Mysize = 0;
part3.u._Buf[0] = 0;
if ( part2._Myres >= 8 )
operator delete(part2.u._Ptr);
part2._Myres = 7;
part2._Mysize = 0;
part2.u._Buf[0] = 0;
if ( part1._Myres >= 8 )
operator delete(part1.u._Ptr);
part1._Myres = 7;
part1._Mysize = 0;
part1.u._Buf[0] = 0;
if ( tf_active_code._Myres >= 8 )
operator delete(tf_active_code.u._Ptr);
return v26;
}
py
'''
pip install pycryptodome
'''
import base64
import ctypes
import io
import os
import random
from typing import Union
from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse
import hashlib
import time
from datetime import datetime
def convert_to_time64(time_str):
# 解析时间字符串为 datetime 对象
dt_obj = datetime.strptime(time_str, r"%Y-%m-%d %H:%M:%S")
# 将 datetime 对象转换为时间戳
timestamp = dt_obj.timestamp()
# # 将时间戳转换为 _time64 格式
# time64 = int(timestamp * 1e7) # 1e7 是将秒转换为 100 纳秒的单位
time64 = int(timestamp)
return time64
def convert_to_time_string(time64):
# 将 _time64 格式的时间戳转换为秒数
# timestamp = time64 / 1e7 # 将 100 纳秒转换为秒
# 使用 fromtimestamp 将秒数转换为 datetime 对象
dt_obj = datetime.fromtimestamp(time64)
# 使用 strftime 方法将 datetime 对象格式化为时间字符串
time_str = dt_obj.strftime("%Y-%m-%d %H:%M:%S")
return time_str
pubk = "-----BEGIN RSA PUBLIC KEY-----\n"\
"MCYCHwC9s2qhNcaeKtlin3VtwnU9Vv4x/j0wBPS43F/8eKMCAwEAAQ==\n"\
"-----END RSA PUBLIC KEY-----\n"
def rsa_pk_enc(data: bytes) -> bytes:
# http://factordb.com/index.php?query=1309267119417726280330942057320079958095363483536018220587938405183944867
# e=65537
p = 1138829745998159918316484590691394789
q = 1149660099780921729474053823339894503
n = p*q
# phi = (p - 1) * (q - 1)
# d = inverse(e, phi)
# print(d)
d = 461760535243012729352417637561931856791126802617053449862506727428818545
t = int.from_bytes(data, 'big')
x = pow(t, d, n)
bs = i2bs(x)
# print(x)
# print(bs,bs.hex())
return bs
# from rsa import PublicKey, common, transform, core
# def rsa_pubkey_dec(cipher:bytes, PUBLIC_KEY:bytes=pubk.encode()):
# public_key = PublicKey.load_pkcs1(PUBLIC_KEY)
# encrypted = transform.bytes2int(cipher)
# print('e:',public_key.e)
# print('n:',public_key.n)
# decrypted = core.decrypt_int(encrypted, public_key.e, public_key.n)
# print('rsa_pubkey_dec result:',decrypted)
# text = transform.int2bytes(decrypted)
# return text
table = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x6B, 0x79, 0x6E, 0x6A, 0x41, 0x34, 0x45, 0x48, 0x78, 0x36, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x63, 0x4E, 0x57, 0x32, 0x7A, 0x6C, 0x53, 0x58, 0x4C, 0x59, 0x30, 0x64, 0x75, 0x77, 0x44,
0x6F, 0x51, 0x70, 0x56, 0x46, 0x7C, 0x61, 0x37, 0x38, 0x5A, 0x62, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x39, 0x67, 0x65, 0x43, 0x74, 0x69, 0x73, 0x50, 0x6D, 0x68, 0x72, 0x66, 0x4F, 0x31, 0x33,
0x55, 0x4B, 0x42, 0x35, 0x4D, 0x49, 0x54, 0x76, 0x71, 0x47, 0x4A, 0x7B, 0x52, 0x7D, 0x7E, 0x7F]
def s_transform(s: str):
ret = ''
for x in s:
ret += chr(table[ord(x)])
return ret
def re_transfrom(s: str):
ret = ''
for x in s:
ret += chr(table.index(ord(x)))
return ret
def i2bs(m: int, byteorder='big'):
hex_m = m.to_bytes((m.bit_length() + 7) // 8, byteorder=byteorder)
return hex_m
def rsa_pub_dec(decoded_data: bytes, PUBLIC_KEY: bytes = pubk.encode()) -> bytes:
public_key = RSA.import_key(PUBLIC_KEY)
# 获取模数和公钥指数
n = public_key.n
e = public_key.e
# 打印结果
print("Modulus (n):", n)
# bs_n=n.to_bytes(128,'big')
# print(bs_n,bs_n.hex())
print("Exponent (e):", e)
c = int.from_bytes(decoded_data, 'big')
m = pow(c, e, n)
print('pow:', m)
hex_m = i2bs(m)
return hex_m
class CustomBase32Codec:
def __init__(self, custom_alphabet='ABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
if len(custom_alphabet) != 32:
raise ValueError("Custom alphabet must contain 32 characters.")
# Standard Base32 alphabet
standard_alphabet = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
# Create translation tables
self.encode_trans = bytes.maketrans(
standard_alphabet, custom_alphabet.encode())
self.decode_trans = bytes.maketrans(
custom_alphabet.encode(), standard_alphabet)
def encode(self, data):
if isinstance(data, str):
data = data.encode('utf-8')
# Use the standard base64 library to encode and then translate to custom alphabet
encoded = base64.b32encode(data)
return encoded.translate(self.encode_trans)
def decode(self, data):
if isinstance(data, str):
data = data.encode('utf-8')
# Translate from custom alphabet to standard and then decode using standard base64 library
standard_encoded = data.translate(self.decode_trans)
return base64.b32decode(standard_encoded)
def reflect_data(x, width):
# See: https://stackoverflow.com/a/20918545
if width == 8:
x = ((x & 0x55) << 1) | ((x & 0xAA) >> 1)
x = ((x & 0x33) << 2) | ((x & 0xCC) >> 2)
x = ((x & 0x0F) << 4) | ((x & 0xF0) >> 4)
elif width == 16:
x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1)
x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2)
x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4)
x = ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)
elif width == 32:
x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1)
x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2)
x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4)
x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8)
x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16)
else:
raise ValueError('Unsupported width')
return x
def crc_poly(data, n, poly, crc=0, ref_in=False, ref_out=False, xor_out=0):
g = 1 << n | poly # Generator polynomial
# Loop over the data
for d in data:
# Reverse the input byte if the flag is true
if ref_in:
d = reflect_data(d, 8)
# XOR the top byte in the CRC with the input byte
crc ^= d << (n - 8)
# Loop over all the bits in the byte
for _ in range(8):
# Start by shifting the CRC, so we can check for the top bit
crc <<= 1
# XOR the CRC if the top bit is 1
if crc & (1 << n):
crc ^= g
# Reverse the output if the flag is true
if ref_out:
crc = reflect_data(crc, n)
# Return the CRC value
return crc ^ xor_out
def CRC8_MAXIM(data: bytes):
crc8 = crc_poly(data, n=8, poly=0x31, ref_in=True, ref_out=True, xor_out=0)
return crc8
def convert_bytes_to_structure(st: object, byte: bytes):
assert ctypes.sizeof(st) == len(byte), 'size error! need:%d,give:%d' % (
ctypes.sizeof(st), len(byte))
# ctypes.memmove(ctypes.pointer(st), byte, ctypes.sizeof(st))
ctypes.memmove(ctypes.addressof(st), byte, ctypes.sizeof(st))
class TYPE_BASE(ctypes.LittleEndianStructure):
_pack_: int = 1
def __init__(self, data: Union[bytes, list, tuple, set]) -> None:
if isinstance(data, bytes):
convert_bytes_to_structure(self, data)
elif isinstance(data, (list, tuple, set)):
convert_bytes_to_structure(self, bytes(data))
elif isinstance(data, io.IOBase):
data.readinto(self)
'''
struct LicenseInfo{
char var0;
char var1;
char major_version2;
char var3;
int expiration4;
char var8;
char unknow9[7];
char var10;
char var11;
char unknow12[11];
char crc1d;
};
'''
class LicenseInfo(TYPE_BASE):
# _pack_: int = 1
_fields_: list = [
("var0", ctypes.c_ubyte),
("var1", ctypes.c_ubyte),
("major_version2", ctypes.c_ubyte),
("var3", ctypes.c_ubyte),
("expiration4", ctypes.c_uint32),
("var8", ctypes.c_ubyte),
("unknow9", ctypes.c_byte*7),
("var10", ctypes.c_ubyte),
("var11", ctypes.c_ubyte),
("unknow12", ctypes.c_byte*11),
("crc1d", ctypes.c_ubyte
),
]
def __init__(self, data: Union[bytes, list, tuple, set]) -> None:
super().__init__(data)
self.get_var()
def get_var(self):
if (self.var8 & 0xf) != 0:
if (self.var8 & 0xf) == 1 or (self.var8 & 0xf) == 2:
self.ver2 = self.var0
self.ver1 = self.var10
else:
self.ver2 = self.var0 & 0x1f
self.ver1 = self.var0 >> 5
def __str__(self) -> str:
info = ''
info += 'ver1:%02x\n' % self.ver1
info += 'ver2:%02x\n' % self.ver2
info += 'major_version2:%02x\n' % self.major_version2
info += 'var3:%02x\n' % self.var3
info += 'expiration4:%s\n' % convert_to_time_string(self.expiration4)
info += 'var8:%02x\n' % self.var8
info += 'unknow9:%s\n' % bytes(self.unknow9)
info += 'var10:%02x\n' % self.var10
info += 'var11:%02x\n' % self.var11
info += 'unknow12:%s\n' % bytes(self.unknow12)
info += 'crc1d:%02x\n' % self.crc1d
return info
def parse_license(data: bytes):
custom_b32 = CustomBase32Codec()
decoded_data = custom_b32.decode(data)
print("Custom Base32 Decoded:", decoded_data)
print('hex:', decoded_data.hex())
# enc=custom_b32.encode(b'SUPPORT@HASLEO.COM')
# print('enc:',enc)
# text=rsa_pubkey_dec(decoded_data)
text = rsa_pub_dec(decoded_data)
print('rsa_pubkey_dec:', text)
print('rsa_pubkey_dec hex:', text.hex())
enc = rsa_pk_enc(text)
print('test enc:', enc, enc.hex())
rsa_dec = text[:-1]+b'\x00'
# CRC-8/MAXIM
crc8 = CRC8_MAXIM(rsa_dec)
print('crc8/MAXIM :', crc8, hex(crc8))
obj = LicenseInfo(text)
print(str(obj))
def GenActivationCode(license, machine_code) -> str:
lic_md5 = hashlib.md5(license).hexdigest()
# print('lic_md5:',lic_md5)
mc_md5 = hashlib.md5(machine_code).hexdigest()
# print('mc_md5:',mc_md5)
s = '8000|%s|%s|%s' % (lic_md5[8:16], mc_md5[8:16], machine_code.decode())
# print(s)
re_s = re_transfrom(s)
# print(re_s)
return re_s
def GenLicense() -> bytes:
lic = b''
ver2 = 1
ver1 = 1 # random.randint(1,4)
lic += (ver2 | (ver1 << 5)).to_bytes(1, 'little') # this way var8 must 0
lic += b'\x01' # var1
lic += b'\xff' # major_version2
lic += b'\x00' # var3
expiration4 = convert_to_time64('2077-01-01 12:00:00')
t = convert_to_time_string(expiration4)
# print(t)
lic += expiration4.to_bytes(4, 'little')
var8 = b'\x00'
lic += var8
lic += os.urandom(7) # unknow9[7]
lic += b'\x00' # var10
lic += b'\xff' # var11 month
lic += os.urandom(11) # unknow12[11]
crc8 = CRC8_MAXIM(lic+b'\x00')
lic += crc8.to_bytes(1, 'little')
# print('lic:',lic,lic.hex())
# print(str(LicenseInfo(lic)))
enc = rsa_pk_enc(lic)
license = CustomBase32Codec().encode(enc)
return license
if __name__ == "__main__":
license = GenLicense()
print('License:', license.decode())
print('Please input MachineCode:')
mc = input().encode()
ac = GenActivationCode(license, mc)
print('ActivationCode', ac)
activate.log 日志中显示激活成功
ps
网络检验
int __userpurge do_net_check_4502D0@<eax>(int license@<edx>, UnknowClass *a2@<esi>, int a3)
{
int result; // eax
int v4; // edi
result = 0x5401001;
if ( !a2->CActiveOnline_obj_8FDCF4 || !license )
return result;
result = a2->CActiveOnline_obj_8FDCF4->vftable_0->Init_490DD0(
(int)a2->CActiveOnline_obj_8FDCF4,
L"EasyUEFI",
(const wchar_t *)license,
1);
if ( (result & 0xFFF) != 0 )
return result;
// net_check_490F80
v4 = a2->CActiveOnline_obj_8FDCF4->vftable_0->sub_490F80((int)a2->CActiveOnline_obj_8FDCF4, a3);
a2->CActiveOnline_obj_8FDCF4->vftable_0->sub_490EE0((_DWORD *)a2->CActiveOnline_obj_8FDCF4);
return v4;
}
main中还用一个DistributeLicense,不跟了