Hi all, I’m just trying to update my x86 architecture knowledge to be AMD64-relevant. I think I have a handle on almost everything going on WRT segmentation on 64 bit win 7, but I’d like to get a sanity check if possible.
Q1 Setup:
When I look at the GDT and segment selectors in the kernel my VM I see this:
0: kd> dd @gdtr
fffff80000b95000 00000000 00000000 00000000 00000000 fffff800
00b95010 00000000 00209b00 0000ffff 00cf9300
fffff80000b95020 0000ffff 00cffa00 0000ffff 00cff300 fffff800
00b95030 00000000 0020fb00 00000000 00000000
fffff80000b95040 60800067 00008bb9 fffff800 00000000 fffff800
00b95050 e0003c00 ff40f3fa 00000000 00000000
fffff80000b95060 0000ffff 00cf9a00 00000000 00000000 fffff800
00b95070 00000000 00000000 00000000 00000000
Which interpreted with a slightly updated version of the windbg plugin from http://opensecuritytraining.info/IntermediateX86.html (because there’s no 64 bit version of the class yet) is:
GDT[0x00] = Empty Descriptor.
GDT[0x01] = Empty Descriptor.
GDT[0x02] = 64 bit ring 0 Code: Execute/Read, Accessed
GDT[0x03] = 32 bit ring 0 Data: Read/Write, Accessed
GDT[0x04] = 32 bit ring 3 Code: Execute/Read
GDT[0x05] = 32 bit ring 3 Data: Read/Write, Accessed
GDT[0x06] = 64 bit ring 3 Code: Execute/Read, Accessed
GDT[0x07] = Empty Descriptor.
GDT[0x08] = 64-bit TSS (Busy)
GDT[0x0a] = 32 bit ring 3 Data: Read/Write, Accessed
GDT[0x0b] = Empty Descriptor.
GDT[0x0c] = 32 bit ring 0 Code: Execute/Read
GDT[0x0d] = Empty Descriptor.
GDT[0x0e] = Empty Descriptor.
GDT[0x0f] = Empty Descriptor.
So
index 2 = kernel 64 bit code segment
index 3 = kernel data segment
index 4 = userspace 32 bit code segment
index 5 = userspace data segment
index 6 = userspace 64 bit code segment (I saw a blog post talking about how 32 bit code far jumps into this segment before calling to kernel, and I confirmed this.)
index 8 = 64 bit TSS (pointed to by task register)
index A = what the FS register (32 bit TEB?) points at
Q1:
But what is index C used for? I haven’t seen anything reference it, but maybe someone else has?
Q2 setup:
I want to confirm that in userspace GS points at a 64 bit address for the TEB. Because data segments can’t actually specify a 64 bit address, that means I should be able to read MSR IA32_GS_BASE (0xC0000101) from a forced userspace context and see the same thing as if I do !teb, right?
So I do
1: kd> !process 0 0 notepad.exe
PROCESS fffffa8000de27f0
SessionId: 1 Cid: 0bcc Peb: 7fffffdf000 ParentCid: 0338
DirBase: 173d4000 ObjectTable: fffff8a001c92790 HandleCount: 278.
Image: notepad.exe
1: kd> .process /i fffffa8000de27f0
1: kd> g
0: kd> .reload (the .process /r option never works properly for me)
0: kd> u ntdll!NtOpenFile
ntdll!NtOpenFile:
00000000777401e0 4c8bd1 mov r10,rcx 00000000
777401e3 b830000000 mov eax,30h
00000000777401e8 0f05 syscall 00000000
777401ea c3 ret
00000000`777401eb 0f1f440000 nop dword ptr [rax+rax]
So OK, I should be in userspace (this is 64 bit notepad btw) in the kernel debugger at this point. So I do
1: kd> rdmsr 0xC0000101
msr[c0000101] = fffff880009e8000 1: kd\> rdmsr 0xC0000102 msr[c0000102] = 000007ff
fffdd000
1: kd> !teb
TEB at 000007fffffdd000
Q2:
OK, so the TEB address seems to be in IA32_KERNEL_GS_BASE…so maybe it’s just because I’m in the kernel debugger it’s doing the swapgs instruction before calling back into the kernel debugger?
But here’s the thing which I don’t get at all. If I then resume the VM, go into the VM and attach with userspace windbg, and do !teb, I get
TEB at 000007fffffd9000
Anyone know why they show different addresses?
Q3: I’ve heard that Winodws 7 starts to use the LDT for user-mode scheduling? How would I see evidence of that? Because ? @ldtr shows up as zero for me, and I don’t see any LDT entry in the GDT.
thks
JB