# Write-up Eschaton CTF 2026 ( REV)
# Retro
- Chạy thử chương trình:

- Không thao tác được gì, mở ghidra lên thử.
- Kiểm tra các hàm, ta thấy hàm `FUN_022e`:
- 
- Như vậy chương trình sẽ kiểm tra `DAT_c000` xem có bằng 0 hay 1 hay 2 không để in ra cái gì đấy. Chương trình khi khởi động sẽ mặc định là 0 nên sẽ in ra màn hình trên 
=> dùng hxd fix lại giá trị của `DAT_c000` thử . Ta sẽ sửa ở đây, đổi 0x0 thành 0x1 và 0x2 
- `DAT_c000` = 0x1:
-`DAT_c000` = 0x2 :
# Key1

- Chương trình sẽ nhận 1 username sau đó sẽ gen ra 1 key, ta phải nhập đúng 5 key từ 5 username ngẫu nhiên từ server.
Mở ida, ta có hàm tạo key sau:
```cpp=
__int64 __fastcall proc_a(unsigned __int8 *a1, _BYTE *pass)
{
unsigned __int8 *username; // rbx
__int64 len_user; // r12
_QWORD *v4; // rax
__int64 v5; // r8
_QWORD *v6; // r9
unsigned __int8 *v7; // rax
__int64 v8; // rcx
__int64 v9; // rax
__int64 v10; // r8
_QWORD *v11; // r9
_DWORD *v13; // r11
_WORD *v14; // r10
int passs; // eax
unsigned __int8 *v16; // rax
__int16 v17; // dx
unsigned __int16 v18; // ax
__int16 v19; // si
__int16 v20; // ax
__int16 v21; // dx
__int16 v22; // cx
__int64 v23; // rax
__int64 v24; // [rsp+8h] [rbp-50h]
_WORD *v25; // [rsp+8h] [rbp-50h]
_QWORD *v26; // [rsp+10h] [rbp-48h]
_DWORD *v27; // [rsp+10h] [rbp-48h]
_QWORD *v28; // [rsp+18h] [rbp-40h]
_BYTE v29[8]; // [rsp+20h] [rbp-38h] BYREF
char v30; // [rsp+28h] [rbp-30h] BYREF
int v31; // [rsp+30h] [rbp-28h] BYREF
_WORD v32[18]; // [rsp+34h] [rbp-24h] BYREF
username = a1;
len_user = j_strlen((__int64)a1);
if ( (unsigned __int64)(len_user - 4) <= 12 )
{
v4 = (_QWORD *)_ctype_b_loc();
v5 = *v4;
v6 = v4;
v7 = a1;
while ( 1 )
{
v8 = *v7;
if ( (*(_BYTE *)(v5 + 2 * v8) & 8) == 0 && (_BYTE)v8 != '_' )
break;
if ( ++v7 == &a1[len_user] )
{
v26 = v6;
v24 = v5;
v9 = j_strlen((__int64)pass);
v10 = v24;
v11 = v26;
if ( v9 == 19 && pass[4] == '-' && pass[9] == '-' && pass[14] == '-' )
{
v13 = pass;
v14 = v29;
LABEL_12:
passs = *v13;
LOBYTE(v32[0]) = 0;
v31 = passs;
v16 = (unsigned __int8 *)&v31;
while ( (*(_BYTE *)(v10 + 2LL * *v16 + 1) & 0x10) != 0 )
{
if ( v32 == (_WORD *)++v16 )
{
v25 = v14;
v28 = v11;
v27 = v13;
*v14 = _isoc23_strtoul(&v31, 0, 16);
v14 = v25 + 1;
if ( &v30 != (char *)(v25 + 1) )
{
v11 = v28;
v13 = (_DWORD *)((char *)v27 + 5);
v10 = *v28;
goto LABEL_12;
}
v17 = *a1;
v18 = 31279;
if ( (_BYTE)v17 )
{
do
{
++username;
v18 = v17 + 33 * v18;
v17 = *username;
}
while ( (_BYTE)v17 );
v19 = v18 ^ 0x9C3E;
v20 = (8 * v18) ^ (v18 >> 5) ^ 0xB7A1;
v21 = (v19 + v20) ^ 0xE4D2;
v22 = (v19 + v20) ^ v20 ^ 0x78EC;
}
else
{
v21 = -20533;
v22 = 22269;
v20 = 25864;
v19 = -6639;
}
LOWORD(v31) = v19;
v32[0] = v21;
v32[1] = v22;
HIWORD(v31) = v20;
v23 = 0;
while ( *(_WORD *)&v29[v23 * 2] == v32[v23 - 2] )
{
if ( ++v23 == 4 )
return 1;
}
return 0;
}
}
}
return 0;
}
}
}
return 0;
}
```
Phân tích:
+ Username phải từ 4-16 kí tự.
+ Key phải đúng 19 kí tự mà mỗi 4 kí tự có "-".
+ Có thể thấy chương trình sẽ khởi tạo key từ username được nhập
+ Ta có seed : `v18 = 31279`
```cpp=
do
{
++username;
v18 = v17 + 33 * v18;
v17 = *username;
}
while ( (_BYTE)v17 );
```
- Chương trình sẽ lấy từng kí tự của username nhân `v18` rồi cộng lại, cuối cùng lưu vào `v18`. Sau đó từng phần của key sẽ được tính toán như sau.
- Part 1 :
`v19 = v18 ^ 0x9C3E;`
- Part 2 :
`v20 = (8 * v18) ^ (v18 >> 5) ^ 0xB7A1`
- Part 3 :
`v21 = (v19 + v20) ^ 0xE4D2`
- Part 4 :
`v22 = (v19 + v20) ^ v20 ^ 0x78EC`
Cuối cùng chuyển các part sang mã hex và ghép lại:
`*v14 = _isoc23_strtoul(&v31, 0, 16); `
=> Viết được script sau:
```python=
from pwn import *
def gen_key(username: str) -> str:
v18 = 31279
for c in username:
v18 = (ord(c) + 33 * v18) & 0xFFFF
part1 = (v18 ^ 0x9C3E) & 0xFFFF
part2 = ((v18 * 8) ^ (v18 >> 5) ^ 0xB7A1) & 0xFFFF
part3 = ((part1 + part2) ^ 0xE4D2) & 0xFFFF
part4 = ((part1 + part2) ^ part2 ^ 0x78EC) & 0xFFFF
return f"{part1:04X}-{part2:04X}-{part3:04X}-{part4:04X}"
def main():
context.log_level = "info"
host = "node-2.mcsc.space"
port = 12141
p = remote(host, port)
for i in range(1, 6):
log.info (f" Dang giai bai {i}/5")
p.recvuntil(b"Username: ")
username = p.recvline().strip().decode()
key = gen_key(username)
p.sendlineafter(b"Enter key: ", key.encode())
p.interactive()
if __name__ == "__main__":
main()
```

