anytxt searcher 1.3.2998 记录

anytxt searcher 1.3.2998 记录

文件信息

版本 1.3.2998 
PE64
    操作系统: Windows(Vista)[AMD64, 64 位, GUI]
    链接程序: Microsoft Linker(14.16.27049)
    编译器: Microsoft Visual C/C++(19.16.27049)[LTCG/C++]
    语言: C++
    库: Microsoft C/C++ Runtime[dynamic]
    库: Qt(5.14.2.0)
    工具: Visual Studio(2017, v15.9)
    签名工具: Windows Authenticode(2.0)[PKCS #7]
    附加: Binary[偏移=0x00f2a000,大小=0x59c8]
        证书: WinAuth(2.0)[PKCS #7]
  • qt5 动态链接,

  • ollvm混淆

  • 可通过zh_CHS.ini 文件中字符串id进行关键函数定位

  • 日志文件目录C:\ProgramData\Anytxt\log

  • AI赋能,大部分工作由AI完成。

这里只记录许可解析流程,没有进行按钮事件分析,而是直接定位CLicence类,分析许可解析加载的过程。

扫码登陆应该是Protobuf gRPC

可用工具还原.proto marin-m/pbtk: A toolset for reverse engineering and fuzzing Protobuf-based apps

User.proto

感觉大有可为,嘿嘿,略;

syntax = "proto3";

package User;

service UserGreeter {
    rpc LoginByWechat(WechatTokenRequest) returns (TokenResponse);
    rpc LoginByGoogle(GoogleTokenRequest) returns (TokenResponse);
    rpc LoginByMicrosoft(MicrosoftTokenRequest) returns (TokenResponse);
    rpc LoginByPasswd(AccountTokenRequest) returns (TokenResponse);
    rpc Logout(LogoutRequest) returns (BoolResponse);
    rpc GetUserInfo(GetUserInfoRequest) returns (ValueResponse);
    rpc CheckUserDevice(CheckUserDeviceRequest) returns (BoolResponse);
    rpc SetUserInfo(SetUserInfoRequest) returns (BoolResponse);
    rpc UserGetVipReward(GetVipRewardRequest) returns (BoolResponse);
    rpc DeviceOnline(DeviceOnlineRequest) returns (BoolResponse);
    rpc GetUtcTime(Empty) returns (UtcTimeResponse);
    rpc GetRunTimes(GetRunTimesRequest) returns (RunTimesResponse);
    rpc IsServerOK(IsServerOKRequest) returns (BoolResponse);
    rpc GetOption(GetOptionRequest) returns (ValueResponse);
    rpc OrderCreate(OrderCreateRequest) returns (OrderResponse);
    rpc OrderCheck(OrderCheckRequest) returns (BoolResponse);
    rpc OrderCancel(OrderCancelRequest) returns (BoolResponse);
    rpc GetPlans(GetPlansRequest) returns (GetPlansResponse);
    rpc GetBonusStatistics(GetBonusStatisticsRequest) returns (ValueResponse);
    rpc ApplyForBonusExchange(ApplyForBonusExchangeRequest) returns (BoolResponse);
    rpc GetApplicationInfo(GetApplicationInfoRequest) returns (ValueResponse);
    rpc GetWechatQRcode(Empty) returns (GetWechatQRcodeResponse);
    rpc CheckWechatQRcode(CheckWechatQRcodeRequest) returns (CheckWechatQRcodeResponse);
}

message WechatTokenRequest {
    string wechat_id = 1;
    int64 device_serial_number = 2;
}

message GoogleTokenRequest {
    string google_id = 1;
    int64 device_serial_number = 2;
}

message MicrosoftTokenRequest {
    string microsoft_id = 1;
    int64 device_serial_number = 2;
}

message AccountTokenRequest {
    string username = 1;
    string password = 2;
    int64 device_serial_number = 3;
}

message LogoutRequest {
    string user_token = 1;
    int64 device_serial_number = 2;
}

message GetUserInfoRequest {
    string user_token = 1;
    int64 value_key = 2;
}

message SetUserInfoRequest {
    string user_token = 1;
    int64 value_key = 2;
    string value_content = 3;
}

message CheckUserDeviceRequest {
    string user_token = 1;
    int64 device_serial_number = 2;
}

message GetOptionRequest {
    string key = 1;
    bool success = 2;
}

message TokenResponse {
    string content = 1;
    bool success = 2;
}

message ValueResponse {
    string content = 1;
    bool success = 2;
}

message BoolResponse {
    bool success = 1;
}

message UtcTimeResponse {
    int64 utc_time = 1;
}

message RunTimesResponse {
    int64 run_times = 1;
}

message Empty {
    
}

message GetVipRewardRequest {
    string user_token = 1;
}

message DeviceOnlineRequest {
    int64 device_serial_number = 1;
    int64 recommender_id = 2;
    string location = 3;
    string os_arch = 4;
    string os_name = 5;
    string os_version = 6;
    int64 anytxt_version = 7;
}

message GetRunTimesRequest {
    int64 device_serial_number = 1;
}

message IsServerOKRequest {
    string version = 1;
}

message OrderCreateRequest {
    string user_token = 1;
    int64 plan_id = 2;
    int64 volumes = 3;
    int64 pay_way = 4;
    double price = 5;
    int32 plan_language = 6;
}

message OrderCheckRequest {
    int64 order_id = 1;
    string user_token = 2;
}

message OrderCancelRequest {
    int64 order_id = 1;
    string user_token = 2;
}

message OrderResponse {
    int64 order_id = 1;
    string pay_url = 2;
    bool success = 3;
}

message GetPlansRequest {
    int32 language = 1;
}

message GetPlansResponse {
    bool success = 1;
    string plans_json = 2;
}

message GetBonusStatisticsRequest {
    string user_token = 1;
}

message ApplyForBonusExchangeRequest {
    string user_token = 1;
}

message GetApplicationInfoRequest {
    string user_token = 1;
    int64 value_key = 2;
}

message GetWechatQRcodeResponse {
    bool success = 1;
    string json_value = 2;
}

message CheckWechatQRcodeRequest {
    string ticket = 1;
}

message CheckWechatQRcodeResponse {
    bool success = 1;
    string json_value = 2;
}

CLicence

QSettings 存储许可信息

对应注册表:

HKEY_CURRENT_USER\Software\CBEWIN\Anytxt 字符串值License

HKEY_LOCAL_MACHINE

__int64 __fastcall CLicence_14026AA00(CLicence *CLicence)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v49 = 0xFFFFFFFFFFFFFFFEui64;
  v50 = CLicence;
  LOBYTE(CLicence->Offline_status_0) = 1;
  QDate::QDate(&CLicence->QDate_startDate_18);
  QDate::QDate(&CLicence->QDate_Expireddate_20);
  QString::QString(&CLicence->qstr_licinfo_28);
  CLicence->field_30 = 0;
  QString::QString(&CLicence->qstr__lic_mem_anytxt_38);
  QString::QString(&CLicence->qstr_lic_40);
  QReadWriteLock::QReadWriteLock(&CLicence->qreadwritelock48, 0i64);
  QString::QString(&CLicence->qstr_reg_CBEWIN_50);
  QString::QString(&CLicence->qstr_reg_crent_user_CBEWIN_58);
  QString::QString(&CLicence->qstr_reg_user_CBEWIN_60);
  // __int64 __fastcall sub_14026B210(__int64 a1, __int64 a2)
  // {
  //   __int64 result; // rax
  //   __int64 v3; // [rsp+0h] [rbp-48h] BYREF
  //   double v4; // [rsp+20h] [rbp-28h]
  //   __m128i si128; // [rsp+28h] [rbp-20h]
  //   unsigned __int64 v6; // [rsp+38h] [rbp-10h]

  //   v6 = &v3 ^ qword_140E70770;
  //   si128 = _mm_load_si128(&n_183_140CE5970);
  //   v4 = (7 - (3 + 3)) * 1;
  //   result = (1 * v4);
  //   if ( result <= 0 )
  //     return result;

  //   *(a2 + 0xF) = 0x1FF;
  //   result = a2;
  //   *a2 = 0xAAE63FB7;
  //   *(a2 + 4) = 0x92A6FAA5;
  //   *(a2 + 8) = 0xB0E132B7;
  //   *(a2 + 0xC) = 0xEFFF;
  //   *(a2 + 0xE) = 0xB7;
  //   return result;
  // }
  v3 = sub_14026B210(v2, v52);
  v4 = v3;
  if ( v3[0x10] )
  {
    // .lic.mem.anytxt
    *v3 ^= 0x99u;
    *(v3 + 1) ^= 0x53u;
    *(v3 + 2) ^= 0x8Fu;
    *(v3 + 3) ^= 0xC9u;
    *(v3 + 4) ^= 0x8Bu;
    *(v3 + 5) ^= 0x97u;
    *(v3 + 6) ^= 0xC3u;
    *(v3 + 7) = ~v3[7];
    *(v3 + 8) ^= 0x99u;
    *(v3 + 9) ^= 0x53u;
    *(v3 + 0xA) ^= 0x8Fu;
    *(v3 + 0xB) ^= 0xC9u;
    *(v3 + 0xC) ^= 0x8Bu;
    *(v3 + 0xD) ^= 0x97u;
    *(v3 + 0xE) ^= 0xC3u;
    *(v3 + 0xF) = ~v3[0xF];
    *(v3 + 0x10) = 0;
  }

  QString::QString(v39);
  v5 = QString::QString(v44, v4);
  QString::operator=(v39, v5);
  QString::~QString(v44);
  QString::operator=(&CLicence->qstr__lic_mem_anytxt_38, v39);
  v6 = QString::begin(v39);
  v7 = QString::end(v39);
  v8 = 0i64;
  v9 = (v7 - v6 + 1) >> 1;
  if ( v6 > v7 )
    v9 = 0i64;

  if ( v9 )
  {
    while ( v9 )
    {
      *v6 = 0;
      v6 = (v6 + 2);
      --v9;
    }
  }

  QString::~QString(v39);
  for ( i = 0i64; i < 0x10; ++i )
    v52[i] |= 0x91 - i;

  // __int64 __fastcall sub_14026B3A0(__int64 a1, __int64 a2)
  // {
  //   __int64 result; // rax

  //   *(a2 + 2) = 0x1AFE674;
  //   result = a2;
  //   *a2 = 0xE7C9;
  //   return result;
  // }
  v11 = sub_14026B3A0(i, v51);
  v12 = v11;
  if ( v11[5] )
  {
    // .lic
    *v11 ^= 0xE7u;
    *(v11 + 1) ^= 0x8Bu;
    *(v11 + 2) ^= 0x1Du;
    *(v11 + 3) ^= 0x85u;
    *(v11 + 4) ^= 0xAFu;
    *(v11 + 5) = 0;
  }

  QString::QString(v40);
  v13 = QString::QString(v45, v12);
  QString::operator=(v40, v13);
  QString::~QString(v45);
  QString::operator=(&CLicence->qstr_lic_40, v40);
  v14 = QString::begin(v40);
  v15 = QString::end(v40);
  v16 = (v15 - v14 + 1) >> 1;
  if ( v14 > v15 )
    v16 = 0i64;

  if ( v16 )
  {
    while ( v16 )
    {
      *v14 = 0;
      v14 = (v14 + 2);
      --v16;
    }
  }

  QString::~QString(v40);
  for ( j = 0i64; j < 5; ++j )
    v51[j] |= 0x91 - j;

  // unsigned __int64 __fastcall sub_14026B520(__int64 a1, _DWORD *a2)
  // {
  //   // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  //   v9 = &v3 ^ qword_140E70770;
  //   si128 = _mm_load_si128(&n_127_140CE5640);
  //   v7 = 0xA97E;
  //   v6 = _mm_load_si128(&n_121_140CE5290);
  //   v8 = 0x7F;
  //   v4 = (7 - (3 + 3)) * 1;
  //   result = (1 * v4);
  //   if ( result <= 0 )
  //     return result;

  //   a2[8] = 0x17FA97E;
  //   result = a2;
  //   *a2 = 0x543AAC7F;
  //   a2[1] = 0xD4560D86;
  //   a2[2] = 0x4020AB76;
  //   a2[3] = 0xDE510298;
  //   a2[4] = 0x5E23A279;
  //   a2[5] = 0xC04D0796;
  //   a2[6] = 0x513AB576;
  //   a2[7] = 0xC05C039A;
  //   return result;
  // }
  v18 = sub_14026B520(j, &v54);
  v19 = v18;
  if ( v18[0x23] )
  {
    // HKEY_LOCAL_MACHINE\SOFTWARE\CBEWIN
    *v18 ^= 0x37u;
    *(v18 + 1) ^= 0xE7u;
    *(v18 + 2) ^= 0x7Fu;
    *(v18 + 3) ^= 0xDu;
    *(v18 + 4) ^= 0xD9u;
    *(v18 + 5) ^= 0x41u;
    *(v18 + 6) ^= 0x19u;
    *(v18 + 7) ^= 0x97u;
    *(v18 + 8) ^= 0x37u;
    *(v18 + 9) ^= 0xE7u;
    *(v18 + 0xA) ^= 0x7Fu;
    *(v18 + 0xB) ^= 0xDu;
    *(v18 + 0xC) ^= 0xD9u;
    *(v18 + 0xD) ^= 0x41u;
    *(v18 + 0xE) ^= 0x19u;
    *(v18 + 0xF) ^= 0x97u;
    *(v18 + 0x10) ^= 0x37u;
    *(v18 + 0x11) ^= 0xE7u;
    *(v18 + 0x12) ^= 0x7Fu;
    *(v18 + 0x13) ^= 0xDu;
    *(v18 + 0x14) ^= 0xD9u;
    *(v18 + 0x15) ^= 0x41u;
    *(v18 + 0x16) ^= 0x19u;
    *(v18 + 0x17) ^= 0x97u;
    *(v18 + 0x18) ^= 0x37u;
    *(v18 + 0x19) ^= 0xE7u;
    *(v18 + 0x1A) ^= 0x7Fu;
    *(v18 + 0x1B) ^= 0xDu;
    *(v18 + 0x1C) ^= 0xD9u;
    *(v18 + 0x1D) ^= 0x41u;
    *(v18 + 0x1E) ^= 0x19u;
    *(v18 + 0x1F) ^= 0x97u;
    *(v18 + 0x20) ^= 0x37u;
    *(v18 + 0x21) ^= 0xE7u;
    *(v18 + 0x22) ^= 0x7Fu;
    *(v18 + 0x23) = 0;
  }

  QString::QString(v41);
  v20 = QString::QString(v46, v19);
  QString::operator=(v41, v20);
  QString::~QString(v46);
  QString::operator=(&CLicence->qstr_reg_CBEWIN_50, v41);
  v21 = QString::begin(v41);
  v22 = QString::end(v41);
  v23 = (v22 - v21 + 1) >> 1;
  if ( v21 > v22 )
    v23 = 0i64;

  if ( v23 )
  {
    while ( v23 )
    {
      *v21 = 0;
      v21 = (v21 + 2);
      --v23;
    }
  }

  QString::~QString(v41);
  for ( k = 0i64; k < 0x23; ++k )
    *(v55 + k + 0x18) |= 0x91 - k;

  // __int64 __fastcall sub_14026B6F0(__int64 a1, __int64 a2)
  // {
  //   // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  //   v8 = &v3 ^ qword_140E70770;
  //   si128 = _mm_load_si128(&n_209_140CE4B00);
  //   v7 = 0x47D7;
  //   v6 = _mm_load_si128(&n_203_140CE4C50);
  //   v4 = (7 - (3 + 3)) * 1;
  //   result = (1 * v4);
  //   if ( result <= 0 )
  //     return result;

  //   *(a2 + 0x21) = 0x147;
  //   result = a2;
  //   *a2 = 0x32E80CD1;
  //   *(a2 + 4) = 0x952A347C;
  //   *(a2 + 8) = 0x3FE302CB;
  //   *(a2 + 0xC) = 0x822C227C;
  //   *(a2 + 0x10) = 0x24FE1BCB;
  //   *(a2 + 0x14) = 0x86282365;
  //   *(a2 + 0x18) = 0x28F102CB;
  //   *(a2 + 0x1C) = 0x8E283261;
  //   *(a2 + 0x20) = 0xD7;
  //   return result;
  // }
  v25 = sub_14026B6F0(k, v53);
  v26 = v25;
  if ( v25[0x22] )
  {
    // HKEY_CURRENT_USER\SOFTWARE\CBEWIN

    *v25 ^= 0x99u;
    *(v25 + 1) ^= 0x47u;
    *(v25 + 2) ^= 0xADu;
    *(v25 + 3) ^= 0x6Bu;
    *(v25 + 4) ^= 0x23u;
    *(v25 + 5) ^= 0x77u;
    *(v25 + 6) ^= 0x7Fu;
    *(v25 + 7) ^= 0xC7u;
    *(v25 + 8) ^= 0x99u;
    *(v25 + 9) ^= 0x47u;
    *(v25 + 0xA) ^= 0xADu;
    *(v25 + 0xB) ^= 0x6Bu;
    *(v25 + 0xC) ^= 0x23u;
    *(v25 + 0xD) ^= 0x77u;
    *(v25 + 0xE) ^= 0x7Fu;
    *(v25 + 0xF) ^= 0xC7u;
    *(v25 + 0x10) ^= 0x99u;
    *(v25 + 0x11) ^= 0x47u;
    *(v25 + 0x12) ^= 0xADu;
    *(v25 + 0x13) ^= 0x6Bu;
    *(v25 + 0x14) ^= 0x23u;
    *(v25 + 0x15) ^= 0x77u;
    *(v25 + 0x16) ^= 0x7Fu;
    *(v25 + 0x17) ^= 0xC7u;
    *(v25 + 0x18) ^= 0x99u;
    *(v25 + 0x19) ^= 0x47u;
    *(v25 + 0x1A) ^= 0xADu;
    *(v25 + 0x1B) ^= 0x6Bu;
    *(v25 + 0x1C) ^= 0x23u;
    *(v25 + 0x1D) ^= 0x77u;
    *(v25 + 0x1E) ^= 0x7Fu;
    *(v25 + 0x1F) ^= 0xC7u;
    *(v25 + 0x20) ^= 0x99u;
    *(v25 + 0x21) ^= 0x47u;
    *(v25 + 0x22) = 0;
  }

  QString::QString(v42);
  v27 = QString::QString(v47, v26);
  QString::operator=(v42, v27);
  QString::~QString(v47);
  QString::operator=(&CLicence->qstr_reg_crent_user_CBEWIN_58, v42);
  v28 = QString::begin(v42);
  v29 = QString::end(v42);
  v30 = (v29 - v28 + 1) >> 1;
  if ( v28 > v29 )
    v30 = 0i64;

  if ( v30 )
  {
    while ( v30 )
    {
      *v28 = 0;
      v28 = (v28 + 2);
      --v30;
    }
  }

  QString::~QString(v42);
  for ( m = 0i64; m < 0x22; ++m )
    v53[m] |= 0x91 - m;

  // __int64 __fastcall sub_14026B8C0(__int64 a1, __int64 a2)
  // {
  //   // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  //   v8 = &v3 ^ qword_140E70770;
  //   si128 = _mm_load_si128(&n_207_140CE4B60);
  //   v7 = 0xF9DF72D0;
  //   v6 = _mm_load_si128(&n_210_140CE4C10);
  //   v4 = (7 - (3 + 3)) * 1;
  //   result = (1 * v4);
  //   if ( result <= 0 )
  //     return result;

  //   *(a2 + 0x23) = 0x1F9;
  //   result = a2;
  //   *a2 = 0xA0D470CF;
  //   *(a2 + 4) = 0x8C244E1A;
  //   *(a2 + 8) = 0xD7CD68D5;
  //   *(a2 + 0xC) = 0x88315E01;
  //   *(a2 + 0x10) = 0xA5C577D2;
  //   *(a2 + 0x14) = 0xBD117416;
  //   *(a2 + 0x18) = 0x9CE35AF0;
  //   *(a2 + 0x1C) = 0x8C355819;
  //   *(a2 + 0x20) = 0x72D0;
  //   *(a2 + 0x22) = 0xDF;
  //   return result;
  // }
  v32 = sub_14026B8C0(m, v55);
  v33 = v32;
  if ( v32[0x24] )
  {
    // HKEY_USERS\.DEFAULT\Software\CBEWIN
    *v32 ^= 0x87u;
    *(v32 + 1) ^= 0x3Bu;
    *(v32 + 2) ^= 0x91u;
    *(v32 + 3) ^= 0xF9u;
    *(v32 + 4) ^= 0x45u;
    *(v32 + 5) ^= 0x1Bu;
    *(v32 + 6) ^= 0x77u;
    *(v32 + 7) ^= 0xC9u;
    *(v32 + 8) ^= 0x87u;
    *(v32 + 9) ^= 0x3Bu;
    *(v32 + 0xA) ^= 0x91u;
    *(v32 + 0xB) ^= 0xF9u;
    *(v32 + 0xC) ^= 0x45u;
    *(v32 + 0xD) ^= 0x1Bu;
    *(v32 + 0xE) ^= 0x77u;
    *(v32 + 0xF) ^= 0xC9u;
    *(v32 + 0x10) ^= 0x87u;
    *(v32 + 0x11) ^= 0x3Bu;
    *(v32 + 0x12) ^= 0x91u;
    *(v32 + 0x13) ^= 0xF9u;
    *(v32 + 0x14) ^= 0x45u;
    *(v32 + 0x15) ^= 0x1Bu;
    *(v32 + 0x16) ^= 0x77u;
    *(v32 + 0x17) ^= 0xC9u;
    *(v32 + 0x18) ^= 0x87u;
    *(v32 + 0x19) ^= 0x3Bu;
    *(v32 + 0x1A) ^= 0x91u;
    *(v32 + 0x1B) ^= 0xF9u;
    *(v32 + 0x1C) ^= 0x45u;
    *(v32 + 0x1D) ^= 0x1Bu;
    *(v32 + 0x1E) ^= 0x77u;
    *(v32 + 0x1F) ^= 0xC9u;
    *(v32 + 0x20) ^= 0x87u;
    *(v32 + 0x21) ^= 0x3Bu;
    *(v32 + 0x22) ^= 0x91u;
    *(v32 + 0x23) ^= 0xF9u;
    *(v32 + 0x24) = 0;
  }

  QString::QString(v43);
  v34 = QString::QString(v48, v33);
  QString::operator=(v43, v34);
  QString::~QString(v48);
  QString::operator=(&CLicence->qstr_reg_user_CBEWIN_60, v43);
  v35 = QString::begin(v43);
  v36 = QString::end(v43);
  v37 = (v36 - v35 + 1) >> 1;
  if ( v35 > v36 )
    v37 = 0i64;

  if ( v37 )
  {
    while ( v37 )
    {
      *v35 = 0;
      v35 = (v35 + 2);
      --v37;
    }
  }

  QString::~QString(v43);
  do
  {
    v55[v8] |= 0x91 - v8;
    ++v8;
  }
  while ( v8 < 0x24 );

  GetHardwareID_14026C5D0(CLicence);
  x_lic_1402745C0(CLicence);
  return CLicence;
}

x_lic_1402745C0

__int64 __fastcall x_lic_1402745C0(CLicence *CLicence)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v8 = 0xFFFFFFFFFFFFFFFEui64;
  ClearLicence_mem_temp_1402742B0((__int64)CLicence);
  v2 = QString::QString((QString *)v6);
  v10 = LoadAndUpdateLicence_140275EB0((__int64)CLicence, (__int64)v2) && LOBYTE(CLicence->Offline_status_0);
  QString::~QString(v6);
  if ( (int)((double)1 * (((double)7 - ((double)3 + (double)3)) * (double)(LOBYTE(CLicence->Offline_status_0) == 0))) )
  {
    ClearLicence_mem_temp_1402742B0((__int64)CLicence);
    v3 = 0;
    goto LABEL_18;
  }

  v7 = ((double)7 - ((double)3 + (double)3)) * (double)0;
  if ( (int)((double)1 * v7) )
  {
    if ( (int)((double)1 * (((double)7 - ((double)3 + (double)3)) * (double)1)) )
    {
      v3 = v10;
      goto LABEL_18;
    }
  }
  else
  {
    CLicence_14026AA00(&CLicencea);
    v4 = (unsigned __int8)sub_140275640(&CLicencea, 0i64) && (unsigned __int8)sub_14026CC00((__int64)&CLicencea);
    if ( (int)((double)1 * (((double)7 - ((double)3 + (double)3)) * (double)v4)) )
      sub_140275640(CLicence, 0i64);

    QString::~QString(&CLicencea.qstr_reg_user_CBEWIN_60);
    QString::~QString(&CLicencea.qstr_reg_crent_user_CBEWIN_58);
    QString::~QString(&CLicencea.qstr_reg_CBEWIN_50);
    QReadWriteLock::~QReadWriteLock((QReadWriteLock *)&CLicencea.qreadwritelock48);
    QString::~QString(&CLicencea.qstr_lic_40);
    QString::~QString(&CLicencea.qstr__lic_mem_anytxt_38);
    QString::~QString(&CLicencea.qstr_licinfo_28);
  }

  v3 = v10;

LABEL_18:
  result = 1i64;
  if ( (int)((double)1 * (((double)7 - ((double)3 + (double)3)) * (double)1)) > 0 )
    return v3;

  return result;
}

