Mount createprocessw to implement full control over Process Creation

Source: Internet
Author: User
 Author: system32

This document demonstrates how to implement global hook
[Preface]
[Overview]
[Copy-on-write]
[Three feasible methods]
<Query the base address and attributes of createprocessw>
<Enumerate all processes in the system>
<Modify attributes of the createprocessw page>
<Allocate an available space in the process>
<Write code to remote process space>
<Compiler magic>
<Troubleshooting>
[Complete DEMO code]
[Resource]
++ ++ ++
[Preface]
When I wrote this document, I had enough food and encountered many problems. Thanks to bkbll, a1rsupply and sobeit, and the hard work of tch, this document was born, this article may have some errors, these errors are caused by my mistakes, if you have any comments and views, welcome to http://www.itaq.org pointed out, or e-mail: zf35@citiz.net
[Overview]
The implementation of Process Creation control on the server is of great significance. by monitoring the creation of processes, we can allow the allowed processes to be correctly created, programs that are not allowed will fail to be created. This prevents unknown Trojans, viruses, and worms from threatening the server. To achieve the above purpose, you must hook the APIS related to the Windows creation process, and add the actual SoftICE tracking according to the records in "inside the Windows NT" and "Native api reference, the API call process for the Windows creation process is as follows:

Code
Createprocessa-> createprocessw-> createprocessinternalw->... -> Zwcreateprocess is finally called.

In this document, we use createprocessw to achieve our goal. Of course, you can also use several other APIs. The Demo code in this document is slightly changed and can be applied to any ring3 function.
There are many ways to hook an API. This article uses the method of rewriting the function entry point to mount createprocessw, for more details, see sobeit's "several methods to hook APIs in Windows".

[Copy-on-write]
In my initial test, I used SoftICE's a createprocessw to rewrite the code of the function entry point. After F5 switched back to windows, I found everything was desired. But when I wrote a program to modify the code of the createprocessw entry point, the changes are only valid for this process, but have no impact on other processes of the system. After tracing with SoftICE, it is found that the virtual address of createprocessw in this process is mapped to a new physical address, which is different from that of other processes, if you have read the copy-on-write mechanism of webcrazy, it is not hard to see that this is the impact of the copy-on-write mechanism. For system DLL, each DLL is mapped to the same virtual address of different processes, and these virtual addresses point to the same physical address. Through this mechanism, the system achieves the lowest resource consumption. when a process tries to rewrite the data in the physical memory, in order not to affect other processes, the system automatically allocates a new physical memory, copying and rewriting the data in the original physical memory, then, the virtual address of the process that changed the memory is re-mapped to the new physical memory, while other processes are still mapped to the original physical memory, this is the copy-on-write technology. How does the system determine when to use copy-on-write? This is determined by the virtual address Pte. When the copy-on-write mark in the Pte is set, any write operation on this virtual address will result in a copy-on-write.

[Three feasible methods]
To implement global hook, we cannot be restricted by the copy-on-write mechanism. Currently, I have come up with three methods to achieve our goal.
1. use the driver to modify the attributes of the page table item (PTE) so that the virtual address corresponding to createprocessw loses the copy-on-write attribute, in this way, modifications to the createprocessw entry point code in the process will take effect for all processes in the system, so as to implement global hook.

2. you can use an object // phymem provided by windows to directly read and write the physical memory. First, you can locate the eprocess (kteb) (PS: for details about how to locate the eprocess of any process in ring3, refer to the "eprocess for processes" article I wrote earlier.) After obtaining the eprocess, you can get the page Directory of the process, then, read the physical memory content of the page directory using // phymem, simulate the operating system to convert the virtual address> physical memory address, and finally obtain the physical address corresponding to createprocessw, using // phymem, we can avoid the copy-on-write mechanism and directly rewrite createprocessw.

3. Achieve the goal through the most common means, first enumerate all processes in the system, then modify the page attributes of each process through functions such as virtualqueryex, virtualallocex, and virtualprotectex, and allocate new space. Finally, we use writeprocessmemory to write our code to the space of each process, and use the createprocessw entry to rewrite JMP ****** to jump to our code and change the execution process of the function.

