【原创】利用中转输出表制作HijackDll(附工具源码)
作 者: baixinye
时 间: 2012-08-05,16:48:45
链 接: http://bbs.pediy.com/showthread.php?t=154269

众所周知,PE文件中的导出表指向一个IMAGE_EXPORT_DIRECTORY结构,该结构定义如下:

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

其中AddressOfFunctions指向的是一个RVA数组,而这些RVA在“正常情况”下就是每个导出函数在内存中相对于文件头的偏移,在PE加载到内存中后,经过简单的计算就能得到每个导出函数的实际地址!

上面说了在“正常情况”下,那么在某些特殊情况下,这些RVA指向的就不是函数地址偏移了,如果一个导出函数的RVA在导出表地址范围内,那么它就是一个中转输出。
比如说,导出表的VirtualAddress等于0x3000,size等于0x200,如果导出函数的RVA落在0x3000到0x3200之间,这个导出函数就是一个中转输出。

如果导出函数是一个中转输出,那么此时的RVA指向一个以零结尾的字符串组成的DLL的名称和一个用点分开的输出函数的名称,象“otherdll.exportname”这样,或者是DLL的名称和导出序号,象“otherdll.#19”这样。

举个实际的例子,Kernel32.dll中的HeapAlloc函数就是一个中转输出,该函数的RVA指向的是一个零结尾的字符串“NTDLL.RtlAllocateHeap”,这表明了该函数被调用或者被其它模块引用时被重定位到NTDLL的RtlAllocateHeap函数中,而Kernel32.dll中不存在该函数的任何代码,见下图所示:

OK,有了这些基础,我们试想以下,如果把一个目标DLL的导出函数名称以及以序号导出的函数序号获取到,然后在自己写的某个DLL中将这些信息“复制”过来,那么我们自己的DLL文件就有了目标DLL的所有导出函数,如果有应用程序调用我们的DLL的导出函数那么都会重定向到目标DLL中!

目标DLL(被劫<vb_highlight>持的DLL)和我们自己的DLL可以在同一个文件夹下,这样中转输出的DLL名要和修改后的被劫<vb_highlight>持的DLL名一致!后面会举例介绍。
(也可以劫<vb_highlight>持不在同一个文件夹下的DLL,这种情况下中转DLL名需要填写为被劫<vb_highlight>持DLL的绝对路径,比如 C:\windows\system32\lpk),

为此,我写了一个小工具来辅助我们生成这样的DLL,如图:

使用方法如下:
1、提供导出表的DLL后面我们选择需要Hijack的DLL路径
2、修改导出表的DLL后面选择我们自己写的DLL文件,一般来说我们制作的恶意DLL只关注DllMain部分,所以我们只需要将功能代码写在DllMain处
3、中转DLL名字后面填写需要Hijack的DLL名,这个地方不要加DLL后缀(也可以填写DLL的绝对路径,比如 C:\windows\system32\lpk)
4、选择以新增节还是扩大最后一个节的方式插入我们的中转函数信息
5、点击生成后写入需要生成的dll名

这样一个包含中转输出的DLL就生成了,我们将它放在需要劫<vb_highlight>持的DLL的同一个目录下,然后将被劫<vb_highlight>持的DLL改名为填写的中转DLL名,将生成的中转DLL名改为被劫<vb_highlight>持的DLL的原来的名字,这样在应用程序显式或者隐式调用被劫<vb_highlight>持DLL的时候就会加载我们的DLL!

我们使用两种方法来演示如何使用该方法劫<vb_highlight>持DLL!

第一种方法,劫<vb_highlight>持相同目录下的DLL文件:

我们用QQ目录下的Common.dll来做这个试验,test.dll是我写的一个很简单的DLL,dllmain中创建了一个线程,线程中弹出一个MessageBox以表示DLL被劫<vb_highlight>持!

首先选择QQ\Bin\Common.dll和我们的test.dll,中转输出名填写“Bommon”

然后生成一个Common.dll的中转Dll,注意不要覆盖了QQ的原始Common.dll,保存到另外一个地方

最后我们将QQ目录下的原始Common.dll改名为何中转输出名一致的Bommon,最后将我们生成的Common.dll复制到QQ\Bin目录中

可以看到,我们的HijackDll具备了和目标Dll完全一样的导出信息:

启动QQ,完美劫<vb_highlight>持了Common.dll

第二种方法,劫<vb_highlight>持系统目录下的DLL文件(或者说在dll搜索路径中的某个dll文件):

该方法就是将中转DLL名填写为绝对路径,比如我们劫<vb_highlight>持msimg32.dll,提供导出表我们选择系统目录下的msimg32.dll,需要修改导出表的DLL我们选择测试的test.dll,最重要的中转DLL名字我们填写为:C:\windows\system32\msimg32
如图:

然后将生成的msimg32.dll放到QQ\bin下,照样完美劫<vb_highlight>持!

使用中转函数名进行DLL劫<vb_highlight>持方法的优点:
1、大家可以专心于劫<vb_highlight>持DLL的功能开发,而不用去费力写导出函数的中转跳转,写好我们的劫<vb_highlight>持DLL后只需用工具就能把导出信息复制过来
2、对于某些被劫<vb_highlight>持的DLL的导出函数地址是一个数据段地址的情况,该方法就不会出错,因为我们只是将地址中转,如果使用以前的DLL劫<vb_highlight>持方法,必须要将导出函数地址中的这个数据段内容复制过来,而复制多大的数据是一个难点,因为我们不知道被劫<vb_highlight>持DLL的这个数据段导出地址导出的是一系列数据(结构)还是一个变量!稍有不慎就会出错!
3、同目录下的DLL劫<vb_highlight>持只需要将被劫<vb_highlight>持的DLL文件改个名字,而其它目录下的DLL劫<vb_highlight>持只需要知道被劫<vb_highlight>持DLL的路径
4、如果将程序中的代码用在病毒技术中,则可以实现随机、任意、动态的DLL劫<vb_highlight>持,比如恶意代码可以在QQ\Bin目录下随机选择某个Dll来进行Dll劫<vb_highlight>持,只需要动态将DLL输出信息“复制”到恶意的DLL中,然后将被劫<vb_highlight>持的DLL改个名字即可,或者随机从系统目录中选择需要劫<vb_highlight>持的DLL复制到目标程序的目录下进行劫<vb_highlight>持(也可以直接将中转Dll名设置为被劫<vb_highlight>持Dll所在的路径)!

