如何实现.net程序的进程注入
如何实现.net程序的进程注入
周银辉
进程注入比较常见,比如用IDE调试程序以及一些Spy程序,如果仅仅为了与调试器通讯,可以使用.net提供的Debugger接口(在EnvDTE.dll的EnvDTE命名空间下).但无论出于什么目的,进程注入都是比较好玩的事情,所以不妨一试 . 进程注入的方法貌似很多(比如像特洛伊一样乔装打扮让目标进程误认为你的程序集合法而加载到目标进程),这里提到的仅是其中的一种或某些方法的结合.
大致原理是这样的:
- 源进程(也就是你的代码所在的进程)获得目标进程(也就是你的注入目标所在的进程)的ID或进程对象
- 源进程提供一回调函数methodA(也就是你想要注入到目标进程后所执行的代码)
- 将目标进程和回调函数methodA的完整路径(其所在的Assembly,Classic以及MethodName)提交给Injector(也就是我们编写的负责注入的类),让Injector来完成注入和让目标进程执行回调函数
- Injector根据提供的目标进程ID取得目标进程对象,并获得目标进程的一个线程(我们称为目标线程)
- 在目标线程中分配一块内存,将回调函数methodA的完整路径作为字符串存入该内存中
- Injector在目标进程中安装一个钩子(Hook)监视某一个Windows消息(messageA),撰写钩子的回调函数methodB(该方法中的内容稍后解释)
- 像目标进程发消息messageA,并将刚才分配的内存的基地址作为消息参数传递.
- 由于我们针对messageA安装了钩子,所以目标进程会调用我们钩子函数methodB,并会把分配的内存的基地址包含在函数参数中
- methodB中, 根据函数参数中的内存基地址在内存中解析出其实际对象,也就是一个表示我们的methodA的完整路径的字符串.根据该字符串中所表示的Assembly,className, methodName利用.net反射,反射出其MethodInfo对象(注意,关键点,methodB被回调时已经是在目标进程的某个线程中了)
- Invoke反射出的MethodInfo对象, 我们的methodA得到了执行.
下面这个图可能会帮助你理解上面的话:
![]()
如果还没明白的话,那就看代码吧(这需要一点点C++/CLI知识,但我已经为每句加上了注释,应该蛮好懂的,关于C++/CLI可以点击这里了解更多.)
#include "stdafx.h"
#include "Injector.h"
#include <vcclr.h>
using namespace ManagedInjector;
//defines a new window message that is guaranteed to be unique throughout the system.
//The message value can be used when sending or posting messages.
static unsigned int WM_GOBABYGO = ::RegisterWindowMessage(L"Injector_GOBABYGO!");
static HHOOK _messageHookHandle;
//-----------------------------------------------------------------------------
//Spying Process functions follow
//-----------------------------------------------------------------------------
void Injector::Launch(System::IntPtr windowHandle, System::Reflection::Assembly^ assembly, System::String^ className, System::String^ methodName) {
System::String^ assemblyClassAndMethod = assembly->Location + "$" + className + "$" + methodName;
//convert String to local wchar_t* or char*
pin_ptr<const wchar_t> acmLocal = PtrToStringChars(assemblyClassAndMethod);
//Maps the specified executable module into the address space of the calling process.
HINSTANCE hinstDLL = ::LoadLibrary((LPCTSTR) _T("ManagedInjector.dll"));
if (hinstDLL)
{
DWORD processID = 0;
//get the process id and thread id
DWORD threadID = ::GetWindowThreadProcessId((HWND)windowHandle.ToPointer(), &processID);
if (processID)
{
//get the target process object (handle)
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (hProcess)
{
int buffLen = (assemblyClassAndMethod->Length + 1) * sizeof(wchar_t);
//Allocates physical storage in memory or in the paging file on disk for the specified reserved memory pages.
//The function initializes the memory to zero.
//The return value is the base address of the allocated region of pages.
void* acmRemote = ::VirtualAllocEx(hProcess, NULL, buffLen, MEM_COMMIT, PAGE_READWRITE);
if (acmRemote)
{
//copies the data(the assemblyClassAndMethod string)
//from the specified buffer in the current process
//to the address range of the target process
::WriteProcessMemory(hProcess, acmRemote, acmLocal, buffLen, NULL);
//Retrieves the address of MessageHookProc method from the hintsDLL
HOOKPROC procAddress = (HOOKPROC)GetProcAddress(hinstDLL, "MessageHookProc");
//install a hook procedure to the target thread(before the system sends the messages to the destination window procedure)
_messageHookHandle = ::SetWindowsHookEx(WH_CALLWNDPROC, procAddress, hinstDLL, threadID);
if (_messageHookHandle)
{
//send our custom message to the target window of the target process
::SendMessage((HWND)windowHandle.ToPointer(), WM_GOBABYGO, (WPARAM)acmRemote, 0);
//removes the hook procedure installed in a hook chain by the SetWindowsHookEx function.
::UnhookWindowsHookEx(_messageHookHandle);
}
//removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.
::VirtualFreeEx(hProcess, acmRemote, buffLen, MEM_RELEASE);
}
::CloseHandle(hProcess);
}
}
//Decrements the reference count of the loaded DLL
::FreeLibrary(hinstDLL);
}
}
__declspec( dllexport )
// The procedure for hooking, this will be called back after hooked
int __stdcall MessageHookProc(int nCode, WPARAM wparam, LPARAM lparam) {
//HC_ACTION: indicate that there are argments in wparam and lparam
if (nCode == HC_ACTION)
{
CWPSTRUCT* msg = (CWPSTRUCT*)lparam;
//when the target window received our custom message
if (msg != NULL && msg->message == WM_GOBABYGO)
{
//get the argument passed by the message
//actually, the argument is the base address (a pointer)
//of the assemblyClassAndMethod string in the target process memory
wchar_t* acmRemote = (wchar_t*)msg->wParam;
//gcnew: creates an instance of a managed type (reference or value type) on the garbage collected heap
System::String^ acmLocal = gcnew System::String(acmRemote);
//split the string into substring array with $. Under this context:
//acmSplit[0]:the assembly's location
//acmSplit[1]:className;
//acmSplit[2]:methodName
//we use these infomation to reflect the method in the source assembly, and invoke it in the target process
cli::array<System::String^>^ acmSplit = acmLocal->Split('$');
//refect the method, and invoke it
System::Reflection::Assembly^ assembly = System::Reflection::Assembly::LoadFile(acmSplit[0]);
if (assembly != nullptr)
{
System::Type^ type = assembly->GetType(acmSplit[1]);
if (type != nullptr)
{
System::Reflection::MethodInfo^ methodInfo =
type->GetMethod(acmSplit[2], System::Reflection::BindingFlags::Static | System::Reflection::BindingFlags::Public);
if (methodInfo != nullptr)
{
methodInfo->Invoke(nullptr, nullptr);
}
}
}
}
}
return CallNextHookEx(_messageHookHandle, nCode, wparam, lparam);
}
接下来,做个DEMO尝试一下:

解决方案中的InjectorDemo就是我们上述的源进程,它会利用Injector将下面这段代码注入到Target进程中并执行:
public static void DoSomethingEvie()
{
vartargetWindow = Application.Current.MainWindow;
if(targetWindow != null)
{
varlb = newLabel{Content = "haha, i caught you :)"};
targetWindow.Content = lb;
}
}
也就是说InjectorDemo进程会将InjectTargetApp进程的主窗口的内容修改成"haha, i caught you"这样的一个Label.
运行程序:
上面的两个窗口分别处于不同的进程中, 点击 "Inject it" 按钮, 其辉调用如下代码:
ManagedInjector.Injector.Launch(targetProcess.MainWindowHandle, typeof(InjectorWindow).Assembly, typeof(InjectorWindow).FullName, "DoSomethingEvie");
然后:
点击这里下载Demo
仅供参考(日志内容仅仅记录了一种存在性,并非特定问题的解决方案,讨论其意义性是毫无意义的,谢谢)
如何实现.net程序的进程注入的更多相关文章
- Sql-Server应用程序的高级注入
本文作者:Chris Anley 翻译: luoluo [luoluonet@hotmail.com] [目 录] [概要] [介绍] [通过错误信息获取信息] [更深入的访问] [xp_cmdshe ...
- 使用VC++通过远程进程注入来实现HOOK指定进程的某个API
前阵子读到一篇关于<HOOK API入门之Hook自己程序的MessageBoxW>的博客,博客地址:http://blog.csdn.net/friendan/article/detai ...
- Android中通过进程注入技术改动广播接收器的优先级
前言 这个周末又没有吊事,在家研究了怎样通过进程的注入技术改动广播接收器的优先级.关于这个应用场景是非常多的.并且也非常重要.所以就非常急的去fixed了. Android中的四大组件中有一个广播:B ...
- “聊天剽窃手”--ptrace进程注入型病毒
近日,百度安全实验室发现了一款"聊天剽窃手"病毒.该病毒可以通过ptrace方式注入恶意代码至QQ.微信程序进程.恶意代码可以实时监控手机QQ.微信的聊天内容及联系人信息. 该病毒 ...
- 通过修改EIP寄存器实现32位程序的DLL注入
功能:通过修改EIP寄存器实现32位程序的DLL注入 <如果是64位 记得自己对应修改汇编代码部分> 原理:挂起目标进程,停止目标进程EIP的变换,在目标进程开启空间,然后把相关的指令机器 ...
- Android进程注入
全部代码在这里下载:http://download.csdn.net/detail/a345017062/8133239 里面有两个exe.inj是一个C层进程注入的样例.inj_dalvik是我写的 ...
- 利用“进程注入”实现无文件复活 WebShell
引子 上周末,一个好兄弟找我说一个很重要的目标shell丢了,这个shell之前是通过一个S2代码执行的漏洞拿到的,现在漏洞还在,不过web目录全部不可写,问我有没有办法搞个webshell继续做内网 ...
- Android中通过进程注入技术修改广播接收器的优先级
前言 这个周末又没有吊事,在家研究了如何通过进程的注入技术修改广播接收器的优先级,关于这个应用场景是很多的,而且也很重要,所以就很急的去fixed了. Android中的四大组件中有一个广播:Broa ...
- Android中通过进程注入技术修改系统返回的Mac地址
致谢 感谢看雪论坛中的这位大神,分享了这个技术:http://bbs.pediy.com/showthread.php?t=186054,从这篇文章中学习到了很多内容,如果没有这篇好文章,我在研究的过 ...
随机推荐
- Visualforce简介
Visualforce Visualforce是一个和Apex语言相匹配的开发框架.开发者可以使用Visualforce和Apex建立自定义网络应用程序. Visualforce的基本功能类似于前端框 ...
- Jmeter 测试计划元素详解
Jmeter 测试计划元素详解 by:授客 QQ:1033553122 由于篇幅问题,采用链接分享的形式,烦请复制以下网址,黏贴到浏览器中打开,下载 http://pan.baidu.com/s/1n ...
- Oracle 使用SQL*Plus连接数据库
Oracle使用SQL*Plus连接数据库 by:授客 QQ:1033553122 使用sqlplus连接数据库 A 方式1 1.开启SQL*Plus,但不连接到数据库 $ sqlplus /NO ...
- 安卓开发之Room实体定义数据
使用Room实体定义数据 在Room库中,entities(实体)代表着相关字段集.每一个entity(实体)代表着相关联数据库中的一个表.entity 类必须通过Database 类中的entiti ...
- Centos7安装搭建Bugzilla 5.0
1.安装准备: Centos7保证网络连通,如果网络不能连通,可通过配置yum源使用代理服务. vim /etc/yum.conf # The proxy server - proxy server: ...
- solr-query
解释: 1.query:获取全部数据的SQL 2.deltaImportQuery:获取增量数据时使用的SQL 3.deltaQuery:获取pk的SQL 4.parentDeltaQuery:获取父 ...
- 高通 sensor 从native到HAL
app注册传感器监听 Android Sensor Framework 的整体架构如下图所示: 前几篇sensor相关的文章介绍了sensor的hal的知识,以press_sensor实时显示气压坐标 ...
- 18LaTeX学习系列之---LaTeX的参考文献
目录 目录 前言 (一)简单的参考文献 1.说明 2.源代码 3.输出效果 (二)以文件管理的方式 1.说明: 2.源代码: 3.输出效果 (三)直接从源网站获取 1.说明 2.操作 目录 本系列是有 ...
- C++基础算法学习——汉洛塔问题
汉诺塔问题古代有一个梵塔,塔内有三个座A.B.C,A座上有64个盘子,盘子大小不等,大的在下,小的在上(如图).有一个和尚想把这64个盘子从A座移到C座,但每次只能允许移动一个盘子,并且在移动过程中, ...
- Beta冲刺(2/5)(麻瓜制造者)
今日完成任务 邓弘立:继续完成了昨天未完成的登录接口的重编码与测试. 李佳铭|:进一步完善了收藏UI 江郑: 对使用前端框架页面元素的进一步优化,基本功能进行中 刘双玉:部分图书馆租借接口修改 肖小强 ...