From http://hi.baidu.com/shenzhe108618/blog/item/f849d7f43d84a6e77709d779.html
There are three main DLL injection methods: Application hook technology, remote thread creation, and trojan dll.
I. Apply Hook Technology for DLL Injection
I have previously written an introduction to hook. If you have read or previously written a hook program, you have already injected such DLL. It installs a hook for the system or a thread. If it is a global hook, your dll will be loaded into the address space of any called process during the process call, which is a waste of resources. Therefore, in the download demonstration, I only install thread hooks for a specified thread.
1. Use BCB to create a DLL Project (if you are using VC or another project, check it yourself) and enter the following code:
// ================================================ ============================================
// File: unitlib. cpp
// Description: demonstrate DLL Injection Using Hook Technology.
// Inject the code in this DLL into the specified process space.
// Author: edification (innocent)
// ================================================ ============================================
// Function declaration
Extern "C" _ declspec (dllexport) _ stdcall
Bool sethook (DWORD dwthreadid );
Extern "C" _ declspec (dllexport) _ stdcall
Lresult callback myproc (INT ncode, wparam, lparam );
Static hhook = NULL; // hook handle
Static hinstance hinst; // The current DLL handle
Int winapi dllentrypoint (hinstance hinst, unsigned long reason, void * lpreserved)
{
Hinst = hinst;
Return 1;
}
//---------------------------------------------------------------------------
// Install the hook function
Bool _ declspec (dllexport) _ stdcall sethook (DWORD dwthreadid)
{
If (dwthreadid! = 0)
{
MessageBox (null, ("DLL has been injected! Nthreadid = "+
Inttostr (dwthreadid). c_str (), "DLL ",
Mb_iconinformation + mb_ OK );
// Install the hook of the specified Thread
Hhook = setwindowshookex (wh_getmessage, (hookproc) myproc,
Hinst, dwthreadid );
If (hhook! = NULL)
Return true;
} Else
{
MessageBox (null, "DLL is about to be withdrawn from the notepad process space! "," DLL ",
Mb_iconinformation + mb_ OK );
Return (unhookwindowshookex (hhook ));
}
Return true;
}
// Hook Function
Lresult callback _ declspec (dllexport) _ stdcall
Myproc (INT ncode, wparam, lparam)
{
// Because it only demonstrates DLL injection, nothing will be done here and it will be handed over to the system for processing.
Return (callnexthookex (hhook, ncode, wparam, lparam ));
}
//---------------------------------------------------------------------------
This dll contains two functions: sethook and myproc ). The installation hook function provides a parameter that specifies the thread to install. If this parameter is set to 0, the hook is uninstalled.
Compile the project to generate the DLL file we want to inject to the specified process.
2. Establish a test project. Create an application project with BCB, add two buttons in the form, one for installing thread hooks and the other for uninstalling. The Code is as follows:
//---------------------------------------------------------------------------
// Sethook function prototype Declaration
Typedef bool (winapi * lpsethook) (unsigned long dwthreadid );
//---------------------------------------------------------------------------
_ Fastcall tfrmmain: tfrmmain (tcomponent * owner)
: Tform (owner)
{
}
//---------------------------------------------------------------------------
// Install the hook
Void _ fastcall tfrmmain: button1click (tobject * sender)
{
String szpath;
Lpsethook lproc;
Handle hdll;
Bool Bret;
Process_information Info;
Startupinfo start;
Memset (& START, 0, sizeof (start ));
// Get the DLL file name to be loaded
Szpath = Application-> exename;
Szpath = szpath. substring (0, szpath. Length ()
-String (strrscan (szpath. c_str (), '/'). Length ());
Szpath = szpath + "/dlllib. dll ";
// Load the DLL
Hdll = loadlibrary (szpath. c_str ());
If (hdll! = NULL)
{
Lproc = (lpsethook) getprocaddress (hdll, "sethook ");
If (lproc! = NULL)
{
// Because there is no proper tool to get the thread ID, and for the sake of simplicity, a new notepad process is created here to get its thread ID and install hooks on it, inject our DLL into the notepad process.
Bret = CreateProcess (null,
"C:/winnt/system32/notepad.exe ",
Null,
Null,
True,
0,
Null,
Null,
& Start,
& Info );
If (Bret! = 0)
{
If (* lproc) (info. dwthreadid) = false)
Showmessage ("sethook failed with error" +
Inttostr (getlasterror ()));
}
Else
{
Showmessage ("CreateProcess failed with error" +
Inttostr (getlasterror ()));
}
}
}
}
//---------------------------------------------------------------------------
// Uninstall the hook
Void _ fastcall tfrmmain: button2click (tobject * sender)
{
String szpath;
Lpsethook lproc;
Handle hdll;
Szpath = Application-> exename;
Szpath = szpath. substring (0, szpath. Length ()
-String (strrscan (szpath. c_str (), '/'). Length ());
Szpath = szpath + "/dlllib. dll ";
Hdll = loadlibrary (szpath. c_str ());
If (hdll! = NULL)
{
Lproc = (lpsethook) getprocaddress (hdll, "sethook ");
If (lproc! = NULL)
(* Lproc) (0 );
}
}
//---------------------------------------------------------------------------
Next, generate an executable file and click the first install hook button. Then you can use the tool we wrote to view the module, you will see the dll path and file name in the module, which indicates that we have successfully injected our DLL into the notepad process space. Click the unmount button and check the module in the notepad process. The complete file name of the DLL file is not displayed. This indicates that the injection to the notepad process has been successfully revoked.
Ii. Using Remote threads for DLL Injection
This method is more complex than the previous one, and can only be used in Win2000 (XP, not the latest 2003 ). The procedure is as follows:
1) obtain the ID of the remote process;
2) allocate a piece of memory in the remote process space to store the complete dll path to be injected;
3) write the dll path to be injected to the allocated remote process space;
4) obtain the loadlibray address from kernel32.dll;
5) Call the createremotethread function to create a remote thread by taking the address of the loadlibrary function obtained from kernel32.dll as the address of the thread function and using the DLL file name to be injected as the parameter;
In step 2 and step 3, why do we need to write the DLL file name to the address space of the Remote Process for operations? This is described in Windows core programming:
The "(DLL file name to be injected) string is in the address space of the calling process. The address of the string has been assigned to the newly created remote thread, which passes it to l o a d l I B R A R Y. However, when l o a d l I B R A R Y a cancels the reference to the memory address, the d l path name string will no longer exist, remote threads may cause access violations ";
In step 4, why not call loadlibrary directly? This is described in Windows core programming:
"If a call to C r e a t e r e m o t e t h r e a d uses a pair of l o a d l I B R A R Y direct reference, this will be converted into the address of the form replacement program of l o a d l I B R A R Y a in the input section of your module. Passing the address of the physical replacement program as the starting address of the remote thread will cause the remote thread to start executing some puzzling things. The result is likely to cause access violations ."
Now let's start with our example.
1. Just like the above application hook for DLL injection, we should first create a DLL project, which can not write any code at all, because we only want to inject the DLL into the specified process to achieve the goal, but to look good, I still want to write an API function in it. The Code is as follows:
Extern "C" _ declspec (dllexport) _ stdcall void about ();
Int winapi dllentrypoint (hinstance hinst, unsigned long reason, void * lpreserved)
{
Return 1;
}
//---------------------------------------------------------------------------
Void _ declspec (dllexport) _ stdcall about ()
{
MessageBox (null, "This dll module demonstrates the DLL injection technology. N"
"Inject this module into the specified loadlibrary by calling the program"
"Process address space. "," DLL injection technology ",
Mb_iconinformation + mb_ OK );
}
Compile it to get the DLL file we use for injection. Next is the test project.
2. Compile a test project. Create an application project with BCB, put two buttons in the form, one for injection, the other for Undo, and the other for text box control, waiting for the user to enter the process ID. The Code is as follows:
//---------------------------------------------------------------------------
// DLL injection Function
Bool winapi loadlib (DWORD dwprocessid, lpwstr lpszlibname)
{
Handle hprocess = NULL,
Hthread = NULL;
Lpwstr lpszremotefile = NULL;
// Open the Remote Process
Hprocess = OpenProcess (process_create_thread
| Process_vm_operation
| Process_vm_write,
False,
Dwprocessid );
If (hprocess = NULL)
{
MessageBox (null, ("OpenProcess failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Allocate the space for storing DLL file names in Remote Processes
Lpszremotefile = (lpwstr) virtualallocex (hprocess, null,
Sizeof (wchar) * lstrlenw (lpszlibname) + 1,
Mem_commit, page_readwrite );
If (lpszremotefile = NULL)
{
MessageBox (null, ("virtualallocex failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Copy the DLL file name to the remote allocated process space
If (! Writeprocessmemory (hprocess, lpszremotefile,
(Pvoid) lpszlibname, sizeof (wchar) * lstrlenw (lpszlibname) + 1,
Null ))
{
MessageBox (null, ("writeprocessmemory failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Obtain the address of the loadlibrary function in kennel32.dll.
Pthread_start_routine pfnthreadrtn =
(Pthread_start_routine) getprocaddress (
Getmodulehandle ("kernel32.dll"), "loadlibraryw ");
If (pfnthreadrtn = NULL)
{
MessageBox (null, ("getprocaddress failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Create a remote thread
Hthread = createremotethread (hprocess,
Null,
0,
Pfnthreadrtn, // loadlibrary address
Lpszremotefile, // name of the DLL to be loaded
0,
Null );
If (hthread = NULL)
{
MessageBox (null, ("createremotethread failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Wait for the thread to return
Waitforsingleobject (hthread, infinite );
// Release the memory in the process space
Virtualfreeex (hprocess, lpszremotefile, 0, mem_release );
// Close the handle
Closehandle (hthread );
Closehandle (hprocess );
Return true;
}
// Release the injected DLL in the process space
Bool winapi freelib (DWORD dwprocessid, lptstr lpszlibname)
{
Handle hprocess = NULL,
Hthread = NULL,
Hthsnapshot = NULL;
Moduleentry32 hmod = {sizeof (hmod )};
Bool bfound;
// Retrieve all module images of a specified process
Hthsnapshot = createconlhelp32snapshot (th32cs_snapmodule,
Dwprocessid );
If (hthsnapshot = NULL)
{
MessageBox (null, ("createremotethread failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Obtain the specified module in the list of all modules
Bool bmoremod = module32first (hthsnapshot, & hmod );
If (bmoremod = false)
{
MessageBox (null, ("module32first failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Obtain the desired module cyclically
For (; bmoremod = module32next (hthsnapshot, & hmod ))
{
// Showmessage (string (hmod. szexepath) + "|" + String (lpszlibname ));
If (strcmp (hmod. szexepath, lpszlibname) = 0) |
(Strcmp (hmod. szmodule, lpszlibname) = 0 ))
Break;
}
// Open the process
Hprocess = OpenProcess (process_create_thread | process_vm_operation,
False, dwprocessid );
If (hprocess = NULL)
{
MessageBox (null, ("OpenProcess failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Obtain the address of the freelibrary function in kernel32.dll.
Pthread_start_routine pfnthreadrtn =
(Pthread_start_routine) getprocaddress (
Getmodulehandle ("kernel32.dll"), "freelibrary ");
If (pfnthreadrtn = NULL)
{
MessageBox (null, ("getprocaddress failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Create a remote thread to execute the freelibrary Function
Hthread = createremotethread (hprocess,
Null,
0,
Pfnthreadrtn,
Hmod. modbaseaddr,
0,
Null );
If (hthread = NULL)
{
MessageBox (null, ("createremotethread failed with error"
+ Inttostr (getlasterror (). c_str (), "error ",
Mb_iconinformation + mb_ OK );
Return false;
}
// Wait for the thread to return
Waitforsingleobject (hthread, infinite );
// Close the handle
Closehandle (hthread );
Closehandle (hthsnapshot );
Closehandle (hprocess );
Return true;
}
//---------------------------------------------------------------------------
Void _ fastcall tfrmmain: btloadclick (tobject * sender)
{
M_szdllfile = Application-> exename;
M_szdllfile = m_szdllfile.substring (0, m_szdllfile.length ()
-String (strrscan (m_szdllfile.c_str (), '/'). Length ());
M_szdllfile = m_szdllfile + "/dlllib. dll ";
M_dwprocessid = strtoint (edit-> text );
Loadlib (m_dwprocessid, widestring (m_szdllfile). c_bstr ());
}
//---------------------------------------------------------------------------
Void _ fastcall tfrmmain: btunloadclick (tobject * sender)
{
Freelib (m_dwprocessid, m_szdllfile.c_str ());
}
//---------------------------------------------------------------------------
Now, compile the above project into an EXE file, and then we can perform the DLL injection test. Open notepad first (of course, you can also open other processes, or directly test the loaded processes), find its process ID through the Windows Task Manager. Run our test project, enter the process ID in the text box, and click inject. In this case, we can use the first tool we wrote to view the modules contained in its process space. You will find that our dll has been successfully loaded into its process space. Click Uninstall to cancel DLL injection.
Iii. Inject using the trojan dll
The principle of this method is to write a DLL with the same interface function as the DLL called by the original process, and then replace the original DLL with our DLL. During the replacement process, we will write functions of interest to replace the original functions, while functions of the original dll will be called in the form of function forwarding for functions of no interest. There is a premise that you must know the functions in the original DLL when writing the DLL, so that the corresponding API functions cannot be found when other processes call the DLL, especially when replacing system DLL files, be careful.
This method is demonstrated below. I did this. First, write a DLL as the replaced DLL named dlllib. DLL (last renamed as _ dlllib. DLL), and then write the trojan dll named troydll. DLL (renamed as the original DLL name, that is, dlllib. DLL), and dlllib. DLL has the same API function process, but changes an API function to complete our work, because another API function needs to forward the function, to the original DLL (renamed as _ dlllib. DLL dlllib. DLL ). At this time, our test program was originally called dlllib. DLL, but because dlllib. the dll has been troydll. the DLL is replaced, so the test program actually calls troydll. DLL, and for the function for forwarding, it is through troydll. DLL calls dlllib. DLL (renamed _ dlllib. DLL. At this point, our trojan dll has actually been injected into the process space of our test program.
1. Compile the original DLL. The code for dlllib. dll (renamed as _ dlllib. dll) is as follows:
// ================================================ ============================================
// File: unitlib. cpp
// Description: This shows how to use the trojan dll for DLL injection. This is its own DLL, and another trojan dll will
// Perform Function forwarding and implement other functions.
// Author: edification (innocent)
// ================================================ ============================================
// Function declaration
Extern "C" _ declspec (dllexport) _ stdcall void about ();
Extern "C" _ declspec (dllexport) _ stdcall int add (int A, int B );
Int winapi dllentrypoint (hinstance hinst, unsigned long reason, void * lpreserved)
{
Return 1;
}
//---------------------------------------------------------------------------
Void _ declspec (dllexport) _ stdcall about ()
{
Try
{
MessageBox (null, "this is the original DLL file! "," Original DLL ",
Mb_iconinformation + mb_ OK );
} Catch (exception & E)
{
MessageBox (null, E. Message. c_str (), "dlllib", mb_ OK );
}
}
// Add two numbers (Note: Here is the sum of two numbers)
Int _ declspec (dllexport) _ stdcall add (int A, int B)
{
Return (A + B );
}
2. Compile the trojan dll. The code for troydll. dll is as follows:
// ================================================ ============================================
// File: unittroy. cpp
// Note: this is the trojan dll, which will change its DLL file to the DLL file name to be replaced.
// Prepared by: cultivate
// ================================================ ============================================
Extern "C" _ declspec (dllexport) _ stdcall void about ();
Extern "C" _ declspec (dllexport) _ stdcall int add (int A, int B );
Int multiply (int A, int B );
// Declaration of the function prototype in DLL
Typedef void (winapi * about )();
Typedef int (winapi * Add) (int A, int B );
Static string szdllname;
Int winapi dllentrypoint (hinstance hinst, unsigned long reason, void * lpreserved)
{
Szdllname = Application-> exename;
Szdllname = szdllname. substring (0, szdllname. Length ()
-String (strrscan (szdllname. c_str (), '/'). Length ());
// Name of the renamed dlllib. dll file
Szdllname = szdllname + "/_ dlllib. dll ";
Return 1;
}
//---------------------------------------------------------------------------
Void _ declspec (dllexport) _ stdcall about ()
{
// Directly forward Functions
Handle hdll = NULL;
Hdll = loadlibrary (szdllname. c_str ());
About about;
Try
{
If (hdll! = NULL)
{
About = (about) getprocaddress (hdll, "about ");
If (about! = NULL)
About ();
}
Else
MessageBox (null, "loading the original DLL error! "," Trojan dll ",
Mb_iconinformation + mb_ OK );
} Catch (exception & E)
{
MessageBox (null, E. Message. c_str (), "dlltroy", mb_ OK );
}
}
Int _ declspec (dllexport) _ stdcall add (int A, int B)
{
Int nret;
Handle hdll = NULL;
Add add;
Hdll = loadlibrary (szdllname. c_str ());
If (hdll! = NULL)
{
// For the convenience of demonstration, the forward function is forwarded here to see the value that should have been returned.
Add = (ADD) getprocaddress (hdll, "add ");
If (add! = NULL)
Nret = add (A, B );
Showmessage ("this is the call result in the original dll:" + inttostr (nret ));
}
Else
MessageBox (null, "An error occurred while loading the original DLL! "," Trojan dll ", mb_ OK );
// Change the sum of the two numbers to multiply them, and return the product of the two numbers.
Nret = multiply (A, B );
Return nret;
}
Int multiply (int A, int B)
{
Return (A * B );
}
3. Compile a test project. Add two buttons in the form to call the two API functions in dlllib. dll. The Code is as follows:
Typedef (winapi * about )();
Typedef int (winapi * Add) (int A, int B );
//---------------------------------------------------------------------------
_ Fastcall tfrmmain: tfrmmain (tcomponent * owner)
: Tform (owner)
{
}
//---------------------------------------------------------------------------
Void _ fastcall tfrmmain: formcreate (tobject * sender)
{
M_szdllname = Application-> exename;
M_szdllname = m_szdllname.substring (0, m_szdllname.length ()
-String (strrscan (m_szdllname.c_str (), '/'). Length ());
M_szdllname = m_szdllname + "/dlllib. dll ";
}
//---------------------------------------------------------------------------
// Call the about () function
Void _ fastcall tfrmmain: button1click (tobject * sender)
{
Handle hdll;
About about;
Try
{
Hdll = loadlibrary (m_szdllname.c_str ());
If (hdll! = NULL)
{
About = (about) getprocaddress (hdll, "about ");
If (about! = NULL)
About ();
}
} Catch (exception & E)
{
MessageBox (handle, E. Message. c_str (), "error", mb_ OK );
}
}
//---------------------------------------------------------------------------
// Call the add () function
Void _ fastcall tfrmmain: button2click (tobject * sender)
{
Handle hdll;
Add add;
Int nret;
Hdll = loadlibrary (m_szdllname.c_str ());
If (hdll! = NULL)
{
Add = (ADD) getprocaddress (hdll, "add ");
If (add! = NULL)
Nret = add (10, 2 );
Showmessage ("result returned from the trojan dll:" + inttostr (nret ));
}
}
4. Test. Change dlllib. DLL to _ dlllib. dll, and change troydll. DLL to dlllib. dll. Next, run our test project and click the button to call the about () function, because about () is implemented through dlllib. DLL (that is, troydll. DLL) to forward the function (to the original DLL, that is, _ dlllib. DLL), so the original DLL (that is, _ dlllib. DLL. In this case, use the tool of the Process Module to view the process space. You will find that your trojan dll (the renamed dlllib. DLL) has been successfully injected into the process space of the test program.
Click the button to call the add () function. You will see that the result of adding two numbers is the product of the two numbers, because we have already done it in the trojan dll. This is the key to using it. Gina at Windows login, do you know? Do you want someone else's login password? This method is used to replace MSGINA. dll with its own DLL, and the complicated password is also obtained ~. (Do you want to write it yourself? Check Winlogon logon management and Gina introduction)