首页
社区
课程
招聘
[原创]一种通用DLL劫持技术研究
发表于: 2018-11-29 17:24 49342

[原创]一种通用DLL劫持技术研究

2018-11-29 17:24
49342

通用DLL劫持技术研究
by anhkgg
2018年11月29日

Dll劫持相信大家都不陌生,理论就不多说了。Dll劫持的目的一般都是为了自己的dll模块能够在别人进程中运行,然后做些不可描述的事情。

为了让别人的程序能够正常运行,通常都需要在自己的dll中导出和劫持的目标dll相同的函数接口,然后在自己的接口函数中调用原始dll的函数,如此使得原始dll的功能能够正常被使用。导出接口可以自己手工写,也可以通过工具自动生成,比如著名的Aheadlib。这种方法的缺点就是针对不同的dll需要导出不同的接口,虽然有工具帮助,但也有限制,比如不支持x64。

除此之外,很早之前就知道一种通用dll劫持的方法,原理大致是在自己的dll的dllmian中加载被劫持dll,然后修改loadlibrary的返回值为被劫持dll加载后的模块句柄。这种方式就是自己的dll不用导出和被劫持dll相同的函数接口,使用更加方便,也更加通用。

下面就尝试分析一下如何实现这种通用的dll劫持方法。

随便写一个测试代码:

用windbg加载看看堆栈,如下所示。在test中通过LoadLibraryW加载mydll.dll,最后进入mydll!DllMain。现在需要分析系统映射dll之后是如何把基地址返回给LoadLibraryW,然后才能想办法把这个值给修改成加载mydll.dll.1的值。

先去reactos翻看一下,找到如下的函数调用结构。在LdrLoadDll参数中BaseAddress就是最后返回给LoadLibraryW的值,所以继续看BaseAddress是如何赋值的。BaseAddress继续传给LdrpLoadDll,在LdrpLoadDll中,首先通过LdrpMapDll映射dll模块,返回一个LdrEntry的LDR_DATA_TABLE_ENTRY结构,保存了dll加载的基址、大小、名字等信息。接着LdrEntry会插入到peb->ldr链表结构中,然后调用LdrpRunInitializeRoutines,在LdrpRunInitializeRoutines中最终会调用DllMain,此处不继续深入分析。最后LdrEntry->DllBase赋值给BaseAddress。到此流程分析清楚,下面考虑如何修改这个值。

记得映像中的那种方法,是通过堆栈回溯到LdrpLoadDll中,找到LdrEntry进行修改(不确实是否准备,时间久远了),但因为LdrEntry是局部变量,不同系统可以不一样,兼容性差一些。但看到这个调用流程之后,其实还有另一种方式。LdrEntry->DllBase赋值给BaseAddress,那么在赋值之前把这个LdrEntry->DllBase修改了即可,在DllMain正好是修改的时机,但是不需要使用堆栈回溯的方式。因为LdrEntry已经插入到peb->ldr中,那么在DllMain中可以直接获取peb->ldr遍历链表找到目标dll堆栈的LdrEntry就是需要修改的LdrEntry,然后修改即可。

不过这个分析都是基于reactos来的,还是需要确认一下真是windows系统的ntdll是如何首先的。

在win7 x64系统中,ntdll的关键代码如下所示。差别是LdrpLoadDll直接返回的ldrentry,而不是BaseAddress,在LdrpLoadDll内部流程基本和reactos一致。所以方案应该可行,后续验证确实证明可行。

实现其实非常简单,关键代码如下所示。两部分代码,一个是加载原始dll模块(mydll.dll.1)拿到真是的模块句柄hMod(基地址),第二个就是遍历peb->ldr找到mydll.dll的ldrentry,然后修改dllbase为hMod。

经测试在win7 x84和win10 x64中即是有效的,其他系统未测试,如果有问题,请留言或自行解决。

