Snipaste-2.10.8-x64 離線激活記錄

目錄

  • Snipaste-2.10.8-x64 離線激活記錄
  • 離線激活流程
  • UnlockProDialog
  • requestOfflineActivation_1401B22E0
  • xx_Licensing_desktop_OfflineActivation_140224BA0
  • xx_OfflineActivation_check_140225D70
  • 1、x_xor_decompress_140224460
  • 2、ed25519簽名驗證 xx_verifier_1402247F0
  • 3、xx_parse_license_json_14021BA10
  • 4、LicensingDesktop_set_info_140228AA0
  • 5、refresh_time_140225EA0
  • refreshActivation定時器
  • refreshActivation_140224E90
  • check_ref_time_14021D310
  • 字段計算/驗證相關
  • dom 值==》x_Blake2s_128_140277030
  • machineid
  • x_MachineId_140260310
  • calculateCharTransitionSum_140276DA0
  • 許可激活狀態
  • license_info
  • 顯示激活信息
  • 網絡校驗
  • x_net_activation_140228A40
  • handleActivationReply_14021A9C0
  • gotActivationResult信號
  • 以及QNetworkAccessManager的 finished信號
  • 公鑰加載x_pubkey_140224270
  • 公鑰校驗點
  • x_check_pubkey_140234500
  • x_check_pubkey1_140234600
  • x_check_pubkey2_1402347C0
  • py
  • device_id.py
  • offlinekg.py
  • ps

qt6 程序,分析信號槽,確定按鈕事件

使用ADVobfuscator,(不是最新版本,狀態機使用boost );字符串編譯時混淆,激活相關函數使用狀態機混淆

激活方案為:ed25519 簽名驗證

離線激活流程

UnlockProDialog

qmetaobject

.rdata:00000001404C52D0 UnlockProDialog_1404C52D0 dq 0          ; DATA XREF: sub_1401AB800+572↑o
.rdata:00000001404C52D0                                         ; sub_1401AB800+82C↑o ...
.rdata:00000001404C52D8 UnlockProDialog QMetaObject__d <offset sub_140321470, \
.rdata:00000001404C52D8                                 offset qt_meta_stringdata_UnlockProDialog, \
.rdata:00000001404C52D8                                 offset qt_meta_dataUnlockProDialog, \
.rdata:00000001404C52D8                                 offset UnlockProDialog__qt_static_metacall, 0, \
.rdata:00000001404C52D8                                 offset off_1404C50A0>

UnlockProDialog 構造函數

