分享
 
 
 

病毒基础系列-API函数地址的获取

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

病毒基础系列

by Hume/冷雨飘心

前言:

病毒没有什么可怕的,也并不象想像中的复杂,玩汇编的人如果没有看过病毒?简直是白活一遭...病毒就象是双刃剑,恶意使用就会带来恶果,我本人对于此类行为深恶痛绝!我们研究不是为了破坏而是为了知己知彼,另外病毒中确实也有很多高超的技巧值得我们学习,这才是我们的目的所在,我绝没有教唆人犯罪的意图而且就我的水平来讲也远达不到.

在研究病毒之前有几项基础知识要了解:

1)ring0的获取,可参见我翻译的一篇ring0的文章,另外这些资料internet上也很多.

2)Seh的知识,可参见我写的<<seh in asm研究>>

3)PE结构的知识,ZouDan大侠的论文,IczeLion的PE教学和载 LUEVELSMEYER的《PE文件格式》,最为重要!

4)文件读写的基本知识,主要是CreateFileA,ReadFile,WriteFile,CreateFileMapping...等文件读写知识,如果你还不了解,最好先学学win32ASM的基础知识.

5)PolyEngine...MetaMorphism等基本概念

6)anti-debug的一些概念

7)有关MBR,FAT等知识,对了解一些老Virus有用.

下面我有的一些tips,可能会对理解病毒有所帮助.另外这些技术在加壳类软件中也很常见.

Tip1: API函数地址的获取

这是一个老题目了,如果我们不用任何引入库,能否在程序中调用api函数?当然可以!方法有很多,你可能早就知道了,如果你已经了解了,就此打住,这是为还不了解这一技术而写.另外这也是病毒必用的技巧之一,如果你对病毒技术感兴趣,接着看下去.

这里假设你了解PE的基本结构,如果还不懂,找点资料来看看,到处都是呦.

在几乎每个病毒的开头都用下面的语句:

call delta

delta:

pop ebp

sub ebp,offset delta

mov dword ptr [ebp+offset appBase],ebp

让我们考虑一下程序的执行情况,如果下面的代码由编译器自动编译连接,那么程序执行的基址一般是400000h,如果是在Nt下执行,那么基址可能不同,比如从100000h开始,不用担心,操作系统的Loader会自动为你重定位.但是这里停下来让我们看一下,如果你想要把这段代码附加到其他程序的后面并想让其正确执行的话,就不是那么简单了,因为你的代码可能要从555588h处开始执行,而在没有得到宿主程序许可的情况下期望操作系统自动为你修正偏移错误是不可能的,既然有非常的目的,就得费点力气,自己搞定重定位.而上面的代码就是首先得到eip指针,也是delta在程序执行时的实际偏移,然后减掉代码头到delta的偏移从而得到你的代码的真正基址,后面对于偏移的操作都应以这个真正的偏移为准.这就是你上面看到的.如果不明白,就仔细想一下,nothing difficult!下面的例子演示了这一点,并没有全部重定位,因为这只是技术演示.

现在回到本文的正式内容,要想获得api的地址,得首先获得诸如kernel32.dll,user32.dll的基址,然后再找到真正的函数地址.如何获得基址和函数地址呢呢?有几种方法

1)搜寻宿主的引入表获得GetModuleHandleA函数和GetProcAddress的地址,然后通过他返回系统dll的基址.因为很多程序都要使用这两个函数,因此在某些情况下是可行的,如果宿主没有使用GetProcAddress,那你就不得不搜寻Export表了.

2)直接获得kernel32.dll的基址,然后再搜寻Export表获得GetProcAddress和LoadLibraryA的地址,然后我们就能得到任何想调用的函数地址.

3)硬编码调用函数,比如在9X下GetModuleHandleA的地址一般是BFF7****.

第一种和第三种方法存在兼容性的问题,假如宿主没有调用GetModuleHandleA,那么你就不能获得基址,别的就更别想了...硬编码问题更大,操作系统不同则不能运行了,比如9X下可能在有些计算机上正常,但肯定不能在Nt/2K下运行...

第二种方法兼容性比较好,因此作以介绍.

一点背景:在PE Loader装入我们的程序启动后堆栈顶的地址是是程序的返回地址,肯定在Kernel中!

因此我们可以得到这个地址,然后向低地址缩减验证一直到找到模块的起始地址,验证条件为PE头不能大于4096bytes,PE header的ImageBase值应该和当前指针相等,嘿嘿,简单吧,而且兼容性还不错.

要获得Api的地址首先要获得GetModuleHandle,LoadLibraryA,GetProcAddress的地址,这是通过搜索Export表来实现的,具体原理就是PE Export表的结构,如果了解了PE结构就很简单了.下面我加了点注释,没有优化代码,是为了便于理解.

好,这一部分结束了!

这是一个例子,没有用任何预引入函数,加了一条invoke InitCommonControls是为了在2K下也能正常运行,否则不能在2K下不加载!

程序得到MessageBoxA的地址然后显示一个消息框,目的在于演示,重要部分加了注释,很好明白.

注意连接时加入/section:.text,RWE选项。

.586

.model flat, stdcall

option casemap :none ; case sensitive