害怕这种方案不行,还想了另一种思路,在dllmain中hook LdrpLoadDll的返回调用地址处,修改dataentry的值,因为LdrLoadDll函数接口固定,所以这种方式也应该是通用的,不过实现起来其实还比现在的麻烦些,所以只是保留了这种思路,并未去实现验证,留给爱折腾的朋友吧。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-1-2 13:45 被KevinsBobo编辑 ,原因: 删除广告
收藏
免费 26
支持
分享
最新回复 (48)
雪    币: 1535
活跃值: (695)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
沙发
2018-11-29 17:26
0
雪    币: 25
活跃值: (506)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
板凳
2018-11-29 18:07
0
雪    币: 1449
活跃值: (128)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
嗯...这种注入方式省了好多工作量,优雅!
2018-11-29 18:54
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
修改BaseAddress后,就无需导出接口了
2018-11-29 19:08
0
雪    币: 1449
活跃值: (128)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
不过如果不断掉ldr->InLoadOrderModuleList这个链表里面的mydll.dll.1的记录,那么很容易就可以检测到这种注入,因为mydll.dll和mydll.dll.1的加载基址一样
2018-11-29 19:16
0
雪    币: 10072
活跃值: (3008)
能力值: ( LV15,RANK:515 )
在线值:
发帖
回帖
粉丝
7
Yougar 不过如果不断掉ldr->InLoadOrderModuleList这个链表里面的mydll.dll.1的记录,那么很容易就可以检测到这种注入,因为mydll.dll和mydll.dll.1的加载 ...
有道理,对抗的事可以继续考虑
2018-11-29 19:17
0
雪    币: 8924
活跃值: (5147)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jgs
8
收藏,学习,消化,谢谢楼主
2018-11-29 19:20
0
雪    币: 207
活跃值: (39)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
仔细看了一遍。很方便的做法,收藏。然后结尾 win7 x86 写成x84
2018-11-29 20:46
0
雪    币: 4614
活跃值: (4532)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
x64程序不支持内联汇编,需要怎么写
2018-11-29 20:52
0
雪    币: 10072
活跃值: (3008)
能力值: ( LV15,RANK:515 )
在线值:
发帖
回帖
粉丝
11
yaoguen x64程序不支持内联汇编,需要怎么写
单写个asm文件,或者使用nt的函数,或者...
2018-11-29 21:16
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
yaoguen x64程序不支持内联汇编,需要怎么写
单独写asm文件,或者写shellcode
但x64程序不是fs段,而是gs段
2018-11-29 21:42
0
雪    币: 10072
活跃值: (3008)
能力值: ( LV15,RANK:515 )
在线值:
发帖
回帖
粉丝
13
yaoguen x64程序不支持内联汇编,需要怎么写
更新了github,你可以去验证一下
2018-11-29 23:35
0
雪    币: 7559
活跃值: (5397)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
14
之前弄过HOOK的,对于有检测注入的,用来做对抗的意义大.用于破解/添加修复软件功能倒是不错.啥软件都行,改个名字放进去就完事,不用改表.
2018-11-30 00:09
0
雪    币: 745
活跃值: (3823)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
2018-11-30 02:13
0
雪    币: 4859
活跃值: (2774)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
这种只限loadlibrary这种方式调用的dll吧
如果是调用lib 在pe导入表就包含的dll函数 pe在加载的时候就已经报错了 根本走不到dll的dllmain里面
2018-11-30 02:47
0
雪    币: 4614
活跃值: (4532)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
lononan 之前弄过HOOK的,对于有检测注入的,用来做对抗的意义大.用于破解/添加修复软件功能倒是不错.啥软件都行,改个名字放进去就完事,不用改表.
谢谢
最后于 2018-11-30 09:03 被yaoguen编辑 ,原因:
2018-11-30 09:02
0
雪    币: 4614
活跃值: (4532)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
Angelxf 更新了github,你可以去验证一下
谢谢!
2018-11-30 09:04
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
好东西--mark
2018-11-30 09:07
0
雪    币: 1795
活跃值: (63)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
20
厉害,支持。。。
2018-11-30 09:09
0
雪    币: 1
活跃值: (310)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
21
__readgsqword(0x60)获得64位的PEB地址吧。。。
2018-11-30 10:09
0
雪    币: 26
活跃值: (256)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
mark一下!
2018-12-1 15:59
0
雪    币: 661
活跃值: (1193)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
mark
2018-12-4 09:22
0
雪    币: 10635
活跃值: (2329)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
能劫持NET的DLL吗?
2018-12-4 09:57
0
雪    币: 66
活跃值: (2746)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
冰狗  好思路
2018-12-13 13:38
0
游客
登录 | 注册 方可回帖
返回
//