Introduction to Windows User Mode Exploitation pt. 1
Windows User Mode Exploit Development: General Course Information:
Quick bit of info about the course :
- Userland(mode I will use this interchangeably) oriented
- 32 bit : Calling convention
- EIP (Extended Instruction Pointer) and SEH (Structured Error handler) overwrites : IP Instruction Pointer Immediate pointer to address being executed) , SEH Exceptions have a structure (List like) overwrite the exception handler address and you have control (challenge is identifying the SEH structure and second on list is SEH address?)
- EggHunter
- Custom Shellcode
- IDA Pro
- DEP (Data Execution Prevention) with ROP (Return Oriented Programming)
- Bypassing ASLR (Address Space Layout Randomization)
- How to create and use RW(read and write primitives) to achieve complex attacks
Memory
When a binary is executed , it allocates memory within the memory boundaries. lowest memory address (`32 bit 0x00000000`) and highest memory address (`0x7FFFFFFF`) used by applications (not kernel).
On `32 bit` systems the `Low Memory Address` , `0x0000000` start from the 'top' , program image starts from `0x00040000`, end of Dynamic Link Library `0x7FFDF000`, beginning and end (`High Memory Address`) `0x7FFFFFFF` and `0xFFFFFFFF` is Kernel Memory Space in the 'bottom' .
The Stack
Threads execute code from the program image (binary/exe/dll.. etc. file ), short term data area for functions, local variables, program control information is the stack. each thread running has its own stack.
Stack is viewed by processor using LIFO (Last In First Out) items put (`PUSH`) / pushed (add) on the stack and (`POP`)/ popped (removed) on top of the stack are removed first.
Calling Conventions
Describe how functions receive their parameters from their caller and how they return the result. The x86 architecture allows multiple calling conventions.
Difference is how the:
- parameters and return value are passed (placed in CPU registers, pushed on stack, or both)
- in which order they are passed
- how the stack is prepared and cleaned up before and after the call
- what CPU registers the called function must preserve for the caller
Compiler determines which calling convention is used for all functions in a program (but programmer can set custom commands.)
Function Return Mechanics
When a thread calls a function, it must know what address to return once the function completes.
Return address is always stored on the stack (plus parameters and local variables) this is called *stack frame*
return address is used to restore execution flow to the calling function.
Registers
9 32 bit registers (on 32-bit architecture). Registers are :
- small
- extremely high speed CPU storage locations
- data is , manipulated /read efficiently
WINDBG
Debugger is a computer program inserting itself between the target application and the CPU (proxy*) :
- View memory
- Interact with memory
- Interact with execution flow
Memory space is mainly divided into Ring0 (Kernel) and Ring3 (User-Mode)
ASM (Assembly) programming language one to one mapping between binary content and programming language.
Opcode is a binary sequence interpreted by the CPU as a specific instruction.
Debugging Symbols
Symbols permit WinDBG to reference internal functions, structures and global variables using names instead of address.
Commands
- `.reload /f` force reload of symbols
- `u` unassemble from Memory e.g.. `u kernel32!GetCurrentThread`
- `db` display bytes e.g.. display bytes register `db esp` , display bytes address `db 00faf974` , display bytes symbol name`db kernel32WriteFile`
- `dw ` display WORDS (two bytes) e.g. `dw esp`
- `dd` display double words , DWORDS (four bytes) e.g. `dd esp`
- `dq` display QWORDS (8 bytes) e.g. `dq 00faf974`
- `dW` and `dc` display ASCII characters along DWORDS and WORDS respectively `dc KERNELBASE` , e.g. `dW KERNELBASE+0x40`
- `L` parameter changes default length displayed , `0x80` is the default length e.g. `dd esp L4 ` ==> 00001111 22223333 44445555 66667777 (4 double words)
- `da` and `du` , displays ASCII and Unicode format respectively
- `poi` pointer to data e.g. `dd poi(esp)`
- `dt` dumps structures from memory e.g. `dt ntdll!_TEB` supplying the -r flag recursively display nested structures where present e.g. `dt -r ntdll!_TEB @$teb` , `dt ntdll!_TEB @$teb ThreadLocalStoragePointer`
- `?? sizeof(ntdll!_TEB)` check size of structure
- `ea` write ASCII to register/address e.g. `ea esp "Hello"`
- `s` search memory e.g `s -d 0 L?80000000 41414141` (`search`(s) `DWORD`(-d) s`tarting search address` (0) `max memory range`(80000000(full range on 32 bit)) `pattern we want to search in memory `(41414141)
- `r` inspect\edit CPU registers e.g.` r ecx `, `r` , edit ecx register` r ecx=41414141`
- `lm` list modules e.g `lm m kernel*` explanation` lm` (list modules) `m` (filter by module pattern) `kernel*` (module pattern)
Controlling the Program Execution in WinDBG
Software Breakpoints -
WinDBG temporarily replaces the first opcode of the instruction of where we want to halt with an INT 3 assembly instruction. (we can also set as many as we want)
- `bp kernel32!WriteFile` breakpoint on kernel32!WriteFile
- `bl` list breakpoint
- `bc` clear break point
- `bd `disable breakpoint
- `be` enable breakpoint
- `bu` breakpoint on unresolved (not loaded in process memory space)
Bonus
- `lm` list module e.g. `lm m ole32`
- `bp kernel32!WriteFile ".printf \"The number of bytes written is: %p\", poi(esp + 0x0C);.echo;g"` automating execution of commands e.g. print number of bytes written once the breakpoint set on WriteFile is hit : we chose to display the value pointed to by the ESP register at offset 0x0C (12 bytes), which corresponds to the number of bytes to write to the target file (third argument) when kernel32!WriteFile is called.
`BOOL WriteFile(`
`HANDLE hFile,`
`LPCVOID lpBuffer,`
`DWORD nNumberOfBytesToWrite,`
`LPDWORD lpNumberOfBytesWritten,`
`LPOVERLAPPED lpOverlapped`
`);`
Windows x86 API makes use of the (_stdcall_) calling convention in which function arguments are pushed on the stack in reverse order (right to left) in this case each argument occupies four bytes of memory on the stack.
Hardware Breakpoints
Handled by processor and stored in the processors debug registers, they stop code execution when a particular type of access , such as read, write or execute is made to a targeted memory location.
Best to monitor changes or access to data memory.
- `ba e 1 kernel32!WriteFile` explained as `ba` (set breakpoint) `e` (execute (can be r or w too read and write respectively)) `1` (size in bytes) `kernel32!WriteFile` (address we are targeting)
Stepping through code
- `p` step over
- `t` step into
- `pt` execute till return (till end of that function)
- `x` e.g `x kernelbase!CreateProc*` explanation `x` (examine) `kernelbase!CreateProc*` (symbols in kernelbase module)
- `?` evaluate expression command e.g. `? 7726bc0 - 77231430` (calculate the difference)
- `.formats` converting data in different formats e.g. `.formats 41414141`
- Psuedo registers , 20 in number ($ t0 to t19) can be used as variables in mathematical calculations e.g `r @$to = (41414141 - 414141) * 0n10 *` we use the $t0 pseudo register and store the value of the first calculation. Then we read the $t0 register and WinDBG outputs the result to verify the value. Finally, we right-shift $t0 by 8 bits to get the final result.
Comments
Post a Comment