Winhex 21.2 分析

winhex21.2

只针对21.2,其他版本不可以,因为data2解密时的AES key(PRIVATE_KEY)不同

data1 字段没有继续跟建议直接指定21C99167CC69236A2EB9540CF881EFF6

无法使用专业工具 ,功能不熟,

keygen详见py脚本

image-20240810224020648

1、check data1&Cksm

许可信息内存结构

struct LicInfo
{
  char name[81];
  char mailarr[61];
  char homeaddr[61];
  char keydata[32];
};

BSS:00718264 ; char name_718264[81]
BSS:00718264 name_718264     db 51h dup(?)           ; DATA XREF: check_lic_6869AC+D0↑o
BSS:00718264                                         ; check_lic_6869AC+12E↑o ...
BSS:007182B5 ; _BYTE mailaddr_7182B5
BSS:007182B5 mailaddr_7182B5 db 3Dh dup(?)           ; DATA XREF: check_lic_6869AC+172↑o
BSS:007182B5                                         ; check_lic_6869AC+5CD↑o ...
BSS:007182F2 ; _BYTE homeaddr_7182F2[61]
BSS:007182F2 homeaddr_7182F2 db 3Dh dup(?)           ; DATA XREF: check_lic_6869AC+5DB↑o
BSS:007182F2                                         ; sub_6954BC+23B↑o
BSS:0071832F ; char keydata_71832F[32]
BSS:0071832F keydata_71832F  db 20h dup(?) 

check_lic_data1_6869AC

data1 校验:

1、
高3位==3;低5位 ==1; ==>0x61
(name_718264.keydata[12] ^ name_718264.keydata[8] ^ 0xB7) 

2、
开始时间 距离08/05/2015    0x4705
*(_WORD *)&name_718264.keydata[2] ^ *(_WORD *)&name_718264.keydata[12] ^ 0xEA69;

3、
结束时间  距离08/05/2015   0x4705   
要小于0x611Cu 07/09/2024
要大于0x58E9u  08/28/2028
*(_WORD *)&name_718264.keydata[4] ^ *(_WORD *)&name_718264.keydata[6] ^ 0x159D

4、
用户数 小于=3750u 0xea6
number_718624 = *(_WORD *)&name_718264.keydata[0xA] ^ *(_WORD *)&name_718264.keydata[2] ^ 0x69C5;

Cksm 校验

Cksm =crc32(LicInfo+b'sector-aligned')