UnlockProDialog *__fastcall UnlockProDialog_1401AA650(UnlockProDialog *a1)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v109 = a1;
  QDialog::QDialog(a1, 0i64, 0xA041003i64);
  *(_QWORD *)&a1->qobject0 = &UnlockProDialog::`vftable';
  a1->qword10 = &UnlockProDialog::`vftable';
  a1->ui_28 = (UnlockProDialogUi *)operator new(0x350ui64);
  a1->qword30 = 0i64;
  sub_140298C20(&a1->qvalidator38, a1);
  SerialValidator_140298EA0((QValidator *)&a1->qvalidator50, (struct QObject *)a1);
  a1->dword70 = 0;
  QTimer::QTimer((QTimer *)&a1->qtimer78, (struct QObject *)a1);
  a1->qword88 = 0i64;
  a1->qword90 = 0i64;
  x_UnlockProDialogUi_1401A5C50(a1->ui_28, (QObject *)a1);
  LOBYTE(v2) = 1;
  QWidget::setAttribute(a1, 0x37i64, v2);
  QLineEdit::setValidator((QLineEdit *)a1->ui_28->le_email_F8, (const struct QValidator *)&a1->qvalidator38);
  QLineEdit::setValidator((QLineEdit *)a1->ui_28->le_licenseKey_108, (const struct QValidator *)&a1->qvalidator50);
  v3 = sub_140096230(4);
  QLineEdit::setTextMargins((QLineEdit *)a1->ui_28->le_email_F8, v3, v3, v3, v3);
  QLineEdit::setTextMargins((QLineEdit *)a1->ui_28->le_licenseKey_108, v3, v3, v3, v3);
  sub_1401AA5D0(a1->ui_28->activationSpinner_120);
  sub_1401AA5D0(a1->ui_28->deactivationSpinner_1E8);
  sub_1401AA5D0(a1->ui_28->offlineActivationSpinner_318);
  v71 = (QProxyStyle *)operator new(0x10ui64);
  *(_OWORD *)v71 = 0i64;
  QProxyStyle::QProxyStyle(v71, 0i64);
  *(_QWORD *)v71 = &StayColorfulPixmapStyle::`vftable';
  QWidget::setStyle(a1->ui_28->lb_heart_1B8, v71);
  lb_heart_1B8 = a1->ui_28->lb_heart_1B8;
  v5 = sub_140096230(0x1C);
  v133 = 0x5B;
  // /Snipaste/icons/red_heart.svg
  qmemcpy(v134, "at\b52+:(/>t2845(t)>?", 0x14);
  v134[0x14] = 4;
  strcpy(v135, "3>:)/u(-<");
  for ( i = 0i64; i < 0x1E; ++i )
    v134[i] ^= v133;

  v135[9] = 0;
  QString::QString(&v130, v134);
  v8 = (const struct QPixmap *)LOADSVG_14026A960((unsigned __int64)v131, &v130, v7, v5);
  QLabel::setPixmap(lb_heart_1B8, v8);
  QPixmap::~QPixmap((QPixmap *)v131);
  QString::~QString(&v130);
  QObject::connect(v103, &a1->qtimer78, "2timeout()", a1, "1clearActivationButtonStatus()", 0);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v103);
  v9 = x_Licensing_desktop_14023B4F0();
  QObject::connect(v104, v9, "2validated(bool)", a1, "1onValidated(bool)", 0);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v104);
  v10 = x_Licensing_desktop_14023B4F0();
  QObject::connect(v105, v10, "2deactivated(bool)", a1, "1onDeactivated(bool)", 0);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v105);
  v11 = Themer_1400CAC70();
  QObject::connect(v106, v11, "2updateLanguage()", a1, "1retranslateUi()", 0);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v106);
  v12 = Themer_1400CAC70();
  QObject::connect(v107, v12, "2appDarkModeChanged(bool)", a1, "1updateHtmlStyle()", 0);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v107);
  updateHtmlStyle_1401B1340(a1);
  QTextEdit::document(a1->ui_28->tb_details_60);
  v13 = sub_140096230(5);
  QTextDocument::setDocumentMargin(v14, (double)v13);
  QPlainTextEdit::setWordWrapMode(a1->ui_28->pte_offlineLicenseCode_2D8, 3i64);
  *(_QWORD *)&v70 = QAbstractButton::clicked;
  DWORD2(v70) = 0;
  pb_purchase_B8 = a1->ui_28->pb_purchase_B8;
  v110 = v70;
  v16 = operator new(0x18ui64);
  *(_DWORD *)v16 = 1;
  v16[1] = purchase_click_1401B42F0;
  v16[2] = a1;
  QObject::connectImpl(v84, pb_purchase_B8, &v110, a1, 0i64, v16, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v84);
  *(_QWORD *)&v70 = QAbstractButton::clicked;
  DWORD2(v70) = 0;
  pb_enterOfflineToken = a1->ui_28->pb_enterOfflineToken_158;
  v111 = v70;
  v18 = operator new(0x18ui64);
  *(_DWORD *)v18 = 1;
  v18[1] = enterOfflineToken_1401B42B0;
  v18[2] = a1;
  QObject::connectImpl(&v83, pb_enterOfflineToken, &v111, a1, 0i64, v18, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)&v83);
  *(_QWORD *)&v70 = QWidget::close;
  DWORD2(v70) = 0;
  *(_QWORD *)&v83 = QAbstractButton::clicked;
  DWORD2(v83) = 0;
  pb_cancel_1_C8 = a1->ui_28->pb_cancel_1_C8;
  v77 = v70;
  v112 = v83;
  v20 = operator new(0x20ui64);
  *(_DWORD *)v20 = 1;
  v20[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v20 + 1) = v70;
  QObject::connectImpl(v85, pb_cancel_1_C8, &v112, a1, &v77, v20, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v85);
  *(_QWORD *)&v77 = QWidget::close;
  DWORD2(v77) = 0;
  *(_QWORD *)&v70 = QAbstractButton::clicked;
  DWORD2(v70) = 0;
  pb_cancel_2_188 = a1->ui_28->pb_cancel_2_188;
  v78 = v77;
  v113 = v70;
  v22 = operator new(0x20ui64);
  v23 = v78;
  *(_DWORD *)v22 = 1;
  v22[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v22 + 1) = v23;
  QObject::connectImpl(v86, pb_cancel_2_188, &v113, a1, &v78, v22, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v86);
  *(_QWORD *)&v78 = QWidget::close;
  DWORD2(v78) = 0;
  *(_QWORD *)&v77 = QAbstractButton::clicked;
  DWORD2(v77) = 0;
  pb_cancel_3_348 = a1->ui_28->pb_cancel_3_348;
  v75 = v78;
  v114 = v77;
  v25 = operator new(0x20ui64);
  v26 = v75;
  *(_DWORD *)v25 = 1;
  v25[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v25 + 1) = v26;
  QObject::connectImpl(v87, pb_cancel_3_348, &v114, a1, &v75, v25, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v87);
  *(_QWORD *)&v75 = QWidget::close;
  DWORD2(v75) = 0;
  *(_QWORD *)&v78 = QAbstractButton::clicked;
  DWORD2(v78) = 0;
  pb_later_250 = a1->ui_28->pb_later_250;
  v73 = v75;
  v115 = v78;
  v28 = operator new(0x20ui64);
  v29 = v73;
  *(_DWORD *)v28 = 1;
  v28[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v28 + 1) = v29;
  QObject::connectImpl(v88, pb_later_250, &v115, a1, &v73, v28, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v88);
  *(_QWORD *)&v73 = QAbstractButton::clicked;
  DWORD2(v73) = 0;
  pb_ok_248 = a1->ui_28->pb_ok_248;
  v116 = v73;
  v31 = operator new(0x18ui64);
  *(_DWORD *)v31 = 1;
  v31[1] = ok_clicked_1401B4140;
  v31[2] = a1;
  QObject::connectImpl(v89, pb_ok_248, &v116, a1, 0i64, v31, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v89);
  *(_QWORD *)&v73 = QLabel::linkActivated;
  DWORD2(v73) = 0;
  lb_refreshPrompt_1D0 = a1->ui_28->lb_refreshPrompt_1D0;
  v117 = v73;
  v33 = operator new(0x18ui64);
  *(_DWORD *)v33 = 1;
  v33[1] = &refreshPrompt_linkactivated_1401B4050;
  v33[2] = a1;
  QObject::connectImpl(v90, lb_refreshPrompt_1D0, &v117, a1, 0i64, v33, 0, 0i64, QLabel::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v90);
  *(_QWORD *)&v73 = QAbstractButton::clicked;
  DWORD2(v73) = 0;
  pb_back_178 = a1->ui_28->pb_back_178;
  v118 = v73;
  v35 = operator new(0x18ui64);
  *(_DWORD *)v35 = 1;
  v35[1] = sub_1401B4010;
  v35[2] = a1;
  QObject::connectImpl(v91, pb_back_178, &v118, a1, 0i64, v35, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v91);
  *(_QWORD *)&v73 = QAbstractButton::clicked;
  DWORD2(v73) = 0;
  pb_back_3_328 = a1->ui_28->pb_back_3_328;
  v119 = v73;
  v37 = operator new(0x18ui64);
  *(_DWORD *)v37 = 1;
  v37[1] = back_clicked_1401B3F30;
  v37[2] = a1;
  QObject::connectImpl(v92, pb_back_3_328, &v119, a1, 0i64, v37, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v92);
  *(_QWORD *)&v73 = QAbstractButton::clicked;
  DWORD2(v73) = 0;
  pb_copyDeviceCode_2B8 = a1->ui_28->pb_copyDeviceCode_2B8;
  v120 = v73;
  v39 = (CopyArgs *)operator new(0x18ui64);
  *(_DWORD *)v39->n_0 = 1;
  v39->cb_8 = copyDeviceCode_clicked_1401B3F70;
  v39->obj_10 = a1;
  QObject::connectImpl(v93, pb_copyDeviceCode_2B8, &v120, a1, 0i64, v39, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v93);
  *(_QWORD *)&v73 = updateOnlineActivationButtonStatus_1401B1F50;
  DWORD2(v73) = 0;
  *(_QWORD *)&v75 = QLineEdit::textChanged;
  DWORD2(v75) = 0;
  le_email_F8 = a1->ui_28->le_email_F8;
  v76 = v73;
  v121 = v75;
  v41 = operator new(0x20ui64);
  v42 = v76;
  *(_DWORD *)v41 = 1;
  v41[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v41 + 1) = v42;
  QObject::connectImpl(v94, le_email_F8, &v121, a1, &v76, v41, 0, 0i64, QLineEdit::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v94);
  *(_QWORD *)&v76 = updateOnlineActivationButtonStatus_1401B1F50;
  DWORD2(v76) = 0;
  *(_QWORD *)&v73 = QLineEdit::textChanged;
  DWORD2(v73) = 0;
  le_licenseKey_108 = a1->ui_28->le_licenseKey_108;
  v79 = v76;
  v122 = v73;
  v44 = operator new(0x20ui64);
  v45 = v79;
  *(_DWORD *)v44 = 1;
  v44[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v44 + 1) = v45;
  QObject::connectImpl(v95, le_licenseKey_108, &v122, a1, &v79, v44, 0, 0i64, QLineEdit::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v95);
  *(_QWORD *)&v79 = offlineLicenseCode_textchanged_1401B20B0;
  DWORD2(v79) = 0;
  *(_QWORD *)&v76 = QPlainTextEdit::textChanged;
  DWORD2(v76) = 0;
  pte_offlineLicenseCode_2D8 = a1->ui_28->pte_offlineLicenseCode_2D8;
  v80 = v79;
  v123 = v76;
  v47 = operator new(0x20ui64);
  v48 = v80;
  *(_DWORD *)v47 = 1;
  v47[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v47 + 1) = v48;
  QObject::connectImpl(v96, pte_offlineLicenseCode_2D8, &v123, a1, &v80, v47, 0, 0i64, QPlainTextEdit::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v96);
  *(_QWORD *)&v80 = requestOnlineActivation_1401B2160;
  DWORD2(v80) = 0;
  *(_QWORD *)&v79 = QAbstractButton::clicked;
  DWORD2(v79) = 0;
  pb_activate_180 = a1->ui_28->pb_activate_180;
  v81 = v80;
  v124 = v79;
  v50 = operator new(0x20ui64);
  v51 = v81;
  *(_DWORD *)v50 = 1;
  v50[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v50 + 1) = v51;
  QObject::connectImpl(v97, pb_activate_180, &v124, a1, &v81, v50, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v97);
  *(_QWORD *)&v81 = requestOfflineActivation_1401B22E0;
  DWORD2(v81) = 0;
  *(_QWORD *)&v80 = QAbstractButton::clicked;
  DWORD2(v80) = 0;
  pb_offlineActivate_340 = a1->ui_28->pb_offlineActivate_340;
  v82 = v81;
  v125 = v80;
  v53 = operator new(0x20ui64);
  v54 = v82;
  *(_DWORD *)v53 = 1;
  v53[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v53 + 1) = v54;
  QObject::connectImpl(v98, pb_offlineActivate_340, &v125, a1, &v82, v53, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v98);
  *(_QWORD *)&v82 = deactivate_clicked_1401B2370;
  DWORD2(v82) = 0;
  *(_QWORD *)&v81 = QAbstractButton::clicked;
  DWORD2(v81) = 0;
  pb_deactivate_228 = a1->ui_28->pb_deactivate_228;
  v74 = v82;
  v126 = v81;
  v56 = operator new(0x20ui64);
  v57 = v74;
  *(_DWORD *)v56 = 1;
  v56[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v56 + 1) = v57;
  QObject::connectImpl(v99, pb_deactivate_228, &v126, a1, &v74, v56, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v99);
  *(_QWORD *)&v74 = QAbstractButton::clicked;
  DWORD2(v74) = 0;
  pb_enterLicense_C0 = a1->ui_28->pb_enterLicense_C0;
  v127 = v74;
  v59 = operator new(0x18ui64);
  *(_DWORD *)v59 = 1;
  v59[1] = back_clicked_1401B3F30;
  v59[2] = a1;
  QObject::connectImpl(v100, pb_enterLicense_C0, &v127, a1, 0i64, v59, 0, 0i64, QAbstractButton::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v100);
  *(_QWORD *)&v74 = QLabel::linkActivated;
  DWORD2(v74) = 0;
  lb_getOfflineLicenseCode_2F0 = a1->ui_28->lb_getOfflineLicenseCode_2F0;
  v128 = v74;
  v61 = operator new(0x18ui64);
  *(_DWORD *)v61 = 1;
  v61[1] = getOfflineLicenseCode_linkactivated_1401B3F00;
  v61[2] = a1;
  QObject::connectImpl(v102, lb_getOfflineLicenseCode_2F0, &v128, a1, 0i64, v61, 0, 0i64, QLabel::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v102);
  *(_QWORD *)&v74 = onPageChanged_1401B16C0;
  DWORD2(v74) = 0;
  *(_QWORD *)&v82 = QStackedWidget::currentChanged;
  DWORD2(v82) = 0;
  sw_pages_28 = a1->ui_28->sw_pages_28;
  v108 = v74;
  v129 = v82;
  v72 = operator new(0x20ui64);
  v63 = v108;
  *(_DWORD *)v72 = 1;
  v72[1] = cancel_clicked__or_email_textchanged_1400D6E30;
  *((_OWORD *)v72 + 1) = v63;
  QObject::connectImpl(v101, sw_pages_28, &v129, a1, &v108, v72, 0, 0i64, QStackedWidget::staticMetaObject);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v101);
  lb_logo_18 = a1->ui_28->lb_logo_18;
  v65 = sub_140096230(0x60);
  v66 = (const struct QPixmap *)sub_1402619A0((__int64)v132, v65);
  QLabel::setPixmap(lb_logo_18, v66);
  QPixmap::~QPixmap((QPixmap *)v132);
  v67 = sub_140096230(0x60);
  QWidget::setFixedHeight(v68, v67);
  QStackedWidget::setCurrentIndex(a1->ui_28->sw_pages_28, 0);
  retranslateUi_1401AE2B0((QWidget *)a1);
  return a1;
}

pb_offlineActivate_340 點擊事件requestOfflineActivation_1401B22E0

*(_QWORD *)&v81 = requestOfflineActivation_1401B22E0;
  DWORD2(v81) = 0;
  *(_QWORD *)&v80 = QAbstractButton::clicked;
  DWORD2(v80) = 0;
  pb_offlineActivate_340 = a1->ui_28->pb_offlineActivate_340;
void __fastcall UnlockProDialog::qt_static_metacall(QWidget *a1, int id, __int64 a3, __int64 a4)
{
  if ( !id )
  {
    // [case 0],SLOT Public Void retranslateUi()
    // [case 1],SLOT Private Void updateHtmlStyle()
    // [case 2],SLOT Private Void onPageChanged()
    // [case 3],SLOT Private Void updateAccountStatus()
    // [case 4],SLOT Private Void updateOnlineActivationButtonStatus()
    // [case 5],SLOT Private Void updateOfflineActivationButtonStatus()
    // [case 6],SLOT Private Void clearActivationButtonStatus()
    // [case 7],SLOT Private Void requestOnlineActivation()
    // [case 8],SLOT Private Void requestOfflineActivation()
    // [case 9],SLOT Private Void requestOnlineDeactivation()
    // [case 10],SLOT Private Void onValidated(Bool success)
    // [case 11],SLOT Private Void onDeactivated(Bool success)
    switch ( 0x40000000u )
    {
      case 0u:
        retranslateUi_1401AE2B0(a1);
        break;

      case 1u:
        updateHtmlStyle_1401B1340(a1);
        break;

      case 2u:
        onPageChanged_1401B16C0(a1);
        break;

      case 3u:
        updateAccountStatus_1401B1810(a1);
        break;

      case 4u:
        updateOnlineActivationButtonStatus_1401B1F50(a1);
        break;

      case 5u:
        offlineLicenseCode_textchanged_1401B20B0((UnlockProDialog *)a1);
        break;

      case 6u:
        clearActivationButtonStatus_onDeactivated_1401B3360((UnlockProDialog *)a1, 0);
        break;

      case 7u:
        requestOnlineActivation_1401B2160((UnlockProDialog *)a1);
        break;

      case 8u:
        requestOfflineActivation_1401B22E0((UnlockProDialog *)a1);
        break;

      case 9u:
        deactivate_clicked_1401B2370((UnlockProDialog *)a1);
        break;

      case 10u:
        onValidated_1401B23A0((UnlockProDialog *)a1);
        break;

      case 11u:
        clearActivationButtonStatus_onDeactivated_1401B3360(
          (UnlockProDialog *)a1,
          2 * (**(unsigned __int8 **)(a4 + 8) ^ 1) + 6);
        break;

      default:
        return;
    }
  }
}

requestOfflineActivation_1401B22E0

void __fastcall requestOfflineActivation_1401B22E0(UnlockProDialog *a1)
{
  __int64 v2; // rax
  LicensingDesktop *v3; // rax
  char v4[16]; // [rsp+20h] [rbp-38h] BYREF
  __int64 v5; // [rsp+30h] [rbp-28h]
  char v6[32]; // [rsp+38h] [rbp-20h] BYREF

  v2 = QPlainTextEdit::toPlainText(a1->ui_28->pte_offlineLicenseCode_2D8, v6);
  QString::trimmed(v2, v4);
  QString::~QString(v6);
  if ( v5 )
  {
    clearActivationButtonStatus_onDeactivated_1401B3360(a1, 2);
    // Licensing_desktop
    v3 = get_Licensing_desktop_14023B4F0();
    // 224BA0
    // xx_Licensing_desktop_OfflineActivation_140224BA0
    (*(void (__fastcall **)(LicensingDesktop *, char *))(*(_QWORD *)&v3->Licensing_0 + 0x98i64))(v3, v4);
  }

  QString::~QString(v4);
}

xx_Licensing_desktop_OfflineActivation_140224BA0

void __fastcall xx_Licensing_desktop_OfflineActivation_140224BA0(__int64 Licensing_desktop_obj, QString *code)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v14 = 0;
  if ( *(__int64 *)&code->size > 3 && *(_WORD *)QString::operator[](code, &part1, 2i64) == '-' )
  {
    v4 = 1;
    QString::operator[](code, &part1, 1i64);
    QString::mid(code, &part2, 3i64, 0xFFFFFFFFFFFFFFFFui64);
    v5 = calculateCharTransitionSum_140276DA0(&v13, &part2);
    if ( (_WORD)part1 == *v5 )
    {
      v6 = (QByteArray *)base64dec_1402774A0((__int64)v10, (__int64)&part2);
    }
    else
    {
      v6 = QByteArray::QByteArray(&v9);
      v4 = 2;
    }

    v14 = v4;
    xx_OfflineActivation_check_140225D70((LicensingDesktop *)Licensing_desktop_obj, (__int64)v6);
    if ( (v4 & 2) != 0 )
    {
      LOBYTE(v4) = v4 & 0xFD;
      QByteArray::~QByteArray(&v9);
    }

    if ( (v4 & 1) != 0 )
      QByteArray::~QByteArray((QByteArray *)v10);

    QString::~QString(&part2);
  }

  part1 = Licensing_desktop_obj;
  // 14022473C
  part2.ref = (__int64)xx_ck_machineid_time_dom_1402243A0 + 0x240;
  part2.size_8 = 0x240;
  v7 = (LicensingResult *)sub_140226EB0(v10, (__int128 *)&part2.ref, (__int64)&part1);
  activate_SIGNAL_validated_14023B900((LicensingDesktop *)Licensing_desktop_obj, v7);
  QByteArray::~QByteArray((QByteArray *)v11);
}

xx_OfflineActivation_check_140225D70

void __fastcall xx_OfflineActivation_check_140225D70(LicensingDesktop *a1, __int64 activationcode)
{
  QByteArray *v3; // rax
  QByteArray *v4; // rax
  XLicenseInfo *v5; // rax
  FuncData v6; // [rsp+20h] [rbp-128h] BYREF
  QByteArray v7; // [rsp+30h] [rbp-118h] BYREF
  XLicenseInfo v8; // [rsp+48h] [rbp-100h] BYREF
  LicensingDesktop *v9; // [rsp+150h] [rbp+8h] BYREF

  // 前0x40為sig,後面作為msg(license info)
  v6.ptr = (char *)x_xor_decompress_140224460 + 0x20E;
  v6.offset = 0x20E;
  v3 = sub_140228150(&v7, (__int128 *)&v6, activationcode);
  QByteArray::operator=(&a1->xorsig_msg_bs198, v3);
  QByteArray::~QByteArray(&v7);
  // ed25519_
  v6.ptr = (char *)xx_verifier_1402247F0 + 0x12E;
  v6.offset = 0x12E;
  v4 = sub_140227DA0(&v7, (__int128 *)&v6, (__int64)&a1->xorsig_msg_bs198);
  v5 = xx_parse_license_json_14021BA10(&v8, v4);
  v9 = a1;
  v6.ptr = (char *)LicensingDesktop_set_info_140228AA0 + 0x16C;
  v6.offset = 0x16C;
  sub_1402283E0((__int128 *)&v6, (__int64)&v9, (__int64)v5);
  dst_XLicenseInfo_14021CD50(&v8);
  QByteArray::~QByteArray(&v7);
  QTimer::stop(a1->refreshActivation_timer1B8);
  refresh_time_140225EA0(a1);
}

1、x_xor_decompress_140224460

QByteArray *__fastcall x_xor_decompress_140224460(QByteArray *a1, const struct QByteArray *a2)
{
  __int128 v5; // [rsp+20h] [rbp-60h] BYREF
  _QWORD msg_[3]; // [rsp+30h] [rbp-50h] BYREF
  QByteArray sig; // [rsp+48h] [rbp-38h] BYREF
  QByteArray msg; // [rsp+60h] [rbp-20h] BYREF
  _QWORD *msg1; // [rsp+A0h] [rbp+20h] BYREF

  if ( QByteArray::size((QByteArray *)a2) >= 0x41 )
  {
    QByteArray::left(a2, &sig, 0x40i64);
    QByteArray::mid(a2, msg_, 0x40i64, 0xFFFFFFFFFFFFFFFFui64);
    msg1 = msg_;
    *(_QWORD *)&v5 = (char *)x_qbytearray_xor_1402243C0 + 0x243;
    DWORD2(v5) = 0x243;
    sub_140226540(&v5, (__int64)&sig, (__int64)&msg1);// msg 進行xor sig
    x_decompressGzipData_140277310(&msg, (QByteArray *)msg_);// 解壓
    if ( QByteArray::isNull(&msg) )
    {
      // 如果[0x40:]與前面[:0x40] sig進行xor後能被解壓時
      QByteArray::QByteArray(a1, a2);
    }
    else
    {
      // 未壓縮的情況
      QByteArray::operator=(msg_, &msg);
      msg1 = msg_;
      *(_QWORD *)&v5 = (char *)x_qbytearray_xor_1402243C0 + 0x239;
      DWORD2(v5) = 0x239;
      sub_140226540(&v5, (__int64)&sig, (__int64)&msg1);// msg再進行xor,即恢復原始數據
      QByteArray::append(&sig, (const struct QByteArray *)msg_);
      QByteArray::QByteArray(a1, &sig);
    }

    QByteArray::~QByteArray(&msg);
    QByteArray::~QByteArray((QByteArray *)msg_);
    QByteArray::~QByteArray(&sig);
  }
  else
  {
    QByteArray::QByteArray(a1, a2);
  }

  return a1;
}

2、ed25519簽名驗證 xx_verifier_1402247F0

QByteArray *__fastcall xx_verifier_1402247F0(QByteArray *a1, QByteArray *xorsig_msg)
{
  QByteArray *v4; // rax
  QByteArray v6; // [rsp+20h] [rbp-28h] BYREF

  v4 = x_pubkey_140224270(&v6);
  x_ed25519_Verifier_1402245D0(a1, v4, xorsig_msg);
  QByteArray::~QByteArray(&v6);
  return a1;
}

QByteArray *__fastcall x_pubkey_140224270(QByteArray *a1)
{
  unsigned __int64 v2; // rdx
  char v4[32]; // [rsp+28h] [rbp-38h] BYREF

  v4[0] = 0x90;
  v4[1] = 0xB0;
  v2 = 0i64;
  v4[2] = 0x3B;
  v4[3] = 0x42;
  v4[4] = 0x5F;
  v4[5] = 0x5B;
  v4[6] = 0x36;
  v4[7] = 0x73;
  v4[8] = 0x35;
  v4[9] = 0x89;
  v4[0xA] = 0x4E;
  v4[0xB] = 0xB1;
  v4[0xC] = 0xE;
  v4[0xD] = 0x24;
  v4[0xE] = 0x90;
  v4[0xF] = 0xDA;
  v4[0x10] = 0x32;
  v4[0x11] = 0x9A;
  v4[0x12] = 0x5E;
  v4[0x13] = 0x53;
  v4[0x14] = 0x2D;
  v4[0x15] = 0x7B;
  v4[0x16] = 0x54;
  v4[0x17] = 0xD4;
  v4[0x18] = 0xF8;
  v4[0x19] = 0xBC;
  v4[0x1A] = 0xA8;
  v4[0x1B] = 0x5C;
  v4[0x1C] = 0x92;
  v4[0x1D] = 0x46;
  v4[0x1E] = 0x9A;
  strcpy(&v4[0x1F], "j");
  do
    v4[v2++] -= 0xA;
  while ( v2 < 0x20 );

  // 86a6313855512c692b7f44a7041a86d02890544923714acaeeb29e52883c9060
  QByteArray::QByteArray(a1, v4, 0xFFFFFFFFFFFFFFFFui64);
  return a1;
}

QByteArray *__fastcall x_ed25519_Verifier_1402245D0(QByteArray *a1, QByteArray *ed25519_key, QByteArray *xorsig_msg)
{
  const char *v6; // rax
  __int64 signature_len; // rdi
  const char *signature; // rsi
  __int64 message_len; // r14
  char *message; // rax
  FuncData v12; // [rsp+30h] [rbp-138h] BYREF
  QByteArray partB_message; // [rsp+40h] [rbp-128h] BYREF
  __int64 v14[2]; // [rsp+58h] [rbp-110h] BYREF
  QByteArray pratA_signature; // [rsp+68h] [rbp-100h] BYREF
  void **verifier; // [rsp+80h] [rbp-E8h] BYREF
  void **v17; // [rsp+88h] [rbp-E0h]
  char v18[176]; // [rsp+90h] [rbp-D8h] BYREF

  v14[1] = (__int64)a1;
  if ( QByteArray::size(ed25519_key) == 0x20 && QByteArray::size(xorsig_msg) >= 0x41 )
  {
    QByteArray::left(xorsig_msg, &pratA_signature, 0x40i64);
    QByteArray::mid(xorsig_msg, &partB_message, 0x40i64, 0xFFFFFFFFFFFFFFFFui64);
    v14[0] = (__int64)&partB_message;
    // 0x140224596
    v12.ptr = (char *)x_qbytearray_xor_1402243C0 + 0x1D6;
    v12.offset = 0x1D6;
    wrap_func_1402267A0(&v12, &pratA_signature, v14);
    v6 = QByteArray::data(ed25519_key);
    ed25519_140337408(&verifier, (__int64)v6);
    signature_len = QByteArray::size(&pratA_signature);
    signature = QByteArray::data(&pratA_signature);
    message_len = QByteArray::size(&partB_message);
    message = QByteArray::data(&partB_message);
    //    ed25519::Verifier verifier(public_key);
    //         return verifier.VerifyMessage(message, message_len, signature, signature_len);
    if ( VerifyMessage_1403372C0((__int64)&verifier, (__int64)message, message_len, (__int64)signature, signature_len) )
    {
      QByteArray::QByteArray(a1, &partB_message);
      verifier = &CryptoPP::ed25519Verifier::`vftable';
      v17 = &CryptoPP::ed25519Verifier::`vftable';
      ed25519PublicKey_140223BE0((__int64)v18);
      QByteArray::~QByteArray(&partB_message);
      QByteArray::~QByteArray(&pratA_signature);
      return a1;
    }

    verifier = &CryptoPP::ed25519Verifier::`vftable';
    v17 = &CryptoPP::ed25519Verifier::`vftable';
    ed25519PublicKey_140223BE0((__int64)v18);
    QByteArray::QByteArray(a1);
    QByteArray::~QByteArray(&partB_message);
    QByteArray::~QByteArray(&pratA_signature);
  }
  else
  {
    QByteArray::QByteArray(a1);
  }

  return a1;
}

3、xx_parse_license_json_14021BA10

{
    "nam":"",
    "eml":"",
    "lic":"",
    "dev":n,//設備數量 
    "pln":"",//Personal,Business,Trial
    "dom":"",//工作組
    "api":n,//api 版本
    "iat":"2025-11-22T01:01:001",
    "exp":"",
    "exx":"",
    "ref":"",
    "hwi":{
        "machineid":"",
        "platform":1,
        "domain":"",
    }
}
XLicenseInfo *__fastcall xx_parse_license_14021BA10(XLicenseInfo *a1, QByteArray *a2)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v56 = a1;
  if ( QByteArray::isNull(a2) )
  {
    *(_QWORD *)&a1->api_f0 = 0i64;
    *(_OWORD *)&a1->name_0.ref = 0i64;
    *(_QWORD *)a1->name_0.data_10 = 0i64;
    QByteArray::QByteArray(&a1->name_0);
    *(_OWORD *)&a1->eml_18.ref = 0i64;
    *(_QWORD *)a1->eml_18.data_10 = 0i64;
    QByteArray::QByteArray(&a1->eml_18);
    *(_OWORD *)&a1->lic_30.ref = 0i64;
    *(_QWORD *)a1->lic_30.data_10 = 0i64;
    QByteArray::QByteArray(&a1->lic_30);
    *(_QWORD *)&a1->dev_48 = 0i64;
    *(_OWORD *)&a1->pln_50.ref = 0i64;
    *(_QWORD *)a1->pln_50.data_10 = 0i64;
    QByteArray::QByteArray(&a1->pln_50);
    *(_OWORD *)&a1->dom_68.ref = 0i64;
    *(_QWORD *)a1->dom_68.data_10 = 0i64;
    QByteArray::QByteArray(&a1->dom_68);
    QDateTime::QDateTime((QDateTime *)&a1->iat_datetime_80);
    QDateTime::QDateTime((QDateTime *)&a1->exp_datetime_88);
    QDateTime::QDateTime((QDateTime *)&a1->eex_datetime_90);
    QDateTime::QDateTime((QDateTime *)&a1->ref_datetime_98);
    a1->platform_A0 = 0i64;
    *(_OWORD *)&a1->machineid_A8.ref = 0i64;
    *(_QWORD *)a1->machineid_A8.data_10 = 0i64;
    QByteArray::QByteArray(&a1->machineid_A8);
    *(_OWORD *)&a1->qbytearrayC0.ref = 0i64;
    *(_QWORD *)a1->qbytearrayC0.data_10 = 0i64;
    QByteArray::QByteArray(&a1->qbytearrayC0);
    *(_OWORD *)&a1->domain_D8.ref = 0i64;
    *(_QWORD *)a1->domain_D8.data_10 = 0i64;
    QByteArray::QByteArray(&a1->domain_D8);
  }
  else
  {
    QJsonDocument::fromJson(v55, a2, 0i64);
    if ( QJsonDocument::isObject((QJsonDocument *)v55) )
    {
      XLicensingInfo_14021CDF0(&v90);
      QJsonDocument::object(v55, v53);
      v128 = 0x7A;
      nam[0] = 0x14;
      nam[1] = 0x1A;
      nam[2] = 0x11;
      v130 = 0;
      v4 = 0i64;
      for ( i = 0i64; i < 3; ++i )
        // nam
        nam[i] ^= (_BYTE)i + (_BYTE)v128;

      v130 = 0;
      QString::QString(&v93, nam);
      v6 = QJsonObject::operator[](v53, v106, &v93);
      QString::QString(&v92);
      v7 = (QStringData *)QJsonValueRef::toString(v6, v95, &v92);
      QByteArray::QByteArray(&v64);
      XX_encrypt_string_140258F90((__int64)&v64, v7);
      QByteArray::operator=(&v90, &v64);        // SET nam
      QByteArray::~QByteArray(&v64);
      QString::~QString(v95);
      QString::~QString(&v92);
      QString::~QString(&v93);
      v120 = 0x3A;
      strcpy((char *)eml, "_VP");
      for ( j = 0i64; j < 3; ++j )
        // eml
        *((_BYTE *)eml + j) ^= (_BYTE)j + (_BYTE)v120;

      HIBYTE(eml[0]) = 0;
      QString::QString(&v68, (const char *)eml);
      v9 = QJsonObject::operator[](v53, v107, &v68);
      QString::QString(&v67);
      v10 = (QStringData *)QJsonValueRef::toString(v9, v94, &v67);
      QByteArray::QByteArray(&v66);
      XX_encrypt_string_140258F90((__int64)&v66, v10);
      QByteArray::operator=(&v90.eml_18, &v66);
      QByteArray::~QByteArray(&v66);
      QString::~QString(v94);
      QString::~QString(&v67);
      QString::~QString(&v68);
      v125[1] = 0x66;
      lic[0] = 0xA;
      lic[1] = 0xE;
      lic[2] = 0xB;
      v127 = 0;
      for ( k = 0i64; k < 3; ++k )
        // lic
        lic[k] ^= (_BYTE)k + LOBYTE(v125[1]);

      v127 = 0;
      QString::QString(&v70, lic);
      v12 = QJsonObject::operator[](v53, v108, &v70);
      QString::QString(&v69);
      v13 = (QStringData *)QJsonValueRef::toString(v12, v104, &v69);
      QByteArray::QByteArray(&v60);
      XX_encrypt_string_140258F90((__int64)&v60, v13);
      QByteArray::operator=(&v90.lic_30, &v60);
      QByteArray::~QByteArray(&v60);
      QString::~QString(v104);
      QString::~QString(&v69);
      QString::~QString(&v70);
      qmemcpy(v50, "uv", 2);
      v50[2] = 0x87;
      v50[3] = 0;
      for ( m = 0i64; m < 3; ++m )
        // dev
        v50[m] -= 0x11;

      QString::QString(&v71, v50);
      v15 = (QJsonValueRef *)QJsonObject::operator[](v53, v109, &v71);
      v90.dev_48 = QJsonValueRef::toInt(v15, 0);
      QString::~QString(&v71);
      v124[1] = 0x37;
      strcpy((char *)v125, "GTW");
      for ( n = 0i64; n < 3; ++n )
        // pln
        *((_BYTE *)v125 + n) ^= (_BYTE)n + LOBYTE(v124[1]);

      HIBYTE(v125[0]) = 0;
      QString::QString(&v72, (const char *)v125);
      v17 = QJsonObject::operator[](v53, v110, &v72);
      QString::QString(&v91);
      v18 = (QStringData *)QJsonValueRef::toString(v17, v103, &v91);
      QByteArray::QByteArray(&v61);
      XX_encrypt_string_140258F90((__int64)&v61, v18);
      QByteArray::operator=(&v90.pln_50, &v61);
      QByteArray::~QByteArray(&v61);
      QString::~QString(v103);
      QString::~QString(&v91);
      QString::~QString(&v72);
      v123[1] = 0x26;
      strcpy((char *)v124, "BHE");
      for ( ii = 0i64; ii < 3; ++ii )
        // dom
        *((_BYTE *)v124 + ii) ^= (_BYTE)ii + LOBYTE(v123[1]);

      HIBYTE(v124[0]) = 0;
      QString::QString(&v74, (const char *)v124);
      v20 = QJsonObject::operator[](v53, v111, &v74);
      QString::QString(&v73);
      v21 = (QStringData *)QJsonValueRef::toString(v20, v102, &v73);
      QByteArray::QByteArray(&v65);
      XX_encrypt_string_140258F90((__int64)&v65, v21);
      QByteArray::operator=(&v90.dom_68, &v65);
      QByteArray::~QByteArray(&v65);
      QString::~QString(v102);
      QString::~QString(&v73);
      QString::~QString(&v74);
      v136[1] = 0x7C;
      v137[0] = 0x1D;
      v137[1] = 0xC;
      v137[2] = 0x15;
      v138 = 0;
      for ( jj = 0i64; jj < 3; ++jj )
        // api
        v137[jj] ^= LOBYTE(v136[1]);

      v138 = 0;
      QString::QString(&v75, v137);
      v23 = (QJsonValueRef *)QJsonObject::operator[](v53, v112, &v75);
      LOBYTE(v90.api_f0) = QJsonValueRef::toInt(v23, 0);
      QString::~QString(&v75);
      v135 = 0x28;
      strcpy((char *)v136, "AI\\");
      for ( kk = 0i64; kk < 3; ++kk )
        // iat
        *((_BYTE *)v136 + kk) ^= v135;

      HIBYTE(v136[0]) = 0;
      QString::QString(&v77, (const char *)v136);
      v25 = QJsonObject::operator[](v53, v113, &v77);
      QString::QString(&v76);
      v26 = QJsonValueRef::toString(v25, v101, &v76);
      // Qt::ISODateWithMs   9
      // ISO 8601 extended format: uses yyyy-MM-dd for dates, HH:mm:ss.zzz for times or yyyy-MM-ddTHH:mm:ss.zzz (e.g. 2017-07-24T15:46:29.739) for combined dates and times, optionally with a time-zone suffix (Z for UTC otherwise an offset as ±HH:mm) where appropriate. When parsed, a single space, ' ', may be used in place of the 'T' separator between date and time; no other spacing characters are permitted. This format also accepts HH:mm and plain HH formats for the time part, either of which may include a fractional part, HH:mm.zzz or HH.zzz, applied to the last field present (hour or minute).

      // ISO 8601 擴展格式:日期採用 yyyy-MM-dd 時間採用 HH:mm:ss.zzz 或 yyyy-MM-ddTHH:mm:ss.zzz(例如 2017-07-24T15:46:29.739)表示日期與時間組合,必要時可添加時區後綴(UTC使用Z,其他時區使用±HH:mm偏移量)。解析時,日期與時間分隔符可使用單個空格 ‘ ’替代 ‘T’;不允許使用其他空格字符。該格式還接受 HH:mm 和純 HH 時間格式,二者均可包含小數部分 HH:mm.zzz 或 HH.zzz,應用於最後一個字段(小時或分鐘)。
      v27 = QDateTime::fromString(v58, v26, 9i64);
      QDateTime::operator=(&v90.iat_datetime_80, v27);
      QDateTime::~QDateTime((QDateTime *)v58);
      QString::~QString(v101);
      QString::~QString(&v76);
      QString::~QString(&v77);
      v51[0] = 0x77;
      v51[1] = 0x8A;
      v51[2] = 0x82;
      v51[3] = 0;
      for ( mm = 0i64; mm < 3; ++mm )
        // exp
        v51[mm] -= 0x12;

      QString::QString(&v79, v51);
      v29 = QJsonObject::operator[](v53, v114, &v79);
      QString::QString(&v78);
      v30 = QJsonValueRef::toString(v29, v100, &v78);
      v31 = QDateTime::fromString(v59, v30, 9i64);
      QDateTime::operator=(&v90.exp_datetime_88, v31);
      QDateTime::~QDateTime((QDateTime *)v59);
      QString::~QString(v100);
      QString::~QString(&v78);
      QString::~QString(&v79);
      qmemcpy(v52, "nn", 2);
      v52[2] = 0x81;
      v52[3] = 0;
      for ( nn = 0i64; nn < 3; ++nn )
        // eex
        v52[nn] -= 9;

      QString::QString(&v81, v52);
      v33 = QJsonObject::operator[](v53, v119, &v81);
      QString::QString(&v80);
      v34 = QJsonValueRef::toString(v33, v99, &v80);
      v35 = QDateTime::fromString(v57, v34, 9i64);
      QDateTime::operator=(&v90.eex_datetime_90, v35);
      QDateTime::~QDateTime((QDateTime *)v57);
      QString::~QString(v99);
      QString::~QString(&v80);
      QString::~QString(&v81);
      v122[1] = 0x54;
      strcpy((char *)v123, "&00");
      for ( i1 = 0i64; i1 < 3; ++i1 )
        // ref
        *((_BYTE *)v123 + i1) ^= (_BYTE)i1 + LOBYTE(v122[1]);

      HIBYTE(v123[0]) = 0;
      QString::QString(&v83, (const char *)v123);
      v37 = QJsonObject::operator[](v53, v115, &v83);
      QString::QString(&v82);
      v38 = QJsonValueRef::toString(v37, v98, &v82);
      v39 = QDateTime::fromString(&v56, v38, 9i64);
      QDateTime::operator=(&v90.ref_datetime_98, v39);
      QDateTime::~QDateTime((QDateTime *)&v56);
      QString::~QString(v98);
      QString::~QString(&v82);
      QString::~QString(&v83);
      eml[1] = 0x3C;
      strcpy((char *)v122, "TJW");
      for ( i2 = 0i64; i2 < 3; ++i2 )
        // hwi
        *((_BYTE *)v122 + i2) ^= (_BYTE)i2 + LOBYTE(eml[1]);

      HIBYTE(v122[0]) = 0;
      QString::QString(&v84, (const char *)v122);
      v41 = QJsonObject::operator[](v53, v116, &v84);
      QJsonValueRef::toObject(v41, v54);
      QString::~QString(&v84);
      // machineid
      strcpy(v134, "|prwx}txs");
      for ( i3 = 0i64; i3 < 9; ++i3 )
        v134[i3] -= 0xF;

      QString::QString(&v86, v134);
      v43 = QJsonObject::operator[](v54, v117, &v86);
      QString::QString(&v85);
      v44 = (QStringData *)QJsonValueRef::toString(v43, v97, &v85);
      QByteArray::QByteArray(&v63);
      XX_encrypt_string_140258F90((__int64)&v63, v44);
      QByteArray::operator=(&v90.machineid_A8, &v63);
      QByteArray::~QByteArray(&v63);
      QString::~QString(v97);
      QString::~QString(&v85);
      QString::~QString(&v86);
      v139 = 0x5C;
      // platform
      strcpy(v140, ",0=(:3.1");
      for ( i4 = 0i64; i4 < 8; ++i4 )
        v140[i4] ^= v139;

      v140[8] = 0;
      QString::QString(&v87, v140);
      v46 = (QJsonValueRef *)QJsonObject::operator[](v54, v105, &v87);
      LODWORD(v90.platform_A0) = QJsonValueRef::toInt(v46, 0);
      QString::~QString(&v87);
      v131 = 0x63;
      qmemcpy(v132, "\a\v\b\a", 4);
      v132[4] = 0xE;
      v132[5] = 6;
      v133 = 0;
      do
      {
        // domain
        v132[v4] ^= (_BYTE)v4 + (_BYTE)v131;
        ++v4;
      }
      while ( v4 < 6 );

      v133 = 0;
      QString::QString(&v89, v132);
      v47 = QJsonObject::operator[](v54, v118, &v89);
      QString::QString(&v88);
      v48 = (QStringData *)QJsonValueRef::toString(v47, v96, &v88);
      QByteArray::QByteArray(&v62);
      XX_encrypt_string_140258F90((__int64)&v62, v48);
      QByteArray::operator=(&v90.domain_D8, &v62);
      QByteArray::~QByteArray(&v62);
      QString::~QString(v96);
      QString::~QString(&v88);
      QString::~QString(&v89);
      QByteArray::QByteArray(&a1->name_0);
      QByteArray::operator=(a1, &v90);
      QByteArray::QByteArray(&a1->eml_18);
      QByteArray::operator=(&a1->eml_18, &v90.eml_18);
      QByteArray::QByteArray(&a1->lic_30);
      QByteArray::operator=(&a1->lic_30, &v90.lic_30);
      a1->dev_48 = v90.dev_48;
      QByteArray::QByteArray(&a1->pln_50);
      QByteArray::operator=(&a1->pln_50, &v90.pln_50);
      QByteArray::QByteArray(&a1->dom_68);
      QByteArray::operator=(&a1->dom_68, &v90.dom_68);
      QDateTime::QDateTime(&a1->iat_datetime_80, &v90.iat_datetime_80);
      QDateTime::QDateTime(&a1->exp_datetime_88, &v90.exp_datetime_88);
      QDateTime::QDateTime(&a1->eex_datetime_90, &v90.eex_datetime_90);
      QDateTime::QDateTime(&a1->ref_datetime_98, &v90.ref_datetime_98);
      LODWORD(a1->platform_A0) = v90.platform_A0;
      QByteArray::QByteArray(&a1->machineid_A8);
      QByteArray::operator=(&a1->machineid_A8, &v90.machineid_A8);
      QByteArray::QByteArray(&a1->qbytearrayC0);
      QByteArray::operator=(&a1->qbytearrayC0, &v90.qbytearrayC0);
      QByteArray::QByteArray(&a1->domain_D8);
      QByteArray::operator=(&a1->domain_D8, &v90.domain_D8);
      LOBYTE(a1->api_f0) = v90.api_f0;
      QJsonObject::~QJsonObject((QJsonObject *)v54);
      QJsonObject::~QJsonObject((QJsonObject *)v53);
      dst_XLicenseInfo_14021CD50(&v90);
    }
    else
    {
      *(_QWORD *)&a1->api_f0 = 0i64;
      *(_OWORD *)&a1->name_0.ref = 0i64;
      *(_QWORD *)a1->name_0.data_10 = 0i64;
      QByteArray::QByteArray(&a1->name_0);
      *(_OWORD *)&a1->eml_18.ref = 0i64;
      *(_QWORD *)a1->eml_18.data_10 = 0i64;
      QByteArray::QByteArray(&a1->eml_18);
      *(_OWORD *)&a1->lic_30.ref = 0i64;
      *(_QWORD *)a1->lic_30.data_10 = 0i64;
      QByteArray::QByteArray(&a1->lic_30);
      *(_QWORD *)&a1->dev_48 = 0i64;
      *(_OWORD *)&a1->pln_50.ref = 0i64;
      *(_QWORD *)a1->pln_50.data_10 = 0i64;
      QByteArray::QByteArray(&a1->pln_50);
      *(_OWORD *)&a1->dom_68.ref = 0i64;
      *(_QWORD *)a1->dom_68.data_10 = 0i64;
      QByteArray::QByteArray(&a1->dom_68);
      QDateTime::QDateTime((QDateTime *)&a1->iat_datetime_80);
      QDateTime::QDateTime((QDateTime *)&a1->exp_datetime_88);
      QDateTime::QDateTime((QDateTime *)&a1->eex_datetime_90);
      QDateTime::QDateTime((QDateTime *)&a1->ref_datetime_98);
      a1->platform_A0 = 0i64;
      *(_OWORD *)&a1->machineid_A8.ref = 0i64;
      *(_QWORD *)a1->machineid_A8.data_10 = 0i64;
      QByteArray::QByteArray(&a1->machineid_A8);
      *(_OWORD *)&a1->qbytearrayC0.ref = 0i64;
      *(_QWORD *)a1->qbytearrayC0.data_10 = 0i64;
      QByteArray::QByteArray(&a1->qbytearrayC0);
      *(_OWORD *)&a1->domain_D8.ref = 0i64;
      *(_QWORD *)a1->domain_D8.data_10 = 0i64;
      QByteArray::QByteArray(&a1->domain_D8);
    }

    QJsonDocument::~QJsonDocument((QJsonDocument *)v55);
  }

  return a1;
}

4、LicensingDesktop_set_info_140228AA0

void __fastcall LicensingDesktop_set_info_140228AA0(LicensingDesktop *a1, XLicenseInfo *a2)
{
  XLicenseInfo v4; // [rsp+20h] [rbp-E0h] BYREF

  QByteArray::QByteArray(&v4.name_0, &a2->name_0);
  QByteArray::QByteArray(&v4.eml_18, &a2->eml_18);
  QByteArray::QByteArray(&v4.lic_30, &a2->lic_30);
  v4.dev_48 = a2->dev_48;
  QByteArray::QByteArray(&v4.pln_50, &a2->pln_50);
  QByteArray::QByteArray(&v4.dom_68, &a2->dom_68);
  QDateTime::QDateTime((QDateTime *)&v4.iat_datetime_80, (const struct QDateTime *)&a2->iat_datetime_80);
  QDateTime::QDateTime((QDateTime *)&v4.exp_datetime_88, (const struct QDateTime *)&a2->exp_datetime_88);
  QDateTime::QDateTime((QDateTime *)&v4.eex_datetime_90, (const struct QDateTime *)&a2->eex_datetime_90);
  QDateTime::QDateTime((QDateTime *)&v4.ref_datetime_98, (const struct QDateTime *)&a2->ref_datetime_98);
  LODWORD(v4.platform_A0) = a2->platform_A0;
  QByteArray::QByteArray(&v4.machineid_A8, &a2->machineid_A8);
  QByteArray::QByteArray(&v4.qbytearrayC0, &a2->qbytearrayC0);
  QByteArray::QByteArray(&v4.domain_D8, &a2->domain_D8);
  LOBYTE(v4.api_f0) = a2->api_f0;
  QByteArray::operator=(&a1->licinfo_60, &v4);
  QByteArray::operator=(&a1->licinfo_60.eml_18, &v4.eml_18);
  QByteArray::operator=(&a1->licinfo_60.lic_30, &v4.lic_30);
  a1->licinfo_60.dev_48 = v4.dev_48;
  QByteArray::operator=(&a1->licinfo_60.pln_50, &v4.pln_50);
  QByteArray::operator=(&a1->licinfo_60.dom_68, &v4.dom_68);
  QDateTime::operator=(&a1->licinfo_60.iat_datetime_80, &v4.iat_datetime_80);
  QDateTime::operator=(&a1->licinfo_60.exp_datetime_88, &v4.exp_datetime_88);
  QDateTime::operator=(&a1->licinfo_60.eex_datetime_90, &v4.eex_datetime_90);
  QDateTime::operator=(&a1->licinfo_60.ref_datetime_98, &v4.ref_datetime_98);
  LODWORD(a1->licinfo_60.platform_A0) = v4.platform_A0;
  QByteArray::operator=(&a1->licinfo_60.machineid_A8, &v4.machineid_A8);
  QByteArray::operator=(&a1->licinfo_60.qbytearrayC0, &v4.qbytearrayC0);
  QByteArray::operator=(&a1->licinfo_60.domain_D8, &v4.domain_D8);
  LOBYTE(a1->licinfo_60.api_f0) = v4.api_f0;
  dst_XLicenseInfo_14021CD50(&v4);
}

5、refresh_time_140225EA0

需要patch,不然會refresh

void __fastcall refresh_time_140225EA0(LicensingDesktop *a1)
{
  int v2; // ebx
  QTimer *v3; // rcx
  int v4; // edx
  QTimer *refreshActivation_timer1B8; // rbx
  __int128 v6; // [rsp+20h] [rbp-38h] BYREF
  int v7; // [rsp+30h] [rbp-28h] BYREF
  QByteArray v8; // [rsp+38h] [rbp-20h] BYREF
  LicensingDesktop *v9; // [rsp+60h] [rbp+8h] BYREF

  DWORD2(v6) = 0x17C;
  v9 = a1;
  *(_QWORD *)&v6 = (char *)xx_ck_machineid_time_dom_1402243A0 + 0x17C;
  v2 = *sub_140226EB0(&v7, &v6, (__int64)&v9);
  QByteArray::~QByteArray(&v8);
  if ( v2 != 0xC )
  {
    if ( a1->refresh_times_1C0 || !(unsigned __int8)sub_14021D290(&a1->licinfo_60) )
    {
      refreshActivation_timer1B8 = a1->refreshActivation_timer1B8;
      v4 = sub_14021D370(&a1->licinfo_60);
      v3 = refreshActivation_timer1B8;
    }
    else
    {
      v3 = a1->refreshActivation_timer1B8;
      v4 = 1;
    }

    QTimer::start(v3, v4);
  }
}

__int64 __fastcall xx_ck_machineid_time_dom_1402243A0(__int64 a1, LicensingDesktop *a2)
{
  xx_ck_machineid_time_dom_14021CE90(&a2->licinfo_60, (LicensingResult *)a1);
  return a1;
}


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

  v25 = a2;
  v4 = 0;
  v23 = 0;
  if ( QByteArray::isEmpty(&a1->eml_18) || LODWORD(a1->platform_A0) != 1 )
    goto LABEL_27;

  if ( QByteArray::isEmpty(&a1->dom_68) )
  {
LABEL_21:
    dec_string_1402590C0(&a1->machineid_A8, (QString *)&temp);
    separator[0] = '-';
    dec_string_1402590C0(&a1->machineid_A8, &v30);
    bytes_size = x_get_bytes_sz_1402189B0(&v30);
    // 0x140276fcd
    v27.data = (QStringData *)((char *)machineid_140276EB0 + 0x11D);
    LODWORD(v27.end) = 0x11D;
    memset(v34, 0, sizeof(v34));
    QString::QString((QString *)((char *)v34 + 8));
    memset(v36, 0, sizeof(v36));
    v14 = operator new(0x10ui64);
    v14[1] = 0i64;
    v36[0] = (__int64)v14;
    *v14 = v36;
    v38 = 0;
    v41 = 0;
    v39 = 0i64;
    v40 = 0;
    v24 = 0;
    v35 = 0;
    v37 = 0;
    // int bytes_size, unsigned __int8 separator
    sub_140220CE0((__int64)v34, (__int128 *)&v27, (__int64)&bytes_size, (__int64)separator);
    QString::QString(&v29, (const struct QString *)((char *)v34 + 8));
    sub_14003B6F0((__int64)v36);
    QString::~QString((char *)v34 + 8);
    v15 = qst_isequal_140039840(&v29, (QString *)&temp);
    QString::~QString(&v29);
    QString::~QString(&v30);
    QString::~QString(&temp);
    if ( v15 )
    {
      // 減20分鐘
      pre = (const struct QDateTime *)QDateTime::addSecs(&a1->iat_datetime_80, &v25, -1200ui64);
      // iat_datetime -20分鐘要早於當前時間
      currentDateTime_ = (QDateTime *)QDateTime::currentDateTime(&bytes_size);
      LOBYTE(pre) = QDateTime::precedes(currentDateTime_, pre);
      QDateTime::~QDateTime((QDateTime *)&bytes_size);
      QDateTime::~QDateTime((QDateTime *)&v25);
      if ( !(_BYTE)pre )
      {
        currentDateTime = (const struct QDateTime *)QDateTime::currentDateTime(&v25);
        // 檢查第一個日期時間是否在第二個日期時間之前(即第一個是否早於第二個)。
        v19 = QDateTime::precedes((QDateTime *)&a1->exp_datetime_88, currentDateTime);
        QDateTime::~QDateTime((QDateTime *)&v25);
        p_activationcode_8 = &a2->activationcode_8;
        if ( v19 )
          a2->status_0 = 0x1F;
        else
          // this way
          a2->status_0 = 0;

        goto LABEL_29;
      }

      // System time error.
      a2->status_0 = 8;

LABEL_28:
      p_activationcode_8 = &a2->activationcode_8;

LABEL_29:
      QByteArray::QByteArray(p_activationcode_8);
      return (__int64)a2;
    }

LABEL_27:
    a2->status_0 = 0xC;
    goto LABEL_28;
  }

  get_wki100_langroup_1402A0820(&v27);
  v5 = dec_string_1402590C0(&a1->dom_68, (QString *)&temp);
  isequal = qst_isequal_140039840(v5, &v27);
  QString::~QString(&temp);
  if ( isequal )
    goto LABEL_7;

  v7 = (const struct QByteArray *)QString::toUtf8(&v27, &v33);
  v8 = x_Blake2s_128_140277030(&v32, v7, 4);
  v9 = QByteArray::toHex(v8, &v31, 0);
  v10 = (const struct QByteArray *)QByteArray::toUpper(v9, &v30);
  QString::QString(&v29, v10);
  v4 = 0x3E;
  v23 = 0x3E;
  v11 = dec_string_1402590C0(&a1->dom_68, (QString *)&temp);
  v12 = qst_isequal_140039840(v11, &v29);
  QString::~QString(&temp);
  if ( v12 )
LABEL_7:
    v13 = 0;
  else
    v13 = 1;

  if ( (v4 & 0x20) != 0 )
  {
    v4 &= ~0x20u;
    QString::~QString(&v29);
  }

  if ( (v4 & 0x10) != 0 )
  {
    v4 &= ~0x10u;
    QByteArray::~QByteArray((QByteArray *)&v30);
  }

  if ( (v4 & 8) != 0 )
  {
    v4 &= ~8u;
    QByteArray::~QByteArray(&v31);
  }

  if ( (v4 & 4) != 0 )
  {
    v4 &= ~4u;
    QByteArray::~QByteArray(&v32);
  }

  if ( (v4 & 2) != 0 )
    QByteArray::~QByteArray(&v33);

  if ( !v13 )
  {
    QString::~QString(&v27);
    goto LABEL_21;
  }

  a2->status_0 = 0xC;
  QByteArray::QByteArray(&a2->activationcode_8);
  QString::~QString(&v27);
  return (__int64)a2;
}
refreshActivation定時器

//refresh_time_140225EA0

//Licensing_desktop_140224860
 QObject::connect(&v10, a1->refreshActivation_timer1B8, "2timeout()", a1, "1refreshActivation()", 0);
refreshActivation_140224E90

需要patch

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

  api_f0_low = 0;
  ++a1->refresh_times_1C0;
  v8 = a1;
  *(_QWORD *)&v4.status_0 = (char *)xx_ck_machineid_time_dom_1402243A0 + 0x152;
  LODWORD(v4.activationcode_8.ref) = 0x152;
  v2 = sub_140226EB0(&v5, (__int128 *)&v4, (__int64)&v8);
  api_f0_low = 1;
  v3 = *v2 == 0xC || QByteArray::isNull(&a1->xorsig_msg_bs198);
  QByteArray::~QByteArray(&v6);
  if ( !v3 )
  {
    if ( (unsigned __int8)check_ref_time_14021D310(&a1->licinfo_60) )
    {
      api_f0_low = LOBYTE(a1->licinfo_60.api_f0);
      // 網絡激活
      *(_QWORD *)&v4.status_0 = (char *)x_net_activation_140228A40 + 0x221;
      LODWORD(v4.activationcode_8.ref) = 0x221;
      ((void (__fastcall *)(LicensingResult *, _QWORD *, QByteArray *, int *))sub_1402278E0)(
        &v4,
        &a1->LicensingClient_1B0,
        &a1->xorsig_msg_bs198,
        &api_f0_low);
    }
    else
    {
      // this way
      v4.status_0 = 0;
      QByteArray::QByteArray(&v4.activationcode_8);
      activate_SIGNAL_validated_14023B900(a1, &v4);
      QByteArray::~QByteArray(&v4.activationcode_8);
    }

    refresh_time_140225EA0(a1);
  }
}
check_ref_time_14021D310
__int64 __fastcall check_ref_time_14021D310(XLicenseInfo *a1)
{
  const struct QDateTime *v1; // rbx
  QDateTime *v2; // rax
  char v4; // [rsp+30h] [rbp+8h] BYREF
  char v5; // [rsp+38h] [rbp+10h] BYREF

  v1 = (const struct QDateTime *)QDateTime::addSecs(&a1->ref_datetime_98, &v5, 0xFFFFFFFFFFFFFB50ui64);
  v2 = (QDateTime *)QDateTime::currentDateTime(&v4);
  // currentDateTime 在ref_datetime 之前
  LOBYTE(v1) = !QDateTime::precedes(v2, v1);
  QDateTime::~QDateTime((QDateTime *)&v4);
  QDateTime::~QDateTime((QDateTime *)&v5);
  // 需要false
  return (unsigned __int8)v1;
}

字段計算/驗證相關

dom 值==》x_Blake2s_128_140277030

dom 有2中校驗方式,一種明文比較,一種hash計算比較

get_wki100_langroup_1402A0820(&v27);
  v5 = dec_string_1402590C0(&a1->dom_68, (QString *)&temp);
  isequal = qst_isequal_140039840(v5, &v27);
  QString::~QString(&temp);
  if ( isequal )
    goto LABEL_7;

  v7 = (const struct QByteArray *)QString::toUtf8(&v27, &v33);
  v8 = x_Blake2s_128_140277030(&v32, v7, 4);
  v9 = QByteArray::toHex(v8, &v31, 0);
  v10 = (const struct QByteArray *)QByteArray::toUpper(v9, &v30);
struct QByteArray *__fastcall x_Blake2s_128_140277030(
        struct QByteArray *a1,
        const struct QByteArray *data,
        int right_count)
{
  __int64 r_count1; // rsi
  unsigned __int64 i; // rax
  const struct QByteArray *v7; // rax
  QByteArray *v8; // rax
  struct QByteArray *v10; // [rsp+20h] [rbp-29h] BYREF
  QByteArray v11; // [rsp+28h] [rbp-21h] BYREF
  QByteArray v12; // [rsp+40h] [rbp-9h] BYREF
  struct QByteArray v13; // [rsp+58h] [rbp+Fh] BYREF
  int v14; // [rsp+70h] [rbp+27h]
  char v15[10]; // [rsp+74h] [rbp+2Bh] BYREF
  char v16; // [rsp+7Eh] [rbp+35h]

  r_count1 = right_count;
  v10 = a1;
  // QCryptographicHash::Blake2s_128 19
  QCryptographicHash::QCryptographicHash(&v10, 19i64);
  v14 = 0x26;
  // Snipaste 2
  qmemcpy(v15, "uHOVGURC", 8);
  v15[8] = 6;
  v15[9] = 0x14;
  v16 = 0;
  for ( i = 0i64; i < 0xA; ++i )
    v15[i] ^= v14;

  v16 = 0;
  QByteArray::QByteArray(&v11, v15, 0xFFFFFFFFFFFFFFFFui64);
  QCryptographicHash::addData((QCryptographicHash *)&v10, &v11);
  QByteArray::~QByteArray(&v11);
  // "1"
  v7 = (const struct QByteArray *)QByteArray::number(&v12, 1i64, 0xAi64);
  QCryptographicHash::addData((QCryptographicHash *)&v10, v7);
  QByteArray::~QByteArray(&v12);
  QCryptographicHash::addData((QCryptographicHash *)&v10, data);
  v8 = QCryptographicHash::result((QCryptographicHash *)&v10, &v13);
  QByteArray::right(v8, a1, r_count1);
  QByteArray::~QByteArray(&v13);
  QCryptographicHash::~QCryptographicHash((QCryptographicHash *)&v10);
  return a1;
}

machineid

QString *__fastcall machineid_140276EB0(QString *a1, int bytes_size, unsigned __int8 separator)
{
  QByteArray *SQMClient_MachineId; // rax
  struct QByteArray *v7; // rax
  const struct QByteArray *v8; // rax
  _WORD *v9; // rax
  const struct QString *v10; // rax
  QByteArray v12; // [rsp+40h] [rbp-88h] BYREF
  QString v13; // [rsp+60h] [rbp-68h] BYREF
  QByteArray v14; // [rsp+78h] [rbp-50h] BYREF
  struct QByteArray v15; // [rsp+90h] [rbp-38h] BYREF
  struct QByteArray v16; // [rsp+A8h] [rbp-20h] BYREF
  __int16 v17; // [rsp+E8h] [rbp+20h] BYREF

  v12.ref = (__int64)x_MachineId_140260310 + 0x157;
  v12.size_8 = 0x157;
  SQMClient_MachineId = sub_140226170(&v14, (__int128 *)&v12.ref);
  x_Blake2s_128_140277030(&v15, SQMClient_MachineId, bytes_size);
  QByteArray::~QByteArray(&v14);
  v7 = QByteArray::toHex(&v15, &v16, 0);
  v8 = (const struct QByteArray *)QByteArray::toUpper(v7, &v12);
  QString::QString(&v13, v8);
  QByteArray::~QByteArray(&v12);
  QByteArray::~QByteArray(&v16);
  // input_str, separator, first_step, subsequent_step
  format_string_with_separator_140276C90(a1, &v13, separator, 4, 8);
  v9 = calculateCharTransitionSum_140276DA0(&v17, (QStringData *)&v13);
  QString::append(a1, (unsigned __int16)*v9);
  v10 = (const struct QString *)QString::number(&v14, 1i64, 0xAi64);
  QString::append(a1, v10);
  QString::~QString(&v14);
  QString::~QString(&v13);
  QByteArray::~QByteArray(&v15);
  return a1;
}

x_MachineId_140260310

struct QByteArray *__fastcall x_MachineId_140260310(struct QByteArray *a1)
{
  LSTATUS v2; // ebx
  QString *v3; // rax
  __int64 v4; // rax
  DWORD cbData; // [rsp+30h] [rbp-E8h] BYREF
  int v7; // [rsp+34h] [rbp-E4h]
  HKEY hKey; // [rsp+38h] [rbp-E0h] BYREF
  __int64 v9[4]; // [rsp+40h] [rbp-D8h] BYREF
  QByteArray v10; // [rsp+60h] [rbp-B8h] BYREF
  struct QByteArray *v11; // [rsp+78h] [rbp-A0h]
  BYTE Data[128]; // [rsp+80h] [rbp-98h] BYREF

  v11 = a1;
  QSysInfo::machineUniqueId(a1);
  v7 = 1;
  if ( QByteArray::isNull(a1) )
  {
    hKey = 0i64;
    if ( !RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\SQMClient", 0, 0x20119u, &hKey) )
    {
      cbData = 0x80;
      v2 = RegQueryValueExW(hKey, L"MachineId", 0i64, 0i64, Data, &cbData);
      RegCloseKey(hKey);
      if ( !v2 )
      {
        v9[0] = (unsigned __int64)(cbData - 1) >> 1;
        v9[1] = (__int64)Data;
        QtPrivate::convertToLatin1(&v10, v9);
        v7 = 3;
        QByteArray::operator=(a1, &v10);
        QByteArray::~QByteArray(&v10);
      }
    }
  }

  if ( !QByteArray::isNull(a1) )
    return a1;

  v3 = netif_hardwareAddress_140276B80((QString *)v9);
  v4 = QString::toLocal8Bit(v3, &v10);
  QByteArray::operator=(a1, v4);
  QByteArray::~QByteArray(&v10);
  QString::~QString(v9);
  return a1;
}

calculateCharTransitionSum_140276DA0

_WORD *__fastcall calculateCharTransitionSum_140276DA0(_WORD *a1, QString *a2)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v2 = *(_QWORD *)&a2->size;
  if ( v2 )
  {
    v6 = 1;
    v7 = 0;
    if ( v2 > 1 )
    {
      v8 = 1i64;
      do
      {
        v9 = *(_WORD *)QString::operator[](a2, &v17, v8);
        v10 = (unsigned __int16 *)QString::operator[](a2, &v18, v8 - 1);
        v11 = 0;
        v12 = *v10;
        v13 = *v10;
        if ( v12 <= 0xFFu )
          v11 = v13;

        v14 = 0;
        if ( v9 <= 0xFFu )
          v14 = v9;

        v15 = v14;
        v16 = v14 - v11;
        if ( v16 < 0 )
          v16 = v11 - v15;

        v2 = *(_QWORD *)&a2->size;
        ++v6;
        v7 += v16;
        v8 = v6;
      }
      while ( v6 < v2 );
    }

    QString::operator[](a2, a1, v7 % v2);
    return a1;
  }
  else
  {
    *a1 = '0';
    return a1;
  }
}

許可激活狀態

x_code_14021D460

0: 成功
1:Unknown error
3:Network error
4:Unable to connect to the server.
5:Server internal error.
6:Permission denied.
7:Please try again later.
Too many requests.

8:System time error.
0xa:Invalid license key.
0xb:Invalid arguments.
0xc:Invalid credentials.
0xd:Invalid email.
0x14:Please check your input.
The license key has already been associated with a different email address.

0x15:The license key has been revoked.
0x16:The license has expired.
0x1e:The license has reached its device limit.
0x1f:Please check your network connection and <a href="%1">refresh</a> to try again.
The activation on this device has expired.
0x20: Please try again after %1.
 Deactivation request denied.
 0x21:You've exceeded the allowed frequency for deactivations. Please try again later. 
  Deactivation request denied.
  0x

license_info

struct __declspec(align(8)) XLicenseInfo
{
  QByteArray name_0;
  QByteArray eml_18;
  QByteArray lic_30;
  int dev_48;
  QByteArray pln_50;
  QByteArray dom_68;
  _QWORD iat_datetime_80;
  _QWORD exp_datetime_88;
  _QWORD eex_datetime_90;
  _QWORD ref_datetime_98;
  _QWORD platform_A0;
  QByteArray machineid_A8;
  QByteArray qbytearrayC0;
  QByteArray domain_D8;
  int api_f0;
};
dev_48          ==>設備數量
pln_50          ==>Personal,Business,Trial
dom_68 (工作組)

iat_datetime_80  (Issued At)==》(-20分鐘仍早於當前時間)
exp_datetime_88  (Expiration 過期時間)
eex_datetime_90  (?Extended Expiry)==》License expires on
ref_datetime_98  (refreshActivation下次激活校驗的時間)
    ==》currentDateTime 在ref_datetime 之前
    
platform_A0  ==》平台    1  ?windows desktop
machineid_A8

顯示激活信息

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

  // 0x14005cb57
  *(_QWORD *)&v71 = (char *)sub_14005CA10 + 0x147;
  DWORD2(v71) = 0x147;
  *(_OWORD *)&v43.data = v71;
  sub_1401B3D30(&error_code, (__int128 *)&v43);
  if ( error_code != 0xC )
  {
    v3 = x_Licensing_desktop_14023B4F0();
    v78 = 0x49;
    // %1: %2
    // %3 (%4 %5)
    strcpy(v79, "lxsil{Clzial}il|`");
    v4 = 0i64;
    for ( i = 0i64; i < 0x11; ++i )
      v79[i] ^= v78;

    v79[0x11] = 0;
    v6 = QString::QString(&v57, v79);
    // devices
    strcpy(&v70[5], "fgxkegu");
    for ( j = 0i64; j < 7; ++j )
      v70[j + 5] -= 2;

    QMetaObject::tr(&UnlockProDialog_1404C52D0, &devices, &v70[5], 0i64, 0xFFFFFFFF);
    dev_number = (QString *)QString::number(v56, (unsigned int)v3->licinfo_60.dev_48, 0xAi64);
    // pln==>Personal,Business,Trial
    dec_string_1402590C0(&v3->licinfo_60.pln_50, &v50);
    pln = sub_1401B2400(v9, &v55, &v50);
    name = sub_14021D420(&v3->licinfo_60.name_0, &v54);
    qmemcpy(v72, "exz|", 4);
    v72[4] = 0x86;
    v72[5] = 0x87;
    v72[6] = 0x78;
    v72[7] = 0x85;
    v72[8] = 0x78;
    v72[9] = 0x77;
    v72[0xA] = 0x33;
    v72[0xB] = 0x87;
    v72[0xC] = 0x82;
    v72[0xD] = 0;
    // Registered to
    for ( k = 0i64; k < 0xD; ++k )
      v72[k] -= 0x13;

    QMetaObject::tr(&UnlockProDialog_1404C52D0, &Registered_to, v72, 0i64, 0xFFFFFFFF);
    // %1: %2
    // %3 (%4 %5)
    x_qsprintf_140183870(v6, (__int64)&v45, &Registered_to, name, pln, dev_number, &devices);
    QString::~QString(&Registered_to);
    QString::~QString(&v54);
    QString::~QString(&v55);
    QString::~QString(&v50);
    QString::~QString(v56);
    QString::~QString(&devices);
    QString::~QString(&v57);
    if ( QDateTime::isValid((QDateTime *)&v3->licinfo_60.eex_datetime_90) )
    {
      v13 = QString::QString(&v60, "\n%1: %2");
      v14 = QLocale::QLocale((QLocale *)v44);
      v15 = x_Licensing_desktop_14023B4F0();
      v16 = (_QWORD *)QDateTime::date(&v15->licinfo_60.eex_datetime_90, v48);
      v17 = (QString *)QLocale::toString(v14, v59, *v16, 1i64);
      v66 = 0x57;
      qmemcpy(v67, "\x1B1:?5/8~:", 9);
      v67[9] = 0x18;
      v67[0xA] = 0x11;
      v67[0xB] = 0xB;
      v67[0xC] = 0x11;
      v67[0xD] = 1;
      v67[0xE] = 0x16;
      v67[0xF] = 0x46;
      v67[0x10] = 8;
      v67[0x11] = 6;
      v68 = 0;
      for ( m = 0i64; m < 0x12; ++m )
        // License expires on   
        v67[m] ^= (_BYTE)m + (_BYTE)v66;

      v68 = 0;
      QMetaObject::tr(&UnlockProDialog_1404C52D0, &v52, v67, 0i64, 0xFFFFFFFF);
      v19 = sub_14001EB90(v13, (__int64)v58, &v52, v17);
      QString::operator+=(&v45, v19);
      QString::~QString(v58);
      QString::~QString(&v52);
      QString::~QString(v59);
      QLocale::~QLocale((QLocale *)v44);
      QString::~QString(&v60);
    }

    QLabel::setText(a1->ui_28->lb_licenseInfo_1C8, &v45);
    ui_28 = a1->ui_28;
    if ( to_restart_1405EFB91 )
    {
      lb_restartPrompt_208 = ui_28->lb_restartPrompt_208;
      QString::QString(&v43);
      QLabel::setText(lb_restartPrompt_208, &v43);
      QString::~QString(&v43);
      lb_refreshPrompt_1D0 = a1->ui_28->lb_refreshPrompt_1D0;
      QString::QString(&v42);
      QLabel::setText(lb_refreshPrompt_1D0, &v42);
      v23 = &v42;
    }
    else
    {
      if ( !error_code )
      {
        v27 = ui_28->lb_restartPrompt_208;
        qmemcpy(v69, "7C", 2);
        v69[2] = 0x1C;
        strcpy(v70, "7D");
        for ( n = 0i64; n < 5; ++n )
          v69[n] -= 0x12;

        // %1
        // %2
        v29 = QString::QString(&v63, v69);
        *(_DWORD *)&v75[3] = 0x7D;
        v76[0] = 0x2F;
        v76[1] = 0x18;
        v76[2] = 0xE;
        v76[3] = 9;
        v76[4] = 0x1C;
        v76[5] = 0xF;
        v76[6] = 9;
        v76[7] = 0x5D;
        v76[8] = 0x13;
        v76[9] = 0x12;
        v76[0xA] = 0xA;
        v76[0xB] = 0x5D;
        v76[0xC] = 9;
        v76[0xD] = 0x12;
        v76[0xE] = 0x5D;
        v76[0xF] = 0x18;
        v76[0x10] = 0x13;
        v76[0x11] = 0x17;
        v76[0x12] = 0x12;
        v76[0x13] = 4;
        v76[0x14] = 0x5D;
        v76[0x15] = 0x2D;
        v76[0x16] = 0x2F;
        v76[0x17] = 0x32;
        v76[0x18] = 0x5D;
        v76[0x19] = 0x1B;
        v76[0x1A] = 0x18;
        v76[0x1B] = 0x1C;
        v76[0x1C] = 9;
        v76[0x1D] = 8;
        v76[0x1E] = 0xF;
        v76[0x1F] = 0x18;
        v76[0x20] = 0xE;
        strcpy(v77, "B");
        for ( ii = 0i64; ii < 0x22; ++ii )
          // Restart now to enjoy PRO features?
          v76[ii] ^= LOBYTE(v75[3]);

        v77[1] = 0;
        QMetaObject::tr(&UnlockProDialog_1404C52D0, &v53, v76, 0i64, 0xFFFFFFFF);
        qmemcpy(v73, "_slyv+", 6);
        v73[6] = 0x84;
        v73[7] = 0x7A;
        v73[8] = 0x80;
        v73[9] = 0x2B;
        v73[0xA] = 0x71;
        v73[0xB] = 0x7A;
        v73[0xC] = 0x7D;
        v73[0xD] = 0x2B;
        v73[0xE] = 0x84;
        qmemcpy(v74, "z€}+~€{{z}", 0xA);
        v74[0xA] = 0x7F;
        strcpy((char *)v75, ",");
        for ( jj = 0i64; jj < 0x1B; ++jj )
          // ; Thank you for your support!
          v73[jj] -= 0xB;

        // OptionsDialog
        strcpy((char *)&v71, "TuyntsxInfqtl");
        do
          v72[v4++ - 0x10] -= 5;
        while ( v4 < 0xD );

        v32 = (QString *)QCoreApplication::translate(v62, &v71, v73, 0i64, 0xFFFFFFFF);
        v33 = (const struct QString *)sub_14001EB90(v29, (__int64)v61, v32, &v53);
        QLabel::setText(v27, v33);
        QString::~QString(v61);
        QString::~QString(v62);
        QString::~QString(&v53);
        QString::~QString(&v63);
        v34 = a1->ui_28->lb_refreshPrompt_1D0;
        QString::QString(&v42);
        QLabel::setText(v34, &v42);
        QString::~QString(&v42);
        QWidget::show((QWidget *)a1->ui_28->pb_later_250);
        goto LABEL_27;
      }

      v24 = ui_28->lb_restartPrompt_208;
      QString::QString(&v42);
      QLabel::setText(v24, &v42);
      QString::~QString(&v42);
      v25 = a1->ui_28->lb_refreshPrompt_1D0;
      v26 = x_code_14021D460((__int64)&error_code, &v43);
      QLabel::setText(v25, v26);
      v23 = &v43;
    }

    QString::~QString(v23);
    QWidget::hide((QWidget *)a1->ui_28->pb_later_250);

