DS
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Write-up Eschaton CTF 2026 ( REV) # Retro - Chạy thử chương trình: ![image](https://hackmd.io/_uploads/BkXc8BjL-e.png) - 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`: - ![image](https://hackmd.io/_uploads/B1TsdSsUZg.png) - 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 ![image](https://hackmd.io/_uploads/HkiWiSjIZx.png) => 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 ![image](https://hackmd.io/_uploads/rkfI1Uo8Ze.png) - `DAT_c000` = 0x1:![image](https://hackmd.io/_uploads/BJwqiSsU-e.png) -`DAT_c000` = 0x2 :![image](https://hackmd.io/_uploads/By5U3BoL-e.png) # Key1 ![image](https://hackmd.io/_uploads/rJalGOiLWl.png) - 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() ``` ![image](https://hackmd.io/_uploads/HJJH9YoIZx.png) # Key 2 - tương tự bài trên nhưng bây giờ có thêm hwid. ![image](https://hackmd.io/_uploads/ByYnOB3Lbx.png) - 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 ) ![image](https://hackmd.io/_uploads/HypyAToIbx.png) 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 : - ![image](https://hackmd.io/_uploads/HkAs5jsU-e.png) - Lấy seed xoay trái 7 bit rồi XOR với 0x8D2F5A1C; Part 3 :![image](https://hackmd.io/_uploads/HJgdhjjIbx.png) - 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 : ![image](https://hackmd.io/_uploads/ByKHTjiLWx.png) - 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() ``` ![image](https://hackmd.io/_uploads/SJvQBDhUbx.png) # Textmorph ![image](https://hackmd.io/_uploads/HJn_vYJvbe.png) - 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. ![image](https://hackmd.io/_uploads/rJfpQK1D-e.png) Sau khi unpack bằng lệnh `python3 pyinstxtractor.py textmorph`, ta được ![image](https://hackmd.io/_uploads/Byw-_FJDbg.png) - Thấy file textmorph_embedded.pyc. - Thử strings `strings -n 10 textmorph_embedded.pyc ` ta có mấy các fake flag : ![image](https://hackmd.io/_uploads/Hk_fI51vZg.png) ![image](https://hackmd.io/_uploads/BySQLckwWg.png) ![image](https://hackmd.io/_uploads/SkgNU9kvbg.png) và 1 đống gì đó giống base64.![image](https://hackmd.io/_uploads/rJphUqyPWx.png) - 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 . ![image](https://hackmd.io/_uploads/ry1Vki1DWx.png) # key3 ![image](https://hackmd.io/_uploads/SJnZbiJwbl.png) ![image](https://hackmd.io/_uploads/By7a4kWPWl.png) - 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ử ![image](https://hackmd.io/_uploads/SyOfiQGDWx.png)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully