.net 4.0 代码注入 (C# & C++)

首先写一个注入用的 DLL:

// stdafx.h
#include <objbase.h>
#include <MetaHost.h>
#include <cassert>
// ProxyDll.cpp

#define ASSEMBLY_NAME   L"Launcher.exe"
#define LOADER_TYPE     L"moe.jixun.Inject"
#define LOADER_FUNCTION L"Init"

__declspec(dllexport) void Bootstrap() {
	CoInitializeEx(0, COINIT_MULTITHREADED);

	ICLRMetaHost *pMetaHost = nullptr;
	HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
	ICLRRuntimeInfo *pRuntimeInfo = nullptr;
	pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo);

	ICLRRuntimeHost *pClrRuntimeHost = nullptr;
	pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pClrRuntimeHost);

	pClrRuntimeHost->Start();

	DWORD dReturnValue;
	hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(ASSEMBLY_NAME, LOADER_TYPE, LOADER_FUNCTION, L"Test", &dReturnValue);
	assert(hr == S_OK);
}

因为 .net 的 exe 可以当做库来用,可以直接把代码写到我们的 exe 然后注入进去执行。

当然,你可能需要修改上述代码使其寻找 dll 所在的目录。

然后便是编写启动器,负责寻找注入程序以及注入后执行的代码。

// 加入目标函数的引用,可以快速定位
// 或者

namespace moe.jixun
{
    public class Inject
    {
        static HammerCheatInit () {
            // 此处初始化
        }

        public static int Init(String pwzArgument)
        {
            return 1;
        }

        // 测试用函数
        private int Empty()
        {
            return 1;
        }

        // 获取函数的机器码地址
        private static void Test()
        {
            Type typeCheatInit = typeof(HammerCheatInit);
            MethodInfo empty = typeCheatInit.GetMethod("Empty", BindingFlags.NonPublic | BindingFlags.Instance);

            RuntimeHelpers.PrepareMethod(empty.MethodHandle);
            
            var addr = empty.MethodHandle.GetFunctionPointer().ToInt32();

            MessageBox.Show(addr.ToString("x"));
        }
    }
}

如果目标是调试构建版,那么读出来的是一个跳转,需要再读取相对地址。

C# 注入 DLL 到其它进程的代码网上很多,我就不提供了..

以上。


参考

  1. StackOverflow: C++ 对 .net 4.0 进行操作
  2. .net 代码注入的基本概念
  3. 更多的 StackOverflow 帖子
Post your comments here