LABEL_27:
    v35 = a1->ui_28->lb_restartPrompt_208;
    v36 = *(void (__fastcall **)(QWidget *, __int64))(*(_QWORD *)v35 + 0x58i64);
    LOBYTE(v37) = *(_QWORD *)(QLabel::text(v35, v64) + 0x10) != 0i64;
    v36(v35, v37);
    QString::~QString(v64);
    v38 = a1->ui_28->lb_refreshPrompt_1D0;
    v39 = *(void (__fastcall **)(QWidget *, __int64))(*(_QWORD *)v38 + 0x58i64);
    LOBYTE(v40) = *(_QWORD *)(QLabel::text(v38, v65) + 0x10) != 0i64;
    v39(v38, v40);
    QString::~QString(v65);
    QLineEdit::clear((QLineEdit *)a1->ui_28->le_email_F8);
    QLineEdit::clear((QLineEdit *)a1->ui_28->le_licenseKey_108);
    QPlainTextEdit::clear((QPlainTextEdit *)a1->ui_28->pte_offlineLicenseCode_2D8);
    v2 = 1;
    QString::~QString(&v45);
    goto LABEL_28;
  }

  v2 = 0;

LABEL_28:
  QByteArray::~QByteArray((QByteArray *)v47);
  return v2;
}

