EasyUEFI 离线注册分析

离线注册分析

仅做离线分析,文件版本5.3.0.2

一、注册码分析

0、 通过字符信息、窗口事件、调用栈等信息定位到CUpgradeDlg

1、分析CUpgradeDlg metaClass 并根据虚表定位构造函数,

metaClass :

.text:00673220                             CUpgradeDlg_mate_673220 proc near       ; DATA XREF: .rdata:006759C4↓o
.text:00673220 000 6A 0C                                   push    0Ch
.text:00673222 004 6A 04                                   push    4
.text:00673224 008 68 10 96 81 00                          push    offset CUpgradeDlg_map_819610
.text:00673229 00C 68 74 86 8D 00                          push    offset parent_metaClass_8D8674
.text:0067322E 010 68 60 80 44 00                          push    offset CUpgradeDlg_manufacture_448060
.text:00673233 014 68 28 E8 87 00                          push    offset aCupgradedlg ; "CUpgradeDlg"
.text:00673238 018 B9 90 DA 8F 00                          mov     ecx, offset dword_8FDA90
.text:0067323D 018 E8 5C 28 F1 FF                          call    FX__FXMetaClass__metaClass_585A9E ; const FXchar* name,FXObject *(fac)(),const FXMetaClass* base,const void* ass,FXuint nass,FXuint assz
.text:00673242 000 68 C0 48 67 00                          push    offset sub_6748C0 ; void (__cdecl *)()
.text:00673247 004 E8 FC C4 F6 FF                          call    _atexit
.text:0067324C 004 59                                      pop     ecx
.text:0067324D 000 C3                                      retn
.text:0067324D                             CUpgradeDlg_mate_673220 endp

2、构造函数分析,获取控件id组成

image-20240421144126525

得到Register 注册按钮id为0x40

image-20240421143624807

3、进而分析CUpgradeDlg_map_819610 定位控件事件

image-20240421144404763

register_CUpgradeDlg_21_id40_448DE0

激活码格式XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXX (输入时自动‘-’拼接)

int __thiscall register_CUpgradeDlg_21_id40_448DE0(CUpgradeDlg *this, int a2, int a3, int a4)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v43 = a2;
  v44 = a4;
  email = (char *)this->email_98;
  memset(rsa_publick_dec, 0, sizeof(rsa_publick_dec));
  memset(appversion, 0, sizeof(appversion));
  ver2[0] = 0;
  ver1 = 0;
  sub_408680(email, (int)&s_email);             // support@hasleo.com
  v50 = 0;
  sub_408680((char *)this->CLicenseInputTextField_9C, (int)&s_license);
  LOBYTE(v50) = 1;
  memset(ws_email_1, 0, 0x100);
  memset(ws_license, 0, 0x6C);
  v7 = AppVersion_44FF00(appversion);
  v8 = v6;
  v40 = v6;
  if ( !(_WORD)v6 )
  {
    v9 = fxstring_580929((void **)&s_email);
    fxstring_5805EF((void **)&s_email, v9);
    if ( !*((_DWORD *)s_email + 0xFFFFFFFF) )
    {
      v10 = GetLastError() + 0xD001F000000000i64;
      v8 = HIDWORD(v10);
      v7 = v10;
      v35 = v10;
      v34 = 0xD1;

LABEL_57:
      v40 = v8;
      log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", v34, v35);
      goto LABEL_58;
    }

    v11 = fxstring_580929((void **)&s_license);
    fxstring_5805EF((void **)&s_license, v11);
    if ( !*((_DWORD *)s_license + 0xFFFFFFFF) )
    {
      v12 = GetLastError() + 0xD701F100000000i64;
      v8 = HIDWORD(v12);
      v7 = v12;
      v35 = v12;
      v34 = 0xD8;
      goto LABEL_57;
    }

    if ( !s_email
      || v37 == (_BYTE *)0xFFFFFF2C
      || MultiByteToWideChar(0xFDE9u, 0, s_email, 0xFFFFFFFF, ws_email_1, 0x80) <= 0 )
    {
      v13 = GetLastError() + 0xDE000E00000000i64;
      v8 = HIDWORD(v13);
      v7 = v13;
      v35 = v13;
      v34 = 0xDF;
      goto LABEL_57;
    }

    if ( !s_license
      || v37 == (_BYTE *)0xFFFFFF9C
      || MultiByteToWideChar(0xFDE9u, 0, s_license, 0xFFFFFFFF, ws_license, 0x36) <= 0 )
    {
      v14 = GetLastError() + 0xE4000E00000000i64;
      v8 = HIDWORD(v14);
      v7 = v14;
      v35 = v14;
      v34 = 0xE5;
      goto LABEL_57;
    }

    license_format_455420((int)ws_license, ws_license);
    ++this->field_A4;
    v7 = check_rsa_pubk_dec_47D1D0(ws_email_1, ws_license, rsa_publick_dec);
    v8 = v15;
    v40 = v15;
    if ( (_WORD)v15 )
    {
      log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", 0xEE, v7, v15);
      goto LABEL_58;
    }

    v7 = sub_47D430(rsa_publick_dec, ver2, &ver1);
    v8 = v16;
    v40 = v16;
    if ( (_WORD)v16 )
    {
      log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", 0xF4, v7, v16);
      goto LABEL_58;
    }

    if ( ver2[0] != 1 || rsa_publick_dec[1] != 1 )
    {
      v32 = GetLastError() + 0xF901F100000000i64;// Invalid license key.
      v8 = HIDWORD(v32);
      v7 = v32;
      v35 = v32;
      v34 = 0xFA;
      goto LABEL_57;
    }

    if ( (unsigned __int8)(ver1 - 1) > 5u || ver1 == 6 || ver1 == 5 )
    {
      v31 = GetLastError() + 0x10001F100000000i64;
      v8 = HIDWORD(v31);
      v7 = v31;
      v35 = v31;
      v34 = 0x101;
      goto LABEL_57;
    }

    if ( rsa_publick_dec[3] || (v17 = rsa_publick_dec[8] & 0xF, (rsa_publick_dec[8] & 0xF) != 0) && v17 != 1 && v17 != 2 )
    {
      v30 = GetLastError() + 0x10701F100000000i64;
      v8 = HIDWORD(v30);
      v7 = v30;
      v35 = v30;
      v34 = 0x108;
      goto LABEL_57;
    }

    // "5.3.0.2"
    if ( appversion[0] > (unsigned int)(unsigned __int8)rsa_publick_dec[2] && (ver1 == 4 || ver1 == 2) )
    {
      v18 = GetLastError() + 0x11001F100000000i64;
      v8 = HIDWORD(v18);
      v7 = v18;
      v35 = v18;
      v34 = 0x111;
      goto LABEL_57;
    }

    if ( (ver1 == 3 || ver1 == 1)
      && v17 == 2
      && rsa_publick_dec[0x11]
      && _time64(0) >= *(_DWORD *)&rsa_publick_dec[4] + 2678400 * (unsigned int)(unsigned __int8)rsa_publick_dec[0x11] )// rsa_publick_dec[0x11] 月
    {
      v19 = GetLastError() + 0x11B01F100000000i64;
      v8 = HIDWORD(v19);
      v7 = v19;
      v35 = v19;
      v34 = 0x11C;
      goto LABEL_57;
    }

    unknowclass_4500E0 = get_unknowclass_4500E0();
    v21 = do_net_check_4502D0((int)ws_license, unknowclass_4500E0, 0) & 0xFFF;// net_check
    if ( v21 <= 9 )
    {
      if ( v21 == 9 || !v21 )                   // 9 时离线
      {
        this->Active_status_B4 = v21;
        fxstring_5805EF((void **)&this->s_email_A8, (void **)&s_email);// [esp+20]:"support@hasleo.com"
        fxstring_5805EF((void **)&this->s_license_AC, (void **)&s_license);
        v36 = v44;
        this->ver1_B0 = (unsigned __int8)ver1;
        v22 = sub_585C8E(this, v43, a3, v36);

LABEL_42:
        v23 = v22;
        LOBYTE(v50) = 0;
        FX::FXString::~FXString((void **)&s_license);
        v50 = 0xFFFFFFFF;
        FX::FXString::~FXString((void **)&s_email);
        return v23;
      }

      goto LABEL_51;
    }

    if ( v21 > 0xE )
    {
      if ( v21 == 0xF )
      {
        v29 = GetLastError() + 0x13D01F300000000i64;// Your license has expired, please renew it to continue using this software.
        v8 = HIDWORD(v29);
        v7 = v29;
        v35 = v29;
        v34 = 0x13E;
        goto LABEL_57;
      }

      if ( v21 != 0xFFF )
        goto LABEL_51;
    }
    else
    {
      if ( v21 == 0xE )
      {
        v26 = GetLastError() + 0x13701F500000000i64;// The license key has been disabled.
        v8 = HIDWORD(v26);
        v7 = v26;
        v35 = v26;
        v34 = 0x138;
        goto LABEL_57;
      }

      if ( v21 != 0xA )
      {
        if ( v21 == 0xD )
        {
          v25 = GetLastError() + 0x13101F400000000i64;// The license key has exceeded the number of activations allowed.
          v8 = HIDWORD(v25);
          v7 = v25;
          v35 = v25;
          v34 = 0x132;
          goto LABEL_57;
        }

LABEL_51:
        v27 = GetLastError() + 0x14301F600000000i64;// Activation failed.
        v8 = HIDWORD(v27);
        v7 = v27;
        v35 = v27;
        v34 = 0x144;
        goto LABEL_57;
      }
    }

    v28 = GetLastError() + 0x12601F100000000i64;
    v8 = HIDWORD(v28);
    v7 = v28;
    v35 = v28;
    v34 = 0x127;
    goto LABEL_57;
  }

  log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", 0xC9, v7, v6);

