首页
社区
课程
招聘
[原创] 通过Hash值计算API的名字
2007-11-19 17:39 10034

[原创] 通过Hash值计算API的名字

2007-11-19 17:39
10034
通过Hash值计算API的名字

2007.11.15

by marxixing@tom.com

 

在分析shellcode的过程中,我们经常会遇到被编码后的API的hash值,因为hash算法是不可逆算法,我们不可能通过一个DWORD值得知原始的api,为了知道shellcode都调用了哪些api,你就得去不断的去调试,这个工作量是比较大的。我昨天就深有体会。今天,我写了个小工具,只要输入一个DOWRD值和dll文件的名字,就能计算出来api的名字了,呵呵,裤罢.

你可以这样来使用它: ByHashName EC0E4E8E kernel32 ,其中ByHashName是这个程序的名字,EC0E4E8E是api的hash值,kernel32就是该api所在的库了,玩shellcode的大家应该都知道吧。针对上面这个命令行,输出结果应该是LoadLibraryA.

本文所列出的hash值的算法是 ror edi,0d, 也就是将每个字符都右移13位,名字的起始指针放在esi寄存器中。下面我列出了常见的hash值对应的函数名称,当你遇到了他们,就不用在程序中运算了,直接使用他们就是了。对于一个特定的shellcode,这个算法是最常见的,如果你发现了其他的hash算法,只需要更改dll文件的输出函数的hash算法就可以了,shellcode的hash算法不会很难,最多10行汇编代码就能搞定。

2007.11.21晚上改进了一下,做了个纯汇编版本的,不用带个dll尾巴了。但原文件仍然保留。汇编版本附在本文后面。附件中是汇编版本的可执行文件。

; 0EC0E4E8Eh kernel32.dll LoadLibraryA
; 016B3FE72h kernel32.dll CreateProcessA
; 07c0dfcaah kernel32.dll GetProcAddress
; 00c0397ech kernel32.dll GlobalAlloc

; 702F1A36h urlmon.dll URLDownloadToFileA
; 054FEF4Fh urlmon.dll URLDownloadToCacheFileA

 

这是个命令行工具,我使用了汇编语言编写marxixing.dll文件,供c语言编写的主程序调用。 其中dll文件的内容如下:

.386
.model flat, stdcall
option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

.code

DllEntry proc _hInst: HINSTANCE, _reason: DWORD, _reserved: DWORD
mov eax, TRUE
ret
DllEntry Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;得到kernel32在内存中的加载地址,无参数
;eax返回最终的加载地址
MXX_GetKernelBase proc

ASSUME FS:nothing
mov eax, fs:[30h]
mov eax, [eax + 0ch]
mov esi, [eax + 1ch]
lodsd
mov eax, [eax + 8h]
ret

MXX_GetKernelBase endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;通过hash值得到转换前的API的名字
;参数DllBase: dll文件的加载地址
;参数ApiHash: api字符串的Hash值
;返回值:eax返回API名字字符串

MXX_GetFunctionAddress proc DllBase:dword, ApiHash:dword

mov edx, DllBase
mov ebx, [edx + 3ch]
mov ebx, [edx + ebx + 78h]
add ebx, edx ;export table address

mov ecx, [ebx + 18h] ;函数数目
mov edi, [ebx + 20h] ;api名字数组首地址
add edi, edx

;;计算每个函数的hash值,获得我们需要的函数
NextFunc:
jecxz error
dec ecx
mov esi, [edi + ecx * 4h] ;初始时指向最后一个函数的指针
add esi, edx

push edi
push edx

mov edx, esi ;先保存一下

xor edi, edi
cld
Counthash: ;开始计算hash值
xor eax, eax
lodsb
cmp al, ah
jz Apiend

ror edi, 0dh
add edi, eax

jmp Counthash
Apiend:
cmp edi, ApiHash ;hash值计算结束
mov esi, edx ;恢复api名字指针,用来返回
pop edx
pop edi
jnz NextFunc

mov eax, esi
ret

error:
mov eax, 0
ret

MXX_GetFunctionAddress endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

end DllEntry

 

该文件输出了两个函数,因此我们还需要给它加上一个def文件,命名为marxixing.def,内容如下:

LIBRARY marxixing
EXPORTS MXX_GetKernelBase
MXX_GetFunctionAddress

之后,就可以用如下的命令进行编译和链接了,最终生成两个文件,marxixing.lib和marxixing.dll

ml /c /coff marxixing.asm
link /DLL /subsystem:windows /Def:marxixing.def marxixing.obj

 

注意,我们不想用loadlibrary,getproaddress的方式来调用dll里面的函数,因此我写了下面的头文件marxixing.h,这样,就可以直接使用我们的输出函数了。

extern "C" DWORD __stdcall MXX_GetKernelBase();

extern "C" char * __stdcall MXX_GetFunctionAddress(HINSTANCE DllBase, DWORD HashSum);
 

 