網絡校驗

x_net_activation_140228A40

發送網絡請求

void __fastcall x_net_activation_140228A40(__int64 a1, const struct QByteArray *a2, unsigned __int8 api_version)
{
  QByteArray v5; // [rsp+20h] [rbp-28h] BYREF
  QByteArray *v6; // [rsp+68h] [rbp+20h]

  v6 = QByteArray::QByteArray(&v5, a2);
  net_activation_14021AB50(a1, (__int64)v6, api_version);
  QByteArray::~QByteArray(v6);
}

void __fastcall net_activation_14021AB50(__int64 LicensingClient, __int64 key, unsigned __int8 api_v)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  api_v1 = api_v;
  QJsonObject::QJsonObject((QJsonObject *)v22);
  v6 = (const struct QByteArray *)QByteArray::toBase64(key, &v32, 0i64);
  v7 = QString::QString(&v31, v6);
  QJsonValue::QJsonValue((QJsonValue *)v30, v7);
  // token
  strcpy(v41, "|wsmv");
  for ( i = 0i64; i < 5; ++i )
    v41[i] -= 8;

  QString::QString(&v29, v41);
  v9 = QJsonObject::operator[](v22, v37, &v29);
  QJsonValueRef::operator=(v9, v30);
  QString::~QString(&v29);
  QJsonValue::~QJsonValue(v30);
  QString::~QString(&v31);
  QByteArray::~QByteArray(&v32);
  v24[0] = 0x101;
  v26 = 0i64;
  v25 = 0x249F0;
  v10 = sub_1402869E0();
  v11 = QJsonDocument::QJsonDocument((QJsonDocument *)v27, (const struct QJsonObject *)v22);
  v12 = (const struct QByteArray *)QJsonDocument::toJson(v11, &v36, 0i64);
  if ( (_BYTE)api_v1 )
  {
    strcpy(v42, "r~~z}D99vsmox}sxq8}xszk}~o8myw9kzs9€/;9km~s€k~syx");
    for ( j = 0i64; j < 0x31; ++j )
      // https://licensing.snipaste.com/api/v%1/activation
      v42[j] -= 0xA;

    v17 = QString::QString(&v34, v42);
    LOBYTE(v18) = 0x20;
    v20 = *(_WORD *)QChar::QChar(v21, v18);
    v14 = (QString *)QString::arg(v17, v33, api_v1, 0i64, 0xA, v20);
    v15 = 6;
  }
  else
  {
    v38 = 0x5A;
    qmemcpy(v39, "2/(--eON", 8);
    v39[8] = 0xE;
    v39[9] = 0xA;
    v39[0xA] = 7;
    v39[0xB] = 0;
    v39[0xC] = 8;
    v39[0xD] = 0x14;
    v39[0xE] = 1;
    v39[0xF] = 7;
    v39[0x10] = 0xD;
    v39[0x11] = 0x45;
    v39[0x12] = 0x1F;
    v39[0x13] = 3;
    v39[0x14] = 7;
    v39[0x15] = 0x1F;
    v39[0x16] = 0x11;
    v39[0x17] = 2;
    v39[0x18] = 6;
    v39[0x19] = 0x16;
    v39[0x1A] = 0x5A;
    v39[0x1B] = 0x16;
    v39[0x1C] = 0x19;
    v39[0x1D] = 0x1A;
    v39[0x1E] = 0x57;
    v39[0x1F] = 0x18;
    v39[0x20] = 0xA;
    v39[0x21] = 0x12;
    v39[0x22] = 0x53;
    v39[0x23] = 0x1C;
    v39[0x24] = 0x1D;
    v39[0x25] = 0xB;
    v39[0x26] = 0xE9;
    v39[0x27] = 0xF7;
    v39[0x28] = 0xE3;
    v39[0x29] = 0xF7;
    v39[0x2A] = 0xED;
    v39[0x2B] = 0xEA;
    v39[0x2C] = 0xE8;
    v40 = 0;
    for ( k = 0i64; k < 0x2D; ++k )
      // https://licensing.snipaste.com/api/activation
      v39[k] ^= (_BYTE)k + (_BYTE)v38;

    v40 = 0;
    v14 = QString::QString(&v35, v39);
    v15 = 1;
  }

  QUrl::QUrl(v23, v14, 0i64);
  v19 = sub_140288430((__int64)v10, (__int64)v23, v12, (__int64)v24);
  QUrl::~QUrl(v23);
  if ( (v15 & 4) != 0 )
  {
    v15 &= ~4u;
    QString::~QString(v33);
  }

  if ( (v15 & 2) != 0 )
  {
    v15 &= ~2u;
    QString::~QString(&v34);
  }

  if ( (v15 & 1) != 0 )
    QString::~QString(&v35);

  QByteArray::~QByteArray(&v36);
  QJsonDocument::~QJsonDocument((QJsonDocument *)v27);
  QObject::connect(v28, v19, "2finished()", LicensingClient, "1handleActivationReply()", 0);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v28);
  sub_14002A6A0((__int64 *)&v26 + 1);
  sub_14002A6A0((__int64 *)&v26);
  QJsonObject::~QJsonObject((QJsonObject *)v22);
}