# Key 2
- tương tự bài trên nhưng bây giờ có thêm hwid. 
- Load vào ida, xem thử.
```cpp=
if ( a1 != 4 )
{
v2 = sub_458470(&unk_5C3A80, "Usage: ");
v3 = sub_458470(v2, *a2);
sub_458470(v3, " <username> <hwid> <key>\n");
sub_458470(&unk_5C3A80, " username: 4-20 alphanumeric characters\n");
sub_458470(&unk_5C3A80, " hwid: 8-character hex string\n");
sub_458470(&unk_5C3A80, " key: A1B2-XXXX-XXXX-XXXX-CCCC format\n");
return 1;
}
sub_405980(Key, a2[3], &v32);
sub_405980(hwid, a2[2], &v31);
sub_405980(&username, a2[1], &v30);
if ( (unsigned __int64)(len_user - 4) <= 16 )
{
v6 = username;
v7 = &username[len_user];
if ( username == &username[len_user] )
{
LABEL_12:
if ( hwid[1] == 8 )
{
v10 = hwid[0];
v11 = 0;
while ( (unsigned int)sub_4C5BE0(*(unsigned __int8 *)(v10 + v11)) )
{
if ( ++v11 == 8 )
{
v12 = sub_4D6710(v10, 0, 16); // chuyen hwid vao day va doi no thanh so
if ( Key[1] == 24
&& *(_BYTE *)(Key[0] + 4LL) == '-'
&& *(_BYTE *)(Key[0] + 9LL) == '-'
&& *(_BYTE *)(Key[0] + 14LL) == '-'
&& *(_BYTE *)(Key[0] + 19LL) == '-' )
{
v13 = (char *)&v42;
sub_4625A0(&v42, Key, 0, 4); // lay 4 ki tu dau ghi vao v42
if ( v43 != (_QWORD *)4 )
{
LABEL_22:
sub_45EB00((__int64 *)&v42);
break;
}
v14 = *v42;
sub_45EB00((__int64 *)&v42);
if ( v14 == 843198785 ) // 4 ki tu dau
{
v15 = 0;
v37[0] = 0xA00000005LL; // cắt chuỗi tại vị trí các offset
v37[1] = 0x140000000FLL;
while ( 1 )
{
sub_4625A0(&v42, Key, *((int *)v37 + v15), 4);// Lay cum XXXX của input
v16 = v42;
v17 = (unsigned __int8 *)v42;
v18 = (unsigned __int8 *)v43 + (_QWORD)v42;
while ( v18 != v17 )
{
v29 = v17;
v19 = sub_4C5BE0(*v17);
v17 = v29 + 1;
if ( !v19 )
goto LABEL_22;
}
if ( v15 == 3 ) // lấy 3 lần XXXX
break;
*(&v35 + v15++) = sub_4D6710(v16, 0, 16);// bien hex thanh so nguyen
sub_45EB00((__int64 *)&v42);
}
v20 = sub_4D6710(v16, 0, 16); // CCCC của người dùng
sub_45EB00((__int64 *)&v42);
v21 = sub_405900((__int64)username, len_user) ^ v12;// Lay seed
v22 = (_QWORD *)sub_406820(8); // xin 8 bytes
*v22 = off_56A4A0; // part2 ( gán địa chỉ hàm ảo)
v42 = v22;
v23 = (_QWORD *)sub_406820(8);
*v23 = off_56A4C8; // part 3
v43 = v23;
v24 = (_QWORD *)sub_406820(8);
*v24 = off_56A4F0; // part4
v44 = v24;
v25 = (_QWORD *)sub_406820(8);
*v25 = off_56A518;
v26 = v25;
v27 = 0;
v45 = v25;
do
{
v28 = (*(__int64 (__fastcall **)(_DWORD *, _QWORD))(*(_QWORD *)(&v42)[v27] + 16LL))((&v42)[v27], v21);// goi ham tai offset +16
*((_WORD *)v37 + v27++) = v28; // ép kiểu các part(XXXX) sang 2 bytes
v21 = v28; // cap nhat seed
}
while ( v27 != 3 );
(*(void (__fastcall **)(_QWORD *, _QWORD))(*v26 + 16LL))(v26, v28);
do
{
if ( *(_QWORD *)v13 )
(*(void (__fastcall **)(_QWORD))(**(_QWORD **)v13 + 8LL))(*(_QWORD *)v13);
v13 += 8;
}
while ( &v46 != v13 );
if ( LOWORD(v37[0]) == v35 && v36 == *(_DWORD *)((char *)v37 + 2) )
{
v34 = HIWORD(v36);
v33 = LOBYTE(v37[0]) | ((BYTE1(v37[0]) | (WORD1(v37[0]) << 8)) << 8);
v5 = ((unsigned __int16)sub_405900((__int64)&v33, 6) ^ 0x52B1) == v20;
goto LABEL_6;
}
}
}
break;
}
}
}
}
else
{
while ( 1 )
{
v8 = *v6;
v9 = sub_4C5AA0();
if ( v8 != 95 && !v9 )
break;
if ( v7 == ++v6 )
goto LABEL_12;
}
}
}
v5 = 0;
LABEL_6:
sub_45EB00((__int64 *)&username);
sub_45EB00(hwid);
sub_45EB00(Key);
if ( !v5 )
{
sub_458470(&unk_5C3BA0, "Invalid!\n");
return 1;
}
sub_458470(&unk_5C3BA0, "Valid!\n");
return 0;
}
```
- Chương trình đã bị stripped, không có các hàm hay gặp nữa, gây khó khăn trong việc hiểu chương trình làm gì.
- Ta có: ` v12 = sub_4D6710(v10, 0, 16);` sẽ chuyển hwid từ hex sang int .
- `sub_4625A0(&v42, Key, 0, 4);` : tách 4 ký tự đầu Key, `v14 == 843198785 ` sẽ là 4 ký tự đầu của key : `843198785` là `A1B2`.
```cpp=
while ( 1 )
{
sub_4625A0(&v42, Key, *((int *)v37 + v15), 4);
...
if ( v15 == 3 )
break;
```
- đoạn while trên sẽ tách 3 phần XXXX từ key.
- ` v21 = sub_405900((__int64)username, len_user) ^ v12;` : đây sẽ là đoạn tính seed để tính toán các part.
- Bên trong hàm `sub_405900`:
```cpp=
_int64 __fastcall sub_405900(__int64 a1, __int64 a2)
{
__int64 v4; // rdi
__int64 result; // rax
char v6; // cl
int v7; // esi
int v8; // esi
if ( !a2 )
return 1316956697;
v4 = 0;
LODWORD(result) = 1316956697;
do
{
v6 = v4;
v7 = *(unsigned __int8 *)(a1 + v4++); // Lay tung ki tu tu username
v8 = __ROL4__(result ^ (v7 << (8 * (v6 & 3))), 5);
result = (unsigned int)(v8 + 1016194743) ^ __ROR4__(v8 + 1016194743, 11);
}
while ( a2 != v4 );
return result;
}
```
- Giải thích : lấy từng kí tự của username , dịch trái ( 8 * (index & 3)) rồi XOR với result ( result ban đầu là 1316956697) rồi xoay đi 5 bit rồi lưu vào v8
- Tiếp theo result sẽ bằng `( v8+ 1016194743)` rồi XOR với `v8 + 1016194743` xoay phải đi 11 bit. Kết quả result phải là trong khoảng số unsigned int.
- Cuối cùng seed sẽ bằng result XOR với v12( hwid đã chuyển thành int ) 
Tiếp tục, ta có đoạn sau :
```cpp=
v28 = (*(__int64 (__fastcall **)(_DWORD *, _QWORD))(*(_QWORD *)(&v42)[v27] + 16LL))((&v42)[v27], v21);// goi ham tai offset +16
*((_WORD *)v37 + v27++) = v28;
v21 = v28;
```
- Gọi hàm ảo tại offset +16 của đối tượng hiện tại rồi lưu kết quả tính toán vào mảng `v37` cuối cùng cập nhật seed mới bằng kết quả vừa tính ( là các part luôn ).
- Chương trình được lặp lại 3 lần tương đương với part 2, part 3, part 4 của key.
**Các đoạn tính toán các part:**
Part 2 :
- 
- Lấy seed xoay trái 7 bit rồi XOR với 0x8D2F5A1C;
Part 3 :
- Lấy 16 bit cao của part2 rồi XOR với `0x1FA9` kết hợp với part2 XOR `0x6B3Eu` bị dịch trái 16 bit ( đây là phép SWAP (đảo vị trí). 16 bit cao mới được tạo từ 16 bit thấp cũ, và ngược lại. )
Part 4 :

