How to Implement. netProgramProcess Injection
Zhou yinhui
Process injection is common. For example, you can use ide to debug programs and some spy programs. the debugger interface provided by. Net (in envdte. DLL ). however, process injection is fun for whatever purpose, so try again. process injection methods seem to be a lot (for example, you can pretend like a Trojan to make the target process mistakenly think that your assembly is legal and loaded to the target process ), this is only a combination of one or some methods.
The general principle is as follows:
- Source Process (that is, yourCodeObtain the ID or process object of the target process (that is, the process where your injection target is located ).
- The source process provides a callback function methoda (that is, the code you want to run after the target process is injected)
- Submit the complete path of the target process and the callback function methoda (its assembly, classic, and methodname) to the injector (that is, the injection class we wrote ), let injector complete the injection and let the target process execute the callback function
- Injector obtains the target process object based on the provided target process ID and obtains a thread (called the target thread) of the target process)
- Allocate a piece of memory in the target thread and save the full path of the callback function methoda as a string to the memory.
- Injector installs a hook in the target process to monitor a Windows message (messagea) and writes the Hook's callback function methodb (the content in this method will be explained later)
- Send messagea messages like the target process, and pass the base address of the allocated memory as the message parameter.
- Because we have installed hooks for messagea, the target process will call our hook function methodb and include the base address of the allocated memory in the function parameters.
- In methodb, the actual object is parsed in memory based on the memory base address in the function parameters, that is, a string that represents the complete path of our methoda. this parameter is used according to the Assembly, classname, and methodname represented in this string. net reflection, reflecting out its methodinfo object (note: the key point is that methodb is already in a thread of the target process when it is called back)
- The methodinfo object reflected by invoke. Our methoda is executed.
The following figure may help you understand the above:
If you still don't understand it, check the Code. (This requires a little c ++/CLI knowledge, but I have added comments to each sentence. It should be quite understandable, for more information about C ++/CLI, click here .)
# Include "Stdafx. H" # Include "Injector. H" # Include <Vcclr. h> Using namespace Managedinjector; // Defines a new window message that is guaranteed to be unique throughout the system. // The message value can be used when sending or posting messages. Static unsigned int Wm_gobabygo =: registerwindowmessage (L "Injector_gobabygo! " ); Static Hhook _ messagehookhandle;// Functions // spying process functions follow //----------------------------------------------------------------------------- Void Injector: launch (System: intptr windowhandle, system: Reflection: Assembly ^ assembly, system: String ^ classname, system: String ^ methodname) {system :: string ^ assemblyclassandmethod = assembly-> location + "$" + Classname + "$" + Methodname; // Convert string to local wchar_t * or char * Pin_ptr < Const wchar_t > Acmlocal = ptrtostringchars (assemblyclassandmethod );// Maps the specified executable module into the address space of the calling process. Hinstance hinstdll =: loadlibrary (lpctstr) _ T ( "Managedinjector. dll" )); If (Hinstdll) {DWORD processid = 0; // Get the process ID and thread ID DWORD threadid =: getwindowthreadprocessid (hwnd) windowhandle. topointer (), & processid ); If (Processid ){ // Get the target process object (handle) Handle hprocess =: OpenProcess (process_all_access, false, processid ); If (Hprocess ){ Int Bufflen = (assemblyclassandmethod-> Length + 1 )* Sizeof ( Wchar_t ); // Allocates physical storage in memory or in the paging file on disk for the specified reserved memory pages. // The function initializes the memory to zero. // The return value is the base address of the allocated region of pages. Void * Acmremote =: virtualallocex (hprocess, null, bufflen, mem_commit, page_readwrite ); If (Acmremote ){ // Copies the data (the assemblyclassandmethod string) // from the specified buffer in the current process // to the address range of the target process : Writeprocessmemory (hprocess, acmremote, acmlocal, bufflen, null );// Retrieves the address of messagehookproc method from the hintsdll Hookproc procaddress = (hookproc) getprocaddress (hinstdll, "Messagehookproc" ); // Install a hook procedure to the target thread (before the system sends the messages to the destination window procedure) _ Messagehookhandle =: setwindowshookex (wh_callwndproc, procaddress, hinstdll, threadid ); If (_ Messagehookhandle ){ // Send our custom message to the target window of the target process : Sendmessage (hwnd) When whandle. topointer (), wm_gobabygo, (wparam) acmremote, 0 ); // Removes the hook procedure installed in a hook chain by the setwindowshookex function. : Unhookwindowshookex (_ messagehookhandle );} // Removes a hook procedure installed in a hook chain by the setwindowshookex function. : Virtualfreeex (hprocess, acmremote, bufflen, mem_release); }:: closehandle (hprocess );}} // Decrements the reference count of the loaded DLL : Freelibrary (hinstdll );}} _ Declspec ( Dllexport ) // The procedure for hooking, this will be called back after hooked Int _ stdcall Messagehookproc ( Int Ncode, wparam, lparam ){ // Hc_action: indicate that there are argments in wparam and lparam If (Ncode = hc_action) {cwpstruct * MSG = (cwpstruct *) lparam; // When the target window has ed our custom message If (MSG! = NULL & MSG-> message = wm_gobabygo ){ // Get the argument passed by the message // actually, the argument is the base address (a pointer) // Of The assemblyclassandmethod string in the target process memory Wchar_t * Acmremote = ( Wchar_t *) MSG-> wparam; // Gcnew: creates an instance of a managed type (reference or value type) on the garbage collected heap System: String ^ acmlocal = Gcnew System: string (acmremote ); // Split the string into substring array with $. under this context: // acmsploud [0]: the Assembly's location // acmsploud [1]: classname; // acmsploud [2]: methodname // we use these infomation to reflect the method in the source assembly, and invoke it in the target process CLI :: Array <System: String ^> ^ acmsp1_= acmlocal-> split ( '$' ); // Refect the method, and invoke it System: Reflection: Assembly ^ Assembly = system: Reflection: Assembly: LoadFile (acmsp1_[ 0]); If (Assembly! = Nullptr ) {System: type ^ type = assembly-> GetType (acmsp1_[ 1]); If (Type! = Nullptr ) {System: Reflection: methodinfo ^ methodinfo = type-> getmethod (acmspfailed [2], system: Reflection: bindingflags: static | System: Reflection :: bindingflags: public ); If (Methodinfo! = Nullptr ) {Methodinfo-> invoke ( Nullptr , Nullptr );}}}}} Return Callnexthookex (_ messagehookhandle, ncode, wparam, lparam );}
Next, let's try a demo:
In the solution, injectordemo is the above source process. It will use Injector to inject the following code into the target process and execute it:
Public static voidDosomethingevie ()
{
VaRTargetwindow =Application. Current. mainwindow;
If(Targetwindow! =Null)
{
VaRLb =NewLabel{Content ="Haha, I caught you :)"};
Targetwindow. content = LB;
}
}
That is to say, the injectordemo process will change the content of the main window of the injecttargetapp process to a label like "Haha, I caught you.
Run the program:
The preceding two windows are in different processes. Click the "inject it" button to call the following code:
Managedinjector.Injector. Launch (targetprocess. main1_whandle,Typeof(Injectorwindow). Assembly,Typeof(Injectorwindow). Fullname,"Dosomethingevie");
Then:
Click here to download the demo
For reference only(The log content only records one kind of existence, not a solution to a specific problem. It is meaningless to discuss its significance. Thank you)