LABEL_58:
  v46 = 0;
  v33 = (unsigned __int16)(((unsigned __int64)GetLastError() + 0x1F100000000i64) >> 0x20);
  if ( v46 || v33 != (unsigned __int16)v40 )
  {
    if ( (unsigned __int16)v40 | v46 )
      error_402CA0(this, this->FXApp_90, v7, v8, 0);
  }
  else
  {
    error_402CA0(this, this->FXApp_90, v7, v8, 0);
    if ( this->field_A4 >= 3u )
    {
      v22 = sub_585CAD(this, v43, a3, v44);
      goto LABEL_42;
    }
  }

  LOBYTE(v50) = 0;
  FX::FXString::~FXString((void **)&s_license);
  v50 = 0xFFFFFFFF;
  FX::FXString::~FXString((void **)&s_email);
  return 1;
}

check_rsa_pubk_dec_47D1D0

对注册码进行自定义base32解码,再进行RSA公钥解密

自定义字符表为ABCDEFGHJKLMNPQRSTUVWXYZ23456789

rsa解密后为0x1e字节,最后一位为crc8校验值

int __usercall check_rsa_pubk_dec_47D1D0@<eax>(
        const unsigned __int16 *ws_email_1@<edx>,
        const wchar_t *ws_license@<ecx>,
        char *rsa_enc)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  memset(str_license, 0, 0x31);
  v21 = 0;
  memset(dec, 0, sizeof(dec));
  v5 = wcslen(ws_email_1);
  if ( ws_license && wcslen(ws_license) == 48 && ws_email_1 && v5 )
  {
    str_email = (char *)malloc(v5 + 1);
    v7 = str_email;
    if ( str_email )
    {
      if ( v5 == wcstombs(str_email, ws_email_1, v5 + 1) )
      {
        _strupr(v7);
        if ( wcstombs(str_license, ws_license, 49u) == 48 )
        {
          _strupr(str_license);
          v8 = custom_base32_decode_47D0A0(dec, str_license);
          if ( (_WORD)v12 )
          {
            log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x2A0, v8, v12);
          }
          else
          {
            v8 = rsa_dec_47CEF0(dec, rsa_enc);
            if ( v13 )
            {
              log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", v18, 0x2A7, v8);
            }
            else
            {
              v14 = rsa_enc[0x1D];
              rsa_enc[0x1D] = 0;
              if ( v14 != (unsigned __int8)CRC8_47D7E0(0, (unsigned __int8 *)rsa_enc) )
              {
                v15 = GetLastError() + 0x2AF01F100000000i64;
                v8 = v15;
                log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x2B0, v15);
              }

              v7 = *(char **)dec;
            }
          }
        }
        else
        {
          v11 = GetLastError() + 0x297000E00000000i64;
          v8 = v11;
          log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x298, v11);
        }
      }
      else
      {
        v10 = GetLastError() + 0x28F000E00000000i64;
        v8 = v10;
        log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x290, v10);
      }
    }
    else
    {
      v9 = GetLastError() + 0x289000300000000i64;
      v8 = v9;
      log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x28A, v9);
    }

    if ( v7 )
      free(v7);
  }
  else
  {
    v17 = GetLastError() + 0x28101F100000000i64;
    v8 = v17;
    log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x282, v17);
  }

  return v8;
}