许可加载解析流程

LoadAndUpdateLicence_140275EB0

// __int64 LoadAndUpdateLicence(CLicence *lic, const QString *defaultLic)
__int64 __fastcall LoadAndUpdateLicence_140275EB0(CLicence *CLicence, void *a2)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v77 = 0xFFFFFFFFFFFFFFFEui64;
  STACK[0x598] = &v50 ^ qword_140E70770;
  v4 = 0;
  v59 = 0;
  QString::QString(&hexInput);
  v51 = (7 - (3 + 3)) * *(*a2 + 4i64);
  if ( (1 * v51) )
  {
    QString::operator=(&hexInput, a2);
    goto LABEL_52;
  }

  v51 = (7 - (3 + 3)) * 0;
  if ( (1 * v51) )
  {
    v51 = (7 - (3 + 3)) * 1;
    if ( !(1 * v51) )
      goto LABEL_52;

    v5 = (7 - (3 + 3)) * 5.0;

LABEL_14:
    v51 = v5;
    goto LABEL_52;
  }

  if ( !CLicence->field_30 || (v6 = 1, !*(CLicence->qstr_licinfo_28 + 4)) )
    v6 = 0;

  v51 = (7 - (3 + 3)) * v6;
  if ( (1 * v51) )
  {
    QString::operator=(&hexInput, &CLicence->qstr_licinfo_28);
    goto LABEL_52;
  }

  v51 = (7 - (3 + 3)) * 0;
  if ( (1 * v51) )
  {
    v51 = (7 - (3 + 3)) * 1;
    if ( !(1 * v51) )
      goto LABEL_52;

    v5 = (7 - (3 + 3)) * 10.0;
    goto LABEL_14;
  }

  QReadLocker::QReadLocker(v68, &CLicence->qreadwritelock48);
  sub_1402106A0(&v96);
  v7 = QString::toStdString(&CLicence->qstr__lic_mem_anytxt_38, v98);
  v59 = 1;
  if ( *(v7 + 0x18) >= 0x10ui64 )
    v7 = *v7;

  if ( !getfilesize_14026A7D0(&v96, v7) || !v96 || !v97 || (v8 = 1, *(v97 + 8) <= 0) )
    v8 = 0;

  v51 = (7 - (3 + 3)) * v8;
  v9 = (1 * v51);
  v59 = 0;
  std::string::~string(v98);
  if ( v9 )
  {
    if ( v96 && v97 )
      v10 = *v97;
    else
      v10 = 0i64;

    v11 = QString::QString(v67, v10);
    QString::operator=(&hexInput, v11);
    QString::~QString(v67);
  }

  sub_140210A80(&v96);
  QReadLocker::~QReadLocker(v68);
  GetConfigFilePath_140049360(&lic_type[1], &CLicence->qstr_lic_40);
  if ( *(hexInput + 4) || (v12 = QFileInfo::exists(&lic_type[1]), v13 = 1, !v12) )
    v13 = 0;

  v51 = (7 - (3 + 3)) * v13;
  if ( (1 * v51) )
  {
    v54 = 0;
    v14 = sub_1402793C0(&v54, v92);
    sub_14027DE90(v14);
    v15 = stdstring_140017B00(v99, v14);
    if ( *(v15 + 0x18) >= 0x10ui64 )
      v15 = *v15;

    QString::QString(v61, v15);
    v16 = QSettings::QSettings(&v80, &lic_type[1], 1i64);
    v17 = QVariant::QVariant(&vars0);
    v18 = QSettings::value(v16, v78, v61, v17);
    v19 = QVariant::toString(v18, v69);
    QString::operator=(&hexInput, v19);
    QString::~QString(v69);
    QVariant::~QVariant(v78);
    QVariant::~QVariant(&vars0);
    QSettings::~QSettings(&v80);
    QString::~QString(v61);
    free_stdstr_140017BF0(v99);
    for ( i = 0i64; i < 0xF; ++i )
      v92[i] |= 0x91 - i;
  }

  v51 = (7 - (3 + 3)) * (*(hexInput + 4) == 0);
  if ( (1 * v51) )
  {
    v55 = 0;
    v21 = sub_140279560(&v55, v93);
    // Anytxt/License
    sub_14027DE40(v21);
    v22 = stdstring_140017B00(v100, v21);
    if ( *(v22 + 0x18) >= 0x10ui64 )
      v22 = *v22;

    QString::QString(v62, v22);
    v23 = QSettings::QSettings(v83, &CLicence->qstr_reg_CBEWIN_50, 0i64);
    v24 = QVariant::QVariant(v82);
    v25 = QSettings::value(v23, &v81, v62, v24);
    v26 = QVariant::toString(v25, v70);
    QString::operator=(&hexInput, v26);
    QString::~QString(v70);
    QVariant::~QVariant(&v81);
    QVariant::~QVariant(v82);
    QSettings::~QSettings(v83);
    QString::~QString(v62);
    free_stdstr_140017BF0(v100);
    for ( j = 0i64; j < 0xF; ++j )
      v93[j] |= 0x91 - j;
  }

  v51 = (7 - (3 + 3)) * (*(hexInput + 4) == 0);
  if ( (1 * v51) )
  {
    v56 = 0;
    // unsigned __int64 __fastcall sub_140279700(__int64 a1, _DWORD *a2)
    // {
    //   unsigned __int64 result; // rax
    //   __int64 v3; // [rsp+0h] [rbp-48h] BYREF
    //   double v4; // [rsp+20h] [rbp-28h]
    //   int v5; // [rsp+28h] [rbp-20h]
    //   int v6; // [rsp+2Ch] [rbp-1Ch]
    //   int v7; // [rsp+30h] [rbp-18h]
    //   __int16 v8; // [rsp+34h] [rbp-14h]
    //   char v9; // [rsp+36h] [rbp-12h]
    //   unsigned __int64 v10; // [rsp+38h] [rbp-10h]

    //   v10 = &v3 ^ qword_140E70770;
    //   v5 = 0xCFAED364;
    //   v6 = 0xB760379D;
    //   v7 = 0xD5B2DE4C;
    //   v8 = 0x2696;
    //   v9 = 0x4F;
    //   v4 = (7 - (3 + 3)) * 1;
    //   result = (1 * v4);
    //   if ( result <= 0 )
    //     return result;

    //   a2[3] = 0x14F2696;
    //   result = a2;
    //   *a2 = 0xCFAED364;
    //   a2[1] = 0xB760379D;
    //   a2[2] = 0xD5B2DE4C;
    //   return result;
    // }
    v28 = sub_140279700(&v56, v94);
    // void __fastcall sub_14027DDF0(_BYTE *a1)
    // {
    //   if ( a1[0xF] )
    //   {
    //     *a1 ^= 0x25u;
    //     a1[1] ^= 0xBDu;
    //     a1[2] ^= 0xD7u;
    //     a1[3] ^= 0xBBu;
    //     a1[4] ^= 0xE5u;
    //     a1[5] ^= 0x43u;
    //     a1[6] ^= 0x4Fu;
    //     a1[7] ^= 0xFBu;
    //     a1[8] ^= 0x25u;
    //     a1[9] ^= 0xBDu;
    //     a1[0xA] ^= 0xD7u;
    //     a1[0xB] ^= 0xBBu;
    //     a1[0xC] ^= 0xE5u;
    //     a1[0xD] ^= 0x43u;
    //     a1[0xE] ^= 0x4Fu;
    //     a1[0xF] = 0;
    //   }
    // }
    sub_14027DDF0(v28);
    // Anytxt/License
    v29 = stdstring_140017B00(v101, v28);
    if ( *(v29 + 0x18) >= 0x10ui64 )
      v29 = *v29;

    QString::QString(v63, v29);
    v30 = QSettings::QSettings(v86, &CLicence->qstr_reg_crent_user_CBEWIN_58, 0i64);
    v31 = QVariant::QVariant(v85);
    v32 = QSettings::value(v30, v84, v63, v31);
    v33 = QVariant::toString(v32, v71);
    QString::operator=(&hexInput, v33);
    QString::~QString(v71);
    QVariant::~QVariant(v84);
    QVariant::~QVariant(v85);
    QSettings::~QSettings(v86);
    QString::~QString(v63);
    free_stdstr_140017BF0(v101);
    for ( k = 0i64; k < 0xF; ++k )
      v94[k] |= 0x91 - k;
  }

  v51 = (7 - (3 + 3)) * (*(hexInput + 4) == 0);
  if ( (1 * v51) )
  {
    v57[0] = 0;
    // unsigned __int64 __fastcall sub_1402798A0(__int64 a1, _DWORD *a2)
    // {
    //   unsigned __int64 result; // rax
    //   __int64 v3; // [rsp+0h] [rbp-48h] BYREF
    //   double v4; // [rsp+20h] [rbp-28h]
    //   int v5; // [rsp+28h] [rbp-20h]
    //   int v6; // [rsp+2Ch] [rbp-1Ch]
    //   int v7; // [rsp+30h] [rbp-18h]
    //   __int16 v8; // [rsp+34h] [rbp-14h]
    //   char v9; // [rsp+36h] [rbp-12h]
    //   unsigned __int64 v10; // [rsp+38h] [rbp-10h]

    //   v10 = &v3 ^ qword_140E70770;
    //   v5 = 0x8D8A61B8;
    //   v6 = 0x55425F9D;
    //   v7 = 0x97966C90;
    //   v8 = 0x4E96;
    //   v9 = 0x6D;
    //   v4 = (7 - (3 + 3)) * 1;
    //   result = (1 * v4);
    //   if ( result <= 0 )
    //     return result;

    //   a2[3] = 0x16D4E96;
    //   result = a2;
    //   *a2 = 0x8D8A61B8;
    //   a2[1] = 0x55425F9D;
    //   a2[2] = 0x97966C90;
    //   return result;
    // }
    v35 = sub_1402798A0(v57, v95);
    // void __fastcall sub_14027DDA0(_BYTE *a1)
    // {
    //   if ( a1[0xF] )
    //   {
    //     *a1 ^= 0xF9u;
    //     a1[1] ^= 0xFu;
    //     a1[2] ^= 0xF3u;
    //     a1[3] ^= 0xF9u;
    //     a1[4] ^= 0xE5u;
    //     a1[5] ^= 0x2Bu;
    //     a1[6] ^= 0x6Du;
    //     a1[7] ^= 0x19u;
    //     a1[8] ^= 0xF9u;
    //     a1[9] ^= 0xFu;
    //     a1[0xA] ^= 0xF3u;
    //     a1[0xB] ^= 0xF9u;
    //     a1[0xC] ^= 0xE5u;
    //     a1[0xD] ^= 0x2Bu;
    //     a1[0xE] ^= 0x6Du;
    //     a1[0xF] = 0;
    //   }
    // }
    sub_14027DDA0(v35);
    v36 = stdstring_140017B00(&STACK[0x578], v35);
    if ( *(v36 + 0x18) >= 0x10ui64 )
      v36 = *v36;

    QString::QString(v64, v36);
    v37 = QSettings::QSettings(v89, &CLicence->qstr_reg_user_CBEWIN_60, 0i64);
    v38 = QVariant::QVariant(v88);
    v39 = QSettings::value(v37, v87, v64, v38);
    v40 = QVariant::toString(v39, v72);
    QString::operator=(&hexInput, v40);
    QString::~QString(v72);
    QVariant::~QVariant(v87);
    QVariant::~QVariant(v88);
    QSettings::~QSettings(v89);
    QString::~QString(v64);
    free_stdstr_140017BF0(&STACK[0x578]);
    for ( m = 0i64; m < 0xF; ++m )
      v95[m] |= 0x91 - m;
  }

  QString::~QString(&lic_type[1]);

