I. Preface
In general, to inject your own program into other processes, you must use the DLL file. This method has been discussed in the previous article. But in fact, it can be implemented without relying on DLL files. However, this method is not universal and not as flexible as DLL injection, because it needs to write the code into the "injection program". Once the content to be injected changes, you need to rewrite the entire "injection program ". Unlike DLL injection, you only need to modify the DLL program. Even so, the method of injecting without DLL is worth discussing.
Ii. Basic principles of non-DLL Injection
In terms of injection and uninstallation, whether or not a DLL file exists, the remote thread must execute loadlibrary () or freelibrary (), and The writeprocessmemory () function must be used. The difference is that, without DLL injection, the Code must be directly written to the target process.
If we want to achieve our goal in the target process, we need to find relevant API functions. The address of the kernel32.dll file in each process is the same, but this does not mean that other DLL files have the same address in each process. In this way, you need to find the address of the desired API function in the target process. The address used to obtain the API function is loadlibrary () and getprocaddress (). In the target process, you can use these two functions to obtain the address of any desired API function. Encapsulate the desired API functions and the DLL of the API into a struct and write them directly into the space of the target process, or directly write the code to be remotely executed to the target process space, and then run it using createremotethread.
3. Create an Interface
The program is still made using MFC. The interface is simpler than the previous one. You only need to add a "static text", an "edit box", and a "button" in the dialog box, as shown in:
Figure 1 Interface Design
4. CodingHere, we first define a struct in the file nodllinjectdlg. cpp and include the addresses of the functions to be used in order to facilitate the following operations:
#define STRLEN 40typedef struct _DATA{ DWORD dwLoadLibrary; DWORD dwGetProcAddress; DWORD dwGetModuleHandle; DWORD dwGetModuleFileName; char User32Dll[STRLEN]; char MessageBox[STRLEN]; char Text[STRLEN]; char Caption[STRLEN];}DATA, *PDATA;
The loadlibrarya (), getprocaddress (), getmodulehandle (), and getmodulefilename () functions are stored in the struct. They all belong to kernel32.dll, so they can be extracted in advance. User32dll saves the "user32.dll" string because messageboxa (), a dialog box function used for virus simulation, exists in user32.dll. Text and caption indicate the content and title of the dialog box respectively.
Next, write the injection code:
Void cnodllinjectdlg: injectcode (DWORD dwpid) {// obtain the Process Handle handle hprocess = OpenProcess (process_all_access, false, dwpid) to be injected using the PID value ); if (hprocess = NULL) {afxmessagebox ("process opening failed! "); Return;} data Data = {0}; // obtain the handle data of the API function to be used. dwloadlibrary = (DWORD) getprocaddress (getmodulehandle ("kernel32.dll"), "loadlibrarya"); data. dwgetprocaddress = (DWORD) getprocaddress (getmodulehandle ("kernel32.dll"), "getprocaddress"); data. dwgetmodulehandle = (DWORD) getprocaddress (getmodulehandle ("kernel32.dll"), "getmodulehandlea"); data. dwgetmodulefilename = (DWORD) getprocaddress (getmo Dulehandlea ("kernel32.dll"), "getmodulefilenamea"); // the dialog box defines lstrcpy (data. user32dll, "user32.dll"); lstrcpy (data. messageBox, "messageboxa"); lstrcpy (data. text, "you have been hacked! (By J. Y .) "); lstrcpy (data. caption, "warning"); // apply for the memory space of the data structure lpvoid lpdata = virtualallocex (hprocess, // process to allocate memory null, // desired starting address sizeof (data ), // size of region to allocate mem_commit | mem_reserve, // type of allocation page_readwrite); // type of access protection if (lpdata = NULL) {afxmessagebox ("Application Data Region failed! "); Closehandle (hprocess); return;} DWORD dwwritenum = 0; If (! Writeprocessmemory (hprocess, lpdata, & Data, sizeof (data), & dwwritenum) {afxmessagebox ("Data Structure writing process failed! "); // Release the previously applied memory region upon failure. Undo the submit status of the Memory Page virtualfreeex (hprocess, lpdata, sizeof (data), mem_decommit); closehandle (hprocess ); return;} // request the memory space of the thread function DWORD dwfunsize = 0x2000; lpvoid lpcode = virtualallocex (hprocess, null, dwfunsize, mem_commit, page_execute_readwrite ); if (lpcode = NULL) {afxmessagebox ("failed to apply for function region! "); // Release the previously applied memory region upon failure to cancel the submission status of the Memory Page virtualfreeex (hprocess, lpcode, dwfunsize, mem_decommit); closehandle (hprocess); return ;} if (! Writeprocessmemory (hprocess, lpcode, remotethreadproc, dwfunsize, & dwwritenum) {afxmessagebox ("thread function writing process failed! "); // Release the previously applied memory region upon failure. Undo the submit status of the Memory Page virtualfreeex (hprocess, lpdata, sizeof (data), mem_decommit); virtualfreeex (hprocess, lpcode, dwfunsize, mem_decommit); closehandle (hprocess); return;} Handle hremotethread = createremotethread (hprocess, null, 0, (lpthread_start_routine) lpcode, lpdata, 0, null ); if (hremotethread = NULL) {afxmessagebox ("failed to create a remote thread! "); // Release the previously applied memory region and revoke the submit status of the Memory Page virtualfreeex (hprocess, lpdata, sizeof (data), mem_decommit); virtualfreeex (hprocess, lpcode, dwfunsize, mem_decommit); closehandle (hprocess); return;} afxmessagebox ("successful injection! "); // Wait for the thread to exit waitforsingleobject (hremotethread, infinite); // release the previously applied memory area and cancel the submit status of the Memory Page virtualfreeex (hprocess, lpdata, sizeof (data), mem_decommit); virtualfreeex (hprocess, lpcode, dwfunsize, mem_decommit); closehandle (hremotethread); closehandle (hprocess );}
The above code is a little longer, but in fact, its principle is still very simple, here I still need to determine whether the execution is successful, if the execution fails, release the previously applied resources. Therefore, the above code is very simple.
There is no difference between uninstalling code and injecting code. The key is to write the thread function into the target process, so that the address of the thread function in the target process can be directly given when createremotethread () is used.
The code of the thread function is as follows:
DWORD winapi remotethreadproc (lpvoid lpparam) {pdata = (pdata) lpparam; // define the API function prototype hmodule (_ stdcall * myloadlibrary) (lpctstr ); farproc (_ stdcall * mygetprocaddress) (hmodule, lpcstr); hmodule (_ stdcall * mygetmodulehandle) (lpctstr); int (_ stdcall * mymessagebox) (hwnd, lpctstr, lpctstr, uint); DWORD (_ stdcall * mygetmodulefilename) (hmodule, lptstr, DWORD); myloadlibrary = (hmodule (_ stdcall *) (lpctstr) pdata-> dwloadlibrary; mygetprocaddress = (farproc (_ stdcall *) (hmodule, lpcstr) pdata-> modules; mygetmodulehandle = (hmodule (_ stdcall *) (lpcstr) pdata-> dwgetmodulehandle; mygetmodulefilename = (DWORD (_ stdcall *) (hmodule, lptstr, DWORD nsize) pdata-> dwgetmodulefilename; hmodule = myloadlibrary (pdata-> user32dll ); mymessagebox = (INT (_ stdcall *) (hwnd, lpctstr, lpctstr, uint) mygetprocaddress (hmodule, pdata-> MessageBox); char szmodulename [max_path] = {0 }; mygetmodulefilename (null, szmodulename, max_path); mymessagebox (0, pdata-> text, pdata-> caption, 0); Return 0 ;}
The code of the thread function is a little complex, but in fact these are basic knowledge and will not be repeated. Then write the "inject" button event:
void CNoDllInjectDlg::OnBtnInject() { // TODO: Add your control notification handler code here DWORD dwPid = GetDlgItemInt(IDC_EDIT_PID, FALSE, FALSE); InjectCode(dwPid);}
Finally, add the following content to the nodllinjectdlg. h file:
void InjectCode(DWORD dwPid);
So far, all the code has been compiled, and the actual test is feasible (release version). The effect is the same as described in the previous article.
5. Additional instructions
If compiled in debug mode, VC ++ adds a lot of debugging-related content to the program, and the content address is relative to the current process address, when the code arrives in another process, it may cause errors. Therefore, we should use the release method for compiling, because the release method does not cause injection of code to other processes due to the insertion of debugging-related code.
In addition, if DLL-free injection is used, the "ice blade" is used to view the module information of the injected code process. Before and after injection, the number of modules will not change, the number of modules increases only when DLL injection is performed. For this DLL-free injection method, to end the injection, you only need to close the injection program directly. As in this example, the dialog box is displayed, and the dialog box is closed, indicating that the injection is invalid.
Vi. SummaryThis article is the last part of DLL injection research. I believe these three articles will give you a more comprehensive understanding of DLL injection. By using the DLL injection and uninstallation tools compiled in the second article, we can provide the same tool support for subsequent studies and will continue to use them in the future. Here, I also welcome your valuable comments. For the discussion in this article, you may find that I have not found any problems. After all, the readers of the Board are confused and can improve them together.
Research on Anti-Virus defense article 011st: DLL injection (lower) -- DLL-free Injection