rsa_dec_47CEF0

int __thiscall rsa_dec_47CEF0(char *data, char *out)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v2 = 0;
  memset(rsa_PUBLICkey, 0, 0x1000u);
  qmemcpy(
    rsa_PUBLICkey,
    "-----BEGIN RSA PUBLIC KEY-----\n"
    "MCYCHwC9s2qhNcaeKtlin3VtwnU9Vv4x/j0wBPS43F/8eKMCAwEAAQ==\n"
    "-----END RSA PUBLIC KEY-----\n",
    0x75u);
  v3 = BIO_new_mem_buf(rsa_PUBLICkey, 0x75);
  v4 = v3;
  if ( v3 )
  {
    bio_SSL_SESSION = PEM_read_bio_SSL_SESSION(v3, 0, 0, 0);
    v7 = bio_SSL_SESSION;
    if ( bio_SSL_SESSION )
    {
      // static int RSA_eay_public_encrypt(int flen, const unsigned char *from,
      //          unsigned char *to, RSA *rsa, int padding)
      if ( RSA_eay_public_decrypt_602D40(0x1E, (int)data, (int)out, (int)bio_SSL_SESSION, 3) < 0 )
      {
        v9 = GetLastError() + 0x13D000200000000i64;
        v2 = v9;
        log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x13E, v9);
      }
    }
    else
    {
      v8 = GetLastError() + 0x135007200000000i64;
      v2 = v8;
      log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x136, v8);
    }

    BIO_free_all(v4);
    if ( v7 )
      RSA_free(v7);
  }
  else
  {
    v5 = GetLastError() + 0x12D000300000000i64;
    v2 = v5;
    log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x12E, v5);
  }

  CRYPTO_cleanup_all_ex_data();
  return v2;
}

校验注册码信息

/*
if (license_info[8]&0xf)!=0:
	if (license_info[8]&0xf)==1 or (license_info[8]&0xf)==2:
		ver2=license_info[0]
		ver1=license_info[0x10]
	else:
		error
else:
	ver2=license_info[0]&0x1f
	ver1=license_info[0]>>5
*/ 
v7 = sub_47D430(rsa_publick_dec, ver2, &ver1);
    v8 = v16;
    v40 = v16;
    if ( (_WORD)v16 )
    {
      log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\UpgradeDlg.cpp", 0xF4, v7, v16);
      goto LABEL_58;
    }
//ver2==1  license_info[1]==1
    if ( ver2[0] != 1 || rsa_publick_dec[1] != 1 )
    {
      v32 = GetLastError() + 0xF901F100000000i64;// Invalid license key.
      v8 = HIDWORD(v32);
      v7 = v32;
      v35 = v32;
      v34 = 0xFA;
      goto LABEL_57;
    }
//ver1<5
    if ( (unsigned __int8)(ver1 - 1) > 5u || ver1 == 6 || ver1 == 5 )
    {
      v31 = GetLastError() + 0x10001F100000000i64;
      v8 = HIDWORD(v31);
      v7 = v31;
      v35 = v31;
      v34 = 0x101;
      goto LABEL_57;
    }
//license_info[3]==0
//(license_info[8] & 0xF)==0 or 1 or 2
    if ( rsa_publick_dec[3] || (v17 = rsa_publick_dec[8] & 0xF, (rsa_publick_dec[8] & 0xF) != 0) && v17 != 1 && v17 != 2 )
    {
      v30 = GetLastError() + 0x10701F100000000i64;
      v8 = HIDWORD(v30);
      v7 = v30;
      v35 = v30;
      v34 = 0x108;
      goto LABEL_57;
    }

// "5.3.0.2"
//5<=license_info[2]
//ver1!=2  ver1!=4
    if ( appversion[0] > (unsigned int)(unsigned __int8)rsa_publick_dec[2] && (ver1 == 4 || ver1 == 2) )
    {
      v18 = GetLastError() + 0x11001F100000000i64;
      v8 = HIDWORD(v18);
      v7 = v18;
      v35 = v18;
      v34 = 0x111;
      goto LABEL_57;
    }
/*
(ver1!=1 and ver1!=3) || 
(license_info[8] & 0xF)!=2 ||
license_info[0x11]==0 || 
(time(2)>license_info[4] + 2678400 *license_info[0x11])
*/
    if ( (ver1 == 3 || ver1 == 1)
      && v17 == 2
      && rsa_publick_dec[0x11]
      && _time64(0) >= *(_DWORD *)&rsa_publick_dec[4] + 2678400 * (unsigned int)(unsigned __int8)rsa_publick_dec[0x11] )// rsa_publick_dec[0x11] 月
    {
      v19 = GetLastError() + 0x11B01F100000000i64;
      v8 = HIDWORD(v19);
      v7 = v19;
      v35 = v19;
      v34 = 0x11C;
      goto LABEL_57;
    }

    unknowclass_4500E0 = get_unknowclass_4500E0();
    v21 = do_net_check_4502D0((int)ws_license, unknowclass_4500E0, 0) & 0xFFF;// net_check
    if ( v21 <= 9 )
    {
      if ( v21 == 9 || !v21 )                   // 9 时离线
      {
        this->Active_status_B4 = v21;
        fxstring_5805EF((void **)&this->s_email_A8, (void **)&s_email);// [esp+20]:"support@hasleo.com"
        fxstring_5805EF((void **)&this->s_license_AC, (void **)&s_license);
        v36 = v44;
        this->ver1_B0 = (unsigned __int8)ver1;
        v22 = sub_585C8E(this, v43, a3, v36);

LABEL_42:
        v23 = v22;
        LOBYTE(v50) = 0;
        FX::FXString::~FXString((void **)&s_license);
        v50 = 0xFFFFFFFF;
        FX::FXString::~FXString((void **)&s_email);
        return v23;
      }

      goto LABEL_51;
    }

sub_47D430

