Author: Orbit)
E_mail: inte2000@163.com
The previous article describes how to find the running "Source insight" window. This article describes how "tabsiplus" performs code injection. After Windows 9x, Windows operating systems strictly protect the process space, and processes cannot access data or even code through a fixed memory address like a 16-bit Windows system, this means that to implement a software extension function, you must "inject" your code into the software's process space. Of course, A process can also use Windows message transmission mechanism or Mailslot, pipe and other processes to communicate with each other, but not all programs are so "kindly ", these interfaces are left for others to operate, so it is not a method to inject custom code into another process.
There are many ways to inject code into other processes ..... (Xxxxx is omitted here ).
[# $ % ^ &, Please put down the bricks. "The XXXXX word is omitted here" is not for the public, but because there are too many code injection methods, A random search is a lot of resources, not to mention a lot of resources, but also a lot of such as wool and dog hair. No matter how carefully constructed and prepared sentences, you cannot copy the "bad luck ", if you want to learn about these technologies, please refer to an article on codeproject: Three Ways to inject your code into another process]
When Windows loads a dynamic link library for executable files, it does not create a separate process space for the dynamic link library, but copies it, maps to the process space where the executable file is loaded. That is to say, if a Dynamic Linked Library is used by two executable files at the same time, the Dynamic Linked Library has two copies, data between them does not affect each other. This loading method is the basis for implementing code injection: Put the custom code in the dynamic link library to load the program to be mounted, in this way, the Custom Code enters the process space of the program to be hung, and the resources in the process space belonging to the program to be hung can be accessed, including the memory, handle, and kernel object, of course, the more important thing is the function import table, which is the key to the normal operation of the injected program.
The key to the current problem is how to let the program be loaded into our custom dynamic link library. This is the key to implementing plug-ins. The different methods of code injection are the implementation methods in this step, we have selected one of these methods, such as econnoisseurs, that is, using the createremotethread () API to load the custom dynamic link library into the process space of "Source insight. It should be noted that Windows 95/98/me does not support this API, so this method can only be used for Windows built based on the NT Technology (again, there are not many people using these old operating systems now. Do you need any reason not to support them? No? Yes ?..... Q $ # ^ # % # ^ $ % & % ^ *). The usage of createremotethread () is similar to that of createthread (), but createthread () can only start threads in the process, while createremotethread () can start one thread in another process. Createremotethread () requires two conditions: one is the starting address of the thread function, and the other is the thread function parameter, createremotethread () requires the same thread function type as createthread (). There is a non-type pointer parameter. Generally, the thread creator uses this pointer to pass a struct pointer to the thread, all the parameters required by the thread are in this struct. Of course, this struct must also be in the Process space of the process to be hung. Obviously, there will not be such a "clever" function in the suspended process waiting for our createremotethread () to be used, and it will not be "clever" that there is such a qualified struct. Therefore, these conditions must be created by yourself.
Fortunately, Windows provides all the means for us to create conditions. Let's take a look at these two APIs: virtualallocex () and virtualfreeex (), which are used to allocate and release a piece of memory in a specified process, the specified process can be another process. The writeprocessmemory () and readprocessmemory () APIs can write and read the memory of a specified process. Of course, the specified process can also be another process. Now we have the means to operate the memory in other processes, and we can read and write, but the key to the problem is what to read and write? In fact, there are two parts to write into another process: one is the code of the thread function, and the other is the parameter of the thread function. A thread parameter is a piece of memory data. There is no secret. The key is the thread function code, which is generated by another compiler, its ing address and memory access address are both offset from the calculation of the virtual address in this process. Therefore, to copy the code of this function to another process and run it, a lot of details need to be processed. First, this function must stay away from any running library functions and APIs. It is very simple. Once these library functions and APIs are used, after the code is copied to another process, you need to import the table based on the functions of another process and manually modify the call addresses of these database functions and APIs. This is consistent with the virus method, I don't want to be so troublesome, so I 'd better not use them. However, library functions and APIs cannot be used. Is there any way for this thread function to load our customized dynamic link library? The answer is: no. Obviously, the standard C/C ++ language does not load the dynamic link library syntax if you do not call the running library function or API, so you must use (at least) windows API.
Loading a dynamic link library on Windows and running one of the export functions requires three steps: 1. load the dynamic link library; 2. locate the export function address and run the function. 3. release the dynamic link library. These operations involve three APIs: loadlibrarya (W), getprocaddressa (w), and freelibrary, all of which are located in kernel32.dll, and almost all Windows applications use kernel32.dll, of course, some programs do not use this dynamic link library, but such programs are usually not necessary. On Windows, the addresses of these three APIs are fixed in each process, which is the key dependency of the loading method described in this article, it is to obtain the addresses of these three APIs in the local process, and then pass them as parameters to the startup thread function in the process being hung, in this way, the thread function can use these three APIs (called directly through the function address) to load our customized dynamic link library.
To sum up our method, we first use OpenProcess () to get the process handle of the process to be hung up, and then call virtualallocex () to allocate two pieces of memory in the process to be hung up, A piece of code is used to fill in the startup thread code called by createremotethread (), and a piece of code is used to store the parameters that need to be passed to the remote thread function. The memory size used to pass parameters is easy to determine, the parameter size determines the address of the three APIs, as well as the file name (full path) of the custom dynamic link library ), the startup method described in this article is to set an export function in the Custom dynamic library and call this export function to initialize the plug-in program. Therefore, the name of the export function must also be included. Of course, the name of this export function is set in advance. Why do we need to transfer it dynamically? Just use it directly, for example:
Parablock-> pgetprocessaddress (hmudule, "initfunc ");
If you really want to do this, complete the following actions before reading the following: stand for a wall, and then move down at a rate of 5 meters/second, until you stop ........................
.......................
.......................
Finished? Now let's see why we should do this: Because "initfunc" will be put into the static data segment of the local process by the compiler, the actual operation of this Code is the address in the static data segment, this static data does not exist in the process of being hung. When you copy the code to the process of being hung, call the code according to this address, otherwise, a useless data is obtained, leading to parablock-> pgetprocessaddress call failure. Otherwise, an Invalid Address is accessed, leading to unexpected suspension of the Program (for example, the program fails to capture this exception ), do you understand now? This will open your head. This remote thread function cannot reference any external variables. All external variables must allocate a piece of memory through virtualallocex () in the process to be mounted, and then copy it.
The key to better processing the parameter memory is to copy the thread function code. In summary, this thread function cannot internally call the Runtime library functions and APIs, and cannot use external variables, in addition, there are other requirements for this function, such as the failure to use exception mechanisms (including windows structured exception handling), and the failure to use Jump functions jump and longjump, it is even hard to use case statements (there is no theoretical basis, but many hackers admit this, probably because different compilers generate code in different ways), which is easy to understand, because it is necessary to ensure that the function code generated by the compiler is continuously stored, so that it is easy to copy. This thread function cannot be too large. After all, if you want to become a respected plug-in, you have to consider the program to be suspended and try to save memory. The memory size to be allocated is determined by the actual function code size. You can use an estimate of a large enough value. For example, tabsiplus uses 1024 bytes because the tabsiplus thread function is very small, 1 K bytes is enough. If you want to pursue perfection, you can use the adjacent function address subtraction (completed by the function name) method to calculate the exact size of the function code block. However, no compiler can ensure that the machine code is generated in the order of C/C ++ code. They only do their best.
Now let's make a final conclusion. This method requires two pieces of memory to be allocated in the processes to be mounted. The first is to allocate remote thread parameters. The following is the parameter structure definition:
Typedef hmodule (winapi * ploadlibraryw) (lpcwstr );
Typedef bool (winapi * pfreelibrary) (hmodule );
Typedef farproc (winapi * pgetprocaddress) (hmodule, char *);
Struct remotethreadpara
{
DWORD lasterror;
Ploadlibraryw fnloadlibraryw;
Pfreelibrary fnfreelibrary;
Pgetprocaddress fngetprocaddress;
Wchar lpmodulepath [max_path]; // The dll path
Char lpfunctionname [256]; // The called Function
//... Other parameters are available.
};
The following is the parameter processing code:
Remotethreadpara * C = 0;
DWORD rc = (DWORD)-1;
Hmodule hkernel32 = 0;
Remotethreadpara localcopy;
// Allocate memory for parameter block
C = (remotethreadpara *) virtualallocex (hprocess, 0, sizeof (remotethreadpara), mem_commit, page_readwrite );
// First fill in a local structure
# Ifdef _ Unicode
Lstrcpyw (localcopy. lpmodulepath, lpdllpath );
# Else
WsprintfW (localcopy. lpmodulepath, l "% hs", lpdllpath); // lpdllpath is the full path name of the custom dynamic library.
# Endif
If (lpfunctionname = NULL)
Localcopy. lpfunctionname [0] = '/0 ';
Else
Lstrcpyna (localcopy. lpfunctionname, lpfunctionname, sizeof_array (localcopy. lpfunctionname); // lpfunctionname is the name of the startup function.
// Kernel32.dll
Hkernel32 = getmodulehandle (_ T ("kernel32.dll "));
// Get the addresses for the functions, what we will use in the remote thread
Localcopy. fnloadlibraryw = (ploadlibraryw) getprocaddress (hkernel32, "loadlibraryw ");
Localcopy. fnfreelibrary = (pfreelibrary) getprocaddress (hkernel32, "freelibrary ");
Localcopy. fngetprocaddress = (pgetprocaddress) getprocaddress (hkernel32, "getprocaddress ");
Writeprocessmemory (hprocess, C, & localcopy, sizeof localcopy, 0); // do you understand why a local structure is required? Because only this function can operate C memory
The following is the function processing code:
// Allocate memory for injected code
P = virtualallocex (hprocess, 0, 1024, mem_commit, page_execute_readwrite );
// Copy function there, we will execute this piece of code
Writeprocessmemory (hprocess, P, remotedllthread, 1024, 0 );
The following is the critical remotedllthread thread function code:
DWORD _ stdcall remotedllthread (lpvoid ppara)
{
Remotethreadpara * prblock = (remotethreadpara *) ppara;
Hmodule = NULL;
// Load the requested DLL
If (prblock-> bloadlibrary)
{
Hmodule = (hmodule) (* prblock-> fnloadlibraryw) (prblock-> lpmodulepath );
}
// Call Function
If (prblock-> lpfunctionname [0]! = 0)
{
// Execute a function if we have a function name
PFN = (PFn) (* prblock-> fngetprocaddress) (hmodule, prblock-> lpfunctionname );
// Execute the function, and get the result
If (PFN! = NULL)
{
DWORD ret = 0;
Ret = (* PFn) (); // call the startup function of the plug-in Dynamic Link Library
}
}
// Free Library
If (PFN-> bfreelibrary)
{
PFN-> fnfreelibrary (hmodule );
}
// ...... Other processing code
Return 0;
}
PFN is a prototype for customizing the dynamic link library startup function:
Typedef DWORD (winapi * PFn )();
Now everything is ready, and we have nothing to do, that is, calling createremotethread () to start a remote thread and loading our custom Dynamic Link Library:
Ht = createremotethread (hprocess, 0, 0, (DWORD (_ stdcall *) (void *) P, C, 0, & threadid );
This article will show you how to build a custom dynamic link library that provides custom functions.
Source insignt file tag plug-in: tabsiplus:
Click to download