1. 病毒的原理

  首先我似乎该介绍下什么叫做病毒,因为很多人现在总是把病毒和木马混为一谈,不-这也不能怪他们,因为现在很多木马也采用了病毒相关的技术, 所以也就没有了木马病毒之分。病毒是指编制或者在计算机程序中插入的破坏计算机功能或者破坏数据,影响计算机使用并且能够自我复制的一组计算机指令或者程序代码。但是它没有任何窃取相关个人信息的功能,这和木马是有差别的。很久以前vxer(病毒作者)被成为“天才的程序员”,他们以编写完美、精巧严谨、传播、隐藏、对抗思路新颖的病毒代码为目的。但现在已经没有vxer了,现在的病毒作者已经没有人去追寻传统的目的了,很头痛。所以拟写这个专题也是为了延续我们老前辈们方向也是鄙人的兴趣。


  很好有了上面的理解,我想你对病毒概念应该有所了解了,知道什么是病毒以及编写病毒的目的(请记住:我们做的仅仅是病毒研究,仅此而已)。那么下面我们就开始真刀真枪的进行讲解病毒的原理。

  我想学过PE文件结构的朋友都知道,我们的代码以及相关数据、结构都存在我们的PE文件的区段中,这样PE LOADER加载器在加载的时候会将区段映射到我们编译器链接相对于基地址的RVA地址中。其实我很厌恶讲解这些基础的理论知识,但是怕部分初学者看不懂,所以我在这里还是要介绍下相关的基础知识。(因为部分xxx觉得这些没有必要讲解, 但是请记住每个人都是从这个过程走过来的)

初学者概念讲解: (如果对PE结构掌握,就直接跳:- )

  基地址是程序建议的加载地址 它存储在_IMAGE_OPTIONAL_HEADER结构的ImageBase成员。PE 加载器首先尝试将文件加载到基地址指定的地址,如果这个地址被占用,则PE 加载器尝试将文件加载到其他地址上。由于分页机制,我们的win32操作系统上各个进程之间的虚拟地址空间是独立的,也就是说一般对于exe文件的基地址是不会被占用的,所以一般exe文件 PE Loader都能将其加载到基地址指定的地址中。

  RVA地址指的是相对于基地址的虚拟地址。举个例子, 假如我们exe程序定义了一段数据,程序的基地址是00400000h,这段数据的地址是00403201h,那么这段数据RVA地址 = 00403201h - 00400000h = 3201h (其实学过16位汇编的朋友也应该比较熟悉,因为这就和我们相对于段地址的偏移是相似的,只不过在win32环境下已经没有了段的概念,所有的地址都是相对于基地址的偏移)

:-

  那么讲了前面的知识做什么用呢?我是想讲解是:

  假如我们在我们的代码是如下调用段弹出消息框的函数的代码

  $-2      >/$  31C0          xor     eax, eax
  $ ==>    >|.  50            push    eax                              ; /Style => MB_OK|MB_APPLMODAL
  $+1      >|.  50            push    eax                              ; |Title => NULL
  $+2      >|.  68 11104000   push    00401011                         ; |Text = "Virus?,AD,"理"
  $+7      >|.  50            push    eax                              ; |hOwner => NULL
  $+8      >|.  FF15 58104000 call    dword ptr [401058]         ; \MessageBoxA


  那么大家思索把这段代码移植到我们的被感染对象中,我们需要改变哪些地方能使它成功的运行并弹出消息框呢?(我们这里先不要考虑其他因素例如是否返回宿主或者是否从这个地址执行,我们假定被感染对象就是从我们这段代码处开始执行的)

  大家是不是应该要先把这段代码中的绝对偏移找到呢?

  那么我们看到了
          $+2      >|.  68 11104000   push    00401011                         ; |Text = "Virus?,AD,"理"
          $+8      >|.  FF15 58104000 call    dword ptr [401058]       ; \MessageBoxA

  这两处代码一个是压入堆栈00401011h常量, 00401011h是我们定义的字符串的地址。另一个是call    dword ptr [401058], 这里调用的是00401058h内存偏移处的存储地址,其实也就是大家所说的IAT成员地址,也是我们的输入表结构中的FirstThunk成员指向的IMAGE_THUNK_DATA数组。 这个IMAGE_THUNK_DATA数组在文件没有被加载的时候, 数组成员指向的是各个描述函数结构IMAGE_IMPORT_BY_NAME的地址,被加载到内存后就是各个api函数的地址。
  
  OK,了解了以上几点。我们来反思维思考,我们如果直接将这段代码给插入到被感染对象,并且被感染对象加载后,我们的这段代码会出现什么样的错误。

  首先00401011处不一定是我们定义的以0结尾字符串的地址, 00401058处不一定存储的是MessageBoxA函数地址,可能存储的不是一个有效的地址或是一个数据,那么程序就会发生异常了。

  如何解决这些问题呢,这就要求我们需要掌握下节课程的内容了。{ 重定位 、获得kernel32.dll基地址、动态获取并填充API函数 },我们想只要我们解决了重定位、获得kernel32.dll基地址这样我们的病毒程序就没有输入表结构,所有的函数均是自己采用动态获取并填充的,那么我们的程序是不是就可以移植了吗。

  今天这篇文章主要就是让大家理解病毒的原理,至于如何实现,那么我们下篇文章再见。