Get the kernel variable of the Windows system into:
http://www.xfocus.net
Creation time: 2004-08-05
Article attribute: original
Article submission:
Tombkeeper (T0MBKEEPER_AT_HOTMAIL.COM)
Get core variables for Windows systems
Servers: Yu
Email: Tombkeeper [0x40] nsfocus [0x2e] COM
Tombkeeper [0x40] xfocus [0x2e] org
Completed in: 2004.07.30
Keywords: PslinedModuleList, PsactiveProcesshead, NTSystemdebugControl
PSNTOSIMAGEBASE, KDVERSIONBLOCK, KDDEBUGERDATABLOCK, kernel variable
The important kernel variables such as psloadedModuleList are not exported by ntoskrnl.exe, nor open letters.
Number can be obtained. And these core variables are used for rootkit, anti-rootkit, and core overflow.
is crucial.
Here we take PslineDModuleList, PSActiveProcesshead, etc., introduced these
Method of variables.
For Windows NT 4.0 and Windows 2000, there is no "gentle" approach to get these variables.
The ideal method is also the characteristic code search, which is very effective, generally
No problem; for Windows XP and Windows 2003, we found some more elegant options.
The method of the feature code search is first introduced.
[DWORD KERNELBASE]
To perform a feature code search, first position Ntoskrnl.exe in the loading address of the kernel KERNELBASE.
This address can pass the SystemModuleInformation of ZwQuerySysteminformation Class 10
Come. Reference resource [1] is given. In fact, the value of kernelbase is the same.
Union is very fixed, you can use it as a constant:
Windows NT: 0x80100000
Windows 2000: 0x80400000
Windows XP: 0x804d1000
Windows 2003: 0x804e0000
Windows NT 4.0 ntoskrnl.exe OptionalHeader-> ImageBase = 0x80100000,
NTLDR will also load the kernel according to this value, but it is not the case from Windows 2000. Maybe
For this historical reason, the * (dword *) PSNTOSIMAGEBASE of each system is always initialized to 0x80100000.
In addition, the kernel variables PSNTOSIMAGEBASE, KDPNTOSIMAGEBASE, etc. also points to kernelbase:
KernelBase = * (dword *) PSNTOSIMAGEBASE
KernelBase = * (dword *) KDPNTOSIMAGEBASE
[LIST_ENTRY PSLOADMODULIST]
PSLoadedModuLIST This global variable points to a bidirectional linked list that holds the loaded drive information.
Through it, it can enumerate all drive modules in the system.
Although many kernel functions have been used in psloadedModuleList, most of them have not been exported, and
Singing from the base address is very spent. For Windows 2000, it is a good idea from the following place:
NT! mmgetsystemRoutineaddress 0x66: 804f0ed0 8b35f0E84680 MOV ESI, [NT! PslineAdModuleList (8046e8f0)]
804f0ed6 81FEF0E84680 CMP ESI, 0X8046E8F0
The process is as follows:
1, ImageBase = loadingLibrarya ("Ntoskrnl.exe")
2, getProcaddress (ImageBase, "MmgetsystemRoutineaddress")
3. Search character code:
* (Word *) (MmgetsystemRoutineaddress i) = 0x358B && /
* (Word *) (MmgetsystemRoutineaddress i 6) = 0xfe81
&&&&
* (DWORD *) (MMgetsystemRoutineaddress i 2) == /
* (DWORD *) (MmgetsystemRoutineadDress i 8)
4, position the address in the kernel:
PslinedModuleList = /
* (DWORD *) (MmgetsystemRoutineaddress i 2) (kernelbase - imagebase)
From SP0 to SP4, I is not the same, but it is definitely not more than 0x100.
For Windows NT, it is not so lucky, there is no ideal API that can be used for positioning, only from
Start search. The following code has a good stability and uniqueness to SP1 ~ SP6A:
801CEB1C: 8B 4D 08 MOV ECX, DWORD PTR [EBP 8]
801ceb1f: 89 01 MOV DWORD PTR [ECX], EAX
801ceb21: 8b 45 0c MOV Eax, DWORD PTR [EBP 0CH]
801 CEB24: 89 10 MOV DWORD PTR [EAX], EDX
801CEB26: 8B 36 MOV ESI, DWORD PTR [ESI]
801 CEB28: 81 Fe 70 0B 15 80 CMP ESI, 80150B70H // PslineedModuleList
If you use the driver to do this, you don't have to violent search, fuzen_op (fuzen_op@yahoo.com)
In Fu_Rootkit 2.0 (Reference Resources [2]) used a more clever code:
DWORD FINDPSLOADMODULIST (in PDRIVER_Object DriverObject)
{
PModule_ENTRY PM_CURRENT;
IF (driverObject == null)
Return 0;
PM_CURRENT = * ((PModule_Entry *) ((DWORD) DriverObject 0x14));
IF (pm_current == null)
Return 0;
Gul_psloadedModuleList = pm_current;
While (PModule_Entry) PM_Current-> le_mod.flink! = gul_psloadedModuleList) {
IF ((pm_current-> unk1 == 0x00000000) && /
(pm_current-> driver_path.length == 0))))
{
Return (DWORD) PM_CURRENT;
}
PM_Current = (Module_ENTRY *) PM_CURRENT-> Le_Mod.flink;
}
Return 0;
}
[List_entry psactiveprocesshead]
In theory, PSACTIVEPROCESSHEAD can also be taken by search code, but there is a simpler
method.
Ntoskrnl.exe exported psinitialsystemprocess is a peprocess, pointing to System into
Cheng's EPROCESS. This Eprocess's structural member eProcess.ActiveProcessLinks.blink is
PSactiveProcesshead:
KD> DT _eprocess ActiveProcessLinks.blink Poi (psinitialsystemprocess)
0x0A0 ActiveProcessLinks: [0x81356900 - 0x8046e728]
0x004 blink: 0x8046e728 [0x81a2fb00 - 0xff5a4CE0]
KD>? PSactiveProcessheadhead
Evaluate Expression: -2142836952 = 8046e728
This structure is different in different operating systems and needs to be treated separately.
[struct _kddebugger_data64 kddebuggerdatablock]
Windows 2000 starts, the system introduces the variable kddebuggerdatablock. It contains a lot of
The kernel variable. If you can get it, you can solve many problems. Unfortunately, there is no in Windows NT.
This variable. WDBGEXTS.H of Windbg SDK contains its structure:
Typedef struct _kddebugger_data64
Because it is relatively long, it is not quoted here.
From the reverse engineering result of the 5.0.2195.6902 version Ntoskrnl.exe, only two functions are used
The variable is not exported, and the two functions are not exported, and there is no obvious feature before and after the code, and it cannot be searched directly.
Code is obtained.
However, we found that ntoskrnl.exe exports KDENABLEDEBUGGER, KDENABLEDEBUGGER
Call KDINITSYSTEM, and KDINITSYSTEM quoted KDDebuggerDataBlock:
N <100
Windows 2000:
KDENABLEDEBUGER N:
6A 00 Push 0
6A 00 Push 0
C6 05 28 41 48 00 01 MOV _poHiberinProgress, 1
E8 1C DC 10 00 Call _kdinitsystem @ 8; kdinitsystem (x, x)
Kdinitsystem N:
68 70 02 00 00 Push 270H // Sizeof (KDDebuggerDataBlock) B9 50 D1 54 00 MOV ECX, Offset _kdpdebuggerDataListHead
68 D8 FA 46 00 Push Offset KddebuggerDataBlock
8b 40 18 MOV EAX, [EAX 18H]
68 4B 44 42 47 Push 4742444BH // "KDBG", can be used as a searcher
A3 3C D1 54 00 MOV DS: _KDPNTOSIMAGEBASE, EAX
89 0D 54 D1 54 00 MOV DS: DWORD_54D154, ECX
89 0D 50 D1 54 00 MOV DS: _KDPDebuggerDataListhead, ECX
Windows XP
KDENABLEDEBUGER N:
6A 00 Push 0
6A 00 Push 0
C6 05 8c 98 47 00 01 MOV _poHiberinProgress, 1
E8 2b 17 13 00 Call _kdinitsystem @ 8; kdinitsystem (x, x)
Kdinitsystem N:
68 90 02 00 00 Push 290h
68 E0 9D 46 00 push offset kddebuggerdatablock
BE 74 96 59 00 MOV ESI, Offset _kdpdebuggerDataListHead
68 4B 44 42 47 Push 4742444BH
89 35 78 96 59 00 MOV DS: DWORD_599678, ESI
89 35 74 96 59 00 MOV DS: _KdpdebuggerDataListHead, ESI
WINDOWS 2003
KDENABLEDEBUGER N:
56 Push ESI
56 Push ESI
C6 05 0C 08 49 00 01 MOV PoHiberinProgres, 1
E8 CB AD 15 00 Call _kdinitsystem @ 8; kdinitsystem (x, x)
Kdinitsystem N:
68 18 03 00 00 push 318h
68 D0 A3 47 00 Push Offset KddebuggerDataBlock
BE 18 10 5D 00 MOV ESI, Offset _kdpdebuggerDataListhead
68 4B 44 42 47 Push 4742444BH
89 35 1C 10 5D 00 MOV DS: DWORD_5D101C, ESI
89 35 18 10 5D 00 MOV DS: _KDPDebuggerDataListhead, ESI
It can be seen that the uniqueness of the above code characteristics is very good. It is no problem for searching for search. I am at the same time.
List three system code, just for comparison, in fact, it is not necessary to take such violent means for Windows XP and Windows 2003.
The following describes how to make Windows XP and Windows 2003.
[struct _dbgkd_get_version64 kdversionblock]
OPC0DE and EDGAR Barbosa mentioned in Reference Resources [3], Windows XP and Windows 2003 introduced
A new kernel variable: kdversionblock, which contains psloadedModuleList.
The structure of KdversionBlock in WDBGEXTS.H of Windbg SDK:
TYPEDEF STRUCT _DBGKD_GET_VERSION64 {
Ushort Majorversion;
Ushort minorversion;
Ushort protocolversion;
Ushort flags;
USHORT MACHINETYPE;
Uchar maxpackettype;
Uchar maxStatechange;
Uchar maxmanipulate;
Uchar simulation;
Ushort unused [1];
Ulong64 kernbase;
Ulong64 pslineedmodulelist;
Ulong64 debuggerDataList;
} DBGKD_GET_VERSION64, * PDBGKD_GET_VERSION64;
KDVERSIONBLOCK is a member of KPCR:
LKD> DT _KPCR ffdff000
NT! _KPCR
0x000 NTTIB: _NT_TIB
0x000 Used_exceptionList: 0xf717dbcc
0x004 USED_STACKBASE: (NULL)
0x008 Perfglobalgroupmask: (NULL)
0x00c TSSCopy: 0x80042000
0x010 Contextswitches: 0x1f8b07a
0x014 setmembercopy: 1
0x018 Used_sel: 0x7ffde000
0x01c Selfpcr: 0xffdff000
0x020 PRCB: 0xffdff120
0x024 Irql: 0x2 ''
0x028 IRR: 0
0x02c Irractive: 0
0x030 IDR: 0xffff24e0
0x034 kdversionblock: 0x8055a3a8 <-
0x038 IDT: 0x8003F400
0x03c GDT: 0x8003F000
0x040 TSS: 0x80042000
0x044 Majorversion: 1
0x046 MinorVersion: 1
0x048 setmember: 1
0x04c stallscalefactor: 0x64
0x050 spareunused: 0 ''
0x051 Number: 0 '' 0x052 SPARE0: 0 ''
0x053 SecondlevelCacheassociative: 0x8 ''
0x054 vdmalert: 0
0x058 kernelreserved: [14] 0
0x090 SecondlevelCachesize: 0x80000
0x094 halnderved: [16] 0
0x0D4 InterruptMode: 0
0x0D8 spare1: 0 ''
0x0dc kernelreserved2: [17] 0
0x120 prcbdata: _Kprcb
The KPCR of Windows 2000 and NT is no such member:
KD> DT _KPCR ffdff000
NT! _KPCR
0x000 NTTIB: _NT_TIB
0x01c Selfpcr: 0xffdff000
0x020 PRCB: 0xffdff120
0x024 Irql: 0 ''
0x028 IRR: 0
0x02c Irractive: 0
0x030 idR: 0xffffffff
0x034 reserved2: 0 <-
0x038 IDT: 0x80036400
0x03c gdt: 0x80036000
0x040 TSS: 0x802a4000
0x044 Majorversion: 1
0x046 MinorVersion: 1
0x048 setmember: 1
0x04c stallscalefactor: 0x64
0x050 DebugActive: 0 ''
0x051 Number: 0 ''
0x052 vdmalert: 0 ''
0x053 Reserved: [1] ""
0x054 kernelreserved: [15] 0
0x090 SECONDLEVELCACECHESIZE: 0
0x094 halnderved: [16] 0
0x0D4 InterruptMode: 0
0x0D8 spare1: 0 ''
0x0dc kernelreserved2: [17] 0
0x120 prcbdata: _Kprcb
KPCR's value on each version of the Windows system is fixed 0xffdff000, which gives us another
Method for obtaining PSLoadedModuleList:
#define kpcr 0xffdff000
PSLoadedModuleList = * (DWORD *) (* (DWORD *) (KPCR 0x34) 0x18)
The structural members of KdversionBlock actually KdpdebuggerDataListhead, and:
KdpdebuggerDataListHead.flink = kddebuggerdatablock
KdpdebuggerDataListHead.blink = kddebuggerdatablock
That is, KDVersionBlock has also obtained KDDebuggerDataBlock.
[NTSYSTEMDEBUGCONTROL to get KDVERSIONBLOCK]
On Windows XP and Windows 2003, KD is running in using the "-kl" parameter, even
There is a load symbol table, which is still able to give the correct PSLoadedModuleList:
Windows Server 2003 Kernel Version 3790 Up Free X86 Compatible
Product: Server, Suite: TerminalServer Singleunrts
Built by: 3790.srv03_rtm.030324-2048
KERNEL BASE = 0x804e0000 psloadedModuleList = 0x8056ac08
Obviously, Windows 5.1 provides a machine that gets psloadedmodulelist and kernelbase
system. Debug the KD with Windbg (boiled bean burning ...) found that dbgeng.dll calls an unknown
Native API NTSystemdebugControl, I got the KDVERSIONBLOCK mentioned above. Call
The process is as follows:
DBGENG! DebugClient :: WaitForEvent
DBGENG! RawwaitForevent
Dbgeng! WaitForanyTarget
DBGENG! LOCALLIVEKERNELTARGETINFO :: WaitForevent
DBGENG! LivekernelTargetInfo :: initfromkdversion
DBGENG! LOCALLIVEKERNELTARGETINFO :: GetTargetkDVersion
NTDLL! NTSYSTEMDEBUGCONTROL
For NTSystemDebugControl, in addition to a vulnerability report of Bugtraq ID 9694, interconnected
No relevant information is found online. (In fact, the question of the author is not a vulnerability, because,
To perform this API, you must have a sedebugprivilege privilege, and under normal circumstances, only administrator users
There is only this privilege. For this vulnerability, see Reference Resources [4]).
The results of reverse engineering show, on Windows XP and Windows 2003, NTSystemDebugControl
Function number 7 will call internal functions KdpsysgetVersion:
__stdcall kdpsysgetversion (x)
Arg_0 = dword PTR 0ch
PUSH ESI
Push EDI
Mov EDI, [ESP ARG_0]
Push 0ah
POP ECX
Mov ESI, Offset _kdversionBlock
REP MOVSD
POP EDI
POP ESI
Retn 4
With NTSystemdebugControl, you can get KDVERSIONBLOCK: TYPEDEF ENUM _DEBUG_CONTROL_CODE {
DebuggetkDVersionBlock = 7
} Debug_control_code;
EnablePrivilege (SE_DEBUG_NAME);
ZWSystemDebugControl
DebuggetkDVersionBlock,
NULL,
0,
& Kdversionblock,
Sizeof (kdversionblock),
NULL
);
Printf ("kernbase: 0x% .8x / n", kdversionblock.kernbase;
Printf ("PslineDModuleList: 0x% .8x / N", KDVERSIONBLOCK.PSLOADMODULELIST);
Printf ("DebuggerDataList: 0x% .8x / N", KDVERSIONBLOCK.DEBUGGGERDATALIST);
In addition to getting KDVERSIONBLOCK, NtsystemDebugControl has a lot of powerful features, I
Will introduce in another document.
Summary now.
For Windows 2000, the most important thing is to search for code, get KDDebuggerDataBlock, get
This, actually gets psloadedmodulelist, psactiveprocesshead, and so on.
For Windows XP and Windows 2003, the best way is to directly use NTSystemDebugControl
Go to KDVERSIONBLOCK and then get KddebuggerDataBlock.
Reference resources:
[1] Several implementation and application of internal nuclear level hook
http://www.xfocus.net/articles/200303/499.html
[2] fu_rootkit 2.0
https://www.rootkit.com/vault/fuzen_op/fu_rootkit.zip
[3] Finding Some Non-Exported Kernel Variables in Windows XP
http://www.rootkit.com/vault/opc0de/getvarxp.pdf
[4] Microsoft Windows NTSystemdebugControl () Kernel API Function Privilege
Escalation Vulnerability
http://www.securityfocus.com/bid/9694