LABEL_52:
  v51 = (7 - (3 + 3)) * (*(hexInput + 4) == 0);
  if ( (1 * v51) )
  {
    ClearLicence_mem_temp_1402742B0(CLicence);
    goto LABEL_67;
  }

  v51 = (7 - (3 + 3)) * 0;
  if ( (1 * v51) )
  {
    v51 = (7 - (3 + 3)) * 1;
    if ( (1 * v51) )
      v51 = (7 - (3 + 3)) * 4.0;

    goto LABEL_67;
  }

  v51 = (7 - (3 + 3)) * (operator==(&hexInput, &CLicence->qstr_licinfo_28) == 0);
  if ( (1 * v51) )
  {
    ClearLicence_mem_temp_1402742B0(CLicence);
    QString::QString(&info);
    lic_mid_14026BAF0 = get_lic_mid_14026BAF0(CLicence);
    setkey_140206B60(v91, lic_mid_14026BAF0);
    v43 = DecodeLicenseData_140207160(v91, v73, &hexInput);
    QString::operator=(&info, v43);
    QString::~QString(v73);
    v51 = (7 - (3 + 3)) * (*(info + 4) == 0);
    if ( (1 * v51) )
    {
      cpuid_1401E5910 = get_cpuid_1401E5910(v74);
      v45 = QString::toLongLong(cpuid_1401E5910, 0i64, 0x10);
      setkey_140206B60(v90, v45);
      QString::~QString(v74);
      v46 = DecodeLicenseData_140207160(v90, v75, &hexInput);
      QString::operator=(&info, v46);
      QString::~QString(v75);
      v51 = (7 - (3 + 3)) * (*(info + 4) == 0);
      if ( (1 * v51) )
      {
        v51 = (7 - (3 + 3)) * 1;
        if ( (1 * v51) > 0 )
        {
          sub_140064350(v90);
          sub_140064350(v91);
          goto LABEL_65;
        }
      }

      sub_140064350(v90);
    }

    sub_140064350(v91);
    v52[0] = 0;
    lic_type[0] = 0;
    QDate::currentDate(&startDate);
    QDate::currentDate(&endDate_1);
    LOBYTE(v4) = LoadAndVerifyLicense_14027ADC0(CLicence, &info, lic_type, &startDate, &endDate_1, v52) == 0;
    v51 = (7 - (3 + 3)) * v4;
    if ( !(1 * v51) || (v51 = (7 - (3 + 3)) * 1, (1 * v51) <= 0) )
    {
      QWriteLocker::QWriteLocker(v76, &CLicence->qreadwritelock48);
      v48 = lic_type[0];
      CLicence->lic_type_4 = lic_type[0];
      LOBYTE(CLicence->Offline_status_0) = v52[0];
      CLicence->lictype_id_10 = sub_140273FC0(CLicence, v48);
      CLicence->QDate_startDate_18 = startDate;
      CLicence->QDate_Expireddate_20 = endDate_1;
      QString::operator=(&CLicence->qstr_licinfo_28, &hexInput);
      QWriteLocker::~QWriteLocker(v76);
      QString::~QString(&info);
      goto LABEL_67;
    }

LABEL_65:
    QString::~QString(&info);
    v47 = 0;
    goto LABEL_70;
  }