int __fastcall sub_47D430(char *rsa_publick_dec, char *ver2, char *ver1)
{
  int result; // eax
  __int64 v4; // kr00_8

  result = 0;
  if ( (*((_WORD *)rsa_publick_dec + 4) & 0xF) != 0 )
  {
    // +8  低4bit 不等于0时,值应为1或2
    if ( (*((_WORD *)rsa_publick_dec + 4) & 0xF) == 1 )
    {
      *ver2 = *rsa_publick_dec;
      *ver1 = rsa_publick_dec[0x10];
    }

    else if ( (*((_WORD *)rsa_publick_dec + 4) & 0xF) == 2 )
    {
      *ver2 = *rsa_publick_dec;
      *ver1 = rsa_publick_dec[0x10];
    }
    else
    {
      v4 = GetLastError() + 0x33301F100000000i64;
      log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\License.cpp", 0x334, v4);
      return v4;
    }
  }
  else
  {
    // 取首字节 5bit
    *ver2 = *rsa_publick_dec & 0x1F;
    // (首字节>>5)
    *ver1 = (unsigned __int8)*rsa_publick_dec >> 5;
  }

  return result;
}

二、离线激活码分析

定位COfflineActiveDlg控件事件

image-20240421151153685

ok_440920

int __thiscall ok_440920(COfflineActiveDlg *this, int a2, int a3, int a4)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  License_Code_98 = (char *)this->License_Code_98;
  v30 = a2;
  v29 = a4;
  sub_408680(License_Code_98, (int)&License_Code);
  v34 = 0;
  sub_408680((char *)this->Machine_Code_A0, (int)Machine_Code);
  LOBYTE(v34) = 1;
  sub_408680((char *)this->FXTextField_Activation_Code_A8, (int)&Activation_Code);
  LOBYTE(v34) = 2;
  memset(ws_License_Code, 0, sizeof(ws_License_Code));
  memset(ws_Activation_Code, 0, 0x100);
  v6 = fxstring_580929((void **)&License_Code);
  fxstring_5805EF((void **)&License_Code, v6);
  if ( *((_DWORD *)License_Code + 0xFFFFFFFF) )
  {
    v10 = fxstring_580929(Machine_Code);
    fxstring_5805EF(Machine_Code, v10);
    if ( *((_DWORD *)Machine_Code[0] + 0xFFFFFFFF) )
    {
      v12 = fxstring_580929((void **)&Activation_Code);
      fxstring_5805EF((void **)&Activation_Code, v12);
      if ( *((_DWORD *)Activation_Code + 0xFFFFFFFF) )
      {
        if ( License_Code
          && &v24 != (int *)0xFFFFFFCC
          && MultiByteToWideChar(0xFDE9u, 0, License_Code, 0xFFFFFFFF, ws_License_Code, 0x80) > 0 )
        {
          if ( tows_43F490(Activation_Code, ws_Activation_Code) > 0 )
          {
            ++this->field_B4;
            unknowclass_4500E0 = get_unknowclass_4500E0();
            if ( (unline_check_450320(ws_License_Code, ws_Activation_Code, unknowclass_4500E0) & 0xFFF) == 0 )
            {
              v19 = sub_585C8E((CUpgradeDlg *)this, a2, a3, v29);
              goto LABEL_23;
            }

            v17 = GetLastError() + 0x11A01F700000000i64;// "Activation code is incorrect."
            v7 = HIDWORD(v17);
            v8 = v17;
            v23 = v17;
            v22 = 0x11B;
          }
          else
          {
            v15 = GetLastError() + 0x111000E00000000i64;// "The specified string is invalid."
            v7 = HIDWORD(v15);
            v8 = v15;
            v23 = v15;
            v22 = 0x112;
          }
        }
        else
        {
          v14 = GetLastError() + 0x10A000E00000000i64;
          v7 = HIDWORD(v14);
          v8 = v14;
          v23 = v14;
          v22 = 0x10B;
        }
      }
      else
      {
        v13 = GetLastError() + 0x103000D00000000i64;// "The specified string is an empty string."
        v7 = HIDWORD(v13);
        v8 = v13;
        v23 = v13;
        v22 = 0x104;
      }
    }
    else
    {
      v11 = GetLastError() + 0xFC000D00000000i64;
      v7 = HIDWORD(v11);
      v8 = v11;
      v23 = v11;
      v22 = 0xFD;
    }
  }
  else
  {
    v9 = GetLastError() + 0xF5000D00000000i64;
    v7 = HIDWORD(v9);
    v8 = v9;
    v23 = v9;
    v22 = 0xF6;
  }

  v28 = v7;
  log_450470((int)L"%S %d nRet=0x%016llX\n", ".\\OfflineActiveDlg.cpp", v22, v23);
  v31 = 0;
  v18 = (unsigned __int16)(((unsigned __int64)GetLastError() + 0x1F700000000i64) >> 0x20);
  if ( v31 || v18 != (unsigned __int16)v7 )
  {
    if ( (unsigned __int16)v28 | v31 )
      error_402CA0(this, this->FXApp_90, v8, v7, 0);

    goto LABEL_21;
  }

  error_402CA0(this, this->FXApp_90, v8, v7, 0);
  if ( this->field_B4 < 3u )
  {
LABEL_21:
    LOBYTE(v34) = 1;
    FX::FXString::~FXString((void **)&Activation_Code);
    LOBYTE(v34) = 0;
    FX::FXString::~FXString(Machine_Code);
    v34 = 0xFFFFFFFF;
    FX::FXString::~FXString((void **)&License_Code);
    return 1;
  }

  v19 = sub_585CAD(this, v30, a3, v29);

LABEL_23:
  v21 = v19;
  LOBYTE(v34) = 1;
  FX::FXString::~FXString((void **)&Activation_Code);
  LOBYTE(v34) = 0;
  FX::FXString::~FXString(Machine_Code);
  v34 = 0xFFFFFFFF;
  FX::FXString::~FXString((void **)&License_Code);
  return v21;
}

unline_check_450320

// ws_License_Code, ws_Activation_Code
int __usercall unline_check_450320@<eax>(
        wchar_t *ws_License_Code@<edx>,         // 注册码
        wchar_t *ws_Activation_Code@<ecx>,      // 激活码
        UnknowClass *a3@<esi>)
{
  int result; // eax
  int v5; // edi

  result = 0x7601001;
  if ( !a3->CActiveOnline_obj_8FDCF4 || !ws_License_Code || !ws_Activation_Code )
    return result;

  result = a3->CActiveOnline_obj_8FDCF4->vftable_0->Init_490DD0(// CActiveOnline_vft+0xc
             (int)a3->CActiveOnline_obj_8FDCF4,
             L"EasyUEFI",
             ws_License_Code,
             1);
  if ( (result & 0xFFF) != 0 )
    return result;

  v5 = a3->CActiveOnline_obj_8FDCF4->vftable_0->sub_491730(
         (_DWORD *)a3->CActiveOnline_obj_8FDCF4,
         ws_Activation_Code,
         wcslen(ws_Activation_Code));
  a3->CActiveOnline_obj_8FDCF4->vftable_0->sub_490EE0((_DWORD *)a3->CActiveOnline_obj_8FDCF4);
  return v5;
}