char __fastcall check_lic_data1_6869AC(CHAR *input, const WCHAR *a2, char a3, char a4)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v25 = 0;
  v38 = a3;
  lpCaption = a2;
  input1 = input;
  v24 = &savedregs;
  v23[1] = (unsigned int)&loc_6872B2;
  v23[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
  __writefsdword(0, (unsigned int)v23);
  dara1_correct_718436 = 0;
  *(_BYTE *)numb_3_6FD970 = 0;
  v4 = 0;
  byte_6F9400[0x24] = 0;
  byte_6F9400[0x23] = 0;
  byte_6F9400[0x20] = 0;
  byte_6F9400[0x2F] = 0;
  byte_6F9400[0x2C] = 0;
  byte_6F9400[0x1A] = 0;
  byte_6F9400[0x22] = 0;
  byte_6F9400[0x21] = 0;
  wFatDate = 0;
  end_date_718620 = 0;
  v37 = 0;
  lpMultiByteStr = input1;
  if ( !*input1 )
    goto END_103;
  v34 = name_718264.keydata[0];
  v35 = name_718264.keydata[1];
  while ( 1 )
  {
    _408B68 = find_408B68(lpMultiByteStr, '\x93');
    if ( !_408B68 )
      break;
    *_408B68 = '"';
  }
  while ( 1 )
  {
    v6 = find_408B68(lpMultiByteStr, '\x94');
    if ( !v6 )
      break;
    *v6 = '"';
  }
  if ( !(unsigned __int8)strip_687C94((char **)&lpMultiByteStr) )
    goto END_103;
  FillChar(&name_718264, 0xEBu);
  if ( !(unsigned __int8)getLineStartToTemp_687EC0((int)&lpMultiByteStr, 0)
    // Name:
    || lstrcmpiA(&temp_getdata_7191E4, Name__6FC884)
    || !(unsigned __int8)strip_687C94((char **)&lpMultiByteStr)
    || !(unsigned __int8)get_line_data_687D80((char **)&lpMultiByteStr) )
  {
    goto END_103;
  }
  str_copy_408D20(&name_718264, &temp_getdata_7191E4);
  // mailto:
  _409A00 = find_409A00(lpMultiByteStr, *mailto__6FDBF4);
  if ( _409A00 )
  {
    v8 = find_408B68(_409A00, 0xD);
    if ( v8 )
      *v8 = 0;
    // Altered by e-mail client?
    sub_694EF4(lpMultiByteStr, *off_6FC868, 3);
  }
  v9 = 1;
  mailarr = name_718264.mailarr;
  // mailaddr和homeaddr  分别61字节
  do
  {
    if ( !(unsigned __int8)strip_687C94((char **)&lpMultiByteStr)
      || !(unsigned __int8)getLineStartToTemp_687EC0((int)&lpMultiByteStr, 0)
      // Addr
      || !str_isequal_409E2C(&temp_getdata_7191E4, Addr_6FD2C0, 4, 1)
      || !(unsigned __int8)strip_687C94((char **)&lpMultiByteStr)
      || !(unsigned __int8)get_line_data_687D80((char **)&lpMultiByteStr) )
    {
      goto END_103;
    }
    str_copy_408D20(mailarr, &temp_getdata_7191E4);
    ++v9;
    mailarr += 61;
  }
  while ( v9 != 3 );
  key_data_flag_7183E4 = 2;
  v11 = 1;
  keydata = name_718264.keydata;
  // 两个 Data/Key
  do
  {
    if ( !(unsigned __int8)strip_687C94((char **)&lpMultiByteStr)
      || !(unsigned __int8)getLineStartToTemp_687EC0((int)&lpMultiByteStr, 0)
      // Key    
      // Data
      || !str_isequal_409E2C(&temp_getdata_7191E4, Key_6FC3A8, 3, 1)
      && !str_isequal_409E2C(&temp_getdata_7191E4, Data_6FCEC4, 4, 1) )
    {
      goto END_103;
    }
    // Data
    if ( v11 == 1 && str_isequal_409E2C(&temp_getdata_7191E4, Data_6FCEC4, 4, 1) )
      key_data_flag_7183E4 = 0x14;              // 第一个为Data时
    if ( !(unsigned __int8)strip_687C94((char **)&lpMultiByteStr)
      || !(unsigned __int8)get_line_data_687D80((char **)&lpMultiByteStr)
      || hexstr2bytes_40A81C(&temp_getdata_7191E4, keydata, 0xFFFFFFFF, 0x10, 0) != 0x10 )
    {
      goto END_103;
    }
    ++v11;
    keydata += 0x10;
  }
  while ( v11 != 3 );
  if ( key_data_flag_7183E4 == 2 )
    // 第一个为key时
    key_data_flag_7183E4 = name_718264.keydata[0xD] & 0x1F;
  else
    // data  this one
    key_data_flag_7183E4 = ((name_718264.keydata[0xC] ^ name_718264.keydata[8] ^ 0xB7) & 0x1F) + 0x14;
  // b c d f 10 11 12 13 14 15
  if ( (unsigned __int8)key_data_flag_7183E4 < 0xBu
    || (unsigned __int8)key_data_flag_7183E4 > 0x15u
    || key_data_flag_7183E4 == 0xE )
  {
    goto LABEL_101;
  }
  if ( (unsigned __int8)key_data_flag_7183E4 < 0xCu )// 0xb 时  错误
  {
    if ( (unsigned __int16)(*(_WORD *)name_718264.keydata ^ *(_WORD *)&name_718264.keydata[0xE]) < 1235u )
      sub_692E04(0x3C);
    else
      sub_692E04(0x2B);
    sub_687C2C(1);
    goto END_103;
  }
  if ( (unsigned __int8)key_data_flag_7183E4 >= 0x14u )
    // this one
    wFatDate = *(_WORD *)&name_718264.keydata[4] ^ *(_WORD *)&name_718264.keydata[6] ^ 0x159D;// this way
  else
    wFatDate = *(_WORD *)name_718264.keydata ^ *(_WORD *)&name_718264.keydata[0xE];
  if ( (unsigned __int8)key_data_flag_7183E4 >= 0x14u )
  {
    // this one
    star_date = *(_WORD *)&name_718264.keydata[2] ^ *(_WORD *)&name_718264.keydata[12] ^ 0xEA69;
    v28 = star_date < 0;
    if ( (wFatDate & 0x4000) != 0 )
      wFatDate &= ~0x4000u;
    else
      start_date1_71861E = (star_date & 0x3FFF) + 0x4705;// 天数,距离 08/05/2015
  }
  *(_BYTE *)evaluation_6FD0FC = (wFatDate & 0x8000u) != 0;
  if ( *(_BYTE *)evaluation_6FD0FC )
    wFatDate &= ~0x8000u;
  if ( (unsigned __int8)key_data_flag_7183E4 >= 0x14u )
    wFatDate += 0x4705;                         // 08/05/2015
                                                // 得到结束日期
  if ( *(_BYTE *)evaluation_6FD0FC )
    end_date_718620 = wFatDate;
  // 07/09/2024
  v29 = wFatDate >= 0x58E9u;
  // 08/28/2028
  if ( wFatDate < 0x611Cu )
  {
    DosDateTimeToFileTime(wFatDate, 0, &FileTime);
    get_date_str_41D18C(&FileTime, lic_FileTime_718A60);
    if ( key_data_flag_7183E4 != 0x15 )         // !=0x15 error
    {
      name_718264.name[0] = 0;
      *(_DWORD *)name_718264.keydata = 0;
      *(_BYTE *)numb_3_6FD970 = 0;
      if ( v38 )
      {
        sub_40C060(2, (int)&v25);
        *off_6FDA08 = System::__linkproc__ ValLong(v25, v31);
      }
      if ( v29 )
      {
        LOBYTE(v4) = 1;
        sub_692E04(0x2B);
      }
      else
      {
        sub_692E04(0x3C);
      }
      v14 = sub_4211C4(v4, 3, 0x47Bu);
      sub_420A50((int)v14, (int)&history_719410, user_txt);
      sub_420A50((int)&history_719410, (int)&history_719410, lic_FileTime_718A60);
      if ( (_BYTE)v4 )
      {
        strcopy_409854((int)&history_719410, (int)" -> OK");
        str_40C5BC(&history_719410);
        v15 = sub_4211C4(v4, 3, 0x7Fu);
        sub_409594(&history_719410, v15);
      }
      if ( lpCaption )
        MessageBoxW(0, &history_719410, lpCaption, 0x30u);
      else
        sub_6949CC(&history_719410, 3);
      goto END_103;
    }
    strip_687C94((char **)&lpMultiByteStr);
    if ( !(unsigned __int8)getLineStartToTemp_687EC0((int)&lpMultiByteStr, 0) )
      goto LABEL_101;
    // Cksm
    if ( lstrcmpiA(&temp_getdata_7191E4, Cksm_6FC6CC) )
      goto LABEL_101;
    strip_687C94((char **)&lpMultiByteStr);
    if ( !(unsigned __int8)getLineStartToTemp_687EC0((int)&lpMultiByteStr, 0) )
      goto LABEL_101;
    if ( (int)hexstr2bytes_40A81C(&temp_getdata_7191E4, v33, 0xFFFFFFFF, 4, 0) < 1 )
      goto LABEL_101;
    remove_40BD94(&name_718264, ' ', 1);
    remove_40BD94(name_718264.mailarr, 0x20, 1);
    remove_40BD94(name_718264.homeaddr, 0x20, 1);
    hash_init_417784(v26, 6, 0);                // 6-->crc32
    hash_update_417A04(v26, name_718264.name, 0xEB);
    // sector-aligned
    hash_update_417A04(v26, sector_aligned_6FD928, 0xE);
    hash_final_417D18(v26, out);
    if ( *(_DWORD *)out != *(_DWORD *)v33 )
      goto LABEL_101;
    // 3
    *(_BYTE *)numb_3_6FD970 = (unsigned __int8)(name_718264.keydata[0xC] ^ name_718264.keydata[8] ^ 0xB7) >> 5;
    if ( *(_BYTE *)numb_3_6FD970 == 6 && v28 )
      *xway_ctr_6FCC58 = 1;
    if ( *(_BYTE *)numb_3_6FD970 == 4 )
    {
      *(_BYTE *)numb_3_6FD970 = 0;
      goto LABEL_101;
    }
    number_718624 = *(_WORD *)&name_718264.keydata[0xA] ^ *(_WORD *)&name_718264.keydata[2] ^ 0x69C5;
    if ( (unsigned __int16)number_718624 > 0xEA6u )// 大于 error
    {
LABEL_102:
      FillChar(&name_718264, 0xEBu);
      wFatDate = 0;
      *(_BYTE *)numb_3_6FD970 = 0;
      start_date1_71861E = 0;
      goto END_103;
    }
    if ( *(_BYTE *)numb_3_6FD970 == 6 )
    {
LABEL_101:
      sub_687C2C(0);
      goto LABEL_102;
    }
    sub_68693C();
    str_copy_408D20(license_717CB4, input1);
    if ( !a4 && (v34 != name_718264.keydata[0] || v35 != name_718264.keydata[1]) )
    {
      if ( !find_409A00(input1, *license_file_6FCB4C) )
      {
        str_copy_408D20(license_717CB4, "// ");
        // WinHex
        strcat_40953C(license_717CB4, *(_BYTE **)off_6FD834);
        //  license file
        strcat_40953C(license_717CB4, *license_file_6FCB4C);
        str_app_end_40C594(license_717CB4);
        str_app_end_40C594(license_717CB4);
        strcat_40953C(license_717CB4, input1);
      }
      sub_421728((unsigned __int8 *)user_txt, &history_719410, 0);// user.txt  历史记录 (F4)
      wstr_4096E8(NewFileName, (int)&history_719410);
      // .bak
      strcopy_409854((int)NewFileName, (int)off_6FD1DC[0]);
      if ( (unsigned __int8)sub_419ACC(&history_719410, 0) )
        MoveFileW(&history_719410, NewFileName);
      wstr_4096E8(NewFileName, (int)&history_719410);
      v16 = strlen_408C04((int)license_717CB4);
      v17 = sub_41A4F0((int)NewFileName, (int)license_717CB4, v16);
      if ( !v17 )
      {
        v18 = sub_4211C4(0, 3, 0x31Du);
        sub_68C330(v18, NewFileName);
        strcopy_409854((int)&history_719410, (int)" ");
        if ( !dara1_correct_718436 )
          *(_DWORD *)name_718264.keydata = 0;
        v22 = sub_408B18((int)&history_719410);
        v19 = sub_4211C4(0, 3, 0x3Du);
        sub_420A50((int)v19, v22, *(LPCSTR *)off_6FD834);
        // "XXX\user.txt" 创建成功。 重新启动程序 WinHex 立即重启?
        v20 = sub_694A14(&history_719410, *(LPCSTR *)off_6FD834, 0x1002, 0xFFFFFFFC);
        if ( (_BYTE)v20 == 1 )
        {
          LOBYTE(v20) = 1;
          sub_692C74(v20);
        }
        goto END_103;
      }
      sub_68A1D0(v17, (int)NewFileName, 0x53u, 0, 0);
    }
    dara1_correct_718436 = 0;
    if ( v29 && *(_DWORD *)name_718264.keydata != 0 )
    {
      if ( (unsigned __int8)(*(_BYTE *)numb_3_6FD970 - 2) < 2u || *(_BYTE *)numb_3_6FD970 == 6 )
        // need 1
        dara1_correct_718436 = 1;
    }
    else
    {
      *(_BYTE *)numb_3_6FD970 = 0;
    }
  }
END_103:
  __writefsdword(0, v23[0]);
  v24 = (int *)&loc_6872B9;
  System::__linkproc__ LStrClr(&v25);
  return v37;
}

