A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #17443  by myid
 Sat Dec 29, 2012 1:33 pm
I know we can use "SGDT" instruction to get GDT base and size, and WINDBG show the GDT structure:
Code: Select all
nt!_KGDTENTRY64
   +0x000 LimitLow         : Uint2B
   +0x002 BaseLow          : Uint2B
   +0x004 Bytes            : <unnamed-tag>
   +0x004 Bits             : <unnamed-tag>
   +0x008 BaseUpper        : Uint4B
   +0x00c MustBeZero       : Uint4B
   +0x000 Alignment        : Uint8B
But how to get each item's BASE address and LIMIT?
I use WINDBG to view memory, I found that the value of member "MustBeZero" always is not zero. :cry:
I don't know the meaning of "MustBeZero". I guess the real structure is:
Code: Select all
typedef struct _GDT
{
	WORD	LimitLow;
	WORD	BaseLow;
	DWORD	BytesBits;
	DWORD	BaseUpper;
	WORD	LimitUpper;	//or BaseMiddle?
	WORD	BaseMiddle;	//or LimitUpper?
}GDT, *PGDT;
correct?
 #17445  by ISergey256
 Sat Dec 29, 2012 5:35 pm
Code: Select all
typedef union _KGDTENTRY64
{
    struct
    {
        USHORT LimitLow;
        USHORT BaseLow;
        union
        {
            struct
            {
                UCHAR BaseMiddle;
                UCHAR Flags1;
                UCHAR Flags2;
                UCHAR BaseHigh;
            } Bytes;
            struct
            {
                ULONG BaseMiddle:8;
                ULONG Type:5;
                ULONG Dpl:2;
                ULONG Present:1;
                ULONG LimitHigh:4;
                ULONG System:1;
                ULONG LongMode:1;
                ULONG DefaultBig:1;
                ULONG Granularity:1;
                ULONG BaseHigh:8;
            } Bits;
        };
        ULONG BaseUpper;
        ULONG MustBeZero;
    };
    UINT64 Alignment;
} KGDTENTRY64, *PKGDTENTRY64;
 #17447  by myid
 Sat Dec 29, 2012 10:40 pm
ISergey256 wrote:
Code: Select all
typedef union _KGDTENTRY64
{
    struct
    {
        USHORT LimitLow;
        USHORT BaseLow;
        union
        {
            struct
            {
                UCHAR BaseMiddle;
                UCHAR Flags1;
                UCHAR Flags2;
                UCHAR BaseHigh;
            } Bytes;
            struct
            {
                ULONG BaseMiddle:8;
                ULONG Type:5;
                ULONG Dpl:2;
                ULONG Present:1;
                ULONG LimitHigh:4;
                ULONG System:1;
                ULONG LongMode:1;
                ULONG DefaultBig:1;
                ULONG Granularity:1;
                ULONG BaseHigh:8;
            } Bits;
        };
        ULONG BaseUpper;
        ULONG MustBeZero;
    };
    UINT64 Alignment;
} KGDTENTRY64, *PKGDTENTRY64;
Thanks in advance.
 #17453  by feryno
 Mon Dec 31, 2012 10:10 am
what is the purpose of obtaining bases and limits?
do you need to parse the whole GDT or are you interested only in some selectors?
don't forget that for win x64 FS and GS bases are in MSRs
also for obtaining limit there is a way in 2 asm instructions like these samples
Code: Select all
mov cx,cs
lsl eax,cx
Code: Select all
str dx
lsl eax,dx
if you want to extract limit directly from desired GDT offset then sample looks like this
Code: Select all
mov ax,10h
lsl eax,ax
also another thought - if bit 2 of selector is set to 1 then you need to parse LDT instead of GDT (but I doubt whether win x64 even uses LDT, maybe everything is only in GDT)

later edit - remembered another thing
under x64 when the System bit is set to 1 (see the descriptor structure posted by ISergey256) then the descriptor is 8 bytes wide (e.g. code, data, stack where base is limited to 32 bits - so for FS and GS there is a need to have 64 bit base in MSR), when the bit is set to 0 (0=System-Segment Descriptor) it is expanded to 16 bytes (e.g. TSS, LDT, gates) - occupies 2 entries in GDT
so when you want to obtain TSS base then bits 63-32 of TSS base are located at dword +8

something like this:
Code: Select all
	str	cx				; store task register
	sub	rsp,8*2
	sgdt	[rsp+6]
	mov	rdx,[rsp+8]			; grab GDT base
	add	rsp,8*2
	test	cl,00000100b			; check bit 2 of selector (TI bit)
	jnz	error					; TSS can't be located in LDT (only hypothetical situation, such system cannot be alive)
	and	ecx,0000FFF8h			; leave only bits 16-3 of selector
	bt	dword [rdx + rcx*1 + 4],12	; check System bit of descriptor
	jc	error					; again only hypothetical check, system with TSS with this bit set to 1 can't be alive
	mov	eax,[rdx + rcx*1 + 2]
	mov	rcx,[rdx + rcx*1 + 4]
	and	eax,         00FFFFFFh		; base address bits 23-0
	and	rcx,0FFFFFFFFFF000000h	; base address bits 63-24
	or	rax,rcx
; rax = TSS base
sorry I'm not able to convert the above code into C (but it is trivial for somebody skilled in C)