⭐ If you would like to buy me a coffee, well thank you very much that is mega kind! : https://www.buymeacoffee.com/honeyvig Hire a web Developer and Designer to upgrade and boost your online presence with cutting edge Technologies
Showing posts with label dll. Show all posts
Showing posts with label dll. Show all posts

Saturday, April 23, 2022

C# Inject a Dll into a Process (w/ CreateRemoteThread)

 

Since I’ve been asked if this is possible - well…you can do DLL Injection using C# but the injected DLL must be written in a language that doesn’t depend on a CLR (C/C++ would be a good option here, but it’s ok to write the injector in C#).

almost all AV programs detect this as a possible malware simply because this behaviour is specific to some viruses/keygens/etc. - and they prefer to be rather paranoid than ineffective. Even if this technique has a bad reputation it has legit uses like hotpatching & logging - and this is what I’m going to write about.

Fun fact: you can achieve similar results (e.g., memory access) by hooking and patching a function in the original binary (not in C# though).

Some theory

DLL Injection is a technique used to make a running process (executable) load a DLL without requiring a restart (name makes it kind of obvious :p).

It is usually done using 2 programs:

  • an Injector (written in any language)
  • a DLL (compiled to a native language)

The purpose of the injector is to…inject the DLL into the target process. In order to do so:

  1. get the handle of the process (OpenProcess())
  2. obtain the address of this method: LoadLibraryA() (from kernel32.dll) by using GetProcAddress(); we’re trying to make the target process call it in order to load our library; DON’T hardcode this address - since Windows Vista came out, it will be different every time.
  3. use VirtualAllocEx to allocate a few bytes of memory on the target process
  4. write there the name/path of our library (WriteProcessMemory())
  5. with CreateRemoteThread() spawn the thread which will run LoadLibraryA() with the pointer to the allocated address as an argument (that pointer actually indicates the name of the DLL).

One more thing: when the DLL is loaded, its DllMain() method (entry point) will be called with DLL_PROCESS_ATTACH as reason (fdwReason).

Writing the DLL

For this tutorial I used a dummy DLL which displays a MessageBox once it’s successfully loaded.

Note: always return true at the end - otherwise some processes will crash when injecting.

I’m using this DLL:


#include<Windows.h>
extern "C" __declspec(dllexport) bool WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
        {
            MessageBox(NULL, "Hello World!", "Dll says:", MB_OK);
	    break;
        }

        case DLL_PROCESS_DETACH:
            break;

        case DLL_THREAD_ATTACH:
            break;

        case DLL_THREAD_DETACH:
            break;
    }
    return true;
}

Writing the Injector

Ok, the fancy part. I kind of explained how all this works in the first part of the tutorial so just remember: get the handle, allocate some memory on the process, write there the name of the DLL and finally, create a thread that will call LoadLibraryA and load your DLL.

Also, check the comments in code and refer to the “theory” part of this article whenever you feel the need to.

Here be sourcecode!


using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

public class BasicInject
{
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

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

    [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    static extern IntPtr 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", SetLastError = true)]
    static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);