该方法的缺点:
1、劫<vb_highlight>持其它目录下的DLL文件需要预先知道该DLL文件的绝对路径

利用中转输出表制作HijackDll的更多相关文章

  1. 利用javascript:void(0)制作假的提交按钮替代button

    在写html页面,我们很自然的在表单提交的地方采用button来作为提交按钮,但是,用<button type=”button”>按钮</button>作为提交代码会有个问题, ...

  2. WPF ScrollViewer(滚动条) 自定义样式表制作 (改良+美化)

    原文:WPF ScrollViewer(滚动条) 自定义样式表制作 (改良+美化) 注释直接写在代码里了   不太理解意思的 可以先去看看我上一篇  WPF ScrollViewer(滚动条)  自定 ...

  3. PHP简单利用token防止表单重复提交

    <?php /* * PHP简单利用token防止表单重复提交 * 此处理方法纯粹是为了给初学者参考 */ session_start(); function set_token() { $_S ...

  4. WPF ScrollViewer(滚动条) 自定义样式表制作 再发一套样式 细节优化

    艾尼路 出的效果图 本人嵌套 WPF ScrollViewer(滚动条) 自定义样式表制作 图文并茂 WPF ScrollViewer(滚动条) 自定义样式表制作 (改良+美化) 源代码

  5. PHP简单利用token防止表单重复提交(转)

    <?php/* * PHP简单利用token防止表单重复提交 */function set_token() { $_SESSION['token'] = md5(microtime(true)) ...

  6. PE文件结构(四) 输出表

    PE文件结构(四) 參考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 输出表 一般来说输出表存在于dll中.输出表提供了 文件里函数的名字跟这些函数的地址, PE装载器通过输出表来改 ...

  7. 【百度地图API】如何利用自己的数据制作社交地图?只显示可视区域内的标注

    原文:[百度地图API]如何利用自己的数据制作社交地图?只显示可视区域内的标注 摘要:如果你自己的数据已经超过1万个,如何进行合理的显示?除了聚合marker外,还有一个办法.那就是,只显示可视区域内 ...

  8. C/S模式开发中如何利用WebBrowser控件制作导航窗体

    原文:C/S模式开发中如何利用WebBrowser控件制作导航窗体 转自: CSDN 相信不少同学们都做过MIS系统的开发,今天这里不讨论B/S模式开发的问题.来谈谈winform开发.用过市面上常见 ...

  9. 利用css+原生js制作简易钟表

    利用css+原生js制作简单的钟表.效果如下所示 实现该效果,分三大块:html.javascript.css html部分html部分比较简单,定义一个clock的div,内部有原点.时分秒针.日期 ...

随机推荐

  1. C++ - 操作运算符

    一.操作运算符 操作运算符:在C++中,编译器有能力将数据.对象和操作符共同组成表达式,解释为对全局或成员函数的调用 该全局或成员函数被称为操作符函数,程序员可以通过重定义函数操作符函数,来达到自己想 ...

  2. maven 高级玩法

    maven 高级玩法 标签(空格分隔): maven 实用技巧 Maven 提速 多线程 # 用 4 个线程构建,以及根据 CPU 核数每个核分配 1 个线程进行构建 $ mvn -T 4 clean ...

  3. Python爬取中文页面的时候出现的乱码问题(续)

    我在上一篇博客中说明了在爬取数据的时候,把数据写入到文件的乱码问题 在这一篇里面我做一个总结: 1.首先应该看一个案例 我把数据写在.py文件中: #coding:utf-8 s = 'hehe测试中 ...

  4. git创建公钥匙

    目的: 使用SSH公钥可以让你在你的电脑和码云通讯的时候使用安全连接(git的remote要使用SSH地址) 1.打开终端进入.ssh目录输入当下命令 cd ~/.ssh 如果.ssh文件夹不存在,执 ...

  5. send()/ recv() 和 write()/ read()

    Linux下数据的接收和发送write()/ read() Linux 不区分套接字文件和普通文件,使用 write() 可以向套接字中写入数据,使用 read() 可以从套接字中读取数据. 两台计算 ...

  6. React Native商城项目实战04 - 封装TabNavigator.Item的创建

    1.Main.js /** * 主页面 */ import React, { Component } from 'react'; import { StyleSheet, Text, View, Im ...

  7. java内存分布详解

    参见:http://blog.csdn.net/bluetjs/article/details/52874711 基本类型和引用类型.二者作为局部变量,都放在栈中,基本类型直接在栈中保存值,引用类型只 ...

  8. leetcode-easy-array-1 two sum

    mycode  33.91% class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: for i ...

  9. 数据结构和算法(Java版)快速学习(栈与队列)

    栈是仅允许在表尾进行插入和删除操作的线性表.我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom).栈是一种后进先出(Last In First Out)的线性表,简称(LIFO ...

  10. ps 和 pstree的用法

    ps 查看某个具体的命令进程: ps -C cmd-name: 如: ps -C httpd // 如果有多个名字相同的进程, 如httpd... 应该是它下面的子进程, 这时会显示第一个进程id. ...