2、check data2(在特定功能时触发)

check_lic_data2_62DADC

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

  lpBuffer[0x28] = a1;
  v1 = 0;
  CursorA = LoadCursorA(0, (LPCSTR)0x7F02);
  SetCursor(CursorA);
  VirtualQuery((void *)lpAddress, &Buffer, 0x1Cu);
  v24[0] = 0;
  if ( VirtualProtect(Buffer.BaseAddress, 0x2000u, PAGE_EXECUTE_READWRITE, &flNewProtect) )
  {
    calc_lic_data2__key_62DD14();//计算解密key
    v3 = sz_0x424_6E9404;
    nSize = (unsigned __int16)sz_0x424_6E9404;
    MOVE_407288(lpBuffer, (const void *)lpAddress, (unsigned __int16)sz_0x424_6E9404);
    FillChar(keydata, 0x20u);
    MOVE_407288(keydata, dec_lic_data2_to_privatekey_70E64C, 0x10);
    LOBYTE(v5) = 1;
    v6 = (__int64 *)AES_256_CTR_set_sha256key_6E0D60(0, block_xor_6E0AC4, v5, keydata, 0, 0);
    AES_256_CTR_6E1130(v6, lpBuffer, nSize, 0i64, 0);
    nullsub_15();
    System::__linkproc__ FreeMem(v7, 0x67A);
    FillChar(keydata, 0x20u);
    lpBaseAddress = (int)lpAddress;
    CurrentProcess = GetCurrentProcess();
    if ( ((int (__stdcall *)(HANDLE, int, _DWORD *, unsigned int, int *))*ptr_WriteProcessMemory)(
           CurrentProcess,
           lpBaseAddress,
           lpBuffer,
           nSize,
           &lpNumberOfBytesWritten) )
    {
      if ( nSize == lpNumberOfBytesWritten )
      {
        FillChar(lpBuffer, nSize);
        VirtualProtect(Buffer.BaseAddress, 0x2000u, flNewProtect, &flOldProtect);
        HIWORD(v17) = 0x2000;
        LODWORD(v17) = Buffer.BaseAddress;
        v9 = GetCurrentProcess();
        FlushInstructionCache(v9, v17, flNewProtect);
        // c2
        if ( *(_BYTE *)((_DWORD)lpAddress + v3 - 1) == byte_6E9408 )
        {
          FillChar(dec_lic_data2_to_privatekey_70E64C, 0x10u);
          LOBYTE(v1) = 1;
          v10 = LoadCursorA(0, (LPCSTR)0x7F00);
          SetCursor(v10);
          return v1;
        }
      }
    }
    else
    {
      LastError_0 = (va_list *)GetLastError_0();
      sub_40D910(LastError_0, v24, (WCHAR *)0x7F);
    }
    FillChar(dec_lic_data2_to_privatekey_70E64C, 0x10u);
  }
  else
  {
    v12 = (va_list *)GetLastError_0();
    sub_40D910(v12, v24, (WCHAR *)0x7F);
  }
  v13 = LoadCursorA(0, (LPCSTR)0x7F00);
  v14 = SetCursor(v13);
  if ( v24[0] )
    sub_694A14(v24, *(LPCSTR *)off_6FD5C8[0], 1, 0);
  else
    sub_687BC4(v14);
  return v1;
}