LABEL_67:
  v51 = (7 - (3 + 3)) * 1;
  if ( (1 * v51) <= 0 )
  {
    QString::~QString(&hexInput);
    return result;
  }

  v47 = *(CLicence->qstr_licinfo_28 + 4) > 0;

LABEL_70:
  QString::~QString(&hexInput);
  return v47;
}

关键流程

  • 先尝试使用mid作为key解析license数据
  • 解密失败后使用cpuid作为key进行解析
  v51 = (7 - (3 + 3)) * (operator==(&hexInput, &CLicence->qstr_licinfo_28) == 0);
  if ( (1 * v51) )
  {
    ClearLicence_mem_temp_1402742B0(CLicence);
    QString::QString(&info);
    lic_mid_14026BAF0 = get_lic_mid_14026BAF0(CLicence);
    setkey_140206B60(v91, lic_mid_14026BAF0);
    v43 = DecodeLicenseData_140207160(v91, v73, &hexInput);
    QString::operator=(&info, v43);
    QString::~QString(v73);
    v51 = (7 - (3 + 3)) * (*(info + 4) == 0);
    if ( (1 * v51) )
    {
      cpuid_1401E5910 = get_cpuid_1401E5910(v74);
      v45 = QString::toLongLong(cpuid_1401E5910, 0i64, 0x10);
      setkey_140206B60(v90, v45);
      QString::~QString(v74);
      v46 = DecodeLicenseData_140207160(v90, v75, &hexInput);
      QString::operator=(&info, v46);
        
       
  • 再次解密(两种方案)
  • 解析解密后的许可信息,‘-’进行分隔,4/5组信息
        
            QDate::currentDate(&startDate);
    QDate::currentDate(&endDate_1);
    LOBYTE(v4) = LoadAndVerifyLicense_14027ADC0(CLicence, &info, lic_type, &startDate, &endDate_1, v52) == 0;
    v51 = (7 - (3 + 3)) * v4;
    if ( !(1 * v51) || (v51 = (7 - (3 + 3)) * 1, (1 * v51) <= 0) )
    {
      QWriteLocker::QWriteLocker(v76, &CLicence->qreadwritelock48);
      v48 = lic_type[0];
      CLicence->lic_type_4 = lic_type[0];
      LOBYTE(CLicence->Offline_status_0) = v52[0];
      CLicence->lictype_id_10 = sub_140273FC0(CLicence, v48);
      CLicence->QDate_startDate_18 = startDate;
      CLicence->QDate_Expireddate_20 = endDate_1;
      QString::operator=(&CLicence->qstr_licinfo_28, &hexInput);
      QWriteLocker::~QWriteLocker(v76);
      QString::~QString(&info);
      goto LABEL_67;
    }

解密所用key的相关函数

GetHardwareID_14026C5D0

记作mid, 日志文件ATGUI_2026xxxx.log 中存在

:[ 96 : ATGUI.cpp] Logic cores, xxxxxxxxxxxx

void __fastcall GetHardwareID_14026C5D0(CLicence *CLicence)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v22 = 0xFFFFFFFFFFFFFFFEui64;
  v16 = CLicence;
  get_cpuid_1401E5910(v14);
  QString::QString(v13, "\\\\.\\C:");
  v1 = 0i64;
  FileW = CreateFileW(L"\\\\.\\C:", 0, 0, 0i64, 3u, 0, 0i64);
  InBuffer[0] = 0i64;
  memset(OutBuffer, 0, sizeof(OutBuffer));
  BytesReturned = 0;
  DeviceIoControl(FileW, 0x2D1400u, InBuffer, 0xCu, OutBuffer, 0x1000u, &BytesReturned, 0i64);
  v3 = QByteArray::QByteArray(v18, OutBuffer + OutBuffer[5], 0x20);
  v4 = sub_140204EA0(v3);
  v5 = QVariant::QVariant(v23, v4);
  v6 = QVariant::toString(v5, v17);
  QString::operator=(v13, v6);
  QString::~QString(v17);
  QVariant::~QVariant(v23);
  QByteArray::~QByteArray(v18);
  CloseHandle(FileW);
  CLicence_1 = v16;
  QString::append(v14, v13);
  v8 = QString::toUtf8(v14, v21);
  v9 = QCryptographicHash::hash(v20, v8, 0i64);
  v10 = QByteArray::toHex(v9, v19);
  v11 = *(*v10 + 4i64);
  v12 = QByteArray::data(v10);
  if ( v12 && v11 )
    v1 = ComputeHardwareHash_140043210(v12, v11);

  CLicence_1->ComputeHardwareHash_8 = v1;
  QByteArray::~QByteArray(v19);
  QByteArray::~QByteArray(v20);
  QByteArray::~QByteArray(v21);
  QString::~QString(v13);
  QString::~QString(v14);
}

get_cpuid_1401E5910

QString *__fastcall get_cpuid_1401E5910(QString *a1)
{
  unsigned int RAX; // edi
  __int64 v8; // rax
  __int64 v9; // rax
  __int64 v10; // rax
  const struct QString *v11; // rdi
  QString *v12; // rbx
  __int64 v14; // [rsp+0h] [rbp-68h] BYREF
  int v15; // [rsp+20h] [rbp-48h]
  char v16[8]; // [rsp+28h] [rbp-40h] BYREF
  char v17[8]; // [rsp+30h] [rbp-38h] BYREF
  __int64 v18; // [rsp+38h] [rbp-30h]
  QString *v19; // [rsp+40h] [rbp-28h]
  _DWORD v20[2]; // [rsp+48h] [rbp-20h] BYREF
  __int64 v21; // [rsp+50h] [rbp-18h]
  unsigned __int64 v22; // [rsp+58h] [rbp-10h]

  v18 = 0xFFFFFFFFFFFFFFFEui64;
  v22 = &v14 ^ qword_140E70770;
  v19 = a1;
  v15 = 0;
  QString::QString(a1, &byte_140A00602);
  v15 = 1;
  v20[0] = 0;
  _RAX = 1i64;
  __asm { cpuid }
  RAX = _RAX;
  v20[1] = _RBX;
  v21 = _RCX;
  v8 = QString::number(v17, _RDX, 0x10i64);
  v9 = QString::toUpper(v8, v16);
  QString::operator=(a1, v9);
  QString::~QString(v16);
  QString::~QString(v17);
  v10 = QString::number(v20, RAX, 0x10i64);
  v11 = QString::toUpper(v10, v17);
  v12 = QString::QString(v16, a1);
  v15 = 3;
  QString::append(v16, v11);
  QString::operator=(a1, v12);
  QString::~QString(v16);
  QString::~QString(v17);
  QString::~QString(v20);
  return a1;
}

DecodeLicenseData_140207160

// __int64 DecodeLicenseData(__int64 ctx, __int64 resultQStr, __int64 hexInput)
void *__fastcall DecodeLicenseData_140207160(PackContext *a1, __int64 resultQStr, __int64 hexInput)
{
  __int64 v5; // rax
  __int64 v6; // rdx
  QByteArray *v7; // r8
  __int64 v8; // rax
  char v10[8]; // [rsp+20h] [rbp-28h] BYREF
  char v11[8]; // [rsp+28h] [rbp-20h] BYREF
  char v12[8]; // [rsp+30h] [rbp-18h] BYREF
  __int64 v13; // [rsp+38h] [rbp-10h]
  QArrayData *QArrayData; // [rsp+58h] [rbp+10h] BYREF
  char v15; // [rsp+68h] [rbp+20h] BYREF

  QArrayData = resultQStr;
  v13 = 0xFFFFFFFFFFFFFFFEui64;
  v5 = QString::toLower(hexInput, v11);
  v6 = QString::toLatin1(v5, v10);
  QByteArray::fromHex(&v15, v6);
  QByteArray::~QByteArray(v10);
  QString::~QString(v11);
  v7 = QByteArray::QByteArray(v12, &v15);
  DecodeDataStream_140207230(a1, &QArrayData, v7);
  LODWORD(a1) = QArrayData->size;
  v8 = QByteArray::operator char const *(&QArrayData);
  QString::fromUtf8(resultQStr, v8, a1);
  QByteArray::~QByteArray(&QArrayData);
  QByteArray::~QByteArray(&v15);
  return resultQStr;
}

DecodeDataStream_140207230

QByteArray *__fastcall DecodeDataStream_140207230(PackContext *a1, QByteArray *out, __int64 data)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v35 = data;
  v34 = out;
  v30 = 0xFFFFFFFFFFFFFFFEui64;
  v3 = data;
  v4 = out;
  if ( a1->QArrayData_8->size )
  {
    QByteArray::QByteArray(&array, data);
    if ( *(*v3 + 4i64) < 3 )
    {
LABEL_6:
      QByteArray::QByteArray(v4);

LABEL_22:
      QByteArray::~QByteArray(&array);
      goto LABEL_23;
    }

    if ( QByteArray::at(&array, 0) != 3 )
    {
      LODWORD(a1->error_code_18) = 2;
      goto LABEL_6;
    }

    v6 = QByteArray::at(&array, 1);
    v28 = v6;
    v7 = QByteArray::mid(&array, &v33, 2i64);
    QByteArray::operator=(&array, v7);
    QByteArray::~QByteArray(&v33);
    size = array->size;
    v33 = 0;
    if ( size > 0 )
    {
      v9 = v33;
      v10 = size;
      v11 = 0;
      do
      {
        v12 = QByteArray::operator[](&array, v31, v9);
        v13 = QByteRef::operator char(v12);
        v14 = a1->QArrayData_8 + *a1->QArrayData_8->data + (v9 & 7);
        v15 = v11 ^ *v14 ^ QByteArray::at(&array, v9);
        v16 = QByteArray::operator[](&array, v32, v9);
        QByteRef::operator=(v16, v15);
        v11 = v13;
        ++v9;
      }
      while ( v9 < v10 );

      v6 = v28;
      v4 = v34;
      v3 = v35;
    }

    v17 = QByteArray::mid(&array, &v33, 1i64);
    QByteArray::operator=(&array, v17);
    QByteArray::~QByteArray(&v33);
    if ( (v6 & 2) != 0 )
    {
      if ( array->size < 2 )
      {
ERROR_3:
        LODWORD(a1->error_code_18) = 3;
        QByteArray::QByteArray(v4);
        goto LABEL_22;
      }

      QDataStream::QDataStream(v32, &array, 1i64);
      QDataStream::operator>>(v32, &v33);
      QDataStream::~QDataStream(v32);
      v18 = QByteArray::mid(&array, &v36, 2i64);
      QByteArray::operator=(&array, v18);
      QByteArray::~QByteArray(&v36);
      v19 = array->size;
      v20 = QByteArray::constData(&array);
      v21 = qChecksum(v20, v19);
      v22 = v21 == v33;
    }
    else
    {
      if ( (v6 & 4) == 0 )
        goto LABEL_19;

      if ( array->size < 20 )
        goto ERROR_3;

      QByteArray::left(&array, &v36, 0x14i64);
      v23 = QByteArray::mid(&array, &v28, 0x14i64);
      QByteArray::operator=(&array, v23);
      QByteArray::~QByteArray(&v28);
      // Sha1
      QCryptographicHash::QCryptographicHash(&v33, 2i64);
      QCryptographicHash::addData(&v33, &array);
      v24 = QCryptographicHash::result(&v33, &v28);
      v22 = QByteArray_equals_140204E20(v24, &v36);
      QByteArray::~QByteArray(&v28);
      QCryptographicHash::~QCryptographicHash(&v33);
      QByteArray::~QByteArray(&v36);
    }

    if ( !v22 )
      goto ERROR_3;

LABEL_19:
    if ( (v6 & 1) != 0 )
    {
      v25 = array->size;
      v26 = QByteArray::constData(&array);
      qUncompress(&v33, v26, v25);
      QByteArray::operator=(&array, &v33);
      QByteArray::~QByteArray(&v33);
    }

    LODWORD(a1->error_code_18) = 0;
    QByteArray::QByteArray(v4, &array);
    goto LABEL_22;
  }

  LODWORD(a1->error_code_18) = 1;
  QByteArray::QByteArray(out);

LABEL_23:
  QByteArray::~QByteArray(v3);
  return v4;
}