Init_490DD0

int __thiscall Init_490DD0(CActiveOnline *this, const wchar_t *productname, const wchar_t *ws_License_Code, int a4)
{
  int v5; // esi
  const wchar_t *v6; // eax
  DWORD LastError; // eax

  if ( this->dword8 )
  {
    v5 = 0x3901004;
  }
  else
  {
    v6 = productname;
    if ( productname )
    {
      while ( *v6++ )
        ;

      if ( v6 - (productname + 1) )
      {
        if ( ws_License_Code )
        {
          if ( wcslen(ws_License_Code) >= 48 )
          {
            this->gapC = a4;
            sub_490D20(this);
            v5 = transform_498770(&this->vec_char_Activation_Code_table_50);
            if ( (v5 & 0xFFF) == 0 )
            {
              std::wstring::operator+=((std::wstring *)&this->productname_E8, productname);
              std::wstring::operator+=((std::wstring *)&this->ws_License_Code_104, ws_License_Code);
              remove_bar_4994B0((std::wstring *)&this->ws_License_Code_104);
              this->dword8 = 1;
            }
          }
          else
          {
            v5 = 0x3D01002;
          }
        }
        else
        {
          v5 = 0x3C01002;
        }
      }
      else
      {
        v5 = 0x3B01002;
      }
    }
    else
    {
      v5 = 0x3A01002;
    }
  }

  if ( (v5 & 0xFFF) != 0 )
  {
    LastError = GetLastError();
    flog_496C40(L"[A] Init failed! uReturn = %x SysErr = %d", v5, LastError);
  }
  else
  {
    flog_496C40(L"[A] Init success.");
  }

  return v5;
}

校验激活码sub_491730

1、激活码根据字母表进行替换

2、根据‘|’进行分隔成4部分

3、

第1部分hex字符串为“8000”或“8001"

第2部分为license_md5[8:8+8]

第3部分为machine_code_md5[8:8+8]

第4部分为machine_code机器码

