作者:麒麟框架
項目地址:https://qilingframework.github.io/www_zh/
微博:https://weibo.com/sgniwx?is_all=1

二進制分析工具的現狀

物聯網設備正面臨前所未有的威脅。惡意軟件攻擊的對象通常是安全性差或者配置不當的網絡設備。硬件廠商和安全行業都在努力研究各種攻擊行為,以制造更安全的產品。而“針對物聯網設備的攻擊”和“惡意軟件分析”則是這個過程中,我們所面臨的兩個最大的挑戰。

目前“物聯網設備”和“惡意軟件”同時運行于各種不同的操作系統與CPU架構中,逆向工程師需要了解全部CPU架構,這極大的降低了分析效率。同時,很多無法得到及時更新的分析工具,在面對層出不窮的新型攻擊方式時,則顯得捉襟見肘。

而現階段很多二進制分析工具(系統仿真、用戶模式仿真、二進制插樁工具和沙箱), 都只針對單一類型的操作系統或CPU架構,且這些工具間幾乎不可能共享信息或交叉引用數據。 這就是逆向工程的困難所在。

[1]Sonicwall的研究顯示,2018年,惡意軟件攻擊大幅上升,達到105.2億次,創下歷史新高,且網絡犯罪分子使用了新的威脅策略。

解決方案

麒麟框架旨在改變物聯網安全研究、惡意軟件分析和逆向工程的現狀。我們的目標是構建一個跨平臺、支持多體系結構的分析框架,而不僅僅是做一個逆向工具。麒麟框架擁有強大的功能,例如在二進制執行之前或執行期間進行代碼攔截和任意代碼注入。它還可以在執行期間補丁目標二進制文件。

麒麟框架是用Python編寫的開源工具。Python是逆向工程師常用的簡單的編程語言,這極大的降低了二次開發的門檻。

麒麟框架是什么

麒麟框架不僅僅是一個仿真平臺或逆向工程工具。它還將“二進制插樁”和“二進制仿真”結合一起。借助麒麟框架,你可以:
- 動態干預二進制程序執行流程
- 在二進制程序執行期間對其進行動態補丁
- 在二進制程序執行期間對其進行代碼注入
- 局部執行二進制程序,而不是運行整個文件
- 任意補丁“脫殼”已加殼程序內容

麒麟框架能夠模擬:
- Windows x86 32/64位
- Linux x86 32/64位,ARM,AARCH64,MIPS
- MacOS x86 32/64位
- FreeBSD x86 32/64位

麒麟框架能夠在Windows/MacOS/Linux/FreeBSD等操作系統上運行,且不受CPU架構的限制

麒麟框架是如何操作的

演示環境

Hardware : X86 64位 OS : Ubuntu 18.04 64位

Demo #1 獲取Wannacry的斷路器開關地址

麒麟框架運行Wannacry惡意軟件獲取斷路器開關地址

qiling DEMO 1: Catching wannacry's killer switch

代碼樣本

from qiling import *

def stopatkillerswtich(ql):
    ql.uc.emu_stop()

if __name__ == "__main__":
    ql = Qiling(["rootfs/x86_windows/bin/wannacry.bin"], "rootfs/x86_windows")
    ql.hook_address(stopatkillerswtich, 0x40819a)
    ql.run()

執行輸出

0x1333804: __set_app_type(0x2)
0x13337ce: __p__fmode() = 0x500007ec
0x13337c3: __p__commode() = 0x500007f0
0x132f1e1: _controlfp(0x10000, 0x30000) = 0x8001f
0x132d151: _initterm(0x40b00c, 0x40b010)
0x1333bc0: __getmainargs(0xffffdf9c, 0xffffdf8c, 0xffffdf98, 0x0, 0xffffdf90) = 0
0x132d151: _initterm(0x40b000, 0x40b008)
0x1001e10: GetStartupInfo(0xffffdfa0)
0x104d9f3: GetModuleHandleA(0x00) = 400000
0x125b18e: InternetOpenA(0x0, 0x1, 0x0, 0x0, 0x0)
0x126f0f1: InternetOpenUrlA(0x0, "http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com", "", 0x0, 0x84000000, 0x0)

Demo #2 在Ubuntu X64位上模擬ARM路由器固件

麒麟框架動態補丁及模擬ARM路由器固件,把其/usr/bin/httpd在X86_64位 Ubuntu上運行

qiling DEMO 2: Fully emulating httpd from ARM router firmware with Qiling on Ubuntu X64 machine

代碼樣本

from qiling import *

