在10年第11期上笔者曾经发表过一篇文章名为《感染exe文件的病毒原理与实现》 ,
在那篇文章中笔者详细介绍了实现一个感染exe文件病毒的原理。唯一美中不足的是那篇文
章中的代码全部由win32汇编实现,对于一些初学者来说学习起来有一定难度,更为重要的
是如果要对那个程序中的病毒代码进行扩展,添加的代码中对变量的调用都要经过地址重定
位,这大大增加了程序扩展的难度。本文及后续文章中将用C++来实现这个病毒。C++中实
现这个病毒的方法为把病毒代码写在一个完整的函数里,这样病毒代码里所用到的变量皆为
局部变量,不需要地址重定位。但如何获得病毒函数的起始地址与结束地址成为第一个要解
决的问题。笔者通过对C++程序的反汇编及调试,得到了解决这个问题的方法。本文的源代
码并不长,但是却是完成这个病毒极其重要的一步,为了避免跨度太大,病毒的其它技术环
节将在后续文章中给出。
从C++到机器码
这一节里带大家熟悉一下C++的反汇编代码,这一节的源代码为工程Test,笔者用到的
中间数据都放在了data.txt中。先看一下这个简单的C++程序:
#include <iostream.h>
void test()
{
cout << test << endl;
return;
}
{
cout << test << endl;
test();
return;
}
void main()
这个程序试着在主函数中及函数内部获得函数test的内存地址,运行后输出:
0X00401014(读者的这个地址可能与笔者不一样) 。现在打开OllyDBG,点击文件->打开,
选择生成的test.exe,经过一阵反汇编后指针停在00403600处。向下找到004036E4处,
这里有个call指令,这里是main函数的入口地址,把光标定位在这里,按F4执行到这条
指令,再按F7进入主函数。进入主函数后发现光标停在了00401019处,这里是一个跳转指
令:
00401019 $ E9 72000000 JMP Test.main
也就是说程序并没有直接进入我们的主函数区,而是执行了一条跳转指令,这个跳转指
令让程序跳转到主函数去执行。其实这是VC编译器的一个约定,程序中所有对函数的调用
并不是直接去转到被调函数去执行,而是先转到位于00401000附近的jmp区,由jmp指令
跳转到被调函数去执行。
按F8向下执行就进入了主函数,主函数的开始几句为:
00401093 . 83EC 40 SUB ESP,40
00401090 > > \55 PUSH EBP
00401091 . 8BEC MOV EBP,ESP
这几句代码是VC编译器自动添加的,所有用VC编译器生成的程序,函数的开头皆为这
几句,可以说是VC编译器的一个标志。第三句为函数中用到的所有局部变量统一在栈中申
请空间。过了这几句编译器自动添加的代码才是我们自己写的代码。
向下找到函数结尾处,发现几句指令为:
004010D5 . 8BE5 MOV ESP,EBP
004010D7 . 5D POP EBP
004010D8 . C3 RETN
这三句指令为函数结束的标志,也是编译器自动添加的。
主函数中间有一句为:
004010C3 . E8 4CFFFFFF CALL Test.00401014
这一句是我们写的调用函数 test的反汇编代码,也就是让程序跳转到jmp,再由jmp
指令跳转到函数中去执行。如果你足够细心的话会发现一个问题,一开始我们运行程序时输
出的函数test的地址并不是真正的函数入口地址, 而是这条位于00401000附近的jmp指令
地址!如果我们以这个地址作为函数的开始地址复制函数代码的十六进制码,是必会复制很
多很多的无用代码,甚至被复制的代码在运行时会出错。所以,我们必须想办法得到函数真
正的入口地址。
主函数中得到test函数的真正入口地址
本节所用到的程序为附件中的ReadFun工程的主函数。
分析一下jmp区的jmp指令会发现, 每一个jmp指令由两部分组成: E9—jmp的机器码, |