CreateProcessW implements full control over process creation

Source: Internet
Author: User
Article title: CreateProcessW implements full control over process creation. Linux is a technology channel of the IT lab in China. Includes basic categories such as desktop applications, Linux system management, kernel research, embedded systems, and open source.
[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 the virtual address will lead to a copy-on-writ
  
[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 physical memory. First, you can locate the Eprocess (KTEB) of the process itself (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, use \ phymem to read the physical memory content of the page Directory, simulate the operating system, 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.
  
Queries 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 hProce
Ss process 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
  
   <将代码写入远程进程空间>
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)
{
_
  
Sm 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] means that we use WritePr
Related Article

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.