首页
社区
课程
招聘
[Anti Virus专题]1.7 - 打造DLL内存加载引擎.
2009-6-1 19:02 55808

[Anti Virus专题]1.7 - 打造DLL内存加载引擎.

2009-6-1 19:02
55808
1. 7 打造DLL内存加载引擎.

何为dll内存加载引擎?
       
        实际简单说就是我们来模拟loadlibrary函数,只是我们模拟的是内存加载,而不是读取磁盘文件到内存中在进行加载(实际上是一样,恩你要喜欢模拟完全的Loadlibrary 也可以 无非多几个io函数)。我们virus和rat用于来做一些anti 的yy。 国外的一些rat就是采用此方式来躲避杀毒软件,它的应用功能代码集成在dll中,在需要用到应用功能的时候传输dll数据到远程客户端,远程客户端采用DLL内存加载的方式来执行代码,这样杀毒软件就xxxxxxx 呵.动态编码 也和这个思路类似,只不过这个方式更方便些。。

        恩我们今天就来实现dll内存加载引擎,其实其实实现这个对于以后的写壳的pe loader也可以来运用 恩,该说的废话说完了,进入主题。

        首先看下我们内存加载引擎的流程。

        1. 申请一段大小为dll映射内存后的映像大小的内存空间。

        2. 移动各个区段的数据到申请的内存。

        2. 修复引入表结构的地址表。

        4. 通过重定位结构修复需要重定位的地址。

        5. 调用DllMain入口点

        完毕!.......

流程解析:

        1. 首先第一步地球人都知道pe结构中pe header结构当中的imagesize存放的是我们整个文件映射到内存后的映像大小,这个大小是经过对齐的。        恩没错读取这个成员值,来申请内存空间,我

们申请的内存空间的属性为“可读可写可执行”,我们用VirtualAlloc来申请。

        2. 读取各个节表结构的各区段的物理偏移和物理大小,然后移动各区段数据到节表结构对应的的内存空间中(注意:实际上就是将节表结构的VirtualAddress + 申请的内存空间地址),移动的

大小则为我们物理大小.

        3. 修复引入表结构的地址表。其实就是修复引入表结构FirstThunk指向的地址表,因为我们的程序api调用的也是FirstThunk所指向的地址表成员。有引入表常识的人都知道, 程序在未加载之前FirstThunk指向的地址表成员都指向的是一个IMAGE_IMPORT_BY_NAME结构,当加载后这个地址表的成员都被替换成相应的函数地址。所以我们的处理引入表过程函数 可以直接读取FirstThunk来取得相应的引入函数名称及序号等,没必要读取OriginalFirstThunk来读取。

        4. 通过重定位结构修复需要重定位的地址,恩我们连接器在链接可执行程序的时候会将需要重定位的偏移存放到一个结构中,这样pe loader读取重定位结构就可以定位到需要重定位的地址。

        5. 这个就不说了吧  压入参数, 取得入口点rva+申请目标空间地址然后call调用即可............
Over。