calc_lic_data2__key_62DD14

int calc_lic_data2__key_62DD14()
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  //  name,addr1,addr2
  hash_init_417784(result, 9, 0);               // 9--sha256
  //   char name[81];
  //   char mailarr[61];
  //   char homeaddr[61];
  hash_update_417A04(result, ptr_lic_info_6FD5A8->name, 0xCB);
  hash_final_417D18(result, (char *)user_data_SHA256);
  LOBYTE(v0) = 1;
  v1 = (__int64 *)AES_256_CTR_set_sha256key_6E0D60(0, block_xor_6E0AC4, v0, public_key_6E93E0, 0, 0);
  AES_256_CTR_6E0F68(v1, (char *)user_data_SHA256, 0x20u, 0i64, 0);
  nullsub_15();
  System::__linkproc__ FreeMem(v2, 0x67A);
  hash_init_417784(result, 9, 0);
  hash_update_417A04(result, (char *)user_data_SHA256, 0x20);
  hash_update_417A04(result, ptr_lic_info_6FD5A8->keydata, 0x10);
  hash_final_417D18(result, (char *)lic_enc_data1_sha256);// data1_sha256
                                                // 
  MOVE_407288(dec_lic_data2_to_privatekey_70E64C, &ptr_lic_info_6FD5A8->keydata[0x10], 0x10);
  LOBYTE(v3) = 1;
  v4 = (__int64 *)AES_256_CTR_set_sha256key_6E0D60(0, block_xor_6E0AC4, v3, (char *)lic_enc_data1_sha256, 0, 0);
  AES_256_CTR_6E1130(v4, dec_lic_data2_to_privatekey_70E64C, 0x10u, 0i64, 0);
  nullsub_15();
  return System::__linkproc__ FreeMem(v5, 0x67A);
}