LoadAndVerifyLicense_14027ADC0

// 返回 1:许可证有效(isValid == true)
// 
// 返回 0:许可证无效或解析失败
// local variable allocation has failed, the output may be wrong!
__int64 __fastcall LoadAndVerifyLicense_14027ADC0(
        __int64 a1,
        __int64 licinfo,
        _DWORD *lic_type,
        _QWORD *startDate,
        __int64 endDate_1,
        void *Offline_status)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  a2[1] = 0xFFFFFFFFFFFFFFFEui64;
  PackContext_.mid = 0xCFDD4A4CCB0F024i64;
  PackContext_.QArrayData_8 = QArrayData::sharedNull();
  LODWORD(PackContext_.qw_10) = 0;
  *(&PackContext_.qw_10 + 4) = 1i64;
  v11 = QDateTime::currentMSecsSinceEpoch(v10, v9);
  qsrand(v11);
  set_PackContext_140206BC0(&PackContext_);
  v12 = DecodeLicenseData_140207160(&PackContext_, v24, licinfo);
  QString::QString(&dec_licinfo);
  QString::operator=(&dec_licinfo, v12);
  QString::~QString(v12);
  v25 = (7 - (3 + 3)) * dec_licinfo.d->size;
  if ( (1 * v25) )
  {
    v25 = (7 - (3 + 3)) * 1;
    if ( (1 * v25) > 0 )
    {
      v13 = ParseLicenseString_14027A1D0(1i64, &dec_licinfo, lic_type, startDate, endDate, isValid);

LABEL_19:
      v20 = QString::begin(&dec_licinfo);
      v21 = QString::end(&dec_licinfo);
      v22 = (v21 - v20 + 1) >> 1;
      if ( v20 > v21 )
        v22 = 0i64;

      if ( v22 )
      {
        while ( v22 )
        {
          *v20 = 0;
          v20 = (v20 + 2);
          --v22;
        }
      }

      QString::~QString(&dec_licinfo);
      if ( !PackContext_.QArrayData_8->ref
        || PackContext_.QArrayData_8->ref != 0xFFFFFFFF
        && _InterlockedExchangeAdd(&PackContext_.QArrayData_8->ref, 0xFFFFFFFF) == 1 )
      {
        QArrayData::deallocate(PackContext_.QArrayData_8, 1ui64, 8ui64);
      }

      return v13;
    }
  }
  else
  {
    v25 = (7 - (3 + 3)) * 0;
    if ( (1 * v25) )
    {
      v25 = (7 - (3 + 3)) * 1;
      if ( (1 * v25) )
        v25 = (7 - (3 + 3)) * 3.0;
    }
    else
    {
      v25 = (7 - (3 + 3)) * 1;
      if ( (1 * v25) > 0 )
      {
        LicenceCode_14026BC30 = GenerateLicenceKey_14026BC30(obj, a2);
        DecryptAndParseLicense_14027B750(endDate, v29, LicenceCode_14026BC30, v30, startDate, endDate, isValid);
        v13 = v19;
        QString::~QString(a2);
        goto LABEL_19;
      }
    }
  }

  v14 = QString::begin(&dec_licinfo);
  v15 = QString::end(&dec_licinfo);
  v16 = (v15 - v14 + 1) >> 1;
  if ( v14 > v15 )
    v16 = 0i64;

  if ( v16 )
  {
    while ( v16 )
    {
      *v14 = 0;
      v14 = (v14 + 2);
      --v16;
    }
  }

  QString::~QString(&dec_licinfo);
  result = PackContext_.QArrayData_8;
  if ( !PackContext_.QArrayData_8->ref
    || PackContext_.QArrayData_8->ref != 0xFFFFFFFF
    && (result = PackContext_.QArrayData_8, _InterlockedExchangeAdd(&PackContext_.QArrayData_8->ref, 0xFFFFFFFF) == 1) )
  {
    QArrayData::deallocate(PackContext_.QArrayData_8, 1ui64, 8ui64);
  }

  return result;
}

