none
Calling function in injected process dll RRS feed

  • Question

  • I want to call test function in InjectDll.dll which is already injected to the process.

    but It's said "The program is stopped working".

    and I'm wonder how to get the return value of test function

    Here is Inject function:

    public void InjectDLL(IntPtr hProcess, String strDLLName)
            {
                IntPtr bytesout;
    
                // Length of string containing the DLL file name +1 byte padding
                Int32 LenWrite = strDLLName.Length + 1;
                // Allocate memory within the virtual address space of the target process
                IntPtr AllocMem = (IntPtr)VirtualAllocEx(hProcess, (IntPtr)null, (uint)LenWrite, 0x1000, 0x40); //allocation pour WriteProcessMemory
    
                // Write DLL file name to allocated memory in target process
                WriteProcessMemory(hProcess, AllocMem, strDLLName, (UIntPtr)LenWrite, out bytesout);
                // Function pointer "Injector"
                UIntPtr Injector = (UIntPtr)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
                //UIntPtr Injector = (UIntPtr)GetProcAddress(GetModuleHandle(@"InjectDll.dll"), "test");
                if (Injector == UIntPtr.Zero)
                {
                    MessageBox.Show(" Injector Error! \n ");
                    // return failed
                    return;
                }
    
                // Create thread in target process, and store handle in hThread
                //IntPtr hThread = (IntPtr)CreateRemoteThread(hProcess, (IntPtr)null, 0, Injector, AllocMem, 0, out bytesout);
                IntPtr hThread = (IntPtr)CreateRemoteThread(hProcess, (IntPtr)null, 0, GetProcAddress(GetModuleHandle(@"InjectDll.dll"), "test"), AllocMem, 0, out bytesout);
                
                Console.WriteLine("out"+bytesout);
                
                // Make sure thread handle is valid
                if (hThread == IntPtr.Zero)
                {
                    MessageBox.Show(" hThread 1 Error! \n ");
                    return;
                }
                // Time-out is 10 seconds...
                int Result = WaitForSingleObject(hThread, 10 * 1000);
                // Check whether thread timed out...
                if (Result == 0x00000080L || Result == 0x00000102L || Result == 0xFFFFFFFF)
                {
                    /* Thread timed out... */
                    MessageBox.Show(" hThread 2 Error! \n ");
                    // Make sure thread handle is valid before closing... prevents crashes.
                    if (hThread != IntPtr.Zero)
                    {
                        //Close thread in target process
                        CloseHandle(hThread);
                    }
                    return;
                }
                // Sleep thread for 1 second
                //Thread.Sleep(1000);
                // Clear up allocated space ( Allocmem )
                VirtualFreeEx(hProcess, AllocMem, (UIntPtr)0, 0x8000);
                // Make sure thread handle is valid before closing... prevents crashes.
                if (hThread != IntPtr.Zero)
                {
                    //Close thread in target process
                    CloseHandle(hThread);
                }
                // return succeeded
                
    
                return;
            }

    Here is InjectDll.cpp:

    // dllmain.cpp : Defines the entry point for the DLL application.
    #include "stdafx.h"
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
    					 )
    {
    	switch (ul_reason_for_call)
    	{
    	case DLL_PROCESS_ATTACH:
    		MessageBox(NULL, (LPCWSTR)L"Hello World!", (LPCWSTR)L"Dll says:", MB_OK);
    		break;
    	case DLL_THREAD_ATTACH:
    	case DLL_THREAD_DETACH:
    	case DLL_PROCESS_DETACH:
    		break;
    	}
    	return TRUE;
    }
    
    int test()
    {
    	return 5;
    }

    • Edited by doliolarzz Wednesday, November 1, 2017 9:11 AM
    Wednesday, November 1, 2017 9:09 AM