py

import binascii
import datetime
import hashlib

import random

#pip install pycryptodome
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto.Util.strxor import strxor


#winhex 21.2
PUB_KEY = bytes.fromhex('4DEFEAE49CF72587DEADB0E192EE26C2244563BD5B98461F5CDD4595932AB4FD')

#need a currect license to dec 
PRIVATE_KEY=bytes.fromhex('725D5C612CCC0FF538E919E4365F3C4900000000000000000000000000000000')

CTR_INIT_VALUE = bytes.fromhex('D8DE2B1AA3036D3241607571F1E7C14D')


'''
// X-Ways license file
 
Name: semthex
Addr: ru-board.com
Addr: RUSSIA
Data: 21C99167CC69236A2EB9540CF881EFF6
Data: 2376D8CC4E33860CF5A9E379945DA0BE
Cksm: 3DD34CCA
'''
def str2dt(time_str, format="%Y-%m-%d"):
    dt = datetime.datetime.strptime(time_str, format)
    return dt

def datetime_to_dos_date(dt) -> int:
    year = dt.year - 1980
    month = dt.month
    day = dt.day

    dos_date: int = (year << 9) | (month << 5) | day
    return dos_date

def dos_date_to_datetime(dos_date: int) -> str:
    day = dos_date & 0x1F
    month = (dos_date >> 5) & 0x0F
    year = ((dos_date >> 9) & 0x7F) + 1980

    # 创建 datetime 对象
    dt = datetime.datetime(year, month, day)
    
    # 返回格式化后的时间字符串
    return dt.strftime('%Y-%m-%d')







