文章目录

通过hash算法,我们能够将任意长度的函数名称变成四个字节(DWORD)的长度。这里简单分析一下上述hash值的计算方法。假设现在有一个函数,名为“AB”,然后调用GetHash函数:

1
hash = GetHash("AB");

进入GetHash函数,它会将函数名称中的字符一个一个地分别取出进行计算,有几个字符就循环计算几次。首先是第一次循环,取出字符“A”,然后有:

1
digest = ((digest << 25) | (digest >> 7 ));

这里由于digest在上面被赋值为0,且为DWORD类型,因此这里不管怎么计算,它的值都是0。然后计算:

1
digest += *fun_name;

此时的digest是0,*fun_name保存的是第一个字符“A”,它们相加也就是ASCII码值的相加,结果就是digest的值为“00000000 00000000 00000000 01000001”。然后执行语句:

1
fun_name++;

令指针指向第二个字符“B”,从而进入第二次循环。首先计算:

1
digest = ((digest << 25) | (digest >> 7 ));

首先将digest左移25位,即“10000010 00000000 00000000 00000000”,然后将其右移7位,即“10000010 00000000 00000000 00000000”,然后江这两个值做“或”运算,则digest的值为“10000010 00000000 00000000 00000000”。事实上,上述语句的目的是实现digest的循环右移7位(或循环左移25位),由于C语言没有直接实现循环移位的运算符号,因此只能通过这种方式运算。然后计算:

1
digest += *fun_name;

也就是将digest的值加上“B”的ASCII码值,结果为“10000010 00000000 00000000 01000010”,这也就是最终的运算结果,以十六进制显示就是0x82000042。

接下来我们获取“MessageBox”、“ExitProcess”、“LoadlibraryA”的hash值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<stdio.h>
#include<windows.h>
DWORD GetHash(char *fun_name)
{
DWORD digest = 0;
while(*fun_name)
{
digest = (( digest<<25 ) | (digest>>7 ));
digest +=*fun_name;
fun_name++;
}
return digest;
}
int main()
{
DWORD hash;
hash = GetHash("MassageBOXA");
printf("The hash of MessageBox is 0x%.8x\n", hash);
hash = GetHash("EXitProcess");
printf("The hash of ExitProcess is 0x%.8x\n", hash);
hash = GetHash("LoadLibaryA");
printf("The hash of LoadlibraryA is 0x%.8x", hash);
getchar();
return 0;
}

结果如下:

1
2
3
The hash of MessageBox is 0xddb80a61
The hash of ExitProcess is 0x4fd18923
The hash of LoadlibraryA is 0x56fd704e

文章目录