def my_sandbox(path, rootfs):
    ql = Qiling(path, rootfs, stdin = sys.stdin, stdout = sys.stdout, stderr = sys.stderr)
    # Patch 0x00005930 from br0 to ens33
    ql.patch(0x00005930, b'ens33\x00', file_name = b'libChipApi.so')
    ql.root = False
    ql.run()


if __name__ == "__main__":
    my_sandbox(["rootfs/tendaac15/bin/httpd"], "rootfs/tendaac15")

Demo #3 熱修補Windows crackme

麒麟框架熱修補丁Windows crackme程序使其顯示“Congratulation”窗口。

qiling DEMO 3: hotpatching a Windows crackme

代碼樣本

from qiling import *

def force_call_dialog_func(ql):
    # get DialogFunc address
    lpDialogFunc = ql.unpack32(ql.mem_read(ql.sp - 0x8, 4))
    # setup stack memory for DialogFunc
    ql.stack_push(0)
    ql.stack_push(1001)
    ql.stack_push(273)
    ql.stack_push(0)
    ql.stack_push(0x0401018)
    # force EIP to DialogFunc
    ql.pc = lpDialogFunc


def my_sandbox(path, rootfs):
    ql = Qiling(path, rootfs)
    # NOP out some code
    ql.patch(0x004010B5, b'\x90\x90')
    ql.patch(0x004010CD, b'\x90\x90')
    ql.patch(0x0040110B, b'\x90\x90')
    ql.patch(0x00401112, b'\x90\x90')
    # hook at an address with a callback
    ql.hook_address(0x00401016, force_call_dialog_func)
    ql.run()


if __name__ == "__main__":
    my_sandbox(["rootfs/x86_windows/bin/Easy_CrackMe.exe"], "rootfs/x86_windows")

執行輸出

0x10cae10: GetStartupInfo(0xffffdf40)
0x1121fa7: GetStdHandle(0xfffffff6) = 0xfffffff6
0x111fbc4: GetFileType(0xfffffff6) = 0x2
0x1121fa7: GetStdHandle(0xfffffff5) = 0xfffffff5
0x111fbc4: GetFileType(0xfffffff5) = 0x2
0x1121fa7: GetStdHandle(0xfffffff4) = 0xfffffff4
0x111fbc4: GetFileType(0xfffffff4) = 0x2
0x1121fd1: SetHandleCount(0x20) = 32
0x1121fbf: GetCommandLineA() = 0x501091b8
0x111fcd4: GetEnvironmentStringsW() = 0x501091e4
0x1117ffa: WideCharToMultiByte(0x0, 0x0, 0x501091e4, 0x1, 0x0, 0x0, 0x0, 0x0) = 2
0x1117ffa: WideCharToMultiByte(0x0, 0x0, 0x501091e4, 0x1, 0x50002098, 0x2, 0x0, 0x0) = 1
0x111fcbc: FreeEnvironmentStringsW(0x501091e4) = 1
0x1116a0b: GetACP() = 437
0x1121f8f: GetCPInfo(0x1b5, 0xffffdf44) = 1
0x1121f8f: GetCPInfo(0x1b5, 0xffffdf1c) = 1
0x111e43e: GetStringTypeW(0x1, 0x40541c, 0x1, 0xffffd9d8) = 0
0x10ffc95: GetStringTypeExA(0x0, 0x1, 0x405418, 0x1, 0xffffd9d8) = 0
0x111e39c: LCMapStringW(0x0, 0x100, 0x40541c, 0x1, 0x0, 0x0) = 0
0x1128a50: LCMapStringA(0x0, 0x100, 0x405418, 0x1, 0x0, 0x0) = 0
0x111e39c: LCMapStringW(0x0, 0x100, 0x40541c, 0x1, 0x0, 0x0) = 0
0x1128a50: LCMapStringA(0x0, 0x100, 0x405418, 0x1, 0x0, 0x0) = 0
0x111685a: GetModuleFileNameA(0x0, 0x40856c, 0x104) = 42
0x10cae10: GetStartupInfo(0xffffdfa0)
0x11169f3: GetModuleHandleA(0x00) = 400000
0x104cf42: DialogBoxParamA(0x400000, 0x65, 0x00, 0x401020, 0x00) = 0
Input DlgItemText :

        << enter any string or number here >>

0x1063d14: GetDlgItemTextA(0x00, 0x3e8, 0xffffdef4, 0x64) = 3
0x105ea11: MessageBoxA(0x00, "Congratulation !!", "EasyCrackMe", 0x40) = 2
0x1033ba3: EndDialog(0x00, 0x00) = 1
0x1124d12: ExitProcess(0x01)

Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.jmbmsq.com/1062/