使用工具

  • VM
  • 分析工具 : PEBear, DLL Export Viewer
  • 組語除錯工具 : WinREPL
  • C++ ROP Gadget : rp++
  • Debugger : x64dbg, Windbg Preview

Windbg操作

  • | : Process Status ~ : Thread Status
  • 顯示記憶體內容 : d{b|d|q|u} + Ln (顯示N個)
  • 以某種資料結構解讀 : dt (module)!_name + rn (recursive)
  • 對記憶體寫入 : 數值e{b|d|q}, 字串e{a|u|za|zu} (z : 指以NULL做結尾)
  • 暫存器 : r, r [reg] = [val]
  • 取值 : poi
  • 反組譯 : u, uf
  • 斷點 : bp [addr] .if [cond]{} .else{gc}
  • 列出載入的模組 : lm
  • 執行 : go, Step in : t, Step over : p
  • Mapping : !address
  • 查看權限 : !vprot
  • 查看Error Code : !error Value [Flags], Flags=Win32, NTSTATUS…
  • 查看Symbol : x module!symbol

呼叫慣例

  • 流程控制 : call / ret
  • 參數 : 使用 CX, DX, R8, R9, stack
  • Prologue, Epilogue : 保存/恢復上一個frame的RBP

Buffer Overflow

列舉一些危險的函數

  • gets()
  • scanf()
  • stcpy()
  • sprintf()
  • memcpy()
  • strcat()

會覆蓋到在stack frame以下的saved RIP

Dynamic Library

  • Dynamic-Link library
  • ntdll : Native API
  • kernelbase : kerel32中部分函數(偏核心)
  • kernel32 : Win32API
  • msvcrt : Windows Libc

IAT

  • Import Address Table
  • 類似Linux GOT

保護機制

  • DEP : NX
  • Security Cookie : 類似Linux Stack Canary
  • ASLR : library的基址在開機時就決定了, 同一隻DLL在不同Process使用CoW機制
  • CFG : Link時建立function table, 執行期間建立bitmap, 避免indirect jump
    • 只檢查通往的函數, 不會檢查如何過來這個函數
  • CFG-SupressExports mode : 禁止其他合法DLL函數, 不過還是可以利用相同image
  • ACG : 禁止創造RWX segment
  • Child Process Policy : 禁止fork出新的process

Shellcode

  • System call number經常修改

    • 呼叫API -> 需要找出API的位址
  • _TEB : Thread Environment Block

    • 執行緒資訊
    • _NT_TIB : Exception List, Stack
    • PEB位址
    • 由FS/GS指向
  • _PEB : Process Environment Block

    • _PEB_LDR_DATA
    • _LDR_DATA_TABLE_ENTRY
      • InMemoryOrderModuleList : Binary->ntdll->kernel32->kernelbase
    • ProcessHeap
    • Image Base
  • 獲取DLL位址 : 使用GS

    • PEB : GS+0x60
    • PEB->Ldr : PEB+0x18
    • InMemoryOrderModuleList : 獲得kernel32.dll基址 (Ldr+0x20)
      • Binary->ntdll->kernel32
    • 使用 mov rdi, qword ptr [rdi]爬Linked List
    • 從List Node獲得基址 : kernel32+0x20
  • 獲取函數地址 : 利用RVA

    • 需要Export Table
    • NT Header RVA : [kernel32 + 0x3c]
    • NT header : kernel32+RVA
    • Export Directory RVA : [nt_header +4+0x14+0x70]
    • Export Directory : kernel32+RVA
    • Name pointer table RVA : [Export Directory Table + 0x20]
    • Name pointer Table : Export Directory Table+RVA
    • Function Name RVA : [Name Pointer Table + index * 4]
    • 對於每個Index, 爬出Name pointer Table保存的Function Name, 找WinExec
    • Ordinal Table RVA : [Export Directory Table RVA+ 0x24]
    • Ordinal Table : kernel32+RVA
    • Ordinal : Ordinal Table + index * 2
    • Export Address Table RVA : [Export Directory Table + 0x1c]
    • Export Address Table : kernel32+RVA
    • WinExec RVA : Export Address Table + Ordinal * 4
    • WinExec : kernel32+RVA
  • 呼叫函數

    • RCX : cmd.exe
    • RSP對齊0x10 (避免踩到movaps)
    • 呼叫WinExec

Return to Library

  • 用以克制DEP
  • 由於ASLR, 需要洩漏記憶體資訊(相對offset不變)
  • IAT, stack上殘留值, heap上的結構體

File Operation

  • Linux FD = Windows File HANDLE
  • open() = CreateFile() / OpenFile()
  • read() = ReadFile()
  • write() = WriteFile()

Lab1

  • flag1 : 設定RIP跳轉到打印flag處
  • flag2 : 設定RIP跳轉到該函數
  • flag3 : 在XOR處設定Contidional Breakpoint, 使原本存放亂數的RAX變成0

Lab2

  • 換行符號與Linux上不同 : \r\n
  • cyclic找crash offset
  • 覆蓋RIP

Lab3

  • 利用一次任意讀取洩漏IAT上的地址
  • 計算offset獲得kernel32.dll基址
  • 利用BOF呼叫WinExec()