Talk about Windows NT / 2000 internal data structure
Webcrazy
TSU00@263.net)
Note: This article is initially found
Www.nsfocus.com
Now we combine regmon.
http://www.sysinternals.com/) The implementation method in NT will come back to the Windows NT / 2000 internal data structure.
Regmon is a utility that monitors the application access system registry. Everyone knows that WINAPI REGXXX is generally called in the app to use the registry, and the Regxxx will eventually call Native API ZWXXXX! (See Windows NT / 2000 DDK Documentation). REGMON is through changing these routines to achieve the purpose of monitoring the registry. The implementation of ZWXXX is as follows:
Mov Eax, ServiceID
Lea Edx, ParameterTable
Int 2eh
Ret paramtablebytes
This is the NT System Services, is it a bit similar to Linux (only Linux is 80h interrupt, it also has ServiceID, such as the Fork system call serviceID 2).
System Services is defined below in DDK Documentation:
The set of native, user-mode routines exported by the Executive for Use Only by protected subsystems. Each System Service Has a name of the form twolattersxxxyy Where:
Twoltters Is The Prefix for All System Services.
XXX IS Usually a Verb, Describing The Operation of a Given Service.
YYY IS generally the Object Type The Service Operates ON.
System Services consists of two parts in the system, and a part is exported by Win32k.sys, and the other part is served by Ntoskrnl.exe. The former mainly completes communication of Win32, POSIX and OS / 2, and the kernel in NT, and can only be called by the user's application, such as USER32! WaitMessage, etc. Since Regmon only involves the latter, this article will discuss it, and all the following discussions about System Service are suitable!
Last time (
NSFOCUS Magazine 10) I used to mention KeserVicedescriptAble, and said its structure is as follows:
Struct _ServiceDescriptorentry {
Unsigned Int * ServiceTableBase;
Unsigned int * ServiceCountertableBase;
Unsigned int numberofservices;
Unsigned char * paramtablebase;
ServiceDescriptAblentry
ntoskrnl.exe export global variables KeServiceDescriptorTable point ServiceDescriptorTableEntry (derived from win32k.sys System Services has its own ServiceDescriptorTable, which 1000h Service ID from the beginning, from the point KeServiceDescriptorTable the offset 50h in Win2000 Server, the structure and derived ntosrknl.exe Basic consistency, this article does not discuss, the NTCall command in Softice can list all System Service in a particular case. Below we first use Softice 4.05 for Windows NT / 2000 to analyze the situation of the X86 platform Windows 2000 Server Build 2195 (here only the extracted part, the data that may get different at different times will not be the same)
: DD KeserviceDescriptable L 4 * 4
/ / If you look at Win32k.sys exportable table, please use DD KeserviceDescriptAble 50 L 4 * 4
// Hop up to offset 50h downward downward
0008: 8046AB80 804704D8 00000000 000000f8 804708bc ..g .......... g.
| | _SERVICETABLEBASE value | | | | _PARAMTABLEBASE value
| | _ Seems to always be 0 |
| _KESERVICEDScriptable address | _NUMBEROFSERVICE
: DD @KServicedescriptable L byte (@ (keserviceDescriptable 08) * 4
// DD ServiceDescriptAblentry-> ServiceTableBase L NumberofService * 4
0008: 804704D8 804AB3BF 804AE86B 804BDEF3 8050B034 ..j.k.j ... k.4.p.
|
| _SERVICEID = 0 System Service Entrance address (according to the subkey)
0008: 804704e8 804C11F4 80459214 8050C2FF 8050C33F ..l ... e ... p.?.p.
0008: 804704f8 804b581c 80508874 8049860a 804fc7e2 .xk.t.p ... i ... o.
80455f7 8049c8a6 80448472 804a8d50 .ui ... I.r.d.p.j.
0008: 80470518 804B6BFB 804F0CEF 804FCB95 8040189A. Kk ... o ... o ... @.
0008: 80470528 804d06cb 80418f66 804f69d4 8049e0cc ..m.f.a..io ... i.
...(slightly)
: DB @ (keserviceDescriptable 0C) l byte (@ (keserviceDescriptable 08))
// DB ServiceDescriptAblentry-> ParamTableBase
0008: 804708BC 18 20 2C 2C 40 2C 40 44-0C 18 18 08 04 04 0C 10., @, @ D ........
|
| _ServiceID = 0 SYSTEM service parameter number * 4 (ie the number of parameters is 18h / 4 = 6)
0008: 804708CC 18 08 08 0C 08 08 04 04-04 0C 04 20 08 0C 14 0C ........... ....... ()
Which application has to be operated on the system registry, as long as you inject your own code in the SYSTEM service it operate, it is also changing the execution process of these System Service, first performing your own code (used for recording in Regmon) The GUI section is used) and then returns to the original operation. Through the above analysis, we know that the SESTEM Service's execution process can be changed as long as the ServiceTableBase to ServiceTableBase NumberofService * 4 range, and as long as you know the SYSTEM Service's serviceID, you can change this System Service entry address in this area, So how do you get the SYSTEM Service's service ID! We can make an example with Zwopenkey:
: u zwopenkey
Ntoskrnl! Zwopenkey
00080000 MOV Eax 00000067
| | | _SERVICEID
| _ Machine code (where the second byte, ZwopenKey linear address plus one is ServiceID)
0008: 80400E2F 8D542404 LEA EDX, [ESP 04]
0008: 80400E33 CD2E INT 2E
0008: 80400E35 C20C00 RET 000c
This way you know the ZWXXX routine name (ie the linear address in the memory), is it possible to implement our purpose? Let's take a look at the specific implementation code of REGMON:
.
.
.
/ / Save ZwopenKey original entrance to use in HookRegopenkey
RealRegopenkey = syscall (zwopenkey);
/ / Modify the ZwopenKey process, point to the new entry, turn to ZwopenKey to turn to execute hookregopenkey
Syscall (zwopenkey) = (pvoid) hookregopenkey;
.
.
.
Syscall is as defined in the Intel platform:
#define syscall (_function) serviceable-> serviceable [* (pulong) ((puChar) _function 1)]
ServiceTable-> ServiceTable is the serviceDescriptableTableEntry-> ServiceTableBase described above (for easy description). _function 1 is the address where ServiceId is located. The entire expression is the location of the orthoction address of the _Function corresponding to the Ingredient address of the SYSTEM Service. Please refer to Regsys.c and Regsys.h for other definitions!
You can use Softice to compare the changes in the System Service entry address before and after loading before and after loading, deepen the understanding of the SYSTEM Service interception.
Ok, now we know that REGMON's basic implementation method (of course, it is necessary to implement this feature, and consider many problems, such as communication between the protective state application and the kernel driver, thread synchronization, etc.).
Let's take a look at another application of KeserviceDescriptable! If we reassign paragraph memory pool, construct your own serviceable and paramtable arrays (must copy the original System Services, otherwise ...), then modify ServiceTableBase and ParamTableBase Make it point to your own serviceable and paramtable, modify NumberofServices, can you add a SYSTEM service from you! If you are interested, you can refer to << undocumented NT>. I have never seen this book, I only know that it is famous online. Oh, thanks to James Shatlyk to provide me with an example code for the book. If you have seen this book (I don't know if there is a Chinese version, e-text can be available), can you contact me? After talking to the system service, let's take a look at how REGMON has acquired system process names in Driver. .
First talk about KTEB (KERNEL THREAD Environment Block) and KPEB (Kernel Process Environment Block), like Teb (which should be user-teb), KPEB / KTEB records system kernel process / thread information. To learn KTEB, KPEB, you first want to know how to get their base address in the current process / thread, you can first look at Native API IOGETCURRENTPROCESS. It is defined in Windows 2000 DDK Document:
Peprocess IOGETCURRENTPROCESS ();
Using IDA Pro or Softice, you can see that it is only implemented by several assembly instructions in Ntoskrnl.exe:
Mov Eax, FS: [00000124]
MOV EAX, [EAX 00000044] // NT 4.0 The following value should be [EAX 40]
RET
This Native API is very typical, and its first instruction acquires the KTEB of the current thread, and the entire API just returns the KPEB to the KTEB start 68 (i.e., 16) bytes to return to the user. You can use Softice to verify.
Let's take another look at how it is true:
/ / -------------------------------------------------------------------------------------------- ----------------------
//
// getProcessNameOffset
//
// in An Effort to Remain Version-Independent, Rather Than Using A
// Hard-Coded Into the KPEB (Kernel Process Environment Block, WE
// scan the kpeb loops for the name, Which shouth match That
// of the gui process
//
/ / -------------------------------------------------------------------------------------------- ----------------------
Ulong getProcessNameOffset ()
{
Peprocess curproc;
INT I;
DBGPRINT ("" getProcessNameOffset / n ")))))
Curproc = psgetcurrentprocess ();
//
// scan for 12kb, hopping the kpeb never big company trat!
//
For (i = 0; i <3 * Page_size; i ) {
IF (! Strncmp (sysname, (pchar) Curproc i, strlen (sysname))) {Return i;
}
}
//
// name not found - OH, Well
//
Return 0;
}
/ / -------------------------------------------------------------------------------------------- ----------------------
//
// getProcess
//
// Uses undocumented data structure offsets to obtain the name of the
// Currently Executing process.
//
/ / -------------------------------------------------------------------------------------------- ----------------------
FiltersTatus getProcess (Pchar Name)
{
Peprocess curproc;
Char * nameptr;
Ulong i;
//
// We Only Try and get the name if we located the name offset
//
IF (ProcessNameOffset) {
Curproc = psgetcurrentprocess ();
Nameptr = (pchar) Curproc ProcessNameOffset
STRNCPY (Name, Nameptr, 16);
} else {
STRCPY (Name, "???");
}
.
.
.
}
This code is extracted from the NT Driver section in Regmon, detailed see Regsys.c.
The main function of these two functions is to obtain the process name for the procedure. Everyone knows that the Win32 API cannot be called in the Driver section, and the NTQuerySystemInformation provided by the NT actuator is mainly for all processes, threads, or other NT internal information, so we must find other methods (general way is to track the corresponding Win32 API with Debugger Reverse engineering with fun but full of challenges, then identifying the specific implementation process in the NT acting body, you can also use this method to verify this article).
These two functions in REGMON passes the process name by finding KPEB, and getProcessNameOffset mainly calls PsgetCurrentProcess to get the KPEB base address, then search for KPEB, get the offset of ProcessName relative to KPEB, stored in the global variable processnameoffset. Define psgetCurrentProcess as follows in NT / 2000 DDK:
#define psgetcurrentprocess () ogetcurrentprocess ()
IOGETCURRENTPROCESS has been discussed earlier.
The author is looking for in the 3-Page memory area (1 page in x86). From the program, you can know if he does not know if it will exceed this range, and the sysname in the block is defined as System because the DriveREntry entry is in the DRIVERENTRY The SYSTEM process schedule (GetProcessNameOffset is called in DriveRentry). You can also use Softice to detect the value of ProcessNameOffset in a specific Windows NT / 2000 version. In the X86 platform Windows 2000 Server Build 2195 it is 1FCH (1DCH in NT 4.0 and 3.51), then find several processes based on this value to check check.
GetProcess adds the current process's KPEB base address to the ProcessNameOffset value (the Native API process in REGMON is called operation registry). As for the specific structure of KPEB / KTEB, the specific meaning of each byte, because of its so-called undocument, I check MSDN, go to all news groups, track the NT core, and have not found a small part of them, this is also my hand. The purpose of the articles, the masters who want to understand, friends can exchange exchanges, there is also a mistake in this article, but also hope that you can point out and talk to me, thank you!
Reference:
1.Regmon 4.22 source code
2.Windows 2000 DDK Documentation