# heaven gate


do cũng đã thấy 1 bài tương tự nên mình cũng đã đoán được phần nào bài này sử dụng kỹ thuật anti debugging: heaven's gate
chạy thử:

thử debug:



có vẻ như không được rồi, chưa có thông tin gì hết.
heaven gate là kỹ thuật có thể chuyển đổi việc thực thi code 64 bit và 32bit trong tiến trình 32bit hoặc ngược lại, gây khó khăn, cản trở việc disassembling và debugging.
Kỹ thuật này mình tìm kiếm trên mạng thấy khá ít thông tin, tuy nhiên ta cũng có thể hiểu được qua qua phần nào cách chương trình hoạt động.
```python
entrypoint
| #32bit
v
call far ptr dword_754488
| #chuyển đổi sang trạng thái 64bit
v
?????????
| #dùng retf chuyển lại về 32 bit
v
call far ptr loc_751347
| #64
v
????????? #nhận đầu vào input và xử lý
| #retfar again??? chưa biết được! khả năng cao là thế!
v
call far ptr word_754512
| #64
v
?????????
```
về cơ chế call far:
đặt breakpoint ngay tại call far, ta để ý địa chỉ instruction tiếp theo và thanh ghi `CS`:

thanh ghi CS đang là `0x23`, địa chỉ instruction tiếp theo là `0x921007`.
tiếp tục ta step into (F7):

ta thấy lệnh `call far` thực hiện push thanh ghi cs, push địa chỉ return vào stack, và đổi thanh ghi `CS` sang `0x33`.
nếu ta chú ý kỹ hơn:

9A = opcode cho call far
ta thấy nó thực sự gọi địa chỉ `0x924158` (tức `58 41 92 00` LE) chứ không phải là `dword_924488` như IDA hiển thị.
vậy lúc này chương trình sẽ tiếp tục thực thi lệnh tại `0x924158` với mode 64bit
đây là lý do tại sao khi ta F7 thì nó lại vào `0x924158` thay vì `0x924488`

để trở về thì chương trình sử dùng lệnh `retf`:

ta tiếp tục F7:


ta thấy con trỏ stack đã lên 8 bytes
tức `retf` thực hiện pop 4 bytes từ stack địa chỉ trở về, pop 4 bytes tiếp theo (phải là 4 bytes vì stack 32bit mỗi ô 4 bytes dù thanh ghi `CS` chỉ chứa 2 bytes) để trả về giá trị thanh ghi `CS` ban đầu đã push.
chương trình tiếp tục thực thi instruction 32 bit:

do không debug được nên mình đã nghĩ ra cách khác
đầu tiên, ta chạy challenge ngoài terminal trước:

lúc này chương trình vẫn đang chờ input
ta sẽ tận dùng khoảng thời gian suspend này để attach vào ida, tiện thể syscall cũng đã được thực thi, nếu debug từ đầu chương trình thì sẽ không được nhập input (sử dụng ida64 vì chỗ này đang trong 64bit):


tuy nhiên ta có thể thấy: nếu debug bằng local windows debugger thì các thanh ghi vẫn đang là 32 bit, tức đây là debugger 32, sẽ không thể debug 1 cách bình thường được.
windbg có thể sử dụng được trong trường hợp này.
khi ta attach sử dụng windbg:

thanh ghi lúc này là 64 bit, tức đang sử dụng debugger 64, ta cũng có thể thấy chương trình đang dừng tại syscall chờ mình nhập input.
tuy code trông khá đẹp, tuy nhiên vùng này vẫn đang thực thi ở môi trường 64 bit nên chỗ assembly kia đã bị gen sai.
để có thể biết chương trình đang làm gì, ta phải đọc được code.
ta lấy địa chỉ vùng code này trước:

`0x751017`
chuyển qua tab output và chọn windbg:

ta sử dụng lệnh có sẵn trong windbg để disassemble opcode x64:
`uf 0x751017`