include c:\hd\hd.h

include c:\hd\mac.h

;;--------------

GetApiA proto :DWORD,:DWORD

;;--------------

.CODE

appBase dd ?

k32Base dd ?

lpApiAddrs label near

dd offset sGetModuleHandle

dd offset sGetProcAddress

dd offset sExitProcess

dd offset sLoadLibrary

dd 0

sGetModuleHandle db "GetModuleHandleA",0

sGetProcAddress db "GetProcAddress",0

sExitProcess db "ExitProcess",0

sLoadLibrary db "LoadLibraryA",0

sMessageBoxA db "MessageBoxA",0

aGetModuleHandle dd 0

aGetProcAddress dd 0

aExitProcess dd 0

aLoadLibrary dd 0

aMessageBoxA dd 0

u32 db "User32.dll",0

k32 db "Kernel32.dll",0

sztit db "By Hume,2002",0

szMsg0 db "Hey,Hope U enjoy it!",0

;;-----------------------------------------

__Start:

invokeInitCommonControls

call delta

delta:

pop ebp ;得到delta地址

sub ebp,offset delta ;因为在其他程序中基址可能不是默认的所以需要重定位

mov dword ptr [ebp+offset appBase],ebp ;呵呵仔细想想

mov ecx,[esp] ;返回地址

xor edx,edx

getK32Base:

dec ecx ;逐字节比较验证

mov dx,word ptr [ecx+IMAGE_DOS_HEADER.e_lfanew] ;就是ecx+3ch

test dx,0f000h ;Dos Header+stub不可能太大,超过4096byte

jnz getK32Base ;加速检验

cmp ecx,dword ptr [ecx+edx+IMAGE_NT_HEADERS.OptionalHeader.ImageBase]

jnz getK32Base ;看Image_Base值是否等于ecx即模块起始值,

mov [ebp+offset k32Base],ecx ;如果是,就认为找到kernel32的Base值

lea edi,[ebp+offset aGetModuleHandle]

lea esi,[ebp+offset lpApiAddrs]

lop_get:

lodsd

cmp eax,0

jz End_Get

push eax

push dword ptr [ebp+offset k32Base]

callGetApiA ;获取API地址

stosd

jmp lop_get

End_Get:

push offset u32

call dword ptr [ebp+offset aLoadLibrary] ;在程序空间加载User32.dll

lea EDX,[EBP+OFFSET sMessageBoxA]

push edx

push eax

mov eax,dword ptr [ebp+aGetProcAddress] ;用GetProcAddress获得MessageBoxA的地址

call eax ;调用GetProcAddress

push 40h+1000h ;style

push offset sztit ;title

push offset szMsg0 ;消息内容

push 0

call eax ;一个消息框产生了...嘿嘿

;有理由为此高兴吧,因为我们没有预先引入

@@: ;这些函数

push 0

call [ebp+aExitProcess]

;-----------------------------------------

K32_api_retrieve proc Base:DWORD ,sApi:DWORD

push edx ;保存edx

xor eax,eax ;此时esi=sApi

Next_Api: ;edi=AddressOfNames

mov esi,sApi

xor edx,edx

dec edx

Match_Api_name:

mov bl,byte ptr [esi]

inc esi

cmp bl,0

jz foundit

inc edx

push eax

mov eax,[edi+eax*4] ;AddressOfNames的指针,递增

add eax,Base ;注意是RVA,一定要加Base值

cmp bl,byte ptr [eax+edx] ;逐字符比较

pop eax

jz Match_Api_name ;继续搜寻

inc eax ;不匹配,下一个api

loop Next_Api

jmp no_exist ;若全部搜完,即未存在

foundit:

pop edx ;edx=AddressOfNameOrdinals

shl eax,1 ;*2得到AddressOfNameOrdinals的指针

movzx eax,word ptr [edx+eax] ;eax返回指向AddressOfFunctions的指针

ret

no_exist:

pop edx

xor eax,eax

ret

K32_api_retrieve endp

;-----------------------------------------

GetApiA proc Base:DWORD,sApi:DWORD

local ADDRofFun:DWORD

pushad

mov edi,Base

add edi,IMAGE_DOS_HEADER.e_lfanew

mov edi,[edi] ;现在edi=off PE_HEADER

add edi,Base ;得到IMAGE_NT_HEADERS的偏移

mov ebx,edi

mov edi,[edi+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress]

add edi,Base ;得到edi=IMAGE_EXPORT_DIRECTORY入口

mov eax,[edi+1ch] ;AddressOfFunctions的地址

add eax,Base

mov ADDRofFun,eax

;ecx=NumberOfNames

mov ecx,[edi+18h]

mov edx,[edi+24h]

add edx,Base ;edx=AddressOfNameOrdinals

mov edi,[edi+20h]

add edi,Base ;edi=AddressOfNames

invokeK32_api_retrieve,Base,sApi

mov ebx,ADDRofFun

shl eax,2 ;要*4才得到偏移

add eax,ebx

mov eax,[eax]

add eax,Base ;加上Base!

mov [esp+7*4],eax ;eax返回api地址

popad

ret

GetApiA endp

;-----------------------------------------

END__Start

;------------------------------------------End all

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有