// local variable allocation has failed, the output may be wrong!
CActiveOnline *__thiscall sub_491730(CActiveOnline *this, void *Activation_Code, int Activation_Code_size)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v27 = this;
  tf_active_code._Myres = 7;
  tf_active_code._Mysize = 0;
  tf_active_code.u._Buf[0] = 0;
  v61 = 6;
  part1._Myres = 7;
  part1._Mysize = 0;
  part1.u._Buf[0] = 0;
  part2._Myres = 7;
  part2._Mysize = 0;
  part2.u._Buf[0] = 0;
  part3._Myres = 7;
  part3._Mysize = 0;
  part3.u._Buf[0] = 0;
  part4._Myres = 7;
  part4._Mysize = 0;
  part4.u._Buf[0] = 0;
  memset(plicense, 0, sizeof(plicense));
  v45 = 0;
  *(_DWORD *)v46 = 0;
  v47 = 0;
  v53 = 0;
  *(_DWORD *)_Ptr = 0;
  v55 = 0;
  v56 = 0;
  *(_DWORD *)v57 = 0;
  v58 = 0;
  v59 = 0;
  v49 = 0;
  *(_DWORD *)v50 = 0;
  v51 = 0;
  p2 = 0;
  pmachine_code = 0;
  p3 = 0;
  v42 = 0xF;
  v41 = 0;
  LOBYTE(v40) = 0;
  v37 = 0xF;
  v36 = 0;
  LOBYTE(v35) = 0;
  v28 = operator new(1u);
  LOBYTE(v61) = 7;
  if ( this->dword8 )
  {
    if ( Activation_Code )
    {
      if ( Activation_Code_size )
      {
        wstring_43D4C0(&tf_active_code, Activation_Code, wcslen((const unsigned __int16 *)Activation_Code));
        //激活码根据字母表进行替换
         v26 = (CActiveOnline *)vec_498A40(
                                 &this->vec_char_Activation_Code_table_50,
                                 (int)&tf_active_code,
                                 (int)&tf_active_code);
        if ( ((unsigned __int16)v26 & 0xFFF) == 0 )
        {
          p_part3 = &part3;
          v26 = (CActiveOnline *)&v24;
     
          std::wstring::wstring((std_wstring_d *)&v24, (const std::wstring *)&tf_active_code);
		//根据‘|’进行分隔成4部分
          v26 = (CActiveOnline *)split_492500(&part4, &part2, &part1, (std_wstring_d)v24, p_part3);
          if ( ((unsigned __int16)v26 & 0xFFF) == 0 )
          {
            BUF = (union std_wstring_union *)part1.u._Ptr;
            if ( part1._Myres < 8 )
              BUF = &part1.u;
			//第一部分hex字符串为8000h或8001h
            v5 = wcstol(BUF->_Buf, 0, 0x10) - 0x8000;
            if ( v5 > 17 )
              v26 = (CActiveOnline *)0x2E401001;
            else
              v26 = (CActiveOnline *)sub_4926A0(v5);//    case 0:case 1: result = 0;

            if ( ((unsigned __int16)v26 & 0xFFF) == 0 )
            {
              v6 = v27;
              p_wstring_debug_machine_code_120 = &v27->wstring_debug_machine_code_120;
                //第4部分为机器码
              if ( compare_495110(&v27->wstring_debug_machine_code_120, &part4) )
              {
                if ( part2._Mysize == 8 || part3._Mysize == 8 )
                {
                  Ptr = (union std_wstring_union *)part2.u._Ptr;
                  if ( part2._Myres < 8 )
                    Ptr = &part2.u;

                  WideCharToMultiByte(0, 0, Ptr->_Buf, 0xFFFFFFFF, &p2, 0xA, 0, 0);
                  p_u = (union std_wstring_union *)part3.u._Ptr;
                  if ( part3._Myres < 8 )
                    p_u = &part3.u;

                  WideCharToMultiByte(0, 0, p_u->_Buf, 0xFFFFFFFF, &p3, 0xA, 0, 0);
                  if ( v6->ws_License_Code_104._Myres < 8 )
                    v10 = v6->ws_License_Code_104.u._Buf;
                  else
                    v10 = v6->ws_License_Code_104.u._Ptr;

                  WideCharToMultiByte(0, 0, v10, 0xFFFFFFFF, plicense, 0x40, 0, 0);
                  if ( p_wstring_debug_machine_code_120->_Myres < 8 )
                    v11 = p_wstring_debug_machine_code_120->u._Buf;
                  else
                    v11 = p_wstring_debug_machine_code_120->u._Ptr;

                  WideCharToMultiByte(0, 0, v11, 0xFFFFFFFF, &pmachine_code, 0x18, 0, 0);
                  temp_str = (int)&v24.u._Ptr;
                  std::string::string((std::string *)&v24.u, plicense);
                  v12 = (const std::string *)md5_4986F0(&twstr, *(std_string_d *)v24.u._Buf);
                  LOBYTE(v61) = 8;
                  std::string::assign((std::string *)lic_md5, v12, 0, 0xFFFFFFFF);
                  LOBYTE(v61) = 7;
                  std::string::~string((int)&twstr);
                  temp_str = (int)&v24.u._Ptr;
                  std::string::string((std::string *)&v24.u, &pmachine_code);
                  v13 = (const std::string *)md5_4986F0(&twstr, *(std_string_d *)v24.u._Buf);
                  LOBYTE(v61) = 9;
                  std::string::assign((std::string *)v34, v13, 0, 0xFFFFFFFF);
                  LOBYTE(v61) = 7;
                  std::string::~string((int)&twstr);
                  v14 = (std_wstring_d *)std::string::substr(
                                           (std::basic_string<char,std::char_traits<char>,glitch::core::SAllocator<char,0> > *)lic_md5,
                                           (std::basic_string<char,std::char_traits<char>,glitch::core::SAllocator<char,0> > *)&twstr,
                                           8u,
                                           8u);
                  if ( v14->_Myres < 0x10 )
                    v15 = &v14->u;
                  else
                    v15 = (union std_wstring_union *)v14->u._Ptr;

                  v16 = strcmp((const char *)v15, &p2);// 第2部分为license_md5[8:8+8]
                  std::string::~string((int)&twstr);
                  if ( v16 )
                  {
                    v26 = (CActiveOnline *)0x14B01003;
                  }
                  else
                  {
                    v20 = (std_wstring_d *)std::string::substr(
                                             (std::basic_string<char,std::char_traits<char>,glitch::core::SAllocator<char,0> > *)v34,
                                             (std::basic_string<char,std::char_traits<char>,glitch::core::SAllocator<char,0> > *)&twstr,
                                             8u,
                                             8u);
                    if ( v20->_Myres < 0x10 )
                      v21 = &v20->u;
                    else
                      v21 = (union std_wstring_union *)v20->u._Ptr;

                    v22 = strcmp((const char *)v21, &p3);// 第3部分为machine_code_md5[8:8+8]
                    std::string::~string((int)&twstr);
                    if ( v22 )
                      v26 = (CActiveOnline *)0x14C01003;
                  }
                }
                else
                {
                  v26 = (CActiveOnline *)0x14401003;
                }
              }
              else
              {
                v26 = (CActiveOnline *)0x1420100B;
              }
            }
          }
        }
      }
      else
      {
        v26 = (CActiveOnline *)0x12801002;
      }
    }
    else
    {
      v26 = (CActiveOnline *)0x12701002;
    }
  }
  else
  {
    v26 = (CActiveOnline *)0x12501004;
  }

  sub_48F3B0((CActiveOnline *)&v27->wstring_www_com_6C);
  v17 = v26;
  v18 = (union std_wstring_union *)part1.u._Ptr;
  if ( ((unsigned __int16)v26 & 0xFFF) != 0 )
  {
    if ( part1._Myres < 8 )
      v18 = &part1.u;

    p_part3 = (std_wstring_d *)v18;
    LastError = GetLastError();
    flog_496C40(L"[A] AutoActive failed! uReturn = %x SysErr = %d wsStatus = %s", v17, LastError);
  }
  else
  {
    if ( part1._Myres < 8 )
      v18 = &part1.u;

    flog_496C40(L"[A] AutoActive success. wsStatus = %s", v18);
  }

  operator delete(v28);
  if ( v37 >= 0x10 )
    operator delete(v35);

  v37 = 0xF;
  v36 = 0;
  LOBYTE(v35) = 0;
  if ( v42 >= 0x10 )
    operator delete(v40);

  v42 = 0xF;
  v41 = 0;
  LOBYTE(v40) = 0;
  if ( part4._Myres >= 8 )
    operator delete(part4.u._Ptr);

  part4._Myres = 7;
  part4._Mysize = 0;
  part4.u._Buf[0] = 0;
  if ( part3._Myres >= 8 )
    operator delete(part3.u._Ptr);

  part3._Myres = 7;
  part3._Mysize = 0;
  part3.u._Buf[0] = 0;
  if ( part2._Myres >= 8 )
    operator delete(part2.u._Ptr);

  part2._Myres = 7;
  part2._Mysize = 0;
  part2.u._Buf[0] = 0;
  if ( part1._Myres >= 8 )
    operator delete(part1.u._Ptr);

  part1._Myres = 7;
  part1._Mysize = 0;
  part1.u._Buf[0] = 0;
  if ( tf_active_code._Myres >= 8 )
    operator delete(tf_active_code.u._Ptr);

  return v26;
}

py

'''
pip install pycryptodome
'''
import base64
import ctypes
import io
import os
import random
from typing import Union
from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse

import hashlib
import time
from datetime import datetime


def convert_to_time64(time_str):
    # 解析时间字符串为 datetime 对象
    dt_obj = datetime.strptime(time_str, r"%Y-%m-%d %H:%M:%S")
    # 将 datetime 对象转换为时间戳
    timestamp = dt_obj.timestamp()
    # # 将时间戳转换为 _time64 格式
    # time64 = int(timestamp * 1e7)  # 1e7 是将秒转换为 100 纳秒的单位
    time64 = int(timestamp)
    return time64


def convert_to_time_string(time64):
    # 将 _time64 格式的时间戳转换为秒数
    # timestamp = time64 / 1e7  # 将 100 纳秒转换为秒
    # 使用 fromtimestamp 将秒数转换为 datetime 对象
    dt_obj = datetime.fromtimestamp(time64)
    # 使用 strftime 方法将 datetime 对象格式化为时间字符串
    time_str = dt_obj.strftime("%Y-%m-%d %H:%M:%S")
    return time_str


