之前我发了一贴是关于hook的,
http://bbs.csdn.net/topics/391958344
现在继续上篇文章,讲一下自己是如何把一个.net写的dll注入到其他进程的
同样,先是给出全部源码:
https://github.com/bigbaldy1128/DotNetInjector
1.为何想做这个
其实dll注入是烂大街的东西了,不过都是C++的(
这块特指注入的dll是C++的),我这个人比较喜欢研究个东西,所以就搞出这么个东西来,也许大家觉得没什么用或者已经有更好的实现方式,但我只是兴趣使然,也欢迎大家吐槽
2.技术要点
首先要说几点:
1.实现用到了asm,C++,C#,并不是一个纯C#的实现,其中有些东西可以用C#实现,但为了省事选择了C++
2.只测试了win7 32bit/64bit,其他系统没跑,因为有C和汇编估计会有系统兼容问题,希望大家反馈
下面来说说总体思路:
C#程序通过远程线程注入的方式注入一个C++的dll,该dll中以com方式调用C#的dll,然后再用shellcode执行C#dll中的方法,具体远程线程dll注入原理我就不再敖述了,网上文章一大片,请大家自行google
我的原理图:
详细流程:
(1) 用C#编写一个com(B.dll),里面声明一个接口,你需要做的事情都写在里面,例如:
[Guid("00C74C42-D58C-40E9-B09F-B09D129A4057")]
public interface IHook
{
void Apply();
}
[Guid("56C2BC3F-942F-4967-BFD2-D5E07281DB49")]
public class Hook : IHook
{
public void Apply()
{
Monitor.Install("monitors");
}
}
(2) 用C++编写一个Dll(A.dll),里面就一个方法,以com方式调用B.dll中Apply方法
EXTERN_C __declspec(dllexport) VOID Hook()
{
CoInitialize(NULL);
ComForHook::IHookPtr hook(__uuidof(ComForHook::Hook));
hook->Apply();
CoUninitialize();
}
其实到这里,有人会问,把这个Hook方法放入DllMain中不就可以了吗,可惜并不是这样,因为以com方式加载最终还是调用了
LoadLibaray函数,这样
进程会卡死在DllMain中,所以得用其他办法来调用Hook函数了,这里我给出的办法是
编写shellcode
(3) 编写shellcode实现Hook方法的调用
首先说一下什么是shellcode,shellcode就是一段编译好了的汇编指令,一般来讲都是用汇编实现,但写起来对于新手来说并不容易,具体可以参考《0day安全:软件漏洞分析技术》这本书的第三章(开发shellcode的艺术),后来,人们也想出了一套用C来编写shellcode的方式,大幅度降低了开发难度,我参考的就是
https://nickharbour.wordpress.com/2010/07/01/writing-shellcode-with-a-c-compiler/。
主要流程就是在内存中找到我的dll并找到我的函数,然后调用它,即:
PEB->LDR->我的dll(A.dll)->PE头->导出表->我的函数(Hook),call Hook
32位的很好实现,因为C是支持内联汇编的,按照上述流程,需要先找到PEB:
PPEB __declspec(naked) get_peb(void)
{
__asm
{
mov eax, fs:[0x30]
ret
}
}
但64位的就不太方便了,因为VS是不支持64位内联汇编和裸函数的,
nickharbour 的那篇文章中也没有64bit的实现,所以只能自己搞了,我想的是直接编译asm文件再链接,但也遇到了一些问题,例如调用时函数地址超出了shellcode的范围,所以放弃了,改用自己写的方式,也许我的方法比较笨,但是还是说一下,希望高手能指点更好的方法。
我先声明了一个函数,如下所示,里面的代码仅仅是为了让函数有足够的空间
PPEB get_peb(void)
{
int a = 0;
return 0;
}
编译我的ShellCode工程运行后会生成shellcode.bin文件,用IDA打开定位get_peb的位置:
可以看到文件偏移是
0x211,先记录下来
然后使用x64dbg随便加载一个64位程序,编写汇编指令mov rax,gs:[0x60],记录前面的16进制数
最后用winhex打开shellcode.bin,定位到0x211的位置,将上图中的16进制数敲入,后面的指令全部填入90直到遇到C3为止,当然你直接填一个C3也可以
到了这里,64位shellcode编写完成了
3.测试流程
(1) 进入BinTest_x64,这里有我编译后的完整测试文件
(2) 运行Target.exe并点击【Call】,提示“想hook我没戏!”
(3) 运行HookMain.exe,点击【注入】
(4),再点击【Call】按钮,提示"竟然被hook了"
哈哈,是不是很好玩,这个东西我就是写着玩的,觉得过程很有意思所以分享出来,也没有什么新鲜东西,一切都是兴趣使然
最后插个题外话,也是我自己对于编程的看法:
我学什么是因为我喜欢什么而不是他能挣多少钱,掌握一门新语言并不难,难的是你能一直保持着最初的兴趣,我从编码中获得快乐,这对于我来讲更有意义