Skip to content

Commit

Permalink
Merge pull request #3 from 0vercl0k/fbl_gdt
Browse files Browse the repository at this point in the history
Add gdt.js.
  • Loading branch information
0vercl0k authored Oct 24, 2021
2 parents 87aa82d + d5a6d84 commit f4d58f4
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 6 deletions.
22 changes: 22 additions & 0 deletions Manifest/Manifest.1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@
</Components>
</ExtensionPackage>

<ExtensionPackage>
<Name>Gdt</Name>
<Version>1.0.0.1</Version>
<Description>Gdt dump</Description>
<Components>
<ScriptComponent Name='Gdt' Type='Engine' File='..\gdt\gdt.js' FilePathKind='RepositoryRelative'>
<FunctionAliases>
<FunctionAlias Name='gdt'>
<AliasItem>
<Syntax>
<![CDATA[!gdt <segment selector>]]>
</Syntax>
<Description>
<![CDATA[Dump the GDT or a GDT entry.]]>
</Description>
</AliasItem>
</FunctionAlias>
</FunctionAliases>
</ScriptComponent>
</Components>
</ExtensionPackage>

<ExtensionPackage>
<Name>sm</Name>
<Version>1.0.0.1</Version>
Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

`windbg-scripts` is a collection of [JavaScript](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/javascript-debugger-scripting) debugger extensions for WinDbg.

