Last active
April 20, 2022 15:29
-
-
Save hkraw/5bc0a4cf4615da4e3bb3a846ecb4fe19 to your computer and use it in GitHub Desktop.
add proper chain handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//"use script"; | |
const color_red = "[31m"; | |
const color_green = "[32m"; | |
const color_yellow = "[33m"; | |
const color_blue = "[43m"; | |
const color_mag = "[35m"; | |
const color_cyan = "[36m"; | |
const color_default = "[0m"; | |
const DefaultNumberOfInstructions = 3; | |
const DefaultMaxStringLength = 15; | |
const DefaultNumberOfLines = 10; | |
String.prototype.ljust = function(length, char) { | |
var fill = []; | |
while(fill.length + this.length < length) { | |
fill[fill.length] = char; | |
} | |
return fill.join('') + this; | |
} | |
String.prototype.rjust = function(length, char) { | |
var fill = []; | |
while(fill.length + this.length < length) { | |
fill[fill.length] = char; | |
} | |
return this + fill.join(''); | |
} | |
String.prototype.format = function() { | |
str = this; | |
for(k in arguments) { | |
str = str.replace("{" + k + "}", arguments[k]); | |
} | |
return str; | |
} | |
const log = host.diagnostics.debugLog; | |
let logln = function ( e ) { host.diagnostics.debugLog(e); } | |
let region_Stack = function( addr, end ) { logln( color_red + addr + color_default ); } | |
let region_Heap = function( addr, end ) { logln( color_cyan + addr + color_default); } | |
let region_Image = function( addr, end ) { login ( color_yellow + addr + color_default ); } | |
function ReadU64(Addr) { | |
let Value = null; | |
try { | |
Value = host.memory.readMemoryValues( | |
Addr, 1, 8 | |
)[0]; | |
} catch(e) { | |
} | |
return Value; | |
} | |
function ReadU32(Addr) { | |
let Value = null; | |
try { | |
Value = host.memory.readMemoryValues( | |
Addr, 1, 4 | |
)[0]; | |
} catch(e) { | |
} | |
return Value; | |
} | |
function ReadU16(Addr) { | |
let Value = null; | |
try { | |
Value = host.memory.readMemoryValues( | |
Addr, 1, 2 | |
)[0]; | |
} catch(e) { | |
} | |
return Value; | |
} | |
function ReadString(Addr, MaxLength) { | |
let Value = null; | |
try { | |
Value = host.memory.readString(Addr); | |
} catch(e) { | |
return null; | |
} | |
if(Value.length > MaxLength) { | |
return Value.substr(0, MaxLength); | |
} | |
return Value; | |
} | |
function ReadWideString(Addr) { | |
let Value = null; | |
try { | |
Value = host.memory.readWideString(Addr); | |
} catch(e) { | |
} | |
return Value; | |
} | |
function Disassemble(Addr) { | |
const Code = host.namespace.Debugger.Utility.Code; | |
const Disassembler = Code.CreateDisassembler( | |
PointerSize == 8 ? 'X64' : 'X86' | |
); | |
const Instrs = Array.from(Disassembler.DisassembleInstructions(Addr).Take( | |
DefaultNumberOfInstructions | |
)); | |
return Instrs.map( | |
// | |
// Clean up the assembly. | |
// Turn the below: | |
// 'mov rbx,qword ptr [00007FF8D3525660h] ; test rbx,rbx ; je 00007FF8D34FC2EB' | |
// Into: | |
// 'mov rbx,qword ptr [00007FF8D3525660h] ; test rbx,rbx ; je 00007FF8D34FC2EB' | |
// | |
p => p.toString().replace(/[ ]+/g, ' ') | |
).join(' ; '); | |
} | |
function FormatU64(Addr) { | |
return '0x' + Addr.toString(16).padStart(16, '0'); | |
} | |
function FormatU32(Addr) { | |
return '0x' + Addr.toString(16).padStart(8, '0'); | |
} | |
function FormatString(Str) { | |
if(Str.length > DefaultMaxStringLength) { | |
return Str.substr(0, DefaultMaxStringLength) + '...' | |
} | |
return Str; | |
} | |
function BitSet(Value, Bit) { | |
return Value.bitwiseAnd(Bit).compareTo(0) != 0; | |
} | |
// | |
// Initialization / global stuff. | |
// | |
let Initialized = false; | |
let ReadPtr = null; | |
let PointerSize = null; | |
let FormatPtr = null; | |
let IsTTD = false; | |
let IsUser = false; | |
let IsKernel = false; | |
let VaSpace = []; | |
function *SectionHeaders(BaseAddress) { | |
if(IsKernel && ReadU32(BaseAddress) == null) { | |
// | |
// If we can't read the module, then..bail :(. | |
// XXX: Fix this? Session space? Paged out? | |
// | |
logln('Cannot read ' + BaseAddress.toString(16) + ', skipping.'); | |
return; | |
} | |
// 0:000> dt _IMAGE_DOS_HEADER e_lfanew | |
// +0x03c e_lfanew : Int4B | |
const NtHeaders = BaseAddress.add(ReadU32(BaseAddress.add(0x3c))); | |
// 0:000> dt _IMAGE_NT_HEADERS64 FileHeader | |
// +0x004 FileHeader : _IMAGE_FILE_HEADER | |
// 0:000> dt _IMAGE_FILE_HEADER NumberOfSections SizeOfOptionalHeader | |
// +0x002 NumberOfSections : Uint2B | |
// +0x010 SizeOfOptionalHeader : Uint2B | |
const NumberOfSections = ReadU16(NtHeaders.add(0x4 + 0x2)); | |
const SizeOfOptionalHeader = ReadU16(NtHeaders.add(0x4 + 0x10)); | |
// 0:000> dt _IMAGE_NT_HEADERS64 OptionalHeader | |
// +0x018 OptionalHeader : _IMAGE_OPTIONAL_HEADER64 | |
const OptionalHeader = NtHeaders.add(0x18); | |
const SectionHeaders = OptionalHeader.add(SizeOfOptionalHeader); | |
// 0:000> ?? sizeof(_IMAGE_SECTION_HEADER) | |
// unsigned int64 0x28 | |
const SizeofSectionHeader = 0x28; | |
for(let Idx = 0; Idx < NumberOfSections; Idx++) { | |
const SectionHeader = SectionHeaders.add( | |
Idx.multiply(SizeofSectionHeader) | |
); | |
// 0:000> dt _IMAGE_SECTION_HEADER Name | |
// +0x000 Name : [8] UChar | |
const Name = ReadString(SectionHeader, 8); | |
// 0:000> dt _IMAGE_SECTION_HEADER VirtualAddress | |
// +0x00c VirtualAddress : Uint4B | |
const Address = BaseAddress.add( | |
ReadU32(SectionHeader.add(0xc)) | |
); | |
// 0:000> dt _IMAGE_SECTION_HEADER SizeOfRawData | |
// +0x08 Misc : Uint4B | |
// XXX: Take care of alignment? | |
const VirtualSize = ReadU32(SectionHeader.add(0x08)); | |
// 0:000> dt _IMAGE_SECTION_HEADER Characteristics | |
// +0x024 Characteristics : Uint4B | |
const Characteristics = ReadU32(SectionHeader.add(0x24)); | |
const Properties = [ | |
'-', | |
'-', | |
'-' | |
]; | |
// The section can be read. | |
const IMAGE_SCN_MEM_READ = host.Int64(0x40000000); | |
if(BitSet(Characteristics, IMAGE_SCN_MEM_READ)) { | |
Properties[0] = 'r'; | |
} | |
if(IsKernel) { | |
const IMAGE_SCN_MEM_DISCARDABLE = host.Int64(0x2000000); | |
if(BitSet(Characteristics, IMAGE_SCN_MEM_DISCARDABLE)) { | |
Properties[0] = '-'; | |
} | |
} | |
// The section can be written to. | |
const IMAGE_SCN_MEM_WRITE = host.Int64(0x80000000); | |
if(Characteristics.bitwiseAnd(IMAGE_SCN_MEM_WRITE).compareTo(0) != 0) { | |
Properties[1] = 'w'; | |
} | |
// The section can be executed as code. | |
const IMAGE_SCN_MEM_EXECUTE = host.Int64(0x20000000); | |
if(Characteristics.bitwiseAnd(IMAGE_SCN_MEM_EXECUTE).compareTo(0) != 0) { | |
Properties[2] = 'x'; | |
} | |
yield new _Region( | |
Address, | |
VirtualSize, | |
Name, | |
Properties.join('') | |
); | |
} | |
} | |
function HandleTTD() { | |
const CurrentSession = host.currentSession; | |
// | |
// Grab addressable chunks. | |
// | |
logln('Populating the VA space with TTD.Data.Heap..'); | |
const CurrentThread = host.currentThread; | |
const Position = CurrentThread.TTD.Position; | |
const Chunks = CurrentSession.TTD.Data.Heap().Where( | |
p => p.TimeStart.compareTo(Position) < 0 && | |
p.Action == 'Alloc' | |
); | |
for(const Chunk of Chunks) { | |
VaSpace.push(new _Region( | |
Chunk.Address, | |
Chunk.Size, | |
'Heap', | |
'rw-' | |
)); | |
} | |
// | |
// Grab virtual allocated memory regions. | |
// | |
logln('Populating the VA space with VirtualAllocated regions..'); | |
const VirtualAllocs = CurrentSession.TTD.Calls( | |
'kernelbase!VirtualAlloc' | |
).Where( | |
p => p.TimeStart.compareTo(Position) < 0 | |
); | |
for(const VirtualAlloc of VirtualAllocs) { | |
VaSpace.push(new _Region( | |
VirtualAlloc.ReturnValue, | |
VirtualAlloc.Parameters[1], | |
'VirtualAlloced', | |
// XXX: parse access | |
'rw-' | |
)); | |
} | |
// | |
// Grab mapped view regions. | |
// | |
logln('Populating the VA space with MappedViewOfFile regions..'); | |
const MapViewOfFiles = CurrentSession.TTD.Calls( | |
'kernelbase!MapViewOfFile' | |
).Where( | |
p => p.TimeStart.compareTo(Position) < 0 | |
); | |
for(const MapViewOfFile of MapViewOfFiles) { | |
VaSpace.push(new _Region( | |
MapViewOfFile.ReturnValue, | |
0x1000, | |
'MappedView', | |
// XXX: parse access | |
'rw-' | |
)); | |
} | |
} | |
function HandleUser() { | |
// | |
// Enumerate the modules. | |
// | |
// logln('Populating the VA space with modules..'); | |
const CurrentProcess = host.currentProcess; | |
for(const Module of CurrentProcess.Modules) { | |
// | |
// Iterate over the section headers of the module. | |
// | |
for(const Section of SectionHeaders(Module.BaseAddress)) { | |
VaSpace.push(new _Region( | |
Section.BaseAddress, | |
Section.Size, | |
'Image ' + Module.Name + ' (' + Section.Name + ')', | |
Section.Properties | |
)); | |
} | |
// | |
// Add a catch all in case a pointer points inside the PE but not | |
// inside any sections (example of this is the PE header). | |
// | |
VaSpace.push(new _Region( | |
Module.BaseAddress, | |
Module.Size, | |
'Image ' + Module.Name, | |
'r--' | |
)); | |
} | |
// | |
// Enumerates the TEBs and the stacks. | |
// | |
//logln('Populating the VA space with TEBs & thread stacks..'); | |
for(const Thread of CurrentProcess.Threads) { | |
const Teb = Thread.Environment.EnvironmentBlock; | |
// | |
// TEB! | |
// | |
// In the case where you have broken `ntdll` symbols, you might not have | |
// the definition of the `_TEB` structure. In this case, the structured | |
// `Teb` object above is undefined (like in issues #2). So we try to be resilient | |
// against that in the below. | |
// | |
if(Teb == undefined) { | |
const General = host.namespace.Debugger.State.PseudoRegisters.General; | |
VaSpace.push(new _Region( | |
General.teb.address, | |
0x100, | |
'Teb of ' + Thread.Id.toString(16), | |
'rw-' | |
)); | |
continue; | |
} | |
VaSpace.push(new _Region( | |
Teb.address, | |
Teb.targetType.size, | |
'Teb of ' + Thread.Id.toString(16), | |
'rw-' | |
)); | |
// | |
// Stacks! | |
// | |
const StackBase = Teb.NtTib.StackBase.address; | |
const StackLimit = Teb.NtTib.StackLimit.address; | |
VaSpace.push(new _Region( | |
StackLimit, | |
StackBase.subtract(StackLimit), | |
'Stack', | |
'rw-' | |
)); | |
} | |
// | |
// Get the PEB. Keep in mind we can run into the same symbol problem with the | |
// PEB - so account for that. | |
// | |
//logln('Populating the VA space with the PEB..'); | |
const Peb = CurrentProcess.Environment.EnvironmentBlock; | |
if(Peb == undefined) { | |
const General = host.namespace.Debugger.State.PseudoRegisters.General; | |
VaSpace.push(new _Region( | |
General.peb.address, | |
0x1000, | |
'Peb', | |
'rw-' | |
)); | |
logln(`/!\\ Several regions have been skipped because nt!_TEB / nt!_PEB aren't available in your symbols.`); | |
} else { | |
VaSpace.push(new _Region( | |
Peb.address, | |
Peb.targetType.size, | |
'Peb', | |
'rw-' | |
)); | |
} | |
} | |
function HandleKernel() { | |
// | |
// Enumerate the kernel modules. | |
// | |
logln('Populating the VA space with kernel modules..'); | |
const CurrentSession = host.currentSession; | |
const SystemProcess = CurrentSession.Processes.First( | |
p => p.Name == 'System' | |
); | |
const MmUserProbeAddress = ReadPtr( | |
host.getModuleSymbolAddress('nt', 'MmUserProbeAddress') | |
); | |
const KernelModules = SystemProcess.Modules.Where( | |
p => p.BaseAddress.compareTo(MmUserProbeAddress) > 0 | |
); | |
for(const Module of KernelModules) { | |
// | |
// Iterate over the section headers of the module. | |
// | |
for(const Section of SectionHeaders(Module.BaseAddress)) { | |
VaSpace.push(new _Region( | |
Section.BaseAddress, | |
Section.Size, | |
'Driver ' + Module.Name + ' (' + Section.Name + ')', | |
Section.Properties | |
)); | |
} | |
// | |
// Add a catch all in case a pointer points inside the PE but not | |
// inside any sections (example of this is the PE header). | |
// | |
VaSpace.push(new _Region( | |
Module.BaseAddress, | |
Module.Size, | |
'Driver ' + Module.Name, | |
'r--' | |
)); | |
} | |
} | |
function InitializeVASpace() { | |
if(IsUser) { | |
HandleUser(); | |
} | |
if(IsTTD) { | |
// | |
// If we have a TTD target, let's do some more work. | |
// | |
HandleTTD(); | |
} | |
if(IsKernel) { | |
HandleKernel(); | |
} | |
} | |
function InitializeWrapper() { | |
if(!Initialized) { | |
const CurrentSession = host.currentSession; | |
// | |
// Initialize the ReadPtr function according to the PointerSize. | |
// | |
PointerSize = CurrentSession.Attributes.Machine.PointerSize; | |
ReadPtr = PointerSize.compareTo(8) == 0 ? ReadU64 : ReadU32; | |
FormatPtr = PointerSize.compareTo(8) == 0 ? FormatU64 : FormatU32; | |
const TargetAttributes = CurrentSession.Attributes.Target; | |
IsTTD = TargetAttributes.IsTTDTarget; | |
IsUser = TargetAttributes.IsUserTarget; | |
IsKernel = TargetAttributes.IsKernelTarget; | |
// | |
// One time initialization! | |
// | |
Initialized = true; | |
} | |
} | |
// | |
// The meat! | |
// | |
class _Region { | |
constructor(BaseAddress, Size, Name, Properties) { | |
this.Name = Name; | |
this.BaseAddress = BaseAddress; | |
this.EndAddress = this.BaseAddress.add(Size); | |
this.Size = Size; | |
this.Properties = Properties; | |
this.Executable = false; | |
this.Readable = false; | |
this.Writeable = false; | |
if(Properties.indexOf('r') != -1) { | |
this.Readable = true; | |
} | |
if(Properties.indexOf('w') != -1) { | |
this.Writeable = true; | |
} | |
if(Properties.indexOf('x') != -1) { | |
this.Executable = true; | |
} | |
} | |
In(Addr) { | |
const InBounds = Addr.compareTo(this.BaseAddress) >= 0 && | |
Addr.compareTo(this.EndAddress) < 0; | |
return InBounds; | |
} | |
toString() { | |
const Prop = [ | |
this.Readable ? 'r' : '-', | |
this.Writeable ? 'w' : '-', | |
this.Executable ? 'x' : '-' | |
]; | |
return this.Name + ' ' + Prop.join(''); | |
} | |
} | |
function AddressToRegion(Addr) { | |
// | |
// Map the address space with VA regions. | |
// | |
const Hits = VaSpace.filter( | |
p => p.In(Addr) | |
); | |
// | |
// Now, let's get the most precise region information by ordering | |
// the hits by size. | |
// | |
const OrderedHits = Hits.sort( | |
p => p.Size | |
); | |
// | |
// Return the most precise information we have! | |
// | |
return OrderedHits[0]; | |
} | |
class _ChainEntry { | |
constructor(Addr, Value) { | |
this.Addr = Addr; | |
this.Value = Value; | |
this.AddrRegion = AddressToRegion(this.Addr); | |
this.ValueRegion = AddressToRegion(this.Value); | |
if(this.ValueRegion == undefined) { | |
this.Name = 'Unknown'; | |
} else { | |
// | |
// Just keep the file name and strips off the path. | |
// | |
this.Name = this.ValueRegion.Name; | |
this.Name = this.Name.substring(this.Name.lastIndexOf('\\') + 1); | |
} | |
this.Last = false; | |
} | |
Equals(Entry) { | |
return this.Addr.compareTo(Entry.Addr) == 0; | |
} | |
toString() { | |
let color = color_default; | |
if(this.Name[0] == 'S') { | |
color = color_red; | |
} else if (this.Name.search(".dll") != -1) { | |
color = color_cyan; | |
} else if(this.Name.search(".exe") != -1) { | |
color = color_cyan; | |
} | |
const S = color + FormatPtr(this.Value) + ' (' + this.Name + ')' + color_default; | |
if(!this.Last) { | |
return S; | |
} | |
// | |
// We only provide disassembly if we know that the code is executeable. | |
// And in order to know that, we need to have a valid `AddrRegion`. | |
// | |
if(this.AddrRegion != undefined && this.AddrRegion.Executable) { | |
return Disassemble(this.Addr); | |
} | |
// | |
// If we have a string stored in a heap allocation what happens is the following: | |
// - The extension does not know about heap, so `AddrRegion` for such a pointer | |
// would be `undefined`. | |
// - Even though it is undefined, we would like to display a string if there is any, | |
// instead of just the first qword. | |
// So to enable the scenario to work, we allow to enter the below block with an `AddrRegion` | |
// that is undefined. | |
// | |
if(this.AddrRegion == undefined || this.AddrRegion.Readable) { | |
const IsPrintable = p => { | |
return p != null && | |
// XXX: ugly AF. | |
p.match(/^[a-z0-9!"#$%&'()*+,/\\.:;<=>?@\[\] ^_`{|}~-]+$/i) != null && | |
p.length > 5 | |
}; | |
// | |
// Maybe it points on a unicode / ascii string? | |
// | |
const Ansi = ReadString(this.Addr); | |
if(IsPrintable(Ansi)) { | |
return `${FormatPtr(this.Addr)} (Ascii(${FormatString(Ansi)}))`; | |
} | |
const Wide = ReadWideString(this.Addr); | |
if(IsPrintable(Wide)) { | |
return `${FormatPtr(this.Addr)} (Unicode(${FormatString(Wide)}))`; | |
} | |
} | |
// | |
// If we didn't find something better, fallback to the regular | |
// output. | |
// | |
return S; | |
} | |
} | |
class _Chain { | |
constructor(Addr) { | |
this.__Entries = []; | |
this.__HasCycle = false; | |
this.__Addr = Addr; | |
while(this.FollowPtr()) { }; | |
this.__Length = this.__Entries.length; | |
// | |
// Tag the last entry as 'last'. | |
// | |
if(this.__Length >= 1) { | |
this.__Entries[this.__Length - 1].Last = true; | |
} | |
} | |
FollowPtr() { | |
// | |
// Attempt to follow the pointer. | |
// | |
const Value = ReadPtr(this.__Addr); | |
if(Value == null) { | |
// | |
// We are done following pointers now! | |
// | |
return false; | |
} | |
// | |
// Let's build an entry and evaluate what we want to do with it. | |
// | |
const Entry = new _ChainEntry(this.__Addr, Value); | |
const DoesEntryExist = this.__Entries.find( | |
p => p.Equals(Entry) | |
); | |
if(DoesEntryExist) { | |
// | |
// If we have seen this Entry before, it means there's a cycle | |
// and we will stop there. | |
// | |
this.__HasCycle = true; | |
return false; | |
} | |
// | |
// This Entry is of interest, so let's add it in our list. | |
// | |
this.__Entries.push(Entry); | |
this.__Addr = Value; | |
return true; | |
} | |
toString() { | |
if(this.__Entries.length == 0) { | |
return ''; | |
} | |
// | |
// Iterate over the chain. | |
// | |
let S = this.__Entries.join(' -> '); | |
// | |
// Add a little something if we have a cycle so that the user knows. | |
// | |
if(this.__HasCycle) { | |
S += ' [...]'; | |
} | |
return S; | |
} | |
*[Symbol.iterator]() { | |
for(const Entry of this.__Entries) { | |
yield Entry; | |
} | |
} | |
} | |
let xi = function( addr ) { | |
const Code = host.namespace.Debugger.Utility.Code; | |
const Disassembler = Code.CreateDisassembler( 'X64' ); | |
const Instrs = Array.from(Disassembler.DisassembleInstructions( addr ).Take(3)); | |
return Instrs.map( | |
p => p.toString().replace(/[ ]+/g,' ') | |
).join('; '); | |
} | |
let color_print = function( addr ) { | |
let AddrRegion = AddressToRegion(addr); | |
let Name = ""; | |
if(AddrRegion == undefined) { | |
return color_default; | |
} else { | |
Name = AddrRegion.Name; | |
Name = Name.substring(Name.lastIndexOf('\\') + 1); | |
} | |
if(Name[0] == 'S') { | |
return color_red; | |
} else if (Name.search(".dll") != -1) { | |
return color_cyan; | |
} else if(Name.search(".exe") != -1) { | |
return color_cyan; | |
} | |
} | |
let read_mem = function( addr , size, n ) { | |
return host.memory.readMemoryValues(addr, n, size); | |
} | |
let getUserRegisters = function(print_registers) { | |
let Regs = host.currentThread.Registers.User; | |
let registers = { | |
"rax": Regs.rax, "rbx": Regs.rbx, "rcx":Regs.rcx, "rdx":Regs.rdx, | |
"rsi":Regs.rsi, "rdi":Regs.rdi, "rip":Regs.rip, "rsp":Regs.rsp, | |
"rbp":Regs.rbp, "r8 ":Regs.r8, "r9 ":Regs.r9, "r10":Regs.r10, | |
"r11":Regs.r11, "r12":Regs.r12, "r13":Regs.r13, "r14":Regs.r14, | |
"r15":Regs.r15 | |
}; | |
let chain = 0; | |
let Header = 0; | |
let color = color_default; | |
InitializeWrapper(); | |
InitializeVASpace(); | |
if (print_registers) { | |
for (let [key, value] of Object.entries(registers)) { | |
logln(`${color_mag}${key}${color_default}: `); | |
chain = new _Chain(value, [value]); | |
color = color_print(value); | |
let Header = color + FormatPtr(value) + color_default; | |
if(chain.toString().split('->').length > 1) { | |
Header += ' -> '; | |
} else if(chain.toString().split('->')[0].search('Unknown') != -1) { | |
Header += ' -> '; | |
} else if(chain.toString().split('->')[0].search(';') != -1) { | |
Header += ' -> '; | |
} | |
logln(Header + chain.toString() + '\n'); | |
} | |
} | |
return registers; | |
}; | |
let step = function(aaa, n) { | |
var Control = host.namespace.Debugger.Utility.Control; | |
var dbg = host.namespace.Debugger; | |
for(var j = 1; j <= n; j++) { Control.ExecuteCommand(aaa); } | |
logln(`${color_cyan}------------------------------Registers---------------------------------------${color_default}\n`); | |
getUserRegisters(true); | |
logln(`${color_cyan}------------------------------Disassembly-------------------------------------${color_default}\n`); | |
var i = 0; | |
for(let Line of Control.ExecuteCommand('u @rip')) { | |
if(i == 1) { | |
logln(`${color_red} ==>${color_default} ${color_green}${Line}\n${color_default}`) | |
} | |
else { | |
logln(`${color_yellow} ${Line}\n${color_default}`); | |
} | |
i += 1; | |
} | |
logln(`${color_cyan}-------------------------------Stack------------------------------------------${color_default}\n\n`); | |
for(let Line of Control.ExecuteCommand("!telescope @rsp")) { logln(Line + '\n'); } | |
} | |
let si = function( n = 1) { | |
step('t', n) | |
} | |
let ni = function( n = 1) { | |
step('p', n); | |
} | |
let printHex = function( size, bytes ) { | |
let hexStr = bytes.toString(16); | |
hexStr = hexStr.ljust(size, '0'); | |
logln(`0x${hexStr} `); | |
} | |
let x = function(n, addr, size) { | |
if(addr == undefined) { | |
logln("[+] x/xg `@addr` `n`\n"); | |
} else { | |
if(n % 2 != 0) { n += 1; } | |
var data = read_mem(addr, size, n); | |
for(let i = 0; i < data.length; i += 2) { | |
logln(`0x${(addr + i * 8).toString(16)}: `) | |
printHex(size * 2, data[i]); | |
printHex(size * 2, data[i + 1]); | |
logln('\n'); | |
} | |
} | |
} | |
let x_xg = function(addr, n = 28) { | |
x(n, addr, 8); | |
} | |
let x_xdw = function(addr, n = 28) { | |
x(n, addr, 4); | |
} | |
let x_xw = function(addr, n = 28) { | |
x(n, addr, 2); | |
} | |
let x_xb = function(addr) { | |
var data = read_mem(addr, 1)[0]; | |
logln(`0x${data.toString(16)}\n`); | |
} | |
function Telescope(Addr, n) { | |
if(!Initialized) { | |
let CurrentSession = host.currentSession; | |
// | |
// Initialize the ReadPtr function according to the PointerSize. | |
// | |
PointerSize = CurrentSession.Attributes.Machine.PointerSize; | |
ReadPtr = PointerSize.compareTo(8) == 0 ? ReadU64 : ReadU32; | |
FormatPtr = PointerSize.compareTo(8) == 0 ? FormatU64 : FormatU32; | |
const TargetAttributes = CurrentSession.Attributes.Target; | |
IsTTD = TargetAttributes.IsTTDTarget; | |
IsUser = TargetAttributes.IsUserTarget; | |
IsKernel = TargetAttributes.IsKernelTarget; | |
// | |
// One time initialization! | |
// | |
Initialized = true; | |
} | |
if(Addr == undefined) { | |
logln('!telescope <addr>'); | |
return; | |
} | |
// | |
// Initialize the VA space. | |
// | |
InitializeVASpace(); | |
var CurrentSession = host.currentSession; | |
var Lines = n == undefined ? DefaultNumberOfLines : n; | |
var PointerSize = CurrentSession.Attributes.Machine.PointerSize; | |
var FormatOffset = p => '0x' + p.toString(16).padStart(4, '0'); | |
for(let Idx = 0; Idx < Lines; Idx++) { | |
const Offset = PointerSize.multiply(Idx); | |
const CurAddr = Addr.add(Offset); | |
const Chain = new _Chain(CurAddr); | |
const Header = color_red + FormatPtr(CurAddr) + color_default + '|+' + FormatOffset(Offset); | |
logln(Header + ': ' + Chain + '\n'); | |
} | |
VaSpace = []; | |
} | |
function initializeScript() { | |
return [ | |
new host.apiVersionSupport(1, 3), | |
new host.functionAlias(si, 'si'), | |
new host.functionAlias(ni, 'ni'), | |
new host.functionAlias(x_xg, 'xg'), | |
new host.functionAlias(x_xdw, 'xdw'), | |
new host.functionAlias(x_xw, 'xw'), | |
new host.functionAlias(x_xb, 'xb'), | |
new host.functionAlias(xi, 'xi'), | |
new host.functionAlias(Telescope, 'telescope') /* https://github.com/0vercl0k/windbg-scripts/tree/master/telescope */ | |
]; | |
} | |
/* I've taken the code to make chains and find regions from https://github.com/0vercl0k/windbg-scripts/tree/master/telescope */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment