# reverse(逆向工程) ## 基本知識 從source code 到 執行檔會經過 1. preprocess:將library或一些定義的東西全部展開,可利用gcc -E <file.c>來查看 2. compile:將高階語言轉換成組合語言,可利用gcc -S -masm=intel <file.c>查看 3. assemble:將組合語言轉換成0101的machine code,可利用gcc -c <file.s> 4. link:將生成的object的file連接起來變為執行檔,可利用gcc <file.o> ## 基本工具 ### Static analysis - file:可以用來看file的type - strings:會輸出file中可以輸出的字串 - 參數 -n:最小輸出字串n長度 - 參數 | grep n :抓取相關字串 - nm :會顯示compiler中的symbol - readelf:展示關於ELF的檔案 - 參數 -a :顯示全部 - 參數 -S :只看section header - objdump:顯示object的內容 - 參數 -M intel -d :將machine code轉為組合語言 ### Dynamic analysis - strace:可以看程式執行時call了那些系統call - Itrace:可以看程式執行時call了那些library call - gdb:為GNU的Debugger - 下載: - git clone https://github.com/longld/peda.git ~/peda - git clone https://github.com/scwuaptx/Pwngdb.git ~/Pwngdb - cp ~/Pwngdb/.gdbinit ~/ - 概念:可以用來即使追蹤程式,可以設置變數與設定數值 - 語法: - break:設定斷點 - run:執行程式 - next:執行下一行 - step:進入function中(一般用next會直接做完function) - finish:直接完成funciton - print:輸出數值 - set:設定記憶體數值 - into break:查看斷點 - info register:查看占存器 - 相關連結: https://gist.github.com/rkubik/b96c23bd8ed58333de ## x86-64 組合語言(intel) ### 名詞 - register(rax):用來儲存東西的(像address 或 狀態等) - stack:儲存local variable或address的 ### 語言 - mov dst src(移動) - add,sub,imul,idiv,and,or,xor dst src(運算子) - inc,dec,neg,not dst(只需一個參數,像加一,not) - cmp val1,val2(比較) - jump,ja,jb,jna,jbe,je,jne,jz label(跳到label) - nop (不做任何事) - syscall(系統函式呼叫) - push,pop val ## Tips ### Patch binary 可以利用hexedit來修改machine code ### Hook function 可以用來重新定義原本function中的意義,做出新的function定義,安插在library前 ## decompile 工具 - Ghidra - IDA Pro(Hex-Rays) 以上工具可以把machine code轉為較能看得懂高階語言,同時也能做hook,patch binary或string得查找功能。但其還是有許多限制,像目前只能翻譯c和c++在x86-64下的程式,並且可能會因為compiler的優化或被加殼的原因,而造成難以看懂 - Z3-solver 可用satisfiability modulo theories,類似可以解各式邏輯問題,當我們給其一些constraint時,他會幫我們找到其符合的解 - Angr 類似IDA,但適用於各種語言(輸入為binary的檔案),他會將其轉為自己使用的語言,且為symbolic execution,且因為其含有Z3-Solver,固可以其可以解一些conditional range。 # 網路攻防戰week12 reverse ## 1 ![](https://i.imgur.com/KbovSgg.png) 這個是先用strings顯現出內容再用grep把要的資訊擷取出來 ## 2 ![](https://i.imgur.com/apgyYNX.png) 這個是先用chmod +x 把讓檔案變成可執行的,接著用strace ./檔案 來查看其所用的system call,會發現檔案在write中,故用 strace -s 1024 使用輸出的字元增加來看到全部內容 # 網路攻防戰week13 reverse ## 1(上課展示) ``` #include <stdio.h> #include <stdlib.h> #include <time.h> int foo(int a, int b) { puts("this is foo"); int c = a + b; return c; } int main() { srand(time(0)); int x, y; scanf("%d%d", &x, &y); int out = foo(x, y); if (out == rand() % 0x4000000) { puts("this is 0xdeadbeef"); } return 0; } ``` 在這支程式中,我們輸入x,y來看其相加是否與rand() % 0x4000000的值相同,但理論上我們不可能這麼幸運能夠猜到這個答案,故我們用hook function來將其hook起來,換成其他含式。 1. 用readelf -a a.out,找出在dynsym中是否有rand這個function,可以發現在最dynsym最下面有rand,故可以利用hook function來掉包他![](https://i.imgur.com/m6WDq9T.png) 2. 用man 3 rand,來查找rand的prototype的形式,可以發現input式void,output是int,故等等的hook function需要與其也相同的形式![](https://i.imgur.com/FnjRlNC.png) 3.寫一個與rand相同prototype的library,`int rand(void) { return 0; }`,並用gcc -fPIC -shared rand.c -ldl -o rand.so,將其編譯成share library,並以LD_PRELOAD=./rand.so ./a.out,這樣我們就將rand這個function被我們定義的所hook起來,這樣我們輸入時就rand的答案永遠為0(我們可以利用ldd ./a.out來看其load library的順序,故當我們寫LD_PRELOAD=./rand.so ./a.out,我們將rand.so這個library放在原本的library前面,如此一來我們就可以將其掉包) ## 常用的hookfunction https://github.com/zardus/preeny ## 2 使用patch來得到答案 我們目前得到一個檔案,啟動後發現其要我們猜數字,故猜測這是一個猜數字然後看是否相等的遊戲。 1. 先用objdump -d guess_2 ,來看其大概做了那些操作,可以發現在2e、33的位置有call隨機的function,接下來做一連串操作,發現在8d的地方有比較,並看是否相同來跳,故猜測我們輸入的數字後,會根據cmp是否相同來看是否輸出答案,故我們可以利用patch來將75 5e(jne),改成nop,讓其直接繼續執行![](https://i.imgur.com/mWdJlX3.png) 2. 使用python來看nop的16進位為多少,可以得知為90,故我們可以將75 5e改成90 ``` Python 3.8.10 (default, Sep 28 2021, 16:10:42) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information.>>> from pwn import* >>> context.arch = "amd64" >>> asm("nop") b'\x90' ``` 3. 可以看到bne的位置在400b93,開啟hexedit去全找b93,並將75 5e改成90 90,在執行後,可以發現隨邊輸入數字都能獲得答案,可以看到jne被改成nop了![](https://i.imgur.com/lYCGB0a.png) ## 3 使用IDA + angr 1. 這題給了一個程式,先用IDA打開,可以發現其在判斷一個參數是否與2相同,相同就輸出correct,![](https://i.imgur.com/zDN6pw3.png) 2. 轉到組合語言看,可以發現其輸出correct後有call一個put,故我們讓程式直接跳到這個put就能得到答案,看到其從記憶體的400602開,故等等讓angr跑到那裏![](https://i.imgur.com/3jVeBr7.png) 3. 以下為script ,但不知為甚麼無法啟動,故最後是用一行行跑出結果 ``` import angr import claripy project = angr.Project("./ais3_crackme-2f923b31101b28928009ceb1a816dcae") argv1 = claripy.BVS("argv1", 100*8) initial_state = project.factory.entry_state( args=["./ais3_crackme-2f923b31101b28928009ceb1a816dcae", argv1] ) sm = project.factory.simulation_manager(initial_state) sm.explore(find=0x400602) found = sm.found[0] solution = found.solver.eval(argv1, cast_to=bytes) print(repr(solution)) ``` ![](https://i.imgur.com/jfJeNRf.png) # OllyDbg reference:[https://blog.csdn.net/eastmount/article/details/108708564](https://) ## 簡介 其為一個結合IDA與SoftICE的逆向工程軟體,其結合動態與靜態分析的軟體。 ### 常用快捷鍵 1. F2 設置斷點,程序運行到此處會暫停,再按一次會刪除斷點 2. F9 開始運行程式 3. F8 一次走一步,遇到CALL不會進入子程序 4. F7 一次走一步,但會進入子程序 5. F4 運行到預選位置 6. CTRL+F9 執行到返回 ## 掃雷實戰 從這裡下載掃雷遊戲[https://github.com/eastmountyxz/Reverse-Engineering-01-Saolei](https://) 1. 先將OllyDbg載入掃雷遊戲,因為遊戲開始時會呼叫視窗,故我們可以先找到BEGAINPAINT,設置breakpoint,![](https://i.imgur.com/gy1HsOS.png) 2. 發現BegainPaint和EndPaint中間有call別的函數,follow進入這個function中![](https://i.imgur.com/09QvTyn.png) 3. 除了有開啟畫面的call外,其在遊戲進行時畫面並沒有閃爍,故猜測其利用BITBLT,設立breakpoint進入後發現其有一個雙重迴圈,且猜測掃雷遊戲是由一個二維陣列組合而成,結合這個雙重迴圈,猜測是在這裡設置雷點的位置,觀察這個程式,其一開始先將ESI歸零(用XOR自己的方式)並做比較,並用INC來加一,顧可以猜測ESI是判斷迴圈是否跳出的iterator,再看較小的迴圈發現,其call MOV EBX+ESI,而ESI再後面也有加1的動作,所以猜測EBX是一個基本位置,然後ESI來增加位置,故我們先跟進EBX的register來觀察![](https://i.imgur.com/NTGZznl.png) 4. 從EBX可以觀察,10一開始出現許多,但到後面期很長才會出依次,猜測其時為圖示的邊界,而0F出現的次數比8F多,猜測8F是地雷,0F是安全的地方,實際開啟地雷遊戲後測試,發現確實在第9個位置出現地雷,並對照其他出現地雷的地方,與圖上8F的出現地方相同 ![](https://i.imgur.com/9f6kgJr.png) ![](https://i.imgur.com/1mwGYUK.png) ## 從已知漏洞設計外掛軟件