* [basics](https://github.com/0vercl0k/windbg-scripts/tree/master/basics): various examples of basic usage of various APIs,
* [parse_eh_win64](https://github.com/0vercl0k/windbg-scripts/blob/master/parse_eh_win64): example of extending the data-model with exception handling related information (cf [Debugger data model, Javascript & x64 exception handling](https://doar-e.github.io/blog/2017/12/01/debugger-data-model/)),
* [telescope](https://github.com/0vercl0k/windbg-scripts/blob/master/telescope): [telescope](https://gef.readthedocs.io/en/latest/commands/dereference/) like command for WinDbg,
* [sm](https://github.com/0vercl0k/windbg-scripts/blob/master/sm): pretty-printing of Spidermonkey `js::Value` and `JSObject` objects,
* [codecov](https://github.com/0vercl0k/windbg-scripts/blob/master/codecov): extract code-coverage out of a [TTD](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-debugging-overview) trace,
* [policybuffer](https://github.com/0vercl0k/windbg-scripts/blob/master/policybuffer): disassemble a Chrome policy buffer program.
* [basics](basics/): various examples of basic usage of various APIs,
* [parse_eh_win64](parse_eh_win64/): example of extending the data-model with exception handling related information (cf [Debugger data model, Javascript & x64 exception handling](https://doar-e.github.io/blog/2017/12/01/debugger-data-model/)),
* [telescope](telescope/): [telescope](https://gef.readthedocs.io/en/latest/commands/dereference/) like command for WinDbg,
* [sm](sm/): pretty-printing of Spidermonkey `js::Value` and `JSObject` objects,
* [codecov](codecov/): extract code-coverage out of a [TTD](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-debugging-overview) trace,
* [policybuffer](policybuffer/): disassemble a Chrome policy buffer program,
* [gdt](gdt/): dump the [Global Descriptor Table](https://wiki.osdev.org/Global_Descriptor_Table).

## Installing the script gallery

Expand Down
171 changes: 171 additions & 0 deletions gdt/gdt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Axel '0vercl0k' Souchet - October 8 2021

'use strict';

//
// Small reminders from the manual intels on segments in x64:
// - Because ES, DS, and SS segment registers are not used in 64-bit mode, their fields (base, limit, and attribute) in
// segment descriptor registers are ignored.
// - Selector.Index selects one of 8192 descriptors in the GDT or LDT. The processor multiplies
// the index value by 8 (the number of bytes in a segment descriptor) and adds the result to the base
// address of the GDT or LDT (from the GDTR or LDTR register, respectively).
// - The first entry of the GDT is not used by the processor.
// - The hidden descriptor register fields for FS.base and GS.base are physically mapped to MSRs in order to load all
// address bits supported by a 64-bit implementation. Software with CPL = 0 (privileged software) can load all
// supported linear-address bits into FS.base or GS.base using WRMSR.
//

const log = host.diagnostics.debugLog;
const logln = p => log(`${p}\n`);
const hex = p => `0x${p.toString(16)}`;

const GdtSystemEntryTypes = new Map([
[0, 'Reserved'],
[1, 'Reserved'],
[2, 'LDT'],
[3, 'Reserved'],
[4, 'Reserved'],
[5, 'Reserved'],
[6, 'Reserved'],
[7, 'Reserved'],
[8, 'Reserved'],
[9, 'TSS64 Available'],
[10, 'Reserved'],
[11, 'TSS64 Busy'],
[12, 'CallGate64'],
[13, 'Reserved'],
[14, 'InterruptGate64'],
[15, 'TrapGate64'],
]);

const GdtNonSystemEntryTypes = new Map([
[0, 'Data Read-Only'],
[1, 'Data Read-Only Accessed'],
[2, 'Data Read/Write'],
[3, 'Data Read/Write Accessed'],
[4, 'Data Read-Only Expand-Down'],
[5, 'Data Read-Only Expand-Down Accessed'],
[6, 'Data Read/Write Expand-Down'],
[7, 'Data Read/Write Expand-Down Accessed'],
[8, 'Code Execute-Only'],
[9, 'Code Execute-Only Accessed'],
[10, 'Code Execute/Read'],
[11, 'Code Execute/Read Accessed'],
[12, 'Code Execute-Only Conforming'],
[13, 'Code Execute-Only Conforming Accessed'],
[14, 'Code Execute/Read Conforming'],
[15, 'Code Execute/Read Conforming Accessed'],
]);

const GdtEntryTypes = new Map([
[0, GdtSystemEntryTypes],
[1, GdtNonSystemEntryTypes]
]);

class GdtEntry {
constructor(Addr) {
this._Addr = Addr;
const Entry = host.createPointerObject(Addr, 'nt', '_KGDTENTRY64*');
const LimitHigh = Entry.Bits.LimitHigh.bitwiseShiftLeft(16);
const LimitLow = Entry.LimitLow;
this._Limit = LimitHigh.add(LimitLow);
// For whatever reason _KGDTENTRY64 is 5 bits long. The intel manuals describes
// it as 4bits and the 'Descriptor type' bit.
// We grab the lower 4 bits as the type, and the MSB as the 'Descriptor type'.
this._Type = Entry.Bits.Type & 15;
this._NonSystem = (Entry.Bits.Type >> 4) & 1;
this._TypeS = GdtEntryTypes.get(this._NonSystem).get(this._Type);
// Note that system descriptors in IA-32e mode are 16 bytes instead
// of 8 bytes.
this._Size = 8;
if (!this._NonSystem && this._TypeS != 'Reserved') {
this._Size = 16;
}
this._Dpl = Entry.Bits.Dpl;
this._Granularity = Entry.Bits.Granularity;
this._Present = Entry.Bits.Present;
this._LongMode = Entry.Bits.LongMode;
this._DefaultBig = Entry.Bits.DefaultBig;
const BaseUpper = this._Size == 8 ? 0 : Entry.BaseUpper.bitwiseShiftLeft(32);
const BaseHigh = Entry.Bytes.BaseHigh.bitwiseShiftLeft(24);
const BaseMiddle = Entry.Bytes.BaseMiddle.bitwiseShiftLeft(16);
const BaseLow = Entry.BaseLow;
this._Base = BaseUpper.add(BaseHigh).add(BaseMiddle).add(BaseLow);
}

toString() {
const Increments = this._Granularity == 1 ? 1024 * 4 : 1;
// For example, when the granularity flag is set, a limit of 0 results in
// valid offsets from 0 to 4095.
const Size = this._Limit * Increments + (this._Granularity ? 0xfff : 0);
let S = `dt nt!_KGDTENTRY64 ${hex(this._Addr)}
Base: [${hex(this._Base)} -> ${hex(this._Base.add(Size))}]
Type: ${this._TypeS} (${hex(this._Type)})
DPL: ${hex(this._Dpl)}
Present: ${hex(this._Present)}`;
if (this._TypeS.startsWith('Code')) {
S += `
Mode: ${this._LongMode ? '64b' : (this._DefaultBig ? '32b Compat' : '16b Compat')}`
}
return S;
}
}

function DumpGdtEntry(Addr) {
return new GdtEntry(Addr);
}

function DumpAllGdt() {
const Registers = host.currentThread.Registers;
const GdtBase = Registers.Kernel.gdtr;
const GdtEnd = GdtBase.add(Registers.Kernel.gdtl);
logln(`Dumping the GDT from ${hex(GdtBase)} to ${hex(GdtEnd)}..`);
for (let CurrentEntry = GdtBase, Idx = 0;
CurrentEntry.compareTo(GdtEnd) < 0;
Idx++) {
const Entry = DumpGdtEntry(CurrentEntry);
logln(`[${Idx}]: ${Entry}`);
CurrentEntry = CurrentEntry.add(Entry._Size);
}
}

function DumpGdt(Selector) {
const Registers = host.currentThread.Registers;
const GdtBase = Registers.Kernel.gdtr;
const Index = Selector.bitwiseShiftRight(3);
const Offset = Index.multiply(8);
const EntryAddress = GdtBase.add(Offset);
const Entry = DumpGdtEntry(EntryAddress);
logln(Entry);
}

function Gdt(Selector) {
const Attributes = host.currentSession.Attributes;
const IsKernel = Attributes.Target.IsKernelTarget;
//
// XXX: Not sure how to do this better?
// Attributes.Machine.PointerSize is 4 when running in a Wow64 thread :-/.
//
let Is64Bit = true;
try { host.createPointerObject(0, 'nt', '_KGDTENTRY64*'); } catch(e) { Is64Bit = false; }
if (!IsKernel || !Is64Bit) {
logln('The running session is not a kernel session or it is not running a 64-bit OS, so exiting');
return;
}

if (Selector == undefined) {
DumpAllGdt();
} else {
DumpGdt(Selector);
}
}

function initializeScript() {
return [
new host.apiVersionSupport(1, 3),
new host.functionAlias(
Gdt,
'gdt'
),
];
}

0 comments on commit f4d58f4

Please sign in to comment.