We know there are many ways to inject a dynamic connection library into other processes. The most common method is to use the hook function, but this method has two main disadvantages: First, if a process does not load user32.dll, the hook dll will never be loaded. When the second hook DLL is loaded, the hook dll can be loaded only when the process sends a USER32 call. That is to say, if the process is performing complex numerical calculations and there is no time for message calling, the hook dll will not be loaded. Theoretically, there is no precise way to determine whether our hook dll has been injected into the desired process. Another common method is to use the createremotethread function to enable a thread in other processes to load the DLL. It should be said that this is a perfect solution. This method avoids all the disadvantages of using the hook function, but unfortunately this function can only be used in winnt/2000.
This article will discuss a new method for injecting a dynamic connection library into other processes. The idea is similar to the createremotethread function, except that it can be used in operating systems such as Win9x, Win2k, and WINXP. Here we will show you how to inject the dll(injectdll.dll(into the assumer.exe process!
ProgramThe idea is as follows:
1: the ID of any thread in the assumer.exe process.
2: According to the thread ID, get the thread handle
3: suspend the thread and save the current "context" of the thread"
4: Change the EIP pointer of this thread so that it points to the function (injectcodefun) where we load the DLL, and then restore the thread.
5: after our DLL loading function is run, we will suspend this thread again and use the previously saved "context" to restore this thread to its status before it is changed, and continue running.
The hacker did not notice any exceptions!
Next we will explain in detail how to implement the above process by programming.
The implementation of step 1 is very easy. We only need to call the toolhelp function to get what we need. Here we will not detail it, please referSource codeGetprocessid and getthreadid.
Step 2 is quite troublesome. In Win9x, no function is provided, and thread handle can be obtained by the thread ID (Fortunately, Win2k provides this function ). Fortunately, we can find this function on some foreign BBS, which uses some undisclosed structures. The purpose of this article is not to discuss this issue. If you are interested, you can refer to our sourceCodeOpenthread2 function. This function is used to input a thread ID parameter and return the corresponding thread handle.
The implementation in step 3 is also very easy and standard. We can use sdks such as suspendthread and getthreadcontext to easily complete the process.
Step 4: This step is the most important step. For ease of instruction, we will reference the statements in our source code. Please refer to the injectcode=thread function in the source code.
First, we can use the following code to change the EIP pointer of the thread.
Threadcontext. EIP = (DWORD) m_lpcodebase;
Setthreadcontext (m_hinjectthread, & threadcontext );
The variable m_lpcodebase points to the first address of our loaded DLL function (injectcodefun.
the most important part here is how we generate our DLL Loading Function (injectcodefun ). Note that we cannot simply write a function in our program and assign its first address to the EIP. This is because the installation of dllscripts is to be run in the assumer.exe address space. If we use functions in our own address space, the system will inevitably crash. The solution is to put the loaded DLL function (injectcodefun) written in the address space shared by all programs, in Win9x 0x80000000 ~ 0xffffffff is the address space we want to share. How can we put the DLL function we wrote in this address space? There are many methods. We use a standard method "memory image file" to solve this problem. We use the createfilemapping function to allocate a shared address space, and then copy the DLL loading function we wrote to this address space. For specific code, refer to the initinject function in the source code.
There are two other problems in the loaded DLL function (injectcodefun) that we have written. First, we can't use any variables defined in our own programs in this function, the reason is the same as above, because the address space is different. In addition, we cannot directly call functions. For example, we can directly use loadlibray in injectcodefun. This is because if you directly use loadlibray, you need to go through the program's import table and jump to the real windows loadlibray function. However, different processes have different imports, so we cannot directly call functions. We can use a technology called "dynamic constructor" to create our functions. First, use getprocaddress to obtain the direct address of the loadlibray function, and then use a special number to replace it with 0x11111111 in the place where loadlibray is called, finally, after copying our function to the shared address space, search for the shared memory to find this special number and replace it with the correct address we have previously obtained. The second interesting phenomenon is that the injectcodefun function we wrote should not be returned. This is because this function runs in the explorer thread. We do not know the correct content of the stack or the address pointed to by ESP. If the function returns, we will lose control of the program. Our solution is to send a custom message to our main program after loadlibray is called, to notify our program that the loading task has been completed, and then let the thread enter an endless loop.
Step 5 when our program receives the custom message, it will suspend this thread again and use the setthreadcontext function to restore the "context" of the previously stored thread, then resume running this thread. The result is that assumer.exe does not feel interrupted.
The above is the method we have introduced. Readers can refer to our source code to learn more about the above method. The function of the source code is to inject our dll(injectdll.dll.exe into assumer.exe, create a new thread in injectdll. dll, and then display the current time in the upper left corner of the screen. The source code is divided into Win9x and Win2k versions. The main difference between these two versions is that the method for allocating shared memory is different. The source code has been compiled using vc6 in operating systems such as pwn98, pwinme, Win2k, and WINXP.