Answers

  • I have put together a demo for you.  The demo was written in C++ using VS2015 and consists of a small dialog application and a dll.  They should reside in the same folder.  There are buttons to start notepad (used for convenience), inject the dll into the notepad process, start a remote thread to call a function from the dll in the notepad process and finally, unload the dll from the notepad process.  While there is some error handling since it is a demo the error handling is not extensive and does not check for things like multiple execution, or trying to do the dll injection more than once per process.

    One change that I made from our prior discussions was that for the x64 build I use the Toolhelp library to find the injected dll's instance handle in the notepad process.  This is because GetExitCodeThread stores the result of LoadLibrary's remote execution in a DWORD (a 32 bit value) and so in the x64  build the 64 bit instance handle would not be properly obtained.

    The demo should illustrate the concepts we have already discussed and how to apply them.

    I tested the demo on Win7 and Win 8.1 for x86 and on Win Server 2008 R2 for x64.  I will leave the porting to C# from C++ to you. :)

    You can download the demo from InjectTest.zip

    • Marked as answer by doliolarzz Friday, November 3, 2017 4:41 AM
    Thursday, November 2, 2017 1:02 PM

All replies

  • You would have to provide CreateRemoteThread the address of the test function as well as handling parameters within the target process address space. 


    • Edited by RLWA32 Wednesday, November 1, 2017 11:12 AM
    Wednesday, November 1, 2017 11:10 AM
  • IntPtr hThread = (IntPtr)CreateRemoteThread(hProcess,
    (IntPtr)null, 0, GetProcAddress(GetModuleHandle(@"InjectDll.dll"), "test"), 
    AllocMem, 0, out bytesout);
                

    Do I call it right?

    hThread seem to be a IntPtr.Zero


    • Edited by doliolarzz Wednesday, November 1, 2017 11:28 AM
    Wednesday, November 1, 2017 11:26 AM
  • IntPtr hThread = (IntPtr)CreateRemoteThread(hProcess,
    (IntPtr)null, 0, GetProcAddress(GetModuleHandle(@"InjectDll.dll"), "test"), 
    AllocMem, 0, out bytesout);
                

    Do I call it right?

    hThread seem to be a IntPtr.Zero


    No.  GetProcAddress is returnining the address within the calling process, not the target process.  It is a peculiarity of Windows that it loads Kernel32.dll at the same virtual address in the address spaces of different processes.  That is why the address of LoadLibraryA can be retrieved using this method.

    You have a couple of things to consider.  First, think about how you obtained the address of LoadLibraryA within the address space of the target process.  Hypothetically, you could do the same thing for GetProcAddress and retrieve its address within the target process' address space.  However, you would still have the problem of passing parameters to it.  LoadLibraryA takes one parameter, the address of the name of the dll to load.  This can conveniently be passed using CreateRemoteThread's parameters.  However, GetProcAddress takes two parameters, not one.  So even if you obtained the correct address for GetProcAddress in the target process you could not pass those two parameters using CreateRemoteThread.

    There is another way.  Regardless of the virtual address where Inject.dll is loaded, the test function will always be located at the same offset from the load address of the module.  You should be able to use the load address of the dll in the target process address space + the offset to calculate the address of the test function in the target process address space.  You can then use this address with CreateRemoteThread.  For starters, I suggest you try this with a test function that takes no parameters.

    The load address of the dll in the address space of the target process is returned by the remote thread that executed LoadLibraryA.  This can be retrieved using GetExitCodeThread.



    • Edited by RLWA32 Wednesday, November 1, 2017 12:28 PM added detail
    Wednesday, November 1, 2017 12:02 PM
  • Only functions that reside in Kernel32.dll can be safely called from within DllMain.  Calling MessageBox from within DllMain is an unsafe practice.  See Dynamic-Link Library Best Practices.  If you want to see some output when DllMain is called you can use OutputDebugString which will display your output in the Visual Studio IDE Output pane if the process is being debugged.  You can still see the output using DebugView outside of the Visual Studio debugger.

    Wednesday, November 1, 2017 12:22 PM
  • I've tried this, injected process was unexpectedly shutdown (already remove msgbox from dll).

    Another, How can I get the return of my test function(which is 5).

    Thank you for replying :)

    public void InjectDLL(IntPtr hProcess, String strDLLName)
            {
                IntPtr bytesout;
    
                IntPtr hLoader = LoadLibrary(strDLLName);
                UIntPtr hLoaderProc = GetProcAddress(hLoader, "test");
                uint offset = (uint)hLoaderProc - (uint)hLoader;
                FreeLibrary(hLoader);
                Int32 LenWrite = strDLLName.Length + 1;
    
                IntPtr AllocMem = (IntPtr)VirtualAllocEx(hProcess, IntPtr.Zero, (uint)LenWrite, 0x1000, 0x40);
                WriteProcessMemory(hProcess, AllocMem, strDLLName, (UIntPtr)LenWrite, out bytesout);
                UIntPtr Injector = (UIntPtr)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
                IntPtr hThread = (IntPtr)CreateRemoteThread(hProcess, IntPtr.Zero, 0, Injector, AllocMem, 0, out bytesout);
                int Result = WaitForSingleObject(hThread, 5000);
    
    
                IntPtr hModule;
                GetExitCodeThread(hThread, out hModule);
                CloseHandle(hThread);
    
                IntPtr AllocMem2 = VirtualAllocEx(hProcess, IntPtr.Zero, (uint)LenWrite, 0x1000, 0x04);
                IntPtr hThread2 = (IntPtr)CreateRemoteThread(hProcess, IntPtr.Zero, 0, (UIntPtr)((uint)hModule + offset), IntPtr.Zero, 0, out bytesout);
                WaitForSingleObject(hThread, 5000);
                CloseHandle(hThread2);
                return;
            }






    • Edited by doliolarzz Wednesday, November 1, 2017 5:46 PM
    Wednesday, November 1, 2017 5:29 PM
  • I suggest you revise the code to check the return values of all functions that you are using to make sure that they actually succeeded.  For functions that set the last error code you should also call GetLastError() for additional information in the event an error occurs.  Double check the parameters that your are using to ensure that they are correct.  Make sure that you have obtained a valid process handle with all of the necessary privileges.  I have not checked your code.  You can also place a call to DebugBreak() within your injected dll so that you have an opportunity to attach the debugger to the target process.
    Wednesday, November 1, 2017 5:44 PM
  • I have no idea what I did wrong.

    Trying to debug program, It's said "Unhandled exception at 0x0041122B in RDWorksV8.exe: 0xC0000005: Access violation writing location 0x55EE2048."

    I'm sure that my target process base address space and offset are correct.

    Is it look normal? https://imgur.com/a/YfDLv

    public MainWindow()
            {
                InitializeComponent();
                Thread.Sleep(1000);
                String DLLName = "c:/InjectDll.dll";
                String strProcessName = "RDWorksV8";
                System.Diagnostics.Process.Start("c:/RDWorksV8/RDWorksV8.exe");//c:/RDWorksV8/RDWorksV8.exe
                Int32 ProcID = Process.GetProcessesByName(strProcessName)[0].Id;
                if (ProcID >= 0)
                {
                    IntPtr hProcess = (IntPtr)OpenProcess(0x1F0FFF, 1, ProcID);
                    if (hProcess == null)
                    {
                        MessageBox.Show("OpenProcess() Failed!");
                        return;
                    }
                    else
                    {
                        UIntPtr fnLoadLibrary = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
                        Inject(hProcess, fnLoadLibrary, DLLName);
                        IntPtr hModule = GetRemoteModuleHandle((uint)ProcID, ref DLLName);
                        uint offset = getOffset(DLLName, "test");
                        MessageBox.Show(hModule.ToString());
                        MessageBox.Show(offset.ToString());
                        UIntPtr fnImplant = (UIntPtr)((uint)hModule + offset);
                        IntPtr result = Inject(hProcess, fnImplant, "test");
                        MessageBox.Show(result.ToString());
                    }
    
                }
            }
            IntPtr Inject(IntPtr hProcess, UIntPtr Injector, String DLLName)
            {
                IntPtr BytesOut;
                IntPtr baseAddress = VirtualAllocEx(hProcess, IntPtr.Zero, (uint)DLLName.Length + 1, 0x1000, 0x40);
                if (!WriteProcessMemory(hProcess, baseAddress, DLLName, (UIntPtr)DLLName.Length + 1, out BytesOut))
                    return IntPtr.Zero;
                IntPtr hThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, Injector, baseAddress, 0, out BytesOut);
                WaitForSingleObject(hThread, 10000);
                VirtualFreeEx(hProcess, baseAddress, (UIntPtr)0, 0x8000);
    
                IntPtr ExitCode = IntPtr.Zero;
                GetExitCodeThread(hThread, out ExitCode);
                CloseHandle(hThread);
                return ExitCode;
            }
            uint getOffset(String DLLName, String functionName)
            {
                IntPtr hLoader = LoadLibrary(DLLName);
                UIntPtr hLoaderProc = GetProcAddress(hLoader, functionName);
                uint Offset = (uint)hLoaderProc - (uint)hLoader;
                FreeLibrary(hLoader);
                return Offset;
            }
            public static IntPtr GetRemoteModuleHandle(uint pId, ref string module)
            {
                var modEntry = new MODULEENTRY32();
                var hSnapshot = CreateToolhelp32Snapshot(SnapshotFlags.Module, pId);
                modEntry.dwSize = (uint)Marshal.SizeOf(modEntry);
                if (!Module32First(hSnapshot, ref modEntry))
                {
                    CloseHandle(hSnapshot);
                    return IntPtr.Zero;
                }
                while (string.Equals(modEntry.szModule, module, StringComparison.InvariantCultureIgnoreCase) && Module32Next(hSnapshot, ref modEntry)) ;
                CloseHandle(hSnapshot);
                if (!string.Equals(modEntry.szModule, module, StringComparison.InvariantCultureIgnoreCase))
                    return modEntry.modBaseAddr;
                return IntPtr.Zero;
            }







    • Edited by doliolarzz Thursday, November 2, 2017 8:28 AM
    Wednesday, November 1, 2017 6:45 PM
  • I have put together a demo for you.  The demo was written in C++ using VS2015 and consists of a small dialog application and a dll.  They should reside in the same folder.  There are buttons to start notepad (used for convenience), inject the dll into the notepad process, start a remote thread to call a function from the dll in the notepad process and finally, unload the dll from the notepad process.  While there is some error handling since it is a demo the error handling is not extensive and does not check for things like multiple execution, or trying to do the dll injection more than once per process.

    One change that I made from our prior discussions was that for the x64 build I use the Toolhelp library to find the injected dll's instance handle in the notepad process.  This is because GetExitCodeThread stores the result of LoadLibrary's remote execution in a DWORD (a 32 bit value) and so in the x64  build the 64 bit instance handle would not be properly obtained.

    The demo should illustrate the concepts we have already discussed and how to apply them.

    I tested the demo on Win7 and Win 8.1 for x86 and on Win Server 2008 R2 for x64.  I will leave the porting to C# from C++ to you. :)

    You can download the demo from InjectTest.zip

    • Marked as answer by doliolarzz Friday, November 3, 2017 4:41 AM
    Thursday, November 2, 2017 1:02 PM
  • I got it!, that's very hard for who don't know how windows works.

    Thank you for your help :) RLWA32

    Friday, November 3, 2017 4:43 AM
  • You're welcome.  One of the dangers of dll injection and remote threads is that the target application has no idea what is happening behind its back.  It is not aware of memory allocation in its address space, the lthe injected dll, or any action that the dll might take. 

    To illustrate this point I suggest you make a change to the demo.  Change the SayHello() function in the dll so that instead of just displaying a message box it writes a line of text into notepad's edit control.  The text will appear in notepad's window, but notepad does not know that it is there.  See what happens if you then try to type another line into notepad's window using the keyboard.

    For example, insert the following after the call to MessageBox -

    	if (hNotepad)
    	{
    		HWND hEdit = GetWindow(hNotepad, GW_CHILD);
    		if (hEdit)
    			SetWindowText(hEdit, _T("Text Inserted by Injected DLL"));
    	}
    

    Notice that if you close Notepad right after injecting the text it does not ask you to save your changes!  Also notice that if you begin typing the insertion takes place at the beginning of the line, not after the injected text. 

    • Edited by RLWA32 Friday, November 3, 2017 1:09 PM added example
    Friday, November 3, 2017 8:52 AM
  • Now that you have seen that Notepad was unaware of the injected text when SetWindowText was used I suggest you make another change to SayHello to see how a different result can be obtained.  Replace the call to SetWindowText with a call to SendMessage and send Notepad's edit control an EM_REPLACESEL message with the text that you want to insert in the control.  Notice how now Notepad recognizes the injected text.
    Saturday, November 4, 2017 7:52 PM
  • can you share your InjectTest.zip ?  , this is not available here.

    HASMUKH M. GINOYA Sr.Software Engineer Vadodara, Gujarat, INDIA ginoyaha@gmail.com

    Thursday, December 12, 2019 6:30 AM