pubk = "-----BEGIN RSA PUBLIC KEY-----\n"\
    "MCYCHwC9s2qhNcaeKtlin3VtwnU9Vv4x/j0wBPS43F/8eKMCAwEAAQ==\n"\
    "-----END RSA PUBLIC KEY-----\n"


def rsa_pk_enc(data: bytes) -> bytes:
    # http://factordb.com/index.php?query=1309267119417726280330942057320079958095363483536018220587938405183944867
    # e=65537
    p = 1138829745998159918316484590691394789
    q = 1149660099780921729474053823339894503
    n = p*q
    # phi = (p - 1) * (q - 1)
    # d = inverse(e, phi)
    # print(d)
    d = 461760535243012729352417637561931856791126802617053449862506727428818545
    t = int.from_bytes(data, 'big')
    x = pow(t, d, n)
    bs = i2bs(x)
    # print(x)
    # print(bs,bs.hex())
    return bs


# from rsa import PublicKey, common, transform, core
# def rsa_pubkey_dec(cipher:bytes, PUBLIC_KEY:bytes=pubk.encode()):
#         public_key = PublicKey.load_pkcs1(PUBLIC_KEY)
#         encrypted = transform.bytes2int(cipher)
#         print('e:',public_key.e)
#         print('n:',public_key.n)
#         decrypted = core.decrypt_int(encrypted, public_key.e, public_key.n)
#         print('rsa_pubkey_dec result:',decrypted)
#         text = transform.int2bytes(decrypted)
#         return text

table = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
         0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
         0x6B, 0x79, 0x6E, 0x6A, 0x41, 0x34, 0x45, 0x48, 0x78, 0x36, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
         0x40, 0x63, 0x4E, 0x57, 0x32, 0x7A, 0x6C, 0x53, 0x58, 0x4C, 0x59, 0x30, 0x64, 0x75, 0x77, 0x44,
         0x6F, 0x51, 0x70, 0x56, 0x46, 0x7C, 0x61, 0x37, 0x38, 0x5A, 0x62, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
         0x60, 0x39, 0x67, 0x65, 0x43, 0x74, 0x69, 0x73, 0x50, 0x6D, 0x68, 0x72, 0x66, 0x4F, 0x31, 0x33,
         0x55, 0x4B, 0x42, 0x35, 0x4D, 0x49, 0x54, 0x76, 0x71, 0x47, 0x4A, 0x7B, 0x52, 0x7D, 0x7E, 0x7F]


def s_transform(s: str):
    ret = ''
    for x in s:
        ret += chr(table[ord(x)])

    return ret


def re_transfrom(s: str):
    ret = ''
    for x in s:
        ret += chr(table.index(ord(x)))
    return ret


def i2bs(m: int, byteorder='big'):
    hex_m = m.to_bytes((m.bit_length() + 7) // 8, byteorder=byteorder)
    return hex_m


def rsa_pub_dec(decoded_data: bytes, PUBLIC_KEY: bytes = pubk.encode()) -> bytes:
    public_key = RSA.import_key(PUBLIC_KEY)

    # 获取模数和公钥指数
    n = public_key.n
    e = public_key.e

    # 打印结果
    print("Modulus (n):", n)
    # bs_n=n.to_bytes(128,'big')
    # print(bs_n,bs_n.hex())
    print("Exponent (e):", e)
    c = int.from_bytes(decoded_data, 'big')
    m = pow(c, e, n)
    print('pow:', m)
    hex_m = i2bs(m)
    return hex_m


class CustomBase32Codec:
    def __init__(self, custom_alphabet='ABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
        if len(custom_alphabet) != 32:
            raise ValueError("Custom alphabet must contain 32 characters.")

        # Standard Base32 alphabet
        standard_alphabet = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
        # Create translation tables
        self.encode_trans = bytes.maketrans(
            standard_alphabet, custom_alphabet.encode())
        self.decode_trans = bytes.maketrans(
            custom_alphabet.encode(), standard_alphabet)

    def encode(self, data):
        if isinstance(data, str):
            data = data.encode('utf-8')

        # Use the standard base64 library to encode and then translate to custom alphabet
        encoded = base64.b32encode(data)
        return encoded.translate(self.encode_trans)

    def decode(self, data):
        if isinstance(data, str):
            data = data.encode('utf-8')

        # Translate from custom alphabet to standard and then decode using standard base64 library
        standard_encoded = data.translate(self.decode_trans)
        return base64.b32decode(standard_encoded)


def reflect_data(x, width):
    # See: https://stackoverflow.com/a/20918545
    if width == 8:
        x = ((x & 0x55) << 1) | ((x & 0xAA) >> 1)
        x = ((x & 0x33) << 2) | ((x & 0xCC) >> 2)
        x = ((x & 0x0F) << 4) | ((x & 0xF0) >> 4)
    elif width == 16:
        x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1)
        x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2)
        x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4)
        x = ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)
    elif width == 32:
        x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1)
        x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2)
        x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4)
        x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8)
        x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16)
    else:
        raise ValueError('Unsupported width')
    return x


def crc_poly(data, n, poly, crc=0, ref_in=False, ref_out=False, xor_out=0):
    g = 1 << n | poly  # Generator polynomial

    # Loop over the data
    for d in data:
        # Reverse the input byte if the flag is true
        if ref_in:
            d = reflect_data(d, 8)
        # XOR the top byte in the CRC with the input byte
        crc ^= d << (n - 8)
        # Loop over all the bits in the byte
        for _ in range(8):
            # Start by shifting the CRC, so we can check for the top bit
            crc <<= 1
            # XOR the CRC if the top bit is 1
            if crc & (1 << n):
                crc ^= g
    # Reverse the output if the flag is true
    if ref_out:
        crc = reflect_data(crc, n)

    # Return the CRC value
    return crc ^ xor_out


def CRC8_MAXIM(data: bytes):
    crc8 = crc_poly(data, n=8, poly=0x31, ref_in=True, ref_out=True, xor_out=0)
    return crc8


def convert_bytes_to_structure(st: object, byte: bytes):
    assert ctypes.sizeof(st) == len(byte), 'size error! need:%d,give:%d' % (
        ctypes.sizeof(st), len(byte))
    # ctypes.memmove(ctypes.pointer(st), byte, ctypes.sizeof(st))
    ctypes.memmove(ctypes.addressof(st), byte, ctypes.sizeof(st))


