ACDSee Ultimate18.0 中文 离线激活
ACDSee Ultimate18.0 中文 离线激活
目录
版本信息
VS_VERSION_INFO.StringFileInfo.040904b0.CompanyName:ACD Systems International Inc.
VS_VERSION_INFO.StringFileInfo.040904b0.FileDescription:ACDSee 2025 旗舰版
VS_VERSION_INFO.StringFileInfo.040904b0.ProductName:ACDSee 2025 旗舰版
VS_VERSION_INFO.StringFileInfo.040904b0.InternalName:ACDSee 2025 旗舰版
VS_VERSION_INFO.StringFileInfo.040904b0.OriginalFilename:ACDSeeUltimate2025.exe
VS_VERSION_INFO.StringFileInfo.040904b0.FileVersion:18.1.0.4080
VS_VERSION_INFO.StringFileInfo.040904b0.ProductVersion:18.1.0.4080
VS_VERSION_INFO.StringFileInfo.040904b0.LegalCopyright:版权所有 (c) 2024 ACD Systems International Inc.
VS_VERSION_INFO.VarFileInfo.Translation:04b00409
离线激活
Key
Request Code
Application Unlock Code
离线激活分为3步
1、验证key
xx_do_check_key_14107CD60
char __fastcall xx_do_check_key_14107CD60(__int64 *a1, _QWORD *key)
{
__int64 v2; // rbx
_QWORD *v4; // rax
char _108AF90_sub_14108AF90; // si
volatile signed __int32 *v6; // rbx
__int64 v7; // [rsp+20h] [rbp-18h] BYREF
volatile signed __int32 *v8; // [rsp+28h] [rbp-10h]
char mid; // [rsp+40h] [rbp+8h] BYREF
v2 = *a1;
if ( !*a1 )
return 0;
if ( !*(_BYTE *)(v2 + 0x10) )
return 0;
v4 = p_acdIDLicenseKey_14108B8C0(key);
ptr_ILicenseKey_14108BA60(&v7, (__int64)v4);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
&mid,
(void *)(v2 + 0x60)); // [rbx+60]:L"xxxx" 机器码
// 108AF90
// sub_14108AF90
_108AF90_sub_14108AF90 = (*(__int64 (__fastcall **)(__int64, char *))(*(_QWORD *)v7 + 0x18i64))(v7, &mid);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&mid);
if ( !v8 || _InterlockedExchangeAdd(v8 + 2, 0xFFFFFFFF) != 1 )
return _108AF90_sub_14108AF90;
v6 = v8;
// 00000001401099B0
(**(void (__fastcall ***)(volatile signed __int32 *))v8)(v8);
if ( _InterlockedExchangeAdd(v6 + 3, 0xFFFFFFFF) == 1 )
(*(void (__fastcall **)(volatile signed __int32 *))(*(_QWORD *)v8 + 8i64))(v8);
return _108AF90_sub_14108AF90;
}
bool __fastcall sub_14108AF90(_QWORD *a1)
{
_CheckForDebuggerJustMyCode(&unk_143814CC1);
if ( !*(_DWORD *)(a1[1] - 0x10i64) ) // key size
return 0;
// 108B110
// xx_acdIDLicenseKey_get_key_type_14108B110 判断key类型
if ( (*(unsigned int (__fastcall **)(_QWORD *))(*a1 + 0x28i64))(a1) == 0xD
|| (*(unsigned int (__fastcall **)(_QWORD *))(*a1 + 0x28i64))(a1) == 0xC )
{
return 1;
}
return (unsigned int)xx_check_key_141099A40((char *)a1[2]) == 1;
}
xx_acdIDLicenseKey_get_key_type_14108B110
__int64 __fastcall xx_acdIDLicenseKey_get_key_type_14108B110(__int64 a1)
{
unsigned int n2; // edi
int part_key; // eax
__int64 v5; // r8
wchar_t *__shifted(CStringData,0x18) ptr_1; // [rsp+20h] [rbp-28h] BYREF
wchar_t *__shifted(CStringData,0x18) ptr; // [rsp+28h] [rbp-20h] BYREF
n2 = 0;
_CheckForDebuggerJustMyCode(&unk_143814CC1);
if ( !*(_DWORD *)(*(_QWORD *)(a1 + 8) - 0x10i64) )
return 0i64;
// a1+8==>key
part_key = ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::ReverseFind(a1 + 8, '-');
v5 = (unsigned int)(part_key - 0xE);
if ( part_key == 0xFFFFFFFF || (int)v5 < 0 )
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
&ptr,
&Parameters);
else
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Mid(a1 + 8, &ptr, v5, 0xEi64);// 取子串尾部的 14 字节,
if ( ADJ(ptr)->nDataLength )
{
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Mid(&ptr, &ptr_1, 6i64, 1i64);// 再提取其第 7 个字符,
// 最终根据预设映射表返回整数值。用于验证密钥的版本或类型标识。
if ( ADJ(ptr_1)->nDataLength )
{
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::MakeUpper(&ptr_1);
switch ( (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::operator[](&ptr_1, 0i64) )
{
case 'A':
n2 = 1;
break;
case 'B':
n2 = 2;
break;
case 'C':
n2 = 3;
break;
case 'D':
n2 = 4;
break;
case 'E':
n2 = 5;
break;
case 'F':
n2 = 6;
break;
case 'G':
n2 = 7;
break;
case 'H':
n2 = 8;
break;
case 'I':
n2 = 9;
break;
case 'J':
n2 = 0xA;
break;
case 'P':
n2 = 0xD;
break;
case 'S':
n2 = 0xC;
break;
default:
break;
}
}
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&ptr_1);
}
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&ptr);
return n2;
}
key类型
【1-9】
0xa key is for floating license versions
0xc or 0xd 此密钥需要在线激活。重新安装以激活密钥。
0,0xa,0xb,0xc,0xd 类型密钥对 ACDSee 旗舰版 无效
xx_check1_14106F1D0
// xx_acdIDLicenseKey_get_key_type_14108B110
if ( (*(unsigned int (__fastcall **)(__int64))(*(_QWORD *)v28 + 0x28i64))(v28) == 0xA )
{
v9 = ***(_QWORD ***)(a1 + 0x5A8);
if ( !v9 || !*(_BYTE *)(v9 + 0x10) || !*(_BYTE *)(v9 + 0xCB) )
{
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&lpText);
// "Your key is for floating license versions of %s only. Enter a regular key."
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Format(&lpText, 19337i64, lpCaption);
MessageBoxW(*(HWND *)(a1 + 0x40), lpText, lpCaption, 0);
*a2 = 1;
p_lpText = &lpText;
goto LABEL_39;
}
}
v12 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v8 + 0x28i64))(v8) - 0xC;
if ( !v12 || v12 == 1 ) // 0xc or 0xd
{
v13 = ***(_QWORD ***)(a1 + 0x5A8);
if ( !v13 || !*(_BYTE *)(v13 + 0x10) || !(unsigned __int8)sub_1410947D0(v13 + 0xE8) )
{
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&lpText_2);
// "此密钥需要在线激活。重新安装以激活密钥。"
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Format(&lpText_2, 19906i64, lpCaption);
MessageBoxW(*(HWND *)(a1 + 0x40), lpText_2, lpCaption, 0);
*a2 = 1;
p_lpText = &lpText_2;
LABEL_39:
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(p_lpText);
v22 = v29;
if ( !v29 )
goto LABEL_43;
goto LABEL_40;
}
xx_offine_enterkey_141044350
// xx_acdIDLicenseKey_get_key_type_14108B110
lickey_type = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v33 + 0x28i64))(v33);
if ( !lickey_type || (v10 = lickey_type - 0xA) == 0 || (v11 = v10 - 1) == 0 || (v12 = v11 - 1) == 0 || v12 == 1 )
{
// 密钥位置41的字符 返回值
// A-I 1-9
// J 10
// P 13
// S 12
// 其他 0
// 以下值错误:
// 0,0xa,0xb,0xc,0xd
lpCaption = (LPCWSTR *)(*(__int64 (__fastcall **)(_QWORD *, char *))(*a1 + 8i64))(a1, v31);
v24 = (LPCWSTR *)ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
v32,
0x4DF3i64);
if ( a2 )
hWnd = *(HWND *)(a2 + 0x40);
// [rsp+40]:L"输入的密钥对 ACDSee 旗舰版 无效。检查您的密钥。"
xx_check_key_141099A40
__int64 __fastcall xx_check_key_141099A40(char *key)
{
int n0x75B26; // eax
unsigned int i; // [rsp+40h] [rbp-178h]
char a7; // [rsp+48h] [rbp-170h]
char a6; // [rsp+49h] [rbp-16Fh]
char a5; // [rsp+4Ah] [rbp-16Eh]
char check[128]; // [rsp+80h] [rbp-138h]
char part3[8]; // [rsp+100h] [rbp-B8h] BYREF
char a4[8]; // [rsp+108h] [rbp-B0h] BYREF
char a2[16]; // [rsp+110h] [rbp-A8h] BYREF
char calc_out[128]; // [rsp+120h] [rbp-98h] BYREF
_CheckForDebuggerJustMyCode(byte_1438225AB);
if ( !key || strnlen(key, 0x32ui64) != 0x30 ) // 48字符 (0x30)
return 0i64;
// key 使用‘-’ 分隔为7段,每段6,42+6==48
a2[6] = *key;
a2[1] = key[1];
a2[2] = key[2];
a2[3] = key[3];
a2[4] = key[4];
a2[5] = key[5];
if ( key[6] != '-' )
return 0i64;
a2[0] = key[7];
check[0] = key[8];
check[1] = key[9];
check[2] = key[0xA];
check[3] = key[0xB];
check[4] = key[0xC];
if ( key[0xD] != '-' )
return 0i64;
check[5] = key[0xE];
check[6] = key[0xF];
check[7] = key[0x10];
check[8] = key[0x11];
check[9] = key[0x12];
check[0xA] = key[0x13];
if ( key[0x14] != '-' )
return 0i64;
check[0xB] = key[0x15];
check[0xC] = key[0x16];
check[0xD] = key[0x17];
check[0xE] = key[0x18];
check[0xF] = key[0x19];
check[0x10] = key[0x1A];
if ( key[0x1B] != 0x2D )
return 0i64;
part3[0] = key[0x1C];
part3[1] = key[0x1D];
part3[2] = key[0x1E];
part3[3] = key[0x1F];
part3[4] = key[0x20];
a5 = key[0x21];
if ( key[0x22] != '-' )
return 0i64;
a4[0] = key[0x23];
a4[1] = key[0x24];
a4[2] = key[0x25];
a4[3] = key[0x26];
a6 = key[0x27];
a7 = key[0x28];
if ( key[0x29] != '-' )
return 0i64;
check[0x11] = key[0x2A];
check[0x12] = key[0x2B];
check[0x13] = key[0x2C];
check[0x14] = key[0x2D];
check[0x15] = key[0x2E];
check[0x16] = key[0x2F];
a4[4] = 0;
n0x75B26 = ParseBase36String_141095B80((__int64)a4);
if ( n0x75B26 == 0x75B26 || (unsigned int)(n0x75B26 - 0x75B26) > 0xC350 )
return 0i64;
if ( part3[0] < 0x41 || part3[0] > 0x5A )
return 0i64;
xx_key_calc_141099580(2, a2, part3, a4, a5, a6, a7, (__int64)calc_out);
for ( i = 0; i < 0x17; ++i )
{
if ( !transform_cmp_141099100(check[i], calc_out[i]) )
return 0i64;
}
return 1i64;
}
// // 解析36进制字符串为整数
// // str: 输入字符串(仅支持0-9, A-Z)
// // 返回值: 对应的整数值(无效字符/空串返回0)
__int64 __fastcall ParseBase36String_141095B80(__int64 a1)
{
unsigned int v2; // [rsp+20h] [rbp-28h]
int i; // [rsp+24h] [rbp-24h]
unsigned __int64 i_1; // [rsp+30h] [rbp-18h]
_CheckForDebuggerJustMyCode(byte_1438225AB);
v2 = 0;
i_1 = 0xFFFFFFFFFFFFFFFFui64;
do
++i_1;
while ( *(_BYTE *)(a1 + i_1) );
for ( i = 0; i < (int)i_1; ++i )
v2 = Base36CharToValue_141095B20(*(_BYTE *)(a1 + i)) + 36 * v2;
return v2;
}
xx_key_calc_141099580
__int64 __fastcall xx_key_calc_141099580(int n2, char *a2, char *a3, char *a4, char a5, char a6, char a7, __int64 out)
{
unsigned __int64 count; // [rsp+28h] [rbp-250h]
unsigned int v10; // [rsp+30h] [rbp-248h]
int src_[4]; // [rsp+40h] [rbp-238h] BYREF
char buf[256]; // [rsp+50h] [rbp-228h] BYREF
char dst[256]; // [rsp+150h] [rbp-128h] BYREF
_CheckForDebuggerJustMyCode(byte_1438225AB);
memset(dst, 0, 0xFFui64);
memset(buf, 0, 0xFFui64);
buf[0] = *a2;
buf[1] = a2[1];
buf[2] = a2[2];
buf[3] = a2[3];
buf[4] = a2[4];
buf[5] = a2[5];
buf[6] = a2[6];
buf[7] = *a3;
buf[8] = a3[1];
buf[9] = a3[2];
buf[0xA] = a3[3];
buf[0xB] = a3[4];
buf[0xC] = a5;
buf[0xD] = *a4;
buf[0xE] = a4[1];
buf[0xF] = a4[2];
buf[0x10] = a4[3];
buf[0x11] = a6;
buf[0x12] = a7;
v10 = CalculateCRC32_i_141098F80(buf, 0x13i64, 0x17i64);
int2bytes_le_1410994D0(v10, dst);
CustomBase32Encode_1410991E0((unsigned __int8 *)dst, 4, &buf[0x13], 1);
count = 0xFFFFFFFFFFFFFFFFui64;
do
++count;
while ( buf[count] );
qmemcpy(dst, buf, (int)count);
*(_DWORD *)&dst[(int)count] = xx_pid2_md5value_143616438[0];// 5cbd8386
xx_md5_141098AA0(src_, dst, count + 4); // md5
int2bytes_le_1410994D0(src_[0], dst);
int2bytes_le_1410994D0(src_[1], &dst[4]);
int2bytes_le_1410994D0(src_[2], &dst[8]);
int2bytes_le_1410994D0(src_[3], &dst[0xC]);
return CustomBase32Encode_1410991E0((unsigned __int8 *)dst, 0x10, (char *)out, n2);
}
CalculateCRC32_i_141098F80
__int64 __fastcall CalculateCRC32_i_141098F80(char *buf, __int64 length, __int64 initial)
{
signed int i_1; // [rsp+20h] [rbp-448h]
int i; // [rsp+24h] [rbp-444h]
int j; // [rsp+28h] [rbp-440h]
char *p; // [rsp+30h] [rbp-438h]
int crc32_table[258]; // [rsp+60h] [rbp-408h]
int length_1; // [rsp+478h] [rbp+10h]
int crc; // [rsp+480h] [rbp+18h]
crc = initial;
length_1 = length;
_CheckForDebuggerJustMyCode(byte_1438225AB);
for ( i = 0; i < 0x100; ++i )
{
i_1 = (unsigned int)ReverseLowBits_141098EF0(i, 8i64) << 0x18;
for ( j = 0; j < 8; ++j )
{
if ( i_1 >= 0 )
i_1 *= 2;
else
i_1 = (2 * i_1) ^ 0x4C11DB7;
}
crc32_table[i] = ReverseLowBits_141098EF0(i_1, 0x20i64);
}
for ( p = buf; p < &buf[length_1]; ++p )
// sar ==>算术右移
crc = (crc >> 8) ^ crc32_table[(unsigned __int8)(crc ^ *p)];
return (unsigned int)crc;
}
CustomBase32Encode_1410991E0
__int64 __fastcall CustomBase32Encode_1410991E0(unsigned __int8 *a1, int sz, char *out, int table_id)
{
char v5; // [rsp+20h] [rbp-98h]
int sz_1; // [rsp+24h] [rbp-94h]
unsigned int v7; // [rsp+28h] [rbp-90h]
int n8; // [rsp+2Ch] [rbp-8Ch]
unsigned int v9; // [rsp+30h] [rbp-88h]
int i; // [rsp+34h] [rbp-84h]
int v11; // [rsp+38h] [rbp-80h]
char _56AFGHJBCDEKLVZ7MNP2YTU8934QRSWX[40]; // [rsp+40h] [rbp-78h] BYREF
char AD5HJK6EUVWFGLMNP2BC34QRSTXYZ789[40]; // [rsp+68h] [rbp-50h] BYREF
_CheckForDebuggerJustMyCode(byte_1438225AB);
strcpy(_56AFGHJBCDEKLVZ7MNP2YTU8934QRSWX, "56AFGHJBCDEKLVZ7MNP2YTU8934QRSWX");
strcpy(AD5HJK6EUVWFGLMNP2BC34QRSTXYZ789, "AD5HJK6EUVWFGLMNP2BC34QRSTXYZ789");
v9 = 0;
v7 = *a1;
sz_1 = 1;
n8 = 8;
for ( i = 8 * sz; i > 0; i -= 5 )
{
if ( n8 < 5 && sz_1 < sz )
{
v7 = a1[sz_1++] | (v7 << 8);
n8 += 8;
}
v11 = v7 & 0x1F;
v7 >>= 5;
n8 -= 5;
if ( table_id == 1 )
v5 = _56AFGHJBCDEKLVZ7MNP2YTU8934QRSWX[v11];
else
v5 = AD5HJK6EUVWFGLMNP2BC34QRSTXYZ789[v11];
out[v9++] = v5;
}
out[v9] = 0;
return v9;
}
2、生成请求码(Request Code)
这部分程序自身负责生成
xx_gen_request_code_141080EA0
char __fastcall xx_gen_request_code_141080EA0(const char *key, LPCWSTR mid, char *out_request_code)
{
char result; // r11
char *dst; // rcx
int n0xFF_1; // edx
int v9; // er9
int n4; // er8
char *SrcBuf_1; // rcx
int v12; // er10
__int64 n0xFF; // rax
__int64 v14; // r8
int n8; // er9
char v17; // [rsp+1Fh] [rbp-219h] BYREF
__int16 temp[128]; // [rsp+20h] [rbp-218h] BYREF
char buf[26]; // [rsp+120h] [rbp-118h] BYREF
char buf_2[230]; // [rsp+13Ah] [rbp-FEh] BYREF
result = md5_base32_141080CF0((char *)mid, (char *)temp);
if ( !result )
return result;
strcpy(buf, (const char *)temp);
dst = &v17;
while ( *++dst != 0 )
;
strcpy(dst, key); // 拼接key
// ASQBETVL824Y5T9GXHM77MNCBSEMTR3H-SG6B9X-V5K64U-TJKB5S-R8ELOB-AVOG94-NLDPA9
// md5==>
// 53391894055338AEFDAFB5AB57C17BD2
result = md5_base32_141080CF0((char *)temp, buf_2);// ==>
// LN6TTFAFLN6L79PRYYXXRSM54J
if ( !result )
return result;
n0xFF_1 = 0;
v9 = 0;
n4 = 0;
// ASQB-ETVL824Y-5T9GXHM7-7MNCBSLN-6TTFAFLN-6L79PRYY-XXRSM54J
SrcBuf_1 = out_request_code;
// 添加分隔符'-'
while ( SrcBuf_1 - out_request_code < 0xFF )
{
++n0xFF_1;
*SrcBuf_1 = SrcBuf_1[buf - out_request_code];
++n4;
++SrcBuf_1;
++v9;
if ( n4 >= 4 )
{
v12 = 0;
n0xFF = n0xFF_1;
v14 = v9;
LABEL_9:
if ( n0xFF >= 0xFF )
return 0;
++n0xFF_1;
out_request_code[n0xFF++] = '-';
n8 = 0;
while ( n0xFF < 0xFF )
{
++n0xFF_1;
out_request_code[n0xFF] = buf[v14];
++n8;
++n0xFF;
++v14;
if ( n8 >= 8 )
{
if ( ++v12 < 6 )
goto LABEL_9;
if ( n0xFF_1 >= 0xFF )
return 0;
out_request_code[n0xFF_1] = 0;
return result;
}
}
return 0;
}
}
return 0;
}
3、验证解锁码(Application Unlock Code)
使用内置硬编码rsa公钥对解锁码(移除分隔符’-‘后)进行解密,与请求码(不包含分隔符’-‘) 进行比较
xx_check_unlock_code_1410448D0
void __fastcall xx_check_unlock_code_1410448D0(_QWORD **a1, __int64 a2)
{
HWND hWnd; // rbx
int n6; // er14
__int64 v6; // rdi
char *s_key; // rax
char *s_mid; // rax
char *v9; // rax
LPCWSTR *v10; // rdi
LPCWSTR *v11; // rax
char *mid_1; // rdi
_QWORD *v13; // rax
const wchar_t *key; // [rsp+20h] [rbp-10h] BYREF
const wchar_t *unlockcode; // [rsp+28h] [rbp-8h] BYREF
const wchar_t *mid_2; // [rsp+70h] [rbp+40h] BYREF
char *unlockcode_1; // [rsp+78h] [rbp+48h] BYREF
char *mid; // [rsp+80h] [rbp+50h] BYREF
const char *s_key_1; // [rsp+88h] [rbp+58h] BYREF
hWnd = 0i64;
LODWORD(mid_2) = 0;
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
&unlockcode,
(void *)(a2 + 0x358)); // unlockcode
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
&key,
a1 + 0xE); // key
n6 = 6;
v6 = *a1[2];
if ( v6 )
{
if ( *(_BYTE *)(v6 + 0x10) )
{
s_key = w2s_141090DD0(&key);
ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>(
&s_key_1,
s_key);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
&mid_2,
(void *)(v6 + 0x60)); // mid
n6 = 0xE;
s_mid = w2s_141090DD0(&mid_2);
ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>(
&mid,
s_mid);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&mid_2);
v9 = w2s_141090DD0(&unlockcode);
ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>(
&unlockcode_1,
v9);
LOBYTE(v6) = xx_check_unlockcode_with_key_and_mid_141081020(unlockcode_1, mid, s_key_1);
ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>::~CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>(&unlockcode_1);
ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>::~CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>(&mid);
ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>::~CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>(&s_key_1);
}
else
{
LOBYTE(v6) = 0;
}
}
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&key);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&unlockcode);
if ( (_BYTE)v6 )
{
mid_1 = (char *)operator new(0x20ui64);
mid = mid_1;
if ( mid_1 )
{
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
&unlockcode_1,
a1 + 0xE);
n6 |= 0x11u;
LODWORD(mid_2) = n6;
*((_QWORD *)mid_1 + 1) = a1[2];
*(_QWORD *)mid_1 = &acdID::OfflineRegistrationApplier::`vftable';
s_key_1 = mid_1 + 0x10;
v13 = p_acdIDLicenseKey_14108B8C0(&unlockcode_1);
ptr_ILicenseKey_14108BA60((_QWORD *)mid_1 + 2, (__int64)v13);
}
else
{
mid_1 = 0i64;
}
mid_2 = (const wchar_t *)mid_1;
if ( (n6 & 1) != 0 )
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&unlockcode_1);
sub_1410490C0((__int64)a1, (__int64)mid_1, a2);
if ( mid_1 )
(**(void (__fastcall ***)(void *, __int64))mid_1)(mid_1, 1i64);
}
else
{
v10 = (LPCWSTR *)((__int64 (__fastcall *)(_QWORD **, char **))(*a1)[1])(a1, &unlockcode_1);
v11 = (LPCWSTR *)ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
&mid_2,
// "应用程序解锁码无法通过验证。请检查您从 ACD 处收到的应用程序解锁码。"
19848i64);
if ( a2 )
hWnd = *(HWND *)(a2 + 0x40);
MessageBoxW(hWnd, *v11, *v10, 0x40u);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&mid_2);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&unlockcode_1);
}
}
xx_check_unlockcode_with_key_and_mid_141081020
key和mid 经md5+base32得到==》请求码(不包含分隔符’-‘)
rsa 公钥信息:
modulus: 29534669871133570287312166136314074499388460293658853527717011579888871213298696906781730851422617542974783536935071
exponent: 65537
bfe3ffd1e62e869ac2b1f3c38e47be2d58c5b7d444497a5b34ac8add28773cd33e321776bcd3b588c534f900c57ab09f
rsa 采用Chilkat CkCrypt2库
// patch to ret 1
bool __fastcall xx_check_unlockcode_with_key_and_mid_141081020(char *unlockcode, char *mid, const char *key)
{
bool v6; // r14
unsigned __int64 sz; // r10
unsigned __int64 unlockcode_sz; // rax
unsigned __int64 key_sz; // rax
unsigned int v10; // esi
int n0xFF; // er8
__int64 n0x56; // rax
char *unlockcode_ptr; // rdx
__int64 n0x2D; // rcx
unsigned __int64 i_1; // rdx
__int64 sz_1; // r8
unsigned __int8 i; // cl
_BYTE *v18; // rax
__int64 unlockcode_rsa_dec; // rbx
char *dst; // rcx
char *temp; // rdx
int ptr_request_code; // eax
int cmp; // ecx
_QWORD ckrsa[16]; // [rsp+20h] [rbp-E0h] BYREF
_QWORD ck_pubkey[16]; // [rsp+A0h] [rbp-60h] BYREF
__int64 v27[16]; // [rsp+120h] [rbp+20h] BYREF
char ABCDEFGHJKLMNPQRSTUVWXYZ23456789[40]; // [rsp+1A0h] [rbp+A0h] BYREF
char v29; // [rsp+1CFh] [rbp+CFh] BYREF
char temp_1[256]; // [rsp+1D0h] [rbp+D0h] BYREF
__int64 out[32]; // [rsp+2D0h] [rbp+1D0h] BYREF
char request_code[1024]; // [rsp+3D0h] [rbp+2D0h] BYREF
v6 = 0;
p_CkGlobal_14213BF00(v27);
if ( !sub_14213BFE0((__int64)v27, "ACDSYS.CB1022023_Lw2icKwnl0Aa ") )
goto LABEL_37;
p_CkPublicKey_142233C70(ck_pubkey);
p_CkRsa_142380110(ckrsa);
sz = 0xFFFFFFFFFFFFFFFFui64;
unlockcode_sz = 0xFFFFFFFFFFFFFFFFui64;
do
++unlockcode_sz;
while ( unlockcode[unlockcode_sz] );
if ( (_DWORD)unlockcode_sz != 0x56 )
goto LABEL_36;
key_sz = 0xFFFFFFFFFFFFFFFFui64;
do
++key_sz;
while ( key[key_sz] );
if ( key_sz != 0x30 )
{
LABEL_36:
sub_142380150(ckrsa);
sub_142233CB0(ck_pubkey);
LABEL_37:
p_CkGlobal_14213BF40(v27);
return 0;
}
v10 = 0;
n0xFF = 0;
n0x56 = 0i64;
unlockcode_ptr = temp_1;
do
{
n0x2D = (unsigned __int8)unlockcode[n0x56];
if ( (_BYTE)n0x2D != '-' )
{
*unlockcode_ptr = n0x2D;
++n0xFF;
++unlockcode_ptr;
}
++n0x56;
}
while ( n0x56 < 0x56 );
if ( (unsigned __int64)n0xFF >= 0xFF )
{
_report_rangecheckfailure(n0x2D, unlockcode_ptr);
JUMPOUT(0x14108131Ei64);
}
temp_1[n0xFF] = 0;
strcpy(ABCDEFGHJKLMNPQRSTUVWXYZ23456789, "ABCDEFGHJKLMNPQRSTUVWXYZ23456789");
i_1 = 0xFFFFFFFFFFFFFFFFui64;
do
++i_1;
while ( ABCDEFGHJKLMNPQRSTUVWXYZ23456789[i_1] );
do
++sz;
while ( temp_1[sz] );
if ( (int)sz <= 0 )
{
// 换表base32
LABEL_23:
v10 = base32_dec_14109CA70(request_code, sz, (__int64)out);
}
else
{
sz_1 = 0i64;
while ( 1 )
{
for ( i = 0; i < (int)i_1; ++i )
{
if ( temp_1[sz_1] == ABCDEFGHJKLMNPQRSTUVWXYZ23456789[i] )
break;
}
if ( i >= (int)i_1 )
break;
request_code[sz_1++] = i;
if ( sz_1 >= (int)sz )
goto LABEL_23;
}
}
if ( (unsigned __int8)sub_142233D50(
ck_pubkey,
"-----BEGIN PUBLIC KEY-----\n"
"MEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxAL/j/9HmLoaawrHzw45Hvi1YxbfUREl6\n"
"WzSsit0odzzTPjIXdrzTtYjFNPkAxXqwnwIDAQAB\n"
"-----END PUBLIC KEY-----",
sz_1) )
{
p_CkByteData_142161A80((__int64)ABCDEFGHJKLMNPQRSTUVWXYZ23456789);
sub_142161BC0(ABCDEFGHJKLMNPQRSTUVWXYZ23456789, out, v10);
v18 = (_BYTE *)sub_142233E20(ck_pubkey);
if ( sub_1423801F0(ckrsa, v18) )
{
unlockcode_rsa_dec = rsa_dec_1423802C0(ckrsa, ABCDEFGHJKLMNPQRSTUVWXYZ23456789);
if ( (unsigned __int8)md5_base32_141080CF0(mid, temp_1) )
{
dst = &v29; // mid_md5_customb32
do
++dst;
while ( *dst );
strcpy(dst, key); // 拼接key
if ( (unsigned __int8)md5_base32_141080CF0(temp_1, request_code) )// ==>request code
{
// loop cmp
temp = &request_code[-unlockcode_rsa_dec];
do
{
ptr_request_code = (unsigned __int8)temp[unlockcode_rsa_dec];
cmp = *(unsigned __int8 *)unlockcode_rsa_dec - ptr_request_code;// cmp
if ( cmp )
break;
++unlockcode_rsa_dec;
}
while ( ptr_request_code );
v6 = cmp == 0;
}
}
}
CkByteData_destruct_142161AE0(ABCDEFGHJKLMNPQRSTUVWXYZ23456789);
}
sub_142380150(ckrsa);
sub_142233CB0(ck_pubkey);
p_CkGlobal_14213BF40(v27);
return v6;
}
跟踪定位
注册逻辑可关注以下类:
acdID::StandaloneEnterLicenseDlg
acdID::OfflineLicenseKeyPanel
acdID::OfflineUnlockPanel
注册表值解密定位:
可在x64dbg中设置条件断点
RegQueryValueExW
rdx!=0&& streq(utf16(rdx),"pid2")
rdx!=0&& streq(utf16(rdx),"md")
rdx!=0&& streq(utf16(rdx),"ud")
……
patch&py
(其实直接修改注册表值可实现免注册、patch,不做分析)
patch xx_check_unlockcode_with_key_and_mid_141081020函数返回1
即可绕过对解锁码的验证
keg 生成与验证
from Crypto.Cipher import Blowfish
import ctypes
import hashlib
import string
import struct
import winreg
import random
xx_pid2_md5value_143616438 = b''
def random_str(sz: int)->str:
out = []
for _ in range(sz):
out.append(random.choice('ABCDEFGHJKLMNPQRSTUVWXYZ23456789'))
return ''.join(out)
def _set_reg_binary_value(key_path:str, value_name:str, binary_data:bytes):
"""
修改注册表中的 REG_BINARY 类型数据
参数:
key_path: 注册表键路径 (如: r"SOFTWARE\Microsoft\Windows\CurrentVersion")
value_name: 值名称 (如: "DevicePath")
binary_data: 要设置的二进制数据 (bytes 类型)
"""
try:
access = winreg.KEY_SET_VALUE #| winreg.KEY_WOW64_64KEY
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path, 0, access) as key:
# 设置 REG_BINARY 值
winreg.SetValueEx(key, value_name, 0, winreg.REG_BINARY, binary_data)
print(f"成功修改注册表值: {key_path}\\{value_name}")
return True
except PermissionError:
print("错误: 权限不足。请以管理员身份运行此程序。")
return False
except FileNotFoundError:
print(f"错误: 注册表路径不存在: {key_path}")
return False
except Exception as e:
print(f"修改注册表时出错: {str(e)}")
return False
def set_acd18_lclient_md(data:bytes):
return _set_reg_binary_value(r"SOFTWARE\ACD Systems\ACDSee Ultimate\180\LClient",'md',data)
def _get_reg_valuedata(sub_key_path: str, name: str):
try:
# 连接到 HKEY_LOCAL_MACHINE 根键
reg_key = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
access = winreg.KEY_READ
sub_key = winreg.OpenKey(reg_key, sub_key_path, 0, access)
# 查询 MachineGuid 的值
value, _ = winreg.QueryValueEx(sub_key, name)
return value
except FileNotFoundError:
return "错误:注册表路径或键值不存在"
except PermissionError:
return "错误:权限不足(请以管理员身份运行)"
except Exception as e:
return f"未知错误: {str(e)}"
finally:
# 确保关闭所有打开的键
if 'sub_key' in locals():
winreg.CloseKey(sub_key)
winreg.CloseKey(reg_key)
def _get_acd18_lclient_data(name: str):
return _get_reg_valuedata(r"SOFTWARE\ACD Systems\ACDSee Ultimate\180\LClient", name)
def get_acd18_lclient_pid2() -> bytes:
return _get_acd18_lclient_data('pid2')
def get_acd18_lclient_md() -> bytes:
return _get_acd18_lclient_data('md')
def get_machine_guid() -> str:
return _get_reg_valuedata(r"SOFTWARE\Microsoft\Cryptography", "MachineGuid")
# 辅助函数:Base36 字符转数值
def base36_char_to_value(ch: str) -> int:
"""将字符转换为36进制数值 (0-9,A-Z -> 0-35)"""
if '0' <= ch <= '9':
return ord(ch) - ord('0')
if 'A' <= ch <= 'Z':
return ord(ch) - ord('A') + 10
return 0
# 辅助函数:Base36 字符串转整数
def parse_base36_string(s: str) -> int:
"""将Base36字符串转换为整数"""
result = 0
for char in s:
result = base36_char_to_value(char) + 36 * result
return result
def int_to_base36(n: int) -> str:
"""将整数转换为Base36字符串 (0-9,A-Z)"""
if n == 0:
return "0"
BASE36_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result = []
# 转换整数为Base36字符串
while n:
n, remainder = divmod(n, 36)
result.append(BASE36_CHARS[remainder])
# 反转结果并添加负号
base36_str = ''.join(result[::-1])
return base36_str
crc32_tab = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]
# 辅助函数:CRC-32 计算
def calculate_i_crc32(data: bytes, initial: int = 0) -> int:
# 计算CRC值
crc = ctypes.c_int32(initial)
for byte in data:
index = (crc.value ^ byte) & 0xFF
# acdsee 使用sar 算术右移,故需要进行调整
crc = ctypes.c_int32((crc.value >> 8) ^ crc32_tab[index])
return ctypes.c_uint32(crc.value).value
def CustomBase32Encode_le_1410991E0(data: bytes, alphabet_flag: int = 1) -> bytes:
"""自定义Base32编码 (两种字母表)"""
# 定义两种自定义字母表
alphabet1 = b"56AFGHJBCDEKLVZ7MNP2YTU8934QRSWX"
alphabet2 = b"AD5HJK6EUVWFGLMNP2BC34QRSTXYZ789"
table = alphabet1 if alphabet_flag == 1 else alphabet2
if isinstance(data, str):
data = data.encode()
result = []
buffer = 0
bits_left = 0
# total_bits = len(data) * 8
# 处理每个字节
for byte in data:
buffer = (buffer << 8) | byte
bits_left += 8
# 每次提取5位进行编码
while bits_left >= 5:
bits_left -= 5
index = buffer & 0x1F
buffer = buffer >> 5
# index = (buffer >> bits_left) & 0x1F
result.append(table[index])
# 处理剩余位
if bits_left > 0:
index = buffer & 0x1F
# index = (buffer << (5 - bits_left)) & 0x1F
result.append(table[index])
return bytes(result)
def blowfish_dec(key: bytes, data: bytes):
bf = Blowfish.new(key=key[:16], mode=Blowfish.MODE_CBC, iv=b'12345678')
out = bf.decrypt(data)
return out
def bf_dec_pid2(mid: bytes, pid2: bytes) -> str:
# bf=Blowfish.new(key=mid[:16],mode=Blowfish.MODE_CBC,iv=b'12345678')
out = blowfish_dec(mid[:16], pid2)
ws_sz = struct.unpack_from('<I', out)[0]
ws = out[4:4+ws_sz]
return ws.decode('utf-16-le')
def xx_calc_pid2_md5_1410993B0(lcient_dec_pid2: bytes):
dst = b'102371ewrhr58tifmIoigj564DSFeoipubnLOIUeEIpl89avaUOCV98845689gDKSeoiaFdNZZedajhasfj6sdf87erDF56X'
temp = CustomBase32Encode_le_1410991E0(lcient_dec_pid2, 1)
# print(temp)
x = dst[:7]+temp+dst[7+len(temp):-1]
'''
target==>
102371e6FPT8PN694E6Agj564DSFeoipubnLOIUeEIpl89avaUOCV98845689gDKSeoiaFdNZZedajhasfj6sdf87erDF56
md5==>5C BD 83 86 F6 D5 53 60 D2 82 AF C3 37 02 E4 7C
'''
x = hashlib.md5(x).digest()
return x
def xx_key_calc_141099580(table_id2: int, a2: bytes, a3: bytes, a4, a5: bytes, a6: bytes, a7: bytes) -> bytes:
assert len(a2) == 7, 'a2 len error'
assert len(a3) == 5, 'a2 len error'
assert len(a4) == 4, 'a4 len error'
assert len(a5) == 1, 'a5 len error'
assert len(a6) == 1, 'a6 len error'
assert len(a7) == 1, 'a7 len error'
buf = b''
buf += a2
buf += a3
buf += a5
buf += a4
buf += a6
buf += a7
v = calculate_i_crc32(buf, 0x17)
v = v.to_bytes(4, 'little')
# print(v.hex())
buf += CustomBase32Encode_le_1410991E0(v, 1)
dst = buf+xx_pid2_md5value_143616438[:4]
dst = hashlib.md5(dst).digest()
ret = CustomBase32Encode_le_1410991E0(dst, table_id2)
return ret
def re_transform_cmp_141099100(calc_value):
check_part = []
s1 = b'56AFGHJBCDEKLVZ7MNP2YTU8934QRSWX'
s2 = b'AD5HJK6EUVWFGLMNP2BC34QRSTXYZ789'
for a2 in calc_value:
for i in range(0x20):
if s2[i] == a2:
check_part.append(s1[i])
return bytes(check_part)
def transform_cmp_141099100(a1, a2):
s1 = b'56AFGHJBCDEKLVZ7MNP2YTU8934QRSWX'
s2 = b'AD5HJK6EUVWFGLMNP2BC34QRSTXYZ789'
for i in range(0x20):
if s1[i] == a1:
return s2[i] == a2
return False
def xx_check_key_141099A40(key: bytes) -> bool:
# 1. 基础检查:非空且长度48
if not key or len(key) != 48:
return False
# 2. 分隔符位置检查(必须为连字符)
hyphen_positions = [6, 13, 20, 27, 34, 41]
for pos in hyphen_positions:
if key[pos:pos+1] != b'-':
return False
a2 = key[7:7+1]+key[1:6]+key[0:1]
check_part = key[8:0xd]+key[0xe:0x14]+key[0x15:0x1b]+key[0x2a:0x30]
a3 = key[0x1c:0x21] # A-Z
a5 = key[0x21:0x22]
a4 = key[0x23:0x27]
a6 = key[0x27:0x28]
a7 = key[0x28:0x29]
n = parse_base36_string(a4.decode())
if n == 0x75b26 or n > (0xc350+0x78b26): # [0x75b27--0x84e76]
return False
if a3[0] < 0x41 or a3[0] > 0x5a: # A-Z
return False
calc_value = xx_key_calc_141099580(2, a2, a3, a4, a5, a6, a7)
calc_value = calc_value.rstrip(b'=')
# print('check_part:', check_part)
# print('calc_value:', calc_value)
for i, x in enumerate(check_part): # 0x17
b = transform_cmp_141099100(x, calc_value[i])
if not b:
return False
return True
def genkey(ktype: int = 2) -> bytes:
assert 0 < ktype < 0xa, '[%d]密钥对 ACDSee 旗舰版 无效' % ktype
key = bytearray(random_str(48).encode())
hyphen_positions = [6, 13, 20, 27, 34, 41]
for pos in hyphen_positions:
key[pos:pos+1] = b'-'
s_ktype = re_key_type(ktype)
# a5
key[33:34] = s_ktype.encode()
# a3
key[0x1c:0x1d] = ''.join(random.choices(string.ascii_uppercase)).encode()
a2 = key[7:7+1]+key[1:6]+key[0:1]
a3 = key[0x1c:0x21] # A-Z
a5 = key[0x21:0x22]
key[0x23:0x27] = int_to_base36(random.randint(0x75b27, 0x84e76)).encode()
a4 = key[0x23:0x27]
a6 = key[0x27:0x28]
a7 = key[0x28:0x29]
calc_value = xx_key_calc_141099580(2, a2, a3, a4, a5, a6, a7)
# print('calc_value:',calc_value)
# check_part=key[8:0xd]+key[0xe:0x14]+key[0x15:0x1b]+key[0x2a:0x30]
check_part = re_transform_cmp_141099100(calc_value)
key[8:0xd] = check_part[:5]
key[0xe:0x14] = check_part[5:5+6]
key[0x15:0x1b] = check_part[11:17]
key[0x2a:0x30] = check_part[17:23]
return bytes(key)
def xx_get_key_type_14108B110(key: bytes):
# pos=key.rfind(b'-')
# subkey=key[pos-0xe:pos]
# ktype=subkey[6]
assert len(key) == 48, 'key len error'
ktype = key[33]
t = [0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 0, 'S', 'P']
if chr(ktype) in t:
return t.index(chr(ktype))
else:
return 0
def re_key_type(target: int) -> str:
# 0-0xd
assert 0 <= target <= 13, 'key type error!([0,13])'
t = [0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 0, 'S', 'P']
return t[target]
def dec_md(MachineGuid:bytes,md:bytes):
key: bytes = MachineGuid[:16]
dec = blowfish_dec(key, md)
print(dec)
print(dec.hex())
def test_kg():
MachineGuid = get_machine_guid()
print('MachineGuid:',MachineGuid)
#产品id信息 'ACUW18ZA' ACDSee 旗舰版 18 中文
pid2 = get_acd18_lclient_pid2()
d_pid2 = bf_dec_pid2(MachineGuid.encode(), pid2)
print('d_pid2:',d_pid2)
#计算得到的md5值的前4字节参与key验证计算
xx_pid2_md5value_143616438 = xx_calc_pid2_md5_1410993B0(d_pid2.encode())
print('pid2_md5:',xx_pid2_md5value_143616438.hex())
# test_license_key_validation()
valid_key = genkey(random.randint(1, 9))
print('key:',valid_key.decode())
ret = xx_check_key_141099A40(valid_key)
print(ret)
if __name__ == '__main__':
test_kg()
pass
清理卸载后残留垃圾
reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\ACD Systems" /f
reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ACD Systems" /f
reg delete "HKEY_CURRENT_USER\Software\ACD Systems" /f
rd /s /q "%localappdata%\ACD Systems\3rd Party Plugins"
rd /s /q "%localappdata%\ACD Systems\Accelerators"
rd /s /q "%localappdata%\ACD Systems\acdIDInTouch2"
rd /s /q "%localappdata%\ACD Systems\Actions"
rd /s /q "%localappdata%\ACD Systems\Catalogs"
rd /s /q "%localappdata%\ACD Systems\data"
rd /s /q "%localappdata%\ACD Systems\GeoTag"
rd /s /q "%localappdata%\ACD Systems\ICMCache"
rd /s /q "%localappdata%\ACD Systems\LUTs"
rd /s /q "%localappdata%\ACD Systems\Presets"
rd /s /q "%localappdata%\ACD Systems\SavedSearches"
rd /s /q "%localappdata%\ACD Systems\Saved Selections"
rd /s /q "%localappdata%\ACD Systems\Logs"
rd /s /q "%AppData%\ACD Systems"

浙公网安备 33010602011771号