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采用的是序号导入方式。分别来验证我的引入表处理过程。哈 没什么可说的了,直接看例子和代码吧。