- xoay phải part3 đi 13 bit rồi + 1204305198 rồi ép kiểu thành số dương 32 bit
=> Cuối cùng các part trên sẽ được ép kiểu thành 16 bit để hiển thị lên màn hình như phía trên đã chú thích.
### Kiểm tra kết quả
- `if ( LOWORD(v37[0]) == v35 && v36 == *(_DWORD *)((char *)v37 + 2) )` : So sánh 3 part của mình với giá trị của chương trình đưa ra.
`v33 = LOBYTE(v37[0]) | ((BYTE1(v37[0]) | (WORD1(v37[0]) << 8)) << 8);` và
`v5 = ((unsigned __int16)sub_405900(&v33, 6) ^ 0x52B1) == v20;` : gộp 3 part của mình thành 1 dữ liệu 6 bytes, gọi lại hàm `sub_4059000` rồi XOR với `0x52B1` và so sánh kết quả cuối cùng với cụm CCCC (biến v20) trong Key của người dùng.
Tóm tắt luồng :
- nhận username và hwid.
- Seed = Hash(Username) ^ Int(HWID)
- part1 = A1B2
- Part2 = Func1(Seed)
- Part3 = Func2(Part2)
- Part4 = Funct(Part3)
- ghép part 2, 3, 4 vào với nhau thành buffer
- Part5 = Hash(Buffer) ^ 0x52B1
- Chuyển các giá trị Part 2, 3, 4, 5 thành hex.
- Ghép lại A1B2-Part2-Part3-Part4-Part5
- Nếu đúng in ra valid, ngược lại invalid
### Script
```python=
import sys
from pwn import *
import re
HOST = 'node-3.mcsc.space'
PORT = 35435
# --- Các hàm hỗ trợ Bitwise ---
def rol(val, shift, width=32):
shift %= width
return ((val << shift) & (2**width - 1)) | (val >> (width - shift))
def ror(val, shift, width=32):
shift %= width
return (val >> shift) | ((val << (width - shift)) & (2**width - 1))
def sub_405900(data_bytes):
seed = 1316956697
CONST = 1016194743
v4 = 0
for char in data_bytes:
shift = (v4 & 3) * 8
temp = (char << shift) ^ seed
v8 = rol(temp & 0xFFFFFFFF, 5)
temp_sum = (v8 + CONST) & 0xFFFFFFFF
seed = temp_sum ^ ror(temp_sum, 11)
v4 += 1
return seed & 0xFFFFFFFF
def tao_key(username, hwid_hex):
user_seed = sub_405900(username.encode('ascii'))
hwid_int = int(hwid_hex, 16)
cur_seed = user_seed ^ hwid_int
# ---- --- part2-------
cur_seed = (rol(cur_seed, 7) ^ 0x8D2F5A1C) & 0xFFFFFFFF
part2 = cur_seed & 0xFFFF
#------------part3---------
old_low = cur_seed & 0xFFFF
old_high = (cur_seed >> 16) & 0xFFFF
new_high = old_low ^ 0x6B3E
new_low = old_high ^ 0x1FA9
cur_seed = (new_high << 16) | new_low
part3 = cur_seed & 0xFFFF
#---------part4 ------------
cur_seed = (ror(cur_seed, 13) + 1204305198) & 0xFFFFFFFF
part4 = cur_seed & 0xFFFF
# ------------ Tính CCCC --------------
buffer = bytearray()
buffer.extend(part2.to_bytes(2, 'little'))
buffer.extend(part3.to_bytes(2, 'little'))
buffer.extend(part4.to_bytes(2, 'little'))
checksum_hash = sub_405900(buffer)
checksum = (checksum_hash ^ 0x52B1) & 0xFFFF
return f"A1B2-{part2:04X}-{part3:04X}-{part4:04X}-{checksum:04X}"
def solve():
context.log_level = 'info'
r = remote(HOST, PORT)
# Vòng lặp giải 5 vòng
for i in range(5):
print(f"\n[*] === Round {i+1} ===")
# Đọc đến khi server yêu cầu nhập key
output = r.recvuntil(b'Enter key: ', drop=False).decode()
# Regex lấy Username và HWID
# Username có thể chứa ký tự đặc biệt, nên dùng \S+
username_match = re.search(r'Username:\s*(\S+)', output)
hwid_match = re.search(r'HWID:\s*([0-9a-fA-F]+)', output)
if username_match and hwid_match:
user = username_match.group(1).strip()
hwid = hwid_match.group(1).strip()
# Tính Key
key = tao_key(user, hwid)
# Gửi Key
r.sendline(key.encode())
# Đọc kết quả
response = r.recvline().decode()
print(f"[Server]: {response.strip()}")
r.interactive()
if __name__ == "__main__":
solve()
```

# Textmorph

- Có vẻ chương trình muốn ta nhập gì đó để có được flag.
- Kiểm tra thử thì thấy nó bị pack bằng PyInstaller. 
Sau khi unpack bằng lệnh `python3 pyinstxtractor.py textmorph`, ta được 
- Thấy file textmorph_embedded.pyc.
- Thử strings `strings -n 10 textmorph_embedded.pyc
` ta có mấy các fake flag : 


và 1 đống gì đó giống base64.
- Chú ý đoạn `eNrc` , đây là header đặc trưng của zlib file, viết 1 script python để extract được đoạn base64 này.
```python=
import re
import base64
with open("textmorph_embedded.pyc", "rb") as f:
content = f.read()
match = re.search(rb'([A-Za-z0-9+/=]{100,})', content)
base64_bytes = match.group(1)
file_data = base64.b64decode(base64_bytes)
with open("extracted_data.bin", "wb") as f_out:
f_out.write(file_data)
```
- script để giải nén file zlib trên.
```python=
import zlib
data = open("extracted_data.bin","rb").read()
out = zlib.decompress(data)
with open("output_file", "wb") as f_out:
f_out.write(out)
```
- Nhận được 1 file gif chứa flag .

# key3


