Compare commits
6 Commits
0.1.0
...
loaddriver
Author | SHA1 | Date | |
---|---|---|---|
ebeea02962 | |||
f872b8e14a | |||
71b59861c5 | |||
30da3fe60a | |||
fc61c5e605 | |||
0bb4ecd0e3 |
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -197,6 +197,11 @@ dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.0"
|
||||
@ -454,8 +459,11 @@ dependencies = [
|
||||
name = "parse_pdb_for_offsets"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1012,6 +1020,11 @@ dependencies = [
|
||||
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
@ -1088,6 +1101,7 @@ dependencies = [
|
||||
"checksum h2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9433d71e471c1736fd5a61b671fc0b148d7a2992f666c958d03cd8feb3b88d1"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
|
||||
"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
||||
"checksum http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b708cc7f06493459026f53b9a61a7a121a5d1ec6238dee58ea4941132b30156b"
|
||||
"checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
|
||||
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
|
||||
@ -1180,6 +1194,7 @@ dependencies = [
|
||||
"checksum wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d"
|
||||
"checksum web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf97caf6aa8c2b1dac90faf0db529d9d63c93846cca4911856f78a83cebf53b"
|
||||
"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
|
||||
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
@ -7,6 +7,8 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
hex = "0.4.2"
|
||||
pdb = "0.5.0"
|
||||
widestring = "0.4.0"
|
||||
winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg"] }
|
||||
reqwest = { version = "0.10.1", features = ["blocking"] }
|
||||
|
||||
|
607
README.md
607
README.md
@ -14,7 +14,7 @@ In [Rekall source code](https://github.com/google/rekall/blob/c5d68e31705f4b5bd2
|
||||
|
||||
In Windows 7, 8, another field was added to controll the allocation of `NonPagedPool`, which is why there is [this paper about pool tag quick scanning](https://www.sciencedirect.com/science/article/pii/S1742287616000062).
|
||||
|
||||
However, from Windows 10, the whole game change around when the global offset to those (similar) variables. Instead Windows 10 introduced a new structure `MiState`. `MiState` offset is available and we can get the variables by either:
|
||||
However, from Windows 10, the whole game changed around when the global offset to those (similar) variables are gone. Instead Windows 10 introduced a new variable `MiState`. `MiState` offset is available and we can get those start/end variables by either:
|
||||
|
||||
- Windows 2015: `*((ntoskrnl.exe+MiState)->SystemNodeInformation->NonPagedPool{First,Last}Va)`
|
||||
- Windows 2016: `*((ntoskrnl.exe+MiState)->Hardware.SystemNodeInformation->NonPagedPool{First,Last}Va)`
|
||||
@ -25,99 +25,534 @@ Yeah, now `pool tag quick scanning` is useless (gah). Windows OS changes quite f
|
||||
|
||||
- Windows 2020 Insider preview: `*((ntoskrnl.exe+MiState)->SystemNodeNonPagedPool->NonPagedPool{First,Last}Va)`
|
||||
|
||||
> If you go with low-level, then you only care about the offset and formula to get those variables but knowing the structure is well benefit.
|
||||
|
||||
Anyway, I create this project to help me with my thesis, following outdated structs online yields no result. Oh, yeah, a guy seems to be asking on [how to get `MmNonPagedPoolStart`](https://reverseengineering.stackexchange.com/q/6483) on `stackexchange`, too bad [the answer](https://reverseengineering.stackexchange.com/a/6487) is not so much helpful.
|
||||
|
||||
Take a look at my ntoskrnl.exe pdb file parsed.
|
||||
|
||||
```
|
||||
PDB for Amd64, guid: 3e7ee354-590f-ac1c-62a8-ccf0b6368989, age: 1,
|
||||
PDB for Amd64, guid: 3c6978d6-66d9-c05a-53b6-a1e1561282c8, age: 1,
|
||||
|
||||
MiState 0xc4f280 23:324224
|
||||
KdDebuggerDataBlock 0xc00a30 23:2608
|
||||
Void(UNNOWN) PsActiveProcessHead 0xc1f970 23:129392
|
||||
Void(UNNOWN) MiState 0xc4f200 23:324096
|
||||
Void(UNNOWN) KeNumberNodes 0xcfc000 24:0
|
||||
Void(UNNOWN) PsLoadedModuleList 0xc2ba30 23:178736
|
||||
Void(UNNOWN) KdDebuggerDataBlock 0xc00a30 23:2608
|
||||
|
||||
struct _MI_SYSTEM_INFORMATION
|
||||
- field _MI_POOL_STATE Pools at offset 0
|
||||
- field _MI_SECTION_STATE Sections at offset c0
|
||||
- field _MI_SYSTEM_IMAGE_STATE SystemImages at offset 400
|
||||
- field _MI_SESSION_STATE Sessions at offset 4a8
|
||||
- field _MI_PROCESS_STATE Processes at offset 1550
|
||||
- field _MI_HARDWARE_STATE Hardware at offset 15c0
|
||||
- field _MI_SYSTEM_VA_STATE SystemVa at offset 1780
|
||||
- field _MI_COMBINE_STATE PageCombines at offset 1c40
|
||||
- field _MI_PAGELIST_STATE PageLists at offset 1c60
|
||||
- field _MI_PARTITION_STATE Partitions at offset 1d00
|
||||
- field _MI_SHUTDOWN_STATE Shutdowns at offset 1dc0
|
||||
- field _MI_ERROR_STATE Errors at offset 1e38
|
||||
- field _MI_ACCESS_LOG_STATE AccessLog at offset 1f40
|
||||
- field _MI_DEBUGGER_STATE Debugger at offset 1fc0
|
||||
- field _MI_STANDBY_STATE Standby at offset 20e0
|
||||
- field _MI_SYSTEM_PTE_STATE SystemPtes at offset 2180
|
||||
- field _MI_IO_PAGE_STATE IoPages at offset 2380
|
||||
- field _MI_PAGING_IO_STATE PagingIo at offset 2440
|
||||
- field _MI_COMMON_PAGE_STATE CommonPages at offset 24f0
|
||||
- field _MI_SYSTEM_TRIM_STATE Trims at offset 25c0
|
||||
- field _MI_SYSTEM_ZEROING Zeroing at offset 2600
|
||||
- field _MI_ENCLAVE_STATE Enclaves at offset 2620
|
||||
- field U64 Cookie at offset 2668
|
||||
- field Void** BootRegistryRuns at offset 2670
|
||||
- field UNNOWN ZeroingDisabled at offset 2678
|
||||
- field UChar FullyInitialized at offset 267c
|
||||
- field UChar SafeBooted at offset 267d
|
||||
- field UNNOWN* TraceLogging at offset 2680
|
||||
- field _MI_VISIBLE_STATE Vs at offset 26c0
|
||||
beginstruct _LIST_ENTRY
|
||||
0x0 _LIST_ENTRY* Flink
|
||||
0x8 _LIST_ENTRY* Blink
|
||||
endstruct
|
||||
|
||||
struct _MI_HARDWARE_STATE
|
||||
- field U32 NodeMask at offset 0
|
||||
- field U32 NumaHintIndex at offset 4
|
||||
- field U32 NumaLastRangeIndexInclusive at offset 8
|
||||
- field UChar NodeShift at offset c
|
||||
- field UChar ChannelShift at offset d
|
||||
- field U32 ChannelHintIndex at offset 10
|
||||
- field U32 ChannelLastRangeIndexInclusive at offset 14
|
||||
- field _MI_NODE_NUMBER_ZERO_BASED* NodeGraph at offset 18
|
||||
- field _MI_SYSTEM_NODE_NONPAGED_POOL* SystemNodeNonPagedPool at offset 20
|
||||
- field UNNOWN TemporaryNumaRanges at offset 28
|
||||
- field _HAL_NODE_RANGE* NumaMemoryRanges at offset 48
|
||||
- field _HAL_CHANNEL_MEMORY_RANGES* ChannelMemoryRanges at offset 50
|
||||
- field U32 SecondLevelCacheSize at offset 58
|
||||
- field U32 FirstLevelCacheSize at offset 5c
|
||||
- field U32 PhysicalAddressBits at offset 60
|
||||
- field U32 PfnDatabasePageBits at offset 64
|
||||
- field U32 LogicalProcessorsPerCore at offset 68
|
||||
- field UChar ProcessorCachesFlushedOnPowerLoss at offset 6c
|
||||
- field U64 TotalPagesAllowed at offset 70
|
||||
- field U32 SecondaryColorMask at offset 78
|
||||
- field U32 SecondaryColors at offset 7c
|
||||
- field U32 FlushTbForAttributeChange at offset 80
|
||||
- field U32 FlushCacheForAttributeChange at offset 84
|
||||
- field U32 FlushCacheForPageAttributeChange at offset 88
|
||||
- field U32 CacheFlushPromoteThreshold at offset 8c
|
||||
- field _LARGE_INTEGER PerformanceCounterFrequency at offset 90
|
||||
- field U64 InvalidPteMask at offset c0
|
||||
- field UNNOWN LargePageColors at offset 100
|
||||
- field U64 FlushTbThreshold at offset 110
|
||||
- field UNNOWN OptimalZeroingAttribute at offset 118
|
||||
- field UChar AttributeChangeRequiresReZero at offset 158
|
||||
- field UNNOWN ZeroCostCounts at offset 160
|
||||
- field U64 HighestPossiblePhysicalPage at offset 180
|
||||
- field U64 VsmKernelPageCount at offset 188
|
||||
beginstruct _RTL_BITMAP
|
||||
0x0 U32 SizeOfBitMap
|
||||
0x8 U32 Buffer
|
||||
endstruct
|
||||
|
||||
struct _MI_SYSTEM_NODE_NONPAGED_POOL
|
||||
- field _MI_DYNAMIC_BITMAP DynamicBitMapNonPagedPool at offset 0
|
||||
- field U64 CachedNonPagedPoolCount at offset 48
|
||||
- field U64 NonPagedPoolSpinLock at offset 50
|
||||
- field _MMPFN* CachedNonPagedPool at offset 58
|
||||
- field Void NonPagedPoolFirstVa at offset 60
|
||||
- field Void NonPagedPoolLastVa at offset 68
|
||||
- field _MI_SYSTEM_NODE_INFORMATION* SystemNodeInformation at offset 70
|
||||
beginstruct _EPROCESS
|
||||
0x0 _KPROCESS Pcb
|
||||
0x438 _EX_PUSH_LOCK ProcessLock
|
||||
0x440 Void UniqueProcessId
|
||||
0x448 _LIST_ENTRY ActiveProcessLinks
|
||||
0x458 _EX_RUNDOWN_REF RundownProtect
|
||||
0x460 U32 Flags2
|
||||
0x460 UNNOWN JobNotReallyActive
|
||||
0x460 UNNOWN AccountingFolded
|
||||
0x460 UNNOWN NewProcessReported
|
||||
0x460 UNNOWN ExitProcessReported
|
||||
0x460 UNNOWN ReportCommitChanges
|
||||
0x460 UNNOWN LastReportMemory
|
||||
0x460 UNNOWN ForceWakeCharge
|
||||
0x460 UNNOWN CrossSessionCreate
|
||||
0x460 UNNOWN NeedsHandleRundown
|
||||
0x460 UNNOWN RefTraceEnabled
|
||||
0x460 UNNOWN PicoCreated
|
||||
0x460 UNNOWN EmptyJobEvaluated
|
||||
0x460 UNNOWN DefaultPagePriority
|
||||
0x460 UNNOWN PrimaryTokenFrozen
|
||||
0x460 UNNOWN ProcessVerifierTarget
|
||||
0x460 UNNOWN RestrictSetThreadContext
|
||||
0x460 UNNOWN AffinityPermanent
|
||||
0x460 UNNOWN AffinityUpdateEnable
|
||||
0x460 UNNOWN PropagateNode
|
||||
0x460 UNNOWN ExplicitAffinity
|
||||
0x460 UNNOWN ProcessExecutionState
|
||||
0x460 UNNOWN EnableReadVmLogging
|
||||
0x460 UNNOWN EnableWriteVmLogging
|
||||
0x460 UNNOWN FatalAccessTerminationRequested
|
||||
0x460 UNNOWN DisableSystemAllowedCpuSet
|
||||
0x460 UNNOWN ProcessStateChangeRequest
|
||||
0x460 UNNOWN ProcessStateChangeInProgress
|
||||
0x460 UNNOWN InPrivate
|
||||
0x464 U32 Flags
|
||||
0x464 UNNOWN CreateReported
|
||||
0x464 UNNOWN NoDebugInherit
|
||||
0x464 UNNOWN ProcessExiting
|
||||
0x464 UNNOWN ProcessDelete
|
||||
0x464 UNNOWN ManageExecutableMemoryWrites
|
||||
0x464 UNNOWN VmDeleted
|
||||
0x464 UNNOWN OutswapEnabled
|
||||
0x464 UNNOWN Outswapped
|
||||
0x464 UNNOWN FailFastOnCommitFail
|
||||
0x464 UNNOWN Wow64VaSpace4Gb
|
||||
0x464 UNNOWN AddressSpaceInitialized
|
||||
0x464 UNNOWN SetTimerResolution
|
||||
0x464 UNNOWN BreakOnTermination
|
||||
0x464 UNNOWN DeprioritizeViews
|
||||
0x464 UNNOWN WriteWatch
|
||||
0x464 UNNOWN ProcessInSession
|
||||
0x464 UNNOWN OverrideAddressSpace
|
||||
0x464 UNNOWN HasAddressSpace
|
||||
0x464 UNNOWN LaunchPrefetched
|
||||
0x464 UNNOWN Background
|
||||
0x464 UNNOWN VmTopDown
|
||||
0x464 UNNOWN ImageNotifyDone
|
||||
0x464 UNNOWN PdeUpdateNeeded
|
||||
0x464 UNNOWN VdmAllowed
|
||||
0x464 UNNOWN ProcessRundown
|
||||
0x464 UNNOWN ProcessInserted
|
||||
0x464 UNNOWN DefaultIoPriority
|
||||
0x464 UNNOWN ProcessSelfDelete
|
||||
0x464 UNNOWN SetTimerResolutionLink
|
||||
0x468 _LARGE_INTEGER CreateTime
|
||||
0x470 U64[16] ProcessQuotaUsage
|
||||
0x480 U64[16] ProcessQuotaPeak
|
||||
0x490 U64 PeakVirtualSize
|
||||
0x498 U64 VirtualSize
|
||||
0x4a0 _LIST_ENTRY SessionProcessLinks
|
||||
0x4b0 Void ExceptionPortData
|
||||
0x4b0 U64 ExceptionPortValue
|
||||
0x4b0 UNNOWN ExceptionPortState
|
||||
0x4b8 _EX_FAST_REF Token
|
||||
0x4c0 U64 MmReserved
|
||||
0x4c8 _EX_PUSH_LOCK AddressCreationLock
|
||||
0x4d0 _EX_PUSH_LOCK PageTableCommitmentLock
|
||||
0x4d8 _ETHREAD* RotateInProgress
|
||||
0x4e0 _ETHREAD* ForkInProgress
|
||||
0x4e8 _EJOB* CommitChargeJob
|
||||
0x4f0 _RTL_AVL_TREE CloneRoot
|
||||
0x4f8 volatile U64 NumberOfPrivatePages
|
||||
0x500 volatile U64 NumberOfLockedPages
|
||||
0x508 Void Win32Process
|
||||
0x510 _EJOB* Job
|
||||
0x518 Void SectionObject
|
||||
0x520 Void SectionBaseAddress
|
||||
0x528 U32 Cookie
|
||||
0x530 _PAGEFAULT_HISTORY* WorkingSetWatch
|
||||
0x538 Void Win32WindowStation
|
||||
0x540 Void InheritedFromUniqueProcessId
|
||||
0x548 volatile U64 OwnerProcessId
|
||||
0x550 _PEB* Peb
|
||||
0x558 _MM_SESSION_SPACE* Session
|
||||
0x560 Void Spare1
|
||||
0x568 _EPROCESS_QUOTA_BLOCK* QuotaBlock
|
||||
0x570 _HANDLE_TABLE* ObjectTable
|
||||
0x578 Void DebugPort
|
||||
0x580 _EWOW64PROCESS* WoW64Process
|
||||
0x588 Void DeviceMap
|
||||
0x590 Void EtwDataSource
|
||||
0x598 U64 PageDirectoryPte
|
||||
0x5a0 _FILE_OBJECT* ImageFilePointer
|
||||
0x5a8 UChar[15] ImageFileName
|
||||
0x5b7 UChar PriorityClass
|
||||
0x5b8 Void SecurityPort
|
||||
0x5c0 _SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo
|
||||
0x5c8 _LIST_ENTRY JobLinks
|
||||
0x5d8 Void HighestUserAddress
|
||||
0x5e0 _LIST_ENTRY ThreadListHead
|
||||
0x5f0 volatile U32 ActiveThreads
|
||||
0x5f4 U32 ImagePathHash
|
||||
0x5f8 U32 DefaultHardErrorProcessing
|
||||
0x5fc I32 LastThreadExitStatus
|
||||
0x600 _EX_FAST_REF PrefetchTrace
|
||||
0x608 Void LockedPagesList
|
||||
0x610 _LARGE_INTEGER ReadOperationCount
|
||||
0x618 _LARGE_INTEGER WriteOperationCount
|
||||
0x620 _LARGE_INTEGER OtherOperationCount
|
||||
0x628 _LARGE_INTEGER ReadTransferCount
|
||||
0x630 _LARGE_INTEGER WriteTransferCount
|
||||
0x638 _LARGE_INTEGER OtherTransferCount
|
||||
0x640 U64 CommitChargeLimit
|
||||
0x648 volatile U64 CommitCharge
|
||||
0x650 volatile U64 CommitChargePeak
|
||||
0x680 _MMSUPPORT_FULL Vm
|
||||
0x7c0 _LIST_ENTRY MmProcessLinks
|
||||
0x7d0 U32 ModifiedPageCount
|
||||
0x7d4 I32 ExitStatus
|
||||
0x7d8 _RTL_AVL_TREE VadRoot
|
||||
0x7e0 Void VadHint
|
||||
0x7e8 U64 VadCount
|
||||
0x7f0 volatile U64 VadPhysicalPages
|
||||
0x7f8 U64 VadPhysicalPagesLimit
|
||||
0x800 _ALPC_PROCESS_CONTEXT AlpcContext
|
||||
0x820 _LIST_ENTRY TimerResolutionLink
|
||||
0x830 _PO_DIAG_STACK_RECORD* TimerResolutionStackRecord
|
||||
0x838 U32 RequestedTimerResolution
|
||||
0x83c U32 SmallestTimerResolution
|
||||
0x840 _LARGE_INTEGER ExitTime
|
||||
0x848 _INVERTED_FUNCTION_TABLE* InvertedFunctionTable
|
||||
0x850 _EX_PUSH_LOCK InvertedFunctionTableLock
|
||||
0x858 U32 ActiveThreadsHighWatermark
|
||||
0x85c U32 LargePrivateVadCount
|
||||
0x860 _EX_PUSH_LOCK ThreadListLock
|
||||
0x868 Void WnfContext
|
||||
0x870 _EJOB* ServerSilo
|
||||
0x878 UChar SignatureLevel
|
||||
0x879 UChar SectionSignatureLevel
|
||||
0x87a _PS_PROTECTION Protection
|
||||
0x87b UNNOWN HangCount
|
||||
0x87b UNNOWN GhostCount
|
||||
0x87b UNNOWN PrefilterException
|
||||
0x87c U32 Flags3
|
||||
0x87c UNNOWN Minimal
|
||||
0x87c UNNOWN ReplacingPageRoot
|
||||
0x87c UNNOWN Crashed
|
||||
0x87c UNNOWN JobVadsAreTracked
|
||||
0x87c UNNOWN VadTrackingDisabled
|
||||
0x87c UNNOWN AuxiliaryProcess
|
||||
0x87c UNNOWN SubsystemProcess
|
||||
0x87c UNNOWN IndirectCpuSets
|
||||
0x87c UNNOWN RelinquishedCommit
|
||||
0x87c UNNOWN HighGraphicsPriority
|
||||
0x87c UNNOWN CommitFailLogged
|
||||
0x87c UNNOWN ReserveFailLogged
|
||||
0x87c UNNOWN SystemProcess
|
||||
0x87c UNNOWN HideImageBaseAddresses
|
||||
0x87c UNNOWN AddressPolicyFrozen
|
||||
0x87c UNNOWN ProcessFirstResume
|
||||
0x87c UNNOWN ForegroundExternal
|
||||
0x87c UNNOWN ForegroundSystem
|
||||
0x87c UNNOWN HighMemoryPriority
|
||||
0x87c UNNOWN EnableProcessSuspendResumeLogging
|
||||
0x87c UNNOWN EnableThreadSuspendResumeLogging
|
||||
0x87c UNNOWN SecurityDomainChanged
|
||||
0x87c UNNOWN SecurityFreezeComplete
|
||||
0x87c UNNOWN VmProcessorHost
|
||||
0x87c UNNOWN VmProcessorHostTransition
|
||||
0x87c UNNOWN AltSyscall
|
||||
0x87c UNNOWN TimerResolutionIgnore
|
||||
0x880 I32 DeviceAsid
|
||||
0x888 Void SvmData
|
||||
0x890 _EX_PUSH_LOCK SvmProcessLock
|
||||
0x898 U64 SvmLock
|
||||
0x8a0 _LIST_ENTRY SvmProcessDeviceListHead
|
||||
0x8b0 U64 LastFreezeInterruptTime
|
||||
0x8b8 _PROCESS_DISK_COUNTERS* DiskCounters
|
||||
0x8c0 Void PicoContext
|
||||
0x8c8 Void EnclaveTable
|
||||
0x8d0 U64 EnclaveNumber
|
||||
0x8d8 _EX_PUSH_LOCK EnclaveLock
|
||||
0x8e0 U32 HighPriorityFaultsAllowed
|
||||
0x8e8 _PO_PROCESS_ENERGY_CONTEXT* EnergyContext
|
||||
0x8f0 Void VmContext
|
||||
0x8f8 U64 SequenceNumber
|
||||
0x900 U64 CreateInterruptTime
|
||||
0x908 U64 CreateUnbiasedInterruptTime
|
||||
0x910 U64 TotalUnbiasedFrozenTime
|
||||
0x918 U64 LastAppStateUpdateTime
|
||||
0x920 UNNOWN LastAppStateUptime
|
||||
0x920 UNNOWN LastAppState
|
||||
0x928 volatile U64 SharedCommitCharge
|
||||
0x930 _EX_PUSH_LOCK SharedCommitLock
|
||||
0x938 _LIST_ENTRY SharedCommitLinks
|
||||
0x948 U64 AllowedCpuSets
|
||||
0x950 U64 DefaultCpuSets
|
||||
0x948 U64 AllowedCpuSetsIndirect
|
||||
0x950 U64 DefaultCpuSetsIndirect
|
||||
0x958 Void DiskIoAttribution
|
||||
0x960 Void DxgProcess
|
||||
0x968 U32 Win32KFilterSet
|
||||
0x970 volatile _PS_INTERLOCKED_TIMER_DELAY_VALUES ProcessTimerDelay
|
||||
0x978 volatile U32 KTimerSets
|
||||
0x97c volatile U32 KTimer2Sets
|
||||
0x980 volatile U32 ThreadTimerSets
|
||||
0x988 U64 VirtualTimerListLock
|
||||
0x990 _LIST_ENTRY VirtualTimerListHead
|
||||
0x9a0 _WNF_STATE_NAME WakeChannel
|
||||
0x9a0 _PS_PROCESS_WAKE_INFORMATION WakeInfo
|
||||
0x9d0 U32 MitigationFlags
|
||||
0x9d0 <anonymous-tag> MitigationFlagsValues
|
||||
0x9d4 U32 MitigationFlags2
|
||||
0x9d4 <anonymous-tag> MitigationFlags2Values
|
||||
0x9d8 Void PartitionObject
|
||||
0x9e0 U64 SecurityDomain
|
||||
0x9e8 U64 ParentSecurityDomain
|
||||
0x9f0 Void CoverageSamplerContext
|
||||
0x9f8 Void MmHotPatchContext
|
||||
0xa00 _KE_IDEAL_PROCESSOR_ASSIGNMENT_BLOCK IdealProcessorAssignmentBlock
|
||||
0xab8 _RTL_AVL_TREE DynamicEHContinuationTargetsTree
|
||||
0xac0 _EX_PUSH_LOCK DynamicEHContinuationTargetsLock
|
||||
endstruct
|
||||
|
||||
beginstruct _RTL_BITMAP_EX
|
||||
0x0 U64 SizeOfBitMap
|
||||
0x8 U64 Buffer
|
||||
endstruct
|
||||
|
||||
beginstruct _MI_SYSTEM_INFORMATION
|
||||
0x0 _MI_POOL_STATE Pools
|
||||
0xc0 _MI_SECTION_STATE Sections
|
||||
0x400 _MI_SYSTEM_IMAGE_STATE SystemImages
|
||||
0x4a8 _MI_SESSION_STATE Sessions
|
||||
0x1530 _MI_PROCESS_STATE Processes
|
||||
0x1580 _MI_HARDWARE_STATE Hardware
|
||||
0x1740 _MI_SYSTEM_VA_STATE SystemVa
|
||||
0x1c00 _MI_COMBINE_STATE PageCombines
|
||||
0x1c20 _MI_PAGELIST_STATE PageLists
|
||||
0x1cc0 _MI_PARTITION_STATE Partitions
|
||||
0x1d80 _MI_SHUTDOWN_STATE Shutdowns
|
||||
0x1df8 _MI_ERROR_STATE Errors
|
||||
0x1f00 _MI_ACCESS_LOG_STATE AccessLog
|
||||
0x1f80 _MI_DEBUGGER_STATE Debugger
|
||||
0x20a0 _MI_STANDBY_STATE Standby
|
||||
0x2140 _MI_SYSTEM_PTE_STATE SystemPtes
|
||||
0x2340 _MI_IO_PAGE_STATE IoPages
|
||||
0x2400 _MI_PAGING_IO_STATE PagingIo
|
||||
0x24b0 _MI_COMMON_PAGE_STATE CommonPages
|
||||
0x2580 _MI_SYSTEM_TRIM_STATE Trims
|
||||
0x25c0 _MI_SYSTEM_ZEROING Zeroing
|
||||
0x25e0 _MI_ENCLAVE_STATE Enclaves
|
||||
0x2628 U64 Cookie
|
||||
0x2630 Void** BootRegistryRuns
|
||||
0x2638 volatile I32 ZeroingDisabled
|
||||
0x263c UChar FullyInitialized
|
||||
0x263d UChar SafeBooted
|
||||
0x2640 const _tlgProvider_t* TraceLogging
|
||||
0x2680 _MI_VISIBLE_STATE Vs
|
||||
endstruct
|
||||
|
||||
beginstruct _PEB
|
||||
0x0 UChar InheritedAddressSpace
|
||||
0x1 UChar ReadImageFileExecOptions
|
||||
0x2 UChar BeingDebugged
|
||||
0x3 UChar BitField
|
||||
0x3 UNNOWN ImageUsesLargePages
|
||||
0x3 UNNOWN IsProtectedProcess
|
||||
0x3 UNNOWN IsImageDynamicallyRelocated
|
||||
0x3 UNNOWN SkipPatchingUser32Forwarders
|
||||
0x3 UNNOWN IsPackagedProcess
|
||||
0x3 UNNOWN IsAppContainer
|
||||
0x3 UNNOWN IsProtectedProcessLight
|
||||
0x3 UNNOWN IsLongPathAwareProcess
|
||||
0x4 UChar[4] Padding0
|
||||
0x8 Void Mutant
|
||||
0x10 Void ImageBaseAddress
|
||||
0x18 _PEB_LDR_DATA* Ldr
|
||||
0x20 _RTL_USER_PROCESS_PARAMETERS* ProcessParameters
|
||||
0x28 Void SubSystemData
|
||||
0x30 Void ProcessHeap
|
||||
0x38 _RTL_CRITICAL_SECTION* FastPebLock
|
||||
0x40 _SLIST_HEADER* AtlThunkSListPtr
|
||||
0x48 Void IFEOKey
|
||||
0x50 U32 CrossProcessFlags
|
||||
0x50 UNNOWN ProcessInJob
|
||||
0x50 UNNOWN ProcessInitializing
|
||||
0x50 UNNOWN ProcessUsingVEH
|
||||
0x50 UNNOWN ProcessUsingVCH
|
||||
0x50 UNNOWN ProcessUsingFTH
|
||||
0x50 UNNOWN ProcessPreviouslyThrottled
|
||||
0x50 UNNOWN ProcessCurrentlyThrottled
|
||||
0x50 UNNOWN ProcessImagesHotPatched
|
||||
0x50 UNNOWN ReservedBits0
|
||||
0x54 UChar[4] Padding1
|
||||
0x58 Void KernelCallbackTable
|
||||
0x58 Void UserSharedInfoPtr
|
||||
0x60 U32 SystemReserved
|
||||
0x64 U32 AtlThunkSListPtr32
|
||||
0x68 Void ApiSetMap
|
||||
0x70 U32 TlsExpansionCounter
|
||||
0x74 UChar[4] Padding2
|
||||
0x78 Void TlsBitmap
|
||||
0x80 U32[8] TlsBitmapBits
|
||||
0x88 Void ReadOnlySharedMemoryBase
|
||||
0x90 Void SharedData
|
||||
0x98 Void* ReadOnlyStaticServerData
|
||||
0xa0 Void AnsiCodePageData
|
||||
0xa8 Void OemCodePageData
|
||||
0xb0 Void UnicodeCaseTableData
|
||||
0xb8 U32 NumberOfProcessors
|
||||
0xbc U32 NtGlobalFlag
|
||||
0xc0 _LARGE_INTEGER CriticalSectionTimeout
|
||||
0xc8 U64 HeapSegmentReserve
|
||||
0xd0 U64 HeapSegmentCommit
|
||||
0xd8 U64 HeapDeCommitTotalFreeThreshold
|
||||
0xe0 U64 HeapDeCommitFreeBlockThreshold
|
||||
0xe8 U32 NumberOfHeaps
|
||||
0xec U32 MaximumNumberOfHeaps
|
||||
0xf0 Void* ProcessHeaps
|
||||
0xf8 Void GdiSharedHandleTable
|
||||
0x100 Void ProcessStarterHelper
|
||||
0x108 U32 GdiDCAttributeList
|
||||
0x10c UChar[4] Padding3
|
||||
0x110 _RTL_CRITICAL_SECTION* LoaderLock
|
||||
0x118 U32 OSMajorVersion
|
||||
0x11c U32 OSMinorVersion
|
||||
0x120 U16 OSBuildNumber
|
||||
0x122 U16 OSCSDVersion
|
||||
0x124 U32 OSPlatformId
|
||||
0x128 U32 ImageSubsystem
|
||||
0x12c U32 ImageSubsystemMajorVersion
|
||||
0x130 U32 ImageSubsystemMinorVersion
|
||||
0x134 UChar[4] Padding4
|
||||
0x138 U64 ActiveProcessAffinityMask
|
||||
0x140 U32[240] GdiHandleBuffer
|
||||
0x230 Void(UNNOWN)* PostProcessInitRoutine
|
||||
0x238 Void TlsExpansionBitmap
|
||||
0x240 U32[128] TlsExpansionBitmapBits
|
||||
0x2c0 U32 SessionId
|
||||
0x2c4 UChar[4] Padding5
|
||||
0x2c8 _ULARGE_INTEGER AppCompatFlags
|
||||
0x2d0 _ULARGE_INTEGER AppCompatFlagsUser
|
||||
0x2d8 Void pShimData
|
||||
0x2e0 Void AppCompatInfo
|
||||
0x2e8 _UNICODE_STRING CSDVersion
|
||||
0x2f8 const _ACTIVATION_CONTEXT_DATA* ActivationContextData
|
||||
0x300 _ASSEMBLY_STORAGE_MAP* ProcessAssemblyStorageMap
|
||||
0x308 const _ACTIVATION_CONTEXT_DATA* SystemDefaultActivationContextData
|
||||
0x310 _ASSEMBLY_STORAGE_MAP* SystemAssemblyStorageMap
|
||||
0x318 U64 MinimumStackCommit
|
||||
0x320 Void[32] SparePointers
|
||||
0x340 U32[20] SpareUlongs
|
||||
0x358 Void WerRegistrationData
|
||||
0x360 Void WerShipAssertPtr
|
||||
0x368 Void pUnused
|
||||
0x370 Void pImageHeaderHash
|
||||
0x378 U32 TracingFlags
|
||||
0x378 UNNOWN HeapTracingEnabled
|
||||
0x378 UNNOWN CritSecTracingEnabled
|
||||
0x378 UNNOWN LibLoaderTracingEnabled
|
||||
0x378 UNNOWN SpareTracingBits
|
||||
0x37c UChar[4] Padding6
|
||||
0x380 U64 CsrServerReadOnlySharedMemoryBase
|
||||
0x388 U64 TppWorkerpListLock
|
||||
0x390 _LIST_ENTRY TppWorkerpList
|
||||
0x3a0 Void[1024] WaitOnAddressHashTable
|
||||
0x7a0 Void TelemetryCoverageHeader
|
||||
0x7a8 U32 CloudFileFlags
|
||||
0x7ac U32 CloudFileDiagFlags
|
||||
0x7b0 RChar PlaceholderCompatibilityMode
|
||||
0x7b1 RChar[7] PlaceholderCompatibilityModeReserved
|
||||
0x7b8 _LEAP_SECOND_DATA* LeapSecondData
|
||||
0x7c0 U32 LeapSecondFlags
|
||||
0x7c0 UNNOWN SixtySecondEnabled
|
||||
0x7c0 UNNOWN Reserved
|
||||
0x7c4 U32 NtGlobalFlag2
|
||||
endstruct
|
||||
|
||||
beginstruct _MI_DYNAMIC_BITMAP
|
||||
0x0 _RTL_BITMAP_EX Bitmap
|
||||
0x10 U64 MaximumSize
|
||||
0x18 U64 Hint
|
||||
0x20 Void BaseVa
|
||||
0x28 U64 SizeTopDown
|
||||
0x30 U64 HintTopDown
|
||||
0x38 Void BaseVaTopDown
|
||||
0x40 U64 SpinLock
|
||||
endstruct
|
||||
|
||||
beginstruct _MI_HARDWARE_STATE
|
||||
0x0 U32 NodeMask
|
||||
0x4 U32 NumaHintIndex
|
||||
0x8 U32 NumaLastRangeIndexInclusive
|
||||
0xc UChar NodeShift
|
||||
0xd UChar ChannelShift
|
||||
0x10 U32 ChannelHintIndex
|
||||
0x14 U32 ChannelLastRangeIndexInclusive
|
||||
0x18 _MI_NODE_NUMBER_ZERO_BASED* NodeGraph
|
||||
0x20 _MI_SYSTEM_NODE_NONPAGED_POOL* SystemNodeNonPagedPool
|
||||
0x28 _HAL_NODE_RANGE[32] TemporaryNumaRanges
|
||||
0x48 _HAL_NODE_RANGE* NumaMemoryRanges
|
||||
0x50 _HAL_CHANNEL_MEMORY_RANGES* ChannelMemoryRanges
|
||||
0x58 U32 SecondLevelCacheSize
|
||||
0x5c U32 FirstLevelCacheSize
|
||||
0x60 U32 PhysicalAddressBits
|
||||
0x64 U32 PfnDatabasePageBits
|
||||
0x68 U32 LogicalProcessorsPerCore
|
||||
0x6c UChar ProcessorCachesFlushedOnPowerLoss
|
||||
0x70 U64 TotalPagesAllowed
|
||||
0x78 U32 SecondaryColorMask
|
||||
0x7c U32 SecondaryColors
|
||||
0x80 U32 FlushTbForAttributeChange
|
||||
0x84 U32 FlushCacheForAttributeChange
|
||||
0x88 U32 FlushCacheForPageAttributeChange
|
||||
0x8c U32 CacheFlushPromoteThreshold
|
||||
0x90 _LARGE_INTEGER PerformanceCounterFrequency
|
||||
0xc0 U64 InvalidPteMask
|
||||
0x100 U32[12] LargePageColors
|
||||
0x110 U64 FlushTbThreshold
|
||||
0x118 _MI_PFN_CACHE_ATTRIBUTE[16][64] OptimalZeroingAttribute
|
||||
0x158 UChar AttributeChangeRequiresReZero
|
||||
0x160 _MI_ZERO_COST_COUNTS[32] ZeroCostCounts
|
||||
0x180 U64 HighestPossiblePhysicalPage
|
||||
0x188 U64 VsmKernelPageCount
|
||||
endstruct
|
||||
|
||||
beginstruct _MI_SYSTEM_NODE_NONPAGED_POOL
|
||||
0x0 _MI_DYNAMIC_BITMAP DynamicBitMapNonPagedPool
|
||||
0x48 U64 CachedNonPagedPoolCount
|
||||
0x50 U64 NonPagedPoolSpinLock
|
||||
0x58 _MMPFN* CachedNonPagedPool
|
||||
0x60 Void NonPagedPoolFirstVa
|
||||
0x68 Void NonPagedPoolLastVa
|
||||
0x70 _MI_SYSTEM_NODE_INFORMATION* SystemNodeInformation
|
||||
endstruct
|
||||
|
||||
beginstruct _MI_SYSTEM_NODE_INFORMATION
|
||||
0x0 _CACHED_KSTACK_LIST[64] CachedKernelStacks
|
||||
0x40 _GROUP_AFFINITY GroupAffinity
|
||||
0x50 U16 ProcessorCount
|
||||
0x58 Void BootZeroPageTimesPerProcessor
|
||||
0x60 U64 CyclesToZeroOneLargePage
|
||||
0x68 U64 ScaledCyclesToZeroOneLargePage
|
||||
0x70 _MI_WRITE_CALIBRATION WriteCalibration
|
||||
0xc0 volatile I32 IoPfnLock
|
||||
endstruct
|
||||
|
||||
struct _MI_SYSTEM_NODE_INFORMATION
|
||||
- field UNNOWN CachedKernelStacks at offset 0
|
||||
- field _GROUP_AFFINITY GroupAffinity at offset 40
|
||||
- field U16 ProcessorCount at offset 50
|
||||
- field Void BootZeroPageTimesPerProcessor at offset 58
|
||||
- field U64 CyclesToZeroOneLargePage at offset 60
|
||||
- field U64 ScaledCyclesToZeroOneLargePage at offset 68
|
||||
- field _MI_WRITE_CALIBRATION WriteCalibration at offset 70
|
||||
- field UNNOWN IoPfnLock at offset c0
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
Global variables offset are parsed and can be queried by `nt!` in Windbg. In a kernel driver, we need to get the kernel base address (which is `nt!`). Kernel base address is the loaded address of `ntoskrnl.exe`. There is a shellcode to get the address [here](https://gist.github.com/Barakat/34e9924217ed81fd78c9c92d746ec9c6), using IDT table. But when I use the shellcode with the Windows Insider preview 2020, the address is wrong (it still a loaded PE though). Other ways to get the address are listed [here](https://m0uk4.gitbook.io/notebooks/mouka/windowsinternal/find-kernel-module-address-todo). And hereby I present another way to get the kernel base address.
|
||||
|
||||
A device driver can get a pointer to a `EPROCESS` through the use of `PEPROCESS IoGetCurrentProcess`. And as we know, `EPROCESS` has pointer to other `EPROCESS` as a doubly linked list. If we dump them all out, we can notice a few things:
|
||||
|
||||
- The image name returned by calling `IoGetCurrentProcess` is `System`
|
||||
- The `EPROCESS` before `System` is somehow empty
|
||||
|
||||
```cpp
|
||||
PVOID eprocess = (PVOID)IoGetCurrentProcess();
|
||||
DbgPrint("eprocess : 0x%p, [%15s]\n", eprocess, (char*)((ULONG64)eprocess + ImageBaseNameOffset));
|
||||
for (int i = 0; i < 100; i++) {
|
||||
eprocess = (PVOID)(*(ULONG64*)((ULONG64)eprocess + ActiveProcessLinksOffset) - ActiveProcessLinksOffset);
|
||||
DbgPrint("eprocess : 0x%p, [%15s]\n", eprocess, (char*)((ULONG64)eprocess + ImageBaseOffset));
|
||||
}
|
||||
|
||||
// sample output
|
||||
eprocess : 0xFFFFF8037401F528, [ ]
|
||||
eprocess : 0xFFFF840F5A0D9080, [ System]
|
||||
eprocess : 0xFFFF840F5A28C040, [ Secure System]
|
||||
eprocess : 0xFFFF840F5A2EF040, [ Registry]
|
||||
eprocess : 0xFFFF840F622BF040, [ smss.exe]
|
||||
eprocess : 0xFFFF840F6187D080, [ smss.exe]
|
||||
eprocess : 0xFFFF840F6263D140, [ csrss.exe]
|
||||
eprocess : 0xFFFF840F6277F0C0, [ smss.exe]
|
||||
eprocess : 0xFFFF840F627C2080, [ wininit.exe]
|
||||
eprocess : 0xFFFF840F64187140, [ csrss.exe]
|
||||
eprocess : 0xFFFF840F641CD080, [ services.exe]
|
||||
```
|
||||
|
||||
And if we debug and compare the address of that `Empty EPROCESS+ActiveProcessLinksOffset` with `nt!PsActiveProcessHead`, it is just the same. And with the given offset parsed from the PDB file, we can get kernel base address.
|
||||
|
||||
```cpp
|
||||
PVOID eprocess = (PVOID)IoGetCurrentProcess();
|
||||
DbgPrint("eprocess : 0x%p, [%15s]\n", eprocess, (char*)((ULONG64)eprocess + ImageBaseNameOffset));
|
||||
PVOID processHead = (PVOID)(*(ULONG64*)((ULONG64)eprocess + ActiveProcessLinksOffset + BLinkOffset));
|
||||
DbgPrint("PsActiveProcessHead : 0x%p\n", processHead);
|
||||
PVOID ntosbase = (PVOID)((ULONG64)processHead - ActiveHeadOffset);
|
||||
DbgPrint("ntoskrnl.exe : 0x%p\n", ntosbase);
|
||||
```
|
||||
|
||||
From now we have successfully get the kernel base address to index into other global variables.
|
||||
|
||||
(In this way we use `PsActiveProcessHead`, but a better way maybe traversing `PsLoadedModuleList` which could get the correct address of `ntoskrnl.exe` but I do not know)
|
||||
|
190
src/main.rs
190
src/main.rs
@ -1,183 +1,13 @@
|
||||
extern crate reqwest;
|
||||
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use pdb::PDB;
|
||||
use pdb::SymbolData;
|
||||
use pdb::TypeData;
|
||||
use pdb::ClassType;
|
||||
use pdb::FallibleIterator;
|
||||
|
||||
use pdb::TypeFinder;
|
||||
use pdb::TypeIndex;
|
||||
|
||||
const PDBNAME: &str = "ntkrnlmp.pdb";
|
||||
const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe";
|
||||
const PDB_SERVER_PATH: &str = "http://msdl.microsoft.com/download/symbols";
|
||||
|
||||
fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {
|
||||
match type_finder.find(*typ).unwrap().parse().unwrap() {
|
||||
TypeData::Class(ct) => {
|
||||
format!("{}", ct.name.to_string())
|
||||
},
|
||||
TypeData::Primitive(pt) => {
|
||||
format!("{:?}", pt.kind)
|
||||
},
|
||||
TypeData::Pointer(pt) => {
|
||||
format!("{}*", get_type_as_str(type_finder, &pt.underlying_type))
|
||||
},
|
||||
unk => {
|
||||
match unk.name() {
|
||||
Some(s) => format!("{}", s.to_string()),
|
||||
_ => "UNNOWN".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_pdb() {
|
||||
let f = File::open("ntkrnlmp.pdb").expect("No such file ./ntkrnlmp.pdb");
|
||||
let mut pdb = PDB::open(f).expect("Cannot open as a PDB file");
|
||||
|
||||
let info = pdb.pdb_information().expect("Cannot get pdb information");
|
||||
let dbi = pdb.debug_information().expect("cannot get debug information");
|
||||
println!("PDB for {}, guid: {}, age: {},", dbi.machine_type().unwrap(), info.guid, dbi.age().unwrap_or(0));
|
||||
println!("");
|
||||
|
||||
// find global symbols offset
|
||||
let addr_map = pdb.address_map().expect("Cannot get address map");
|
||||
let glosym = pdb.global_symbols().expect("Cannot get global symbols");
|
||||
let mut symbols = glosym.iter();
|
||||
let need_symbols = [
|
||||
"KdDebuggerDataBlock", "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP
|
||||
"MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8
|
||||
"MiState" // Windows 10
|
||||
];
|
||||
while let Some(symbol) = symbols.next().unwrap() {
|
||||
match symbol.parse() {
|
||||
Ok(SymbolData::PublicSymbol(data)) => {
|
||||
let name = symbol.name().unwrap().to_string();
|
||||
for sym in need_symbols.iter() {
|
||||
if &name == sym {
|
||||
let rva = data.offset.to_rva(&addr_map).unwrap_or_default();
|
||||
println!("{} {} {}:{}", name, rva, data.offset.section, data.offset.offset);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// println!("Something else");
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("");
|
||||
|
||||
let mut need_structs = HashMap::new();
|
||||
need_structs.insert("_KDDEBUGGER_DATA64", vec![
|
||||
"MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP
|
||||
"MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8 -- not sure, global symbols
|
||||
"MiState" // Windows 10 -- not sure, global symbols
|
||||
]);
|
||||
|
||||
// these struct supports finding NonPagedPool{First,Last}Va in windows 10
|
||||
need_structs.insert("_MI_SYSTEM_INFORMATION", vec![
|
||||
"Hardware", // windows 10 2016+
|
||||
"SystemNodeInformation" // windows 10 2015
|
||||
]);
|
||||
need_structs.insert("_MI_HARDWARE_STATE", vec![
|
||||
"SystemNodeInformation", // till windows 10 1900
|
||||
"SystemNodeNonPagedPool" // windows insider, 2020
|
||||
]);
|
||||
need_structs.insert("_MI_SYSTEM_NODE_INFORMATION", vec![ // till windows 10 1900
|
||||
"NonPagedPoolFirstVa", "NonPagedPoolLastVa",
|
||||
"NonPagedBitMap" // missing on windows 10 1900+
|
||||
]);
|
||||
need_structs.insert("_MI_SYSTEM_NODE_NONPAGED_POOL", vec![ // windows insider, 2020
|
||||
"NonPagedPoolFirstVa", "NonPagedPoolLastVa"
|
||||
]);
|
||||
|
||||
let type_information = pdb.type_information().expect("Cannot get type information");
|
||||
let mut type_finder = type_information.type_finder();
|
||||
let mut iter = type_information.iter();
|
||||
while let Some(typ) = iter.next().unwrap() {
|
||||
type_finder.update(&iter);
|
||||
match typ.parse() {
|
||||
Ok(TypeData::Class(ClassType {name, fields: Some(fields), ..})) => {
|
||||
let n = name.to_string();
|
||||
// println!("{}", name);
|
||||
if !need_structs.contains_key(&*n) {
|
||||
continue;
|
||||
}
|
||||
println!("struct {}", name);
|
||||
match type_finder.find(fields).unwrap().parse().unwrap() {
|
||||
TypeData::FieldList(list) => {
|
||||
// `fields` is a Vec<TypeData>
|
||||
for field in list.fields {
|
||||
if let TypeData::Member(member) = field {
|
||||
let mem_typ = get_type_as_str(&type_finder, &member.field_type);
|
||||
println!(" - field {} {} at offset {:x}", mem_typ, member.name, member.offset);
|
||||
} else {
|
||||
// handle member functions, nested types, etc.
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
println!("");
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn download_pdb() {
|
||||
let mut ntoskrnl = File::open(NTOSKRNL_PATH).expect("Cannot open ntoskrnl.exe");
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
ntoskrnl.read_to_end(&mut buffer).expect("Cannot read file ntoskrnl.exe");
|
||||
|
||||
let mut buffiter = buffer.chunks(4);
|
||||
while buffiter.next().unwrap() != [0x52, 0x53, 0x44, 0x53] {
|
||||
// signature == RSDS
|
||||
}
|
||||
|
||||
// next 16 bytes is guid in raw bytes
|
||||
let raw_guid: Vec<u8> = vec![
|
||||
buffiter.next().unwrap(),
|
||||
buffiter.next().unwrap(),
|
||||
buffiter.next().unwrap(),
|
||||
buffiter.next().unwrap(),
|
||||
].concat();
|
||||
|
||||
// guid to hex string
|
||||
let guid = (vec![
|
||||
raw_guid[3], raw_guid[2], raw_guid[1], raw_guid[0],
|
||||
raw_guid[5], raw_guid[4],
|
||||
raw_guid[7], raw_guid[6],
|
||||
raw_guid[8], raw_guid[9], raw_guid[10], raw_guid[11],
|
||||
raw_guid[12], raw_guid[13], raw_guid[14], raw_guid[15],
|
||||
].iter().map(|b| format!("{:02X}", b)).collect::<Vec<String>>()).join("");
|
||||
|
||||
// next 4 bytes is age, in little endian
|
||||
let raw_age = buffiter.next().unwrap();
|
||||
let age = u32::from_le_bytes([
|
||||
raw_age[0], raw_age[1], raw_age[2], raw_age[3]
|
||||
]);
|
||||
|
||||
let downloadurl = format!("{}/{}/{}{:X}/{}", PDB_SERVER_PATH, PDBNAME, guid, age, PDBNAME);
|
||||
println!("{}", downloadurl);
|
||||
|
||||
let mut resp = reqwest::blocking::get(&downloadurl).expect("request failed");
|
||||
let mut out = File::create(PDBNAME).expect("failed to create file");
|
||||
io::copy(&mut resp, &mut out).expect("failed to copy content");
|
||||
}
|
||||
mod pdb_store;
|
||||
mod windows;
|
||||
|
||||
fn main() {
|
||||
if !Path::new(PDBNAME).exists() {
|
||||
download_pdb();
|
||||
}
|
||||
parse_pdb();
|
||||
let store = pdb_store::parse_pdb();
|
||||
store.print_default_information();
|
||||
|
||||
let mut windows_ffi = windows::WindowsFFI::new();
|
||||
windows_ffi.print_version();
|
||||
|
||||
println!("NtLoadDriver() -> 0x{:x}", windows_ffi.load_driver());
|
||||
println!("NtUnloadDriver() -> 0x{:x}", windows_ffi.unload_driver());
|
||||
}
|
||||
|
361
src/pdb_store.rs
Normal file
361
src/pdb_store.rs
Normal file
@ -0,0 +1,361 @@
|
||||
use std::io;
|
||||
use std::io::{Read};
|
||||
use std::path::Path;
|
||||
use std::fs::File;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use pdb::PDB;
|
||||
use pdb::SymbolData;
|
||||
use pdb::TypeData;
|
||||
use pdb::ClassType;
|
||||
use pdb::ModifierType;
|
||||
use pdb::Rva;
|
||||
|
||||
use pdb::FallibleIterator;
|
||||
use pdb::TypeFinder;
|
||||
use pdb::TypeIndex;
|
||||
|
||||
|
||||
const PDBNAME: &str = "ntkrnlmp.pdb";
|
||||
const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe";
|
||||
const PDB_SERVER_PATH: &str = "http://msdl.microsoft.com/download/symbols";
|
||||
|
||||
type SymbolStore = HashMap<String, u64>;
|
||||
type StructStore = HashMap<String, HashMap<String, (String, u64)>>;
|
||||
|
||||
pub struct PdbStore {
|
||||
pub symbols: SymbolStore,
|
||||
pub structs: StructStore
|
||||
}
|
||||
|
||||
impl PdbStore {
|
||||
#[allow(dead_code)]
|
||||
pub fn get_offset(&self, name: &str) -> Option<u64> {
|
||||
if name.contains(".") {
|
||||
let v: Vec<&str> = name.split_terminator('.').collect();
|
||||
match self.structs.get(v[0]) {
|
||||
Some(member_info) => {
|
||||
match member_info.get(v[1]) {
|
||||
Some((_memtype, offset)) => Some(*offset),
|
||||
None => None
|
||||
}
|
||||
},
|
||||
None => None
|
||||
}
|
||||
}
|
||||
else {
|
||||
match self.symbols.get(name) {
|
||||
Some(offset) => Some(*offset),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn addr_decompose(&self, addr: u64, full_name: &str) -> Result<u64, String>{
|
||||
if !full_name.contains(".") {
|
||||
return Err("Not decomposable".to_string());
|
||||
}
|
||||
|
||||
let mut name_part: Vec<&str> = full_name.split_terminator('.').collect();
|
||||
let mut next: Vec<_> = name_part.drain(2..).collect();
|
||||
match self.structs.get(name_part[0]) {
|
||||
Some(member_info) => {
|
||||
match member_info.get(name_part[1]) {
|
||||
Some((memtype, offset)) => {
|
||||
if next.len() != 0 {
|
||||
if memtype.contains("*") {
|
||||
return Err(format!("Cannot dereference pointer at {} {}", memtype, name_part[1]));
|
||||
}
|
||||
next.insert(0, memtype);
|
||||
self.addr_decompose(addr + *offset, &next.join("."))
|
||||
}
|
||||
else {
|
||||
Ok(addr + *offset)
|
||||
}
|
||||
},
|
||||
None => Err(format!("Not found member {}", name_part[1]))
|
||||
}
|
||||
},
|
||||
None => Err(format!("Struct {} not found", name_part[0]))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print_default_information(&self) {
|
||||
let need_symbols = [
|
||||
"PsLoadedModuleList", "PsActiveProcessHead", "KeNumberNodes",
|
||||
"PoolBigPageTable", "PoolBigPageTableSize",
|
||||
// "PoolVector", "ExpNumberOfNonPagedPools",
|
||||
"KdDebuggerDataBlock", "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP
|
||||
"MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8
|
||||
"MiNonPagedPoolBitMap", "MiNonPagedPoolVaBitMap",
|
||||
"MiState" // Windows 10
|
||||
];
|
||||
|
||||
let mut need_structs = HashMap::new();
|
||||
need_structs.insert("_POOL_HEADER", vec![]);
|
||||
need_structs.insert("_PEB", vec![]);
|
||||
need_structs.insert("_LIST_ENTRY", vec![
|
||||
"Flink", "Blink"
|
||||
]);
|
||||
need_structs.insert("_FILE_OBJECT", vec![
|
||||
"FileName"
|
||||
]);
|
||||
need_structs.insert("_EPROCESS", vec![
|
||||
"struct_size",
|
||||
"UniqueProcessId", "ActiveProcessLinks", "CreateTime",
|
||||
"Peb", "ImageFilePointer", "ImageFileName", "ThreadListHead"
|
||||
]);
|
||||
need_structs.insert("_KDDEBUGGER_DATA64", vec![
|
||||
"MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP
|
||||
]);
|
||||
need_structs.insert("_POOL_TRACKER_BIG_PAGES", vec![]);
|
||||
|
||||
// these struct supports finding NonPagedPool{First,Last}Va in windows 10
|
||||
need_structs.insert("_MI_SYSTEM_INFORMATION", vec![
|
||||
"Hardware", // windows 10 2016+
|
||||
"SystemNodeInformation" // windows 10 2015
|
||||
]);
|
||||
need_structs.insert("_MI_HARDWARE_STATE", vec![
|
||||
"SystemNodeInformation", // till windows 10 1900
|
||||
"SystemNodeNonPagedPool" // windows insider, 2020
|
||||
]);
|
||||
need_structs.insert("_MI_SYSTEM_NODE_INFORMATION", vec![ // till windows 10 1900
|
||||
"NonPagedPoolFirstVa", "NonPagedPoolLastVa",
|
||||
"NonPagedBitMap", // missing on windows 10 1900+
|
||||
"DynamicBitMapNonPagedPool" // some weird field
|
||||
]);
|
||||
need_structs.insert("_MI_SYSTEM_NODE_NONPAGED_POOL", vec![ // windows insider, 2020
|
||||
"NonPagedPoolFirstVa", "NonPagedPoolLastVa",
|
||||
"DynamicBitMapNonPagedPool" // some weird field
|
||||
]);
|
||||
need_structs.insert("_MI_DYNAMIC_BITMAP", vec![]);
|
||||
need_structs.insert("_RTL_BITMAP", vec![]); // windows 10 until 2020
|
||||
need_structs.insert("_RTL_BITMAP_EX", vec![]); // windows insider, 2020
|
||||
|
||||
for &symbol in &need_symbols {
|
||||
match self.symbols.get(symbol) {
|
||||
Some(offset) => println!("0x{:x} {}", offset, symbol),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
for (&struct_name, members) in &need_structs {
|
||||
match self.structs.get(struct_name) {
|
||||
Some(member_info) => {
|
||||
for &member in members {
|
||||
match member_info.get(member) {
|
||||
Some((memtype, offset)) =>
|
||||
println!("0x{:x} {} {}.{}", offset, memtype, struct_name, member),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {
|
||||
match type_finder.find(*typ).unwrap().parse().unwrap() {
|
||||
TypeData::Class(ct) => {
|
||||
format!("{}", ct.name.to_string())
|
||||
},
|
||||
TypeData::Primitive(pt) => {
|
||||
format!("{:?}", pt.kind)
|
||||
},
|
||||
TypeData::Pointer(pt) => {
|
||||
format!("{}*", get_type_as_str(type_finder, &pt.underlying_type))
|
||||
},
|
||||
TypeData::StaticMember(st) => {
|
||||
format!("static {}", get_type_as_str(type_finder, &st.field_type))
|
||||
},
|
||||
TypeData::Array(at) => {
|
||||
format!("{}{:?}",
|
||||
get_type_as_str(type_finder, &at.element_type), /* get_type_as_str(type_finder, &at.indexing_type), */ at.dimensions)
|
||||
},
|
||||
// TypeData::Enumeration(et) => {
|
||||
// format!("enumeration")
|
||||
// },
|
||||
// TypeData::Enumerate(et) => {
|
||||
// format!("enumerate")
|
||||
// },
|
||||
// TypeData::MemberFunction(mft) => {
|
||||
// format!("member function")
|
||||
// },
|
||||
// TypeData::OverloadedMethod(ovmt) => {
|
||||
// format!("overloaded method")
|
||||
// },
|
||||
// TypeData::Nested(nt) => {
|
||||
// format!("nested")
|
||||
// },
|
||||
// TypeData::BaseClass(bct) => {
|
||||
// format!("base class")
|
||||
// },
|
||||
// TypeData::VirtualBaseClass(vbct) => {
|
||||
// format!("virtual base class")
|
||||
// },
|
||||
// TypeData::VirtualFunctionTablePointer(vftpt) => {
|
||||
// format!("virtual function table pointer")
|
||||
// },
|
||||
TypeData::Procedure(pt) => {
|
||||
let rettype = match pt.return_type {
|
||||
Some(rt) => get_type_as_str(type_finder, &rt),
|
||||
_ => "UNKNOWN".to_string()
|
||||
};
|
||||
format!("{}({})", rettype, get_type_as_str(type_finder, &pt.argument_list))
|
||||
},
|
||||
TypeData::Modifier(mt) => {
|
||||
match mt {
|
||||
ModifierType { constant: true, volatile: true, unaligned: true, .. } =>
|
||||
format!("const volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: true, volatile: true, unaligned: false, .. } =>
|
||||
format!("const volatile {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: true, volatile: false, unaligned: true, .. } =>
|
||||
format!("const unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: false, volatile: true, unaligned: true, .. } =>
|
||||
format!("volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: true, volatile: false, unaligned: false, .. } =>
|
||||
format!("const {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: false, volatile: true, unaligned: false, .. } =>
|
||||
format!("volatile {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: false, volatile: false, unaligned: true, .. } =>
|
||||
format!("unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
_ => format!("modifier {}", get_type_as_str(type_finder, &mt.underlying_type))
|
||||
}
|
||||
},
|
||||
// TypeData::Union(ut) => {
|
||||
// format!("union")
|
||||
// },
|
||||
// TypeData::Bitfield(bft) => {
|
||||
// format!("bitfield")
|
||||
// },
|
||||
TypeData::FieldList(_flt) => {
|
||||
format!("fieldlist")
|
||||
},
|
||||
// TypeData::ArgumentList(alt) => {
|
||||
// format!("arglist")
|
||||
// },
|
||||
// TypeData::MethodList(mlt) => {
|
||||
// format!("methodlist")
|
||||
// },
|
||||
unk => {
|
||||
match unk.name() {
|
||||
Some(s) => format!("{}", s.to_string()),
|
||||
_ => "UNNOWN".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn download_pdb() {
|
||||
let mut ntoskrnl = File::open(NTOSKRNL_PATH).expect("Cannot open ntoskrnl.exe");
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
ntoskrnl.read_to_end(&mut buffer).expect("Cannot read file ntoskrnl.exe");
|
||||
|
||||
let mut buffiter = buffer.chunks(4);
|
||||
while buffiter.next().unwrap() != [0x52, 0x53, 0x44, 0x53] {
|
||||
// signature == RSDS
|
||||
}
|
||||
|
||||
// next 16 bytes is guid in raw bytes
|
||||
let raw_guid: Vec<u8> = vec![
|
||||
buffiter.next().unwrap(),
|
||||
buffiter.next().unwrap(),
|
||||
buffiter.next().unwrap(),
|
||||
buffiter.next().unwrap(),
|
||||
].concat();
|
||||
|
||||
// guid to hex string
|
||||
let guid = (vec![
|
||||
raw_guid[3], raw_guid[2], raw_guid[1], raw_guid[0],
|
||||
raw_guid[5], raw_guid[4],
|
||||
raw_guid[7], raw_guid[6],
|
||||
raw_guid[8], raw_guid[9], raw_guid[10], raw_guid[11],
|
||||
raw_guid[12], raw_guid[13], raw_guid[14], raw_guid[15],
|
||||
].iter().map(|b| format!("{:02X}", b)).collect::<Vec<String>>()).join("");
|
||||
|
||||
// next 4 bytes is age, in little endian
|
||||
let raw_age = buffiter.next().unwrap();
|
||||
let age = u32::from_le_bytes([
|
||||
raw_age[0], raw_age[1], raw_age[2], raw_age[3]
|
||||
]);
|
||||
|
||||
let downloadurl = format!("{}/{}/{}{:X}/{}", PDB_SERVER_PATH, PDBNAME, guid, age, PDBNAME);
|
||||
println!("{}", downloadurl);
|
||||
|
||||
let mut resp = reqwest::blocking::get(&downloadurl).expect("request failed");
|
||||
let mut out = File::create(PDBNAME).expect("failed to create file");
|
||||
io::copy(&mut resp, &mut out).expect("failed to copy content");
|
||||
}
|
||||
|
||||
pub fn parse_pdb() -> PdbStore {
|
||||
// TODO: Detect pdb file and ntoskrnl file version differs
|
||||
// The guid of ntoskrnl and pdb file are different
|
||||
if !Path::new(PDBNAME).exists() {
|
||||
download_pdb();
|
||||
}
|
||||
let f = File::open("ntkrnlmp.pdb").expect("No such file ./ntkrnlmp.pdb");
|
||||
let mut pdb = PDB::open(f).expect("Cannot open as a PDB file");
|
||||
|
||||
let info = pdb.pdb_information().expect("Cannot get pdb information");
|
||||
let dbi = pdb.debug_information().expect("cannot get debug information");
|
||||
println!("PDB for {}, guid: {}, age: {}\n",
|
||||
dbi.machine_type().unwrap(), info.guid, dbi.age().unwrap_or(0));
|
||||
|
||||
let type_information = pdb.type_information().expect("Cannot get type information");
|
||||
let mut type_finder = type_information.type_finder();
|
||||
let mut iter = type_information.iter();
|
||||
while let Some(_typ) = iter.next().unwrap() {
|
||||
type_finder.update(&iter);
|
||||
}
|
||||
|
||||
let mut symbol_extracted: SymbolStore = HashMap::new();
|
||||
let addr_map = pdb.address_map().expect("Cannot get address map");
|
||||
let glosym = pdb.global_symbols().expect("Cannot get global symbols");
|
||||
let mut symbols = glosym.iter();
|
||||
while let Some(symbol) = symbols.next().unwrap() {
|
||||
match symbol.parse() {
|
||||
Ok(SymbolData::PublicSymbol(data)) => {
|
||||
let name = symbol.name().unwrap().to_string();
|
||||
let Rva(rva) = data.offset.to_rva(&addr_map).unwrap_or_default();
|
||||
symbol_extracted.insert(format!("{}", name), rva as u64);
|
||||
},
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut struct_extracted: StructStore = HashMap::new();
|
||||
iter = type_information.iter();
|
||||
while let Some(typ) = iter.next().unwrap() {
|
||||
match typ.parse() {
|
||||
Ok(TypeData::Class(ClassType {name, fields: Some(fields), size, ..})) => {
|
||||
let mut struct_fields = HashMap::new();
|
||||
struct_fields.insert("struct_size".to_string(), ("u32".to_string(), size as u64));
|
||||
match type_finder.find(fields).unwrap().parse().unwrap() {
|
||||
TypeData::FieldList(list) => {
|
||||
for field in list.fields {
|
||||
if let TypeData::Member(member) = field {
|
||||
let mem_typ = get_type_as_str(&type_finder, &member.field_type);
|
||||
struct_fields.insert(
|
||||
format!("{}", member.name), (mem_typ, member.offset as u64));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
struct_extracted.insert(format!("{}", name), struct_fields);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
PdbStore {
|
||||
symbols: symbol_extracted,
|
||||
structs: struct_extracted
|
||||
}
|
||||
}
|
181
src/windows.rs
Normal file
181
src/windows.rs
Normal file
@ -0,0 +1,181 @@
|
||||
use std::ffi::CString;
|
||||
use widestring::{U16CString};
|
||||
|
||||
use winapi::shared::ntdef::*;
|
||||
use winapi::shared::minwindef::{DWORD, HKEY, HMODULE};
|
||||
use winapi::um::winnt::{
|
||||
SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES,
|
||||
REG_DWORD, REG_SZ, REG_OPTION_NON_VOLATILE, KEY_WRITE,
|
||||
PRTL_OSVERSIONINFOW, OSVERSIONINFOW
|
||||
};
|
||||
|
||||
use winapi::um::handleapi::*;
|
||||
use winapi::um::libloaderapi::*;
|
||||
use winapi::um::processthreadsapi::*;
|
||||
use winapi::um::securitybaseapi::*;
|
||||
use winapi::um::winbase::*;
|
||||
use winapi::um::winreg::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum WindowsVersion {
|
||||
Windows10_2015,
|
||||
Windows10_2016,
|
||||
Windows10_2017,
|
||||
Windows10_2018,
|
||||
Windows10_2019,
|
||||
Windows10_2020,
|
||||
Windows10FastRing,
|
||||
Windows10VersionUnknown
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct WindowsFFI {
|
||||
pub version_info: OSVERSIONINFOW,
|
||||
pub short_version: WindowsVersion,
|
||||
driver_registry_string: UNICODE_STRING,
|
||||
ntdll: HMODULE,
|
||||
nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS,
|
||||
nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS,
|
||||
rtl_init_unicode_str: extern "stdcall" fn(PUNICODE_STRING, PCWSTR),
|
||||
rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS,
|
||||
}
|
||||
|
||||
impl WindowsFFI {
|
||||
pub fn new() -> Self {
|
||||
let str_ntdll = CString::new("ntdll").expect("");
|
||||
let str_nt_load_driver = CString::new("NtLoadDriver").expect("");
|
||||
let str_nt_unload_driver = CString::new("NtUnloadDriver").expect("");
|
||||
let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").expect("");
|
||||
let str_rtl_get_version = CString::new("RtlGetVersion").expect("");
|
||||
let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").expect("");
|
||||
|
||||
let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\nganhkhoa.sys").expect("");
|
||||
let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\nganhkhoa").expect("");
|
||||
let str_driver_reg =
|
||||
U16CString::from_str("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa").expect("");
|
||||
let str_type = CString::new("Type").expect("");
|
||||
let str_error_control = CString::new("ErrorControl").expect("");
|
||||
let str_start = CString::new("Start").expect("");
|
||||
let str_image_path = CString::new("ImagePath").expect("");
|
||||
|
||||
let mut str_driver_reg_unicode = UNICODE_STRING::default();
|
||||
let mut version_info = OSVERSIONINFOW {
|
||||
dwOSVersionInfoSize: 0u32,
|
||||
dwMajorVersion: 0u32,
|
||||
dwMinorVersion: 0u32,
|
||||
dwBuildNumber: 0u32,
|
||||
dwPlatformId: 0u32,
|
||||
szCSDVersion: [0u16; 128],
|
||||
};
|
||||
|
||||
let ntdll: HMODULE;
|
||||
let nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS;
|
||||
let nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS;
|
||||
let rtl_init_unicode_str: extern "stdcall" fn(PUNICODE_STRING, PCWSTR);
|
||||
let rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS;
|
||||
|
||||
// some pointer unsafe C code
|
||||
unsafe {
|
||||
ntdll = LoadLibraryA(str_ntdll.as_ptr());
|
||||
let nt_load_driver_ = GetProcAddress(ntdll, str_nt_load_driver.as_ptr());
|
||||
let nt_unload_driver_ = GetProcAddress(ntdll, str_nt_unload_driver.as_ptr());
|
||||
let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr());
|
||||
let rtl_get_version_ = GetProcAddress(ntdll, str_rtl_get_version.as_ptr());
|
||||
|
||||
nt_load_driver = std::mem::transmute(nt_load_driver_);
|
||||
nt_unload_driver = std::mem::transmute(nt_unload_driver_);
|
||||
rtl_init_unicode_str = std::mem::transmute(rtl_init_unicode_str_);
|
||||
rtl_get_version = std::mem::transmute(rtl_get_version_);
|
||||
|
||||
// setup registry
|
||||
let mut registry_key: HKEY = std::ptr::null_mut();
|
||||
RegCreateKeyExA(
|
||||
HKEY_LOCAL_MACHINE, str_registry_path.as_ptr(),
|
||||
0, std::ptr::null_mut(),
|
||||
REG_OPTION_NON_VOLATILE, KEY_WRITE,
|
||||
std::ptr::null_mut(), &mut registry_key, std::ptr::null_mut()
|
||||
);
|
||||
let type_value: [u8; 4] = 1u32.to_le_bytes();
|
||||
let error_control_value: [u8; 4] = 1u32.to_le_bytes();
|
||||
let start_value: [u8; 4] = 3u32.to_le_bytes();
|
||||
let registry_values = [
|
||||
(str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4),
|
||||
(str_error_control.as_ptr(), REG_DWORD, error_control_value.as_ptr(), 4),
|
||||
(str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4),
|
||||
(str_image_path.as_ptr(), REG_SZ,
|
||||
str_driver_path.as_ptr() as *const u8, str_driver_path.to_bytes().len() + 1)
|
||||
];
|
||||
for &(key, keytype, value_ptr, size_in_bytes) in ®istry_values {
|
||||
RegSetValueExA(
|
||||
registry_key, key, 0,
|
||||
keytype, value_ptr, size_in_bytes as u32
|
||||
);
|
||||
}
|
||||
RegCloseKey(registry_key);
|
||||
|
||||
// Setup privilege SeLoadDriverPrivilege
|
||||
let mut token_handle: HANDLE = std::ptr::null_mut();
|
||||
let mut luid = LUID::default();
|
||||
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle);
|
||||
LookupPrivilegeValueA(std::ptr::null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid);
|
||||
let mut new_token_state = TOKEN_PRIVILEGES {
|
||||
PrivilegeCount: 1,
|
||||
Privileges: [LUID_AND_ATTRIBUTES {
|
||||
Luid: luid,
|
||||
Attributes: SE_PRIVILEGE_ENABLED
|
||||
}]
|
||||
};
|
||||
AdjustTokenPrivileges(
|
||||
token_handle, 0, &mut new_token_state, 16, std::ptr::null_mut(), std::ptr::null_mut());
|
||||
CloseHandle(token_handle);
|
||||
|
||||
// init string for load and unload driver routine
|
||||
rtl_init_unicode_str(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16);
|
||||
}
|
||||
|
||||
rtl_get_version(&mut version_info);
|
||||
|
||||
let short_version = match version_info.dwBuildNumber {
|
||||
17134 | 17763 => WindowsVersion::Windows10_2018,
|
||||
18362 | 18363 => WindowsVersion::Windows10_2019,
|
||||
19041 => WindowsVersion::Windows10_2020,
|
||||
_ if version_info.dwBuildNumber >= 19536 => WindowsVersion::Windows10FastRing,
|
||||
_ => WindowsVersion::Windows10VersionUnknown
|
||||
};
|
||||
|
||||
Self {
|
||||
version_info,
|
||||
short_version,
|
||||
driver_registry_string: str_driver_reg_unicode,
|
||||
ntdll,
|
||||
nt_load_driver,
|
||||
nt_unload_driver,
|
||||
rtl_init_unicode_str,
|
||||
rtl_get_version
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_driver(&mut self) -> NTSTATUS {
|
||||
(self.nt_load_driver)(&mut self.driver_registry_string)
|
||||
}
|
||||
|
||||
pub fn unload_driver(&mut self) -> NTSTATUS {
|
||||
(self.nt_unload_driver)(&mut self.driver_registry_string)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_build_number(&self) -> DWORD {
|
||||
self.version_info.dwBuildNumber
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print_version(&self) {
|
||||
println!("Windows version: {}.{}.{} {:?}",
|
||||
self.version_info.dwMajorVersion,
|
||||
self.version_info.dwMinorVersion,
|
||||
self.version_info.dwBuildNumber,
|
||||
self.short_version
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user