    [DllImport("kernel32.dll")]
    static extern IntPtr CreateRemoteThread(IntPtr hProcess,
        IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

    // privileges
    const int PROCESS_CREATE_THREAD = 0x0002;
    const int PROCESS_QUERY_INFORMATION = 0x0400;
    const int PROCESS_VM_OPERATION = 0x0008;
    const int PROCESS_VM_WRITE = 0x0020;
    const int PROCESS_VM_READ = 0x0010;

    // used for memory allocation
    const uint MEM_COMMIT = 0x00001000;
    const uint MEM_RESERVE = 0x00002000;
    const uint PAGE_READWRITE = 4;

    public static int Main()
    {
        // the target process - I'm using a dummy process for this
        // if you don't have one, open Task Manager and choose wisely
        Process targetProcess = Process.GetProcessesByName("testApp")[0];

        // geting the handle of the process - with required privileges
        IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, targetProcess.Id);

        // searching for the address of LoadLibraryA and storing it in a pointer
        IntPtr loadLibraryAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

        // name of the dll we want to inject
        string dllName = "test.dll";

        // alocating some memory on the target process - enough to store the name of the dll
        // and storing its address in a pointer
        IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

        // writing the name of the dll there
        UIntPtr bytesWritten;
        WriteProcessMemory(procHandle, allocMemAddress, Encoding.Default.GetBytes(dllName), (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten);

        // creating a thread that will call LoadLibraryA with allocMemAddress as argument
        CreateRemoteThread(procHandle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, IntPtr.Zero);

        return 0;
    }
}

Call a C# Method from C/C++ (native process)

 

This article presents a method of loading a managed (C#) dll in a native (C++) process by using the Common Language Runtime (CLR). Basically, it refers to calling a C# method from C/C++ and enables calling managed code from native applications. This method was tested on the .Net Framework 4.0.

The trick consists in creating and hosting a CLR instance in the C++ process and then using it to load a managed dll.

Hosting the CLR in a Native Process

The following dependencies will be required


#include <metahost.h>
#pragma comment(lib, "mscoree.lib")

CLRCreateInstance() needs to be called in order to gain access to the ICLRMetaHost interface. This interface contains various methods that will provide general information about the current .NET Framework runtime.

From there, it is required to focus on one version of the framework (I’m working with v4.0.30319) - calling ICLRMetaHost::GetRuntime() will return a pointer to another interface (ICLRRuntimeInfo), which contains… more methods. (this is the upgraded version of ICorRuntimeHost).

The next step is calling ICLRRuntimeInfo::GetInterface() which returns an instance of the ICLRRuntimeHost. The ICLRRuntimeHost needs to be started (ICLRRuntimeHost::Start()) in the current native process and can be used to execute managed code through ICLRRuntimeHost::ExecuteInDefaultAppDomain(). The aforementioned method has the following prototype:


HRESULT ExecuteInDefaultAppDomain (
    [in] LPCWSTR pwzAssemblyPath,  // absolute path to the managed dll (not relative!)
    [in] LPCWSTR pwzTypeName,  // name of the class for example: dllNamespace.dllClass
    [in] LPCWSTR pwzMethodName,  // name of the method 
    [in] LPCWSTR pwzArgument,   // argument(s)
    [out] DWORD *pReturnValue   // this is what the method returns
);

It is advised to always check if each call of the above methods returns a S_OK.

Example: Dummy Managed DLL

This part implements a dummy managed DLL that will be attached to the native application. In this version, I’m implementing a method which displays a MessageBox that contains a message (string) given as parameter; the returned int will also be available in the native code. This method will be called by the C process.


using System.Windows.Forms;

namespace dllNamespace
{
    public class dllClass
    {
        public static int ShowMsg(string msg)
        {
            MessageBox.Show(msg);
            return 0;
        }
    }
}

Example: Native Application

I’ve implemented a loader for the previously presented DLL.


#include <metahost.h>
#pragma comment(lib, "mscoree.lib")

int main()
{
    ICLRMetaHost* metaHost = NULL;
    ICLRRuntimeInfo* runtimeInfo = NULL;
    ICLRRuntimeHost* runtimeHost = NULL;

    if (CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost) == S_OK)
        if (metaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&runtimeInfo) == S_OK)
            if (runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost) == S_OK)
                if (runtimeHost->Start() == S_OK)
	            {		
                    DWORD pReturnValue;
                    runtimeHost->ExecuteInDefaultAppDomain(L"C:\\random.dll", L"dllNamespace.dllClass", L"ShowMsg", L"It works!!", &pReturnValue);

                    runtimeInfo->Release();
                    metaHost->Release();
                    runtimeHost->Release();
                }
    return 0;
} 

P.S.: due to some problems with my compiler, I couldn’t test this code properly - last time, it worked pretty well…hope it still does so.