貌似剩下没什么可说了吧,直接看代码吧。


 ;++
 ;
 ; BOOL DllMemLoad
 ;   (
 ;       pbyte pDllMemory
 ;   )
 ;
 ; Routine Description:
 ;
 ;    Dll内存加载函数
 ;
 ; Arguments:
 ;
 ;    (esp)     - return address
 ;
 ;    Data   	(esp+4*1) - pDllMemory
 ;
 ; Return Value:
 ;
 ;    eax =  
 ;
 ;--
 DllMemLoad:
 	pushad
 ; [esp] - module address
 	mov	ebx, [esp+4*8+4]
 	cmp	word [ebx+MZ_STRUCT.mz_id], 'MZ'
 	jnz	.RetFalse
 	
 	push	ebx
 
 ; edi 	- pe header
 	mov	edi, ebx
 	add	edi, [edi+MZ_STRUCT.mz_peptr]
 	cmp	word [edi+PE_STRUCT.pe_id], 'PE'
 	jnz	.RetFalse
 	 	
 ; ebp 	- alloc image base
 	invoke	VirtualAlloc, 0, [edi+PE_STRUCT.pe_imagesize], MEM_COMMIT, PAGE_EXECUTE_READWRITE
 	test	eax, eax
 	je	.RetFalse
 	xchg	eax, ebp
 	
 ; esi - section table
 	lea 	esi, [edi+PE_STRUCT.pe_ntheadersize]
 	xor	eax, eax
 	lodsw
 	lea	esi, [esi+eax+2]
 
 ; move section to alloc image
 	movzx	ecx, word [edi+ PE_STRUCT.pe_sectionnum]
 .MoveSection:
 	push	ecx
 	
 	; edx - sourcs section va
 	mov	edx, [esi+ PE_SECTION_STRUCT.se_physoffs]
 	add	edx, [esp+4]
 	; eax - dest section va
 	mov	eax, [esi+ PE_SECTION_STRUCT.se_virtrva]
 	add	eax, ebp
 	
 	invoke	RtlMoveMemory, eax, edx, dword [esi+PE_SECTION_STRUCT.se_physsize]
 	add	esi, sizeof.PE_SECTION_STRUCT
 	
 	pop	ecx
 	loop	.MoveSection
 
 ; process import 
	mov	edx, ebp
	mov	eax, edi
	call	InitImport
  
 ; process fixups
 	mov	edx, ebp
 	mov	eax, edi
 	call	InitFixups
 	
 	mov	edx, [edi+PE_STRUCT.pe_entrypointrva]
 	add	edx, ebp
 	
  ; dll main
 	push	0
 	push	1
 	push	ebp
 	call	edx
 	
 .RetTrue:
 	pop	ecx	
  	push	ebp
  	pop	dword [esp+pushad_eax]
 	popad
 	retn	4
 
 .RetFalse:	
 	popad
 	xor	eax, eax
 	retn	4
 	
 
 ;++
 ;
 ; __fastcall BOOL InitImport
 ;   (
 ;       eax - pe header
 ;	 edx - Alloc Dll Mem base
 ;   )
 ;
 ; Routine Description:
 ;
 ;    初始化引入表函数
 ;
 ; Arguments:
 ;
 ;    (esp)     - return address
 ;
 ;    Data   	 
 ;       	eax - pe header
 ;	 	edx - Alloc Dll Mem base
 ;
 ; Return Value:
 ;
 ;    eax =  true or eax = false
 ;
 ;--
 
 InitImport:
 	pushad
 ; [esp] - alloc module address
 	push	edx
 
 ; edi 	 - import table
 	mov	edi, [eax+PE_STRUCT.pe_importrva]
 	add	edi, edx
 	
 .NextImport:	
 	cmp	dword [edi+PE_IMPORT.im_name], 0
 	jz	.RetTrue
 	
 	mov	edx, [edi+PE_IMPORT.im_name]
 	add	edx, [esp]
 	invoke	LoadLibrary, edx
 	test	eax, eax
 	jz	.RetFalse
 	
 ; ebx	 - load dll base
  	xchg	eax, ebx
  	
 ; esi	 - first thunk
  	mov	esi, [edi+PE_IMPORT.im_addresstable]
  	add	esi, [esp]
  	cld
    ..NextIat:
  	lodsd
  	test	eax, eax
  	je	.Next
  	
  	bt	eax, 31
  	jnc	..IatName
  
 ; Iat ordinal
    	movzx	edx, ax	
  	invoke	GetProcAddress, ebx, edx
  	mov	[esi-4], eax
  	jmp	..NextIat
  	
 ; Iat Name
    ..IatName:
    	add	eax, [esp]
  	lea	edx, [eax+2]
  	invoke	GetProcAddress, ebx, edx
  	mov	[esi-4], eax
  	jmp	..NextIat
  	
  .Next:
  	add	edi, sizeof.PE_IMPORT
  	jmp	.NextImport
  	
  .RetTrue:
  	pop	edx
  	popad
  	xor	eax, eax
  	inc	eax
  	retn
  	
  .RetFalse:	
  	pop	edx
	popad
	xor	eax, eax
	retn
	
 ;++
 ;
 ; __fastcall BOOL InitFixups
 ;   (
 ;       eax - pe header
 ;	 edx - Alloc Dll Mem base
 ;   )
 ;
 ; Routine Description:
 ;
 ;    初始化并修订重定位地址函数
 ;
 ; Arguments:
 ;
 ;    (esp)     - return address
 ;
 ;    Data   	 
 ;       	eax - pe header
 ;	 	edx - Alloc Dll Mem base
 ;
 ; Return Value:
 ;
 ;    eax =  true or eax = false
 ;
 ;--
 InitFixups:
  	pushad
  	
  ; esi - fixups table 
  	mov	esi, [eax+PE_STRUCT.pe_fixuprva]
  	test	esi, esi
  	je	.RetFalse
  	cld
  	add	esi, edx
  	
  ; [esp] - fixups end offset 
  	push	[eax+PE_STRUCT.pe_fixupsize]
  	add	[esp], esi
  	
  ; edi - alloc module address
	mov	edi, edx
	
  ; ebp - dels fixups value
 	mov	ebp, edx
 	sub	ebp, [eax+PE_STRUCT.pe_imagebase]
 	
  .NextFixups:
  	cmp	[esp], esi
  	je	.RetTrue
  ; ebx - fixups rva
  	lodsd
  	xchg	eax, ebx
  
  ; ecx - fixups blocksize
  	lodsd
  	xchg	eax, ecx
  	sub	ecx, 8
  	shr	ecx, 1	; ecx = ecx / 2
  	
   ..NextOffet:	
  	xor	eax, eax
  	lodsw
  	bt	eax, 13
  	jnc	..NextLoop
  	
  	and	ax, 0FFFh
  	add	eax, ebx
  	add	dword [edi+eax], ebp
  	
   ..NextLoop:
  	loop	..NextOffet
  	jmp	.NextFixups
  	
  .RetTrue:
  	pop	edx
  	popad
  	xor	eax, eax
  	inc	eax
  	retn
  	
  .RetFalse:
  	popad
  	xor	eax, eax
  	retn




        最后附代码和例子,这个例子中代码段存储了一个test.dll数据,这个dll用于弹出一个消息框以及运行一个cmd程序。这个test.dll我用自定义引入表的方式来编写,MessageBoxA采用的是函数名称导入方式,WinExec采用的是序号导入方式。分别来验证我的引入表处理过程。哈 没什么可说的了,直接看例子和代码吧。

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

