首页
论坛
专栏
课程

[原创]利用中转输出表制作HijackDll(附工具源码)

2012-8-5 16:48 56845

[原创]利用中转输出表制作HijackDll(附工具源码)

2012-8-5 16:48
56845
众所周知,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(被劫持的DLL)和我们自己的DLL可以在同一个文件夹下,这样中转输出的DLL名要和修改后的被劫持的DLL名一致!后面会举例介绍。
(也可以劫持不在同一个文件夹下的DLL,这种情况下中转DLL名需要填写为被劫持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就生成了,我们将它放在需要劫持的DLL的同一个目录下,然后将被劫持的DLL改名为填写的中转DLL名,将生成的中转DLL名改为被劫持的DLL的原来的名字,这样在应用程序显式或者隐式调用被劫持DLL的时候就会加载我们的DLL!

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

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

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

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



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



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



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



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



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

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



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

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

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

附件为AddExport.exe源码以及用于测试的test.dll文件,AddExport.rar中的代码有个小BUG,修改后的代码上传为:AddExport_fix.rar

AddExport.rar
test.dll.rar

AddExport_fix.rar

[推荐]看雪企服平台,提供安全分析、定制项目开发、APP等级保护、渗透测试等安全服务!

上传的附件:
最新回复 (95)
baixinye 1 2012-8-5 17:11
2
0
针对上面说的中转DLL的名称,刚才有测试了一下,可以填写绝对路径,照样可以劫持对应的DLL,比如我们要劫持系统目录下的lpk.dll,可以在中转DLL名中这样填写:

“c:\windows\system32\lpk”

如图:



生成的劫持DLL依然可以被程序载入,这样就可以不用将系统中希望劫持的DLL复制到应用程序目录中了!是否可以使用相对路径或者环境变量等大家可以试一试~
上传的附件:
  • 7.jpg (35.46kb,1032次下载)
HOWMP 1 2012-8-5 18:06
3
0
LZ可对导出变量做处理了?
baixinye 1 2012-8-6 17:18
4
0
是将需要劫持的DLL导出表信息“克隆”到我们的DLL中,并将所有导出函数修改为中转导出,也就是重定向,重定向的dll名就是我们要劫持的DLL名,如果只填写DLL名那么劫持的就是应用程序同目录下的dll,若填写绝对路径则可劫持路径所指的目录下的DLL

而劫持DLL的开发者只需要关注自己dllmain的功能开发,写完了用这个工具把要劫持的DLL导出表信息“克隆”过来就OK!
bycon 1 2012-8-10 09:17
5
0
AheadLib
hbfp 2012-8-10 10:22
6
0
原来见过"中转输出表" ,不清楚是什么情况,现在总算明白了.
yjd 2012-8-10 10:26
7
0
真不错有现成工具。
cvcvxk 10 2012-8-10 10:36
8
0
中转了一份xxx.sys,居然也行~~这下牛B大了~
csjwaman 24 2012-8-10 10:58
9
0
楼主提供了一个新思路,但用AheadLib貌似更灵活些
xiejienet 2012-8-10 14:13
10
0
和AheadLib有哪些区别?
小调调 2012-8-10 14:18
11
0
看了下代码,思路很不错
baixinye 1 2012-8-10 16:06
12
0
我没有用过AheadLib,不过我觉得最大的区别应该就是该工具可以将你开发好后的DLL转化为HijackDll,并且原始DLL不受编程语言的限制,你用任何语言环境写的DLL程序都可以用来转化,你只需要关注dllmain的开发,属于事后生成。

而AheadLib生成的CPP文件只能用于VC、VS编程环境吧,还有我的程序指定中转名很灵活的哦
csjwaman 24 2012-8-10 16:34
13
0
测试了一下,确实不错!赞一个
smartLiu 2012-8-10 17:54
14
0
确实很方便的工具,谢谢楼主了。
qqlinhai 2012-8-11 09:28
15
0
看起来不错,感谢楼主的分享。
muyen 2012-8-11 15:41
16
0
这个东西不错呀,这么好,版主没感觉...
Fido 2012-8-11 20:45
17
0
又一个精华帖!!!!!!!!!!!!!!!!!
dngs 2012-8-11 22:45
18
0
非常好,非常好。
qyc 4 2012-8-12 17:26
19
0
呵呵,做坏事又方便了一点
cwinl 2012-8-12 17:58
20
0
比如dll有5个函数
如果想直接转发2个,自己拦截3个,这样可以实现吗?

我想实现的就是拦截目标dll中需要的2个函数,而其余的函数不改变直接让它转发出去
cwinl 2012-8-13 10:36
21
0
我按照LZ的要求,改动了qq的common.dll,附件了test.dll

现在启动qq,就能弹出hijack的提示框,很好玩

不过我用ida打开了common.dll(hijack dll)和bommon.dll(origin)
看export段
发现每个函数的address都不同啊,这个和LZ的描述不同,请LZ给与解释
上传的附件:
cwinl 2012-8-13 13:28
22
0
我需要拦截dll中的函数
想知道传递给函数的值是什么并log下来
请问要如何实现呢?
knighthui 2012-8-13 21:47
23
0
楼主的程序太强大了,这种感染方式太强了。
xnop 2012-8-14 20:41
24
0
l楼主好V5,赞一个
bluecode 2012-8-14 21:50
25
0
好文好码。。。。支持。
appview 2012-8-14 22:05
26
0
支持原创,up
anger 2012-8-15 15:59
27
0
楼主 的 思路很不错..
peaceclub 6 2012-8-15 23:08
28
0
Export Redirection,呵呵

主要还是要考虑一下,同名如何中转系统DLL

lpk.dll  ->  %systemroot%\system32\lpk.dll
yaneng 2012-8-16 14:06
29
0
思路不错,好贴留名!
dngs 2012-8-17 11:23
30
0
什么时候能再开发一款内存补丁工具呢?

这个工具要实现的功能:
1、不针对内存中某个具体地址,而是搜索内存中的特征值,找到后,用自己的代码替换。
2、搜索过程允许使用通配符。
3、能过大部分的外壳保护
4、如果能加上CAD的ARX文件的补丁方式更佳。

这样做的优点就是,做出来的DLL内补支持软件升级。不需要每次都反复去搞。

现在所有的内存补丁工具均没有这个功能,不好使。
llpplplp 2012-8-18 05:35
31
0
利器啊~~~~
mszl 2012-8-18 11:06
32
0
求test.dll 源码 我自己的DLL 无法达到劫持的效果。总是会有一个函数无法定位
baixinye 1 2012-8-18 12:19
33
0
我的程序会将你自己的DLL原来的导出函数清空的,然后克隆被劫持dll的所有导出信息为你的dll的中转输出,要不把你的dll发上来看看呢?
mszl 2012-8-18 14:23
34
0
我写了一个EXE 调用DLL A , 然后重新编译A 为B (修改提示框的字) 然后用B劫持A ,
当exe调用导出函数的时候 弹


我DLL代码如下
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                                         )
{
        MessageBox(NULL,"正常","正常",MB_OK);
    return TRUE;
}

