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" 
posted @ 2025-07-28 13:57  DirWangK  阅读(673)  评论(0)    收藏  举报