上传的附件:
收藏
点赞7
打赏
分享
最新回复 (60)
雪    币: 181
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
naspy 2009-6-1 19:18
2
0
顶LZ,辛苦了
雪    币: 625
活跃值: (1037)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
xzchina 1 2009-6-1 19:36
3
0
一直在看.
雪    币: 7034
活跃值: (2604)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
netwind 13 2009-6-1 20:32
4
0
谢谢xfish
辛苦了
一直在关注!
雪    币: 348
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
inioo 2009-6-1 22:03
5
0
楼主 牛人 !
雪    币: 226
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
黄庆南 2009-6-1 22:13
6
0
DLL是很神奇的!学习一下.
雪    币: 211
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
百家拳 2009-6-2 00:07
7
0
好文章!
不过...

invoke LoadLibrary, edx ;这个...你不是模拟了么...干脆就改改全部模拟算了...事情挺多的...绝对不止几个IO函数...

雪    币: 315
活跃值: (23)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 5 2009-6-2 00:31
8
0
  ls ls啊 麻烦你搞清楚dll内存加载引擎的概念和用途啊。

  一般内存加载引擎用于加载我们的应用功能dll. 而非系统dll。。应用功能dll引入表可能引入了其他很多动态链接库的输出函数,例如kernel32.dll,它仅仅引入了ntdll的一些函数,由于ntdll我们ring 3下的程序是默认加载的,所以可直接取得。

  它说简单点就是模拟个loadlibrary,但是由于初始化引入表结构需要填充引入函数的地址。所以直接用loadlibrary 加载引入动态链接库。它完全模拟本身就是增加些io函数而已, 你也可以通过搜索物理内存空间来找到这些dll的内存空间就行了,只是我们在ring 3下处理麻烦些 。
