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世界