extern "C" __declspec(dllexport) int fnDllll2(void)
{
        MessageBox(NULL,"fn","fn",MB_OK);
        return 42;
}

DLL见 附件

方便的话 可以分享下您的TEST .dll 的代码嘛
上传的附件:
rrrfff 2012-8-18 14:58
35
0
参考AutoDebug,实现下
mszl 2012-8-18 15:01
36
0
我用ida 逆向了一下 他的test 还是不一样 不知道是不是DLL 需要特殊处理啊。劫持的DLL main函数式进去了但是不能使程序正常使用。
baixinye 1 2012-8-18 17:45
37
0
呵呵,不好意思,当初写程序的时候就考虑过你自己写的DLL有附加数据的情况,比如说debug版的PE,如图:



后来嫌麻烦就没考虑这个问题,你可以想上图那样把多余的数据删除,或者使用release版本的dll做劫持dll,被劫持的dll倒没有任何限制,或者你修改我的代码来去掉这个bug也是很容易的
上传的附件:
mszl 2012-8-18 21:15
38
0
测试了一下用了release的 中转DLL 还是没转到EXE调用的函数 只是dllmain 进去了。2个DLLMAIN 都打出来了 但是只要一调用被劫持DLL的导出函数 就挂了。
mszl 2012-8-18 21:17
39
0
另外为什么你的导出表是空的 ,还有用ida看的时候你的函数列表 就5个函数 我自己的DLL 却N多函数,麻烦分享下代码。我就不纠结DLL的写法,努力写功能啦@
mszl 2012-8-18 21:26
40
0
报告成功了,原来是中专dll名 不能写.DLL 后缀 这个原因导致的。 直接写名字 就成功了。
另外想请教一下, 如果想exe掉的某个函数先在劫持DLL 执行 然后再去被劫持DLL 执行 这种要怎么实现
yjd 2012-8-20 17:51
41
0
什么时候能再开发一款内存补丁工具呢?