雪    币: 6090
活跃值: (599)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
君君寒 2009-6-2 10:01
9
0
呵呵。汇编的,看的一头雾水,用VC实现了PE这个加载任意DLL的工具。。。诶看来汇编的功底要增强了。
这个东西可以用在保护成果上,比如写一个注册框之类的东东,也可以用在木马病毒技术上,国内就有这样的,不过知道的人极少,更加恐怖的是用这个做捆绑,可谓悄无生息,异常恐怖。这个技术,用在坏处的地方很多,用在保护软件上强度很小,所以,用做病毒专题很合适。
雪    币: 115
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hust白客 2009-6-2 11:09
10
0
又出新的了,赶紧收藏再学习
雪    币: 260
活跃值: (39)
能力值: ( LV9,RANK:144 )
在线值:
发帖
回帖
粉丝
THREAD 2009-6-2 13:57
11
0
代码风格不错,结构清晰,读起来很舒服。。。
雪    币: 124
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
水中雁 2 2009-6-2 15:09
12
0
代码先收藏了,谢谢
雪    币: 7300
活跃值: (3758)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
海风月影 22 2009-6-2 15:15
13
0
这个。。。。

哎,只能处理处理系统里面比较标准的dll

我还是不举反例了,否则又成吵架贴了
雪    币: 124
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
水中雁 2 2009-6-2 15:39
14
0
立场不一样,大型软件考虑兼容、稳定,自己用的工具考虑够用就行。
有代码支持一下,说不定某天会有用。
雪    币: 211
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
百家拳 2009-6-2 15:48
15
0
123456
雪    币: 202
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
snowshow 2009-6-2 15:48
16
0
雪    币: 124
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
zyfnhct 2009-6-2 20:58
17
0
终于等到了,谢谢~~~
雪    币: 1708
活跃值: (586)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
cntrump 13 2009-6-2 21:10
18
0
海风大哥有话就说出来嘛,不然我等小菜眼光怎么能长远,怎么学习进步呢
雪    币: 8044
活跃值: (4335)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
sunsjw 1 2009-6-3 15:53
19
0
对我受益非浅,楼主我支持你。。。
对于那些喜欢说风凉话的人。。。BS下他们。。。有本事也写这们科普的文章让我们进步啊。
雪    币: 8044
活跃值: (4335)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
sunsjw 1 2009-6-3 15:54
20
0
这段时间在跟enigma感觉还是有收获。。。
雪    币: 116
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
sethseth 2009-6-4 09:19
21
0
呵呵 你们只是角度不同 一个是从纯技术角度讨论如何规避dll加载过程中所用的API 一个是从实用角度实现Virus dll的映射装载和启动(没有尾巴的vir 存活机率确实高很多嘛 楼主的出发点我没有理解错吧) 
PS:麻烦问一下 不知道dll如果含对话框之类的资源是否也可以这样搞?楼主有没有实验过?
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
jackozoo 14 2009-6-4 10:50
22
0
LS的问的很好~ 小鱼的方法虽有局限性, 但不失为一种很好的思路. 而且一般Virus少有对话框资源~
雪    币: 202
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
snowshow 2009-6-4 11:05
23
0
有没有VC6版的
雪    币: 38
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiaoAngel 2009-6-4 14:52
24
0
1. 申请一段大小为dll映射内存后的映像大小的内存空间。

  2. 移动各个区段的数据到申请的内存。

  3. 修复引入表结构的地址表。

  4. 通过重定位结构修复需要重定位的地址。

  5. 调用DllMain入口点

个人认为这里应该把4和3位置调换一下会更好,虽然现在也能工作了。
雪    币: 95
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
假面泰山 2009-6-4 15:06
25
0
又出来精品了 赶快来学习了。谢谢分享 代码先保存了。慢慢看。
游客
登录 | 注册 方可回帖
返回