In the above three methods, method 1 is just an idea and has not yet become a reality. If you have time, I will try again. Of course, you are welcome to implement it on the page and mail me a piece of code: P method 2 I have written a complete piece of code to implement it, but it is not discussed in this document. Otherwise, the document will become very long, I will introduce the specific implementation of this method in another document. Method 3 makes the focus of this article. The following describes method 3 in detail.
<Query the base address and attributes of createprocessw>
Here we use the virtualqueryex function. Its prototype is as follows:
Size_t
Virtualqueryex
(
Handle hprocess,
Lpcvoid lpaddress,
Pmemory_basic_information lpbuffer,
Size_t dwlength
);
Parameter description:
Handle hprocess the Process Handle to query memory information
Lpcvoid lpaddress: pointer to the memory area to be queried
Pmemory_basic_information lpbuffer pointer to memory_basic_information Structure
Size_t dwlength lpbuffer size

After this function is called, the relevant information is stored in the structure pointed to by lpbuffer.

<Modify the page attributes of createprocessw>
A page has the following attributes:
Page_execute
Page_execute_read
Page_execute_readwrite
Page_execute_writecopy
Page_noaccess
Page_readonly
Page_readwrite
Page_writecopy

We use virtualprotectex to modify the page attributes:
Bool
Virtualprotectex
(
Handle hprocess,
Lpvoid lpaddress,
Size_t dwsize,
DWORD flnewprotect,
Pdword lpfloldprotect
);
Parameter description:
Handle hprocess handle
Lpvoid lpaddress: pointer to the memory area to be modified
Size of the memory area modified by size_t dwsize
New Page properties of dword flnewprotect
Pdword lpfloldprotect pointer to the memory that saves the old page Property

From the code below, we can see that in order to rewrite the code of the function entry point, we must assign it the page_execute_readwrite attribute.

<Allocate available space in the process>
It is not enough to modify the function entry point code. We must write a code to take over createprocessw. Because the process space is isolated from each other, in order to achieve the global hook goal, we must ask each process for a space to store our code. This requires the virtualallocex function. The virtualallocex prototype is as follows:
Lpvoid
Virtualallocex
(
Handle hprocess,
Lpvoid lpaddress,
Size_t dwsize,
DWORD flallocationtype,
DWORD flprotect
);
Parameter description:
Handle hprocess handle
Lpvoid lpaddress pointer to the allocated memory area
Size of the area allocated by size_t dwsize
DWORD flallocationtype memory type
New DWORD flprotect memory attributes

<Write code to remote process space>
We use the writeprocessmemory function to write our code and data to remote processes. Its prototype is as follows:
Bool
Writeprocessmemory (
Handle hprocess,
Lpvoid lpbaseaddress,
Lpcvoid lpbuffer,
Size_t nsize,
Size_t * lpnumberofbyteswritten
);
Parameter description:
Handle hprocess handle
Lpvoid lpbaseaddress: pointer to the write address
Lpcvoid lpbuffer: pointer to the written data
Size_t nsize lpbuffer size
Size_t * number of bytes actually written by lpnumberofbyteswritten

<Compiler magic>
When I use writeprocessmemory to write the content of a jmptoaddress function written by myself to a remote process space, I find that no matter what the content of my jmptoaddress is, the write space is E9 *, which makes me very confused. From the machine code, this is a relatively jump command. So where does it come from? To solve this problem, I debugged it with VC. In the Watch window, enter jmptoaddress to display the virtual address 0x000000xxx of jmptoaddress, and then open the memory window, check the content in the memory and find that it is indeed the jmptoaddress code. This is strange. Where did the mysterious E9 *** come from? So I consulted a1rsupply, he told me that the debugging version of VC will generate a jump table. This is a big picture. It turns out to be a magic of the compiler.

To correctly write code to a remote process, we must calculate the real function address. Below I write a piece of code to calculate the real function address:
_ ASM
{
Pushad
Lea eax, jmptoaddress
MoV ECx, jmptoaddress
SHR ECx, 8
Add eax, ECx
Add eax, 5
MoV jmpaftercalc, eax
Popad
}

<Troubleshooting>
Another major problem I encountered during code writing is how to locate the address. The jmptoaddress () function I wrote is as follows:
Void _ declspec (naked) jmptoaddress (void)
{
_ Asm jmp [hookedaddr]
}
There is no problem with this code in the Local process, but when it is written to the remote process, it will cause various problems. Let's take a look at its assembly code, as shown below:
JMP [00401 CXXX]
We noticed that the virtual address in this process stores the hookedaddr address, but in a remote process, this address points to something else, and JMP will generate unexpected results in the past, to achieve the correct behavior, we first write the hookedaddr content to the remote process using writeprocessmemory, and then reference it with a relative address.
Void _ declspec (naked) jmpaddress (void)
{
_ ASM call flag
Flag:
_ ASM pop eax
_ ASM add eax, 0x0e
_ ASM mov EBX, [eax]
_ ASM JMP EBX
}
After Pop eax, eax stores the virtual address of this command. After a fixed value is added, [eax] is the data written through writeprocessmemory.