class TYPE_BASE(ctypes.LittleEndianStructure):
    _pack_: int = 1

    def __init__(self, data: Union[bytes, list, tuple, set]) -> None:
        if isinstance(data, bytes):
            convert_bytes_to_structure(self, data)
        elif isinstance(data, (list, tuple, set)):
            convert_bytes_to_structure(self, bytes(data))
        elif isinstance(data, io.IOBase):
            data.readinto(self)


'''
struct LicenseInfo{
    char var0;
    char var1;
    char major_version2;
    char var3;
    int expiration4;
    char var8;
    char unknow9[7];
    char var10;
    char var11;
    char unknow12[11];
    char crc1d;

};
'''


class LicenseInfo(TYPE_BASE):
    # _pack_: int = 1
    _fields_: list = [
        ("var0", ctypes.c_ubyte),
        ("var1", ctypes.c_ubyte),
        ("major_version2", ctypes.c_ubyte),
        ("var3", ctypes.c_ubyte),
        ("expiration4", ctypes.c_uint32),
        ("var8", ctypes.c_ubyte),
        ("unknow9", ctypes.c_byte*7),
        ("var10", ctypes.c_ubyte),
        ("var11", ctypes.c_ubyte),
        ("unknow12", ctypes.c_byte*11),
        ("crc1d", ctypes.c_ubyte
         ),
    ]

    def __init__(self, data: Union[bytes, list, tuple, set]) -> None:
        super().__init__(data)
        self.get_var()

    def get_var(self):
        if (self.var8 & 0xf) != 0:
            if (self.var8 & 0xf) == 1 or (self.var8 & 0xf) == 2:
                self.ver2 = self.var0
                self.ver1 = self.var10
        else:
            self.ver2 = self.var0 & 0x1f
            self.ver1 = self.var0 >> 5

    def __str__(self) -> str:
        info = ''
        info += 'ver1:%02x\n' % self.ver1
        info += 'ver2:%02x\n' % self.ver2
        info += 'major_version2:%02x\n' % self.major_version2
        info += 'var3:%02x\n' % self.var3
        info += 'expiration4:%s\n' % convert_to_time_string(self.expiration4)
        info += 'var8:%02x\n' % self.var8
        info += 'unknow9:%s\n' % bytes(self.unknow9)
        info += 'var10:%02x\n' % self.var10
        info += 'var11:%02x\n' % self.var11
        info += 'unknow12:%s\n' % bytes(self.unknow12)
        info += 'crc1d:%02x\n' % self.crc1d
        return info


def parse_license(data: bytes):
    custom_b32 = CustomBase32Codec()
    decoded_data = custom_b32.decode(data)
    print("Custom Base32 Decoded:", decoded_data)
    print('hex:', decoded_data.hex())
    # enc=custom_b32.encode(b'SUPPORT@HASLEO.COM')
    # print('enc:',enc)
    # text=rsa_pubkey_dec(decoded_data)

    text = rsa_pub_dec(decoded_data)
    print('rsa_pubkey_dec:', text)
    print('rsa_pubkey_dec hex:', text.hex())
    enc = rsa_pk_enc(text)
    print('test enc:', enc, enc.hex())

    rsa_dec = text[:-1]+b'\x00'
    # CRC-8/MAXIM
    crc8 = CRC8_MAXIM(rsa_dec)
    print('crc8/MAXIM :', crc8, hex(crc8))

    obj = LicenseInfo(text)
    print(str(obj))


def GenActivationCode(license, machine_code) -> str:
    lic_md5 = hashlib.md5(license).hexdigest()
    # print('lic_md5:',lic_md5)
    mc_md5 = hashlib.md5(machine_code).hexdigest()
    # print('mc_md5:',mc_md5)

    s = '8000|%s|%s|%s' % (lic_md5[8:16], mc_md5[8:16], machine_code.decode())
    # print(s)
    re_s = re_transfrom(s)
    # print(re_s)
    return re_s


def GenLicense() -> bytes:
    lic = b''
    ver2 = 1
    ver1 = 1  # random.randint(1,4)
    lic += (ver2 | (ver1 << 5)).to_bytes(1, 'little')  # this way var8  must 0
    lic += b'\x01'  # var1
    lic += b'\xff'  # major_version2
    lic += b'\x00'  # var3
    expiration4 = convert_to_time64('2077-01-01 12:00:00')
    t = convert_to_time_string(expiration4)
    # print(t)
    lic += expiration4.to_bytes(4, 'little')
    var8 = b'\x00'
    lic += var8
    lic += os.urandom(7)  # unknow9[7]
    lic += b'\x00'  # var10
    lic += b'\xff'  # var11  month
    lic += os.urandom(11)  # unknow12[11]
    crc8 = CRC8_MAXIM(lic+b'\x00')
    lic += crc8.to_bytes(1, 'little')
    # print('lic:',lic,lic.hex())
    # print(str(LicenseInfo(lic)))
    enc = rsa_pk_enc(lic)
    license = CustomBase32Codec().encode(enc)

    return license


if __name__ == "__main__":
    license = GenLicense()
    print('License:', license.decode())
    print('Please input MachineCode:')
    mc = input().encode()
    ac = GenActivationCode(license, mc)
    print('ActivationCode', ac)



image-20240421153019573

image-20240421153045919

activate.log 日志中显示激活成功

image-20240421153142570

image-20240421152912426

ps

网络检验

int __userpurge do_net_check_4502D0@<eax>(int license@<edx>, UnknowClass *a2@<esi>, int a3)
{
  int result; // eax
  int v4; // edi

  result = 0x5401001;
  if ( !a2->CActiveOnline_obj_8FDCF4 || !license )
    return result;

  result = a2->CActiveOnline_obj_8FDCF4->vftable_0->Init_490DD0(
             (int)a2->CActiveOnline_obj_8FDCF4,
             L"EasyUEFI",
             (const wchar_t *)license,
             1);
  if ( (result & 0xFFF) != 0 )
    return result;

  // net_check_490F80
  v4 = a2->CActiveOnline_obj_8FDCF4->vftable_0->sub_490F80((int)a2->CActiveOnline_obj_8FDCF4, a3);
  a2->CActiveOnline_obj_8FDCF4->vftable_0->sub_490EE0((_DWORD *)a2->CActiveOnline_obj_8FDCF4);
  return v4;
}

main中还用一个DistributeLicense,不跟了

posted @ 2024-04-21 15:51  DirWangK  阅读(289)  评论(0编辑  收藏  举报