这个工具要实现的功能:
1、不针对内存中某个具体地址,而是搜索内存中的特征值,找到后,用自己的代码替换。
2、搜索过程允许使用通配符。
3、能过大部分的外壳保护
4、如果能加上CAD的ARX文件的补丁方式更佳。

这样做的优点就是,做出来的DLL内补支持软件升级。不需要每次都反复去搞。

现在所有的内存补丁工具均没有这个功能,不好使。

有的功能,ydlpk已经算有了。
健力宝 2012-8-24 10:55
42
0
为什么我用如下的汇编写的DLL不成功。。。大家帮帮忙
.386
.model flat, stdcall
option casemap :none

include windows.inc
include user32.inc
include kernel32.inc

includelib user32.lib
includelib kernel32.lib
INCLUDE                MACRO.ASM

.data
        lpszByDll db "Welcome",0
       
.data?
        hInstance dd ?
       
.CODE

;入口.如果DLL需要加载资源,需要保存hIinstDLL这个句柄到全局变量.它才是模块句柄
;使用GetModuleHandle获得的永远是主程序的句柄
LibMain proc hInstDLL:DWORD, reason:DWORD, unused:DWORD
        .if reason == DLL_PROCESS_ATTACH                                        ;动态库被加载时调用,返回0加载失败!
                invoke MessageBoxA,NULL,CTEXT("ASDFSADFSADF"),NULL,MB_OK
                mov eax,hInstDLL
                mov hInstance,eax
                mov eax,TRUE
                ret
        .elseif reason == DLL_PROCESS_DETACH
               
        .elseif reason == DLL_THREAD_ATTACH
               
        .elseif reason == DLL_THREAD_DETACH
          ;添加处理代码
        .endif
ret
LibMain Endp

End LibMain
kvllz 9 2012-9-4 11:05
43
0
火翼(xxxxxxx)  11:02:41
10年前就很多人用这个方法了
从pe格式确定就存在的
很老的技术,不过这样有代码、有说明、有工具还是第一次。
神秘力量 2012-9-4 17:08
44
0
顶一个,支持下
qyc 4 2012-10-22 14:20
45
0
在看雪找一下就有相关代码了,不如自己写个,反正我是自己实现了
ghostkim 2012-12-20 21:33
46
0
真不错有现成工具。
lukelqz 2012-12-20 21:37
47
0
好东西啊,收藏了
tzl 10 2012-12-22 19:11
48
0
这个技术含量高要支持。
vfdn 2013-1-2 16:02
49
0
谁能把这代码翻译成Delphi版吗
tylinging 2013-1-2 16:52
50
0
这个不错,谢谢楼主
游客
登录 | 注册 方可回帖
返回