網絡請求完成後==》handleActivationReply

handleActivationReply_14021A9C0

處理

gotActivationResult信號

QObject::connect(
    &v10,
    a1->LicensingClient_1B0,
    "2gotActivationResult(const LicensingResult&)",
    a1,
    "1handleActivationResult(const LicensingResult&)",
    0);

void __fastcall LicensingClient::qt_static_metacall(QObject *a1, int a2, int a3, __int64 a4)
{
  int v4; // er8
  int v5; // er8
  int v6; // er8
  _DWORD *v7; // rcx
  void (__fastcall *v8)(struct QObject *, void *); // rdx

  // [case 0],SIGNAL Public Void gotActivationResult(LicensingResult error)
  // [case 1],SIGNAL Public Void gotActivation(QByteArray activation)
  // [case 2],SIGNAL Public Void gotDeactivationResult(LicensingResult error)
  // [case 3],SLOT Private Void handleActivationReply()
  // [case 4],SLOT Private Void handleDeactivtionReply()

以及QNetworkAccessManager的 finished信號

QObject::connect(v28, v19, "2finished()", LicensingClient, "1handleActivationReply()", 0);

void __fastcall net_activation_14021AB50(__int64 LicensingClient, __int64 key, unsigned __int8 api_v)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  api_v1 = api_v;
  QJsonObject::QJsonObject((QJsonObject *)v22);
  v6 = (const struct QByteArray *)QByteArray::toBase64(key, &v32, 0i64);
  v7 = QString::QString(&v31, v6);
  QJsonValue::QJsonValue((QJsonValue *)v30, v7);
  // token
  strcpy(v41, "|wsmv");
  for ( i = 0i64; i < 5; ++i )
    v41[i] -= 8;

  QString::QString(&v29, v41);
  v9 = QJsonObject::operator[](v22, v37, &v29);
  QJsonValueRef::operator=(v9, v30);
  QString::~QString(&v29);
  QJsonValue::~QJsonValue(v30);
  QString::~QString(&v31);
  QByteArray::~QByteArray(&v32);
  v24[0] = 0x101;
  v26 = 0i64;
  v25 = 0x249F0;
  v10 = sub_1402869E0();
  v11 = QJsonDocument::QJsonDocument((QJsonDocument *)v27, (const struct QJsonObject *)v22);
  v12 = (const struct QByteArray *)QJsonDocument::toJson(v11, &v36, 0i64);
  if ( (_BYTE)api_v1 )
  {
    strcpy(v42, "r~~z}D99vsmox}sxq8}xszk}~o8myw9kzs9€/;9km~s€k~syx");
    for ( j = 0i64; j < 0x31; ++j )
      // https://licensing.snipaste.com/api/v%1/activation
      v42[j] -= 0xA;

    v17 = QString::QString(&v34, v42);
    LOBYTE(v18) = 0x20;
    v20 = *(_WORD *)QChar::QChar(v21, v18);
    v14 = (QString *)QString::arg(v17, v33, api_v1, 0i64, 0xA, v20);
    v15 = 6;
  }
  else
  {
    v38 = 0x5A;
    qmemcpy(v39, "2/(--eON", 8);
    v39[8] = 0xE;
    v39[9] = 0xA;
    v39[0xA] = 7;
    v39[0xB] = 0;
    v39[0xC] = 8;
    v39[0xD] = 0x14;
    v39[0xE] = 1;
    v39[0xF] = 7;
    v39[0x10] = 0xD;
    v39[0x11] = 0x45;
    v39[0x12] = 0x1F;
    v39[0x13] = 3;
    v39[0x14] = 7;
    v39[0x15] = 0x1F;
    v39[0x16] = 0x11;
    v39[0x17] = 2;
    v39[0x18] = 6;
    v39[0x19] = 0x16;
    v39[0x1A] = 0x5A;
    v39[0x1B] = 0x16;
    v39[0x1C] = 0x19;
    v39[0x1D] = 0x1A;
    v39[0x1E] = 0x57;
    v39[0x1F] = 0x18;
    v39[0x20] = 0xA;
    v39[0x21] = 0x12;
    v39[0x22] = 0x53;
    v39[0x23] = 0x1C;
    v39[0x24] = 0x1D;
    v39[0x25] = 0xB;
    v39[0x26] = 0xE9;
    v39[0x27] = 0xF7;
    v39[0x28] = 0xE3;
    v39[0x29] = 0xF7;
    v39[0x2A] = 0xED;
    v39[0x2B] = 0xEA;
    v39[0x2C] = 0xE8;
    v40 = 0;
    for ( k = 0i64; k < 0x2D; ++k )
      // https://licensing.snipaste.com/api/activation
      v39[k] ^= (_BYTE)k + (_BYTE)v38;

    v40 = 0;
    v14 = QString::QString(&v35, v39);
    v15 = 1;
  }

  QUrl::QUrl(v23, v14, 0i64);
  v19 = sub_140288430((__int64)v10, (__int64)v23, v12, (__int64)v24);
  QUrl::~QUrl(v23);
  if ( (v15 & 4) != 0 )
  {
    v15 &= ~4u;
    QString::~QString(v33);
  }

  if ( (v15 & 2) != 0 )
  {
    v15 &= ~2u;
    QString::~QString(&v34);
  }

  if ( (v15 & 1) != 0 )
    QString::~QString(&v35);

  QByteArray::~QByteArray(&v36);
  QJsonDocument::~QJsonDocument((QJsonDocument *)v27);
  QObject::connect(v28, v19, "2finished()", LicensingClient, "1handleActivationReply()", 0);
  QMetaObject::Connection::~Connection((QMetaObject::Connection *)v28);
  sub_14002A6A0((__int64 *)&v26 + 1);
  sub_14002A6A0((__int64 *)&v26);
  QJsonObject::~QJsonObject((QJsonObject *)v22);
}

