通过Hash值计算API的名字【转贴】

通过Hash值计算API的名字
2007-11-19 19:26
标 题: 【原创】 通过Hash值计算API的名字
作 者: marxixing
时 间: 2007-11-19,17:39
链 接: http://bbs.pediy.com/showthread.php?t=55187

通过Hash值计算API的名字

2007.11.15

by [email protected]



在分析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值对应的函数名称,当你遇到了他们,就不用在程序中运算了,直接使用他们就是了。

; 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   DWORD __stdcall MXX_GetKernelBase();

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




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



//输入函数的hash值,求出对应的api名字
#include
#include
#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;

}

你可能感兴趣的:(通过Hash值计算API的名字【转贴】)