GenerateLicenceKey_14026BC30

__int64 __fastcall GenerateLicenceKey_14026BC30(CLicence *obj, __int64 a2)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v23 = a2;
  v21 = 0xFFFFFFFFFFFFFFFEui64;
  v2 = QString::number(
         v18,
         ((13 * obj->ComputeHardwareHash_8) >> 2) + (((13 * obj->ComputeHardwareHash_8) >> 0x20) >> 2),
         0x10i64);
  QString::toLower(v2, &v13);
  QString::~QString(v18);
  v3 = 0;
  v4 = 0;
  v14 = 0;
  v15 = 2;
  v16 = 0;
  LODWORD(v25) = 7;
  while ( 1 )
  {
    v17 = (7 - (3 + 3)) * 1;
    if ( v4 >= (1 * v17) )
      break;

    v5 = 0;
    if ( v13.d->size > 0 )
    {
      v6 = 7;
      LODWORD(v17) = 7;
      do
      {
        if ( (v6 + 9) / 8u != 1 )
        {
          if ( (1 * ((7 - (3 + 3)) * ((v5 & 1) == 0))) )
          {
            v3 += *QString::at(&v13, &v22, v5);
          }

          else if ( !(1 * ((7 - (3 + 3)) * 0)) )
          {
            v3 -= *QString::at(&v13, &v24, v5);
          }
        }

        ++v5;
        v6 = LODWORD(v17);
      }
      while ( v5 < v13.d->size );

      v4 = v14;
    }

    v14 = ++v4;
  }

  v7 = v3 % 0xFF;
  v8 = v16 * v15;
  v25 = (7 - (3 + 3)) * ((v8 + 7 + 8 * v8 + 9) / 8u - 1);
  if ( (8 * v16 * v15 + 0x10) / 8u == 1 || (((2 * v8 + 0x10) / 8u - 1) * v25) > 0 )
  {
    v10 = QString::number(v20, v7, 0x10i64);
    v11 = QString::rightJustified(v10, v19, 2i64);
    v12 = QString::append(&v13, v11);
    QString::toUpper(v12, v23);
    QString::~QString(v19);
    QString::~QString(v20);
    QString::~QString(&v13);
    return v23;
  }
  else
  {
    QString::~QString(&v13);
  }

  return result;
}

DecryptAndParseLicense_14027B750

// void DecryptAndParseLicense(const QString *encryptedHex, const QString *password, int *lictype, QDate *startDate, QDate *endDate, bool *isValid)
void __fastcall DecryptAndParseLicense_14027B750(
        __int64 a1,
        __int64 a2,
        QString *a3,
        _DWORD *a4,
        _QWORD *arg_20,
        _QWORD *a6,
        bool *isOffline)
{
  QString *v8; // rdi
  struct QChar *v9; // rdi
  struct QChar *v10; // rax
  unsigned __int64 v11; // rcx
  struct QChar *v12; // rdi
  struct QChar *v13; // rax
  unsigned __int64 v14; // rcx
  char v15[8]; // [rsp+30h] [rbp-28h] BYREF
  double v16; // [rsp+38h] [rbp-20h]
  __int64 v17; // [rsp+40h] [rbp-18h]
  __int64 dec_licinfo; // [rsp+60h] [rbp+8h] BYREF

  dec_licinfo = a1;
  v17 = 0xFFFFFFFFFFFFFFFEui64;
  v8 = DecryptChaCha20_1402656B0(v15, a2, a3);
  QString::QString(&dec_licinfo);
  QString::operator=(&dec_licinfo, v8);
  QString::~QString(v8);
  v16 = (7 - (3 + 3)) * (*(dec_licinfo + 4) == 0);
  if ( !(1 * v16) || (v16 = (7 - (3 + 3)) * 1, (1 * v16) <= 0) )
  {
    v16 = (7 - (3 + 3)) * 1;
    if ( (1 * v16) <= 0 )
    {
      v9 = QString::begin(&dec_licinfo);
      v10 = QString::end(&dec_licinfo);
      v11 = (v10 - v9 + 1) >> 1;
      if ( v9 > v10 )
        v11 = 0i64;

      if ( v11 )
      {
        while ( v11 )
        {
          *v9 = 0;
          v9 = (v9 + 2);
          --v11;
        }
      }

      goto LABEL_16;
    }

    ParseLicenseString_14027A1D0(1i64, &dec_licinfo, a4, arg_20, a6, isOffline);
  }

  v12 = QString::begin(&dec_licinfo);
  v13 = QString::end(&dec_licinfo);
  v14 = (v13 - v12 + 1) >> 1;
  if ( v12 > v13 )
    v14 = 0i64;

  if ( v14 )
  {
    while ( v14 )
    {
      *v12 = 0;
      v12 = (v12 + 2);
      --v14;
    }
  }

LABEL_16:
  QString::~QString(&dec_licinfo);
}

ParseLicenseString_14027A1D0

bool __fastcall ParseLicenseString_14027A1D0(
        __int64 a1,
        __int64 dec_licinfo,
        _DWORD *lic_type,
        _QWORD *startDate,
        _QWORD *endDate,
        bool *isOfflineMode)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v26 = 0xFFFFFFFFFFFFFFFEui64;
  v6 = 1;
  QStringList_1 = QString::split(dec_licinfo, &QStringList, '-', 1i64, 1);
  p = QStringList_1->p;
  QStringList_1->p = *&QListData::shared_null;
  if ( !QStringList.p->ref
    || QStringList.p->ref != 0xFFFFFFFF && _InterlockedExchangeAdd(&QStringList.p->ref, 0xFFFFFFFF) == 1 )
  {
    v8 = QStringList.p;
    v9 = &QStringList.p->array[QStringList.p->begin];
    for ( i = &QStringList.p->array[QStringList.p->end]; i != v9; QString::~QString(i) )
      i += 0xFFFFFFFF;

    QListData::dispose(v8);
  }

  v11 = 0;
  p_begin = &p->begin;
  v13 = p->end - p->begin;
  if ( v13 >= 4 && v13 <= 5 )
    v6 = 0;

  if ( (1 * ((7 - (3 + 3)) * v6)) && (1 * ((7 - (3 + 3)) * 1)) > 0 )
    goto LABEL_30;

  p_begin = &p->begin;
  *lic_type = QString::toShort(&p->array[p->begin], 0i64, 0xA);
  v14 = QString::toInt(&p[1] + p->begin, 0i64, 0xA);
  v15 = startDate;
  *startDate = *QDate::fromJulianDay(v27, v14);
  v16 = QString::toInt(&p[1].begin + p->begin, 0i64, 0xA);
  *endDate = *QDate::fromJulianDay(v28, v16);
  LOBYTE(v11) = p->end - p->begin > 4;
  if ( (1 * ((7 - (3 + 3)) * v11)) )
  {
    *isOfflineMode = QString::toInt(&p[2] + *p_begin, 0i64, 0xA) != 0;
    v17 = endDate;
    goto LABEL_19;
  }

  if ( (1 * ((7 - (3 + 3)) * 0)) )
  {
    if ( (1 * ((7 - (3 + 3)) * 1)) )
    {
      v17 = endDate;
      v15 = startDate;
      goto LABEL_19;
    }
  }
  else
  {
    *isOfflineMode = 1;
  }

  v17 = endDate;
  v15 = startDate;

LABEL_19:
  if ( (1 * ((7 - (3 + 3)) * 1)) <= 0 )
  {
    result = p;
    if ( p->ref )
    {
      if ( p->ref == 0xFFFFFFFF )
        return result;

      result = p;
      if ( _InterlockedExchangeAdd(&p->ref, 0xFFFFFFFF) != 1 )
        return result;
    }

    v19 = &p->array[*p_begin];
    for ( j = &p->array[p->end]; j != v19; QString::~QString(j) )
      j += 0xFFFFFFFF;

    QListData::dispose(p);
    return result;
  }

  if ( (*v15 + 0xB69EEFF91Fi64) <= 0x16D3E147973i64 && (*v17 + 0xB69EEFF91Fi64) <= 0x16D3E147973i64 )
  {
    v21 = 1;
    goto LABEL_31;
  }

LABEL_30:
  v21 = 0;

LABEL_31:
  if ( p->ref && (p->ref == 0xFFFFFFFF || _InterlockedExchangeAdd(&p->ref, 0xFFFFFFFF) != 1) )
    return v21;

  v22 = &p->array[*p_begin];
  for ( k = &p->array[p->end]; k != v22; QString::~QString(k) )
    k += 0xFFFFFFFF;

  QListData::dispose(p);
  return v21;
}

get_lic_type_1400722A0

__int64 __fastcall get_lic_type_1400722A0(__int64 a1, int a2)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v33[1] = 0xFFFFFFFFFFFFFFFEui64;
  v4 = 0i64;
  v5 = qword_140EC1A50;
  // 1117=免费版
  QString::QString(&v22, "1117");
  load_local_str_140136C90(v5, a1, &v22);
  QString::~QString(&v22);
  v28 = (7 - (3 + 3)) * a2;
  switch ( (1 * v28) )
  {
    case 1:
      v6 = qword_140EC1A50;
      // 1323=家庭版
      QString::QString(&v23, "1323");
      v7 = load_local_str_140136C90(v6, &v29, &v23);
      QString::operator=(a1, v7);
      QString::~QString(&v29);
      QString::~QString(&v23);
      break;

    case 2:
      v8 = qword_140EC1A50;
      // 1468=标准版
      QString::QString(&v24, "1468");
      v9 = load_local_str_140136C90(v8, &v30, &v24);
      QString::operator=(a1, v9);
      QString::~QString(&v30);
      QString::~QString(&v24);
      break;

    case 3:
      // 1324=专业版
      v10 = qword_140EC1A50;
      QString::QString(&v25, "1324");
      v11 = load_local_str_140136C90(v10, &v31, &v25);
      QString::operator=(a1, v11);
      QString::~QString(&v31);
      QString::~QString(&v25);
      break;

    case 4:
      v12 = qword_140EC1A50;
      // 1326=旗舰版
      QString::QString(&v26, "1326");
      v13 = load_local_str_140136C90(v12, &v32, &v26);
      QString::operator=(a1, v13);
      QString::~QString(&v32);
      QString::~QString(&v26);
      break;

    case 5:
    case 6:
      v14 = qword_140EC1A50;
      // 1325=服务器版
      QString::QString(&v27, "1325");
      v15 = load_local_str_140136C90(v14, v33, &v27);
      QString::operator=(a1, v15);
      QString::~QString(v33);
      QString::~QString(&v27);
      break;

    default:
      v16 = qword_140EC1A50;
      // 1117=免费版
      QString::QString(&v20, "1117");
      v34 = v16 + 0x10;
      if ( v16 != 0xFFFFFFFFFFFFFFF0ui64 )
      {
        QMutex::lock();
        v34 |= 1ui64;
      }

      sub_1401316F0(v16 + 0x38);
      d = *(*(v16 + 0x38) + 0x10i64);
      if ( !d )
        goto LABEL_16;

      do
      {
        if ( operator<(&d[3], &v20) )
        {
          d = d[2].d;
        }
        else
        {
          v4 = d;
          d = d[1].d;
        }
      }
      while ( d );

      if ( !v4 || operator<(&v20, &v4[3]) )
LABEL_16:
        v4 = (*(v16 + 0x38) + 8i64);

      sub_1401316F0(v16 + 0x38);
      if ( v4 == (*(v16 + 0x38) + 8i64) )
      {
        v18 = sub_140131C20(v16 + 0x40, &v20);
        QString::QString(v21, v18);
      }
      else
      {
        QString::QString(v21, v4 + 4);
      }

      QMutexLocker::~QMutexLocker(&v34);
      QString::operator=(a1, v21);
      QString::~QString(v21);
      QString::~QString(&v20);
      break;
  }

  result = (1 * ((7 - (3 + 3)) * 1));
  if ( result > 0 )
    return a1;

  return result;
}

