初探计算机病毒(3)--API调用

来源:互联网 发布:centos 6.5安装hadoop 编辑:程序博客网 时间:2024/06/12 00:39

   普通的WINDOWS程序要完成功能免不了要调用系统API(Application Programming Interface)。API是系统已经编写好的功能模块,供外来程序调用。比如显示一个窗口、改变窗口标题、读写文件等等。这些功能模块都是以API函数的形式存在于不同的DLL文件里面。WINDOWS系统主要有几个DLL暴露系统的API函数:
    Kernel32.dll    系统核心函数库
    User32.dll      用户界面函数库
    Gdi32.dll       绘图函数库
    当你用C语言写个一个程序,要调用某个DLL文件当中的某个导出函数时,编译和链接系统会在生成的EXE文件中有所记录。记录调用哪个DLL的哪个函数的的地方叫做EXE文件的导入表。当系统载入EXE文件的时候就会查看导入表,把相关的DLL载入到进程的内存里,并把相关函数的地址写到进程的某个地方,这个地方也在导入表里,叫做IAT(Import Address Table 导入地址表),IAT中记录了每个函数的真实调用地址。这样当程序中有调用相关函数的代码,程序就会找到相应的地址了。
    反回头来说病毒。病毒只是一段可以运行的代码,它附着在一个PE文件中(PE文件不仅指EXE文件,还包括DLL(动态链接库)、SCR(屏幕保护程序)、OCX(ACTIVEX控件)等等)。它可能会需要调用一些系统API,比如获取WINDOWS系统的路径、打开文件、读写文件等等。但是它所附着的EXE文件的导入表中可能并没有它要用到的API,那这个时候怎么办?有人可能会说了,那在这个EXE文件的导入表里加上不就行了吗?想法不错,可是不现实。因为在导入表中中插入数据可能会引起原先导入表后面的数据后移,而造成代码中跳转、内存读写等一系列指令执行的错误,如果要修复这些错误,将是一个非常庞大的工程,已经超出我们的控制能力。另外,有极端的情况是,一个EXE或者DLL文件甚至压根就没有导入表,这时候怎么办?
    好吧,那我们就自力更生,艰苦奋斗。没有导入表我们自己找API函数的调用地址。WINDOWS API中有两个函数是开启这扇门的钥匙: LoadLibraryA(这个函数还有对应的UNICODE版本LoadLibraryW), GetProcAddress。 LoadLibraryA是给一个DLL文件名,则会把这个DLL载入内存,并返回一个句柄(这个句柄就是DLL在内存中的载入地址)。GetProcAddress是把前面这个句柄和一个函数名作为参数送入,则会返回函数的调用地址。这两个函数都在Kernel32.dll文件中。耶~~~~~~~~~~~~~~~~~~就它俩了。
    现在的问题就是如何找到Kernel32.dll在进程中的载入地址,并且得到上面两个函数的地址。
    其实每个WINDOWS程序运行,进程的内存中都会载Kernel32.dll。来找它的载入地址,一共有三种方法,详见
http://bbs.pediy.com/showthread.php?t=85910&prefixid=phpforce_43。本来想自己写一下的,可是后来一看里面东西太复杂了,涉及的东西太多,要把它写成浅显易懂的文字着实很难。有兴趣的可以打开我上面发的链接好好研究一下了。这里只给出第三种方法的汇编代码(因为第三种方法的代码最少,哈哈):
mov  eax, [fs:30h]
mov  eax, [eax+0ch]
mov  eax, [eax+1ch]
mov  eax, [eax]
mov  eax, [eax+8h]
最后eax里存储就是Kernel32.dll的载入地址。
    那现在开始找LoadLibraryA和GetProcAddress的地址。
    上面已经说过了Kernel32.dll也是PE格式的。头里是464个字节的头信息,然后是若干个40字节的节表,再后面就是各个节数据了,其中DLL的导出函数表就再这些数据里面。在头信息里有记录导出函数表的内存偏移。我们找到DLL的输出函数表后,就可以遍历里面导出函数名,找到相应的地址。这里我不想把PE头信息和导出表的结构都写出来,有兴趣的朋友可以翻阅《加密与解密 》(段钢著),里面会有详细的讲述。因为这些内容都写出来,可能需要我把几十页书的内容都照抄过来,OMG,还是算了吧。我在这里只是想阐明一个思路。
    我们从DLL的导出表中找到函数的调用地址,其实做的就是GetProcAddress的工作。只是我们一开始没有GetProcAddress,所以只能自力更生了。我们只要用上面的方法找到LoadLibraryA函数的地址就可以解决所有的API的调用问题,就可以包打天下了。