Last active
December 30, 2022 23:48
-
-
Save e455a81e-d3ba-41a2-bc6d-7aafb1d9a5cd/e1d303a963d45887f29bfd8cfe8d363d to your computer and use it in GitHub Desktop.
Read the page at '0x00000000`7ffe0000' using F# and print its content.
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
open System | |
open System.Runtime.InteropServices | |
[<Literal>] | |
let MAXIMUM_XSTATE_FEATURES = 64 | |
[<Literal>] | |
let PROCESSOR_FEATURE_MAX = 64 | |
[<Struct; StructLayout(LayoutKind.Sequential)>] | |
type XSTATE_FEATURE = | |
{ | |
Offset: uint32 | |
Size: uint32 | |
} | |
[<Struct; StructLayout(LayoutKind.Sequential)>] | |
type XSTATE_CONFIGURATION = | |
{ | |
EnabledFeatures: uint64 | |
Size: uint32 | |
OptimizedSave: bool | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_XSTATE_FEATURES)>] | |
Features: XSTATE_FEATURE array | |
} | |
type NT_PRODUCT_TYPE = | |
| NtProductWinNt = 1 | |
| NtProductLanManNt = 2 | |
| NtProductServer = 3 | |
[<Struct; StructLayout(LayoutKind.Sequential)>] | |
type KSYSTEM_TIME = | |
{ | |
LowPart: uint32 | |
High1Time: int32 | |
High2Time: int32 | |
} | |
type ALTERNATIVE_ARCHITECTURE_TYPE = | |
| StandardDesign | |
| NEC98x86 | |
| EndAlternatives | |
[<Struct; StructLayout(LayoutKind.Sequential)>] | |
type KUSER_SHARED_DATA = | |
{ | |
TickCountLowDeprecated: uint32 | |
TickCountMultiplier: uint32 | |
InterruptTime: KSYSTEM_TIME | |
SystemTime: KSYSTEM_TIME | |
TimeZoneBias: KSYSTEM_TIME | |
ImageNumberLow: uint16 | |
ImageNumberHigh: uint16 | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)>] | |
NtSystemRoot: int16 array | |
MaxStackTraceDepth: uint32 | |
CryptoExponent: uint32 | |
TimeZoneId: uint32 | |
LargePageMinimum: uint32 | |
AitSamplingValue: uint32 | |
AppCompatFlag: uint32 | |
RNGSeedVersion: uint64 | |
GlobalValidationRunlevel: uint32 | |
TimeZoneBiasStamp: int32 | |
NtBuildNumber: uint32 | |
NtProductType: NT_PRODUCT_TYPE | |
ProductTypeIsValid: bool | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)>] | |
Reserved0: bool array | |
NativeProcessorArchitecture: uint16 | |
NtMajorVersion: uint32 | |
NtMinorVersion: uint32 | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = PROCESSOR_FEATURE_MAX)>] | |
ProcessorFeatures: bool array | |
Reserved1: uint32 | |
Reserved3: uint32 | |
TimeSlip: uint32 | |
AlternativeArchitecture: ALTERNATIVE_ARCHITECTURE_TYPE | |
BootId: uint32 | |
SystemExpirationDate: int64 | |
SuiteMask: uint32 | |
KdDebuggerEnabled: bool | |
MitigationPolicies: byte | |
CyclesPerYield: uint16 | |
ActiveConsoleId: uint32 | |
DismountCount: uint32 | |
ComPlusPackage: uint32 | |
LastSystemRITEventTickCount: uint32 | |
NumberOfPhysicalPages: uint32 | |
SafeBootMode: bool | |
VirtualizationFlags: byte | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)>] | |
Reserved12: byte array | |
SharedDataFlags: uint32 | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)>] | |
DataFlagsPad: uint32 array | |
TestRetInstruction: uint64 | |
QpcFrequency: int64 | |
SystemCall: uint32 | |
Reserved2: uint32 | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)>] | |
SystemCallPad: uint64 array | |
TickCount: KSYSTEM_TIME | |
Cookie: uint32 | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)>] | |
CookiePad: uint32 array | |
ConsoleSessionForegroundProcessId: int64 | |
TimeUpdateLock: uint64 | |
BaselineSystemTimeQpc: uint64 | |
BaselineInterruptTimeQpc: uint64 | |
QpcSystemTimeIncrement: uint64 | |
QpcInterruptTimeIncrement: uint64 | |
QpcSystemTimeIncrement32: uint32 | |
QpcInterruptTimeIncrement32: uint32 | |
QpcSystemTimeIncrementShift: byte | |
QpcInterruptTimeIncrementShift: byte | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)>] | |
Reserved8: byte array | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)>] | |
UserModeGlobalLogger: uint16 array | |
ImageFileExecutionOptions: uint32 | |
LangGenerationCount: uint32 | |
Reserved4: uint64 | |
InterruptTimeBias: uint64 | |
QpcBias: uint64 | |
ActiveProcessorCount: uint32 | |
ActiveGroupCount: uint8 | |
Reserved9: uint8 | |
QpcData: uint8 | |
TimeZoneBiasEffectiveStart: uint64 | |
TimeZoneBiasEffectiveEnd: uint64 | |
XState: XSTATE_CONFIGURATION | |
} | |
// Struct used by the VirtualQueryEx function | |
[<Struct; StructLayout(LayoutKind.Sequential)>] | |
type MEMORY_BASIC_INFORMATION = | |
{ BaseAddress: IntPtr | |
AllocationBase: IntPtr | |
AllocationProtect: uint | |
RegionSize: IntPtr | |
State: uint | |
Protect: uint | |
Type: uint } | |
[<DllImport("kernel32.dll", SetLastError = true)>] | |
extern bool ReadProcessMemory( | |
IntPtr hProcess, | |
IntPtr lpBaseAddress, | |
[<Out>] byte[] lpBuffer, | |
int dwSize, | |
int& lpNumberOfBytesRead | |
) | |
[<DllImport("kernel32.dll", SetLastError = true)>] | |
extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, MEMORY_BASIC_INFORMATION& lpBuffer, uint dwLength) | |
// Reads one 4kb page at the specified address from the current process | |
let readPage (address: IntPtr) = | |
let pageSize = 4 * 1024 | |
let mutable buffer = Array.zeroCreate<byte> pageSize | |
let mutable bytesRead = 0 | |
let success = | |
ReadProcessMemory(Diagnostics.Process.GetCurrentProcess().Handle, address, buffer, pageSize, &bytesRead) | |
if success then buffer else failwith "Failed to read memory" | |
// Determines whether the specified address is a valid memory address in the current process | |
let isValidAddress (address: IntPtr) = | |
let mutable info: MEMORY_BASIC_INFORMATION = | |
{ BaseAddress = new IntPtr(0) | |
AllocationBase = new IntPtr(0) | |
AllocationProtect = 0u | |
RegionSize = new IntPtr(0) | |
State = 0u | |
Protect = 0u | |
Type = 0u } | |
if | |
VirtualQueryEx( | |
Diagnostics.Process.GetCurrentProcess().Handle, | |
address, | |
&info, | |
(uint) sizeof<MEMORY_BASIC_INFORMATION> | |
) = 0 | |
then | |
false | |
else | |
info.State = 0x1000u | |
let hexdump (page: byte[]) = | |
let sb = new Text.StringBuilder() | |
let hexLine (i: int) = | |
sb.AppendFormat("{0:X8}: ", i) |> ignore | |
let hexByte (j: int) = | |
if j < page.Length - i then | |
sb.AppendFormat("{0:X2} ", page.[i + j]) |> ignore | |
else | |
sb.Append(" ") |> ignore | |
[ 0..15 ] |> List.iter hexByte | |
sb.Append(" ") | |
let stringLine (i: int) = | |
let stringChar (j: int) = | |
if (j < page.Length) then | |
sb.Append( | |
if page.[i + j] >= 32uy && page.[i + j] <= 126uy then | |
char page.[i + j] | |
else | |
'.' | |
) | |
|> ignore | |
else | |
sb.Append(" ") |> ignore | |
[ 0..15 ] |> List.iter stringChar | |
let rec dumpLines i = | |
if i < page.Length then | |
hexLine i |> ignore | |
stringLine i | |
sb.AppendLine() |> ignore | |
dumpLines (i + 16) | |
dumpLines 0 | |
sb.ToString() | |
let pageAddress = new IntPtr(0x000000007ffe0000L) | |
if isValidAddress (pageAddress) then | |
let page = readPage (pageAddress) | |
printfn "%A" page |> ignore | |
hexdump page |> printfn "%s" |> ignore | |
let pagePtr = Marshal.UnsafeAddrOfPinnedArrayElement (page, 0) | |
let data = Marshal.PtrToStructure<KUSER_SHARED_DATA>(pagePtr) | |
printfn "%A" data |> ignore | |
let systemRoot = | |
data.NtSystemRoot | |
|> Array.map (fun c -> char c) | |
|> Array.toList | |
|> String.Concat | |
printfn "%s" systemRoot |> ignore | |
else | |
printfn "Invalid address" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment