首页
社区
课程
招聘
[Anti Virus专题]1.2 - 3.hash扫描获得api函数地址
2009-4-13 23:34 34412

[Anti Virus专题]1.2 - 3.hash扫描获得api函数地址

2009-4-13 23:34
34412
4. hash扫描获得api函数地址

       
        今天这篇文章也是病毒编写中很重要的一篇文章,“hash扫描获得api函数地址”,通过它我们的病毒就可以在宿主程序中调用相应平台的库函数。呼,说白一点就是实现一个自己的GetProcAddress函数,然后通过上节课的所讲解的思路获得Kernel32基地址,然后来搜索api函数地址。

        这篇文章我分为2个栏目:

        1. 搜索获得api函数地址的实现。

        2. hash算法搜索获得api函数地址的实现。
       
        ;;;;写文章比写代码累多了, 希望辛劳的成果能使大家有所收获,也不枉我此套专题。。。。。。。

;-------------------------------------------------
       
        1. 搜索获得api函数地址的实现:

        Windows和之前的dos最大的一个特色就是采用了动态链接库, 这样我们省了很多的内存。我们可以想象一下如果我们的程序都采用静态库的话,那么我们的所有程序所占内存是相当庞大的,而

Windows采用了动态链接库(这样保证了物理内存仅有一份此动态链接库的copy),这些动态链接库分别提供给我们用户了各种各样的编程接口来实现相应的功能,当我们用户程序调用它时必须包含相应的

库文件、函数名称,这样我们的PE LOADER在加载时才会将相应的动态链接库加载我们的进程的内存空间(实际上windows是通过分页机制将这些DLL的物理内存地址指向我们程序虚拟空间的页表中,这样

我们共享的是同一物理内存)。

        那么我们上面介绍了,windows通过动态链接库提供给我们用户了各种各样的编程接口函数,那么一般的动态链接库的后缀是“.dll”,当然其他的后缀也可以,例如“.exe”, “.sys”,只不

过它们不常用罢了。因为加载器判断的不仅仅是文件后缀名,还有我们的文件结构。
       
        所以一般我们调用某个动态库的函数,我们必须增加这个动态库的导入表结构,这样我们的windows 加载器才会把这个动态库加载到我们的内存空间,并修正导入表结构的导入函数地址,以便

我们的程序能正常的调用函数。那么这个动态链接库是如何输出函数来供我们的用户程序调用呢?它实际上是采用输出表结构来描述本dll需要导出哪些函数来供其他的程序调用,这样其他的用户程序才

能正常的调用此动态链接库的输出函数。

        那么关键的点我们已经知道了,那就是动态链接库是采用输出表结构来描述导出函数。那么如果我们调用某动态链接库的输出函数,首先我们肯定是要查找到这些输出函数的地址?在那里查找

?我们肯定是在输出表结构。好明白这点后,我们来看输出表结构。

struct IMAGE_EXPORT_DIRECTORY
  Characteristics           dd      ?  ;未使用
  TimeDateStamp             dd      ?  ;文件生成时间
  MajorVersion              dw      ?  ;主版本号,一般为0
  MinorVersion              dw      ?  ;次版本号,一般为0
  nName                     dd      ?  ;模块的真实名称
  nBase                     dd      ?  ;基数, 加上序数就是函数地址数组的索引值
  NumberOfFunctions         dd      ?  ;AddressOfFunctions阵列的元素个数
  NumberOfNames             dd      ?  ;AddressOfNames阵列的元素个数
  AddressOfFunctions        dd      ?  ;指向函数地址数组
  AddressOfNames            dd      ?  ;函数名字的指针地址
  AddressOfNameOrdinals     dd      ?  ;指向输出序列号数组
ends
       

        为了更好的理解输出表结构,我们采用fasm编写一段自己定义输出表结构的dll代码。



	format PE GUI 4.0 DLL
	include 'win32ax.inc'
	entry	__DllEntry
	
.text

 ;++
 ;
 ; BOOL
 ;   DllMain(
 ;   IN HINSTANCE hDllHandle, 
 ;   IN DWORD     nReason,    
 ;   IN LPVOID    Reserved    
 ;   )
 ;
 ; Routine Description:
 ;
 ;    测试文件是否是PE文件格式。
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;
 ;    Data   (esp+4) - hDllHandle
 ;	     (esp+8) - nReason
 ;	     (esp+12)- Reserved
 ;
 ; Return Value:
 ;
 ;    eax = TRUE, initialization succeeds; eax = FALSE, initialization fails。
 ;
 ;--

 __DllEntry:
 	xor	eax, eax
 	inc	eax			
 	ret	4*3



 __MyMessageBox:
	xor	eax, eax
	push	eax
	@pushsz	'Dll'
	@pushsz	'一个dll自定导出表结构例子'
	push	eax
	call	[MessageBox]
	ret
	
.idata

section	'.edata' export data    readable

 __IMAGE_EXPORT_DIRECTORY:
 	dd	0, 0, 0, rva szName, 0, 1, 1
 	dd	rva Address_Tab
 	dd 	rva FuncName_Tab
 	dd	rva Ordinals_Tab
 	

	;dll name
	szName	db 'Msg.dll', 0
	
	;
	
	Address_Tab:
		dd rva __MyMessageBox 	;取__MyMessageBox过程 rva地址
	
	FuncName_Tab:
		dd rva ($+4) 		; ($ + 4) ptr "MyMessageBox"
		db 'MyMessageBox', 0
	
	Ordinals_Tab:
		dw 0
	
	
.fixups


       

   ;++
        OK,以上这段代码是实现自己定义输出表结构来实现输出__MyMessageBox过程的动态链接库,我们可以测试下看我们定义的输出表结构是否成功。再写一段过程,代码如下,然后运行,看我们DLL

指定的输出函数过程是否正常运行。

        invoke        LoadLibrary, 'Msg.dll'
        invoke        GetProcAddress, eax, 'MyMessageBox'
        call        eax
        ret

        我们可以看到首先调用LoadLibray函数来将我们的Msg.dll加载到我们进程的内存空间中,获取Msg.dll加载后的内存地址后,调用GetProcAddress来获得MyMessageBox函数的地址。我们上节课

程已经学习了如何查找kernel32.dll的基地址,那么我们只要实现一个GetProcAddress函数就可以轻松的获取kernel32.dll中的函数地址了。好,接下来我们的重点放在如何实现GetProcAddress函数上



   ;--

        我们看刚刚上面我们自己定义输出表结构的动态链接库代码,看我定义输出表结构,我们来模拟下GetProcAddress的思路。
       
        举个例子:
       
        Ordinals_Tab:
                dw 0 ;索引 0
                dw 1 ;索引 1
        Address_Tab:
                rva __MyMessageBox  ;对应 索引 0
                rva __MyMessageBox2 ;对应 索引 1
        nBase = 0

        由于Ordinals_Tab 序号表中的序号值,对应的是Address_Tab的索引。

        那么我们搜索函数的时候,只需要获得对应函数的在“Ordinals_Tab中的序号值”,然后通过(序号值 + 索引基数)就可以在Address_Tab中进行索引查找,得到的就是对应函数的RVA地址。简单

说就是
        mov        eax, [Address_Tab + ((Ordinals_Tab中的序号值 + 索引基数)*4)]

        那么,如何取得对应函数的在“Ordinals_Tab中的序号值”?

        这里我们可以在循环匹配函数名称的时候,如果没有匹配成功则将Ordinals_Tab的地址+2   (+2是因为,Ordinals_Tab表中的成员是dw类型,每次+2则表示指向下一个函数的Ordinals)。如果一旦

匹配成功,则直接读取Ordinals_Tab地址中的序号值,然后乘以4, +Address_Tab来读取函数的RVA地址,了解了思路是不是很简单?

        那好,就让我们来实现代码考验下你是否到底明白了?
       
编写代码如下:

 ;++
 ;
 ; int
 ;  GetApi(
 ;   IN HINSTANCE hModule, 
 ;   IN char *    lpApiString,     
 ;   )
 ;
 ; Routine Description:
 ;
 ;    获取指定函数的内存地址
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;
 ;    Data   (esp+4) - hDllHandle
 ;	     (esp+8) - lpApiString
 ; Return Value:
 ;
 ;    eax -> Function Mem Address。
 ;
 ;--

 GetApi:
	pop 	edx
	pop	eax			;hModule
	pop	ecx			;lpApiString
	push	edx	
	pushad
	mov	ebx, eax		;hModule	ebx
	mov	edi, ecx		;lpApiString	edi	
	xor	al, al
  .Scasb:
	scasb
	jnz	.Scasb
	dec	edi
	sub	edi, ecx
	xchg	edi, ecx		; edi = lpApiString, ecx = ApiLen
	
	mov	eax, [ebx+3ch]	
	mov	esi, [ebx+eax+78h]	;Get Export Rva
	lea	esi, [esi+ebx+IMAGE_EXPORT_DIRECTORY.NumberOfNames]
	lodsd
	xchg	eax, edx		; edx = NumberOfNames
	lodsd
	push	eax			; [esp] = AddressOfFunctions
	lodsd
	xchg	eax, ebp
	lodsd
	xchg	eax, ebp		; ebp = AddressOfNameOrdinals, eax = AddressOfNames
	add	eax, ebx
	
	mov	[esp+4*6], edi		;临时存储
	mov	[esp+4*5], ecx		;临时存储

  .LoopScas:	
	dec	edx
	jz	.Ret
	mov	esi, [eax+edx*4]
	add	esi, ebx
	repz	cmpsb
	jz	.GetAddr
	mov	edi, [esp+4*6]		
	mov	ecx, [esp+4*5]		
	jmp	.LoopScas
	
  .GetAddr:
  	shl	edx, 1
  	add	ebp, edx
	movzx	eax, word [ebp+ebx]
	shl	eax, 2
	add	eax, [esp]
	mov	eax, [ebx+eax]
	add	eax, ebx
  .Ret:
  	pop	ecx
  	mov	[esp+4*7], eax
	popad
	ret



分析:
        代码其余部分很好理解,我们重点来看这里。

.LoopScas:       
        dec        edx
        jz        .Ret
        mov        esi, [eax+edx*4]
        add        esi, ebx
        repz        cmpsb
        jz        .GetAddr
        mov        edi, [esp+4*6]               
        mov        ecx, [esp+4*5]               
        jmp        .LoopScas
       
  .GetAddr:
          shl        edx, 1
          add        ebp, edx
        movzx        eax, word [ebp+ebx]
        shl        eax, 2
        add        eax, [esp]
        mov        eax, [ebx+eax]
        add        eax, ebx

我们之前的思路说:

        在循环匹配的时候, 如果失败则将Ordinals_Tab的地址+2。但这里我们采用的是从后往前循环并通过NumberOfNames来作为索引来取AddressOfNames成员,所以我们就不能用Ordinals_Tab的地址

+2了(快点快点发挥你的想象力,自己实现个Ordinals_Tab的地址+2思路的函数)。

        不过我们循环的时候是取得NumberOfNames来作为循环条件,这个成员表示的是AddressOfNames的元素个数。所以我们循环匹配函数的时候通过NumberOfNames - 1,如果匹配成功的话此时的

[NumberOfNames*2], 将是Ordinals_Tab的索引值。

        然后我们通过 mov eax, [Ordinals_Tab + (索引值 *2)]来获得 AddressOfFunctions的索引值。然后通过 mov eax, [AddressOfFunctions + (索引值*4)]来获得函数地址。

        思路就是这样,我想大家目前更多的事情应该去思考。  o(∩_∩)o... 祝你好运!
       
;---------------------------------------------------------------------

2. hash算法搜索获得api函数地址的实现

        紧接着我们要讲解到的是hash算法搜索获得api函数地址。如上面的代码,我们一般要获得一个函数的地址,通常采用的是明文,例如定义一个api函数字符串"MessageBoxA",然后在

GetProcAddress函数中一个字节一个字节进行比较。这样弊端很多,例如如果我们定义一个杀毒软件比较敏感的api函数字符串,那么可能就会增加杀毒软件对我们的程序的判定值,而且定义这些字符串

还有一个弊端是占用的字节数较大。我们想想如何我们的api函数字符串通过算法将它定义成一个4字节的值,然后在GetProcAddress中把AddressOfNames表中的每个地址指向的api字符串通过我们的算法

压缩成4字节值后,与我们之前定义的4字节值进行判断,如果匹配成功则读取函数地址。
       

        废话就不多说,我们来看一种rol 3移位算法,这个算法是每次将目的地址循环向左移动3位,然后将低字节与源字符串的每个字节进行异或。算法很精巧方便。代码如下:

	
;++
 ;
 ; int
 ;   GetRolHash(  
 ;   IN char * lpApiString   
 ;   )
 ;
 ; Routine Description:
 ;
 ;    计算ApiString Hash值
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;
 ;    Data   (esp+4) - lpApiString
 ;
 ; Return Value:
 ;
 ;    eax = Hash String
 ;
 ;--
 GetRolHash:
 	pop	ecx
 	pop	eax
 	push	ecx
 	push	esi
 	xor	edx, edx
 	xchg	eax, esi
 	cld
  .Next:
 	lodsb
 	test	al, al
 	jz	.Ret
 	rol	edx, 3
 	xor	dl, al
 	jmp	.Next
 	
  .Ret:
  	xchg	eax, edx
 	pop	esi
 	ret
 	

       

        还有很多方便小巧的算法,例如ROR 13等算法。我比较喜欢ROL 3, 所以推荐这个。那么我们接下来,我们来实现个匹配hash字符串的GetProcAddress,其实它和我们上面的基本一样,只不过它

将函数名表的字符串通过我们的算法过程获得hash值后与我们之前定义的hash值进行匹配,匹配成功则获得对应函数的地址。

        过程如下:
 ;++
 ;
 ; int
 ;  GetApi(
 ;   IN HINSTANCE hModule, 
 ;   IN int      iHashApi,     
 ;   )
 ;
 ; Routine Description:
 ;
 ;    获取指定函数的内存地址
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;
 ;    Data   (esp+4) - hDllHandle
 ;	     (esp+8) - iHashApi
 ; Return Value:
 ;
 ;    eax -> Function Mem Address。
 ;
 ;--

 GetApi:
	pop 	edx
	pop	eax			;hModule
	pop	ecx			;lpApiString
	push	edx	
	pushad
	mov	ebx, eax		;hModule	ebx
	mov	edi, ecx		;iHashApi	edi	
	
	mov	eax, [ebx+3ch]	
	mov	esi, [ebx+eax+78h]	;Get Export Rva
	lea	esi, [esi+ebx+IMAGE_EXPORT_DIRECTORY.NumberOfNames]
	lodsd
	xchg	eax, edx		; edx = NumberOfNames
	lodsd
	push	eax			; [esp] = AddressOfFunctions
	lodsd
	xchg	eax, ebp
	lodsd
	xchg	eax, ebp		; ebp = AddressOfNameOrdinals, eax = AddressOfNames
	add	eax, ebx
	xchg	eax, esi		; esi = AddressOfNames
	
	
  .LoopScas:	
	dec	edx
	jz	.Ret
	lodsd
	add	eax, ebx
	
	push	edx
	
	;计算hash字符串
	push	eax
	call	GetRolHash
	
	pop	edx
	cmp	eax, edi
	jz	.GetAddr
	
	add	ebp, 2
	jmp	.LoopScas
	
  .GetAddr:
	movzx	eax, word [ebp+ebx]
	shl	eax, 2
	add	eax, [esp]
	mov	eax, [ebx+eax]
	add	eax, ebx
  .Ret:
  	pop	ecx
  	mov	[esp+4*7], eax
	popad
	ret



        OK,为了验证没有问题。我们来写一段简单的验证过程。。



	format PE GUI 4.0
	include 'win32ax.inc'
	entry	__Entry
	
