Manipulating processes in the kernel
In the kernel operation process, I believe is a lot of WINDOWS kernel programming interested in the first learning point of knowledge of a friend. But here, I want to let everyone down, the operation process in the kernel is nothing special, in terms of the standard method, still call the process-related NATIVE API (of course, this article refers to the process operation, also includes the operation of the thread and DLL module). This article consists of 10 parts: enumerating processes, suspending processes, recovering processes, ending processes, enumerating threads, pausing threads, recovering threads, ending threads, enumerating DLL modules, and unloading DLL modules.
1. Enumerate processes. A process is a program that is active. Each process in the kernel has a huge structure called EPROCESS that records its details, including its name, number (PID), place of birth (process path), who the father is (ppid or parent process id), etc. In the RING3 enumeration process, it is usually only possible to list the number of all processes. But in RING0 , we also have to list its ID (eprocess) address. Incidentally, the most feared thing for a man in, reality is " Hi-Dad" , This kind of thing is more likely to happen in the kernel. Because EPROCESS has and only one member is the record parent process ID , a little change, You can recognize any process as my father. There are many ways to enumerate processes, and the standard method is to use the ZwQuerySystemInformation SystemProcessInformation function number, but if it is used in the kernel, That's really off your pants, farting--superfluous. Because using this function in the kernel is not going to get the EPROCESS address of the process, and once the memory error, it will be blue screen, more escape from any hidden process. So in the kernel stability Yet intensity Enumeration Process method lifting is enumeration PspCidTable , It has the greatest benefit of being able to get the EPROCESS address of the process , and can check out use " Break chain " This low-level tricks hidden processes. But then again, enumerating PspCidTable is not a very cool thing, because PspCidTable is a unlisted variable, to get its address , you must use hard-coded or signed . So My method is: Enumerate pspcidtable in disguise. The kernel has a function called  PSLOOKUPPROCESSBYPROCESSID, which can process PID check the eprocess of the process, and its internal implementation is enumerating the Pspcidtable. The range of pid is from 4 onwards to Max_int (2^31-1), stepping to 4. But in fact, everyone sees PID basically is less than 10000 , and on 10000 PID believe that many people have not seen. So our actual enumeration scope is 4~2^18, if pslookupprocessbyprocessid return failure, it proves that the process does not exist, if the return is successful, then the eprocess, PID, PPID, The process name prints out.
1. Enumerate Processes//Declaration APINtkernelapi uchar*psgetprocessimagefilename (in peprocess Process); Ntkernelapi HANDLE psgetprocessinheritedfromuniqueprocessid (in peprocess Process);//returns process eprocess based on process ID, failure returns NULLpeprocess lookupprocess (HANDLE Pid) {peprocess eprocess=NULL;if(Nt_success (Pslookupprocessbyprocessid (Pid, &eprocess))) returneprocess;ElsereturnNULL;}//Enumerating ProcessesVOID enumprocess () {ULONG I=0; Peprocess Eproc=NULL; for(i =4; i<262144; i = i +4) {Eproc=lookupprocess ((HANDLE) i);if(Eproc! =NULL) {Dbgprint ("eprocess =%p, PID =%ld, PPID =%ld, Name =%s\n", Eproc, (DWORD) Psgetprocessid (Eproc), (DWORD) Psgetprocessinheritedfromuniqueprocessid (Eproc), Psgetprocessimagefilename (Eproc)); Obdereferenceobject (Eproc); }}2. Pause the process. Pausing a process is the activity of pausing a process, but not killing it. The pause process has an exported function after VISTA: pssuspendprocess. Its function prototype is simple: Ntkernelapi//declares that you want to use this functionNTSTATUS//return typePssuspendprocess (peprocess Process);//the only parameter is eprocess 3. The recovery process. The recovery process is the recovery activity for the suspended process, which is the inverse of the previous operation. The recovery process has an exported function after Vista: Psresumeprocess. Its function prototype is simple: Ntkernelapi//declares that you want to use this functionNTSTATUS//return typePsresumeprocess (peprocess Process);//the only parameter is eprocess 4. End the process. The standard way to end a process is to use the zwopenprocess open process to get the handle, then end with zwterminateprocess and finally close the handle with Zwclose. In addition to this approach, it is possible to end the process with memory zeroing, which uses a certain risk of a blue screen in special cases, but is much stronger than the former. Under the premise that WIN64 cannot engage in kernel hooks, the latter can end any protected process. //Formal method End Processvoidzwkillprocess () {HANDLE hprocess=NULL; client_id clientid;object_attributes OA;//Fill CIDClientid.uniqueprocess = (HANDLE)2908;//change this to the PID you want.Clientid.uniquethread =0;//Filling OAOa. Length =sizeof(OA); Oa.rootdirectory=0; Oa.objectname=0; Oa.attributes=0; Oa.securitydescriptor=0; Oa.securityqualityofservice=0;//open process, end process if handle is validZwopenprocess (&hprocess,1, &oa, &ClientId);if(hprocess) {zwterminateprocess (hprocess,0); Zwclose (hprocess);};} Memory clear 0 Way End Process Ntkernelapi VOID Ntapi keattachprocess (peprocess process); Ntkernelapi VOID Ntapi kedetachprocess ();//Memory Clear 0 method End Processvoidpvase () {size_t I=0;//Dependency ProcessKeattachprocess ((peprocess)0xfffffa8003abdb30);//This changes the eprocess of the specified process for(i =0x10000; i<0x20000000; i + =page_size) {__try{memset (PVOID) I,0, page_size);//put the process memory all 0}_except (1){;}}//exit the dependency processkedetachprocess ();}5. Enumerate threads. The thread is similar to the process, and there is an identity card-like structure ethread stored in the kernel, and all of its ethread are placed in the pspcidtable. So there's code like the enumeration process://returns a thread ethread based on thread ID, failure returns NULLpethread lookupthread (HANDLE Tid) {pethread ethread;if(Nt_success (Pslookupthreadbythreadid (Tid,ðread)))returnEthread;ElsereturnNULL;} //enumerates the threads of a specified processVOID enumthread (peprocess Process) {ULONG i=0, C =0; Pethread ETHRD=NULL; Peprocess Eproc=NULL; for(i =4; i<262144; i = i +4) {ETHRD=Lookupthread ((HANDLE) i);if(ETHRD! =NULL) {//Getting the thread to which the process belongsEproc =iothreadtoprocess (ETHRD);if(Eproc = =Process) {//print out ethread and TIDDbgprint ("ethread=%p, tid=%ld\n", ETHRD, (ULONG) Psgetthreadid (ETHRD));} Obdereferenceobject (ETHRD); }}}6. Suspend the thread. Similar to "pending process", the only difference is that no export function is available. The pssuspendthread can be positioned on its own, and its prototype is as follows: NTSTATUS Pssuspendthread (in Pethread Thread,//Thread EthreadOut Pulong Previoussuspendcount OPTIONAL)//The number of hangs, this value increases by 1 per suspend 7. Resume the thread. Similar to the "recovery process", the only difference is that no export function is available. The psresumethread can be positioned on its own, and its prototype is as follows: NTSTATUS Psresumethread (Pethread Thread,//Thread EthreadOut Pulong Previouscount);//The number of restores, this value is reduced by 1 per recovery, friend normal for 0 o'clock lines 8. End Thread. The standard way to end a thread is zwopenthread+zwterminatethread+Zwclose, the brute force method is to call Pspterminatethreadbypointer directly. The method of violence in the course of the following lecture, the standard method is first spoken here. Since Zwterminatethread is not exported, it can only be hardcoded (using the x command in WINDBG to get the address: x NT!zwterminatethread): typedef NTSTATUS (__fastcall*zwterminatethread) (HANDLE hthread, ULONG uexitcode); Zwterminatethread Zwterminatethread=0xfffff80012345678;//to modify this value//Formal method End threadvoidZwkillthread () {HANDLE hthread=NULL; client_id clientid;object_attributes OA;//Fill CIDClientid.uniqueprocess =0; Clientid.uniquethread= (HANDLE)1234;//change here to the TID you want//Filling OAOa. Length =sizeof(OA); Oa.rootdirectory=0; Oa.objectname=0; Oa.attributes=0; Oa.securitydescriptor=0; Oa.securityqualityofservice=0;//open process, end process if handle is validZwopenprocess (&hthread,1, &oa, &ClientId);if(hthread) {zwterminatethread (Hthread,0); Zwclose (hthread);};}9. Enumerate the DLL modules. The DLL module is recorded in the Ldr list of the PEB, and Ldr is a doubly linked list, which can be enumerated. In addition, the DLL module list contains information about the EXE. In other words, enumerating the DLL modules allows you to enumerate the process paths. //declaring offsetsULONG64 Ldrinpeboffset =0x018;//Peb.ldrULONG64 Modlistinpeboffset =0x010;//peb.ldr.InLoadOrderModuleList//Declaration APIntkernelapi ppeb psgetprocesspeb (peprocess Process);//declaring struct bodiestypedefstruct_ldr_data_table_entry{list_entry64 inloadorderlinks; List_entry64 inmemoryorderlinks; List_entry64 ininitializationorderlinks; PVOID dllbase; PVOID entrypoint; ULONG Sizeofimage; Unicode_string Fulldllname; Unicode_string Basedllname; ULONG Flags; USHORT Loadcount; USHORT TlsIndex; PVOID Sectionpointer; ULONG CheckSum; PVOID Loadedimports; PVOID Entrypointactivationcontext; PVOID patchinformation; List_entry64 forwarderlinks; List_entry64 servicetaglinks; List_entry64 staticlinks; PVOID contextinformation; ULONG64 originalbase; Large_integer Loadtime;} Ldr_data_table_entry,*Pldr_data_table_entry;//enumerate modules based on processVOID enummodule (peprocess Process) {ULONG64 Peb=0; ULONG64 LDR=0; Plist_entry Modlisthead=0; Plist_entry Module=0; Ansi_string ansistring; Kapc_state KS;//exit if eprocess address is invalidif(!Mmisaddressvalid (Process))return;//Get PEB AddressPeb =Psgetprocesspeb (Process);//exit if PEB address is invalidif(!Peb)return;//Dependency ProcessKestackattachprocess (Process, &KS); __try{//Get LDR AddressLDR = Peb +(ULONG64) ldrinpeboffset;//test is readable, unreadable and throws an unexpected exitProbeforread (CONST PVOID) LDR,8,8);//get the list headerModlisthead = (plist_entry) (* (PULONG64) LDR +modlistinpeboffset);//Test readability againProbeforread (CONST PVOID) Modlisthead,8,8);//get the information for the first moduleModule = modlisthead->Flink; while(Modlisthead! =Module) {//Print Information: base address, size, DLL pathDbgprint ("base=%p, size=%ld, Path=%wz", (PVOID) (((pldr_data_table_entry) Module)-dllbase), (ULONG) ((pldr_data_table_entry) Module)-sizeofimage),& ((pldr_data_table_entry) Module)fulldllname)); Module= module->Flink;//testing the readability of the next module informationProbeforread (CONST PVOID) Module, the,8);}} __except (exception_execute_handler) {Dbgprint ("[Enummodule]__except (Exception_execute_handler)");}//Cancel the dependency processKeunstackdetachprocess (&KS);} Ten. Unload the DLL module. You can use Mmunmapviewofsection. The prototype of Mmunmapviewofsection is as follows. Fill out the correct eprocess and DLL module base address to unload the DLL. Uninstalling critical DLLs such as NTDLL will cause the process to crash Ntstatus Mmunmapviewofsection (in peprocess process,//eprocess of the processIn PVOID baseaddress)//DLL Module Base Address
Operating processes in the kernel