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