Complete DEMO code

Code: /*************************************** ***************************
* Author :*
* [I .t. S] system32 *
* Module name *
* Hook_api_1.cpp *
* Abstract :*
* This Code show the method of hooking Win32 API *
* Environment :*
* User Mode-Win32 *
* Revision history :*
* 2004-9-20 *
* Express my thanks :*
* Bkbll, a1rsupp1y, sobeit and TCH *
* Our homepage :*
* [Url] http://www.itaq.org [/url] *
**************************************** **************************/

# Include <windows. h>
# Include <stdio. h>
# Include "psapi. H"

# Pragma comment (Lib, "psapi. lib ")

# Define ntapiaddr farproc
# Define k_module "kernel32.dll"
# Define hook_api "createprocessw"

Hmodule hkernel32 = getmodulehandle (k_module );
Ntapiaddr pcreateprocessw = getprocaddress (hkernel32, hook_api );
Lpvoid hookedaddr = NULL;

Void _ declspec (naked) realexecute (void)
{
/* You can add your own hooked createprocessw function here */
_ Asm ret 0x28
}

Void _ declspec (naked) jmptoaddress (void)
{
_ ASM call flag
Flag:
_ ASM pop eax
_ ASM add eax, 0x0e
_ ASM mov EBX, [eax]
_ ASM JMP EBX
}

Bool winapi getdebugprivilege (void );
Bool winapi inserthook (DWORD processid );

Void main (void)
{
DWORD processlist [80], processnum;

Enumprocesses (processlist, sizeof (processlist), & processnum );

Processnum/= sizeof (DWORD );

Printf ("current process num is % d/n/R", processnum );
// Printf ("% 08x/n/R", (lpvoid) realexecute );

Getdebugprivilege ();

// Step over the 0 Process
For (dword count = 1; count <processnum; count ++)
{
Inserthook (processlist [count]);
}

Sleep (2000 );
Return;
}

Bool winapi getdebugprivilege (void)
{
Handle htoken, hprocess;
Token_privileges TP;
Char * release DEBUG = "sedebugprivilege ";

Hprocess = getcurrentprocess ();
Openprocesstoken (hprocess, token_adjust_privileges | token_query, & htoken );
Lookupprivilegevalue (null, release debug, & TP. Privileges [0]. luid );
TP. privilegecount = 1;
TP. Privileges [0]. Attributes = se_privilege_enabled;
Adjusttokenprivileges (htoken, false, & TP, null );
Return 0;
}

Bool winapi inserthook (DWORD processid)
{
Memory_basic_information MBI;
Handle hprocess;
Lpvoid realaftercalc, jmpaftercalc;

Int cb = sizeof (tchar) * 4*1024;

// Only for test
// If (1860! = Processid) goto end;

Printf ("PID is % d/n/R", processid );

Hprocess = OpenProcess (process_all_access, false, processid );

If (null = hprocess)
{
Printf ("failed! /N/R ");
Goto end;
}
// Calculate the real address of realexecute
_ ASM
{
Pushad
Lea eax, realexecute
MoV ECx, realexecute
SHR ECx, 8
Add eax, ECx
Add eax, 5
MoV realaftercalc, eax
Popad
}
// Calculate the real address of jmptoaddress
_ ASM
{
Pushad
Lea eax, jmptoaddress
MoV ECx, jmptoaddress
SHR ECx, 8
Add eax, ECx
Add eax, 5
MoV jmpaftercalc, eax
Popad
}

// Alloc some memory in the process
Hookedaddr = virtualallocex (hprocess, null, CB, mem_commit, page_execute_readwrite );

If (0 = writeprocessmemory (hprocess, hookedaddr, realaftercalc, 5, null ))
Printf ("writeprocessmemory failed! /N/R ");

Virtualqueryex (hprocess, (lpvoid *) pcreateprocessw, & MBI, sizeof (MBI ));
Virtualprotectex (hprocess, MBI. baseaddress, MBI. regionsize, page_execute_readwrite, & MBI. Protect );

Printf ("hookedaddr is 0x % 08x/n/R", hookedaddr );
Writeprocessmemory (hprocess, pcreateprocessw, jmpaftercalc, 0x0e, null );
Writeprocessmemory (hprocess, (char *) pcreateprocessw + 0x13, & hookedaddr, 4, null );

End:
Return 0;
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.