```
WINDBG>uf 0x751017
Flow analysis was incomplete, some code may be missing
chall+0x1017:
00000000`00751017 4883ec50 sub rsp,50h
00000000`0075101b 65488b042560000000 mov rax,qword ptr gs:[60h]
00000000`00751024 488b4020 mov rax,qword ptr [rax+20h]
00000000`00751028 488b4820 mov rcx,qword ptr [rax+20h]
00000000`0075102c 31d2 xor edx,edx
00000000`0075102e 4531c0 xor r8d,r8d
00000000`00751031 4531c9 xor r9d,r9d
00000000`00751034 488d442410 lea rax,[rsp+10h]
00000000`00751039 4889442420 mov qword ptr [rsp+20h],rax
00000000`0075103e 488d0424 lea rax,[rsp]
00000000`00751042 4889442428 mov qword ptr [rsp+28h],rax
00000000`00751047 c744243008000000 mov dword ptr [rsp+30h],8
00000000`0075104f 48c744243800000000 mov qword ptr [rsp+38h],0
00000000`00751058 48c744244000000000 mov qword ptr [rsp+40h],0
00000000`00751061 4989ca mov r10,rcx
00000000`00751064 b806000000 mov eax,6
00000000`00751069 85c0 test eax,eax
00000000`0075106b 7405 je chall+0x1072 (00000000`00751072)
chall+0x106d:
00000000`0075106d eb01 jmp chall+0x1070 (00000000`00751070)
chall+0x1070:
00000000`00751070 4883ec08 sub rsp,8
chall+0x1072:
00000000`00751072 ec in al,dx
00000000`00751073 080f or byte ptr [rdi],cl
chall+0x1074:
00000000`00751074 0f05 syscall
00000000`00751076 4883c408 add rsp,8
00000000`0075107a 668b0424 mov ax,word ptr [rsp]
00000000`0075107e 0fb7c0 movzx eax,ax
00000000`00751081 668b5c2402 mov bx,word ptr [rsp+2]
00000000`00751086 66895c2440 mov word ptr [rsp+40h],bx
00000000`0075108b 660f6ec0 movd xmm0,eax
00000000`0075108f 660f70c000 pshufd xmm0,xmm0,0
00000000`00751094 660f6fc8 movdqa xmm1,xmm0
00000000`00751098 660f73f902 pslldq xmm1,2
00000000`0075109d 660fefc1 pxor xmm0,xmm1
00000000`007510a1 660f73f904 pslldq xmm1,4
00000000`007510a6 660fefc1 pxor xmm0,xmm1
00000000`007510aa bbb979379e mov ebx,9E3779B9h
00000000`007510af 660f6ed3 movd xmm2,ebx
00000000`007510b3 660f70d200 pshufd xmm2,xmm2,0
00000000`007510b8 bb157c4a7f mov ebx,7F4A7C15h
00000000`007510bd 660f6edb movd xmm3,ebx
00000000`007510c1 660f70db00 pshufd xmm3,xmm3,0
00000000`007510c6 660f6fe8 movdqa xmm5,xmm0
00000000`007510ca 660fefea pxor xmm5,xmm2
00000000`007510ce 660f6ff0 movdqa xmm6,xmm0
00000000`007510d2 660f73de01 psrldq xmm6,1
00000000`007510d7 660feff3 pxor xmm6,xmm3
00000000`007510db 660f6ffd movdqa xmm7,xmm5
00000000`007510df 660feffe pxor xmm7,xmm6
00000000`007510e3 660f6fe6 movdqa xmm4,xmm6
00000000`007510e7 660f38dbe4 aesimc xmm4,xmm4
00000000`007510ec 6689c2 mov dx,ax
00000000`007510ef 66c1c209 rol dx,9
00000000`007510f3 660f7efb movd ebx,xmm7
00000000`007510f7 81e3ffff0000 and ebx,0FFFFh
00000000`007510fd 85db test ebx,ebx
00000000`007510ff 7401 je chall+0x1102 (00000000`00751102)
chall+0x1101:
00000000`00751101 eb00 jmp chall+0x1103 (00000000`00751103)
chall+0x1102:
00000000`00751102 006631 add byte ptr [rsi+31h],ah
chall+0x1103:
00000000`00751103 6631d0 xor ax,dx
00000000`00751106 6631d8 xor ax,bx
00000000`00751109 666bc007 imul ax,ax,7
00000000`0075110d 0fb7c0 movzx eax,ax
00000000`00751110 25ff010000 and eax,1FFh
00000000`00751115 0500010000 add eax,100h
00000000`0075111a 488d3d5a000000 lea rdi,[chall+0x117b (00000000`0075117b)]
00000000`00751121 488d3c07 lea rdi,[rdi+rax]
00000000`00751125 4889fe mov rsi,rdi
00000000`00751128 4881c650010000 add rsi,150h
00000000`0075112f b916000000 mov ecx,16h
chall+0x1134:
00000000`00751134 f30f6f0e movdqu xmm1,xmmword ptr [rsi]
00000000`00751138 660fefcf pxor xmm1,xmm7
00000000`0075113c 660f38decc aesdec xmm1,xmm4
00000000`00751141 660f38dfcd aesdeclast xmm1,xmm5
00000000`00751146 f30f7f0e movdqu xmmword ptr [rsi],xmm1
00000000`0075114a 4883ee10 sub rsi,10h
00000000`0075114e e2e4 loop chall+0x1134 (00000000`00751134)
chall+0x1150:
00000000`00751150 4889fe mov rsi,rdi
00000000`00751153 4881c65f010000 add rsi,15Fh
00000000`0075115a b960010000 mov ecx,160h
00000000`0075115f 4831d2 xor rdx,rdx
chall+0x1162:
00000000`00751162 8a06 mov al,byte ptr [rsi]
00000000`00751164 89d3 mov ebx,edx
00000000`00751166 83e301 and ebx,1
00000000`00751169 8a5c1c40 mov bl,byte ptr [rsp+rbx+40h]
00000000`0075116d 30d8 xor al,bl
00000000`0075116f 8806 mov byte ptr [rsi],al
00000000`00751171 48ffce dec rsi
00000000`00751174 48ffc2 inc rdx
00000000`00751177 e2e9 loop chall+0x1162 (00000000`00751162)
chall+0x1179:
00000000`00751179 ffe7 jmp rdi
```
đây mới là assembly thực sự!
làm theo cách này vừa có thể theo dõi stack, thanh ghi,... dễ dàng trên IDA, vừa xem assembly chuẩn từ windbg
hoặc ta có thể dùng cách sau:
vào mục segment:

edit segment:

chuyển sang 64 bit:

bây giờ ida đã biễu diễn code 64bit:

vì chương trình này hơi khó đọc nên mình tạm tóm tắt chương trình:
```
syscall đọc input -> lấy 4 bytes, truyền 2 bytes đầu vào ax, 2 bytes sau vào bx
-> ax được lấy để gen key tính toán giải mã aes, và tính toán địa chỉ nhảy jmp rdi,
aesdec, aesdeclast thực hiện giải mã 352 bytes tính từ rdi được tính toán trước đó
-> bx xor với 352 bytes được giải mã trước đó để hoàn tất giải mã shellcode
-> jmp rdi để nhảy đến shellcode
```
như vậy ta cần nhập vào input 4 bytes sao cho chương trình tính toán đúng địa chỉ nhảy và shellcode tính từ rdi exec đúng.

trỏ vào rdi:

ban đầu mình nghĩ rằng nếu chỉ nhập 4 bytes thì khả năng chương trình này yêu cầu tìm PIN hay password gì đấy, ngồi dịch ngược rất nhiều thời gian mà không có kết quả gì.
ngồi loay hoay rất lâu thì thử nhập prefix flag vào xem sao:


Ồ được rồi này!
Hóa ra là nhập flag :\(
assembly:
```
WINDBG>uf 0x7513D8
Flow analysis was incomplete, some code may be missing
chall+0x13d8:
00000000`007513d8 65488b042560000000 mov rax,qword ptr gs:[60h]
00000000`007513e1 488b4020 mov rax,qword ptr [rax+20h]
00000000`007513e5 488b4820 mov rcx,qword ptr [rax+20h]
00000000`007513e9 31d2 xor edx,edx
00000000`007513eb 4531c0 xor r8d,r8d
00000000`007513ee 4531c9 xor r9d,r9d
00000000`007513f1 488d442410 lea rax,[rsp+10h]
00000000`007513f6 4889442420 mov qword ptr [rsp+20h],rax
00000000`007513fb 488d0424 lea rax,[rsp]
00000000`007513ff 4889442428 mov qword ptr [rsp+28h],rax
00000000`00751404 c744243008000000 mov dword ptr [rsp+30h],8
00000000`0075140c 48c744243800000000 mov qword ptr [rsp+38h],0
00000000`00751415 48c744244000000000 mov qword ptr [rsp+40h],0
00000000`0075141e 4989ca mov r10,rcx
00000000`00751421 b806000000 mov eax,6
00000000`00751426 85c0 test eax,eax
00000000`00751428 7405 je chall+0x142f (00000000`0075142f)
chall+0x142a:
00000000`0075142a eb01 jmp chall+0x142d (00000000`0075142d)
chall+0x142d:
00000000`0075142d 4883ec08 sub rsp,8
chall+0x142f:
00000000`0075142f ec in al,dx
00000000`00751430 080f or byte ptr [rdi],cl
chall+0x1431:
00000000`00751431 0f05 syscall
00000000`00751433 4883c408 add rsp,8
00000000`00751437 668b0424 mov ax,word ptr [rsp]
00000000`0075143b 0fb7c0 movzx eax,ax
00000000`0075143e 668b5c2402 mov bx,word ptr [rsp+2]
00000000`00751443 66895c2440 mov word ptr [rsp+40h],bx
00000000`00751448 660f6ec0 movd xmm0,eax
00000000`0075144c 660f70c000 pshufd xmm0,xmm0,0
00000000`00751451 660f6fc8 movdqa xmm1,xmm0
00000000`00751455 660f73f902 pslldq xmm1,2
00000000`0075145a 660fefc1 pxor xmm0,xmm1
00000000`0075145e 660f73f904 pslldq xmm1,4
00000000`00751463 660fefc1 pxor xmm0,xmm1
00000000`00751467 bbb979379e mov ebx,9E3779B9h
00000000`0075146c 660f6ed3 movd xmm2,ebx
00000000`00751470 660f70d200 pshufd xmm2,xmm2,0
00000000`00751475 bb157c4a7f mov ebx,7F4A7C15h
00000000`0075147a 660f6edb movd xmm3,ebx
00000000`0075147e 660f70db00 pshufd xmm3,xmm3,0
00000000`00751483 660f6fe8 movdqa xmm5,xmm0
00000000`00751487 660fefea pxor xmm5,xmm2
00000000`0075148b 660f6ff0 movdqa xmm6,xmm0
00000000`0075148f 660f73de01 psrldq xmm6,1
00000000`00751494 660feff3 pxor xmm6,xmm3
00000000`00751498 660f6ffd movdqa xmm7,xmm5
00000000`0075149c 660feffe pxor xmm7,xmm6
00000000`007514a0 660f6fe6 movdqa xmm4,xmm6
00000000`007514a4 660f38dbe4 aesimc xmm4,xmm4
00000000`007514a9 6689c2 mov dx,ax
00000000`007514ac 66c1c202 rol dx,2
00000000`007514b0 660f7efb movd ebx,xmm7
00000000`007514b4 81e3ffff0000 and ebx,0FFFFh
00000000`007514ba 85db test ebx,ebx
00000000`007514bc 7401 je chall+0x14bf (00000000`007514bf)
chall+0x14be:
00000000`007514be eb00 jmp chall+0x14c0 (00000000`007514c0)
chall+0x14bf:
00000000`007514bf 006631 add byte ptr [rsi+31h],ah
chall+0x14c0:
00000000`007514c0 6631d0 xor ax,dx
00000000`007514c3 6631d8 xor ax,bx
00000000`007514c6 666bc008 imul ax,ax,8
00000000`007514ca 0fb7c0 movzx eax,ax
00000000`007514cd 25ff010000 and eax,1FFh
00000000`007514d2 0500010000 add eax,100h
00000000`007514d7 488d3d5a000000 lea rdi,[chall+0x1538 (00000000`00751538)]
00000000`007514de 488d3c07 lea rdi,[rdi+rax]
00000000`007514e2 4889fe mov rsi,rdi
00000000`007514e5 4881c650010000 add rsi,150h
00000000`007514ec b916000000 mov ecx,16h
chall+0x14f1:
00000000`007514f1 f30f6f0e movdqu xmm1,xmmword ptr [rsi]
00000000`007514f5 660fefcf pxor xmm1,xmm7
00000000`007514f9 660f38decc aesdec xmm1,xmm4
00000000`007514fe 660f38dfcd aesdeclast xmm1,xmm5
00000000`00751503 f30f7f0e movdqu xmmword ptr [rsi],xmm1
00000000`00751507 4883ee10 sub rsi,10h
00000000`0075150b e2e4 loop chall+0x14f1 (00000000`007514f1)
chall+0x150d:
00000000`0075150d 4889fe mov rsi,rdi
00000000`00751510 4881c65f010000 add rsi,15Fh
00000000`00751517 b960010000 mov ecx,160h
00000000`0075151c 4831d2 xor rdx,rdx
00000000`0075151f 8a06 mov al,byte ptr [rsi]
00000000`00751521 89d3 mov ebx,edx
00000000`00751523 83e301 and ebx,1
00000000`00751526 8a5c1c40 mov bl,byte ptr [rsp+rbx+40h]
00000000`0075152a 3094b10648ffce xor byte ptr [rcx+rsi*4-3100B7FAh],dl
->vẫn bị dissemle sai
```
có vẻ đoạn code này và đoạn code trước đó rất giống nhau.
dựa vào sự tương đồng này, ta có thể viết script bruteforce (chi tiết mình sẽ giải thích bên dưới)
script bruteforce:
```c=
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <immintrin.h> // AES-NI, SSE
#include <inttypes.h> // PRIu32 nếu cần
static uint16_t rol16(uint16_t v, unsigned r) {
r &= 15;
return (uint16_t)(((uint16_t)v << r) | (uint16_t)(v >> (16 - r)));
}
static int read_file(const char* path, uint8_t** out_buf, size_t* out_sz) {
FILE* f = fopen(path, "rb");
if (!f) { perror("fopen"); return -1; }
if (fseek(f, 0, SEEK_END) != 0) { perror("fseek"); fclose(f); return -1; }
long sz = ftell(f);
if (sz < 0) { perror("ftell"); fclose(f); return -1; }
rewind(f);
uint8_t* buf = (uint8_t*)malloc((size_t)sz);
if (!buf) { fclose(f); return -1; }
if (fread(buf, 1, (size_t)sz, f) != (size_t)sz) { perror("fread"); free(buf); fclose(f); return -1; }
fclose(f);
*out_buf = buf;
*out_sz = (size_t)sz;
return 0;
}
// PE RVA -> file offset
static int rva_to_off(const uint8_t* pe, size_t pe_sz, uint32_t rva, uint32_t* out_off) {
if (pe_sz < 0x400) return -1;
uint32_t e_lfanew = *(uint32_t*)(pe + 0x3C);
if ((size_t)e_lfanew + 0x18 > pe_sz) return -1;
if (memcmp(pe + e_lfanew, "PE\0\0", 4) != 0) return -1;
uint16_t num_sections = *(uint16_t*)(pe + e_lfanew + 6);
uint16_t opt_size = *(uint16_t*)(pe + e_lfanew + 20);
uint32_t sect_off = e_lfanew + 24 + opt_size;
if ((size_t)sect_off + (size_t)num_sections * 40 > pe_sz) return -1;
for (uint16_t i = 0; i < num_sections; i++) {
const uint8_t* sh = pe + sect_off + i * 40;
uint32_t virt_size = *(uint32_t*)(sh + 8);
uint32_t virt_addr = *(uint32_t*)(sh + 12);
uint32_t raw_size = *(uint32_t*)(sh + 16);
uint32_t raw_ptr = *(uint32_t*)(sh + 20);
uint32_t span = virt_size > raw_size ? virt_size : raw_size;
if (virt_addr <= rva && rva < virt_addr + span) {
*out_off = raw_ptr + (rva - virt_addr);
return 0;
}
}
return -1;
}
// kiểm tra pattern cố định
static int contains_big_pattern(const uint8_t* buf, size_t len) {
static const uint8_t pat[] = {
0xF3, 0x0F, 0x6F, 0x0E, 0x66, 0x0F, 0xEF, 0xCF,
0x66, 0x0F, 0x38, 0xDE, 0xCC, 0x66, 0x0F, 0x38,
0xDF, 0xCD, 0xF3
};
size_t patlen = sizeof(pat);
if (!buf || len < patlen) return 0;
for (size_t i = 0; i + patlen <= len; i++) {
if (memcmp(buf + i, pat, patlen) == 0)
return 1;
}
return 0;
}
int main(void) {
const char* path = "C:\\Users\\ADMIN\\Downloads\\chall2\\chall - Copy.exe";
uint32_t base_rva = 0x117b;
unsigned r = 9; //khối code đầu tiên
unsigned m = 7; //khối code đầu tiên
start:
uint8_t* pe = NULL; size_t pe_sz = 0;
if (read_file(path, &pe, &pe_sz) != 0) {
fprintf(stderr, "[-] Failed to read %s\n", path);
return 1;
}
uint32_t base_off = 0;
if (rva_to_off(pe, pe_sz, base_rva, &base_off) != 0) {
fprintf(stderr, "[-] RVA->OFF failed\n");
free(pe);
return 1;
}
uint8_t table_orig[0x45F];
/* kiểm tra bounds before memcpy */
if ((size_t)base_off + sizeof(table_orig) > pe_sz) {
fprintf(stderr, "[-] base_off + table size exceeds file size (base_off=0x%08x pe_sz=%zu)\n", base_off, pe_sz);
free(pe);
return 1;
}
memcpy(table_orig, pe + base_off, sizeof(table_orig));
free(pe);
printf("[*] Start bruteforce ASCII\n");
// ASCII printable range: 0x20 (' ') .. 0x7E ('~')
for (uint32_t a0 = 0x20; a0 <= 0x7E; a0++) {
for (uint32_t a1 = 0x20; a1 <= 0x7E; a1++) {
uint16_t ax_seed = (uint16_t)((a1 << 8) | a0);
for (uint32_t b0 = 0x20; b0 <= 0x7E; b0++) {
for (uint32_t b1 = 0x20; b1 <= 0x7E; b1++) {
uint16_t bx_pair = (uint16_t)((b1 << 8) | b0);
uint8_t table[0x45F];
memcpy(table, table_orig, sizeof(table_orig));
// derive keys (intrinsics)
__m128i xmm0 = _mm_set1_epi32((int)ax_seed);
__m128i xmm1 = _mm_slli_si128(xmm0, 2);
xmm0 = _mm_xor_si128(xmm0, xmm1);
xmm1 = _mm_slli_si128(xmm1, 4);
xmm0 = _mm_xor_si128(xmm0, xmm1);
__m128i const1 = _mm_set1_epi32(0x9E3779B9);
__m128i const2 = _mm_set1_epi32(0x7F4A7C15);
__m128i xmm5 = _mm_xor_si128(xmm0, const1);
__m128i xmm6 = _mm_xor_si128(_mm_srli_si128(xmm0, 1), const2);
__m128i xmm7 = _mm_xor_si128(xmm5, xmm6);
__m128i xmm4 = _mm_aesimc_si128(xmm6);
uint32_t low = (uint32_t)_mm_cvtsi128_si32(xmm7);
uint16_t t = (uint16_t)(low & 0xFFFF);
uint16_t dx = rol16(ax_seed, (unsigned)r); // r = new rol
uint16_t axm = (uint16_t)((ax_seed ^ dx ^ t) & 0xFFFF);
axm = (uint16_t)((uint32_t)axm * (uint32_t)m & 0xFFFF);//m = new mul
uint32_t idx = ((uint32_t)axm & 0x1FFu) + 0x100u;
if (idx < 0x100 || idx + 0x160 > sizeof(table)) continue;
// decrypt 0x160 bytes (16 * 0x10 = 352 bytes)
for (int off = 0x150; off >= 0; off -= 0x10) {
__m128i blk = _mm_loadu_si128((const __m128i*)(table + idx + off));
blk = _mm_xor_si128(blk, xmm7);
blk = _mm_aesdec_si128(blk, xmm4);
blk = _mm_aesdeclast_si128(blk, xmm5);
_mm_storeu_si128((__m128i*)(table + idx + off), blk);
}
// final XOR with bx_pair alternating
uint8_t kb0 = (uint8_t)(bx_pair & 0xFF);
uint8_t kb1 = (uint8_t)((bx_pair >> 8) & 0xFF);
for (uint32_t i = 0; i < 0x160; i++) {
uint32_t pos = idx + 0x15F - i;
uint8_t key = (i & 1) ? kb1 : kb0;
table[pos] ^= key;
}
// check pattern
if (contains_big_pattern(table + idx, 0x160)) {
printf("[+] FOUND! '%c%c%c%c' (ax=%04x bx=%04x idx=%#x)\n",
(char)a0, (char)a1, (char)b0, (char)b1,
ax_seed, bx_pair, idx);
FILE* fo = fopen("out.bin", "wb");
if (fo) {
fwrite(table + idx, 1, 0x160, fo);
fclose(fo);
}
else {
perror("fopen out.bin");
}
/* cập nhật base_rva */
base_rva = base_rva + 352 + idx;
r = table[idx + 215];
m = table[idx + 241];
printf("r = 0x%02x m = 0x%02x base_rva = 0x%08x\n",
table[idx + 215], table[idx + 241], base_rva);
goto start;
}
}
}
}
}
printf("[-] No match found in ASCII range.\n");
return 0;
}
```
các phần trong đoạn script giải trên:
```c
int main(void) {
const char* path = "C:\\Users\\ADMIN\\Downloads\\chall2\\chall - Copy.exe";
uint32_t base_rva = 0x117b;
uint8_t* pe = NULL; size_t pe_sz = 0;
if (read_file(path, &pe, &pe_sz) != 0) {
fprintf(stderr, "[-] Failed to read %s\n", path);
return 1;
}
uint32_t base_off = 0;
if (rva_to_off(pe, pe_sz, base_rva, &base_off) != 0) {
fprintf(stderr, "[-] RVA->OFF failed\n");
free(pe);
return 1;
}
uint8_t table_orig[0x45F];
/* kiểm tra bounds before memcpy */
if ((size_t)base_off + sizeof(table_orig) > pe_sz) {
fprintf(stderr, "[-] base_off + table size exceeds file size (base_off=0x%08x pe_sz=%zu)\n", base_off, pe_sz);
free(pe);
return 1;
}
memcpy(table_orig, pe + base_off, sizeof(table_orig));
free(pe);
```
chỗ này ta extract trực tiếp từ pefile để lấy bytes từ RVA `0x117b` để decrypt
tiếp theo đến:
```c
static int contains_big_pattern(const uint8_t* buf, size_t len) {
static const uint8_t pat[] = {
0xF3, 0x0F, 0x6F, 0x0E, 0x66, 0x0F, 0xEF, 0xCF,
0x66, 0x0F, 0x38, 0xDE, 0xCC, 0x66, 0x0F, 0x38,
0xDF, 0xCD, 0xF3
};
size_t patlen = sizeof(pat);
if (!buf || len < patlen) return 0;
for (size_t i = 0; i + patlen <= len; i++) {
if (memcmp(buf + i, pat, patlen) == 0)
return 1;
}
return 0;
}
```
ta lấy 2 phần code giống nhau của 2 đoạn code để có thể nhận diện khi nào ta đã decrypt đúng.
đây là phần mình extract từ:


ta có thể thấy sự tương đồng giữa 2 đoạn code.
như vậy, khi bruteforce, ta chỉ cần kiểm tra xem phần đã decrypt có chứa các bytes này hay không là được.
tuy nhiên, có một số chỗ không hề giống nhau mà sẽ khác đôi chút, khiến ta phải điều chỉnh script giải lại cho phù hợp:


ta thấy có sự khác nhau giữa 2 chỗ rol và imul trên.
vậy ta có:
```c
uint32_t base_rva = 0x117b;
unsigned r = 9; //khối code đầu tiên
unsigned m = 7; //khối code đầu tiên
```
```c
uint16_t dx = rol16(ax_seed, (unsigned)r); // r = new rol
uint16_t axm = (uint16_t)((ax_seed ^ dx ^ t) & 0xFFFF);
axm = (uint16_t)((uint32_t)axm * (uint32_t)m & 0xFFFF);//m = new mul
```
sau mỗi vòng loop ta update lại giá trị:
```c
base_rva = base_rva + 352 + idx; // rva cũ + độ lớn shellcode + khoảng cách từ rva cũ đến rdi
r = table[idx + 215];
m = table[idx + 241];
printf("r = 0x%02x m = 0x%02x base_rva = 0x%08x\n",
table[idx + 215], table[idx + 241], base_rva);
goto start;
```
output:

flag đến đây đã có dạng `KMACTF{32bit_heaven_crashed_in????????????lish_sysca`
về cơ bản thì đã gần hết Flag rồi nhưng phần cuối sẽ không thể nào tiếp tục bruteforce theo kiểu đấy nữa do khối code được decrypt ra không còn tương đồng với block trước nữa
lúc này ta vẫn có thể đoán được 2 ký tự đầu là `ll` để khớp với chữ `syscall`, vậy ta chỉ cần đoán 2 bytes cuối key xor.
tạm thời decrypt với bx=0, ta xem qua hex editor:

ta dễ dàng thấy có rất nhiều đoạn trùng lặp lặp lại, khả năng cao đây là các bytes `0x00`.
đến đây thì flag có thể là:
`KMACTF{32bit_heaven_crashed_in????????????lish_syscalls}`
tuy nhiên nộp flag thì vẫn chưa chính xác?
ta sẽ xem tiếp mớ 352 bytes opcode cuối cùng nó làm gì

như vậy, chương trình tiếp tục đọc input và so sánh với `to_64bit_hel`
ta nhập hết vào chương trình:

thay thế `to_64bit_hel` vào các dấu `?` ta được flag hoàn chỉnh
Flag: `KMACTF{32bit_heaven_crashed_into_64bit_hellish_syscalls}`
# simple


ta nhận thấy bài này có các dấu hiệu của 1 chương trình C#:



ta mở die:

tức chương trình được viết bằng C# và nhưng được biên dịch thẳng về mã máy native thay vì runtime (tương tự C/C++).
công nghệ này đã từng xuất hiện trong flareon 11
ta có thể tham khảo cách tạo signature tại: https://hshrzd.wordpress.com/2024/12/09/flare-on-11-task-7/
lúc này chương trình đang bị strip symbols nên ta rất khó để phân tích chương trình:

trước tiên ta mở visual studio:

chọn framwork .net core 8.0 và enable native AOT publish:

publish:



tiếp theo ta cài thư viện `Bouncy Castle`:


build bằng lệnh:
`dotnet publish -c Release -r win-x64 -p:PublishAot=true`
mở nó bằng IDA (nên dùng IDA 9 đổ lên) và tạo sig file:

mở file challenge lên vào load file signature vừa tạo vào:

bây giờ chương trình đã có tên hàm rất đẹp:

ta vào hàm `sub_1400A6C40`:

đây chỉ là chương trình decrypt aes đơn giản thôi, tuy nhiên mình thử decrypt và không thành công.
bằng cách nào đấy mình bật scyllahide lên và dump custom sbox ra thì decrypt thành công :\)

sbox chỉ có 255 bytes và phải pad thêm bytes `0x00`, chắc author không để ý hoặc có thể cố tình.
script:
```python=
SBOX = [
0xDE,0x1C,0x5B,0x07,0x0D,0x3F,0xD0,0xBF,0xC2,0x82,0x40,0x25,0xF4,0x7E,0x93,0xDD,
0x39,0x05,0x6A,0x16,0x68,0x5A,0x9B,0x7D,0x09,0xB1,0xCA,0xE4,0xAE,0x37,0x6C,0x62,
0xAF,0xB2,0xC1,0x02,0x75,0x71,0xF1,0xCD,0xA3,0x0B,0xBB,0xA0,0x2B,0x38,0x29,0x7B,
0xFB,0x1B,0x01,0x4D,0x17,0x8E,0xCC,0xFC,0xA4,0xA7,0xE3,0x34,0x12,0x91,0x9A,0x9C,
0x30,0x90,0x31,0x3D,0x61,0x96,0x6B,0x3C,0x15,0x54,0x74,0x84,0x21,0xB5,0x85,0xE2,
0xD8,0xB0,0x44,0x3A,0x7C,0x20,0x0C,0x78,0xFE,0xC4,0x51,0xAB,0xDA,0xB6,0x70,0xEB,
0xE1,0x22,0xD9,0x8B,0x72,0xCF,0xEE,0x2A,0xEF,0xE8,0xE0,0x35,0x65,0x32,0xEC,0x66,
0x5F,0xD3,0xB8,0x77,0x33,0xF0,0x92,0x46,0x58,0xB9,0xD5,0xF6,0xC5,0xBA,0xDB,0xB3,
0x2D,0x3E,0x7F,0x04,0xC7,0x6D,0xA2,0xF3,0xCB,0xFD,0x9D,0x5D,0x98,0x67,0x69,0x6F,
0xFA,0x0A,0xA1,0x95,0x80,0x59,0x1A,0x03,0x97,0x83,0x4A,0x11,0x9E,0xC8,0x06,0x24,
0xB4,0x08,0xF2,0xC9,0x10,0xD2,0x1E,0xBD,0xAA,0x9F,0xD1,0x26,0x2E,0xE6,0x0F,0x60,
0xF7,0xA5,0x79,0xC3,0x76,0x87,0x43,0x5E,0x42,0x47,0x86,0x2F,0x3B,0x56,0x8A,0x41,
0x53,0x81,0x50,0x8D,0x4B,0xA9,0x27,0x4E,0x13,0x4F,0x88,0x63,0x48,0x49,0xD6,0xB7,
0x28,0x6E,0xDC,0x5C,0x23,0xEA,0xBE,0x73,0xE9,0x14,0x1D,0x8F,0x4C,0xFF,0xE5,0x64,
0x94,0x1F,0xC0,0xD7,0xBC,0x55,0xC6,0xDF,0xAD,0x7A,0x0E,0x19,0xA8,0x89,0x57,0x36,
0x45,0xE7,0xF9,0xCE,0xF8,0x8C,0x99,0xF5,0x18,0xA6,0x52,0xED,0xAC,0xD4,0x2C,0x00]
INV_SBOX = [0]*256
for i,v in enumerate(SBOX): INV_SBOX[v]=i
RCON = [0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,0x36]
def xtime(a): return ((a<<1)^0x1B) & 0xFF if (a&0x80) else (a<<1)&0xFF
def mul(a,b):
res=0
while b:
if b&1: res ^= a
a = xtime(a)
b >>= 1
return res & 0xFF
def rot_word(w): return w[1:]+w[:1]
def sub_word(w): return [SBOX[b] for b in w]
def key_expansion(key16):
key = list(key16)
Nk=4; Nr=10; Nb=4
w=[key[i*4:(i+1)*4] for i in range(Nk)]
for i in range(Nk, Nb*(Nr+1)):
temp = w[i-1].copy()
if i % Nk == 0:
temp = sub_word(rot_word(temp))
temp[0] ^= RCON[i//Nk]
w.append([ (w[i-Nk][j] ^ temp[j]) & 0xFF for j in range(4)])
roundkeys = []
for r in range(Nr+1):
rk = []
for c in range(4):
rk += w[r*4 + c]
roundkeys.append(rk)
return roundkeys
def add_round_key(state, rk):
return [s ^ k for s,k in zip(state, rk)]
def sub_bytes(state):
return [SBOX[b] for b in state]
def inv_sub_bytes(state):
return [INV_SBOX[b] for b in state]
def shift_rows(s):
out = [0]*16
for r in range(4):
for c in range(4):
out[r + 4*c] = s[r + 4*((c + r) % 4)]
return out
def inv_shift_rows(s):
out = [0]*16
for r in range(4):
for c in range(4):
out[r + 4*c] = s[r + 4*((c - r) % 4)]
return out
def mix_columns(s):
out = [0]*16
for c in range(4):
col = s[c*4:(c+1)*4]
a0,a1,a2,a3 = col
out[c*4+0] = (mul(a0,2) ^ mul(a1,3) ^ a2 ^ a3) & 0xFF
out[c*4+1] = (a0 ^ mul(a1,2) ^ mul(a2,3) ^ a3) & 0xFF
out[c*4+2] = (a0 ^ a1 ^ mul(a2,2) ^ mul(a3,3)) & 0xFF
out[c*4+3] = (mul(a0,3) ^ a1 ^ a2 ^ mul(a3,2)) & 0xFF
return out
def inv_mix_columns(s):
out = [0]*16
for c in range(4):
a0,a1,a2,a3 = s[c*4:(c+1)*4]
out[c*4+0] = (mul(a0,0x0e) ^ mul(a1,0x0b) ^ mul(a2,0x0d) ^ mul(a3,0x09)) & 0xFF
out[c*4+1] = (mul(a0,0x09) ^ mul(a1,0x0e) ^ mul(a2,0x0b) ^ mul(a3,0x0d)) & 0xFF
out[c*4+2] = (mul(a0,0x0d) ^ mul(a1,0x09) ^ mul(a2,0x0e) ^ mul(a3,0x0b)) & 0xFF
out[c*4+3] = (mul(a0,0x0b) ^ mul(a1,0x0d) ^ mul(a2,0x09) ^ mul(a3,0x0e)) & 0xFF
return out
def aes_decrypt_block(cipher16, key16):
roundkeys = key_expansion(key16)
Nr = 10
state = list(cipher16)
state = add_round_key(state, roundkeys[Nr])
for r in range(Nr-1,0,-1):
state = inv_shift_rows(state)
state = inv_sub_bytes(state)
state = add_round_key(state, roundkeys[r])
state = inv_mix_columns(state)
state = inv_shift_rows(state)
state = inv_sub_bytes(state)
state = add_round_key(state, roundkeys[0])
return bytes(state)
if __name__ == "__main__":
key = bytes([0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x97, 0x75, 0x46, 0x20, 0x63, 0x74])
cipher = bytes([0x8A, 0x23, 0x22, 0x6D, 0xDB, 0x7C, 0x18, 0xB4, 0x22, 0xE8, 0x20, 0x56, 0x0D, 0x57, 0x55, 0x2C, 0x48, 0x10, 0x0C, 0x46, 0xA1, 0x8F, 0x69, 0x63, 0xCB, 0xD0, 0xF2, 0xAB, 0x61, 0x8B, 0x65, 0x82, 0x1C, 0x95, 0x0B, 0xF1, 0x14, 0x06, 0x22, 0x91, 0x29, 0x5C, 0x13, 0x5F, 0xFC, 0xC7, 0xC4, 0xA0, 0x6D, 0xA7, 0xFA, 0x80, 0x04, 0x8B, 0xEF, 0xB2, 0xE8, 0xC8, 0xAC, 0x38, 0x24, 0x7C, 0x79, 0xF4, 0x18, 0x48, 0x3D, 0x3A, 0x3F, 0xFD, 0xDE, 0xAC, 0x18, 0xB0, 0x44, 0xB1, 0x5D, 0xA2, 0xE0, 0xA6])
for i in range(0,len(cipher),16):
pt = aes_decrypt_block(cipher[i:i+16], key)
print(pt.decode(),end='')
#KMACTF{97baa5e0a73cba5e114e5d4024dac31a1d6eb7d8964c4f669389482cebee94db}
```
Flag: `KMACTF{97baa5e0a73cba5e114e5d4024dac31a1d6eb7d8964c4f669389482cebee94db}`
# Elecryptor:

ta xem hàm main:

chương trình thực hiện 1 lệnh powershell, ta decrypt [base64](https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)Remove_null_bytes()&input=SkFCd0FHRUFkQUJvQUQwQUlnQkVBRG9BWEFCSkFHMEFjQUJ2QUhJQWRBQmhBRzRBZEFCZkFFNEFid0IwQUdVQUxnQjBBSGdBZEFBaUFEc0FKQUJ3QUd3QVlRQnBBRzRBUFFCYkFGTUFlUUJ6QUhRQVpRQnRBQzRBU1FCUEFDNEFSZ0JwQUd3QVpRQmRBRG9BT2dCU0FHVUFZUUJrQUVFQWJBQnNBRUlBZVFCMEFHVUFjd0FvQUNRQWNBQmhBSFFBYUFBcEFEc0FKQUJyQUdVQWVRQTlBRTRBWlFCM0FDMEFUd0JpQUdvQVpRQmpBSFFBSUFCaUFIa0FkQUJsQUZzQVhRQWdBRFFBTUFBN0FGc0FVd0I1QUhNQWRBQmxBRzBBTGdCVEFHVUFZd0IxQUhJQWFRQjBBSGtBTGdCREFISUFlUUJ3QUhRQWJ3Qm5BSElBWVFCd0FHZ0FlUUF1QUZJQVlRQnVBR1FBYndCdEFFNEFkUUJ0QUdJQVpRQnlBRWNBWlFCdUFHVUFjZ0JoQUhRQWJ3QnlBRjBBT2dBNkFFTUFjZ0JsQUdFQWRBQmxBQ2dBS1FBdUFFY0FaUUIwQUVJQWVRQjBBR1VBY3dBb0FDUUFhd0JsQUhrQUtRQTdBQ1FBWXdCcEFIQUFhQUJsQUhJQVBRQk9BR1VBZHdBdEFFOEFZZ0JxQUdVQVl3QjBBQ0FBWWdCNUFIUUFaUUJiQUYwQUlBQWtBSEFBYkFCaEFHa0FiZ0F1QUV3QVpRQnVBR2NBZEFCb0FEc0FaZ0J2QUhJQUtBQWtBR2tBUFFBd0FEc0FKQUJwQUNBQUxRQnNBSFFBSUFBa0FIQUFiQUJoQUdrQWJnQXVBRXdBWlFCdUFHY0FkQUJvQURzQUpBQnBBQ3NBS3dBcEFIc0FKQUJqQUdrQWNBQm9BR1VBY2dCYkFDUUFhUUJkQUQwQUpBQndBR3dBWVFCcEFHNEFXd0FrQUdrQVhRQXRBR0lBZUFCdkFISUFJQUFrQUdzQVpRQjVBRnNBSkFCcEFDVUFKQUJyQUdVQWVRQXVBRXdBWlFCdUFHY0FkQUJvQUYwQWZRQTdBQ1FBYndCMUFIUUFjQUIxQUhRQVBRQk9BR1VBZHdBdEFFOEFZZ0JxQUdVQVl3QjBBQ0FBWWdCNUFIUUFaUUJiQUYwQUlBQW9BQ1FBWXdCcEFIQUFhQUJsQUhJQUxnQk1BR1VBYmdCbkFIUUFhQUFyQUNRQWF3QmxBSGtBTGdCTUFHVUFiZ0JuQUhRQWFBQXBBRHNBV3dCQkFISUFjZ0JoQUhrQVhRQTZBRG9BUXdCdkFIQUFlUUFvQUNRQVl3QnBBSEFBYUFCbEFISUFMQUF3QUN3QUpBQnZBSFVBZEFCd0FIVUFkQUFzQURBQUxBQWtBR01BYVFCd0FHZ0FaUUJ5QUM0QVRBQmxBRzRBWndCMEFHZ0FLUUE3QUZzQVFRQnlBSElBWVFCNUFGMEFPZ0E2QUVNQWJ3QndBSGtBS0FBa0FHc0FaUUI1QUN3QU1BQXNBQ1FBYndCMUFIUUFjQUIxQUhRQUxBQWtBR01BYVFCd0FHZ0FaUUJ5QUM0QVRBQmxBRzRBWndCMEFHZ0FMQUFrQUdzQVpRQjVBQzRBVEFCbEFHNEFad0IwQUdnQUtRQTdBRnNBVXdCNUFITUFkQUJsQUcwQUxnQkpBRThBTGdCR0FHa0FiQUJsQUYwQU9nQTZBRmNBY2dCcEFIUUFaUUJCQUd3QWJBQkNBSGtBZEFCbEFITUFLQUFrQUhBQVlRQjBBR2dBTEFBa0FHOEFkUUIwQUhBQWRRQjBBQ2tB):
```
$path="D:\Important_Note.txt";$plain=[System.IO.File]::ReadAllBytes($path);$key=New-Object byte[] 40;[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($key);$cipher=New-Object byte[] $plain.Length;for($i=0;$i -lt $plain.Length;$i++){$cipher[$i]=$plain[$i]-bxor $key[$i%$key.Length]};$output=New-Object byte[] ($cipher.Length+$key.Length);[Array]::Copy($cipher,0,$output,0,$cipher.Length);[Array]::Copy($key,0,$output,$cipher.Length,$key.Length);[System.IO.File]::WriteAllBytes($path,$output)
```
viết chương trình decrypt:
```python=
def decrypt(inp: str, out: str):
data = open(inp,"rb").read()
key = data[-40:]
ct = list(data[:-40])
for i in range(len(ct)):
ct[i] ^=key[i % 40]
open(out,"wb").write(bytes(ct))
print(f"Decrypted")
decrypt(r"C:\Users\ADMIN\Downloads\Important_Note.txt", "lmao.bin")
```

không ra gì cả :\(
ta kiểm tra chương trình kỹ hơn:
chú ý initterm:



hàm `atexit` dùng để đăng ký hàm sẽ thực thi khi `exit()` hoặc kết thúc `main`

```c=
void __fastcall sub_7FF7582416F0()
{
const WCHAR *CommandLineW; // rax
LPWSTR v1; // rsi
HRESULT v2; // eax
HRESULT v3; // ebx
__int64 v4; // rcx
WCHAR v5; // ax
__int16 *v6; // rax
bool v7; // zf
HRESULT Object; // eax
PSID v9; // rdi
PSID SidToCheck; // [rsp+60h] [rbp-A0h] BYREF
BOOL IsMember; // [rsp+68h] [rbp-98h] BYREF
struct _SID_IDENTIFIER_AUTHORITY pIdentifierAuthority; // [rsp+6Ch] [rbp-94h] BYREF
BIND_OPTS pBindOptions[3]; // [rsp+78h] [rbp-88h] BYREF
__int64 v14[7]; // [rsp+B0h] [rbp-50h]
__int16 v15; // [rsp+E8h] [rbp-18h]
__int16 v16; // [rsp+17Eh] [rbp+7Eh] BYREF
WCHAR pszName[264]; // [rsp+180h] [rbp+80h] BYREF
*(_WORD *)&pIdentifierAuthority.Value[4] = 1280;
IsMember = 0;
SidToCheck = 0i64;
*(_DWORD *)pIdentifierAuthority.Value = 0;
if ( AllocateAndInitializeSid(&pIdentifierAuthority, 2u, 0x20u, 0x220u, 0, 0, 0, 0, 0, 0, &SidToCheck) )
{
if ( !CheckTokenMembership(0i64, SidToCheck, &IsMember) )
IsMember = 0;
FreeSid(SidToCheck);
}
if ( IsMember ) // isAdmin?
{
sub_7FF758241330();
return;
}
sub_7FF758241020(); // fake explorer.exe
CommandLineW = GetCommandLineW();
IsMember = 0;
v1 = *CommandLineToArgvW(CommandLineW, &IsMember);
v2 = CoInitializeEx(0i64, 2u);
SidToCheck = 0i64;
v3 = v2;
v15 = 0;
memset(pBindOptions, 0, sizeof(pBindOptions));
pBindOptions[0].cbStruct = 48;
v14[0] = 0x760065006C0045i64;
v4 = 0i64;
pBindOptions[1].grfFlags = 4;
v14[1] = 0x6F006900740061i64;
v14[2] = 0x640041003A006Ei64;
v14[3] = 0x69006E0069006Di64;
v14[4] = 0x61007200740073i64;
v14[5] = 0x210072006F0074i64;
v14[6] = 0x3A00770065006Ei64; // v14 = "Elevation:Administrator!new:"
//
do
{
v5 = *(_WORD *)((char *)v14 + v4 * 2);
pszName[v4++] = v5;
}
while ( v5 );
v6 = &v16;
do
{
v7 = v6[1] == 0;
++v6;
}
while ( !v7 );
*(_OWORD *)v6 = xmmword_7FF758243360;
*((_OWORD *)v6 + 1) = xmmword_7FF758243370;
*((_OWORD *)v6 + 2) = xmmword_7FF758243380;
*((_OWORD *)v6 + 3) = xmmword_7FF758243390;
*((_QWORD *)v6 + 8) = 0x43004500420046i64;
*((_DWORD *)v6 + 18) = 8192055; // v6 = {3E5FC7F9-9A51-4367-9063-A120244FBEC7}
v6[38] = 0;
Object = CoGetObject(pszName, pBindOptions, &riid, &SidToCheck);// /////
v9 = SidToCheck;
if ( Object )
{
if ( !SidToCheck )
goto LABEL_16;
}
else
{
if ( !SidToCheck )
goto LABEL_16;
(*(void (__fastcall **)(PSID, LPWSTR, _QWORD, _QWORD, _DWORD, int))(*(_QWORD *)SidToCheck + 72i64))(
SidToCheck,
v1,
0i64,
0i64,
0,
5);
}
(*(void (__fastcall **)(PSID))(*(_QWORD *)v9 + 16i64))(v9);
LABEL_16:
if ( !v3 )
CoUninitialize();
}
```
hàm này kiểm tra quyền Admin, nếu không có quyền admin thì sẽ spawn 1 app hệ thống yêu cầu quyền admin, khi người dùng chọn allow thì chương trình bh.exe sẽ được tạo với quyền admin.
ta xem hàm `sub_7FF758241020`:
```c=
_BOOL8 sub_7FF758241020()
{
HMODULE ModuleHandleW; // rax
NTSTATUS (__stdcall *NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); // rdi
HMODULE v2; // rax
FARPROC RtlEnterCriticalSection; // r14
HMODULE v4; // rax
FARPROC RtlLeaveCriticalSection; // r15
HMODULE v6; // rax
void (__stdcall *RtlInitUnicodeString)(PUNICODE_STRING, PCWSTR); // rsi
DWORD CurrentProcessId; // eax
HANDLE v9; // rax
void *v10; // rbx
wchar_t *v11; // r12
__int64 v12; // rdi
_QWORD *Buffer; // [rsp+30h] [rbp-D0h] BYREF
__int64 v15; // [rsp+38h] [rbp-C8h] BYREF
__int64 v16; // [rsp+40h] [rbp-C0h] BYREF
__int64 v17; // [rsp+48h] [rbp-B8h] BYREF
char v18[8]; // [rsp+50h] [rbp-B0h] BYREF
char BaseAddress[40]; // [rsp+58h] [rbp-A8h] BYREF
WCHAR Destination[264]; // [rsp+80h] [rbp-80h] BYREF
wchar_t String2[264]; // [rsp+290h] [rbp+190h] BYREF
WCHAR Filename[264]; // [rsp+4A0h] [rbp+3A0h] BYREF
ModuleHandleW = GetModuleHandleW(L"ntdll.dll");
NtQueryInformationProcess = (NTSTATUS (__stdcall *)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG))GetProcAddress(ModuleHandleW, "NtQueryInformationProcess");
if ( NtQueryInformationProcess )
{
v2 = GetModuleHandleW(L"ntdll.dll");
RtlEnterCriticalSection = GetProcAddress(v2, "RtlEnterCriticalSection");
if ( RtlEnterCriticalSection )
{
v4 = GetModuleHandleW(L"ntdll.dll");
RtlLeaveCriticalSection = GetProcAddress(v4, "RtlLeaveCriticalSection");
if ( RtlLeaveCriticalSection )
{
v6 = GetModuleHandleW(L"ntdll.dll");
RtlInitUnicodeString = (void (__stdcall *)(PUNICODE_STRING, PCWSTR))GetProcAddress(v6, "RtlInitUnicodeString");
if ( RtlInitUnicodeString )
{
CurrentProcessId = GetCurrentProcessId();
v9 = OpenProcess(0x438u, 0, CurrentProcessId);
v10 = v9;
if ( v9 != (HANDLE)-1i64 )
{
((void (__fastcall *)(HANDLE, _QWORD, char *, __int64, _QWORD))NtQueryInformationProcess)(
v9,
0i64,
v18,
48i64,
0i64);
if ( ReadProcessMemory(v10, BaseAddress, &Buffer, 8ui64, 0i64) )
{
if ( ReadProcessMemory(v10, Buffer + 3, &v17, 8ui64, 0i64) )
{
GetWindowsDirectoryW(Destination, 0x104u);
wcscat_s(Destination, 0x105ui64, L"\\explorer.exe");
v11 = (wchar_t *)malloc(0x104ui64);
wcscpy_s(v11, 0x104ui64, Destination);
((void (__fastcall *)(_QWORD))RtlEnterCriticalSection)(Buffer[7]);
((void (__fastcall *)(__int64, wchar_t *))RtlInitUnicodeString)(Buffer[4] + 96i64, v11);
((void (__fastcall *)(__int64, wchar_t *))RtlInitUnicodeString)(Buffer[4] + 112i64, v11);
GetModuleFileNameW(0i64, Filename, 0x104u);
v12 = *(_QWORD *)(Buffer[3] + 16i64);
v16 = *(_QWORD *)(v17 + 16);
while ( ReadProcessMemory(v10, &v16, &v15, 8ui64, 0i64)
&& ReadProcessMemory(v10, *(LPCVOID *)(v15 + 80), String2, *(unsigned __int16 *)(v15 + 74), 0i64) )
{
if ( !wcsicmp(Filename, String2) )
{
((void (__fastcall *)(__int64, wchar_t *))RtlInitUnicodeString)(v15 + 72, v11);
((void (__fastcall *)(__int64, wchar_t *))RtlInitUnicodeString)(v15 + 88, v11);
LABEL_15:
((void (__fastcall *)(_QWORD))RtlLeaveCriticalSection)(Buffer[7]);
CloseHandle(v10);
return wcsicmp(Destination, String2) != 0;
}
v16 = *(_QWORD *)v15;
if ( v16 == v12 )
goto LABEL_15;
}
}
}
}
}
}
}
}
return 0i64;
}
```
hàm này có khả năng ngụy trang với các chương trình theo dõi process khiến cho nó trông như 1 process bình thường:
đặt breakpoint:

thử mở list process của IDA:

F8:

vẫn là PID đó:

tuy nhiên các app như task manager thì lại không có tác dụng:

tiếp theo đến hàm `Object = CoGetObject(pszName, pBindOptions, &riid, &SidToCheck);`:

khi ta thực thi chương trình sẽ bật lên app có tên là connection manager, yêu cầu quyền admin.
tiếp theo:
```c
else
{
(*(void (__fastcall **)(...))(*(_QWORD *)SidToCheck + 72i64))(
SidToCheck, // Tham số 'this' (con trỏ đến đối tượng COM)
v1, // Tham số 1: Đường dẫn file để thực thi ("C:\...\bh2.exe")
0i64, // Tham số 2: Tham số dòng lệnh (không có)
0i64, // Tham số 3: Thư mục làm việc (không có)
0, // Tham số 4: ...
5); // Tham số 5: Trạng thái hiển thị (SW_SHOW)
}
```
nếu ta để ý kỹ thì sẽ thấy chương trình bh.exe bật lên với cửa sổ admin.
kỹ thuật này mình chưa rõ lắm nó hoạt động chi tiết thế nào :\(
vậy luồng chính của ta vẫn là nằm trong hàm `sub_7FF6AB4E1330()`, sau khi chương trình có quyền admin.
```c=
int sub_7FF690211330()
{
HMODULE ModuleHandleW; // rbx
HRSRC ResourceW; // rax
HRSRC v2; // rdi
HRSRC v3; // rsi
DWORD v4; // r14d
const void *v5; // rdi
_BYTE *v6; // rsi
HRSRC v7; // rbx
__m128 si128; // xmm2
HMODULE ModuleHandleA; // rax
FARPROC ProcAddress; // rax
_QWORD v12[2]; // [rsp+50h] [rbp-B0h] BYREF
__int128 v13; // [rsp+60h] [rbp-A0h] BYREF
__int64 v14; // [rsp+70h] [rbp-90h]
__int64 v15; // [rsp+78h] [rbp-88h]
__int64 v16; // [rsp+80h] [rbp-80h]
__int128 v17; // [rsp+88h] [rbp-78h]
__int128 v18; // [rsp+98h] [rbp-68h]
__int128 v19; // [rsp+A8h] [rbp-58h]
DWORD NumberOfBytesWritten; // [rsp+B8h] [rbp-48h] BYREF
int v21; // [rsp+BCh] [rbp-44h]
__int64 v22; // [rsp+C8h] [rbp-38h]
int v23; // [rsp+D0h] [rbp-30h] BYREF
__int128 v24; // [rsp+D4h] [rbp-2Ch]
__int128 v25; // [rsp+E4h] [rbp-1Ch]
__int128 v26; // [rsp+F4h] [rbp-Ch]
__int128 v27; // [rsp+104h] [rbp+4h]
__int128 v28; // [rsp+114h] [rbp+14h]
__int128 v29; // [rsp+124h] [rbp+24h]
int v30; // [rsp+134h] [rbp+34h]
CHAR ModuleName[16]; // [rsp+140h] [rbp+40h] BYREF
char v32; // [rsp+150h] [rbp+50h]
CHAR ProcName[16]; // [rsp+160h] [rbp+60h] BYREF
char v34; // [rsp+170h] [rbp+70h]
WCHAR TempFileName[264]; // [rsp+180h] [rbp+80h] BYREF
WCHAR Buffer[264]; // [rsp+390h] [rbp+290h] BYREF
ModuleHandleW = GetModuleHandleW(0i64);
ResourceW = FindResourceW(ModuleHandleW, (LPCWSTR)0x68, L"BIN");
v2 = ResourceW;
if ( ResourceW )
{
ResourceW = (HRSRC)LoadResource(ModuleHandleW, ResourceW);
v3 = ResourceW;
if ( ResourceW )
{
v4 = SizeofResource(ModuleHandleW, v2);
v5 = LockResource(v3);
strcpy((char *)v12, "KMACTF_2025");
v6 = malloc(v4);
memcpy(v6, v5, v4);
sub_7FF6902119D0(v6, v4, (__int64)v12); // RC4
LODWORD(ResourceW) = GetTempPathW(0x104u, Buffer);
if ( (_DWORD)ResourceW )
{
LODWORD(ResourceW) = GetTempFileNameW(Buffer, L"res", 0, TempFileName);
if ( (_DWORD)ResourceW )
{
ResourceW = (HRSRC)CreateFileW(TempFileName, 0x40000000u, 0, 0i64, 2u, 0x80u, 0i64);
v7 = ResourceW;
if ( ResourceW != (HRSRC)-1i64 )
{
NumberOfBytesWritten = 0;
if ( WriteFile(ResourceW, v6, v4, &NumberOfBytesWritten, 0i64) )// ghi file
{
CloseHandle(v7);
si128 = (__m128)_mm_load_si128((const __m128i *)&xmmword_7FF690213A70);
v23 = 104;
v21 = 0;
v15 = 0i64;
v24 = 0i64;
v30 = 0;
v25 = 0i64;
v14 = 0i64;
v26 = 0i64;
v32 = 0;
v27 = 0i64;
v34 = 0;
v28 = 0i64;
v29 = 0i64;
v13 = 0i64;
v17 = 0i64;
v18 = 0i64;
v19 = 0i64;
*(__m128 *)ModuleName = _mm_xor_ps(si128, (__m128)_mm_loadu_si128((const __m128i *)&xmmword_7FF690213488));
*(__m128 *)ProcName = _mm_xor_ps(si128, (__m128)_mm_loadu_si128((const __m128i *)&xmmword_7FF690213498));
ModuleHandleA = GetModuleHandleA(ModuleName);// resolve dll
if ( ModuleHandleA )
{
ProcAddress = GetProcAddress(ModuleHandleA, ProcName);// resolve API CreateProcessW
if ( ProcAddress )
{
if ( ((unsigned int (__fastcall *)(WCHAR *, _QWORD, _QWORD, _QWORD, int, int, _QWORD, _QWORD, int *, __int128 *, _QWORD, _DWORD))ProcAddress)(
TempFileName,
0i64,
0i64,
0i64,
1,
4,
0i64,
0i64,
&v23,
&v13,
v12[0],
v12[1])
&& !(unsigned int)sub_7FF690211BC0()// syscall ???
&& !(unsigned int)sub_7FF690211BD6() )// syscall ???
{
sub_7FF6902119D0(v6 + 1024, 0x65000i64, (__int64)v12);// RC4
v22 = 0x65000i64;
v16 = v15 + 4096;
if ( !(unsigned int)sub_7FF690211BCB()// syscall ???
&& !(unsigned int)sub_7FF690211BE1(v13, v16, v6 + 1024, 413696i64, 0i64) )// syscall ???
{
sub_7FF690211BEC(*((_QWORD *)&v13 + 1), 0i64);
sub_7FF690211BF7(v13, 0i64, 0i64);
}
sub_7FF690211C02(v13, 0i64);
sub_7FF690211C0D(*((_QWORD *)&v13 + 1));
sub_7FF690211C0D(v13);
}
}
}
free(v6);
LODWORD(ResourceW) = DeleteFileW(TempFileName);
}
else
{
LODWORD(ResourceW) = CloseHandle(v7);
}
}
}
}
}
}
return (int)ResourceW;
}
```
hàm này thực hiện giải mã rc4 file pe, tạo process, sử dụng resolve API qua `GetProcAddress` và khá nhiều syscall gây khó phân tích.
ta lấy ra file pe bằng cách nop deletefile đi.

vì chương trình thực hiện decrypt RC4 lần nữa từ bytes 1024 nên ta phải decrypt tiếp
`sub_7FF6902119D0(v6 + 1024, 0x65000i64, (__int64)v12);`
script:
```python=
from Crypto.Cipher import ARC4
def main():
key = b'KMACTF_2025'
data = open(r"C:\Users\ADMIN\Downloads\res4B13.tmp","rb").read()
ct=data[1024:413696]
cipher = ARC4.new(key)
pl = cipher.decrypt(ct)
open("lmao2.bin","wb").write(data[:1024]+pl+data[413696:])
print(f"decrypted")
main()
```
sử dụng kỹ thuật như bài simple để lấy symbol .net native:

chương trình trên sử dụng mã hóa aes cbc:

script solve:
```python=
from Crypto.Cipher import AES
data = open('Important_Note.txt','rb').read()
iv = data[-16:]
key = data[-48:-16]
ciphertext = data[:-48]
pt = AES.new(key, AES.MODE_CBC, iv).decrypt(ciphertext)
pt = pt[:-pt[-1]]
data = pt
key = data[-40:]
cipher = data[:-40]
plain = bytes([c ^ key[i % len(key)] for i, c in enumerate(cipher)])
pt=plain
data = pt
key = data[-40:]
cipher = data[:-40]
plain = bytes([c ^ key[i % len(key)] for i, c in enumerate(cipher)])
print(plain)
#b"Congratulations!!! Here is your Flag: N00b_3ncryp70r_w1th_3l3v47i0n_us3_ICMLu4U7il_C0M_In73rf4c3_4nd_.N37_407_^.^\r\nDon't forget to add the Format Flag (KMACTF{...}) when submitting :3"
```
Flag: `KMACTF{Congratulations!!! Here is your Flag: N00b_3ncryp70r_w1th_3l3v47i0n_us3_ICMLu4U7il_C0M_In73rf4c3_4nd_.N37_407_^.^}`