# HKCERT - EasyRev ![image](https://hackmd.io/_uploads/Syr8QFPm-e.png) Xử lí SIMD noise injection (patch nop) ```py from capstone import * from capstone.x86 import * import mmap with open("main.exe", "rb") as f: data = bytearray(f.read()) BASE = 0x140001000 - 0x400 START = 0x140001000 END = 0x140002C02 md = Cs(CS_ARCH_X86, CS_MODE_64) md.detail = True for insn in md.disasm(data[START-BASE:END-BASE], START): mnem = insn.mnemonic if mnem.startswith(("cmpss", "va", "ve", "vr", "vu", "vf", "vt", "vb", "vs", "vh", "vm", "vp", "vx", "vo", "vc", "vd", "sm", "ae", "rd", "fm", "fu", "fc", "fs", "tz", "rc", "pabs", "phsub", "psign")): print(f"patch {hex(insn.address)} {mnem} size={insn.size}") off = insn.address - BASE data[off:off+insn.size] = b"\x90" * insn.size with open("patched.exe", "wb") as f: f.write(data) ``` Nhưng capstone lỗi ở lệnh 'nop r8' (multi-byte nop) nên bị dừng disasm. Để bypass qua chỗ đó thì mình có thể skip qua 4 byte và tiếp tục disasm. Nhưng mình muốn viết script tự nhảy pc để đọc lệnh để phần sau không bị lỗi nữa nếu có thêm byte rác. ```py from capstone import * from capstone.x86 import * with open("main.exe", "rb") as f: data = bytearray(f.read()) BASE_ADDRESS = 0x140001000 START = 0x400 END = 0x23400 md = Cs(CS_ARCH_X86, CS_MODE_64) md.detail = True code = data[START:END] pc = 0 def is_rex_nop(buf): return ( len(buf) >= 4 and buf[0] in range(0x40, 0x50) and buf[1] == 0x0F and buf[2] == 0x1F ) def checkSIMD(s): # if 'mm' in s.op_str or 'st' in s.op_str: # return 1 if s.mnemonic.startswith(("str", "cmpss", "cmpsd", "vi", "va", "ve", "vr", "vu", "vf", "vt", "vb", "vs", "vh", "vm", "vp", "vx", "vo", "vc", "vd", "sm", "ae", "fa", "ff", "fm", "fu", "fc", "fs", "tz", "rc", "rd", "pa", "pm", "ph", "ps", "sldt")): return 1 return 0 while pc < len(code): buf = code[pc:pc+15] insns = list(md.disasm(buf, pc)) if insns: insn = insns[0] file_off = START + pc if checkSIMD(insn): data[file_off:file_off+insn.size] = b'\x90' * insn.size pc += insn.size else: if is_rex_nop(buf): pc += 4 else: pc += 1 with open("patched.exe", "wb") as f: f.write(data) ``` Patch vẫn chưa sạch lắm nhưng mà thôi kệ vẫn đọc được. Code hàm main sau khi patch: ```c int __fastcall main(int argc, const char **argv, const char **envp) { __m64 v3; // mm1 __m64 v4; // mm7 __m128 v5; // xmm1 __m128 v6; // xmm2 float v7; // xmm3_4 double v8; // xmm4_8 __int16 v9; // dx char v10; // cl __int64 v11; // rdx __int64 v12; // rax __int64 v13; // rdx __int64 v14; // r11 __m128i v15; // xmm4 __int64 v16; // rdx __int64 v17; // rcx __int64 v18; // r8 char *v20; // rax __int64 v21; // rdx __int64 v22; // rdx __int64 v23; // r9 __int64 v24; // r8 __int64 v25; // rdx int v26; // edx __int64 v27; // rcx __int64 v28; // rdx int v29; // eax __int64 v30; // rax __int64 v31; // rax _BYTE v33[12]; // [rsp+24h] [rbp-74h] BYREF _BYTE v34[12]; // [rsp+30h] [rbp-68h] BYREF int v35; // [rsp+3Ch] [rbp-5Ch] unsigned __int64 v36; // [rsp+40h] [rbp-58h] unsigned __int64 k; // [rsp+48h] [rbp-50h] _QWORD v38[3]; // [rsp+50h] [rbp-48h] BYREF unsigned __int64 j; // [rsp+68h] [rbp-30h] unsigned __int64 i; // [rsp+70h] [rbp-28h] _BYTE v41[12]; // [rsp+7Ch] [rbp-1Ch] BYREF unsigned __int64 len; // [rsp+88h] [rbp-10h] int v43; // [rsp+94h] [rbp-4h] v43 = 0; ((void (__fastcall *)(int, const char **, const char **))((char *)off_7FF768480260 + 0x2FAB1BB7013BFA7LL))( argc, argv, envp); ((void (__fastcall *)(void *, char *))((char *)off_7FF768480268 + 0x3533C92875EBF31ELL))( &unk_7FF768480FBC, (char *)&unk_7FF7684743A0 + 468); *(double *)v5.m128_u64 = sqrt(v8); ((void (__fastcall *)(void *, void *))((char *)off_7FF768480270 - 0x592B6E96FCCDB559LL))( &unk_7FF768480FBC, &byte_7FF768480E30); LOWORD(v11) = v9 >> v10; len = ((__int64 (__fastcall *)(void *, __int64))((char *)off_7FF768480278 - 0x100E985395D3C573LL))( &byte_7FF768480E30, v11); // len if ( len == 42 ) // len = 42 { ((void (*)(void))((char *)off_7FF7684802A0 - 0xFF6F2DEE741D53CLL))();// func1 for ( i = 0LL; ; ++i ) { v3 = _m_punpckhbw(v3, v4); v6 = (__m128)_mm_unpacklo_epi32((__m128i)v6, (__m128i)v6); if ( i >= len ) break; v13 = (unsigned int)(*((char *)off_7FF768480098 + i + 0x12ADADE3AD60017CLL) + *((char *)encrypting_input + i + 0x6A36A897964DBCB7LL)); *((_BYTE *)encrypting_input + i + 0x6A36A897964DBCB7LL) += *((_BYTE *)off_7FF768480098 + i + 0x12ADADE3AD60017CLL); v14 >>= 36; } LOWORD(v13) = v13 | 0xFF9C; ((void (__fastcall *)(_QWORD, __int64))((char *)off_7FF7684802A0 - 0xFF6F2DEE741D53CLL))(// func1 (unsigned int)_mm_extract_epi32(v15, 32), v13); for ( j = 0LL; j < len; ++j ) { v20 = (char *)encrypting_input + 0x6A36A897964DBCB7LL; v7 = *(double *)v5.m128_u64; __asm { rdsspq r9 } v18 = ~(~(~(~(*((char *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0xD80AF07D) & ~(~*((char *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x27F50F82)) & 0x6AC02584) & ~(~(*((char *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0xD80AF07D) & ~(~*((char *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x27F50F82) & 0x953FDA7B) & 0xB2CAD586); v20[j] = ~(~(~(~(~(*((_BYTE *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x7D) & ~(~*((_BYTE *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x82)) & 0x84) & ~(~(*((_BYTE *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x7D) & ~(~*((_BYTE *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x82) & 0x7B) & 0x86) & ~(~(~(~(~(*((_BYTE *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x7D) & ~(~*((_BYTE *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x82)) & 0x84) & ~(~(*((_BYTE *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x7D) & ~(~*((_BYTE *)encrypting_input + j + 0x6A36A897964DBCB7LL) & 0x82) & 0x7B)) & 0x79)); v16 = (unsigned int)(char)v20; v5 = _mm_movelh_ps(v5, v6); v17 = 0x1DAAD26BEAAFCF79LL; } ((void (__fastcall *)(__int64, __int64, __int64, __int64))((char *)off_7FF7684802A0 - 0xFF6F2DEE741D53CLL))(// func1 v17, v16, v18, _R9); v38[0] = 0x6589602598654235LL; v22 = __ROR8__(v21, 152); v23 = (unsigned __int16)v22; v38[1] = 0x5556575865841236LL; LOBYTE(v22) = (unsigned __int8)v22 >> 1; ((void (__fastcall *)(_QWORD *, __int64, __int64, __int64))((char *)off_7FF7684802A8 - 0x7DA4E0BDECC7FFFCLL))(// func2 v38, v22, v24, v23); for ( k = 0LL; k < len >> 3; ++k ) { ((void (__fastcall *)(__int64, char *, _QWORD *))((char *)off_7FF7684802B0 + 0x6295BE8F36376BC7LL))(// func3 102LL, (char *)encrypting_input + 8 * k + 0x6A36A897964DBCB7LL, v38); v25 = v26 - ((unsigned int)__CFADD__(k + 0x30CBCAE69232D1CDLL, 1LL) + 364126667); } ((void (__fastcall *)(unsigned __int64, __int64))((char *)off_7FF7684802A0 - 0xFF6F2DEE741D53CLL))(len >> 3, v25);// func1 LOBYTE(v28) = v28 ^ 0xF6; *(double *)v6.m128_u64 = v7; v36 = 0LL; while ( 1 ) { v6 = (__m128)_mm_cmpistrm((__m128i)v6, (__m128i)v5, 46); if ( v36 >= len ) break; LOWORD(v27) = __ROR2__(v27, v27); ((void (__fastcall *)(__int64, __int64))((char *)off_7FF7684802A0 - 0xFF6F2DEE741D53CLL))(v27, v28);// func1 v35 = v29; if ( *((char *)encrypting_input + v36 + 0x6A36A897964DBCB7LL) != v29 + *((char *)ciphertext + v36 - 0x2B7A95E9A80E6A6FLL) )// checker { ((void (__fastcall *)(void *, char *))((char *)off_7FF768480280 + 0x1B55CF27643E8BF0LL))(// Wrong &unk_7FF768480FC8, (char *)&unk_7FF7684743A0 + 528); ((void (__fastcall *)(_BYTE *, void *))((char *)off_7FF768480288 + 0x421BDD46CCB7BD16LL))( v34, &unk_7FF768480FC8); // print v30 = ((__int64 (__fastcall *)(_BYTE *))((char *)off_7FF768480290 - 0x2871973C69EB090LL))(v34); ((void (__fastcall *)(__int64))((char *)off_7FF768480298 - 0x5A4CC83C3524CFF2LL))(v30); return 0; } v27 = 0x73291284FC5F8C6BLL; ++v36; v28 = (unsigned int)__ROL4__(v29, 1); } ((void (__fastcall *)(void *, char *))((char *)off_7FF7684802B8 + 0x46C556EBE30FBC8LL))(// Correct &unk_7FF768480FD8, (char *)&unk_7FF7684743A0 + 585); ((void (__fastcall *)(_BYTE *, void *))((char *)off_7FF768480288 + 0x421BDD46CCB7BD16LL))(v33, &unk_7FF768480FD8);// print v31 = ((__int64 (__fastcall *)(_BYTE *))((char *)off_7FF768480290 - 0x2871973C69EB090LL))(v33); ((void (__fastcall *)(__int64))((char *)off_7FF768480298 - 0x5A4CC83C3524CFF2LL))(v31); } else { ((void (__fastcall *)(void *, char *))((char *)off_7FF768480280 + 0x1B55CF27643E8BF0LL))(// Wrong &unk_7FF768480FC8, (char *)&unk_7FF7684743A0 + 528); ((void (__fastcall *)(_BYTE *, void *))((char *)off_7FF768480288 + 0x421BDD46CCB7BD16LL))(v41, &unk_7FF768480FC8);// print v12 = ((__int64 (__fastcall *)(_BYTE *))((char *)off_7FF768480290 - 0x2871973C69EB090LL))(v41); ((void (__usercall *)(__int64@<rcx>))((char *)off_7FF768480298 - 0x5A4CC83C3524CFF2LL))(v12); return 0; } return v43; } ``` func2: keygen XTEA ```c __int64 __fastcall func2(__int64 a1, int a2, double a3, signed __int64 a4) { __int64 v4; // r10 __m64 v5; // mm7 __m64 v6; // mm5 unsigned int v7; // et0 __int64 result; // rax int j; // [rsp+Ch] [rbp-14h] int i; // [rsp+10h] [rbp-10h] __int64 v11; // [rsp+18h] [rbp-8h] v6 = _mm_cvttpd_pi32(*(__m128d *)&a3); v11 = a1; for ( i = 0; i < 32; ++i ) { for ( j = 0; j < 4; ++j ) { LOWORD(a1) = j; a4 = (a4 >> 9) ^ 0xFFFFFFFFEA5EF272uLL; a2 = *(_DWORD *)(v11 + 4LL * ((j + 1) % 4)) + 305419896 + *(_DWORD *)(v11 + 4LL * j); *(_DWORD *)(v11 + 4LL * j) = a2; v4 = __ROL8__(v4, 61); v6 = _m_pcmpgtw(v6, v5); } HIWORD(v7) = a1; LOWORD(v7) = a2; LOWORD(a1) = v7 >> 3; result = (unsigned int)(i + 1); } return result; } ``` func3: XTEA round ```c unsigned int *__fastcall func3(unsigned int a1, unsigned int *a2, __int64 a3) { __m64 v3; // mm0 __m64 v4; // mm3 __m64 v5; // mm4 __m64 v6; // mm5 __m64 v7; // mm6 __m64 v8; // mm7 __m64 v9; // mm0 __m64 v10; // mm6 unsigned int v11; // ecx unsigned int v12; // eax unsigned int v13; // ecx unsigned int v14; // eax unsigned int v15; // r8d unsigned int *result; // rax unsigned int v17; // [rsp+4h] [rbp-24h] unsigned int v18; // [rsp+8h] [rbp-20h] unsigned int v19; // [rsp+Ch] [rbp-1Ch] unsigned int i; // [rsp+10h] [rbp-18h] v19 = *a2; v18 = a2[1]; v17 = 0; v9 = _m_pcmpeqw(_m_por(v3, v5), v6); v10 = _m_pcmpeqw(v7, v8); for ( i = 0; i < a1; ++i ) { v11 = ~((v18 + 1272462553 - (~(~(~((v18 >> 5) & 0x5FAAD220) & ~(~(v18 >> 5) & 0xA0552DDF) & ~(~((16 * v18) & 0x61E7097E) & ~(~(16 * v18) & 0x9E18F681))) & ~(~((16 * v18) & 0x61E7097E) & ~(~(16 * v18) & 0x9E18F681) & ~(~((v18 >> 5) & 0x5FAAD220) & ~(~(v18 >> 5) & 0xA0552DDF))) & 0x3E4DDB5E) & ~(~(~(~((v18 >> 5) & 0x5FAAD220) & ~(~(v18 >> 5) & 0xA0552DDF) & ~(~((16 * v18) & 0x61E7097E) & ~(~(16 * v18) & 0x9E18F681))) & ~(~((16 * v18) & 0x61E7097E) & ~(~(16 * v18) & 0x9E18F681) & ~(~((v18 >> 5) & 0x5FAAD220) & ~(~(v18 >> 5) & 0xA0552DDF)))) & 0xC1B224A1)) - 1272462554) & 0x2D67FDBA); v12 = ~(v11 & ~(~(v18 + 1272462553 - (~(~(~((v18 >> 5) & 0x5FAAD220) & ~(~(v18 >> 5) & 0xA0552DDF) & ~(~((16 * v18) & 0x61E7097E) & ~(~(16 * v18) & 0x9E18F681))) & ~(~((16 * v18) & 0x61E7097E) & ~(~(16 * v18) & 0x9E18F681) & ~(~((v18 >> 5) & 0x5FAAD220) & ~(~(v18 >> 5) & 0xA0552DDF))) & 0x3E4DDB5E) & ~(~(~(~((v18 >> 5) & 0x5FAAD220) & ~(~(v18 >> 5) & 0xA0552DDF) & ~(~((16 * v18) & 0x61E7097E) & ~(~(16 * v18) & 0x9E18F681))) & ~(~((16 * v18) & 0x61E7097E) & ~(~(16 * v18) & 0x9E18F681) & ~(~((v18 >> 5) & 0x5FAAD220) & ~(~(v18 >> 5) & 0xA0552DDF)))) & 0xC1B224A1)) - 1272462554) & 0xD2980245)); v19 += ~(~(~(~((*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(_BYTE)v17 | 0xFFFFFFFC)) + v17) & 0x212F72F5) & ~(~(*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(_BYTE)v17 | 0xFFFFFFFC)) + v17) & 0xDED08D0A) & v12) & ~(~v12 & ~(~((*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(_BYTE)v17 | 0xFFFFFFFC)) + v17) & 0x212F72F5) & ~(~(*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(_BYTE)v17 | 0xFFFFFFFC)) + v17) & 0xDED08D0A))) & 0xC488F4F) & ~(~(~(~((*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(_BYTE)v17 | 0xFFFFFFFC)) + v17) & 0x212F72F5) & ~(~(*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(_BYTE)v17 | 0xFFFFFFFC)) + v17) & 0xDED08D0A) & v12) & ~(~v12 & ~(~((*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(_BYTE)v17 | 0xFFFFFFFC)) + v17) & 0x212F72F5) & ~(~(*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(_BYTE)v17 | 0xFFFFFFFC)) + v17) & 0xDED08D0A)))) & 0xF3B770B0)); v17 += ~(~(~(~(~(*(_DWORD *)((_BYTE *)off_7FF768480078 + 0x3D5A6525234A0D3LL) & 0xFD88B062) & ~(~*(_DWORD *)((char *)off_7FF768480078 + 0x3D5A6525234A0D3LL) & 0x2774F9D)) & 0xAFC63A1) & ~(~(*(_DWORD *)((_BYTE *)off_7FF768480078 + 0x3D5A6525234A0D3LL) & 0xFD88B062) & ~(~*(_DWORD *)((char *)off_7FF768480078 + 0x3D5A6525234A0D3LL) & 0x2774F9D) & 0xF5039C5E) & 0x7B77FC02) & ~(~(~(~(~(*(_DWORD *)((_BYTE *)off_7FF768480078 + 0x3D5A6525234A0D3LL) & 0xFD88B062) & ~(~*(_DWORD *)((char *)off_7FF768480078 + 0x3D5A6525234A0D3LL) & 0x2774F9D)) & 0xAFC63A1) & ~(~(*(_DWORD *)((_BYTE *)off_7FF768480078 + 0x3D5A6525234A0D3LL) & 0xFD88B062) & ~(~*(_DWORD *)((char *)off_7FF768480078 + 0x3D5A6525234A0D3LL) & 0x2774F9D) & 0xF5039C5E)) & 0x848803FD)); v13 = ~((v19 + -(~(~(~((v19 >> 5) & 0x928A6F5C) & ~(~(v19 >> 5) & 0x6D7590A3) & ~(~((16 * v19) & 0x9EE30EA5) & ~(~(16 * v19) & 0x611CF15A))) & ~(~((16 * v19) & 0x9EE30EA5) & ~(~(16 * v19) & 0x611CF15A) & ~(~((v19 >> 5) & 0x928A6F5C) & ~(~(v19 >> 5) & 0x6D7590A3))) & 0xC6961F9) & ~(~(~(~((v19 >> 5) & 0x928A6F5C) & ~(~(v19 >> 5) & 0x6D7590A3) & ~(~((16 * v19) & 0x9EE30EA5) & ~(~(16 * v19) & 0x611CF15A))) & ~(~((16 * v19) & 0x9EE30EA5) & ~(~(16 * v19) & 0x611CF15A) & ~(~((v19 >> 5) & 0x928A6F5C) & ~(~(v19 >> 5) & 0x6D7590A3)))) & 0xF3969E06)) - 1177430714 + 1177430713) & 0xC4A157E1); v14 = ~(v13 & ~(~(v19 + -(~(~(~((v19 >> 5) & 0x928A6F5C) & ~(~(v19 >> 5) & 0x6D7590A3) & ~(~((16 * v19) & 0x9EE30EA5) & ~(~(16 * v19) & 0x611CF15A))) & ~(~((16 * v19) & 0x9EE30EA5) & ~(~(16 * v19) & 0x611CF15A) & ~(~((v19 >> 5) & 0x928A6F5C) & ~(~(v19 >> 5) & 0x6D7590A3))) & 0xC6961F9) & ~(~(~(~((v19 >> 5) & 0x928A6F5C) & ~(~(v19 >> 5) & 0x6D7590A3) & ~(~((16 * v19) & 0x9EE30EA5) & ~(~(16 * v19) & 0x611CF15A))) & ~(~((16 * v19) & 0x9EE30EA5) & ~(~(16 * v19) & 0x611CF15A) & ~(~((v19 >> 5) & 0x928A6F5C) & ~(~(v19 >> 5) & 0x6D7590A3)))) & 0xF3969E06)) - 1177430714 + 1177430713) & 0x3B5EA81E)); v9 = _m_por(v9, v9); v10 = _m_punpcklwd(v10, v4); v15 = ~((*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(v17 >> 11) | 0xFFFFFFFC)) + v17) & 0x9B947D9A) & ~(~(*(_DWORD *)(a3 + 4LL * ~((unsigned __int8)~(v17 >> 11) | 0xFFFFFFFC)) + v17) & 0x646B8265); v18 += ~(~(~(v15 & v14) & ~(~v14 & ~v15) & 0x5F352A7B) & ~(~(~(v15 & v14) & ~(~v14 & ~v15)) & 0xA0CAD584)); } *a2 = v19; result = a2; a2[1] = v18; return result; } ``` Debug step-in vào từng hàm con được gọi trong main ta có được Flow: * input (42 bytes) * xor 0x7f (IV) * func2 -> key * func3: for 102 lần XTEA (chia 5 block 8 bytes) * so khớp cipher Debug Lấy key: breakpoint sau func2, lấy giá trị ở mảng v38. `CD 85 74 C7 F1 31 C4 09 70 6A D7 A3 37 49 0C 56` Debug Lấy cipher: breakpoint trước cmp, lấy giá trị tại rcx sau khi add cs:ciphertext. `F8 AC F7 66 C8 BB 9A C7 DC 1A 82 FF 27 04 0E 91 15 BD 1C 2F 98 F7 96 D2 C2 DF 12 0C 56 50 E6 20 58 AE 5C 67 7A FF 8A 95 43 1A` Debug lại logic của func3 để lấy chính xác code XTEA đã custom: Trong func3: * off_7FF768480078 + 0x3D5A6525234A0D3LL = 0x12345678 --> v17 += 0x9E3779B9 (delta) * ... Script python: ```py ``` SAI. Mình đã mặc định bỏ qua hàm func1 nhưng có vẻ như chỗ lưu cipher bị ghi đè rất nhiều lần qua mỗi lần func1 được gọi?? Antidebug chăng?. Thử cipher ban đầu xem. Với 2 byte cuối cố định, ta có thể tính được giá trị xor là 0xbf để có hậu tố `}`. ![image](https://hackmd.io/_uploads/Bk5qtq_mZg.png) ```py import struct import ctypes cipher_str = "BA 7A AA 6A 2F 7E F8 03 2D B4 AB 92 6B 91 31 DA 95 37 51 13 1F CE 1C 62 51 BC 3F B2 B1 B3 54 17 EF 28 93 AE 52 CA CE A7 DE C2" # debug sai # cipher_str = "F8 AC F7 66 C8 BB 9A C7 DC 1A 82 FF 27 04 0E 91 15 BD 1C 2F 98 F7 96 D2 C2 DF 12 0C 56 50 E6 20 58 AE 5C 67 7A FF 8A 95 43 1A" ciphertext = bytes.fromhex(cipher_str.replace(" ", "")) key_str = "CD 85 74 C7 F1 31 C4 09 70 6A D7 A3 37 49 0C 56" key_bytes = bytes.fromhex(key_str.replace(" ", "")) key = struct.unpack('<4I', key_bytes) def c_uint32(val): return ctypes.c_uint32(val).value def xtea_decrypt_custom(v0, v1, key): DELTA = 0x9E3779B9 ROUNDS = 102 s = c_uint32(DELTA * ROUNDS) for _ in range(ROUNDS): entry1 = c_uint32((v0 << 4) ^ (v0 >> 5)) + v0 entry2 = s + key[(s >> 11) & 3] v1 = c_uint32(v1 - (entry1 ^ entry2)) s = c_uint32(s - DELTA) entry3 = c_uint32((v1 << 4) ^ (v1 >> 5)) + v1 entry4 = s + key[s & 3] v0 = c_uint32(v0 - (entry3 ^ entry4)) return v0, v1 decrypted_buffer = bytearray() num_blocks = len(ciphertext) // 8 for i in range(num_blocks): block = ciphertext[i*8 : (i+1)*8] v0, v1 = struct.unpack('<2I', block) d0, d1 = xtea_decrypt_custom(v0, v1, key) decrypted_buffer += struct.pack('<2I', d0, d1) decrypted_buffer += ciphertext[num_blocks*8:] flag_chars = [] for b in decrypted_buffer: flag_chars.append(chr(((b ^ 0xbf) & 0x7F))) flag = "".join(flag_chars) print(flag) ``` ![image](https://hackmd.io/_uploads/ByZwP5O7bl.png) ![image](https://hackmd.io/_uploads/BJP3D5OmZg.png) Phân tích lại func1: ```c __int64 __fastcall func1(__int64 a1, __int64 a2, float a3, double a4) { __m64 v4; // mm3 __m64 v5; // mm4 __m64 v6; // mm4 char v7; // al char v8; // al char v9; // r9 char v10; // r10 float v11; // xmm4_4 int i; // [rsp+20h] [rbp-8h] unsigned int v14; // [rsp+24h] [rbp-4h] v6 = _m_punpckldq(v5, v4); LOWORD(a2) = (unsigned __int16)a2 >> a1; v7 = ((__int64 (__fastcall *)(__int64, __int64))((char *)off_7FF768480248 + 0x2FAB1BB7013BFA7LL))(a1, a2); v14 = v7 & 1; if ( (v7 & 1) != 0 ) { for ( i = 0; i < 42; ++i ) { *(float *)&a4 = *(float *)&a4 * a3; v8 = ((__int64 (*)(void))((char *)off_7FF768480250 + 0x3533C92875EBF31ELL))(); v9 = ~(*((_BYTE *)off_7FF768480070 + i + 0x3D5A6525234A0D3LL) & 0xA7) & ~(~*((_BYTE *)off_7FF768480070 + i + 0x3D5A6525234A0D3LL) & 0x58); v10 = ~(v8 & 0x6B) & ~(~v8 & 0x94); *(__m128i *)&a4 = _mm_unpacklo_epi16(*(__m128i *)&a4, *(__m128i *)&a4); v4 = _m_pcmpeqw(v4, v6); *(float *)&a4 = v11; *((_BYTE *)off_7FF768480070 + i + 0x3D5A6525234A0D3LL) = ~(~(~(v10 & ~v9) & ~(v9 & ~v10) & 0xCC) & ~(~(~(v10 & ~v9) & ~(v9 & ~v10)) & 0x33)); } } return v14; } ``` Vậy nếu v7 lẻ thì vùng nhớ đó sẽ bị ghi đè. debug xem đoạn v7 này nó call đi đâu ![image](https://hackmd.io/_uploads/SyebMoumbx.png) Make function cho nó rồi decompile thì mình đã thấy được đoạn check debug ![image](https://hackmd.io/_uploads/rkOZ7odXWg.png) Update: Có thể làm sạch hơn đoạn gọi hàm bằng các thao tác trên IDA hoặc IDAPython script hoặc patch raw bằng cách tính ra offset rồi ghi đè vào. Sau bài này mình sẽ thử viết/tổng hợp thêm vài plugin deobfuscator cho IDA. Cách obfuscate để ép thành char* + offset như jumptable kia: ```c typedef long long (__fastcall *fp_t)(long long, long long); void *table[] = { (void *)((char *)func1 - 0x12345678), }; fp_t f = (fp_t)((char *)table[0] + 0x12345678); f(a, b); ```