公鑰加載x_pubkey_140224270

QByteArray *__fastcall x_pubkey_140224270(QByteArray *a1)
{
  unsigned __int64 v2; // rdx
  char v4[32]; // [rsp+28h] [rbp-38h] BYREF

  v4[0] = 0x90;
  v4[1] = 0xB0;
  v2 = 0i64;
  v4[2] = 0x3B;
  v4[3] = 0x42;
  v4[4] = 0x5F;
  v4[5] = 0x5B;
  v4[6] = 0x36;
  v4[7] = 0x73;
  v4[8] = 0x35;
  v4[9] = 0x89;
  v4[0xA] = 0x4E;
  v4[0xB] = 0xB1;
  v4[0xC] = 0xE;
  v4[0xD] = 0x24;
  v4[0xE] = 0x90;
  v4[0xF] = 0xDA;
  v4[0x10] = 0x32;
  v4[0x11] = 0x9A;
  v4[0x12] = 0x5E;
  v4[0x13] = 0x53;
  v4[0x14] = 0x2D;
  v4[0x15] = 0x7B;
  v4[0x16] = 0x54;
  v4[0x17] = 0xD4;
  v4[0x18] = 0xF8;
  v4[0x19] = 0xBC;
  v4[0x1A] = 0xA8;
  v4[0x1B] = 0x5C;
  v4[0x1C] = 0x92;
  v4[0x1D] = 0x46;
  v4[0x1E] = 0x9A;
  strcpy(&v4[0x1F], "j");
  do
    v4[v2++] -= 0xA;
  while ( v2 < 0x20 );

  // 86a6313855512c692b7f44a7041a86d02890544923714acaeeb29e52883c9060
  QByteArray::QByteArray(a1, v4, 0xFFFFFFFFFFFFFFFFui64);
  return a1;
}