现在,该是我们的c语言上场了,我们用它来设计界面:

 

//输入函数的hash值,求出对应的api名字
#include <stdio.h>
#include <windows.h>
#include "marxixing.h"

#pragma comment(lib, "marxixing.lib")

int main(int argc, char * argv[])
{
//参数1为api的hash值
//参数2为dll文件的名字

HINSTANCE dllbase;
char dllname[32] = {0};
char * alloc = NULL;
DWORD hashsum;
DWORD apiname;

if(argc <= 2 )
{
printf("USAGE: ByHashName hashsum dllname.\n");
printf("return: ApiName string\n");
return 0;
}
sscanf(argv[1], "%x", &hashsum);
strcpy(dllname, argv[2]);

dllbase = LoadLibrary(dllname);
if(dllbase == NULL)
{
printf("%s load memory fail!", dllname);
return 0;
}
alloc = MXX_GetFunctionAddress(dllbase, hashsum);
if(alloc == NULL)
{
printf("not find apiname!");
return 0;
}
printf("%s\n",alloc);

FreeLibrary(dllbase);

return 1;

}

*************************************************************
*************************************************************
;汇编版本的实现

.386
.model flat, stdcall
option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
include masm32.inc
includelib masm32.lib
.data
libfail db "LoadLibrary fail!", 0
NotFindApi db "Not find apiname!", 0
.data?
Hashsum db 256 dup(?)
Libname db 64  dup(?)
ApiName   dd ?
HashDword dd ?
LibDword  dd ?

MXX_GetFunctionName proto :DWORD ,  :DWORD

.code
start:
invoke GetCL, 1, addr Hashsum
invoke GetCL, 2, addr Libname

invoke htodw, addr Hashsum  ;转换输入字符串为双字
mov HashDword, eax

invoke LoadLibrary, addr Libname
.IF eax == NULL
  mov ApiName, offset libfail
  jmp over
.ELSE
  mov LibDword, eax
.ENDIF

invoke MXX_GetFunctionName, LibDword, HashDword
.IF eax == NULL
  mov ApiName, offset NotFindApi
.ELSE
  mov ApiName, eax
.ENDIF

over:
invoke MessageBox, NULL, ApiName, addr Libname, MB_OK
invoke FreeLibrary, LibDword
invoke ExitProcess, NULL

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;通过Hash值得到API的名字
;参数DllBase: dll文件的加载地址
;参数ApiHash: api字符串的Hash值
;返回值:eax返回API名字字符串
MXX_GetFunctionName proc DllBase:dword, ApiHash:dword
mov edx, DllBase
mov ebx, [edx + 3ch]
mov ebx, [edx + ebx + 78h]
add ebx, edx  ;export table address
mov ecx, [ebx + 18h]   ;函数数目
mov edi, [ebx + 20h]  ;api名字数组首地址
add edi, edx

;;计算每个函数的hash值,获得我们需要的函数
NextFunc:
jecxz error
dec  ecx
mov esi, [edi + ecx * 4h]  ;初始时指向最后一个函数的指针
add esi, edx

push edi  ;保存原来edi,edx的值,下面要用到它
push edx
mov  edx, esi
xor edi, edi
cld
Counthash:  ;开始计算hash值
xor eax, eax
lodsb
cmp al,  ah
jz  Apiend
ror edi, 0dh
add edi, eax

jmp Counthash
Apiend:
cmp edi, ApiHash  ;hash值计算结束
mov esi, edx     ;恢复api名字指针,用来返回
pop edx   ;恢复原来edx,edi的值
pop edi
jnz NextFunc
mov eax, esi
ret
error:
mov eax, 0
ret

MXX_GetFunctionName endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

end start

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
点赞7
打赏
分享
最新回复 (11)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kgdurgwu 2007-11-19 18:01
2
0
很裤
很帅
很强大
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
无聊仔 2007-11-19 20:11
3
0
有意思,
雪    币: 226
活跃值: (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
十三少 2 2007-11-19 20:30
4
0
把tmd里的那段代码抽出来用就好了。
雪    币: 707
活跃值: (1301)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
qyc 4 2007-11-20 18:23
5
0
很不错!!!
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
雨儿 2007-11-20 22:57
6
0
看着不错啊~!
雪    币: 236
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
shinechou 2007-11-21 15:05
7
0
非常棒的好文,谢谢了!学习!
雪    币: 209
活跃值: (47)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
slsdz 2007-11-23 09:10
8
0
很有用,感谢!
雪    币: 466
活跃值: (119)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
kusky 4 2007-12-3 22:19
9
0
非常吸引了我。
雪    币: 239
活跃值: (20)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
Steve 1 2007-12-5 00:57
10
0
shellcode不熟。
雪    币: 264
活跃值: (44)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
lcjxb 1 2007-12-7 13:38
11
0
好文...不错
雪    币: 77
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cqzj70 2014-3-11 14:51
12
0
mark
游客
登录 | 注册 方可回帖
返回