.text

		
 __Entry:
 	call	GetKrnlBase3
 	
 	push	0016EF74Bh  ; Hash WinExec
 	push	eax
 	call	GetApi
 	
 	push	SW_SHOW
 	@pushsz	"cmd.exe"
 	call	eax
 	ret
 
 

 ;++
 ;
 ; int
 ;  GetApi(
 ;   IN HINSTANCE hModule, 
 ;   IN int      iHashApi,     
 ;   )
 ;
 ; Routine Description:
 ;
 ;    获取指定函数的内存地址
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;
 ;    Data   (esp+4) - hDllHandle
 ;	     (esp+8) - iHashApi
 ; Return Value:
 ;
 ;    eax -> Function Mem Address。
 ;
 ;--

 GetApi:
	pop 	edx
	pop	eax			;hModule
	pop	ecx			;lpApiString
	push	edx	
	pushad
	mov	ebx, eax		;hModule	ebx
	mov	edi, ecx		;iHashApi	edi	
	
	mov	eax, [ebx+3ch]	
	mov	esi, [ebx+eax+78h]	;Get Export Rva
	lea	esi, [esi+ebx+IMAGE_EXPORT_DIRECTORY.NumberOfNames]
	lodsd
	xchg	eax, edx		; edx = NumberOfNames
	lodsd
	push	eax			; [esp] = AddressOfFunctions
	lodsd
	xchg	eax, ebp
	lodsd
	xchg	eax, ebp		; ebp = AddressOfNameOrdinals, eax = AddressOfNames
	add	eax, ebx
	xchg	eax, esi		; esi = AddressOfNames
	
	
  .LoopScas:	
	dec	edx
	jz	.Ret
	lodsd
	add	eax, ebx
	
	push	edx
	
	;计算hash字符串
	push	eax
	call	GetRolHash
	
	pop	edx
	cmp	eax, edi
	jz	.GetAddr
	
	add	ebp, 2
	jmp	.LoopScas
	
  .GetAddr:
	movzx	eax, word [ebp+ebx]
	shl	eax, 2
	add	eax, [esp]
	mov	eax, [ebx+eax]
	add	eax, ebx
  .Ret:
  	pop	ecx
  	mov	[esp+4*7], eax
	popad
	ret


 ;++
 ;
 ; int
 ;   GetKrnlBase3(
 ;    void
 ;   )
 ;
 ; Routine Description:
 ;
 ;    获得kernel32基地址
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;
 ;
 ; Return Value:
 ;
 ;    eax =  krnl32 base
 ;
 ;--
 
 GetKrnlBase3:
 	mov	eax, [fs:30h]
 	mov	eax, [eax+0ch]
 	mov	eax, [eax+1ch]
 	mov	eax, [eax]
	mov	eax, [eax+8h]
	ret 	
 	
 	
 ;++
 ;
 ; int
 ;   GetRolHash(  
 ;   IN char * lpApiString   
 ;   )
 ;
 ; Routine Description:
 ;
 ;    计算ApiString Hash值
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;
 ;    Data   (esp+4) - lpApiString
 ;
 ; Return Value:
 ;
 ;    eax = Hash String
 ;
 ;--
 GetRolHash:
 	pop	ecx
 	pop	eax
 	push	ecx
 	push	esi
 	xor	edx, edx
 	xchg	eax, esi
 	cld
  .Next:
 	lodsb
 	test	al, al
 	jz	.Ret
 	rol	edx, 3
 	xor	dl, al
 	jmp	.Next
 	
  .Ret:
  	xchg	eax, edx
 	pop	esi
 	ret
 	
 	

       

       
;运行后,程序运行一个cmd窗口,然后退出线程。。

例子:
push        0016EF74Bh  ; Hash WinExec
push        eax
call        GetApi

这段例子代码我采用直接压入对应的函数字符串的hash值(如 WinExec 0016EF74Bh),其实我们利用宏完全可以做到在预编译阶段进行hash计算,这个就留到下下节课来讲解吧,为了大家方便,给大家发

布一个Hash Api String计算器。

如下附件图。。

好了,今天这篇文章就到这里了。大家再见。。总算今天下午把这篇文章给赶出来了。已经快接近0点,大家接着观看吧。。

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

上传的附件:
收藏
点赞7
打赏
分享
最新回复 (55)
雪    币: 419
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fixfix 2009-4-13 23:37
2
0
先沙发,写得太好了
雪    币: 268
活跃值: (10)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
三根火柴 4 2009-4-13 23:49
3
0
板凳,学习了!
雪    币: 215
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
不知所谓 1 2009-4-14 00:02
4
0
我发个参考资料
标 题: 克图鲁的呼唤
作 者: forgot
时 间: 2006-10-28,19:17
链 接: http://bbs.pediy.com/showthread.php?t=33985
雪    币: 315
活跃值: (23)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 5 2009-4-14 00:09
5
0
支持下forgot大哥。

fasm预编译阶段进行hash计算,很简单。

