# [WRITEUP ISITDTU 2024] --- ## [Reverse Engineering] ## Name: RE01 :::info :bulb: Đề bài cho 1 file PE 64 bit ::: --- ### :small_blue_diamond:**Link:https://drive.google.com/drive/folders/16vE3lMrlPTfzRRG9OqSMoKq8TAbABeKX?usp=sharing** ### :small_blue_diamond: **Time: 15/01/2025** --- ## :white_check_mark: **WRITEUP** ### 1. Tổng quan - Đầu tiên, sử dụng CFF Explorer để phân tích và lấy được thông tin cơ bản của file như: file PE64bit. ![image](https://hackmd.io/_uploads/SyLW5TNvyg.png) - :bulb: IDA Pro là phương án tốt nhất để phân tích file PE này ### 2. Phân tích - Sau khi load file vào IDA Pro thì ta nhận thấy chương trình khá đơn giản với một số hàm chính ![image](https://hackmd.io/_uploads/HkaZ3TNv1x.png) *Các hàm quan trọng* - Khi đọc hàm main thì có vẻ như chương trình yêu cầu người dùng nhập một mật khẩu và được hash bằng thuật toán SHA1. ![Screenshot 2025-01-15 125357](https://hackmd.io/_uploads/HkdKO0Evyg.png) *Hàm main()* - Nhưng khi thử crack đoạn hash thì với những tool crack phổ biến thì không thể crack được và sau khi kiểm tra lại kỹ thì nhận thấy một hàm rất khả nghi. ![Screenshot 2025-01-15 124704](https://hackmd.io/_uploads/Hy4FtC4Dye.png) *Hàm đáng ngờ* -- Tlscallback() là hàm api của Microsoft có tác dụng chạy trước cả hàm main() còn về docs thì có thể tham khảo ở đây: https://hex-rays.com/blog/tls-callbacks - Tiến hành kiểm tra hàm này ![Screenshot 2025-01-15 134745](https://hackmd.io/_uploads/r1O-iREvyl.png) *Hàm Tlscallback()* - Kiểm tra sub_140004000() ``` void __fastcall sub_140004000(__int64 a1, int a2, __int64 a3) { int v5; // esi __int64 v6; // rdi char *v7; // r13 char *v8; // rax int v9; // r14d __int64 v10; // rdx int *v11; // rcx __int64 v12; // rbx __int64 *v13; // rax int v14; // edx char *v15; // r14 size_t v16; // rcx char *v17; // rbx __int64 v18; // rsi _QWORD *v19; // rcx _QWORD *v20; // rbx __int64 v21; // rdx char *v22; // rax void *Block; // [rsp+20h] [rbp-E0h] BYREF int v24; // [rsp+28h] [rbp-D8h] __int128 Src[14]; // [rsp+30h] [rbp-D0h] BYREF int v26; // [rsp+110h] [rbp+10h] int v27; // [rsp+114h] [rbp+14h] __int128 v28[8]; // [rsp+120h] [rbp+20h] BYREF void *Buf1[2]; // [rsp+1A0h] [rbp+A0h] BYREF __int64 v30; // [rsp+1B0h] [rbp+B0h] __int128 v31; // [rsp+1B8h] [rbp+B8h] char *v32; // [rsp+1C8h] [rbp+C8h] v24 = a2; if ( IsDebuggerPresent() ) -> Kiểm tra debugger exit(0); *(_OWORD *)Buf1 = 0i64; v5 = 0; v6 = 0i64; v30 = 0i64; // Load dữ liệu Src[0] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007770); Src[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400076D0); Src[2] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007700); Src[3] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400076C0); Src[4] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007690); Src[5] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007740); Src[6] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007780); Src[7] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007790); Src[8] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007730); Src[9] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007750); Src[10] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007650); Src[11] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007710); Src[12] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400077A0); Src[13] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007660); v26 = 28; v27 = 72; v31 = 0i64; v7 = (char *)operator new(0xE8ui64); *(_QWORD *)&v31 = v7; v32 = v7 + 232; memmove(v7, Src, 0xE8ui64); v8 = v7 + 232; *((_QWORD *)&v31 + 1) = v7 + 232; v9 = 0; v10 = xmmword_14000B0F0; v11 = (int *)Buf1[1]; if ( (_QWORD)xmmword_14000B0F0 ) { v12 = 0i64; do { v13 = &qword_14000B0E0; if ( *((_QWORD *)&xmmword_14000B0F0 + 1) > 0xFui64 ) v13 = (__int64 *)qword_14000B0E0; v14 = *((char *)v13 + v12) ^ 0x35; -> mã hóa chính LODWORD(Block) = v14; if ( v11 == (int *)v6 ) { sub_140001C20(Buf1, v11, &Block); v6 = v30; v11 = (int *)Buf1[1]; } else { *v11++ = v14; Buf1[1] = v11; } ++v9; ++v12; v10 = xmmword_14000B0F0; } while ( v9 < (unsigned __int64)xmmword_14000B0F0 ); v8 = v7 + 232; } v15 = (char *)Buf1[0]; if ( v10 == 58 ) { v16 = (char *)v11 - (char *)Buf1[0]; if ( v16 == v8 - v7 && !memcmp(Buf1[0], v7, v16) ) -> So sánh { v28[0] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007720); v28[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400076B0); v28[2] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007760); v28[3] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400076F0); v28[4] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007670); v28[5] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400076A0); v28[6] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400076E0); v28[7] = (__int128)_mm_load_si128((const __m128i *)&xmmword_140007680); v17 = (char *)operator new(0x80ui64); Block = v17; memmove(v17, v28, 0x80ui64); do { sub_140001040("%c"); ++v5; v17 += 4; } while ( (unsigned __int64)v5 < 0x20 ); if ( Block ) j_j_free(Block); } } v18 = 2i64 * v24; v19 = *(_QWORD **)(*(_QWORD *)(a1 + 8) + 16i64 * v24); v20 = (_QWORD *)*v19; if ( (_QWORD *)*v19 != v19 ) { do { v21 = *((int *)v20 + 4); if ( !*(_BYTE *)(v21 + a3) ) sub_140004000(a1, v21, a3); v20 = (_QWORD *)*v20; } while ( v20 != *(_QWORD **)(*(_QWORD *)(a1 + 8) + 8 * v18) ); } if ( v7 ) j_j_free(v7); if ( v15 ) { v22 = v15; if ( ((v6 - (_QWORD)v15) & 0xFFFFFFFFFFFFFFFCui64) >= 0x1000 ) { v15 = (char *)*((_QWORD *)v15 - 1); if ( (unsigned __int64)(v22 - v15 - 8) > 0x1F ) invalid_parameter_noinfo_noreturn(); } j_j_free(v15); } } ``` - Nhìn khá dài dòng nhưng thực chất cách mã hóa chỉ đơn giản là xor với 0x35 và so sánh dữ liệu với biến có sẵn. :bulb: Để lấy được bản rõ ta chỉ cần debug và trace đến biến Buf1 ở hàm memcmp() và bypass 2 hàm IsDebuggerPresent() - Đặt breakpoint để bypass các hàm anti debug ![Screenshot 2025-01-15 142210](https://hackmd.io/_uploads/ryMBmkSDyl.png) *Đặt breakpoint ở vị trí đó và chỉnh Zflag=1 để bypass* - Và nhập 58 kí tự a để đến được hàm memcmp() ![image](https://hackmd.io/_uploads/rJmOvySDyg.png) - Sau khi debug đến được hàm memcmp() ta chỉ việc lấy giá trị của bản rõ sau đó xor với 0x35 là ra flag![Screenshot 2025-01-15 145315](https://hackmd.io/_uploads/SkHnqySP1l.png) Source code: ``` cp =""" 000000660000007C 000000610000007C 0000006100000071 0000004E00000060 0000005A00000076 000000520000005B 0000005400000047 0000004600000041 0000006C0000006A 000000400000005A 000000660000006A 000000590000005A 0000005000000043 0000006A00000051 0000007900000061 0000006A00000066 0000005400000076 0000005900000059 0000005400000057 0000005E00000056 000000670000006A 0000000500000050 0000006A00000004 000000540000007D 0000005000000043 000000730000006A 0000005B00000040 0000000F0000006A 000000480000001C """ result = [] cp = cp.replace("\n", "") #kq for i in range(0, len(cp), 16): s = cp[i:i+16] a1 = int(s[-2:], 16) a2 = int(s[6:8], 16) result.append(a1) result.append(a2) for i in result: print(chr(i^0x35), end="") ``` ### 3. Flag ISITDTU{Congrats_You_Solved_TLS_Callback_Re01_Have_Fun_:)} --- *Truongdz*