托管代码的进程注入CLR宿主.docx
- 文档编号:11804260
- 上传时间:2023-06-02
- 格式:DOCX
- 页数:27
- 大小:446.93KB
托管代码的进程注入CLR宿主.docx
《托管代码的进程注入CLR宿主.docx》由会员分享,可在线阅读,更多相关《托管代码的进程注入CLR宿主.docx(27页珍藏版)》请在冰点文库上搜索。
托管代码的进程注入CLR宿主
托管代码的进程注入&CLR宿主
在前面关于CLR寄宿的几篇博客(CLR寄宿(上)MSCOREE.DLL,CLR寄宿(中) 托管exe文件的加载和执行,CLR寄宿(下) 托管宿主)中,介绍了常用的宿主接口。
宿主接口,允许我们使用非托管代码创建CLR宿主,从而启动CLR,运行托管代码,控制垃圾回收……等一系列功能。
本篇博文要讲解的是使用CLR宿主的一个场景——进程注入。
进程注入是一种将代码注入到已有进程地址空间内,并执行的技术。
进程注入的技术有很多,本文基于LoadDLL&CreateRemoteThread技术来讲解。
一般而言,我们会将要执行的代码编译到DLL文件里,然后加载到目标进程内执行。
对于一个非托管DLL直接加载并执行就可以了,但是如果想把一个托管DLL加载到进程中并执行就要费一番周折,因为托管代码是不能直接执行的,要经过CLR的二次编译。
如何解决这个问题呢?
因为环境对进程注入的影响很大,我这里先列出我实验的环境,再具体讲解。
系统:
windows7 ,64位
.net:
4.0
开发工具:
vs2010sp1
测试程序:
均为32位程序
1.1 实现非托管代码调用托管代码
这里用老外的一张图来简单描述下我们的托管代码是如何在目标进程内执行的。
首先使用具有注入功能的程序将一个非托管的C++DLL注入到目标进程中,然后该非托管DLL启动CLR,并加载要执行的托管DLL,最后调用CLR执行托管代码。
过程看起来很简单,这里要解决的第一个问题是创建一个C++DLL,作为CLR宿主。
打开VS2010,选择c++Win32Project项目。
确定之后点下一步,应用类型选DLL,附加选项中选择空项目。
我创建的项目名称为:
ManageCodeInvoker,如下图:
然后在 HeaderFiles文件夹中添加头文件LoadClr.h,内容如下:
#pragma region Includes and Imports
#include
#include
#include
#pragma comment(lib, "mscoree.lib")
#import "mscorlib.tlb" raw_interfaces_only \
high_property_prefixes("_get","_put","_putref") \
rename("ReportEvent", "InteropServices_ReportEvent")
using namespace mscorlib;
#pragma endregion
namespace ManageCodeInvoker
{
class MyClrHost
{
public:
static __declspec(dllexport) void ExcuteManageCode(PCWSTR pszVersion,PCWSTR pszAssemblyName, PCWSTR pszClassName,PCWSTR pszMethodName,PCWSTR argument);
static __declspec(dllexport) void Test();
};
}
上面代码声明了两个函数,ExcuteManageCode和Test。
ExcuteManageCode各参数解释如下:
1) pszVersion:
.NET 运行时版本。
2) pszAssemblyName:
程序集名称。
3) pszClassName:
类名称。
4) pszMethodName:
方法名称。
5) argument:
方法参数。
Test()函数这里用来做测试,直接调用ExcuteManageCode方法。
在SourceFiles文件夹中添加dllmain.cpp和MyClrHost.cpp文件,如下图:
MyClrHost.cpp文件中内容如下:
#include "LoadClr.h"
namespace ManageCodeInvoker
{
void MyClrHost:
:
ExcuteManageCode(PCWSTR pszVersion,PCWSTR pszAssemblyPath, PCWSTR pszClassName,PCWSTR pszMethodName,PCWSTR argument)
{
HRESULT hr;
ICLRMetaHost *pMetaHost = NULL;
ICLRRuntimeInfo *pRuntimeInfo = NULL;
ICLRRuntimeHost *pClrRuntimeHost = NULL;
DWORD dwLengthRet;
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));//创建实例
if(FAILED(hr))
{
goto Cleanup;
}
hr = pMetaHost->GetRuntime(pszVersion, IID_PPV_ARGS(&pRuntimeInfo));//获取CLR信息
if (FAILED(hr))
{
goto Cleanup;
}
BOOL fLoadable;
hr = pRuntimeInfo->IsLoadable(&fLoadable);
if (FAILED(hr))
{
goto Cleanup;
}
if (!
fLoadable)
{
goto Cleanup;
}
hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, //初始化ClrRuntimeHost
IID_PPV_ARGS(&pClrRuntimeHost));
if (FAILED(hr))
{
wprintf(L"ICLRRuntimeInfo:
:
GetInterface failed w/hr 0x%08lx\n", hr);
goto Cleanup;
}
hr = pClrRuntimeHost->Start();//启动CLR
if (FAILED(hr))
{
wprintf(L"CLR failed to start w/hr 0x%08lx\n", hr);
goto Cleanup;
}
//执行代码
hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(pszAssemblyPath,
pszClassName, pszMethodName, argument,&dwLengthRet);
pClrRuntimeHost->Stop();
if (FAILED(hr))
{
goto Cleanup;
}
Cleanup:
if (pMetaHost)
{
pMetaHost->Release();
pMetaHost = NULL;
}
if (pRuntimeInfo)
{
pRuntimeInfo->Release();
pRuntimeInfo = NULL;
}
}
void MyClrHost:
:
Test()
{
ManageCodeInvoker:
:
MyClrHost:
:
ExcuteManageCode(L"v4.0.30319",L"E:
\\Message.dll",L"Message.Message",L"Show",L"HelloWord");
}
}
上面的代码是本小节的核心代码,大致分为三个部分:
1)初始化CLRRUNTIMEHOST
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));一句,创建ICLRMetaHost 实例,这里字段为pMetaHost。
hr = pMetaHost->GetRuntime(pszVersion, IID_PPV_ARGS(&pRuntimeInfo)),创建ICLRRuntimeInfo实例,这里字段为pRuntimeInfo。
hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, //初始化ClrRuntimeHost
IID_PPV_ARGS(&pClrRuntimeHost));
这一句初始化ClrRuntimeHost实例,至此,启动CLR之前的准备工作结束。
下一步为启动CLR。
2)启动CLR
hr=pClrRuntimeHost->Start();//启动CLR
调用ClrRuntimeHost的Start()方法,启动CLR。
3)执行托管代码
执行托管代码的方式很多,大家可参考MSDN(
hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(pszAssemblyPath,
pszClassName, pszMethodName, argument,&dwLengthRet);
pClrRuntimeHost->Stop();
该函数各参数说明如下图:
注意:
ExecuteInDefaultAppDomain方法所调用的方法必须具有下列签名:
staticintpwzMethodName(StringpwzArgument)
其中pwzMethodName表示被调用的方法的名称,pwzArgument表示作为参数传递给该方法的字符串值。
如果 HRESULT 值设置为 S_OK,则将pReturnValue设置为被调用的方法返回的整数值。
否则,不设置pReturnValue。
从CLR的启动到托管代码的执行,都做了介绍,内容不是很多,还有什么疑惑,可留言讨论。
Test()方法内容如下:
void MyClrHost:
:
Test()
{
MyClrHost:
:
ExcuteManageCode(L"v4.0.30319",L"E:
\\Message.dll",L"Message.Message",L"Show",L"HelloWord");
}
在Test()方法中,我用本机的.NET版本和用来测试托管代码Message.dll来调用ExcuteManageCode方法。
修改dllmain.cpp的内容如下:
#include
#include "LoadClr.h"
bool APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
ManageCodeInvoker:
:
MyClrHost:
:
Test();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
在DllMain函数中,调用Test方法,这样当DLL被加载的时候,就会执行Test方法-> ExcuteManageCode方法->执行托管代码 Message.Show(message).
这里大家还没看到要执行的托管代码Message.dll的实际内容,下面我们共同来实现它。
创建一个名为Message的DLL项目,目标平台为x86,添加MessageClass,内容如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Message
{
public class Message
{
public static int Show(string message)
{
MessageBox.Show(message);
return 100;
}
}
}
为方便起见,编译win32DLL项目ManageCodeInvoker和.NET x86 项目Message,将生成的DLL放到一个测试目录中(我放到本地磁盘E:
下)。
第一问题,非托管代码调用托管DLL的问题解决了,只需要将DLL 文件ManageCodeInvoker.DLL注入到目标进程中就可以了。
1.2 进程注入
在讨论LoadDLL&CreateRemoteThread进程注入的原理之前,先准备目标进程,创建一个C# 控制台项目,名为TargetForInject,内容如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TargetForInject
{
class Program
{
static void Main(string[] args)
{
while (true)
{
}
}
}
}
TargetForInject.exe 启动后会处于等待状态。
使用LoadDLL&CreateRemoteThread技术进行进程注入的步骤如下(调用的函数为Windows API):
1) 调用OpenProcess函数打开目标进程,获取目标进程的句柄。
2) 通过GetProcAddress方法获取目标进程中加载的kernel32.dll的LoadLibraryA方法的地址。
3) 调用VirtualAllocEx函数,在目标进程内开辟空间用来存储要注入的DLL的实际路径。
4) 调用WriteProcessMemory函数,将要注入的DLL的路径写入开辟的内存中。
5) 调用Create
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 托管 代码 进程 注入 CLR 宿主