Project: LAN WinDbg / KDNET according to @Mov AX, 0xDEAD for Windows XP SP2 x64 / Server 2003 x64 kernel 3790
Goal:
The goal is to get LAN kernel debugging working for Windows XP Professional x64 Edition / XP SP2 x64 using an Intel i211 LAN adapter on an ASRock Z370 K6 motherboard.
COM1 WinDbg already works and serves as the rescue/debug fallback.
XP x64 boots via NTLDR.
Current status: KDNET loads kdnet.dll when using /DEBUGPORT=NET, but it does not connect yet. Several guessed x64 payload hooks were wrong and caused the system to hang immediately or very early.
Hardware / setup:
Motherboard: ASRock Z370 K6
Has CSM and COM1
LAN: Intel i211
Intel i211 PCI ID: VEN_8086 DEV_1539
Therefore, for MovAX /PCI_ID: /PCI_ID=80861539
Host IP: 192.168.2.102
Target IP: 192.168.2.110
Host port: 50000
Encryption key: 1.2.3.4
CPUFREQ used so far: 3000
Working COM1 fallback boot.ini entry:
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="XP x64 COM1 DEBUG PCILOCK" /fastdetect /DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /BREAK /W2003 /PCILOCK
NET boot.ini entry that was tested:
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="XP x64 KDNET i211" /fastdetect /noexecute=optin /DEBUG /DEBUGPORT=NET /HOST_IP=192.168.2.102 /HOST_PORT=50000 /ENCRYPTION_KEY=1.2.3.4 /CPUFREQ=3000 /TARGET_IP=192.168.2.110 /PCI_ID=80861539 /W2003 /PCILOCK /BREAK
Host WinDbg command:
windbg -k net:port=50000,key=1.2.3.4
Host output when KDNET is not working:
Microsoft (R) Windows Debugger Version 6.3.9600.17200 X86
Using NET for debugging
Opened WinSock 2.0
Waiting to reconnect...
MovAX0xDEAD option mapping:
For Intel i211 we use Option A, not Option B.
Option A:
Win8.1 kdnet.dll -> C:\WINDOWS\system32\kdnet.dll
Win8.1 kd_02_8086.dll -> rename to C:\WINDOWS\system32\kdstub.dll
kdnet10.dll is NOT needed for Option A.
kdnet10.dll belongs only to MovAX Option B with Win10 kd_02_*.dll, mainly for newer NICs such as i219 and newer.
Therefore, for i211, do NOT use kdnet10.dll.
After copying, there is normally no kd_02_8086.dll left under its original name in system32, because it is present as kdstub.dll.
Files on XP x64 for Option A:
C:\WINDOWS\system32\kdnet.dll
C:\WINDOWS\system32\kdstub.dll
C:\WINDOWS\system32\kdcom.dll
Not needed / do not use:
C:\WINDOWS\system32\kdnet10.dll
C:\WINDOWS\system32\kd_02_8086.dll
Important proof regarding the load path:
kdnet.dll was temporarily renamed to kdnet.testoff.
Then the NET boot entry was selected.
Result: no error message, but black screen / very early hang.
Conclusion: /DEBUGPORT=NET really searches for and loads kdnet.dll.
Therefore the NET boot path is active.
The problem is NOT that XP x64 does not touch kdnet.dll at all.
COM boot observation:
With /DEBUGPORT=COM1 only kdcom.dll is loaded.
kdnet.dll / kdstub.dll are not loaded during COM boot, as expected.
This does not prove that KDNET is broken. It only proves that COM1 loads the COM KD transport kdcom.dll.
Directly debugging a /DEBUGPORT=NET boot via COM1 is not possible, because the kernel debugger transport is NET instead of COM.
Exact KD target environment from COM WinDbg:
vertarget:
Windows Server 2003 Kernel Version 3790 (Service Pack 2) MP Free x64
Built by: 3790.srv03_sp2_rtm.070216-1710
XP x64 internally uses the Server 2003 x64 kernel 3790.
Modules / addresses from COM KD:
nt base: fffff80001000000
hal:
base fffff80000800000
end fffff8000085e000
size 0005e000
pci.sys:
base fffffadcc057c000
end fffffadcc059d000
size 00021000
ACPI.sys:
base fffffadcc059d000
end fffffadcc05f2000
kdcom.dll:
base fffffadcc09fb000
end fffffadcc0a05000
NDIS.sys:
base fffffadcc0205000
end fffffadcc026b000
Important pci.sys addresses / RVAs:
pci!PciHookHal:
VA fffffadcc05803e0
RVA 000043e0
pci!PciTranslateBusAddress:
VA fffffadcc0580150
RVA 00004150
pci!PciAssignSlotResources:
VA fffffadcc057fe20
RVA 00003e20
pci!PciLockDeviceResources:
VA fffffadcc0587b90
RVA 0000bb90
pci!PcipSavedAssignSlotResources:
VA fffffadcc0587a68
RVA 0000ba68
pci!PcipSavedTranslateBusAddress:
VA fffffadcc0587a70
RVA 0000ba70
pci!HalPrivateDispatchTable pointer:
VA fffffadcc0584120
RVA 00008120
Content:
fffffadcc0584120 = fffff800011b07d0
HalPrivateDispatchTable:
VA fffff800011b07d0
Before PciHookHal:
[HalPrivateDispatchTable+38] = fffff800008136a0
[HalPrivateDispatchTable+40] = fffff8000084fa70
After PciHookHal:
[HalPrivateDispatchTable+38] = fffffadcc0580150 = pci!PciTranslateBusAddress
[HalPrivateDispatchTable+40] = fffffadcc057fe20 = pci!PciAssignSlotResources
Saved original values after hook:
pci+0xba68 = fffff8000084fa70
pci+0xba70 = fffff800008136a0
PciHookHal code:
pci!PciHookHal:
fffffadcc05803e0 488b0d393d0000 mov rcx,qword ptr [pci!HalPrivateDispatchTable]
fffffadcc05803e7 488b4140 mov rax,qword ptr [rcx+40h]
fffffadcc05803eb 48890576760000 mov qword ptr [pci!PcipSavedAssignSlotResources],rax
fffffadcc05803f2 488d0527faffff lea rax,[pci!PciAssignSlotResources]
fffffadcc05803f9 48894140 mov qword ptr [rcx+40h],rax
fffffadcc05803fd 488b0d1c3d0000 mov rcx,qword ptr [pci!HalPrivateDispatchTable]
fffffadcc0580404 488b4138 mov rax,qword ptr [rcx+38h]
fffffadcc0580408 48890561760000 mov qword ptr [pci!PcipSavedTranslateBusAddress],rax
fffffadcc058040f 488d053afdffff lea rax,[pci!PciTranslateBusAddress]
fffffadcc0580416 48894138 mov qword ptr [rcx+38h],rax
fffffadcc058041a c3 ret
PCILOCK proof:
The boot options string contained:
"DEBUG DEBUGPORT=COM1 BAUDRATE=115200 BREAK PCILOCK"
pci!PciUnicodeStringStrStr successfully searched for PCILOCK.
PCILOCK string:
VA fffffadcc0598900
RVA 0001c900
String "PCILOCK"
pci!PciUnicodeStringStrStr:
VA fffffadcc0583190
RVA 00007190
RtlEqualUnicodeString call inside PciUnicodeStringStrStr:
VA fffffadcc05831fc
RVA 000071fc
Success path:
VA fffffadcc0583238
RVA 00007238
DriverEntry area relevant to PCILOCK:
fffffadcc05980f0 call pci!PciGetRegistryValue
fffffadcc05980f5 test eax,eax
fffffadcc05980f7 js pci!DriverEntry+0x24d
fffffadcc05980f9 mov ecx,dword ptr [rsp+68h]
fffffadcc05980fd lea rax,[pci!string = PCILOCK at fffffadcc0598900]
fffffadcc059814b call pci!PciUnicodeStringStrStr
fffffadcc0598150 test al,al
fffffadcc0598152 je pci!DriverEntry+0x24d
fffffadcc0598154 mov byte ptr [pci!PciLockDeviceResources],dil
Manual setting was tested:
eb fffffadcc0587b90 01
db fffffadcc0587b90 L10
Result:
fffffadcc0587b90 01 00 00 00 00 00 00 00 ...
Conclusion regarding PCILOCK:
/PCILOCK works on XP x64.
pci!PciLockDeviceResources is set to 1 by it.
PciHookHal runs cleanly.
HalPrivateDispatchTable is patched correctly.
The old x86 MovAX PCI hack using [esi+43h] and [esi+38h] must NOT be transferred 1:1 to x64.
HAL x64 search / patch area:
hal base fffff80000800000
Search:
s -b fffff80000800000 L5e000 f7 c2 f0 ff ff ff f7
No hit.
Search:
s -b fffff80000800000 L5e000 f7 c2 f0 ff ff ff
Hit:
fffff8000080970d f7 c2 f0 ff ff ff 75 0e ...
The real x64 instruction starts one byte earlier:
fffff8000080970c 49 f7 c2 f0 ff ff ff = test r10,0FFFFFFFFFFFFFFF0h
Surrounding HAL code:
fffff800008096d0 eb56 jmp fffff80000809728
fffff800008096d2 3bcb cmp ecx,ebx
fffff800008096d4 734d jae fffff80000809723
fffff800008096d6 4e8d44e238 lea r8,[rdx+r12*8+38h]
fffff800008096e0 498b10 mov rdx,qword ptr [r8]
fffff800008096e3 493bd3 cmp rdx,r11
fffff800008096e6 773b ja fffff80000809723
fffff800008096e8 4d8b50f8 mov r10,qword ptr [r8-8]
fffff800008096ec 498d4201 lea rax,[r10+1]
fffff800008096f0 483bc2 cmp rax,rdx
fffff800008096f3 752e jne fffff80000809723
fffff800008096f5 498bc2 mov rax,r10
fffff800008096f8 4833c2 xor rax,rdx
fffff800008096fb 48a90000f0ff test rax,0FFFFFFFFFFF00000h
fffff80000809701 7520 jne fffff80000809723
fffff80000809703 4080fe01 cmp sil,1
fffff80000809707 740c je fffff80000809715
fffff80000809709 4c33d2 xor r10,rdx
fffff8000080970c 49f7c2f0ffffff test r10,0FFFFFFFFFFFFFFF0h
fffff80000809713 750e jne fffff80000809723
fffff80000809715 81c100100000 add ecx,1000h
fffff8000080971b 4983c008 add r8,8
fffff8000080971f 3bcb cmp ecx,ebx
fffff80000809721 72bd jb fffff800008096e0
fffff80000809723 3bcb cmp ecx,ebx
fffff80000809725 0f47cb cmova ecx,ebx
fffff80000809728 4885ff test rdi,rdi
...
fffff800008097cf 4c8b742408 mov r14,qword ptr [rsp+8]
fffff800008097d4 4c8b642410 mov r12,qword ptr [rsp+10h]
fffff800008097d9 488b7c2418 mov rdi,qword ptr [rsp+18h]
fffff800008097de 488b742420 mov rsi,qword ptr [rsp+20h]
fffff800008097e3 488b6c2428 mov rbp,qword ptr [rsp+28h]
fffff800008097e8 488b5c2430 mov rbx,qword ptr [rsp+30h]
fffff800008097ed 4883c438 add rsp,38h
fffff800008097f1 c3 ret
Additional HAL functions:
fffff800008136a0:
fffff800008136a0 488b442428 mov rax,qword ptr [rsp+28h]
fffff800008136a5 4c8900 mov qword ptr [rax],r8
fffff800008136a8 b001 mov al,1
fffff800008136aa c3 ret
fffff8000084fa70:
fffff8000084fa70 488bc4 mov rax,rsp
fffff8000084fa73 4881ec28010000 sub rsp,128h
fffff8000084fa7a 83bc245001000005 cmp dword ptr [rsp+150h],5
...
Important MovAX x86 ASM block from the chat:
use32
ORG equ $80037490
BASE equ $80010000
Continue1 equ $8001B5FA - ($$+ORG)
HalpKdReadPCIConfig@20 equ $80021404
HalpKdWritePCIConfig@20 equ $80021408
GetPciDataByOffset equ $800371B2
SetPciDataByOffset equ $80037020
CPUFREQ_STR equ $80037360
W2003_STR equ $80037368
DEVID_STR equ $8003736E
Win2003 equ $80021178
Header_Patch equ $8001016C
PCI_ID equ $800211AA
__strupr equ $8001B76C - ($$+ORG)
_strstr equ $8001B6E0 - ($$+ORG)
MovAX x86 payload logic from ASM:
Start jumps to MyPatches.
MyPatches begins with:
add esp,0Ch
push eax/ecx/edx/esi/edi/ebx
Base is obtained via call/pop:
call $+5
pop edi
sub edi, base1+ORG-BASE
kdnet internal PCI config function pointers are replaced:
HalpKdReadPCIConfig@20 -> GetPciDataByOffset
HalpKdWritePCIConfig@20 -> SetPciDataByOffset
Header_Patch is set to 5.
The loader block is searched for kdstub.dll.
Optionally, kdnet10.dll is searched.
PE header / reloc / security cookie are patched.
/W2003 is searched for inside the boot options string.
/PCI_ID=xxxxxxxx is searched for and stored in PCI_ID.
hal.dll is searched.
Inside hal.dll, this magic byte sequence is searched:
F7 C2 F0 FF FF FF F7
A JMP to Patch_PCI64 is installed there.
pci.sys is searched.
Inside pci.sys, this magic byte sequence is searched:
B0 01 EB AE CC
A JMP to Patch_Debug_PCI is installed there.
Then registers are restored and execution jumps to Continue1.
MovAX x86 HAL patch:
Patch_PCI64:
mov eax,edx
and eax,6
cmp eax,4
jnz PCI32
add dword [ebp+??],4
dec dword [ebp-??]
PCI32:
test edx,FFFFFFF0h
jmp back
MovAX x86 PCI patch:
Patch_Debug_PCI:
mov al,1
mov esi,[ebp+8]
cmp byte [esi+43h],2
jnz Skip_This
mov dword [esi+38h],BEEFDEADh
Skip_This:
jmp back
Important conclusion:
This x86 patch is NOT directly transferable to x64.
The instruction add esp,0Ch proves that MovAX did not simply hook at the beginning of KdDebuggerInitialize0.
The hook location is a specific x86 location with a specific stack situation.
My previous x64 hook at KdDebuggerInitialize0+0 was guessed and wrong.
Previously incorrect test packages / results:
1. test1
kdnet.dll was only patched for PE/header/import compatibility.
No real ASM payload.
Result: Host only waits with "Waiting to reconnect".
Conclusion: boot path yes, functionality no.
2. test2
A real x64 payload was inserted, but it was wrong.
Hook at KdDebuggerInitialize0 RVA 0x569c.
New section .xpth RVA 0x29000 / VA 0x80039000.
Payload searched the loader list / pci.sys and set pci+0xBB90.
Result: XP x64 hangs from the beginning / very early.
Conclusion: kdnet.dll is loaded and hook/payload is probably reached, but the approach is wrong.
3. test3
No-op payload with new section .xpnop.
Hook still at KdDebuggerInitialize0 RVA 0x569c.
Result: hangs after about one second.
Conclusion: hook location / approach has not been proven correct; no-op does not fix anything.
4. test4
No-op payload inside .reloc instead of a new section.
No new section.
Hook still at KdDebuggerInitialize0 RVA 0x569c.
Result: hangs as before.
Additional mistake: .reloc is not executable, which is problematic with NX.
5. test5
No-op payload in an executable .text code cave.
No new section, no .reloc code.
Hook still at KdDebuggerInitialize0 RVA 0x569c.
Result: immediate hang.
Conclusion: hook at KdDebuggerInitialize0+0 is wrong / not conceptually equivalent to MovAX.
Important correction:
Do not continue hooking KdDebuggerInitialize0+0.
Do not use any more guessed x64 hooks.
First the real x86 MovAX patch must be analyzed at binary level.
What needs to be done next:
Obtain the original x86 Win8.1 kdnet.dll version 6.3.9600.17276.
Apply MovAX kdnet_delta.bin to it.
Binary-diff the original x86 kdnet.dll against the MovAX-patched x86 kdnet.dll.
Determine exactly:
Which bytes were changed at the real hook location?
Where does the first JMP go?
Which x86 function is it really?
Which original instructions are replaced?
Why is add esp,0Ch necessary at the beginning of the payload?
Which register / stack situation does the payload expect?
Find this exact function semantically inside the x64 kdnet.dll.
Only then write the x64 ASM.
The x64 payload must use the real MovAX-analogous location, not KdDebuggerInitialize0+0.
Values still missing for a real x64 MovAX port:
x64 hook location analogous to the real x86 MovAX hook location.
x64 continue address analogous to x86 Continue1 0x8001B5FA.
x64 equivalents of:
HalpKdReadPCIConfig
HalpKdWritePCIConfig
GetPciDataByOffset
SetPciDataByOffset
PCI_ID
Win2003
Header_Patch
x64 equivalent of the location where x86 add esp,0Ch was semantically necessary.
x64 implementation of the HAL patch, if it is really still necessary.
x64 replacement for the x86 PCI structure hack, or a deliberate decision to omit it because /PCILOCK already works.
What is certain:
/DEBUGPORT=NET loads kdnet.dll on XP x64.
If kdnet.dll is missing, the system reaches an early black screen.
Intel i211 Option A means: kdnet.dll + kd_02_8086.dll renamed as kdstub.dll.
kdnet10.dll is wrong for our i211 / Option A test.
/PCILOCK works on XP x64 and sets pci!PciLockDeviceResources.
PciHookHal works and patches HalPrivateDispatchTable correctly.
The old x86 PCI hack using [esi+43h] and [esi+38h] is not directly usable on x64.
The previous x64 payload test packages were not MovAX-conformant because the hook location was guessed.
What is not certain:
Whether the Win8.1 x64 kdnet.dll can fully run on XP x64 with only an x64 MovAX payload.
Whether the HAL patch is still necessary on x64.
Whether /PCILOCK fully replaces the x86 PCI hack.
Whether the Intel i211 kdstub.dll from Win8.1 x64 fully initializes without additional cookie / LoadConfig patches.
Whether host KD version 6.3.9600.17200 is sufficient or whether an exact matching version is required.
Important for the next step:
Do not claim that the ASM payload has already been inserted correctly.
Do not hook KdDebuggerInitialize0+0 again.
First diff the original x86 kdnet.dll against the MovAX-patched kdnet.dll.
Then port the real hook location to x64.
Relevant MovAX note: