[windows] exploit dev
Intro
WinDbg
-
local/remote kernel debugging
setx _NT_SYMBOL_PATH srv*c:\symbols*HTTP://MSDL.MICROSOFT.COM/DOWNLOAD/SYMBOLS
on the debuggee machine:bcdedit /debug on
bcdedit /dbgsettings local
OR if remotebcdedit /dbgsettings NET HOSTIP:[DEBUGGER_IP] port:50000 key:1.1.1.1
OR bootloader/bootmanager debugging (only COM debugging works - no NET)bcdedit /bootdebug {bootmgr} on
bcdedit /set bootdebug on
bcdedit /dbgsettings serial debugport:1 baudrate:115200
-
set dynamic symbols fetching [win 7 and above]
srv*c:\symbols*https://msdl.microsoft.com/download/symbols
[win XP]srv*c:\mss*http://msdl.microsoft.com/download/symbols
-
attach/open process/file [invasive]
cdb.exe -p ProcessID
cdb.exe -pn FilenName.exe
-
attach/open process/file [non-invasive]
cdb.exe -pv -p ProcessID
cdb.exe -pv -pn FilenName.exe
-
break points
bl
- list all break pointsbc [bpID]
- delete specific bpbp [functionName]
- sets bp at functionNamebp
- [sets bp at current IP location] -
execution controls
g
- go until next bpt
- trace/execute til next instruction {step into a function}p
- step/execute next instruction {step over a function}pt
- step until next RETpct
- step until next RET or CALLgu
- go up until current function returnsq
- quit -
[useful commands]
x [module]![symbol]
- Report the address of the specified symbolsx *!
- List all modules currently loadedx module!*
- List all symbols and their addresses in the specified modulex module!symbol*
- List all of the symbols that match the “arg” wild-card filterlm
- list all loaded modules (more detailed than x *!)!lmi [module]
- list module infodt [symbol name]
- display type of a symbolu
- disassemble 8 instructions from current addressu [address]
- disassemble 8 from specified addressu [start - end]
uf routineName
- diass specified routedd addressRange
- display address range.formats [hex value]
- display hex translationr
- display registers -
KD specific
lm n
- list loaded modules!process 0 0
- list all processes!process [Cid] 15
- get process details.process /r /p [Cid]
- switch to process context -
peek into PEB
.process [base address]
!peb
-
registers command
0rM [0-255]
- dump register details with 8-bit mask -
quit kd
bc *
g
<ctrl b> <enter>
DEP
Configuration
WinXP/2k3
/noexecute=policy [boot.ini]
Win Vista and above
bcdedit /enum all
bcdedit /set nx [one of the following options]
OptIn : Enables DEP only for operating system components, including the Windows kernel and drivers. Administrators can enable DEP on selected executable files by using the Application Compatibility Toolkit (ACT).
OptOut : Enables DEP for the operating system and all processes, including the Windows kernel and drivers. However, administrators can disable DEP on selected executable files by using System in Control Panel.<br>
AlwaysOn : Enables DEP for the operating system and all processes, including the Windows kernel and drivers. All attempts to disable DEP are ignored.
AlwaysOff: Disables DEP. Attempts to enable DEP selectively are ignored<br>
DEP-defeating APIs
API | Supported OS |
---|---|
NtSetInformationProcess | XP/2003 server |
SetProcessDEPPolicy | XP/Vista SP1/2008 server |
Virtual Protect | all Win versions |
Virtual Alloc | all Win versions |
WriteProcessMemory | all Win versions |
LoadLibrary | all Win versions |
MapViewOfFile | all Win versions |
Shellcode
JUMPS and CALLS
JUMPS
JMP Type | Example | Machine Encoding |
---|---|---|
Short | JMP SHORT mylabel | 0xEB [signed byte] |
Near direct | JMP NEAR PTR mylabel | 0xE9 [low byte] [high byte] |
Near indirect | JMP EBX | 0xFF 0xE3 |
Far direct | JMP DS:[mylabel] | 0xEA [IP low] [IP high] [CS low] [CS high] |
Far indirect | JMP DWORD PTR[EBX] | 0xFF 0x2F |
CALLS
JMP Type | Example | Machine Encoding |
---|---|---|
Near direct | CALL mylabel | 0xE8 [low byte] [high byte] |
Near indirect | CALL EBX | 0xFF 0xD3 |
Far direct | CALL DS:[mylabel] | 0x9A [IP low] [IP high] [CS low] [CS high] |
Far indirect | CALL DWORD PTR [EBX] | 0xFF 0x1F |
Near return | RET | 0xC3 |
Far return | RETF | 0XCB |
Examples
Jump short '\xEB\x06' JMP 8 bytes ahead (including start of instruction)
Jump near '\xE9\xa3\xfd\xff\xff' JMP 600 bytes back (including start of instruction)
Find Kernel32.dll with WinDBG
x86
Tested on latest Win10 Version 10.0.18362.113
- Find offset 0x30 from FS register [Pointer to PEB]
0:000> dp fs:[30] L1
0053:00000030 02e68000
- Get the pointer to PEB_LDR_DATA
02e680000:000> dt nt!_PEB Ldr Ldr. 02e68000
ntdll!_PEB
+0x00c Ldr : 0x776ddca0 _PEB_LDR_DATAC
+0x000 Length : 0x30
+0x004 Initialized : 0x1 ''
+0x008 SsHandle : (null)
+0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x7ae6f58 - 0x838cf58 ]
+0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x7ae6f60 - 0x838cf60 ]
+0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x7ae2f68 - 0x7b3ef68 ]
+0x024 EntryInProgress : (null)
+0x028 ShutdownInProgress : 0 ''
+0x02c ShutdownThreadId : (null)
- Get pointer to first entry in InMemoryOrderModuleList
0:000> !list -t ntdll!_LIST_ENTRY.Flink -x "dd" -a "L1" 0x7ae6f60
07ae6f60 07ae2f60 # ntdll.dll
07ae2f60 07aeef60 # verifier.dll
07aeef60 07afaf60 # kernel32.dll
07afaf60 07b06f60 # kernelbase.dll
- Subtract the 8-byte linked-list data structure header.
07afaf60 -0x8 = 7afaf58
- Get the base address from the third entry (it would normally be the 2nd entry!)
0:000> dt ntdll!_LDR_DATA_TABLE_ENTRY 7afaf58
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x7b06f58 - 0x7aeef58 ]
+0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x7b06f60 - 0x7aeef60 ]
+0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x7b3ef68 - 0x7b06f68 ]
+0x018 DllBase : 0x772b0000 Void
+0x01c EntryPoint : 0x772c5f70 Void
+0x020 SizeOfImage : 0xe0000
+0x024 FullDllName : _UNICODE_STRING "C:\Windows\System32\KERNEL32.DLL"
+0x02c BaseDllName : _UNICODE_STRING "KERNEL32.DLL"
- Double check dll base address with one-liner
0:00> !peb
Base TimeStamp Module
380000 C:\Program Files (x86)\Internet Explorer\iexplore.exe
775c0000 C:\Windows\SYSTEM32\ntdll.dll
6a8f0000 C:\Windows\SysWOW64\verifier.dll
772b0000 12f36500 Jan 28 12:56:32 1980 C:\Windows\System32\KERNEL32.DLL
- The entire shellcode
mov ebx, fs:0x30 ; Get pointer to PEB
mov ebx, [ebx + 0x0C] ; Get pointer to PEB_LDR_DATA
mov ebx, [ebx + 0x14] ; Get pointer to first entry in InMemoryOrderModuleList
mov ebx, [ebx] ; Get pointer to first dll (ntdll.dll) entry in InMemoryOrderModuleList
mov ebx, [ebx] ; Get pointer to second dll (verifier.dll) entry in InMemoryOrderModuleList
mov ebx, [ebx] ; Get pointer to third dll (kernel32.dll) entry in InMemoryOrderModuleList
mov ebx, [ebx + 0x10] ; Get kernel32.dll base address
x64
- Find the TEB address
0:000> !teb
TEB at 00000000003f3000
The TEB on x64 lies in the GS
register instead of the FS
that we have seen with x86 so far.
Keep in mind that on long-mode, the TEB cannot be accessed via regular segmented registers, thus the gs
is available only in kd.
The teb
is stored in user_gs_base
MSR register which can be read via rdmsr c0000102
, as long as the thread is living in usermode and not swapped by SWAPGS yet (else the value would be IA32_KERNEL_GS_BASE
aka the PCR).
1: kd> !teb
TEB at 000000275e30e000
1: kd> rdmsr c0000102
msr[c0000102] = 00000000'003f3000
- Find the PEB
0:000> dt _TEB 00000000003f3000
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x038 EnvironmentPointer : (null)
+0x040 ClientId : _CLIENT_ID
+0x050 ActiveRpcHandle : (null)
+0x058 ThreadLocalStoragePointer : 0x00000000`003f3058 Void
+0x060 ProcessEnvironmentBlock : 0x00000000`003f2000 _PEB
- Find the PEB_LDR_DATA
0:000> dt _PEB_LDR_DATA 0x00007ffe`e31bb4c0
ntdll!_PEB_LDR_DATA
+0x000 Length : 0x58
+0x004 Initialized : 0x1 ''
+0x008 SsHandle : (null)
+0x010 InLoadOrderModuleList : _LIST_ENTRY [ 0x00000000`001f2bb0 - 0x00000000`001f37e0 ]
+0x020 InMemoryOrderModuleList : _LIST_ENTRY [ 0x00000000`001f2bc0 - 0x00000000`001f37f0 ]
+0x030 InInitializationOrderModuleList : _LIST_ENTRY [ 0x00000000`001f2a00 - 0x00000000`001f3120 ]
+0x040 EntryInProgress : (null)
+0x048 ShutdownInProgress : 0 ''
+0x050 ShutdownThreadId : (null)
- Find the first entry in the list (own process)
0:000> dt _LDR_DATA_TABLE_ENTRY poi(0x00007ffe`e31bb4c0+20)
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x00000000`001f29f0 - 0x00007ffe`e31bb4e0 ]
+0x010 InMemoryOrderLinks : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
+0x020 InInitializationOrderLinks : _LIST_ENTRY [ 0x00000000`00400000 - 0x00000000`00401000 ]
+0x030 DllBase : 0x00000000`00004000 Void
+0x038 EntryPoint : 0x00000000`00520050 Void
+0x040 SizeOfImage : 0x1f2728
+0x048 FullDllName : _UNICODE_STRING "CMD.EXE"
- Find the third entry (kernel32.dll)
0:000> dt _LDR_DATA_TABLE_ENTRY poi(poi(poi(0x00007ffe`e31bb4c0+20)))
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x00000000`001f37f0 - 0x00000000`001f29f0 ]
+0x010 InMemoryOrderLinks : _LIST_ENTRY [ 0x00007ffe`e31bb4f0 - 0x00000000`001f3800 ]
+0x020 InInitializationOrderLinks : _LIST_ENTRY [ 0x00007ffe`e2dc0000 - 0x00007ffe`e2dd70d0 ]
+0x030 DllBase : 0x00000000`000bd000 Void
+0x038 EntryPoint : 0x00000000`00420040 Void
+0x040 SizeOfImage : 0x1f32d0
+0x048 FullDllName : _UNICODE_STRING "KERNEL32.DLL"
- The entire shellcode
mov rax, [gs:0x60] ; Get pointer to PEB
mov rax, [rax+0x18] ; Get pointer to PEB_LDR_DATA
mov rax, [rax+0x20] ; Get pointer to first entry in InMemoryOrderModuleList
mov rax, [rbx] ; Get pointer to second (ntdll.dll) entry in InMemoryOrderModuleList
mov rax, [rax] ; Get pointer to third (kernel32.dll) entry in InMemoryOrderModuleList
mov r12, [rax+0x20] ; Get kernel32.dll base address
Heap
WinDBG command reference
!heap -stat # stats about process heaps usage
!heap -h <heap_addaress> # heap + segments info
dt _HEAP <heap_address> # show heap_base data structure
dt _HEAP_SEGMENT <segment_address> # segment header
!heap -p -a <memory_address> # show heap chunk info [user ptr]
!heap -stat -h <heap_address> # show allocation size breakdown
!heap -flt s <size> # show heap allocations of given size
!heap -a -h <heap_address> # show free list + all chunks
!heap -f <heap_address> # show free list