def sha256(data: bytes) -> bytes:
    return hashlib.sha256(data).digest()



def int_to_bytes(n: int, order='little') -> bytes:
    # 获取整数的位长度
    bit_length = n.bit_length()
    # 计算所需的最小字节数
    byte_length = (bit_length + 7) // 8
    # 转换为字节序列,使用大端字节序
    byte_array = n.to_bytes(byte_length, byteorder=order)
    return byte_array



def zero_pad(data, block_size=16, already_pad_add=False):
    # 计算需要填充的字节数
    pad_len = block_size - (len(data) % block_size)
    if not already_pad_add:
        # 如果数据已经对齐,则 pad_len 会等于 block_size,此时无需填充
        if pad_len == block_size:
            return data
    # 进行填充,使用 b'\0' 表示零字节填充
    padded_data = data + b"\0" * pad_len
    return padded_data


def aes_sha256_ctr(key: bytes, data: bytes, block: bytes = CTR_INIT_VALUE) -> bytes:
    aeskey_sz=len(key)
    if aeskey_sz!=32:
        key=zero_pad(key,32)

    aeskey = sha256(key)
    
    print('[-]key:', key.hex())
    print('[+]aeskey:', aeskey.hex())
    print('[-]data:', data.hex())
    initvalue=int.from_bytes(block, 'little')
    counter = Counter.new(AES.block_size*8, initial_value=initvalue, little_endian=True)
    # print(counter.values())
    cipher = AES.new(key=aeskey, mode=AES.MODE_CTR, counter=counter)
    ret = cipher.encrypt(data)
    print('[+]enc/dec data:', ret.hex())

    # count=len(data)//32
    # end_=int_to_bytes(initvalue+count)
    # print('[-]end counter:',end_.hex())
    #ctr mode--> enc==dec
    
    
    return ret