公鑰校驗點

在patch 公鑰,離線激活成功後,程序重啓後並未顯示註冊,發現其存在公鑰校驗

x_check_pubkey_140234500

__int64 __fastcall x_check_pubkey_140234500(__int64 a1, int a2)
{
  __int64 v3; // rdi
  __int64 v4; // rbx
  std_string *v5; // rax
  __int128 v7; // [rsp+20h] [rbp-68h] BYREF
  char v8[32]; // [rsp+30h] [rbp-58h] BYREF
  char v9[32]; // [rsp+50h] [rbp-38h] BYREF

  v3 = a1 + 4i64 * a2;
  *(_DWORD *)(v3 + 0xC) = 1;
  *(_QWORD *)&v7 = (char *)sub_140224000 + 0x150;
  DWORD2(v7) = 0x150;
  v4 = wrap_1402262C0((__int64)v9, &v7);
  // hqYxOFVRLGkrf0SnBBqG0CiQVEkjcUrK7rKeUog8kGA=
  *(_QWORD *)&v7 = (char *)sub_140223E90 + 0x13C;
  DWORD2(v7) = 0x13C;
  v5 = (std_string *)wrap_1402262C0((__int64)v8, &v7);
  // need 0
  LODWORD(v4) = (unsigned __int8)str_cmp_140050D10(v5, (std_string *)v4);
  sub_14000EEA0((__int64)v8);
  sub_14000EEA0((__int64)v9);
  *(_DWORD *)(a1 + 4) += v4;
  *(_DWORD *)(v3 + 0xC) = 2;
  return 1i64;
}

x_check_pubkey1_140234600

__int64 __fastcall x_check_pubkey1_140234600(__int64 a1, int a2)
{
  __int64 v3; // rdi
  QByteArray *v4; // rbx
  __int64 v5; // rax
  _QWORD *v6; // rax
  QByteArray *v7; // rax
  __int128 v9; // [rsp+20h] [rbp-98h] BYREF
  QByteArray v10; // [rsp+30h] [rbp-88h] BYREF
  QByteArray v11; // [rsp+48h] [rbp-70h] BYREF
  _QWORD v12[4]; // [rsp+60h] [rbp-58h] BYREF
  char v13[32]; // [rsp+80h] [rbp-38h] BYREF

  v3 = a1 + 4i64 * a2;
  *(_DWORD *)(v3 + 0xC) = 1;
  *(_QWORD *)&v9 = (char *)x_pubkey_140224270 + 0x1C8;
  DWORD2(v9) = 0x1C8;
  v4 = sub_140226170(&v11, &v9);
  *(_QWORD *)&v9 = (char *)sub_140223E90 + 0x200;
  DWORD2(v9) = 0x200;
  v5 = wrap_1402262C0((__int64)v13, &v9);
  v6 = sub_140278530(v12, v5);
  v7 = (QByteArray *)QByteArray::fromStdString(&v10, v6);
  // need 1
  LODWORD(v4) = cmp__140100CD0(v7, v4);
  QByteArray::~QByteArray(&v10);
  sub_14000EEA0((__int64)v12);
  sub_14000EEA0((__int64)v13);
  QByteArray::~QByteArray(&v11);
  *(_DWORD *)(a1 + 4) += (_DWORD)v4;
  *(_DWORD *)(v3 + 0xC) = 2;
  return 1i64;
}

x_check_pubkey2_1402347C0

__int64 __fastcall x_check_pubkey2_1402347C0(__int64 a1, int a2)
{
  __int64 v3; // rdi
  QByteArray *v4; // rbx
  QByteArray *v5; // rax
  __int128 v7; // [rsp+20h] [rbp-48h] BYREF
  QByteArray v8; // [rsp+30h] [rbp-38h] BYREF
  QByteArray v9; // [rsp+48h] [rbp-20h] BYREF

  v3 = a1 + 4i64 * a2;
  *(_DWORD *)(v3 + 0xC) = 1;
  // 86A6313855512C692B7F44A7041A86D02890544923714ACAEEB29E52883C9060
  *(_QWORD *)&v7 = (char *)sub_140224370 + 0x215;
  DWORD2(v7) = 0x215;
  v4 = sub_140226170(&v9, &v7);
  *(_QWORD *)&v7 = (char *)x_pubkey_140224270 + 0x254;
  DWORD2(v7) = 0x254;
  v5 = sub_140226170(&v8, &v7);
  // need 1
  LOBYTE(v4) = cmp__140100CD0(v5, v4);
  QByteArray::~QByteArray(&v8);
  QByteArray::~QByteArray(&v9);
  *(_DWORD *)(a1 + 4) += (_BYTE)v4 == 0;
  *(_DWORD *)(v3 + 0xC) = 2;
  return 1i64;
}

py

device_id.py

import hashlib
import wmi
import winreg
def get_workgroup():
    info=wmi.WMI().Win32_ComputerSystem()[0]
    return info.Workgroup
def get_machine_guid():
    """
    獲取註冊表中的MachineGuid值
    
    返回:
        MachineGuid字符串,如果獲取失敗則返回None
    """
    try:
        # 打開註冊表鍵
        key = winreg.OpenKey(
            winreg.HKEY_LOCAL_MACHINE,
            r"SOFTWARE\Microsoft\Cryptography"#r'SOFTWARE\Microsoft\SQMClient'
        )
        
        # 讀取MachineGuid值
        machine_guid, _ = winreg.QueryValueEx(key, "MachineGuid")
        
        # 關閉註冊表鍵
        winreg.CloseKey(key)
        
        return machine_guid
        
    except WindowsError as e:
        print(f"獲取註冊表值失敗: {e}")
        return None
def calculate_adjacent_char_diff_sum(input_string: str) -> str:
    """
    計算字符串中相鄰字符差值的累積和,並返回模運算後的字符
    
    Args:
        input_string: 輸入字符串
        
    Returns:
        str: 根據相鄰字符差值累積和取模後索引位置的字符
    """
    if not input_string:
        return '0'
    
    length = len(input_string)
    if length == 1:
        return input_string[0]
    
    total_diff_sum = 0
    
    for i in range(1, length):
        prev_char = ord(input_string[i-1])
        # 獲取當前字符的ASCII值(如果>255則設為0)
        curr_char = ord(input_string[i])
        # 計算絕對差值並累加
        abs_diff = abs(curr_char - prev_char)
        total_diff_sum += abs_diff
    
    # 計算模運算後的索引
    index = total_diff_sum % length
    
    return input_string[index]