macro RolHash poffset, [szFuncName]{
  local hash, len, char, temp
  virtual at 0
       db  szFuncName
       len = $
       hash = 0
       temp = 0
       repeat len
         hash = (((hash shl 3) and 0FFFFFFFFh) or (hash shr (32 - 3))); hash = hash rol 3
         load char byte from % - 1
         temp = ((hash and 000000FFh) xor char)
         hash = (hash and 0FFFFFF00h) or temp
       end repeat
  end virtual
    dd hash
  poffset dd 0
}

通过此宏配合我之前这个帖子http://bbs.pediy.com/showthread.php?t=83646的。可以整个以
                      dd hash string
_ApiName_Address  dd Adress
表形式建立api函数地址表,方便调用。。

这些无外乎技巧而已,故而放到
1.3 如何编写病毒代码?
    包括如何有效的优化病毒代码

中进行讲解。
雪    币: 625
活跃值: (1027)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
xzchina 1 2009-4-14 08:10
6
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
heroxing 2009-4-14 09:21
7
0
认真学习中,收获不少,我会一直关注LZ的杰作,LZ辛苦了.
雪    币: 181
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
naspy 2009-4-14 09:23
8
0
若若问一句:怎么看起来像字符串匹配丫... ...
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sudaxx 2009-4-14 10:09
9
0
要是是C写的,就好了...
雪    币: 370
活跃值: (52)
能力值: ( LV13,RANK:350 )
在线值:
发帖
回帖
粉丝
moonife 8 2009-4-14 10:56
10
0
lz辛苦了,学习了,我一定要顶下去啊
雪    币: 321
活跃值: (271)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
combojiang 26 2009-4-14 11:38
11
0
楼主辛苦了,顶。
雪    币: 101
活跃值: (88)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
nkspark 3 2009-4-14 12:00
12
0
先顶后看~~~~~
雪    币: 2362
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zapline 2009-4-14 12:01
13
0
学习。。。支持。。。
要是能提供c/c++版的
就好学习多了
汇编看着还是有点晕
雪    币: 379
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
flowons 2 2009-4-14 12:21
14
0
lz辛苦了,支持你!
雪    币: 107
活跃值: (1387)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
frozenrain 2009-4-14 13:48
15
0
学习 这种方法不错 我得去下个编译器跑跑看
雪    币: 133
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gaoqing 2009-4-14 14:17
16
0
你的这个
IMAGE_EXPORT_DIRECTORY是通过
IMAGE_OPTIONAL_HEADER的
DataDirectory的前4个字节找到的吗?
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
heroxing 2009-4-14 14:44
17
0
楼主:  .LoopScas:  
  dec  edx
  jz  .Ret
  lodsd
我觉得是不是要改为:  .LoopScas:  
  test edx,edx
  jz  .Ret
dec  edx
  lodsd好些,如果我们用自定义的输出表,表里只定义一个函数,那这个好象就不行了呀.我是菜鸟,不知道我说的对不对,望指正,谢谢楼主大哥.
雪    币: 315
活跃值: (23)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 5 2009-4-14 15:20
18
0
to Gaoqing:
恩。

to heroxing:
恩。正确的。其实这个如果要完善还要注意很多,例如定位export输出表偏移等,但是这将浪费大量的byte。

   在病毒编写中一般没有必要这么做,因为这些系统库文件格式都是很常规的, 我们一般的病毒代码仅仅是为了获得常用的库函数。例如获得LoadLibraryA以及GetPorcAddress就可以利用获得后的函数地址来进行调用了,所以就没有必要再去处理这些,一切为了优化。
雪    币: 414
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
孟贤 2009-4-14 17:01
19
0
   支持~支持~
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
heroxing 2009-4-14 17:27
20
0
谢谢楼主的回复,小弟受教了.
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
快雪时晴 4 2009-4-14 18:34
21
0
非常希望能在最后附一个汇总了的本系列CHM,便于收藏学习
雪    币: 193
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cham 2009-4-14 20:33
22
0
克鲁图的呼唤看着有点晕,宏没法用od看啊!
雪    币: 618
活跃值: (65)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
dge 6 2009-4-14 21:23
23
0
good ...
雪    币: 260
活跃值: (39)
能力值: ( LV9,RANK:144 )
在线值:
发帖
回帖
粉丝
THREAD 2009-4-14 21:24
24
0
不错
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gkend 2009-4-15 21:10
25
0
这样hash会不会发生碰撞?有没有得到证明?MD5都已经证明会碰撞。
游客
登录 | 注册 方可回帖
返回