class LicInfo:
    def __init__(self,name:bytes,mail:bytes,addr:bytes,data1_hexstr:bytes=b'',data2_hexstr:bytes=b'',cksm_hexstr:bytes=b'') -> None:
        self.name=name
        self.mail=mail
        self.addr=addr
        if data1_hexstr:
            self.data1=bytes.fromhex(data1_hexstr.decode()) 
        else:
            x=LicInfo.gen_data1().hex()
            self.data1=bytes.fromhex(x)
        self.userinfo:bytes=LicInfo.mk_lic_userinfo(name,mail,addr)
        if data2_hexstr:
            self.data2=bytes.fromhex(data2_hexstr.decode())
        else:
            self.data2=self.calc_data2()
        self.lic_allinfo=LicInfo.mk_lic(name,mail,addr,self.data1,self.data2)    
        # print('lic info:',self.lic_info.hex())
        self.cksm=binascii.crc32(self.lic_allinfo+b'sector-aligned').to_bytes(4,'little')
        if cksm_hexstr:
            assert(self.cksm==bytes.fromhex(cksm_hexstr.decode()))

    @staticmethod
    def mk_lic_userinfo(name:bytes,mail:bytes,addr:bytes)->bytes:
        lic_info=zero_pad(name,81)
        lic_info+=zero_pad(mail,61)
        lic_info+=zero_pad(addr,61)
        return lic_info
    @staticmethod
    def mk_lic(name:bytes,mail:bytes,addr:bytes,data1:bytes,data2:bytes)->bytes:
        '''
        struct LicInfo
        {
        char name[81];
        char mailarr[61];
        char homeaddr[61];
        char keydata[32];
        };

        '''
        lic_info=LicInfo.mk_lic_userinfo(name,mail,addr)
        lic_info+=zero_pad(data1,16)
        lic_info+=zero_pad(data2,16)
        '''
        Cksm = binascii.crc32(lic_info+b'sector-aligned')
        print(hex(Cksm))
        '''
        return lic_info
    
    @staticmethod
    def gen_data1()->bytes:
        user_number=0xea6
        enddate=datetime_to_dos_date(str2dt('2028-08-27'))
        startdate=datetime_to_dos_date(str2dt('2024-08-10'))

        data1=b''

        # i_0_1= 0x1100
        i_0_1=random.randint(0,0xffff)
        
        

        OFFSET_DATE=0x4705
    
        # end 要小于0x611Cu 07/09/2024 要大于0x58E9u  08/28/2028
        # *(_WORD *)&name_718264.keydata[4] ^ *(_WORD *)&name_718264.keydata[6] ^ 0x159D; +0x4705
        # i_4_5=0x5544
        i_4_5=random.randint(0,0xffff)
        i_6_7=(enddate-OFFSET_DATE)^0x159d^i_4_5


        # i_9=random.randint(0,0xff)
        i_9=0x99


        
        # i_2_3=0x3322
        i_2_3=random.randint(0,0xffff)

        # start time
        # *(_WORD *)&name_718264.keydata[2] ^ *(_WORD *)&name_718264.keydata[12] ^ 0xEA69;+0x4705
        i_c_d=(startdate-OFFSET_DATE)^i_2_3^0xEA69
        i_c=i_c_d&0xff


        #user number <=3750u 0xea6
        # *(_WORD *)&name_718264.keydata[0xA] ^ *(_WORD *)&name_718264.keydata[2] ^ 0x69C5;
        i_a_b=user_number ^ i_2_3 ^ 0x69C5


        # calc type  
        # 高3位==3;低5位 ==1; ==>0x610x61
        # (name_718264.keydata[12] ^ name_718264.keydata[8] ^ 0xB7) ^0x61
        i_8=i_c^0xB7 ^0x61

        # i_e=random.randint(0,0xff)
        i_e=0xee

        data1+=i_0_1.to_bytes(2,'little')+\
            i_2_3.to_bytes(2,'little')+\
            i_4_5.to_bytes(2,'little')+\
            i_6_7.to_bytes(2,'little')+\
            i_8.to_bytes(1,'little')+\
            i_9.to_bytes(1,'little')+\
            i_a_b.to_bytes(2,'little')+\
            i_c_d.to_bytes(2,'little')+\
            i_e.to_bytes(1,'little')
        
        '''
        # WinHex_v19.8
        unsigned int Random_check_sum_5C3358()
        {
        unsigned int result; // eax
        HANDLE CurrentProcess; // eax

        result = ((unsigned __int8)(lic_info_63EB5C.keydata[0xD] ^ lic_info_63EB5C.keydata[8])
                * (unsigned __int8)(lic_info_63EB5C.keydata[0xB] ^ lic_info_63EB5C.keydata[0xC])
                * ((unsigned __int8)lic_info_63EB5C.keydata[5] + (unsigned int)(unsigned __int8)lic_info_63EB5C.keydata[1])) >> 2;
        if ( (_BYTE)result == lic_info_63EB5C.keydata[0xF] )
            return result;
        if ( Delphi_Random_402EA8(3) == 2 )
            sub_5CC468();
        CurrentProcess = GetCurrentProcess();
        return TerminateProcess(CurrentProcess, 0);
        }
        '''
        i_f=  ((data1[0xD] ^ data1[8])
            * (data1[0xB] ^ data1[0xC])
            * (data1[5] + data1[1])
            ) >> 2
        data1+=(i_f&0xff).to_bytes(1,'little')     

        return data1


    def calc_data2(self)->bytes:
        #name + mail + addr   81+61+61=0xcb
        user_data = sha256(self.userinfo)
        print('AES1:')
        lic_enc = aes_sha256_ctr(PUB_KEY, user_data)
        key2 = sha256(lic_enc+self.data1) 

        print('AES2:')
        ret = aes_sha256_ctr(key2, PRIVATE_KEY)

        return ret[:16]

    def __repr__(self) -> str:
        ret='// X-Ways license file\n\n'
        ret+=f'Name: {self.name.decode()}\n'\
            f'Addr: {self.mail.decode()}\n'\
            f'Addr: {self.addr.decode()}\n'\
            f'Data: {self.data1.hex().upper()}\n'\
            f'Data: {self.data2.hex().upper()}\n'\
            f'Cksm: {self.cksm.hex().upper()}\n'
        return ret
    # def __str__(self) -> str:
    #     return self.__repr__()



def read_lic(user_txt_path:str):
    lines=[]
    with open(user_txt_path,'rb') as f:
        lines=f.readlines()
    infos=[]
    for x in lines:
        if b':' in x:
            temp=x.split(b':')[1].strip()
            infos.append(temp)
    return infos







