- 浏览: 518431 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (299)
- Oracle(pl/sql_Erp_Pro*C) (69)
- 设计模式 (4)
- spring (23)
- ext (17)
- apache开源项目应用 (4)
- jquery (16)
- 生活琐事 (8)
- 下载资源 (23)
- mysql (2)
- Eclipse使用积累 (5)
- 报表类(报表/图表) (13)
- php (4)
- Web多彩文本框 (3)
- json (4)
- jqgrid (2)
- ant (2)
- java算法积累 (8)
- EL表达式/JSTL (4)
- poi (3)
- gwt (2)
- 爬网第一步 (2)
- javascript (17)
- Javaweb (8)
- tomcat (1)
- flex (1)
- Java&DB (3)
- J2SE (7)
- linux (3)
- 数据结构 (1)
- dot net (5)
- struts (1)
- ibatis (1)
- log4j (1)
- 项目管理 (1)
- Java native interface(jni,jacob......) (5)
- applet (1)
- VB.net/C#.net/JNI (20)
- css (1)
- Sqlite (1)
- servlet (1)
- REST (1)
最新评论
-
wenhurena:
能不能给一下解压密码roki.work.2017@gmail. ...
Ebs解体新書と学習資料1 -
liutao1600:
楼主写的太好了,每天学习~~
Spring_MVC(6)测试 -
liutao1600:
太好了,每天学习你的文章~~~
Spring_MVC(3)表单页面处理 -
liutao1600:
学习了,太好了
Spring_MVC(2)控制层处理 -
liutao1600:
学习了~~~
Spring_MVC(1)构建简单web应用
前言:
本文的重点不在于介绍如何注入托管代码,而是侧重于介绍我的研究过程,这里面有很多曲折,可能会使你感到琐屑,但正所谓“授人以鱼,不如授人以渔”,了解了这个过程,会使你理解得更深刻。
正文:
网上关于dll注入的文章实在太多,但基本上都是针对Win32 dll的,而很少涉及到托管dll。
首先让我们来看看Win32 dll是如何注入的,通常有两种方法:钩子和远程线程。而远程线程更灵活,所以本文主要讨论远程线程的方法,为了便于交流,先明确以下概念:
1. 主程序:用于将dll注入到其它进程的exe
2. dll:被注入其它进程的dll
3. 宿主:dll将被注入的其它程序
前两个程序都是我们自己写的,而第3个是原来就有的。
远程注入的基本步骤为:主程序通过CreateRemoteThread函数迫使宿主调用LoadLibrary函数加载dll,从而执行dll的入口函数DllMain,只要我们把代码放到DllMain里,就可以被调用了。
现在我们来看托管dll的注入:
用C#或VB.NET写的dll没有DllMain函数,我们自然想到了功能强大的C++。通常,我们把用C#或VB.NET写的dll,或者用C++写的,但编译为/clr:pure的dll称为托管dll
而把用C++编写的,但编译为/clr的dll称为混合dll。
混合dll也可以调用托管代码,所以也可以将其称为托管dll,本文所说的托管dll注入,实际上是混合dll的注入。
我们首先想到的是用常规方法来注入混合dll,结果会发现:只要在DllMain函数里调用了托管代码,程序就会崩溃。
也许你还会想到下面的方法:
定义一个类,在其构造函数里调用托管代码,然后在全局域里定义这个类的一个变量,当我们这样做了后会发现,注入后,什么也没有执行。
查阅MSDN,我们找到了答案:
DllMain不能直接或间接地调用托管代码,并且全局变量不会进行初始化。
这样的结果让人非常沮丧!
难道真的就没有办法了吗?
一个解决方案:
写一个混合dll,在其中定义一个导出函数,在这个导出函数里可以调用托管代码。
然后写一个非托管dll(也就是Win32 dll),在其DllMain函数里调用前面那个混合dll的导出函数。
这个方案能够解决问题,并且我在一段时间里,也一直使用这个方法。但总觉得不完美:必须使用两个dll。
有没有办法用一个dll就解决问题呢?答案是肯定的。
我在一次偶然的机会中,发现了一个现象:
如里用钩子来实现注入,则全局变量会得到初始化。这个发现让我非常困惑:为什么远程线程注入就不会初始化呢?
我考虑这两种方法的区别:钩子注入时,宿主会调用dll中的钩子回调函数。
于是我大胆设想,只要宿主调用了dll中的任意一个函数,全局变量就会得到初始化。
于是我在dll中定义了一个空实现的函数(因为我的目地是迫使全局变量初始化,而不是去执行这个函数)
结果正如我所料,全局变量被初始化了,其构造函数中的托管代码被调用了!
这里其实已经实现了托管代码的注入,当然,还远远不够完善。
这时候,我又觉得全局变量是多余的了:既然我能够使宿主调用dll中的一个特定函数,为什么不直接把托管代码放到这个函数中呢?
我马上进行了测试,也成功了。
之前我是这样实现让宿主调用dll中的一个特定函数的:
在dll被注入之后,我在DllMain函数里将这个特定函数的地址写到共享内存中(这时DllMain里没有调用托管代码,所以可以执行),然后主程序读取共享内存中的值,再通过远程线程迫使宿主调用这个特定函数。
于是我又想,既然可以在主程序中用远程线程迫使宿主调用dll中的特定函数,为什么不直接在dll中用相同的方法去调用呢?
我还没有来得及验证,马上又想到:dll跟宿主是一个进程,即使用远程线程,传给CreateRomoteThread函数的第一个参数也是-1(GetCurrentProcess()返回-1),为什么不直接用“近程”线程CreateThread呢?
需要着重强调地是:我当时用CreateThread的目的只是让它调用一个特定函数,而不是要去创建一个线程,虽然最终的确创建了一个线程,不过对于此目的,貌似只是一个副作用。
我非常兴奋,马上进行了验证,成功了!
现在我来总结一下托管代码注入的过程:
首先定义一个线程回调函数,可以在其中调用托管代码:
DWORD CALLBACK ThreadProc(LPVOID lp)
{
//可以在此调用托管代码
return 0;
}
然后在dll的入口函数DllMain里调用CreateThread函数:
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(0,0,ThreadProc,0,0,0);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
这样就实现了托管代码的注入。
深入话题:
通常我们会有这样的要求:在主程序中单击某个按扭,使宿主执行dll中的一段代码,多次单击就多次执行。
上面的代码无法实现这个目地,因为只有dll刚被注入到宿主时,DllMain中的DLL_PROCESS_ATTACH才会收到通知,我们自然想到:每次执行后,卸载掉dll,下次单击后,DLL_PROCESS_ATTACH又会收到通知;遗憾的是,目前我还没有办法卸载掉这个dll。
对于非托管dll,我们可以通过FreeLibrary来卸载(如果是在dll内部卸载,还必须借助FreeLibraryAndExitThread函数,关于dll的自卸载,由于没有在这个程序中使用,这里就不做介绍了)
而对于托管dll,查阅MSDN,我们得到的结论是:.Net不支持dll的卸掉,dll只能随着应用程序域的卸载而卸载。
对于混合dll,应该如何卸载呢?
我尝试用Win32 dll的方式卸载,结果也“真的”卸载了,这是因为:
1. DllMain中的DLL_PROCESS_DETACH收到了通知
2. 用模块查看工具去看,宿主中确实不存在注入的dll了
但事实上是失败了,至少有两个问题:
1. 关闭宿主时,会提示出错
2. 再次注入时,虽然DLL_PROCESS_ATTACH会收到通知,但用CreateThread创建的新线程并不被执行
既然MSDN上都说无法卸载托管dll,那这个问题就搁浅了吧。
虽然不能卸载这个dll,但并不是说就不能实现前面提到的问题。
实际上,每次主程序通过CreateRemoteThread函数在宿主创建线程时,DllMain中的DLL_THREAD_ATTACH和DLL_THREAD_DETACH也会收到通知,当然最好不要在这里直接调用CreateThread,这是因为:
1. 如果不做处理,直接在DLL_THREAD_ATTACH中调中CreateThread,显然会造成死循环:每产生一个线程,DLL_THREAD_ATTACH就会收到通知,然后又去创建线程,它又会得到通知……
2. 虽然多次单击按扭注入时,DLL_THREAD_ATTACH都会得到通知;但反过来,得到了通知,不意味着就是远程注入:一个最明显的情况是,对CreateThread的调用就会导致DLL_THREAD_ATTACH收到通知,但这并非远程注入
我的解决办法是:每次主程序调用CreateRemoteThread迫使宿主调用LoadLibrary加载dll的时候,都会使模块计数器加1,根据模块计数器的值的变化,就可以确定是否是远程注入了。
示例程序说明:
示例程序包括3个文件:
1. SuperSpy.exe 用C#写的主程序
2. Invoke.dll 用C++写的dll,也只能用C++来写
3. PropertyControl.dll 用VB.NET写的插件,它不是必需的
除了Invoke.dll必须用C++外,其余两个可以用任意语言写。
你也许会感到奇怪,为什么有两个dll?
其中PropertyControl.dll是一个插件,你完全可以把所有的代码都放到Invoke.dll中,之所以用插件的形式,只是为了方便大家编写自已的插件,插件的规范是,在任意一个类中实现以下成员(你可以用你习惯的语言来编写这个插件):
public static void Inject();
public static string Description
{
get;
}
两个成员都必须是公共、静态的,其中Inject方法是注入后要调用的方法;Description属性是用于描述插件作用的。
我自已实现的插件的功能是:查询和编辑一个托管程序中所有窗口(包括控件)的属性,这是一个很强大的功能,我举两个例子:
1. 星号密码查看。由于已经注入,本来显示为星号的密码,可以直接通过Text属性获得
2. 灰色按扭突破。只需将窗口的Enabled属性设置成true即可
以往要实现这两个功能,都需要分别编写相关的程序,而现在仅仅是这个插件的一个简单应用。而且,你可以编写自己的插件,来实现自己的要求。
发表评论
-
程序集与托管模块
2010-10-26 16:22 1240本文是为了学习程序集而整理的网上资料,主要包括两个部分,概念和 ... -
.NET程序集
2010-10-26 15:03 2231【主要内容】@将源代码 ... -
strong-named
2010-10-26 14:48 876前段时间自己整理的一个有关strong-named assem ... -
CLR笔记(二)
2010-10-26 13:53 9826.类型和成员基础 1.Class的可见性有publi ... -
CLR笔记(一)
2010-10-26 13:22 18041.CLR的执行模型 ... -
Java调用C#
2010-10-25 22:49 1838Java调用C# 下载: http://www.co ... -
Managed Extensions for C++ Reference
2010-10-25 18:10 1389Managed Extensions for C++ Refe ... -
jni调用dll及dll已用其它dll的资料
2010-10-25 16:00 899http://blog.csdn.net/KONGKONGWJ ... -
C# method calls within a Java program
2010-10-23 16:11 1066.net产生的比java晚,其类库的封装在某些方面也比ja ... -
走近COM Interop
2010-10-23 15:40 1637走近COM Interop—— RCW ... -
get chartobjects from VB.net
2010-10-18 10:34 1341Excel.Sheets sheets = oWB.Works ... -
VB.NET调用DLL实现方法解析
2010-10-13 10:43 3510VB.NET开发平台 ... -
VB.net 的Me My MyBase MyClass
2010-10-11 23:46 2014第一次接触 Visual Basic 中的 Me、My、M ... -
使用.Net访问Office编程接口(PIA和IA的区别)
2010-10-11 10:25 3501在这篇文章里面,我将向大家介绍如何在.Net中访问Offi ... -
Exposing .net Components to Com
2010-10-11 09:47 813http://www.codeproject.com/KB/C ... -
.net Com组件注册
2010-10-11 09:30 1962本文将详细为大家介绍一个java调用.net DLL的方法,以 ... -
vb.net 封装组件成com的方法
2010-10-10 17:16 1539前几天一直在研究如何将.net的组件封装成com供非托管代码调 ... -
Writing an Activex control in VB.net
2010-10-09 22:33 1407The problem with that example i ... -
VB set Excel color
2010-10-08 17:30 938Sub Macro3()'' Macro3 Macro' ' ...
相关推荐
总的来说,这个项目展示了如何利用C#和`EasyHook`库来实现在目标进程中注入托管代码,并通过API Hook控制`ReadProcessMemory`的行为,这在调试、监控、甚至恶意软件开发中都有可能应用。理解这个过程需要对.NET ...
在C#中,由于.NET框架的特性,它既支持托管代码(由.NET运行时管理的代码),也支持非托管代码(如C++或WinAPI函数),这使得在C#中进行DLL注入成为可能。 描述中提到的“FastWin32 dll注入库”是这个项目的核心...
在IT领域,DLL注入是一种技术,它允许一个进程将代码注入到另一个正在运行的进程中,以改变或扩展其功能。这种技术广泛应用于软件调试、性能监控、自动化测试以及恶意软件中。本文主要探讨如何使用纯C#实现托管与非...
7. **异常处理**:在非托管代码中处理托管代码抛出的异常,因为两者对异常的处理机制不同。 8. **调试与日志记录**:在开发和维护过程中,有效的调试和日志记录能力至关重要,特别是在处理进程注入这类复杂操作时。...
要将托管DLL注入非托管进程,我们需要跨过.NET与非托管代码的界限。在.NET Framework中,这通常通过P/Invoke(Platform Invoke)实现,它可以调用非托管的WinAPI函数。关键步骤包括: 1. **创建DLL**:编写C#代码,...
Xenos注入器包含的文件msdia140.dll是微软的调试信息库,它用于Visual Studio的调试工具,提供对托管代码的元数据访问。在注入过程中,这个库可能用于解析和交互目标程序的元数据,帮助注入代码更好地理解和操作目标...
工具集和库,用于使用.NET Framework从非托管代码反射性地运行/引导托管代码。 这里展示了三种技术: CLRHosting:使用Microsoft官方的非托管CLR Hosting API加载程序集。 文档: : DemoAssembly:用于测试的演示...
用户可以通过SDK(Software Development Kit)来开发自己的插件DLL,这些插件可以包含任何托管代码,从而实现对目标程序的扩展或修改。SDK通常包括必要的库文件、头文件、示例代码和文档,帮助开发者了解如何编写...
1. 将托管代码编译为IL(中间语言)。 2. 使用CLR(Common Language Runtime)的元数据信息,动态生成对应的本机代码。 3. 将生成的本机代码和必要的运行时环境(如MSIL和元数据)复制到目标进程内存。 4. 创建远程...
DInvoke包含功能强大的原语,可以将它们巧妙地组合起来,以谨慎的精度从磁盘或内存中动态调用非托管代码。这可以用于许多目的,例如PE解析,智能动态API解析,在运行时动态加载PE插件,进程注入以及避免API挂钩。 ...
这是一种混合编程语言,可以同时编写托管代码(与.NET Framework交互的代码)和非托管代码(直接与操作系统交互的代码)。 5. **Windows API**:在C++中进行进程注入通常需要使用Windows API函数,如`CreateProcess...
8. **源代码管理**:压缩包中的"CSharp_Garbage_Code_Generater-master"可能是一个GitHub仓库的名字,暗示了源代码可能托管在GitHub上,用户可以下载并查看整个项目的实现细节。 总的来说,"C++ 垃圾代码生成器"是...
2. **C++/CLI**:学习如何在C++中使用C++/CLI来托管.NET代码,这在DLL注入中很重要,因为它允许非托管代码与.NET环境交互。 3. **进程操作**:掌握如何使用WinAPI函数(如`OpenProcess`、`VirtualAllocEx`、`...
在C#中实现DLL注入相对较少见,因为C++和C#通常更倾向于使用托管代码,而DLL注入往往涉及到非托管的系统级操作。 DLL注入的主要步骤包括: 1. **创建DLL**:首先,你需要编写一个包含所需功能的DLL项目。这个DLL...
4. **注入反射**:在.NET环境中,可以利用反射来动态加载并执行DLL中的代码,但这种方法通常不适用于非托管进程。 现在,让我们深入探讨C#实现DLL注入的步骤: 1. **获取进程信息**:首先,你需要获取目标进程的...
然而,它也有其局限性,尤其是对于托管代码的进程,如基于.NET框架的程序。这是因为.NET程序运行在CLR(Common Language Runtime)环境中,代码执行受到更严格的控制,内核注入通常无法直接影响到它们。 在提供的...
在VB.NET中实现线程注入,需要对Windows API有深入理解,因为大部分注入操作依赖于非托管代码。开发者通常会使用`DllImport`特性来导入并调用这些API,同时,由于涉及到多线程和进程间的操作,理解同步和并发概念也...
DLL注入是一种技术,它允许一个进程将自定义的动态链接库(DLL)加载到另一个进程中,从而在目标进程中执行特定的代码。这种技术在软件调试、性能监控、系统扩展等场景中有广泛应用,但同时也可能被滥用进行恶意活动...
P/Invoke允许托管代码调用非托管(如C语言风格)的DLL函数。 安全性和合法性是DLL注入的重要考虑因素。不正当的DLL注入可能导致系统不稳定,甚至被误认为恶意行为。因此,除非有明确的需求和合法的理由,否则应谨慎...
P/Invoke允许.NET代码与非托管代码交互,比如系统级别的API。 下面是一些关键的C#代码片段: ```csharp using System; using System.Runtime.InteropServices; public class DLLInjector { [DllImport("kernel32...