def x_Blake2s_128_140277030(data:bytes,r_sz:int)->bytes:
    if isinstance(data,str):
        data=data.encode()
    hash_obj = hashlib.blake2s(digest_size=16)
    hash_obj.update(b'Snipaste 2')
    hash_obj.update(b'1')
    hash_obj.update(data)
    out=hash_obj.digest()[-r_sz:]
    # print(out.hex())
    return out
def machineid_140276EB0(machineUniqueId:bytes,r_sz=4,separator='')->bytes:
    out=x_Blake2s_128_140277030(machineUniqueId,r_sz)
    s=out.hex().upper()
    s=format_string_with_separator(s,separator,4,8)
    raw=s.replace(separator,'')
    s+=calculate_adjacent_char_diff_sum(raw)
    s+='1'
    return s.encode()

    

def sub_140277190(input_str):
    """
    將輸入字符串中的十六進制字符根據自定義映射表進行轉換
    """
    # 映射表
    mapping_str = "3679EFHKMNPRTWXY"
    
    # 將輸入字符串轉換為大寫
    upper_str = input_str.upper()
    
    # 如果輸入字符串為空,直接返回
    if len(upper_str) <= 0:
        return upper_str
    
    result_chars = []
    
    # 遍歷輸入字符串的每個字符
    for char in upper_str:
        # 將十六進制字符轉換為數值
        try:
            index = int(char, 16)  # 將十六進制字符轉換為0-15的數值
        except ValueError:
            # 如果不是有效的十六進制字符,返回空字符串
            return ""
        
        # 根據索引從映射表中獲取對應的字符
        mapped_char = mapping_str[index]
        result_chars.append(mapped_char)
    
    # 構建結果字符串
    return ''.join(result_chars)
def format_string_with_separator(input_str, separator, first_step, subsequent_step):
    """
    格式化字符串:按照指定步長插入分隔符
    
    參數:
        input_str: 輸入字符串
        separator: 分隔符
        first_step: 第一段的長度
        subsequent_step: 後續段的長度
        
    返回:
        格式化後的字符串
    """
    if not separator or not input_str:
        return input_str
    
    result = []
    pos = 0
    length = len(input_str)
    step = first_step
    
    while pos < length:
        # 添加分隔符(除了第一個段)
        if pos > 0:
            result.append(separator)
        
        # 計算當前段的實際長度
        actual_step = min(step, length - pos)
        
        # 添加當前段
        result.append(input_str[pos:pos + actual_step])
        
        # 更新位置和步長
        pos += actual_step
        step = subsequent_step
    
    return ''.join(result)
def x_gen_device_id_140219810(MachineId_or_MAC:bytes,r_sz:int):
    out=b'\x01'
    mid=machineid_140276EB0(MachineId_or_MAC,r_sz).decode()
    out+=bytes.fromhex(mid) 
    wkgroup=get_workgroup()
    out+=x_Blake2s_128_140277030(wkgroup,4)
    s=out.hex().upper()
    s+=calculate_adjacent_char_diff_sum(s)
    s=sub_140277190(s)
    s=format_string_with_separator(s,'-',1,5)
    # print(s)
    return s
    
def test():
    machine_guid=get_machine_guid()
    # print(f'machine_guid:{machine_guid}')
    net_device_id=x_gen_device_id_140219810(machine_guid,4)
    print(net_device_id)

if __name__=='__main__':
    test()

offlinekg.py

import base64
import json
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.exceptions import InvalidSignature
import os
from device_id import *

class Ed25519Helper:
    """Ed25519簽名驗證工具類,與CryptoPP兼容"""

    @staticmethod
    def generate_keypair():
        """
        生成Ed25519密鑰對

        Returns:
            tuple: (private_key_bytes(32字節), public_key_bytes(32字節))
        """
        private_key = ed25519.Ed25519PrivateKey.generate()

        # 獲取私鑰的32字節原始格式
        private_bytes = private_key.private_bytes(
            encoding=serialization.Encoding.Raw,
            format=serialization.PrivateFormat.Raw,
            encryption_algorithm=serialization.NoEncryption()
        )

        # 獲取公鑰的32字節原始格式
        public_key = private_key.public_key()
        public_bytes = public_key.public_bytes(
            encoding=serialization.Encoding.Raw,
            format=serialization.PublicFormat.Raw
        )

        return private_bytes, public_bytes

    @staticmethod
    def sign_message(private_key_bytes, message):
        """
        使用Ed25519私鑰對消息進行簽名

        Args:
            private_key_bytes: 32字節私鑰
            message: 要簽名的消息

        Returns:
            bytes: 64字節簽名
        """
        # 從原始字節加載私鑰
        private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_key_bytes)

        # 對消息進行簽名
        signature = private_key.sign(message)
        return signature

    @staticmethod
    def verify_signature(public_key_bytes, message, signature):
        """
        使用Ed25519公鑰驗證簽名

        Args:
            public_key_bytes: 32字節公鑰
            message: 原始消息
            signature: 64字節簽名

        Returns:
            bool: 驗證結果
        """
        try:
            # 從原始字節加載公鑰
            public_key = ed25519.Ed25519PublicKey.from_public_bytes(public_key_bytes)

            # 驗證簽名
            public_key.verify(signature, message)
            return True
        except InvalidSignature:
            return False

    @staticmethod
    def load_public_key_from_file(filename):
        """
        從文件加載公鑰(原始32字節格式)

        Args:
            filename: 公鑰文件路徑

        Returns:
            bytes: 32字節公鑰
        """
        with open(filename, 'rb') as f:
            return f.read()

    @staticmethod
    def save_public_key_to_file(public_key_bytes, filename):
        """
        保存公鑰到文件(原始32字節格式)

        Args:
            public_key_bytes: 32字節公鑰
            filename: 保存路徑
        """
        with open(filename, 'wb') as f:
            f.write(public_key_bytes)

    @staticmethod
    def load_private_key_from_file(filename):
        """
        從文件加載私鑰(原始32字節格式)

        Args:
            filename: 私鑰文件路徑

        Returns:
            bytes: 32字節私鑰
        """
        with open(filename, 'rb') as f:
            return f.read()

    @staticmethod
    def save_private_key_to_file(private_key_bytes, filename):
        """
        保存私鑰到文件(原始32字節格式)

        Args:
            private_key_bytes: 32字節私鑰
            filename: 保存路徑
        """
        with open(filename, 'wb') as f:
            f.write(private_key_bytes)

# 使用示例和測試


def demo_ed25519_workflow():
    """演示完整的Ed25519工作流程"""
    print("=== Ed25519 簽名驗證演示 ===\n")

    # 1. 生成密鑰對
    print("1. 生成Ed25519密鑰對...")
    private_key, public_key = Ed25519Helper.generate_keypair()
    print(f"   私鑰長度: {len(private_key)} 字節")
    print(f"   公鑰長度: {len(public_key)} 字節")
    print(f"   私鑰(hex): {private_key.hex()}")
    print(f"   公鑰(hex): {public_key.hex()}")

    # 2. 要簽名的消息
    message = b"Hello, this is a test message for Ed25519 signature verification!"
    print(f"\n2. 要簽名的消息: {message}")

    # 3. 生成簽名
    print("\n3. 生成簽名...")
    signature = Ed25519Helper.sign_message(private_key, message)
    print(f"   簽名長度: {len(signature)} 字節")
    print(f"   簽名(hex): {signature.hex()}")

    # 4. 驗證簽名(應該成功)
    print("\n4. 驗證簽名...")
    result1 = Ed25519Helper.verify_signature(public_key, message, signature)
    print(f"   正確簽名驗證結果: {result1}")

    # 5. 驗證錯誤的簽名(應該失敗)
    print("\n5. 測試錯誤簽名驗證...")
    wrong_signature = bytes([(b + 1) % 256 for b in signature])  # 修改簽名
    result2 = Ed25519Helper.verify_signature(public_key, message, wrong_signature)
    print(f"   錯誤簽名驗證結果: {result2}")

    # 6. 驗證修改後的消息(應該失敗)
    print("\n6. 測試修改消息驗證...")
    wrong_message = message + b"tampered"
    result3 = Ed25519Helper.verify_signature(public_key, wrong_message, signature)
    print(f"   修改消息驗證結果: {result3}")

    # 7. 文件操作演示
    print("\n7. 文件操作演示...")
    Ed25519Helper.save_public_key_to_file(public_key, "public_key.bin")
    Ed25519Helper.save_private_key_to_file(private_key, "private_key.bin")

    loaded_public = Ed25519Helper.load_public_key_from_file("public_key.bin")
    loaded_private = Ed25519Helper.load_private_key_from_file("private_key.bin")

    # 使用從文件加載的密鑰驗證
    new_signature = Ed25519Helper.sign_message(loaded_private, message)
    result4 = Ed25519Helper.verify_signature(loaded_public, message, new_signature)
    print(f"   文件加載密鑰驗證結果: {result4}")

    # 清理文件
    import os
    os.remove("public_key.bin")
    os.remove("private_key.bin")

    print("\n=== 演示完成 ===")


def compatibility_test():
    """與C++ CryptoPP兼容性測試"""
    print("\n=== 兼容性測試 ===\n")

    # 使用固定的測試密鑰以確保可重複性
    # 這是一個預生成的Ed25519密鑰對
    test_private_key_hex = "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
    test_public_key_hex = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"
    test_message = b"Test message for CryptoPP compatibility"

    private_key = bytes.fromhex(test_private_key_hex)
    public_key = bytes.fromhex(test_public_key_hex)

    print(f"測試私鑰: {test_private_key_hex}")
    print(f"測試公鑰: {test_public_key_hex}")
    print(f"測試消息: {test_message}")

    # 生成簽名
    signature = Ed25519Helper.sign_message(private_key, test_message)
    print(f"生成的簽名: {signature.hex()}")

    # 驗證簽名
    result = Ed25519Helper.verify_signature(public_key, test_message, signature)
    print(f"簽名驗證結果: {result}")

    # 預期的標準Ed25519簽名(用於交叉驗證)
    expected_signature_hex = (
        "e5564300c360ac729086e2cc806e828a"
        "84877f1eb8e5d974d873e06522490155"
        "5fb8821590a33bacc61e39701cf9b46b"
        "d25bf5f0595bbe24655141438e7a100b"
    )
    expected_signature = bytes.fromhex(expected_signature_hex)

    print(f"預期簽名: {expected_signature_hex}")
    print(f"簽名匹配: {signature == expected_signature}")


def make_json(name:str,eml:str,dom:str,machineid:str):
    iat_string = '2025-11-22 01:01:01'
    time_string = '2099-01-01 11:11:11'
    info = {
        "nam": name,
        "eml": eml,
        "lic": "",
        "dev": 666,
        "pln": "Personal",  # Personal,Business,Trial
        "dom": dom,  # 工作組,x_Blake2s
        "api": 0,  # api 版本
        "iat": iat_string,
        "exp": time_string,
        "exx": time_string,
        "ref": time_string,
        "hwi": {
            "machineid": machineid,# x_Blake2s
            "platform": 1,
            "domain": "",
        },
    }
   
    s=json.dumps(info)#,indent='    '
    
    return s
    


def gen_dom()->str:
    # way1
    dom:str=get_workgroup()
    # way2
    # dom=x_Blake2s_128_140277030(dom.encode('utf8'),4).hex().upper()
    # print(f'dom:{dom}')
    return dom
def gen_lic_machineid(sz:int,sep:str)->str:
    machine_guid=get_machine_guid()
    # print(f'machine_guid:{machine_guid}')
    lic_machineid=machineid_140276EB0(machine_guid,sz,sep)
    # print(f'machineid:{lic_machineid}')
    return lic_machineid.decode()

    pass
def s_xor(xor_k:bytes,data:bytes):
    out=[]
    xor_k_sz=len(xor_k)
    for i ,x in enumerate(data):
        out.append(x^xor_k[i%xor_k_sz])
    return bytes(out)
'''
1. 生成Ed25519密鑰對...
   私鑰長度: 32 字節
   公鑰長度: 32 字節
   私鑰(hex): 951743f1381818ec1af9a32a2eafce42c6261f5089468ef863e7b903c183b3f6
   公鑰(hex): 1ebf8f1197d33a99aee6c625e306739eb9bf1c2806324eb7b83a09933062aa04
'''
PRIVATE_KEY =bytes.fromhex('951743f1381818ec1af9a32a2eafce42c6261f5089468ef863e7b903c183b3f6')
PUBLIC_KEY=bytes.fromhex('1ebf8f1197d33a99aee6c625e306739eb9bf1c2806324eb7b83a09933062aa04')

def test():
    # demo_ed25519_workflow()
    # compatibility_test()
    dom=gen_dom()
    # print(f'dom:{dom}')
    machineid=gen_lic_machineid(10,'-')
    # print(f'machineid:{machineid}')
    s=make_json('ikun','ikun@kunkun.com',dom,machineid).encode()
    print('[-]license info:',s.decode())
    sig=Ed25519Helper.sign_message(PRIVATE_KEY,s)
    # print(f'sig:{sig.hex()}')
    ok=Ed25519Helper.verify_signature(PUBLIC_KEY,s,sig)
    print('[-]verify:',ok)
    x_msg=s_xor(sig,s)
    # print('x_msg:',x_msg.hex())
    data=sig+x_msg
    b64_data=base64.standard_b64encode(data)
    part1=calculate_adjacent_char_diff_sum(b64_data.decode())
    port0='0'
    code=f'{port0}{part1}-{b64_data.decode()}'
    print('-------------------------------------------------------------')
    print(code)
    return code 
def gen_k():
    print("1. 生成Ed25519密鑰對...")
    while True:
        private_key, public_key = Ed25519Helper.generate_keypair()
        if b'\x00' in public_key:
            continue
        print(f"   私鑰長度: {len(private_key)} 字節")
        print(f"   公鑰長度: {len(public_key)} 字節")
        print(f"   私鑰(hex): {private_key.hex()}")
        print(f"   公鑰(hex): {public_key.hex()}")
        break
if __name__ == "__main__":
    # gen_k()
    test()
    pass

ps

(refresh_time_140225EA0 需要patch 處理,不然存在網絡驗證的可能)

在patch 公鑰和校驗點後:

Windows離線激活和在線激活的方法_51CTO博客_離線

Windows離線激活和在線激活的方法_51CTO博客_v9_02