1

So I have this very basic cs file which is a .dll file.

And I am using Process Hacker to inject in manually to my NotePad process.. At this point it should execute it and run the MessageBox correct? (Correct me if im wrong on that one)

At first I thought it was something wrong with my injector but it seems to be the dll. (Feel free to check through the Injector down below) (Its my first ever attempt on creating a dll file)

Do I need to make the Dll hook somehow and or is it something really simple im missing?

The DLL.

using System;
using System.Windows.Forms;


namespace SomeName
{
    public class Class1
    {
        public static void Main()
        {
            MessageBox.Show("Lets try this");
        }
    }

}

The Injector

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FormDLLInjection
{
    public partial class Form1 : Form
    {


        public Form1()
        {
            InitializeComponent();
        }

        [DllImport("kernel32")]
        public static extern IntPtr CreateRemoteThread(
  IntPtr hProcess,
  IntPtr lpThreadAttributes,
  uint dwStackSize,
  UIntPtr lpStartAddress, // raw Pointer into remote process
  IntPtr lpParameter,
  uint dwCreationFlags,
  out IntPtr lpThreadId
);

        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(
            UInt32 dwDesiredAccess,
            Int32 bInheritHandle,
            Int32 dwProcessId
            );

        [DllImport("kernel32.dll")]
        public static extern Int32 CloseHandle(
        IntPtr hObject
        );

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        static extern bool VirtualFreeEx(
            IntPtr hProcess,
            IntPtr lpAddress,
            UIntPtr dwSize,
            uint dwFreeType
            );

        [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
        public static extern UIntPtr GetProcAddress(
            IntPtr hModule,
            string procName
            );

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        static extern IntPtr VirtualAllocEx(
            IntPtr hProcess,
            IntPtr lpAddress,
            uint dwSize,
            uint flAllocationType,
            uint flProtect
            );

        [DllImport("kernel32.dll")]
        static extern bool WriteProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            string lpBuffer,
            UIntPtr nSize,
            out IntPtr lpNumberOfBytesWritten
        );

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(
            string lpModuleName
            );

        [DllImport("kernel32", SetLastError = true, ExactSpelling = true)]
        internal static extern Int32 WaitForSingleObject(
            IntPtr handle,
            Int32 milliseconds
            );

        public Int32 GetProcessId(String proc)
        {
            Process[] ProcList;
            ProcList = Process.GetProcessesByName(proc);
            return ProcList[0].Id;
        }

        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");

            if (Injector == null)
            {
                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);
            // Make sure thread handle is valid
            if (hThread == null)
            {
                //incorrect thread handle ... return failed
                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 != null)
                {
                    //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 != null)
            {
                //Close thread in target process
                CloseHandle(hThread);
            }
            // return succeeded
            return;
        }

        private void injectBtn_Click(object sender, EventArgs e)
        {
            String strDLLName = @"DllPath"; // here you put the dll you want, only the path.
            String strProcessName = "notepad"; //here you will put the process name without ".exe"

            Int32 ProcID = GetProcessId(strProcessName);
            if (ProcID >= 0)
            {
                IntPtr hProcess = (IntPtr)OpenProcess(0x1F0FFF, 1, ProcID);
                if (hProcess == null)
                {
                    MessageBox.Show("OpenProcess() Failed!");
                    return;
                }
                else
                    InjectDLL(hProcess, strDLLName);
            }
        }
    }
}
  • 1
    Hmmm...can you inject a .NET assembly into a process which isn't loading the CLR in the first place? –  Oct 25 '16 at 15:11
  • I'm pretty sure yes, saw some threads online and some videos and that worked perfectly, its just that I do not have the same dll as they do, most of them are C++. – Jack G. Pax Oct 25 '16 at 15:14
  • 1
    It's been a while since I worked on this aspect, but pretty sure it is DllMain() that runs when a dll loads, not Main(). Main() would be the entry-point for applictions. Not sure if .Net wraps this differently – cdkMoose Oct 25 '16 at 16:16
  • I will try this out. – Jack G. Pax Oct 25 '16 at 16:31
  • @cdkMoose It's injected but doesnt print out the messagebox. – Jack G. Pax Oct 25 '16 at 16:33

1 Answers1

1

Why isnt my class file executing when launching it in memory?

Sadly, you can't just inject .NET assemblies into a native process that hasn't loaded the CLR in the first place. .NET won't magically do that when you attempt to load a managed DLL from a native process. The only exception to the latter is if your managed code is being exposed as COM objects.

Now your code might actually be causing Notepad to attempt to load your .dll, but due to the absence of DllMain (Windows is expecting it to be a native DLL at this point) will fail.

As a follow-up to cdkMoose's, comment, even if you called it DllMain, by default Main or DllMain are not present in the managed assemblies EXPORTS table because there isn't one. There are additional steps for manually exposing a managed method to appear as an EXPORT entry that native processes will recognise.

Is it all moot?

Let's assume that NotePad had prepared a CLR environment prior in the exact same way that SQL Server does. It would look something like this:

e.g.

HRESULT hr;
ICLRMetaHost *pMetaHost = NULL;
ICLRRuntimeInfo *pRuntimeInfo = NULL;
ICLRRuntimeHost *pClrRuntimeHost = NULL;

// build runtime
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));
hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, 
    IID_PPV_ARGS(&pClrRuntimeHost));

// start runtime
hr = pClrRuntimeHost->Start();

Then in that case NotePad or SQL would not use LoadLibraryA for your assembly but rather:

eg.

// execute managed assembly
DWORD pReturnValue;
hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(
    L"T:\\FrameworkInjection\\_build\\debug\\anycpu\\InjectExample.exe", 
    L"InjectExample.Program", 
    L"EntryPoint", 
    L"hello .net runtime", 
    &pReturnValue);

...assuming your .NET assembly is exposing a static int EntryPoint(String pwzArgument).

Conclusion

So the concern over:

  • whether it should be called Main or DllMain
  • building and exposing an EXPORT entry in managed code

...we need not be concerned with because:

  1. The native process must be preparing a CLR environment first
  2. A native process hosting the CLR won't care what you call your static method
  3. CLR does not require an EXPORTS table
  4. Native code uses the native CLR APIs to load and run an assembly (not a direct call to LoadLibrary)

The native process must load the CLR first before you can inject your code.

Community
  • 1
  • 1