# reverse&pwn ## x86暫存器 ![](https://hackmd.io/_uploads/SJjuJm6Fh.png) | EIP、RIP | 指令暫存器 | 指向下一條指令位址 | | --- | --- | --- | | CF | Carry Flag | 運算產生借位或進位,CF亮起 | | ZF | Zero Flag | 任何運算為0,ZF亮起 | ## x86指令 ```nasm mov rax, 1 ; rax=1 add rax, 5 ; rax+=5 sub rax, 1 ; rax-=1 xor rax, rax ; rax=rax^rax //歸零 or rax, 0x10; rax=rax||0x10 mul ebx ; eax=ebx*eax dec ebx ; ebx-=1 inc ebx ; ebx+=1 jnz LOOP ; jmp if ZF != 1//jump if non zero jmp HANG ; while(true) lea rdi, [rsp+0x10] ; 不取值直接放入 cmp rax, rbx ;rax-rbx; jz EQUAL ; jump if equal(ZF==1) ja ABOVE ; jump if unsigned above (CF==0 or ZF==0)) //if (rax>rbx) jle LESS ; jump less or equal idiv dowrd ptr [rbp-8] ; edx=eax%[rbp-8] syscall 吃rax push rbp;//將rbp放到rsp的位址中,再將rsp向上移8bytes pop rbp;//將rsp位址中的值放到rbp,再將rsp向下移8bytes byte ptr [rax] ;只用一個byte word ptr [rax] ;2byte dword ptr [rax] ;4byte qword ptr [rax] ;8byte oword ptr [rax] ;16byte ``` ## Stack Frame ![](https://hackmd.io/_uploads/SJ5HV_2v2.png =50%x) - Stack Frame最下面放Return Address - 倒數第二放上一個Stack Frame的 RBP位置 - 每一格是8bytes ### Prologue ```nasm push rbp;//將舊Stack基底位置放到新Stack最底端 mov rbp,rsp;//將rbp向上移到新stack的底端 ``` ### 開Stack ```nasm sub rsp,0x20;//將rsp向上撐開一個Stack Frame ... call func1;//call之前會把下一條指令位址push到stack上才開啟一個新的stack frame 下一條指令 ``` ### Epilogue ```nasm leave; mov rsp,rbp;//將rsp彈回rbp位置 pop rbp;//將rbp彈回上一個stack frame的基底位置 ret; //pop rip,將下一條要執行的指令位址放入rip中 ``` **執行完後會回到上一個stack frame的狀態** ## Calling Convention Function傳遞參數的慣例 **x64** - **Windows** - Function(rcx,rdx,r8,r9,stack) - **Linux** - Function(rdi,rsi,rdx,rcx,r8,r9,stack) **x86** - **都放stack** - **__cdecl** - **caller做Stack Cleanup** - func(a,b,c) - push c->push b->push a - **__stdcall** - **callee做Stack Cleanup** - stack放置和__cdecl一樣 - **__fastcall** - 前兩個參數放到Register,再放進Stack - ecx->edx->stack function return值放在rax ### ChatGPT說 1. 32位Windows平台下,前四個整型(integer)參數依次存放在寄存器EAX、EDX、ECX和EBX中。 2. 64位Windows平台下,前四個整型參數依次存放在寄存器RCX、RDX、R8和R9中,而前四個浮點型(floating-point)參數存放在XMM0~XMM3寄存器中。 3. Linux和Unix等平台下,前六個整型參數依次存放在寄存器EDI、ESI、EDX、ECX、R8和R9中。而前八個浮點型參數存放在XMM0~XMM7寄存器中。 ### info func沒東西 可能被打包起來了 ```bash upx -d file -o newfile ``` ### Syscall ![](https://hackmd.io/_uploads/SytwHqdD3.png) ### FD(File Descriptor) | File Descriptor | 名稱 | <unistd.h>符號常數[1] | <stdio.h>檔案流[2] | | --- | --- | --- | --- | | 0 | Standard input | STDIN_FILENO | stdin | | 1 | Standard output | STDOUT_FILENO | stdout | | 2 | Standard error | STDERR_FILENO | stderr | ### Section section放不會變動的資料 - 程式碼在 .text section 有執行權限 - 常數字串放 .rodata section 有讀取權限 ### ELF 保護機制 ```bash checksec file ``` - **PIE(Position Independent Executable)** - 程式碼以相對位置表示,非絕對位置 - **NX(No eXecute)** - .text之外的section不會有執行權限 - **Canary -stack protector** - 在stack 結尾塞入一個隨機數,return 前透過檢查隨機數是否有被修改 - **RELRO (RELocation Read-Only)** - 分成Full/Partial/No 三種型態,分別代表在runtime解析外部function時使用的不同機制 - **Seccomp(SECure COMPuting mode)** - 制定規則來禁止/允許特定syscall呼叫 - **ASLR(Address Space Layout Randomization)** - stack、heap會使用隨機記憶體位址作為base address ## 如何get shell ```c execve("/bin/sh",0,0); system("/bin/sh"); ``` 也可以透過syscall得到shell ### shellcode ```python from pwn import * context.arch="amd64" sc=asm(shellcraft.sh()) ``` ## Memory Layout - **.text:** 拿來放程式碼的 - **.rodata:** read-only data,如寫死的字串 - **.bss:** 尚未初始化的變數 - **heap:** 動態分配的記憶體空間,會隨執行時間增長 - **lib:** malloc()、free()等lib的實作 - **tls:** threat local storage - **stack:** 老熟了在上面 ## Buffer Overflow ### 危險function可能會出現 ```c gets(); strcat(); scanf("%s",&a); ``` ### 怎麼玩 蓋掉return address跳到其他地方 ## Heap 在runtime分配及釋放記憶體,才能有效利用記憶體 ### Chunk 動態記憶體分配的基本單位,最小為0x20 bytes,會對齊0x10 bytes,由於metadata會額外需 要0x10 bytes,因此實際上會多出0x10的大小 - 使用中的Chunk->**`allocated chunk`** - 被釋放的Chunk->**`freed chunk`** - **`freed chunk`** 會被依功能放在不同的 **`bin`** 之中 - 後續請求記憶體時會從 **`bin`** 中取出 **`chunk`** 給Heap使用 ![](https://hackmd.io/_uploads/rkpqwMEu3.png) ### 有的沒的工具 ```shell objdump -M intel -d file |less #查看asm code checksec file #檢查保護機制 ROPgadget --binary file #檢查ROP chain upx -d file -o new_file #把被包起來的library unpack ``` #### ROPgadget usage: ROPgadget.py [-h] [-v] [-c] [--binary <binary>] [--opcode <opcodes>] [--string <string>] [--memstr <string>] [--depth <nbyte>] [--only <key>] [--filter <key>] [--range <start-end>] [--badbytes <byte>] [--rawArch <arch>] [--rawMode <mode>] [--rawEndian <endian>] [--re <re>] [--offset <hexaddr>] [--ropchain] [--thumb] [--console] [--norop] [--nojop] [--callPreceded] [--nosys] [--multibr] [--all] [--noinstr] [--dump] ```shell ROPgadget file --binary ``` #### pwntools ```python from pwn import * context.arch='amd64' #context類似環境變數的東東 context.level='debug' #把數字變成bytes傳給電腦 packed_32=p32(0x12345678) #p32 4bytes packed_64=p64(0x123456789abcdef1) #p64 8bytes #把bytes變回數字 unpacked_32=u32(b'\x78\x56\x34\x12') ``` ## GOT Hijacking :::info **`GOT`:Global Offset Table** >When you execute the function at first time, it would resolve the function, and finally fill the function of the GOT with the correct address of the function. ::: *待補* ## How to reverse engineer an unity game 我不會(目前) https://www.kodeco.com/36285673-how-to-reverse-engineer-a-unity-game ### DnSpy https://blog.csdn.net/jumpe_17/article/details/115468065