---
# System prepended metadata

title: reverse 2022 edu ctf

---

# reverse 2022 edu ctf

## [LAB] Sacred Arts

![](https://i.imgur.com/cNiNySn.png)

先open /tmp/flag

![](https://i.imgur.com/lnSCrMB.png)

沒辦法open的話， print wrong 程式結束
可以open的話，讀裡面的資料，然後 jmp short loc_4010c3

![](https://i.imgur.com/H3cw7sS.png)


loc_4010c3的行為是將 /tmp/flag 裡的 data 做2的補數，交換eax的高八位和低八位，最後跟 byte_40108B 每8個byte做比較，正確的話jmp loc_4010fd 輸出correct



```python
with open('./byte_40108B') as f:
    t = f.readlines()
t = [i.strip() for i in t]

#xchg al, ah
t = [bin(int(i,16))[2:] for i in t]
t = [i[:-16] + i[-8:] + i[-16:-8] for i in t]

#neg rax
t = [int(i, 2)-1 for i in t]
mask = int('1'*64, 2)
t = [i^mask for i in t]
t = [bin(i)[2:] for i in t]

s = ""
for i in t:
    i = i.rjust(64, '0')
    for j in range(0,64,8):
        s += chr(int(i[j:j+8],2))

print(s[::-1])

```
用python 模擬即可得flag
![](https://i.imgur.com/btA36VC.png)



## [LAB] Kekkou

![](https://i.imgur.com/fGF3Dd4.png)

把檔案丟進ida 觀察main function，程式的行為是輸入flag，call sub_11f1, sub_125f再用sub131c的result做判斷，正確就輸出correct


![](https://i.imgur.com/blD8SFL.png)
sub_11f1 的行為是傳一個structure *a1和char** flag當參數

![](https://i.imgur.com/XIksdfc.png)

用 gdb 觀察 sub_11f1 行為，發現做完後會將剛剛的 flag[i] 用linked list的形式  存在 a1

![](https://i.imgur.com/UnVysrQ.png)






sub_125f  的行為是將 linked list 的 data xor byte_4040[idx+2]

![](https://i.imgur.com/SbqByxc.png)

sub131c 確認 linked list 的 data 是否和 arr410 相同

![](https://i.imgur.com/g2mRBUe.png)


把 function 名子改成看得懂的，然後在將剛剛的 sub_125f (對input做xor的function) 設斷點，然後用gdb看 linked-list裡面存的值被xor後變成了多少。

![](https://i.imgur.com/0fAjv7Y.png)

- 將 input做完xor後 存在 linked list 裡的值用 gdb print出來

( input xor $X_i$ ) xor input = $X_i$， 因此能知道 input 裡每一個 byte 會 xor 甚麼值，然後再把 arr410[i] xor $X_i$ 就能回推出正確的 input 了

```python
with open('xor_output', 'r') as f:
    t = f.read()
after_xor = [t.split('\n')[i] for i in range(1, len(t.split('\n')), 2)]
after_xor = [i.split(': ')[1] for i in after_xor]
mod = []

for i in range(65):
    input_i = 49+(i+1)
    x = input_i ^ int(after_xor[i], 16)
    mod.append(x)
    
arr410  = "41 92 41 47 EF BC 65 8B  F2 6F 75 5F 6D 75 DF 9A 5F B3 8F 61 89 31 61 F5  3F 5D 61 69 8F 21 9D 96 A7 61 5C EC 03 5F 70 3C  C0 DC 79 56 6E 25 6F 5F BD DD 72 FF 73 34 69 B5  6D 58 5F 0C 49 40 72 C8 5D"
arr410 = [i for i in arr410.split(' ') if i != '']
correct_input = []
for i in range(65):
    correct_input.append(int(arr410[i],16) ^ mod[i])
    
t = b""
for i in correct_input:
    t += (i).to_bytes(1, byteorder='big')
print(t)

```
執行python script後得 
![](https://i.imgur.com/OieBHNa.png)





## [LAB] Why
![](https://i.imgur.com/StuxIz1.png)

用ida看 main的結構，why的行為是檢查輸入值 -10 後是否等於 enc_flag ，是的話 pass = 1

![](https://i.imgur.com/yPyM3lq.png)

![](https://i.imgur.com/LYY96Iv.png)

從fini_array可以看到有sub_11f8 若 pass 則 correct

![](https://i.imgur.com/7nctkzu.png)

 gdb

![](https://i.imgur.com/oYm3eOL.png)

 ida

不知道為甚麼用ida 看是檢查輸入值 -10 後是否等於 enc_flag，gdb是+10


```python
#gdb
with open('enc_flag') as f:
    t = f.read()
t = [int(i, 16) - 10 for i in t.split()]
t = [chr(i) for i in t]
print(''.join(t))


#ida
with open('enc_flag') as f:
    t = f.read()
t = [int(i, 16) + 10 for i in t.split()]
t = [chr(i) for i in t]
print(''.join(t))
```

-10 跟 +10 都試試看，ida好像寫錯了

![](https://i.imgur.com/RLhYCtn.png)


## [HW] trace


ㄧ

![](https://i.imgur.com/ebxW317.png)

執行一遍，程式行為是輸入flag錯了就 print wrong，用ida 看main，稍微分析後重新命名function name，第十行call了一個奇怪的東西先不管他往下看

![](https://i.imgur.com/nH5h5Cz.png)

- fork_child() : fork 一個process 成功的話執行cs_2022_fall_ouo

![](https://i.imgur.com/KyXMCep.png)

- cs_2022_fall_ouo() : 執行/tmp/cs_2022_fall_ouo， argv[1]是 cs_2022_fall_ouo，由此可知剛剛main裡第十行應改是寫了一個elf 到 /tmp/cs_2022_fall_ouo


fork child process 後進入一個無限迴圈執行兩個function: single_step_getReg()，readAddr()


![](https://i.imgur.com/lQW3oyF.png)

- single_step_getReg() : child 往前走一步然後 load child 的registers 進 regs


![](https://i.imgur.com/YfMtTZO.png)
- readAddr() : 若regs_80 (regs+0x80) == 0xe8cbccdeadbeefe8 就把regs_80 換成0x90909090909090，因為90 是 nop 的 machine code，推測regs_80 是program counter的address，若program counter指到的地方存的值是 0xe8cbccdeadbeefe8 就換成 換成0x90909090909090


![](https://i.imgur.com/W3APrLn.png)

先執行看看剛剛的 child process在幹啥
![](https://i.imgur.com/xvC7IOV.png)
![](https://i.imgur.com/AJJSGVj.png)

用ida 看 /tmp/cs_2022_fall_ouo在做啥，call了一個奇怪的ptr 還有 int 3，看起來不太合理

![](https://i.imgur.com/DGbCVxW.png)

用hex editor把0xe8cbccdeadbeefe8 取代成0x90909090909090

![](https://i.imgur.com/MrzHAbg.png)

再用ida分析可以發現行為變得稍微正常了，plz() 和 give_me_flag() print了一些無關緊要的東西


![](https://i.imgur.com/7IFHlsE.png)

- xor_s2_0_to_0x15() : 把s2 前 15個bytes xor 0x71

![](https://i.imgur.com/2dzNPxl.png)

- compare_and_print_():輸入 flag 若 == s2 就輸出 well done!

```python
with open('s2', 'r') as f:
    t = f.read()
t = t.split()
t = [int(i,16) for i in t]
for i in range(0x17):
    t[i] ^= 0x71
t = [chr(i) for i in t]
print(t)
print("".join(t))
```

執行後可得
![](https://i.imgur.com/EdajJK2.png)





## [HW] pwn_myself


執行之後看起來毫無反應就直接exit了，用ida分析找到一個叫做main的function，main function會確認user的權限，權限太低就離開。改用root執行並且在main附近設個中斷點，用gdb 看 callstack 找到 readKeyboard 這個 function


![](https://i.imgur.com/GVYltqJ.png)

readKeyboard的行為是讀取鍵盤的輸入經過一連串判斷後進入set_string

![](https://i.imgur.com/v0QqSHx.png)

set_string 給arrr[0:44] 賦值，當index == 44 進入 printflag()

![](https://i.imgur.com/afAuB4b.png)

print_flag 第十行先設置 sending_buf 若 sending_buf 前48個char 都等於 flag0 用 udp 傳出text，否則傳出 sending_buf，看來這邊的關鍵是第十行的set_buf()

![](https://i.imgur.com/aekPkKD.png)


進去set_buf裡面看，第16行推測是根據剛剛 set_string 裡 arr的內容來加密後賦值給 sending_buf。

![](https://i.imgur.com/CPQUi6G.png)
![](https://i.imgur.com/ngSkBHW.png)

因為 set_buf() 前面幾行的function點進去看也不知道在幹嘛，且題目提示有使用 openssl，所以用 ida 提供的flair70製作openssl的signature 檔

![](https://i.imgur.com/xuDLJiT.png)


將剛剛製作的openssl.sig load進ida，可以看到第十五行變成aes128cbc加密，推測這邊的行為是將 text2_near_flag, text1_near_flag 當做iv或key 然後對arr加密後傳給sending_buf，因此將 flag0 用 aes128 解密就能知道要將arr是多少

![](https://i.imgur.com/dSJSLdI.png)


![](https://i.imgur.com/EmLUdUD.png)



--- 

## [LAB] AMessageBox
![](https://i.imgur.com/UWjBIZB.png)

觀察程式行為發現隨便輸入個flag會跳出一個msgBox

![](https://i.imgur.com/TNxK0Gf.png)

user32.dll->MsgBox
從符號的視窗中將所有跟msgbox有關的function設置breakpoint


![](https://i.imgur.com/V4AWW2p.png)

- call stack


![](https://i.imgur.com/hRMxF7Y.png)

從上圖的call stack可以找到疑似處理flag的function

![](https://i.imgur.com/zeo7VuG.png)

第一層的判斷是比較amessagebox_904ac0c699abc2f6.B63018和 flag 兩個string的長度，若相同則進入下一關

![](https://i.imgur.com/jX2Xz32.png)

第二層的判斷是將flag的每個字元做 rol 2 和 xor 87 後若與b63018的string相同，則進入下一層
![](https://i.imgur.com/HUEo7oO.png)

```python
t = "B5 E5 8D BD 5C 46 36 4E 4E 1E 0E 26 A4 1E 0E 4E 46 06 16 AC B4 3E 4E 16 94 3E 94 8C 94 8C 9C 4E A4 8C 2E 46 8C 6C"
for c in t.split():
    n = "{:08b}".format(int(c,16) ^ 0x87)
    n = n[-3:] + n[:-3]
    print(chr(int(n, 2)), end='')
```
做完運算結果為 FLAG{8699314d319802ef792b7babac9da58a}

## [LAB] IAT Hook -------------------------
## [LAB] GetProcAddress-------------------------



## [HW]ooxx


![](https://i.imgur.com/jC4DBKO.png)


遊戲結束時會跳出msgbox


![](https://i.imgur.com/ZkisaA7.png)

從符號裡面把msgbox都設斷點

![](https://i.imgur.com/5EeQD2Z.png)

從呼叫堆疊裡面找是誰call msgbox

![](https://i.imgur.com/8eqbk3n.png)

![](https://i.imgur.com/PX5xVR2.png)



assembly 看不懂用ida看，可以看到這邊有三個條件print出各種不同的結果推測其行為是確認:贏或輸或平手


![](https://i.imgur.com/SBabL7h.png)


進去check()裡面看，很明顯這邊是判斷如果2連成線對手就贏了，val存的是每個格子裡是X或是O

![](https://i.imgur.com/6YPV2Id.png)

找到val的位置在(.data +d388)


![](https://i.imgur.com/DZe2d3J.png)



![](https://i.imgur.com/qMBwPH9.png)


用cheat engine打開oxox，找到val的位置 7FF6B1B4D338 (ooxx.exe.text+d388)

![](https://i.imgur.com/kgh9xed.png)

![](https://i.imgur.com/kJfP0B6.png)



cheat engine有個功能可以看哪些instruction 在修改 指定address的值，隨便走一步後，可以看到這行 count為1的 **mov [rcx+rax*4],00002** 修改了val

![](https://i.imgur.com/H99Y4XP.png)

![](https://i.imgur.com/cpSCPSa.png)


把 **mov [rcx+rax*4],00002** 改成 nop 後對手的行為就開始變得異常了

![](https://i.imgur.com/gVi5VBX.png)





## [HW] trojan

![](https://i.imgur.com/LOZ1nmm.png)

用 wireshark 開 log.pcapng
![](https://i.imgur.com/hHvOhJL.png)


用 ida 找到 winmain，從 pcapng 推測 while loop 前面幾行是在localhost:19832 bind 一個 tcp server

![](https://i.imgur.com/QmuizEw.png)

用 x64dbg 分析，在 sreeenshot() 可以看到一個 png檔的路徑，png檔打開來看是螢幕截圖


![](https://i.imgur.com/HJGif31.png)


winmain 第十行的 function把 callBack 綁到 (v7+0x64)，第十一行的 function 行為是設定socket，最後createThread()


![](https://i.imgur.com/Jo1AXbn.png)


callback()的行為是收一個512 bytes的 bufffer，比較其是否等於 "cDqr0hUUz"，若等於讀取 **/temp/_____.png** 的 bytes，tcp 回傳 png 檔案 bytes數，然後第二十行的encrypt 對每一個bytes xor，最後把 加密後的 bytes 由 tcp 回傳


![](https://i.imgur.com/JkPkzSy.png)


把剛剛 log.pcappng tcp 回傳的第二個封包裡 的 bytes 覆蓋 /temp/_______.png，tcp server 再次 callback() 時剛剛的 encrypt() 會把 bytes xor 成未加密的模樣並回傳給client



```python
import socket

host = "127.0.0.1"
port = 19832                   # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.sendall(b'cDqr0hUUz1')
data = s.recv(1024) # drop
data = s.recv(999999)
with open('./data.png', 'wb') as f:
    f.write(data)
s.close()

```
python script執行完，可得一png檔

![](https://i.imgur.com/ES9MLKL.png)



---

## [LAB] Exception [12]
## [LAB] TLS Callback [11]
## [LAB] Meow [11]



## [HW] dropper


![](https://i.imgur.com/fOBKh0D.png)

用 die看發現 dropper 是用 upx 加殼

![](https://i.imgur.com/yMbK3rR.png)

用 upx 脫殼

![](https://i.imgur.com/iQayck9.png)

ida 看 main，可以觀察到 CS_2002 字樣和一些疑似加密解密的動作


![](https://i.imgur.com/7cDkaUY.png)

用 x64dbg 分析 callstack 程式最後是跑到這行就停住了，這邊的行為是 sleep(9a7ec800)，手動把 ecx 改成0，往下走幾步就能看到flag了

![](https://i.imgur.com/xNgTomI.png)





___
## note
IAT - import address table

gdb 

    x *(void**)0x600fe8
    
As @zwol mentioned in the comment, gdb needs type information about the operand to decide its size. This type casting tells gdb that 0x600fe8 is a pointer to a pointer.

python [gdb.execute('ni') for i in range(50)]
![](https://i.imgur.com/G6aFAuk.png)
    
---
## x86 instruction
- lea (load effective address)
    - lea eax, [ebp+8]
    - eax = (ebp + 8)
    - mov eax, [ebp+8]
    - eax = *(ebp + 8)
--- 
## 看瞴
![](https://i.imgur.com/3QvBhmj.png)
https://youtu.be/1EAV4XeQ8C4?t=5451
### PEB(process enviroment block) 
![](https://i.imgur.com/jxY66MC.png)

![](https://i.imgur.com/Ap4k26v.png)
### handle
### hmodule