py

import struct
import zlib
import hashlib
import random
from datetime import date
from typing import Tuple, Optional

# ---------- CRC-16/X.25 (Qt qChecksum) ----------
def crc16_x25(data: bytes) -> int:
    """CRC-16/X.25: poly=0x1021, init=0xFFFF, xorout=0xFFFF, refin=True, refout=True"""
    crc = 0xFFFF
    for b in data:
        crc ^= b & 0xFF
        for _ in range(8):
            if crc & 1:
                crc = (crc >> 1) ^ 0x8408  # 0x8408 是 0x1021 的逆序
            else:
                crc >>= 1
    return crc ^ 0xFFFF

def q_checksum(data: bytes) -> int:
    crc = 0xFFFF
    for b in data:
        crc ^= b
        for _ in range(8):
            if crc & 1:
                crc = (crc >> 1) ^ 0x8408
            else:
                crc >>= 1
    return crc ^ 0xFFFF

def q_compress(data: bytes, level: int = 9) -> bytes:
    compressed = zlib.compress(data, level)
    return struct.pack('>I', len(data)) + compressed

def q_uncompress(data: bytes) -> Optional[bytes]:
    if len(data) < 4:
        return None
    orig_len = struct.unpack('>I', data[:4])[0]
    try:
        decompressed = zlib.decompress(data[4:])
    except zlib.error:
        return None
    if len(decompressed) != orig_len:
        return None
    return decompressed

def feedback_encrypt(plain: bytes, key: bytes) -> bytes:
    if len(key) != 8:
        raise ValueError("Key must be 8 bytes")
    res = bytearray()
    prev = 0
    for i, b in enumerate(plain):
        k = key[i % 8]
        c = b ^ k ^ prev
        res.append(c)
        prev = c
    return bytes(res)

def feedback_decrypt(cipher: bytes, key: bytes) -> bytes:
    if len(key) != 8:
        raise ValueError("Key must be 8 bytes")
    res = bytearray()
    prev = 0
    for i, c in enumerate(cipher):
        k = key[i % 8]
        p = c ^ k ^ prev
        res.append(p)
        prev = c
    return bytes(res)

def encode_data_stream(plain: bytes, key: bytes,
                       compress: bool = True,
                       use_checksum: bool = True,
                       use_hash: bool = False,random_byte = random.randint(0, 255)) -> bytes:
    flags = 0
    payload = plain
    if compress:
        compressed = q_compress(payload)
        if compressed and len(compressed) < len(payload):
            payload = compressed
            flags |= 1
    if use_hash:
        h = hashlib.sha1(payload).digest()
        payload = h + payload
        flags |= 4
    elif use_checksum:
        crc = q_checksum(payload)
        payload = struct.pack('>H', crc) + payload  # 小端存储
        flags |= 2
    
    payload = bytes([random_byte]) + payload
    encrypted = feedback_encrypt(payload, key)
    return bytes([3, flags]) + encrypted

def decode_data_stream(packed: bytes, key: bytes) -> Tuple[Optional[bytes], int]:
    if len(packed) < 3:
        return (None, 1)
    version = packed[0]
    flags = packed[1]
    if version != 3:
        return (None, 2)
    encrypted = packed[2:]
    decrypted = feedback_decrypt(encrypted, key)
    if len(decrypted) < 1:
        return (None, 3)
    payload = decrypted[1:]
    if flags & 2:
        if len(payload) < 2:
            return (None, 3)
        stored_crc = struct.unpack('>H', payload[:2])[0]  # 小端读取
        # print('stored_crc:',hex(stored_crc))
        data = payload[2:]
        if q_checksum(data) != stored_crc:
            return (None, 3)
        payload = data
    elif flags & 4:
        if len(payload) < 20:
            return (None, 3)
        stored_hash = payload[:20]
        data = payload[20:]
        if hashlib.sha1(data).digest() != stored_hash:
            return (None, 3)
        payload = data
    if flags & 1:
        decompressed = q_uncompress(payload)
        if decompressed is None:
            return (None, 3)
        payload = decompressed
    return (payload, 0)

def encode_license_data(plain_text: str, key: bytes) -> str:
    utf8 = plain_text.encode('utf-8')
    packed = encode_data_stream(utf8, key, compress=True, use_checksum=True, use_hash=False,random_byte=0)
    return packed.hex().upper()

def decode_license_data(hex_str: str, key: bytes) -> Tuple[Optional[str], int]:
    try:
        packed = bytes.fromhex(hex_str)
    except ValueError:
        return (None, 1)
    data, err = decode_data_stream(packed, key)
    if err != 0:
        return (None, err)
    try:
        plain = data.decode('utf-8')
    except UnicodeDecodeError:
        return (None, 3)
    return (plain, 0)

def parse_license_string(lic_str: str):
    '''
    lic_type-start_jd-end_jd-{unknown}-{isOffline}
    4或5组数据,
    第4组数据未知
    第5组默认1==》offline,
    '''
    parts = lic_str.strip().split('-')
    if len(parts) not in (4, 5):
        print('[!]parse_license_string error!')
        return (None, None, None, None,False)
    try:
        lic_type = int(parts[0])
        start_jd = int(parts[1])
        end_jd = int(parts[2])
        start_date = qt_julian_to_python_date(start_jd)
        end_date = qt_julian_to_python_date(end_jd)
        unknown = int(parts[3])
        if len(parts)==5:
            isOffline = (int(parts[4]) != 0)
        else:
            # 4
            isOffline=True
        return (lic_type, start_date, end_date, unknown,isOffline)
    except:
        return (None, None, None,None, False)

def load_and_verify_license(encrypted_hex: str):
    mid = 0xCFDD4A4CCB0F024
    key = mid.to_bytes(8, 'little')
    plain, err = decode_license_data(encrypted_hex, key)
    if err != 0:
        return (False, None, None, None, None,False)
    lic_type, s, e, unknown,offline = parse_license_string(plain)
    if lic_type is None:
        return (False, None, None, None, None,False)
    # 简单日期有效性检查(可根据需要扩展)
    if s < e:
        return (True, lic_type, s, e, unknown,offline)
    else:
        return (False, lic_type, s, e, unknown,offline)

def python_date_to_qt_julian(d: date) -> int:
    """将 Python date 转换为 Qt QDate 的儒略日"""
    return d.toordinal() + 1721425

def qt_julian_to_python_date(jd: int) -> date:
    """将 Qt 儒略日转换为 Python date"""
    return date.fromordinal(jd - 1721425)

# offline==>Must be set to True
def generate_valid_license(lic_type: int, start_date: date, end_date: date, unknown:int,offline: bool = True) -> str:
    mid = 0xCFDD4A4CCB0F024
    key = mid.to_bytes(8, 'little')
    start_jd = python_date_to_qt_julian(start_date)
    end_jd = python_date_to_qt_julian(end_date)
    # 必须生成4个字段,标志位为 1 或 0
    flag = '1' if offline else '0'
    # plain = f"{lic_type}-{start_jd}-{end_jd}-{flag}"  #-{unknown}
    plain = f"{lic_type}-{start_jd}-{end_jd}-{unknown}-{flag}"  
    print(f'[-]generate_valid_license plain:{plain},key:{key.hex()}')
    return encode_license_data(plain, key)

# pip install cpuid
import cpuid

def get_cpuid_string() -> str:
    """
    模拟 get_cpuid_1401E5910 函数,返回 CPUID 信息字符串。
    执行 CPUID 指令 (EAX=1),拼接为十六进制字符串。
    """
    # 执行 CPUID 功能 1
    eax,ebx,ecx,edx = cpuid.cpuid(1)


    # 格式化为 8 位十六进制大写字符串,按 EDX EAX 顺序拼接
    result = f"{edx:X}{eax:X}"
    return result


    


def test():
    '''
    这里采用cpuid作为第一层key
    数据 压缩+crc16 
    第二次仍采用第一层的加密方式(xor;没有采用mid生成chacha20 key的方式)
    '''
    id=get_cpuid_string()
    key=int(id,16).to_bytes(8,'little')
    print('[+]cpuid_key:',key.hex())

    
    start = date(2026, 1, 1)
    end = date(2066, 6, 6)
    #4==>旗舰版
    lic_hex = generate_valid_license(4, start, end,666,True)
    print(f"[-]Generated: {lic_hex}")


    ok, ver, s, e, v,o = load_and_verify_license(lic_hex)
    print(f"[-]Result: {ok}, ver={ver}, start={s}, end={e}, unknown={v},offline:{o}")

    # 加密打包
    hex_str = encode_license_data(lic_hex, key)
    print("[=]reg  Anytxt/License value:\n", hex_str,sep='')
    pass

if __name__=='__main__':
    test()
    pass


ps

image-20260413232340431

posted @ 2026-04-13 23:34  DirWangK  阅读(68)  评论(0)    收藏  举报