- Chương trình được viết bằng ngôn ngữ rust và bị stripped tương tự như bài key2.
- Chương trình lần này bắt ta tạo key từ username, hwid, timestamp, tier.
- Mở thử trong ida, ta tìm được hàm chính sau:
```cpp=
int64 sub_2480()
{
_QWORD *v0; // rbx
_BYTE *v1; // rcx
unsigned __int64 v2; // rsi
bool v3; // cf
int v4; // eax
__int64 v5; // rax
unsigned __int64 v6; // r15
unsigned int v7; // edx
_BYTE *v8; // rcx
unsigned __int64 v9; // rdx
__int64 v10; // rax
int v11; // edx
__int64 v12; // rdi
unsigned int v13; // edx
__int64 v14; // r15
__int64 v15; // rdx
unsigned __int8 v16; // si
unsigned int v17; // r13d
unsigned __int8 v18; // r13
unsigned __int8 *v19; // rsi
__int64 v20; // r14
__int64 v21; // rbx
unsigned __int8 *v22; // rdx
int v23; // edi
int v24; // r8d
int v25; // r10d
int v26; // r9d
void *v27; // r12
size_t v28; // rbp
int v29; // edx
_BYTE *v30; // rax
_BOOL8 v31; // rdx
__int64 v32; // rcx
_BYTE *v33; // rax
__int64 v34; // rdx
unsigned int v35; // r14d
unsigned int v36; // edi
unsigned int v37; // esi
_BYTE *v38; // rax
_BOOL8 v39; // rdx
__int64 v40; // rcx
_BYTE *v41; // rax
__int64 v42; // rdx
__int64 v43; // r12
unsigned int v44; // edi
unsigned int v45; // esi
_BYTE *v46; // rax
_BOOL8 v47; // rdx
__int64 v48; // rcx
_BYTE *v49; // rax
__int64 v50; // rdx
unsigned int v51; // ebx
unsigned int v52; // edi
unsigned int v53; // esi
_BYTE *v54; // rax
_BOOL8 v55; // rdx
__int64 v56; // rcx
_BYTE *v57; // rax
__int64 v58; // rdx
__int64 v59; // rbp
unsigned int v60; // edi
unsigned int v61; // esi
_DWORD *v62; // rcx
bool v63; // al
char v64; // cl
__int64 v65; // rsi
char v66; // al
unsigned int v67; // r8d
size_t v68; // rdx
size_t v69; // rdx
unsigned __int64 v70; // rax
char *v71; // rcx
_BYTE *v72; // rdi
size_t v73; // rdx
size_t v74; // rax
char *v75; // rsi
size_t v76; // rdx
size_t v77; // rax
unsigned __int8 v78; // al
size_t v79; // r15
int v80; // r15d
unsigned __int64 v81; // r13
unsigned __int32 v82; // r13d
unsigned __int32 v83; // r15d
int v84; // eax
unsigned __int32 v85; // r13d
int v86; // ecx
int v87; // r13d
int v88; // esi
int v89; // edi
unsigned __int32 v90; // r15d
int v91; // edx
int v92; // r15d
int v93; // ecx
int v94; // edi
int v95; // r8d
int v96; // ecx
int v97; // esi
int v98; // r9d
int v99; // edx
int v100; // edi
int v101; // r8d
int v102; // r10d
int v103; // esi
int v104; // r10d
int v105; // edi
int v106; // r9d
int v107; // ecx
int v108; // edx
int v109; // ecx
unsigned int v110; // r15d
int v111; // r8d
int v112; // esi
int v113; // r13d
int v114; // edi
__int64 v115; // rax
int v116; // edx
unsigned int v117; // esi
__int64 v118; // r15
__int64 v119; // rbp
__int64 v120; // r12
size_t v121; // rdx
unsigned __int64 v122; // r13
__int64 v123; // r14
unsigned __int64 v124; // rbp
size_t v125; // r12
unsigned __int64 v126; // r14
unsigned __int64 v127; // r13
_QWORD *v128; // rbx
__int64 v129; // r14
_QWORD *v130; // r15
__int64 v131; // rsi
__int64 result; // rax
__int64 v133; // rsi
void *v134; // rdi
size_t n; // [rsp+0h] [rbp-238h]
size_t nb; // [rsp+0h] [rbp-238h]
size_t na; // [rsp+0h] [rbp-238h]
char *nc; // [rsp+0h] [rbp-238h]
unsigned __int32 nd; // [rsp+0h] [rbp-238h]
unsigned __int8 *src; // [rsp+8h] [rbp-230h]
char *srca; // [rsp+8h] [rbp-230h]
unsigned __int32 srcb; // [rsp+8h] [rbp-230h]
__int128 v143; // [rsp+10h] [rbp-228h] BYREF
__m256i v144; // [rsp+20h] [rbp-218h] BYREF
__int128 v145; // [rsp+40h] [rbp-1F8h]
__int128 v146; // [rsp+50h] [rbp-1E8h]
__int128 v147; // [rsp+60h] [rbp-1D8h]
unsigned __int64 v148; // [rsp+70h] [rbp-1C8h]
unsigned __int8 v149; // [rsp+78h] [rbp-1C0h]
int v150; // [rsp+79h] [rbp-1BFh]
__int16 v151; // [rsp+7Dh] [rbp-1BBh]
char v152; // [rsp+7Fh] [rbp-1B9h]
size_t v153; // [rsp+80h] [rbp-1B8h]
void *v154; // [rsp+88h] [rbp-1B0h]
__int128 v155; // [rsp+90h] [rbp-1A8h] BYREF
__int128 v156; // [rsp+A0h] [rbp-198h]
_BYTE dest[72]; // [rsp+B0h] [rbp-188h] BYREF
char v158; // [rsp+F8h] [rbp-140h]
int v159; // [rsp+F9h] [rbp-13Fh]
__int16 v160; // [rsp+FDh] [rbp-13Bh]
char v161; // [rsp+FFh] [rbp-139h]
__int64 v162; // [rsp+108h] [rbp-130h]
__int64 v163; // [rsp+110h] [rbp-128h] BYREF
_QWORD *v164; // [rsp+118h] [rbp-120h]
__int64 v165; // [rsp+120h] [rbp-118h]
_QWORD *v166; // [rsp+128h] [rbp-110h]
__int64 v167; // [rsp+130h] [rbp-108h] BYREF
_QWORD *v168; // [rsp+138h] [rbp-100h]
__int64 v169; // [rsp+140h] [rbp-F8h]
__int64 v170; // [rsp+148h] [rbp-F0h] BYREF
__int64 v171; // [rsp+150h] [rbp-E8h]
__int64 v172; // [rsp+158h] [rbp-E0h]
_OWORD v173[3]; // [rsp+160h] [rbp-D8h] BYREF
__int64 v174; // [rsp+190h] [rbp-A8h]
unsigned __int64 v175; // [rsp+198h] [rbp-A0h]
_QWORD v176[7]; // [rsp+1A0h] [rbp-98h] BYREF
char v177; // [rsp+1D8h] [rbp-60h]
__int16 v178; // [rsp+1E0h] [rbp-58h]
_BYTE v179[80]; // [rsp+1E8h] [rbp-50h] BYREF
sub_22B30(v179);
sub_3570(&v163, v179, &off_659E8);
if ( v165 != 6 ) // so luong tham so
{
if ( !v165 )
sub_1F15(0, 0, &off_65A20);
*(_QWORD *)&v155 = v164;
*((_QWORD *)&v155 + 1) = sub_2430;
*(_QWORD *)&v143 = &off_65A38;
*((_QWORD *)&v143 + 1) = 2;
v144.m256i_i64[0] = (__int64)&v155;
*(_OWORD *)&v144.m256i_u64[1] = 1u;
sub_24820(&v143);
*(_QWORD *)&v143 = &off_65A58;
*((_QWORD *)&v143 + 1) = 1;
v144.m256i_i64[0] = 8;
*(_OWORD *)&v144.m256i_u64[1] = 0;
sub_24820(&v143);
*(_QWORD *)&v143 = &off_65A68;
*((_QWORD *)&v143 + 1) = 1;
v144.m256i_i64[0] = 8;
*(_OWORD *)&v144.m256i_u64[1] = 0;
sub_24820(&v143);
*(_QWORD *)&v143 = &off_65A78;
*((_QWORD *)&v143 + 1) = 1;
v144.m256i_i64[0] = 8;
*(_OWORD *)&v144.m256i_u64[1] = 0;
sub_24820(&v143);
*(_QWORD *)&v143 = &off_65A88;
*((_QWORD *)&v143 + 1) = 1;
v144.m256i_i64[0] = 8;
*(_OWORD *)&v144.m256i_u64[1] = 0;
sub_24820(&v143);
*(_QWORD *)&v143 = &off_65A98;
*((_QWORD *)&v143 + 1) = 1;
v144.m256i_i64[0] = 8;
*(_OWORD *)&v144.m256i_u64[1] = 0;
sub_24820(&v143);
sub_26FD0(1);
}
v0 = v164;
sub_41B80(&v170, v164[7], v164[8]);
v1 = (_BYTE *)v0[10]; // timestamp
v2 = v0[11];
if ( v2 == 1 )
{
v4 = (unsigned __int8)*v1;
if ( v4 == 43 )
goto LABEL_132;
v2 = 1;
if ( v4 == 45 )
goto LABEL_132;
goto LABEL_11;
}
if ( !v2 )
goto LABEL_132;
if ( *v1 != 43 )
{
if ( v2 >= 0x11 )
goto LABEL_22;
LABEL_11:
v5 = 0;
v6 = 0; // timestamp
while ( 1 )
{
v7 = (unsigned __int8)v1[v5] - 48;
if ( v7 > 9 )
goto LABEL_132;
v6 = v7 + 10 * v6; // Chuyển đổi timestamp thành số nguyên.
if ( v2 == ++v5 )
goto LABEL_14;
}
}
++v1;
v3 = v2-- < 0x12;
if ( v3 )
goto LABEL_11;
LABEL_22:
v12 = 0;
v6 = 0;
while ( v2 != v12 )
{
v13 = (unsigned __int8)v1[v12] - 48;
if ( v13 <= 9 && is_mul_ok(0xAu, v6) )
{
v14 = 10 * v6;
++v12;
v3 = __CFADD__(v13, v14);
v6 = v13 + v14;
if ( !v3 )
continue;
}
goto LABEL_132;
}
LABEL_14:
v8 = (_BYTE *)v0[13]; // lay chuoi tier
v9 = v0[14]; // độ dài tier
if ( v9 == 1 )
{
v11 = (unsigned __int8)*v8;
if ( v11 == 43 )
goto LABEL_132;
v10 = 1;
if ( v11 == 45 )
goto LABEL_132;
goto LABEL_29;
}
if ( !v9 )
goto LABEL_132;
if ( *v8 != 43 )
{
v10 = 2;
if ( v9 >= 3 )
goto LABEL_85;
LABEL_29:
v15 = 0;
v16 = 0;
while ( 1 )
{
v17 = (unsigned __int8)v8[v15] - 48;
if ( v17 > 9 )
goto LABEL_132;
v18 = 10 * v16 + v17; // chuyen tier thanh so
++v15;
v16 = v18;
if ( v10 == v15 )
goto LABEL_32;
}
}
++v8;
v10 = v9 - 1;
v3 = v9-- < 4;
if ( v3 )
goto LABEL_29;
LABEL_85:
v65 = 0;
v18 = 0;
while ( v9 != v65 )
{
v66 = 10 * v18;
v67 = (unsigned __int8)v8[v65] - 48;
if ( v67 <= 9 && is_mul_ok(0xAu, v18) )
{
++v65;
v18 = v67 + v66;
if ( !__CFADD__((_BYTE)v67, v66) )
continue;
}
goto LABEL_132;
}
LABEL_32:
n = v0[5];
if ( n - 33 < 0xFFFFFFFFFFFFFFE3LL )
goto LABEL_132;
v19 = (unsigned __int8 *)v0[4]; // trỏ tới chuỗi username
v20 = v0[16];
v21 = v0[17];
v22 = &v19[n];
src = v19; // src chứa username
while ( v19 != v22 )
{
v23 = *v19;
if ( (v23 & 0x80u) == 0 )
{
++v19;
}
else
{
v24 = v23 & 0x1F;
v25 = v19[1] & 0x3F;
if ( (unsigned __int8)v23 <= 0xDFu )
{
v19 += 2;
v23 = v25 | (v24 << 6);
}
else
{
v26 = (v25 << 6) | v19[2] & 0x3F;
if ( (unsigned __int8)v23 < 0xF0u )
{
v19 += 3;
v23 = (v24 << 12) | v26;
}
else
{
v23 = ((v23 & 7) << 18) | (v26 << 6) | v19[3] & 0x3F;
if ( v23 == 1114112 )
break;
v19 += 4;
}
}
}
if ( (unsigned int)(v23 - 32) >= 0x5F )
goto LABEL_132;
}
if ( v172 != 16 )
goto LABEL_132;
LODWORD(v173[0]) = 3;
*(_QWORD *)&v143 = v171;
*((_QWORD *)&v143 + 1) = 16;
*(_OWORD *)v144.m256i_i8 = 2u;
v144.m256i_i64[2] = (__int64)v173;
sub_3A10(&v155, &v143, &off_65AD8);
if ( LODWORD(v173[0]) != 3 )
{
v133 = v155;
if ( (_QWORD)v155 )
{
v134 = (void *)*((_QWORD *)&v155 + 1);
LABEL_131:
sub_3CE0(v134, v133, 1);
}
LABEL_132:
*(_QWORD *)&v143 = &off_65A00;
*((_QWORD *)&v143 + 1) = 1;
v144.m256i_i64[0] = 8;
*(_OWORD *)&v144.m256i_u64[1] = 0;
sub_24730(&v143);
sub_26FD0(1);
}
if ( __OFSUB__(-(__int64)v155, 1) )
goto LABEL_132;
v27 = (void *)*((_QWORD *)&v155 + 1);
v162 = v155;
if ( (unsigned __int8)(v18 - 4) < 0xFDu )
goto LABEL_129;
v28 = v156;
*(_QWORD *)&v173[0] = sub_27350(); // lấy hwid từ input
DWORD2(v173[0]) = v29;
sub_27360(&v143, v173, 0, 0); // hàm chuyển dổi
if ( (_DWORD)v143 == 1 )
{
*(_QWORD *)&v155 = *((_QWORD *)&v143 + 1);
DWORD2(v155) = v144.m256i_i32[0];
sub_2120("called `Result::unwrap()` on an `Err` valueSystemTimeError", 43, &v155, &unk_65990, &off_659D0);
}
v153 = v28;
if ( *((_QWORD *)&v143 + 1) + 86400LL < v6 // kiem tra thoi gian ( sai lệch không quá 24h)
|| v21 != 46
|| *((_QWORD *)&v143 + 1) - 86400LL > v6 && *((_QWORD *)&v143 + 1) >= 0x15181u )
{
goto LABEL_129;
}
v154 = v27;
v176[0] = 0;
v176[1] = 46;
v176[2] = v20;
v176[3] = 46;
v176[4] = 0;
v176[5] = 46;
v176[6] = 0x2D0000002DLL;
v177 = 1;
v178 = 1;
sub_3890(&v167, v176, &off_659E8);
if ( v169 != 6
|| v168[1] != 5
|| *(_DWORD *)*v168 ^ 0x4949474B | *(unsigned __int8 *)(*v168 + 4LL) ^ 0x49// phan 1 KGIII
|| v168[3] != 8 )
{
goto LABEL_126;
}
v30 = (_BYTE *)v168[2]; // chứa part 2
v31 = *v30 == 43;
v32 = 8 - v31;
v33 = &v30[v31];
v34 = 0;
v35 = 0; // phan 2
do
{
v36 = (unsigned __int8)v33[v34];
v37 = v36 - 48;
if ( v36 >= 0x3A )
v37 = ((v36 - 65) & 0xFFFFFFDF) + 10;
if ( v37 > 0xF )
goto LABEL_126;
v35 = v37 | (16 * v35); // Hex String to Integer
++v34;
}
while ( v32 != v34 );
if ( v168[5] != 8 ) // độ dài part 3
goto LABEL_126;
v38 = (_BYTE *)v168[4]; // chứa part 3
v39 = *v38 == 43;
v40 = 8 - v39;
v41 = &v38[v39];
v42 = 0;
LODWORD(v43) = 0; // biến lưu giá trị part 3
do
{
v44 = (unsigned __int8)v41[v42];
v45 = v44 - 48;
if ( v44 >= 0x3A )
v45 = ((v44 - 65) & 0xFFFFFFDF) + 10;
if ( v45 > 0xF )
goto LABEL_126;
v43 = v45 | (16 * (_DWORD)v43);
++v42;
}
while ( v40 != v42 );
if ( v168[7] != 8 ) // độ dài part 4
goto LABEL_126;
v46 = (_BYTE *)v168[6];
v47 = *v46 == 43;
v48 = 8 - v47;
v49 = &v46[v47];
v50 = 0;
v51 = 0; // part 4
do
{
v52 = (unsigned __int8)v49[v50];
v53 = v52 - 48;
if ( v52 >= 0x3A )
v53 = ((v52 - 65) & 0xFFFFFFDF) + 10;
if ( v53 > 0xF )
goto LABEL_126;
v51 = v53 | (16 * v51);
++v50;
}
while ( v48 != v50 );
if ( v168[9] != 8 ) // độ dài part 5
goto LABEL_126;
v54 = (_BYTE *)v168[8];
v55 = *v54 == 43;
v56 = 8 - v55;
v57 = &v54[v55];
v58 = 0;
LODWORD(v59) = 0; // part 5
do
{
v60 = (unsigned __int8)v57[v58];
v61 = v60 - 48;
if ( v60 >= 0x3A )
v61 = ((v60 - 65) & 0xFFFFFFDF) + 10;
if ( v61 > 0xF )
goto LABEL_126;
v59 = v61 | (16 * (_DWORD)v59);
++v58;
}
while ( v56 != v58 );
if ( v168[11] != 4 )
goto LABEL_126;
v62 = (_DWORD *)v168[10]; // phan cuoi cua key
if ( *v62 == 1515082306 ) // tier 1 bronze ( BRNZ)
{
v64 = 1;
}
else if ( *v62 == 1381387347 ) // // tier 2 sliver (slvr)
{
v64 = 2;
}
else
{
v63 = *v62 == 1145851719; // tier 3 gold
v64 = 3;
if ( !v63 )
goto LABEL_126;
}
if ( v64 != v18 )
{
LABEL_126:
if ( v167 )
sub_3CE0(v168, 16 * v167, 8);
v27 = v154;
LABEL_129:
v133 = v162;
if ( !v162 )
goto LABEL_132;
v134 = v27;
goto LABEL_131;
}
v166 = v168;
v158 = 0;
v155 = xmmword_4F130;
v156 = xmmword_4F140;
memset(dest, 0, sizeof(dest));
v68 = n;
if ( n >= 0x40 )
{
sub_4190(&v155, src, 0); // đưa username vào trước
v68 = n;
}
memcpy(&dest[8], src, v68); // copy username vao dest (buffer)
v158 = n;
v69 = v153;
if ( v153 >= 64 - n )
{
v71 = (char *)v154;
if ( n )
{
srca = (char *)v154 + 64 - n;
v72 = &dest[n + 8];
v73 = 64 - n;
nb = v153 - (64 - n);
memcpy(v72, v154, v73);
++*(_QWORD *)dest;
sub_4190(&v155, &dest[8], 1);
v71 = srca;
v69 = nb;
}
v74 = v69 & 0x3F;
v75 = &v71[v69 & 0xFFFFFFFFFFFFFFC0LL];
na = v74;
if ( v69 >= 0x40 )
{
v76 = v69 >> 6;
*(_QWORD *)dest += v76;
sub_4190(&v155, v71, v76);
v74 = na;
}
memcpy(&dest[8], v75, v74);
v70 = na;
}
else
{
memcpy(&dest[n + 8], v154, v153);
v70 = v153 + n;
}
v158 = v70;
*(_QWORD *)&v143 = v6;
if ( v70 >= 0x38 )
{
nc = (char *)&v143 + 64 - v70;
v79 = v70 - 56;
memcpy(&dest[v70 + 8], &v143, 64 - v70);
++*(_QWORD *)dest;
sub_4190(&v155, &dest[8], 1);
memcpy(&dest[8], nc, v79);
v77 = v79;
goto LABEL_106;
}
*(_QWORD *)&dest[v70 + 8] = v6; // copy timestamp vao ngay sau username
v77 = v70 + 8;
v158 = v77;
if ( v77 != 63 )
{
LABEL_106:
dest[v77 + 8] = v18; // chuyển tier vào buffer
v78 = v77 + 1;
goto LABEL_107;
}
dest[71] = v18;
++*(_QWORD *)dest;
sub_4190(&v155, &dest[8], 1);
v78 = 0;
LABEL_107:
v158 = v78;
v148 = *(_QWORD *)&dest[64];
v149 = v78;
v150 = v159;
v151 = v160;
v152 = v161;
*(_OWORD *)&v144.m256i_u64[2] = *(_OWORD *)dest;
v147 = *(_OWORD *)&dest[48];
v146 = *(_OWORD *)&dest[32];
v145 = *(_OWORD *)&dest[16];
*(_OWORD *)v144.m256i_i8 = v156;
v143 = v155;
v80 = v78;
v81 = _byteswap_uint64((*(_QWORD *)dest << 9) | (8 * (unsigned int)v78));
v144.m256i_i8[v78 + 24] = 0x80;
if ( v78 == 63 || (memset((char *)&v144.m256i_u64[3] + v78 + 1, 0, v78 ^ 0x3FLL), (v80 ^ 0x38u) <= 7) )
{
sub_4190(&v143, &v144.m256i_u64[3], 1);
memset(v173, 0, sizeof(v173));
v174 = 0;
v175 = v81;
sub_4190(&v143, v173, 1);
}
else
{
v148 = v81;
sub_4190(&v143, &v144.m256i_u64[3], 1);
}
srcb = _byteswap_ulong(v143); //h0
v82 = _byteswap_ulong(DWORD1(v143)); // h1
nd = _byteswap_ulong(DWORD2(v143)); // h2
v83 = _byteswap_ulong(HIDWORD(v143)); // h3
v84 = sub_3F00(v154, v153); // mã hóa crc32
v85 = (v84 ^ srcb) + v82;
v86 = __ROL4__(v85, 25);
v87 = nd ^ __ROL4__(v85, 4);
v88 = __ROL4__(v84, 3);
v89 = v88 ^ v87 ^ 0x5F8C2E7A;
v90 = v89 + (v84 ^ srcb ^ (v83 - (v87 ^ 0x5F8C2E7A)));
v91 = __ROL4__(v90, 25);
v92 = v84 ^ srcb ^ __ROL4__(v90, 4);
v93 = v89 ^ (v86 - (v92 ^ 0x5F8C2E7A));
v94 = __ROL4__(v84, 6);
v95 = v94 ^ v92 ^ 0x5F8C2E7A;
v96 = v95 + v93;
v97 = __ROL4__(v96, 4) ^ v87 ^ v88;
v98 = v97 ^ __ROL4__(v84, 9);
v99 = v98 + (v95 ^ (v91 - v97));
v100 = __ROL4__(v99, 4) ^ v92 ^ v94;
v101 = v100 ^ __ROL4__(v84, 12);
v102 = v101 + (v98 ^ (__ROL4__(v96, 25) - v100));
v103 = __ROL4__(v102, 25);
v104 = v98 ^ __ROL4__(v102, 4);
v105 = __ROL4__(v84, 15);
v106 = v105 ^ v104 ^ 0x5F8C2E7A;
v107 = v106 + (v101 ^ (__ROL4__(v99, 25) - (v104 ^ 0x5F8C2E7A)));
v108 = __ROL4__(v107, 25);
v109 = v101 ^ __ROL4__(v107, 4);
v110 = __ROL4__(v84, 18);
v111 = v110 ^ v109 ^ 0x5F8C2E7A;
v112 = v111 + (v106 ^ (v103 - (v109 ^ 0x5F8C2E7A)));
v113 = __ROL4__(v112, 25);
v114 = __ROL4__(v112, 4) ^ v104 ^ v105;
v115 = (unsigned int)v114 ^ __ROL4__(v84, 21);
v116 = v115 + (v111 ^ (v108 - v114));
v117 = __ROL4__(v116, 25);
v118 = __ROL4__(v116, 4) ^ v109 ^ v110;
v119 = v59 << 32;
v120 = v43 << 32;
v121 = v35;
v122 = (unsigned __int64)((unsigned int)v115 ^ (v113 - (_DWORD)v118)) << 32;
if ( v167 )
{
v153 = v35;
v123 = v115;
sub_3CE0(v166, 16 * v167, 8);
v121 = v153;
v115 = v123;
}
v124 = v51 | (unsigned __int64)v119;
v125 = v121 | v120; // ghep cac phan da tinh toan
v126 = v115 | ((unsigned __int64)v117 << 32);
v127 = v118 | v122;
if ( v162 )
sub_3CE0(v154, v162, 1);
if ( v127 ^ v125 | v126 ^ v124 )
goto LABEL_132;
*(_QWORD *)&v143 = &off_65A10;
*((_QWORD *)&v143 + 1) = 1;
v144.m256i_i64[0] = 8;
*(_OWORD *)&v144.m256i_u64[1] = 0;
sub_24730(&v143);
if ( v170 )
sub_3CE0(v171, v170, 1);
v128 = v164;
v129 = v165;
if ( v165 )
{
v130 = v164 + 1;
do
{
v131 = *(v130 - 1);
if ( v131 )
sub_3CE0(*v130, v131, 1);
v130 += 3;
--v129;
}
while ( v129 );
}
result = v163;
if ( v163 )
return sub_3CE0(v128, 24 * v163, 8);
return result;
}
```
## Các đoạn xử lí dữ liệu:
+ Username giữ nguyên.
+ hwid được chuyển sang số int ( vd: ABCD => 0xAB, 0xCD).
+ Timestamp được truyền theo little edian.
+ Tier thành 1 bytes số nguyên, ( vd: 1 => 0x01).
=> nhét vào 1 buffer.
## Mã hóa
- Ta có hàm hash sha-256 sau: ` sub_4190(&v155, src, 0);`( nhận biết qua các đoạn như `sha256rnds2`, `sha256msg1`) ở đây dữ liệu được đưa vào là buffer chứa `username + hwid (bytes) + timestamp(little edian) + tier` như đã chú thích bên trên.
<details>
<summary>sub_4190(sha-256)</summary>
_int64 __fastcall sub_4190(__m128i *a1, const __m128i *a2, __int64 a3)
{
__int64 result; // rax
__int64 v4; // rbx
__m128i v5; // xmm0
__m128i v6; // xmm3
__m128i v8; // xmm3
const __m128i *v9; // rdx
__m128i si128; // xmm4
__m128i v85; // xmm0
__m128i v86; // xmm1
result = (unsigned __int8)byte_69000;
if ( byte_69000 != 1 )
{
if ( (unsigned __int8)byte_69000 != 255 )
return sub_45F0(a1, a2, a3);
v4 = a3;
result = sub_530();
a3 = v4;
if ( !(_BYTE)result )
return sub_45F0(a1, a2, a3);
}
v5 = _mm_shuffle_epi32(_mm_loadu_si128(a1), 177);
v6 = _mm_shuffle_epi32(_mm_loadu_si128(a1 + 1), 27);
_XMM7 = _mm_alignr_epi8(v5, v6, 8);
v8 = _mm_blend_epi16(v6, v5, 240);
if ( a3 )
{
v9 = &a2[4 * a3];
si128 = _mm_load_si128((const __m128i *)&xmmword_4EC60);
_XMM14 = v8;
_XMM2 = _XMM7;
do
{
_XMM13 = _mm_shuffle_epi8(_mm_loadu_si128(a2), si128);
__asm { sha256rnds2 xmm14, xmm7, xmm0 }
_XMM6 = _mm_shuffle_epi8(_mm_loadu_si128(a2 + 1), si128);
__asm { sha256rnds2 xmm2, xmm14, xmm0 }
__asm { sha256rnds2 xmm14, xmm2, xmm0 }
_XMM5 = _mm_shuffle_epi8(_mm_loadu_si128(a2 + 2), si128);
__asm { sha256rnds2 xmm2, xmm14, xmm0 }
__asm { sha256rnds2 xmm14, xmm2, xmm0 }
__asm { sha256rnds2 xmm2, xmm14, xmm0 }
_XMM1 = _mm_shuffle_epi8(_mm_loadu_si128(a2 + 3), si128);
__asm
{
sha256rnds2 xmm14, xmm2, xmm0
sha256msg1 xmm13, xmm6
}
_XMM12 = _mm_add_epi32(_mm_alignr_epi8(_XMM1, _XMM5, 4), _XMM13);
__asm
{
sha256msg2 xmm12, xmm1
sha256rnds2 xmm2, xmm14, xmm0
}
__asm
{
sha256rnds2 xmm14, xmm2, xmm0
sha256msg1 xmm6, xmm5
}
_XMM13 = _mm_add_epi32(_mm_alignr_epi8(_XMM12, _XMM1, 4), _XMM6);
__asm
{
sha256msg2 xmm13, xmm12
sha256rnds2 xmm2, xmm14, xmm0
}
__asm
{
sha256rnds2 xmm14, xmm2, xmm0
sha256msg1 xmm5, xmm1
}
_XMM15 = _mm_add_epi32(_mm_alignr_epi8(_XMM13, _XMM12, 4), _XMM5);
__asm
{
sha256msg2 xmm15, xmm13
sha256rnds2 xmm2, xmm14, xmm0
}
__asm
{
sha256rnds2 xmm14, xmm2, xmm0
sha256msg1 xmm1, xmm12
}
_XMM5 = _mm_add_epi32(_mm_alignr_epi8(_XMM15, _XMM13, 4), _XMM1);
__asm
{
sha256msg2 xmm5, xmm15
sha256rnds2 xmm2, xmm14, xmm0
}
__asm
{
sha256rnds2 xmm14, xmm2, xmm0
sha256msg1 xmm12, xmm13
}
_XMM6 = _mm_add_epi32(_mm_alignr_epi8(_XMM5, _XMM15, 4), _XMM12);
__asm
{
sha256msg2 xmm6, xmm5
sha256rnds2 xmm2, xmm14, xmm0
}
__asm
{
sha256rnds2 xmm14, xmm2, xmm0
sha256msg1 xmm13, xmm15
}
_XMM1 = _mm_add_epi32(_mm_alignr_epi8(_XMM6, _XMM5, 4), _XMM13);
__asm
{
sha256msg2 xmm1, xmm6
sha256rnds2 xmm2, xmm14, xmm0
}
__asm
{
sha256rnds2 xmm14, xmm2, xmm0
sha256msg1 xmm15, xmm5
}
_XMM13 = _mm_add_epi32(_mm_alignr_epi8(_XMM1, _XMM6, 4), _XMM15);
__asm
{
sha256msg2 xmm13, xmm1
sha256rnds2 xmm2, xmm14, xmm0
}
__asm
{
sha256rnds2 xmm14, xmm2, xmm0
sha256msg1 xmm5, xmm6
}
_XMM12 = _mm_add_epi32(_mm_alignr_epi8(_XMM13, _XMM1, 4), _XMM5);
__asm
{
sha256msg2 xmm12, xmm13
sha256rnds2 xmm2, xmm14, xmm0
}
__asm { sha256msg1 xmm6, xmm1 }
_XMM5 = _mm_add_epi32(_mm_alignr_epi8(_XMM12, _XMM13, 4), _XMM6);
__asm
{
sha256rnds2 xmm14, xmm2, xmm0
sha256msg2 xmm5, xmm12
sha256msg1 xmm1, xmm13
}
_XMM6 = _mm_add_epi32(_mm_alignr_epi8(_XMM5, _XMM12, 4), _XMM1);
__asm
{
sha256rnds2 xmm2, xmm14, xmm0
sha256msg2 xmm6, xmm5
sha256msg1 xmm13, xmm12
}
__asm { sha256msg1 xmm12, xmm5 }
__asm { sha256rnds2 xmm14, xmm2, xmm0 }
__asm { sha256rnds2 xmm2, xmm14, xmm0 }
_XMM15 = _mm_add_epi32(_mm_alignr_epi8(_XMM6, _XMM5, 4), _XMM13);
__asm { sha256msg2 xmm15, xmm6 }
__asm { sha256rnds2 xmm14, xmm2, xmm0 }
__asm { sha256rnds2 xmm2, xmm14, xmm0 }
_XMM1 = _mm_add_epi32(_mm_alignr_epi8(_XMM15, _XMM6, 4), _XMM12);
__asm { sha256msg2 xmm1, xmm15 }
__asm { sha256rnds2 xmm14, xmm2, xmm0 }
__asm { sha256rnds2 xmm2, xmm14, xmm0 }
__asm { sha256rnds2 xmm14, xmm2, xmm0 }
__asm { sha256rnds2 xmm2, xmm14, xmm0 }
_XMM14 = _mm_add_epi32(_XMM14, v8);
_XMM2 = _mm_add_epi32(_XMM2, _XMM7);
a2 += 4;
_XMM7 = _XMM2;
v8 = _XMM14;
}
while ( a2 != v9 );
}
else
{
_XMM14 = v8;
_XMM2 = _XMM7;
}
v85 = _mm_shuffle_epi32(_XMM2, 27);
v86 = _mm_shuffle_epi32(_XMM14, 177);
*a1 = _mm_blend_epi16(v85, v86, 240);
a1[1] = _mm_alignr_epi8(v86, v85, 8);
return result;
}
</details>
- Sau khi đã hash xong, chương trình lấy 16 bytes đầu tiên làm các biến khởi tạo cho thuận toán trộn.
```cpp=
srcb = _byteswap_ulong(v143); // h0
v82 = _byteswap_ulong(DWORD1(v143)); // h1
nd = _byteswap_ulong(DWORD2(v143)); // h2
v83 = _byteswap_ulong(HIDWORD(v143)); // h3
```
Lưu ý: `_byteswap_ulong` được sử dụng vì SHA-256 tính toán theo Big Endian, nhưng kiến trúc x86 (và thuật toán trộn sau đó) sử dụng Little Endian.
`v84 = sub_3F00(v154, v153);` : Chương trình sẽ tính CRC32 với chỉ lệnh `PCLMULQDQ`( `nhận biết qua __asm { pclmulqdq xmm1, xmm0, 1 }`)với input là hwid đã parse rồi lưu vào v84.
<details>
<summary>sub_3F00(CRC32)</summary>
__int64 __fastcall sub_3F00(const __m128i *a1, unsigned __int64 a2)
{
unsigned __int64 v2; // rdx
char v4; // al
__int16 v5; // ax
__int64 v6; // rdi
const __m128i *v7; // rsi
unsigned __int64 v9; // r14
__m128i v43; // xmm1
__m128i v49; // xmm0
__m128i v53; // xmm0
v2 = a2;
v4 = qword_69178[0];
if ( !qword_69178[0] )
{
v4 = sub_1630();
v2 = a2;
}
if ( (v4 & 2) == 0 )
return sub_3D20(0, a1, v2);
v5 = qword_69178[0];
if ( !qword_69178[0] )
{
v9 = v2;
v5 = sub_1630();
v2 = v9;
}
if ( (v5 & 0x400) == 0 )
return sub_3D20(0, a1, v2);
v6 = 0;
v7 = a1;
if ( v2 < 0x80 )
return sub_3D20(v6, v7, v2);
_XMM3 = _mm_loadu_si128(a1 + 1);
_XMM2 = _mm_loadu_si128(a1 + 2);
_XMM1 = _mm_loadu_si128(a1 + 3);
_XMM0 = _mm_xor_si128(_mm_cvtsi32_si128(0xFFFFFFFF), _mm_loadu_si128(a1));
v7 = a1 + 4;
v2 -= 64LL;
_XMM4 = 0x154442BD4uLL;
_XMM5 = _mm_load_si128(xmmword_4EC30);
do
{
_XMM6 = _XMM0;
__asm { pclmulqdq xmm6, xmm4, 0 }
_XMM7 = _XMM0;
__asm { pclmulqdq xmm7, xmm5, 11h }
_XMM0 = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128(v7), _XMM6), _XMM7);
_XMM9 = _XMM3;
__asm { pclmulqdq xmm9, xmm4, 0 }
__asm { pclmulqdq xmm3, xmm5, 11h }
_XMM3 = _mm_xor_si128(_XMM3, _mm_xor_si128(_XMM9, _mm_loadu_si128(v7 + 1)));
_XMM6 = _XMM2;
__asm { pclmulqdq xmm6, xmm4, 0 }
__asm { pclmulqdq xmm2, xmm5, 11h }
_XMM2 = _mm_xor_si128(_XMM2, _mm_xor_si128(_XMM6, _mm_loadu_si128(v7 + 2)));
_XMM6 = _XMM1;
__asm { pclmulqdq xmm6, xmm4, 0 }
__asm { pclmulqdq xmm1, xmm5, 11h }
_XMM1 = _mm_xor_si128(_XMM1, _mm_xor_si128(_XMM6, _mm_loadu_si128(v7 + 3)));
v7 += 4;
v2 -= 64LL;
}
while ( v2 > 0x3F );
_XMM4 = 0x1751997D0uLL;
_XMM6 = _XMM0;
__asm { pclmulqdq xmm6, xmm4, 0 }
_XMM5 = _mm_cvtepu32_epi64((__m64)0xCCAA009ECCAA009ELL);
__asm { pclmulqdq xmm0, xmm5, 11h }
_XMM0 = _mm_xor_si128(_mm_xor_si128(_XMM0, _XMM6), _XMM3);
_XMM3 = _XMM0;
__asm
{
pclmulqdq xmm3, xmm4, 0
pclmulqdq xmm0, xmm5, 11h
}
_XMM0 = _mm_xor_si128(_mm_xor_si128(_XMM0, _XMM3), _XMM2);
_XMM2 = _XMM0;
__asm
{
pclmulqdq xmm2, xmm4, 0
pclmulqdq xmm0, xmm5, 11h
}
_XMM0 = _mm_xor_si128(_mm_xor_si128(_XMM0, _XMM2), _XMM1);
if ( v2 >= 0x10 )
{
do
{
v43 = _mm_loadu_si128(v7);
v2 -= 16LL;
++v7;
_XMM2 = _XMM0;
__asm { pclmulqdq xmm2, xmm4, 0 }
__asm { pclmulqdq xmm0, xmm5, 11h }
_XMM0 = _mm_xor_si128(_XMM0, _mm_xor_si128(_XMM2, v43));
}
while ( v2 > 0xF );
}
_XMM1 = _mm_cvtepu32_epi64((__m64)0xCCAA009ECCAA009ELL);
__asm { pclmulqdq xmm1, xmm0, 1 }
v49 = _mm_xor_si128(_mm_srli_si128(_XMM0, 8), _XMM1);
_XMM2 = _mm_blend_epi16((__m128i)0LL, v49, 3);
_XMM3 = 0x163CD6124uLL;
__asm { pclmulqdq xmm3, xmm2, 0 }
v53 = _mm_xor_si128(_mm_srli_si128(v49, 4), _XMM3);
_XMM2 = _mm_blend_epi16((__m128i)0LL, v53, 3);
__asm { pclmulqdq xmm2, cs:xmmword_4EC50, 10h }
_XMM2 = _mm_blend_epi16(_XMM2, (__m128i)0LL, 252);
_XMM1 = 0x1DB710641uLL;
__asm { pclmulqdq xmm1, xmm2, 0 }
v6 = (unsigned int)~_mm_extract_epi32(_mm_xor_si128(_XMM1, v53), 1);
if ( v2 )
return sub_3D20(v6, v7, v2);
else
return (unsigned int)v6;
}
</details>
- Sau đó chương trình sẽ xử lí đoạn thuật toán sau với `v84` và các biến từ sha-256 => Ra được các part của key.
```cpp=
v85 = (v84 ^ srcb) + v82;
v86 = __ROL4__(v85, 25);
v87 = nd ^ __ROL4__(v85, 4);
v88 = __ROL4__(v84, 3);
v89 = v88 ^ v87 ^ 0x5F8C2E7A;
v90 = v89 + (v84 ^ srcb ^ (v83 - (v87 ^ 0x5F8C2E7A)));
v91 = __ROL4__(v90, 25);
v92 = v84 ^ srcb ^ __ROL4__(v90, 4);
v93 = v89 ^ (v86 - (v92 ^ 0x5F8C2E7A));
v94 = __ROL4__(v84, 6);
v95 = v94 ^ v92 ^ 0x5F8C2E7A;
v96 = v95 + v93;
v97 = __ROL4__(v96, 4) ^ v87 ^ v88;
v98 = v97 ^ __ROL4__(v84, 9);
v99 = v98 + (v95 ^ (v91 - v97));
v100 = __ROL4__(v99, 4) ^ v92 ^ v94;
v101 = v100 ^ __ROL4__(v84, 12);
v102 = v101 + (v98 ^ (__ROL4__(v96, 25) - v100));
v103 = __ROL4__(v102, 25);
v104 = v98 ^ __ROL4__(v102, 4);
v105 = __ROL4__(v84, 15);
v106 = v105 ^ v104 ^ 0x5F8C2E7A;
v107 = v106 + (v101 ^ (__ROL4__(v99, 25) - (v104 ^ 0x5F8C2E7A)));
v108 = __ROL4__(v107, 25);
v109 = v101 ^ __ROL4__(v107, 4);
v110 = __ROL4__(v84, 18);
v111 = v110 ^ v109 ^ 0x5F8C2E7A;
v112 = v111 + (v106 ^ (v103 - (v109 ^ 0x5F8C2E7A)));
v113 = __ROL4__(v112, 25);
v114 = __ROL4__(v112, 4) ^ v104 ^ v105;
v115 = (unsigned int)v114 ^ __ROL4__(v84, 21);
v116 = v115 + (v111 ^ (v108 - v114));
v117 = __ROL4__(v116, 25);
v118 = __ROL4__(v116, 4) ^ v109 ^ v110;
v119 = v59 << 32; // ( part 5)
v120 = v43 << 32; // ( part 3)
v121 = v35; // ( part 2)
v122 = (unsigned __int64)((unsigned int)v115 ^ (v113 - (_DWORD)v118)) << 32;
```
- Trong đoạn code, biến v84 được xoay trái với các giá trị tăng dần theo cấp số cộng của 3 => Tổng cộng qua 8 lần vòng lặp, với magic const = `0x5F8C2E7A`, qua các phép tính mã hóa.
=> Kết quả của thuật toán là 4 số nguyên 32-bit, tương ứng với các part 2,3,4,5 của Key
Cuối cùng sẽ kiểm tra kết quả:
```cpp=
v124 = v51 | (unsigned __int64)v119; // ghep phan 4 va 5 do ng nhap
v125 = v121 | v120; // ghep phan 2 va 3 do ng nhap
v126 = v115 | ((unsigned __int64)v117 << 32); // key do may tao
v127 = v118 | v122; // key do may tao
if ( v127 ^ v125 | v126 ^ v124 ) // so sánh
goto LABEL_132;
```
## Script
```python=
import hashlib
import struct
import binascii
# --- CÁC HÀM BỔ TRỢ ---
def rol32(val, r_bits):
"""Rotate Left 32-bit"""
return ((val << r_bits) & 0xFFFFFFFF) | (val >> (32 - r_bits))
def crc32_func(data):
"""Standard CRC32"""
return binascii.crc32(data) & 0xFFFFFFFF
# --- LOGIC CHÍNH ---
def generate_key(username, hwid_hex, timestamp, tier_int):
# 1. Xử lý Input
# Parse HWID từ Hex string (16 chars) sang 8 bytes raw
try:
hwid_bytes = binascii.unhexlify(hwid_hex)
except:
print("Lỗi: HWID phải là chuỗi Hex hợp lệ (độ dài chẵn, 0-9, A-F).")
return
# Map Tier sang chuỗi
tier_map = {1: "BRNZ", 2: "SLVR", 3: "GOLD"}
suffix = tier_map.get(tier_int, "UNK")
# 2. Tạo SHA-256 Hash Buffer
# Buffer = Username + HWID_Bytes + Timestamp(Little-Endian u64) + Tier(u8)
# - "le64(timestamp) || u8(tier)"
buffer = username.encode() + hwid_bytes + struct.pack('<Q', timestamp) + struct.pack('B', tier_int)
sha_hash = hashlib.sha256(buffer).digest()
# 3. Trích xuất h0-h3 (QUAN TRỌNG: LITTLE ENDIAN)
h0, h1, h2, h3 = struct.unpack('<IIII', sha_hash[:16])
# 4. Tính CRC32 của HWID Bytes
c = crc32_func(hwid_bytes)
# 5. Thuật toán 8 Vòng.
MAGIC = 0x5f8c2e7a
# Setup
a = (h0 ^ c) & 0xFFFFFFFF
b = (h1 + a) & 0xFFFFFFFF
# Round 1
b4 = rol32(b, 4) ^ h2
x1 = b4 ^ MAGIC
c3 = rol32(c, 3)
y1 = x1 ^ c3
# Phép trừ/cộng phải mask 0xFFFFFFFF để mô phỏng tràn số 32-bit
d = (((h3 - x1) & 0xFFFFFFFF) ^ a) + y1
d &= 0xFFFFFFFF
d4 = rol32(d, 4) ^ a
# Round 2
x2 = d4 ^ MAGIC
c6 = rol32(c, 6)
y2 = x2 ^ c6
e = (((rol32(b, 25) - x2) & 0xFFFFFFFF) ^ y1) + y2
e &= 0xFFFFFFFF
# Round 3
f1 = c3 ^ b4 ^ rol32(e, 4)
c9 = rol32(c, 9)
g1 = c9 ^ f1
h_val = (((rol32(d, 25) - f1) & 0xFFFFFFFF) ^ y2) + g1
h_val &= 0xFFFFFFFF
# Round 4
f2 = c6 ^ d4 ^ rol32(h_val, 4)
c12 = rol32(c, 12)
g2 = c12 ^ f2
j = (((rol32(e, 25) - f2) & 0xFFFFFFFF) ^ g1) + g2
j &= 0xFFFFFFFF
# Round 5
j4 = rol32(j, 4) ^ g1
x5 = j4 ^ MAGIC
c15 = rol32(c, 15)
y5 = x5 ^ c15
k = (((rol32(h_val, 25) - x5) & 0xFFFFFFFF) ^ g2) + y5
k &= 0xFFFFFFFF
# Round 6
k4 = rol32(k, 4) ^ g2
x6 = k4 ^ MAGIC
c18 = rol32(c, 18)
y6 = x6 ^ c18
m = (((rol32(j, 25) - x6) & 0xFFFFFFFF) ^ y5) + y6
m &= 0xFFFFFFFF
# Round 7
f7 = c15 ^ j4 ^ rol32(m, 4)
c21 = rol32(c, 21)
n = c21 ^ f7
p = (((rol32(k, 25) - f7) & 0xFFFFFFFF) ^ y6) + n
p &= 0xFFFFFFFF
# Round 8
r_val = c18 ^ k4 ^ rol32(p, 4)
# Final key parts
key2 = r_val & 0xFFFFFFFF
key3 = ((rol32(m, 25) - r_val) & 0xFFFFFFFF) ^ n
key4 = n & 0xFFFFFFFF
key5 = rol32(p, 25)
final_key = f"KGIII-{key2:08X}-{key3:08X}-{key4:08X}-{key5:08X}-{suffix}"
print(f"KEY:{final_key}")
generate_key("subscriber_silver", "DEAD5678FACE1234", 1770302143, 2) #( thay username, hwid, timestamp, tier vào đây).
```
- Nhập thử
