Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Analysis of the principle of Ctrl-Inject, a new process injection technology

2025-01-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)06/01 Report--

Overview

In this article, we will mainly introduce a new method of process injection, which we call "Ctrl-Inject", which uses the mechanism of processing Ctrl signals in console applications to implement injection. In the course of our research, while browsing MSDN, we found a comment about Ctrl signal processing: "this is a function used with the SetConsoleCtrlHandler function (https://docs.microsoft.com/en-us/windows/console/setconsolectrlhandler) and defined by the application." The console process uses this function to process the control signals received by the process. When the signal is received, the system starts a new thread in the process to execute the function. " This means that every time we trigger a signal to a console-based process, the system calls a handler called in the new thread. Because of this, we can make use of this feature to achieve a different process injection.

Control signal processing

When a user or process sends a Ctrl + C (or Break) signal to a console-based process, such as cmd.exe or powershell.exe, the system process csrss.exe creates a new thread in the target process to call the function CtrlRoutine. The CtrlRoutine function is responsible for wrapping handlers that use SetConsoleCtrlHandler. Next, let's take a closer look at CtrlRoutine and first notice the following code:

This function uses a global variable named HandlerList to store the list of callback functions, which loop until one of the handlers returns TRUE (notifying that the signal has been processed). In order for the handler to execute successfully, it must meet the following conditions: 1. The function pointer must be encoded correctly. Each pointer in the list of handlers is encoded using RtlEncodePointer and decoded using RtlDecodePointer API before execution. As a result, unencoded pointers are likely to cause the program to crash. 2. Point to a valid CFG (Control Flow Guard) target. CFG attempts to protect indirect calls by verifying that the target of the indirect call is a valid function. Let's take a look at SetConsoleCtrlHandle and see how it sets up a Ctrl handler so that we can mimic it later. In the following figure, we can see how each pointer is encoded before it is added to the HandlerList.

Next, we see an internal function call called SetCtrlHandler. This function updates two variables: one is HandlerList to add a new pointer, and the other is HandlerListLength, which is increased in length to accommodate the new list size.

Now, because the HandlerList and HandlerListLength variables reside in the kernelbase.dll module, and the module maps to the same address of all processes, we can find their addresses in the process and use WriteProcessMemory to update their values in the remote process. Our work is not done yet, and given the existence of CFG and pointer coding, we need to find a way to bypass them.

Bypass pointer coding

In versions prior to Windows 10, we needed to understand how pointer encoding and decoding works in order to deal with pointer coding protection. Next, let's take a closer look at how EncodePointer works.

To start, there is a call to NtQueryInformationProcess defined as follows:

NTSTATUS WINAPI NtQueryInformationProcess (

_ In_HANDLE ProcessHandle

_ In_PROCESSINFOCLASS ProcessInformationClass

_ Out_ PVOIDProcessInformation

_ In_ULONGProcessInformationLength

_ Out_opt_ PULONG ReturnLength

)

Based on the above definition, we can make the following assumptions: 1. ProcessHandle: when the value of-1 is passed, it represents the function that references the calling process. 2. ProcessInformationClass: the value of this parameter is 0x24, which is an undisclosed value that requires the kernel retrieval process to encrypt Cookie. The Cookie itself resides in the EPROCESS structure. After retrieving the encrypted Cookie, we can see several operations involving the input pointer and encrypting the Cookie. The details are:

EncodedPointer = (OriginalPointer ^ SecretCookie) > > (SecretCookie & 0x1F)

One way to bypass is to use CreateRemoteThread to execute RtlEncodePointer and pass NULL to it as an argument, as follows: 1) EncodedPointer = (0 ^ SecretCookie) > (SecretCookie & 0x1F) 2) EncodedPointer = SecretCookie > > (SecretCookie & 0x1F) this increases the return value to 31 times the value rotated by Cookie (63 in a 64-bit Windows 10 environment, that is, 0x3f). If we use a known encoded address on the target process, we can violently guess the original cookie value. The following code shows how to make a violent guess about Cookie:

In Windows 10 and above, Microsoft has generously provided us with a new set of API called RtlEncodeRemotePointer and RtlDecodeRemotePointer. As the name implies, we pass a process handle and a pointer, and the API will return a valid encoded pointer to the target process. In addition, there is another technique for extracting Cookie, please refer to: https://github.com/changeofpace/Remote-Process-Cookie-for-Windows-7/blob/master/Remote%20Process%20Cookie%20for%20Windows%207/main.cpp.

Bypass CFG

So far, we have injected our code into the target process and modified the values of HandlerList and HandlerListLength. If we try to send a Ctrl+C signal to trigger the code now, the process will throw an exception and eventually terminate itself. The reason for this is that CFG will notice that we are trying to jump to a pointer to an invalid calling target. Fortunately, Microsoft has been very friendly to us, and they have released another useful API called SetProcessValidCallTargets.

WINAPI SetProcessValidCallTargets (

_ In_HANDLEhProcess

_ In_PVOID VirtualAddress

_ In_SIZE_TRegionSize

_ In_ULONG NumberOfOffsets

_ Inout_ PCFG_CALL_TARGET_INFO OffsetInformation

)

In short, after we pass the process handle and pointer, the API sets it as a valid call target. In addition, this can be achieved using the undocumented API that we introduced earlier (https://blog.ensilo.com/documenting-the-undocumented-adding-cfg-exceptions).

Trigger Ctrl+C event

Now that everything is ready, all we need to do is trigger Ctrl + C on the target process to invoke our code. There are several ways to trigger it. In this case, we can use a combination of SendInput to trigger the system-wide Ctrl key button and the PostMessage used to send the C key. The same applies to hidden or invisible console windows. Here are the functions that trigger the Ctrl-C signal:

Reveal the bottom of the story

In essence, in this process injection technique, we inject code into the target process, but we never call it directly. In other words, we never call CreateRemoteThread ourselves or use SetThreadContext to change the execution flow. Instead, we are asking csrss.exe to call it for us, which appears to be a normal behavior and will not be suspected. The reason for this is that each time a Ctrl + C signal is sent to a console-based application, conhost.exe calls something similar to the call stack, as follows:

Where CsrClientCallServer passes a unique index identifier (0x30401), which is then passed to the csrss.exe service. Where a function named SrvEndTask is called from the scheduling table. The call chain is as follows:

At the end of the call chain, we see RtlCreateUserThread, which is responsible for executing our thread on the target process. Note: although Ctrl-Inject technology is only targeted at console applications, it can also be abused on many console applications, most notably cmd.exe.

Summary

Now, we have learned about this new process injection method, how it works and what's going on behind it. In the end, we can summarize the Ctrl-Inject technology. Compared with the traditional thread injection technology, the main advantage of this technology is that the remote thread is created by the trusted Windows process csrss.exe, which makes it more hidden. But there is also a drawback, that is, this approach is only applicable to console applications.

To implement this process injection technique, the steps required are as follows: 1. Attach the OpenProcess to the console process. 2. Allocate a new buffer to the malicious load by calling VirtualAllocEx. 3. Use WriteProcessMemory to write data to the allocated buffer. 4. Use the target process cookie to point the pointer to the specified buffer. This is done by calling RtlEncodePointer with a null pointer and manually encoding the pointer or by calling RtlEncodeRemotePointer. 5. Notify the remote process that the new pointer is a valid pointer that can use SetProcessValidCallTargets. 6. Finally, the Ctrl + C signal is triggered by the combination of PostMessage and SendInput. 7. Restore the original handler list.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report