Simple Reverse - 0x01(Lab - Sacred Arts)
Background
- X86組合語言/基本指令集
-
neg (Negate) instruction
實作:先在執行
neg rax
之前把$rax
設定成2,執行指令之後剛好是2的補數gef➤ set $rax=2 gef➤ info r $rax rax 0x2 0x2 gef➤ ni 0x00000000004010e0 in ?? () gef➤ info r $rax rax 0xfffffffffffffffe 0xfffffffffffffffe
-
X86組合語言/基本指令集/IA32指令:xchg
實作:執行
xchg ah, al
之前先看一下$rax
的狀態gef➤ info r $rax rax 0xfffffffffffffffe 0xfffffffffffffffe gef➤ ni 0x00000000004010e2 in ?? () gef➤ info r $rax rax 0xfffffffffffffeff 0xfffffffffffffeff
Source Code
:::spoiler IDA Pro Disassembler Code
start: ; DATA XREF: LOAD:0000000000400018↑o
; LOAD:0000000000400088↑o
48 C7 C0 02 00 00 00 mov rax, 2
48 C7 C7 1C 10 40 00 mov rdi, offset aTmpFlag ; "/tmp/flag"
48 C7 C6 00 00 00 00 mov rsi, 0
0F 05 syscall ; LINUX - sys_open
49 89 C7 mov r15, rax
EB 0A jmp short loc_401026
; ---------------------------------------------------------------------------
2F 74 6D 70 2F 66 6C 61+aTmpFlag db '/tmp/flag',0 ; DATA XREF: .text:0000000000401007↑o
; ---------------------------------------------------------------------------
loc_401026: ; CODE XREF: .text:000000000040101A↑j
48 83 F8 00 cmp rax, 0
7E 09 jle short loc_401035
EB 41 jmp short loc_40106F
; ---------------------------------------------------------------------------
77 72 6F 6E 67 0A 00 aWrong db 'wrong',0Ah,0 ; DATA XREF: .text:0000000000401043↓o
; ---------------------------------------------------------------------------
loc_401035: ; CODE XREF: .text:000000000040102A↑j
; .text:00000000004010E6↓j
48 C7 C0 01 00 00 00 mov rax, 1
48 C7 C7 01 00 00 00 mov rdi, 1
48 C7 C6 2E 10 40 00 mov rsi, offset aWrong ; "wrong\n"
48 BA 07 00 00 00 00 00+ mov rdx, 7
0F 05 syscall ; LINUX - sys_write
loc_401056: ; CODE XREF: .text:000000000040111E↓j
48 C7 C0 3C 00 00 00 mov rax, 3Ch
48 C7 C7 00 00 00 00 mov rdi, 0
0F 05 syscall ; LINUX - sys_exit
loc_401066: ; DATA XREF: .text:000000000040110B↓o
63 6F 72 movsxd ebp, dword ptr [rdi+72h]
72 65 jb short near ptr loc_4010CA+6
63 74 0A 00 movsxd esi, dword ptr [rdx+rcx+0]
loc_40106F: ; CODE XREF: .text:000000000040102C↑j
48 83 EC 40 sub rsp, 40h
48 C7 C0 00 00 00 00 mov rax, 0
4C 89 FF mov rdi, r15
48 89 E6 mov rsi, rsp
48 C7 C2 32 00 00 00 mov rdx, 32h
0F 05 syscall ; LINUX - sys_read
EB 38 jmp short loc_4010C3
; ---------------------------------------------------------------------------
B3 BA BE B8 84 byte_40108B db 0B3h, 0BAh, 0BEh, 0B8h, 84h
; DATA XREF: .text:loc_4010CA↓o
99 90 8D 92 8B D1 98 9E+ dq 9E98D18B928D9099h, 0D19290D29C8D9A92h, 8F978FBDD1D0888Bh
92 9A 8D 9C D2 90 92 D1+ dq 0CCCDCB92C28C9DC0h, 0CEC2BE8D91D9C7C7h, 0FFFFFFCF82C8CFC7h
FF FF FF db 3 dup(0FFh)
; ---------------------------------------------------------------------------
loc_4010C3: ; CODE XREF: .text:0000000000401089↑j
48 C7 C1 07 00 00 00 mov rcx, 7
loc_4010CA: ; CODE XREF: .text:0000000000401069↑j
48 C7 C3 8B 10 40 00 mov rbx, offset byte_40108B
loc_4010D1: ; CODE XREF: .text:00000000004010EC↓j
48 8D 14 CD F8 FF FF FF lea rdx, ds:0FFFFFFFFFFFFFFF8h[rcx*8]
48 8B 04 14 mov rax, [rsp+rdx]
48 F7 D8 neg rax
86 C4 xchg al, ah
48 3B 04 13 cmp rax, [rbx+rdx]
0F 85 49 FF FF FF jnz loc_401035
E2 E3 loop loc_4010D1
EB 0D jmp short loc_4010FD
; ---------------------------------------------------------------------------
68 65 6C 6C 6F 20 77 6F+aHelloWorld db 'hello world',0Ah,0
; ---------------------------------------------------------------------------
loc_4010FD: ; CODE XREF: .text:00000000004010EE↑j
48 C7 C0 01 00 00 00 mov rax, 1
48 C7 C7 01 00 00 00 mov rdi, 1
48 C7 C6 66 10 40 00 mov rsi, offset loc_401066
48 BA 09 00 00 00 00 00+ mov rdx, 9
0F 05 syscall ; LINUX - sys_write
E9 33 FF FF FF jmp loc_401056
_text ends
end start
:::
Recon
這一題就只是單純的用工人智慧看組語,我的想法是先看一下system call,他先把/tmp/flag
打開[^system_call_大全]1,如果有找到該檔案就會通過cmp然後跳到loc_40106F,並且讀取裡面的內容,然後loc_4010C3就看不懂了,==這時候就直接用gdb跟一下流程==,就會發現其實IDA的翻譯是有問題的,因為後面有一個cmp rax, QWORD PTR [rbx+rdx*1]
,所以就稍微看一下內容是甚麼,
1 |
|
這不就是byte_40108B的所在位置嗎,而實際的rbx+rdx*1
存的內容如下
1 |
|
我們必須修正IDA的錯誤翻譯,可以善用d快捷鍵然後把每一個data長度變成dq,正確翻譯如下
1 |
|
所以整體流程應該就蠻清楚了,這支程式就是先讀取/tmp/flag的資料然後從後面讀取8個bytes後==做了一些操作==和qword_40108B的每一個dq做比較,如果比較的結果不符合就會跳到loc_401035(print出wrong後直接exit(0)),如果每一個dq都是正確的就會到下面的loc_4010FD然後print出一些東西,所以很明顯的是那些==操作==到底做了甚麼事情,如果跟一下gdb就會發現只是
- 把數值變成負數
- 交換ah和al暫存器
Exploit
- 先把ah和al的數值交換
- 取補數 ```python= fake_flag = [“8D909984B8BEBAB3”, “8D9A929E98D18B92”, “D0888BD19290D29C”, “8C9DC08F978FBDD1”, “D9C7C7CCCDCB92C2”, “C8CFC7CEC2BE8D91”, “FFFFFFFFFFFFCF82”] BIG_NUM = 1«64 FLAG = [] for i in fake_flag: tmp = i[:12] + i[14:16] + i[12:14] print(tmp) tmp = BIG_NUM - int(tmp, 16) FLAG.append(bytes.fromhex(hex(tmp)[2:]).decode(‘utf-8’)[::-1])
print(““.join(FLAG)) ```
Reference
-
如果要打開的檔案存在則$rax的數值就會是一個大於零的數值,反之就會是小於零 ↩