def check_lic_data2(licpath=r'user.txt'):
    infos=read_lic(licpath)
    lic=LicInfo(*infos)
    print(lic)
    lic_info=lic.lic_allinfo
    print('lic_info:',lic_info.hex())
    
    lic_data1 = lic.data1
    lic_data2 = lic.data2

    lic_info_sha256 = sha256(lic_info[:0xcb])

    
    print('AES1:')
    lic_enc = aes_sha256_ctr(PUB_KEY, lic_info_sha256)
    lic_enc_data1_sha256 = sha256(lic_enc+lic_data1)  

    print('AES2:')
    lic_enc2 = aes_sha256_ctr(lic_enc_data1_sha256, lic_data2)
    '''
    need 725D5C612CCC0FF538E919E4365F3C4900000000000000000000000000000000
    '''
    print('data2 correct?',PRIVATE_KEY==zero_pad(lic_enc2,32))


    # xordata = b''
    # with open(r'code_data.bin', 'rb') as f:
    #     xordata = f.read()
    # print('AES3:')
    # print('[*]target key:',lic_enc2.hex())
    # buf = aes_sha256_ctr(lic_enc2, xordata)


    # with open('dec.bin', 'wb') as f:
    #     f.write(buf)
    




def check_data1(data1:bytes):#=bytes.fromhex('21C99167CC69236A2EB9540CF881EFF6')

    type_15h=((data1[0xc]^data1[8]^0xb7) &0x1f) +0x14
    print('\ncheck_data1:')
    print('[-]type_15h:',type_15h)
    numb_3=(data1[0xc]^data1[8]^0xb7)>>5
    print('[-]numb_3:',numb_3)

    wfatdate=strxor(strxor(data1[4:6],data1[6:8]),b'\x9d\x15')

    i=int.from_bytes(wfatdate,'little')
    enddate=dos_date_to_datetime(i+0x4705)
    print('[-]enddate:',enddate)

    date=strxor(strxor(data1[2:4],data1[12:14]),b'\x69\xea')
    i=int.from_bytes(date,'little')
    date=dos_date_to_datetime(i+0x4705)
    print('[-]startdate:',date)

    number=strxor(strxor(data1[10:12],data1[2:4]),b'\xc5\x69')#max 3750
    print('[-]number:', int.from_bytes(number,'little'))
    sum=  ((data1[0xD] ^ data1[8])
          * (data1[0xB] ^ data1[0xC])
          * (data1[5] + data1[1])
          ) >> 2
    sum&=0xff
    print('[*]sum correct?',sum==data1[0xf])




def kg(name:bytes=b'test',mail:bytes=b'hello@world.com',addr:bytes=b'xxxxxxx'):

    lic=LicInfo(name,mail,addr)

    check_data1(lic.data1)
    print('\n\nlic:\n')
    print(lic)
    pass

if __name__ == '__main__':
    print('[*]only winhex 21.2!')
    
    kg(b'test',b'hello@world.com',b'xxxxxxx')

    # data1=LicInfo.gen_data1()
    # data1=bytes.fromhex('21C99167CC69236A2EB9540CF881EFF6')
    # check_data1( )

    # check_lic_data2('user.txt')
    pass

out:


[*]only winhex 21.2!
AES1:
[-]key: 4defeae49cf72587deadb0e192ee26c2244563bd5b98461f5cdd4595932ab4fd
[+]aeskey: 9b5c7ec628e4e879a2607be48e4c425b9d0717da2275de4d9697a99702c8862d
[-]data: 05dbd8fc480302dd8faf4259b773c7efb8d33bd1404654975ff46efb8339dbf5
[+]enc/dec data: bbf5a31c5d4d8aa52365d9cd3d385428c65daadaa5eeba6d40ccce13a37dd835
AES2:
[-]key: 05298696128c21de4bf83fab3009648b4ee9bb5e2fbb55f065e72b3f3fd9e266
[+]aeskey: 888b5a9827ff73c97c1ef18e5d8db6ede2e97b5b86189c2af553ae908e42699d
[-]data: 725d5c612ccc0ff538e919e4365f3c4900000000000000000000000000000000
[+]enc/dec data: 73d32c4abbc7218f0329be54bd337f7333bf32ef7f6d26cb76540cd7d78f2c88

check_data1:
[-]type_15h: 21
[-]numb_3: 3
[-]enddate: 2028-08-27
[-]startdate: 2024-08-10
[-]number: 3750
[*]sum correct? True


lic:

// X-Ways license file

Name: test
Addr: hello@world.com
Addr: xxxxxxx
Data: 43FF43B693B318BCF99920D12F4EEE61
Data: 73D32C4ABBC7218F0329BE54BD337F73
Cksm: 7BDDE4A7

image-20240810221231336

参考链接

WinHex 20.4 许可算法分析

posted @ 2024-08-10 23:02  DirWangK  阅读(456)  评论(0编辑  收藏  举报