我只是对正在发生的事情有几个问题,我知道我可以像在DLL中一样直接调用它,但是我也想了解正在发生的事情。
unsigned int __cdecl newhash(int a1, unsigned int a2, int zero)
{
int content; // ebx@1
int v4; // ecx@1
int v5; // edx@1
int i; // eax@1
int v7; // ecx@2
unsigned int v8; // eax@2
int v9; // edx@2
int v10; // ecx@2
int v11; // eax@2
int v12; // edx@2
int v13; // ecx@2
int v14; // eax@2
unsigned int v15; // eax@3
int v16; // edx@15
int v17; // ecx@15
int v18; // eax@15
int v19; // edx@15
int v20; // ecx@15
int v21; // eax@15
int v22; // edx@15
unsigned int contentLength; // [sp+Ch] [bp-4h]@1
content = a1;
contentLength = a2;
v4 = -1640531527;
v5 = -1640531527;
for ( i = zero; contentLength >= 12; contentLength -= 12 )
{
v7 = (*(_BYTE *)(content + 7) << 24)
+ (*(_BYTE *)(content + 6) << 16)
+ (*(_BYTE *)(content + 5) << 8)
+ *(_BYTE *)(content + 4)
+ v4;
v8 = (*(_BYTE *)(content + 11) << 24)
+ (*(_BYTE *)(content + 10) << 16)
+ (*(_BYTE *)(content + 9) << 8)
+ *(_BYTE *)(content + 8)
+ i;
v9 = (v8 >> 13) ^ ((*(_BYTE *)(content + 3) << 24)
+ (*(_BYTE *)(content + 2) << 16)
+ (*(_BYTE *)(content + 1) << 8)
+ *(_BYTE *)content
+ v5
- v7
- v8);
v10 = (v9 << 8) ^ (v7 - v8 - v9);
v11 = ((unsigned int)v10 >> 13) ^ (v8 - v9 - v10);
v12 = ((unsigned int)v11 >> 12) ^ (v9 - v10 - v11);
v13 = (v12 << 16) ^ (v10 - v11 - v12);
v14 = ((unsigned int)v13 >> 5) ^ (v11 - v12 - v13);
v5 = ((unsigned int)v14 >> 3) ^ (v12 - v13 - v14);
v4 = (v5 << 10) ^ (v13 - v14 - v5);
i = ((unsigned int)v4 >> 15) ^ (v14 - v5 - v4);
content += 12;
}
v15 = a2 + i;
switch ( contentLength )
{
case 0xBu:
v15 += *(_BYTE *)(content + 10) << 24;
goto LABEL_5;
case 0xAu:
LABEL_5:
v15 += *(_BYTE *)(content + 9) << 16;
goto LABEL_6;
case 9u:
LABEL_6:
v15 += *(_BYTE *)(content + 8) << 8;
goto LABEL_7;
case 8u:
LABEL_7:
v4 += *(_BYTE *)(content + 7) << 24;
goto LABEL_8;
case 7u:
LABEL_8:
v4 += *(_BYTE *)(content + 6) << 16;
goto LABEL_9;
case 6u:
LABEL_9:
v4 += *(_BYTE *)(content + 5) << 8;
goto LABEL_10;
case 5u:
LABEL_10:
v4 += *(_BYTE *)(content + 4);
goto LABEL_11;
case 4u:
LABEL_11:
v5 += *(_BYTE *)(content + 3) << 24;
goto LABEL_12;
case 3u:
LABEL_12:
v5 += *(_BYTE *)(content + 2) << 16;
goto LABEL_13;
case 2u:
LABEL_13:
v5 += *(_BYTE *)(content + 1) << 8;
goto LABEL_14;
case 1u:
LABEL_14:
v5 += *(_BYTE *)content;
break;
default:
break;
}
v16 = (v15 >> 13) ^ (v5 - v4 - v15);
v17 = (v16 << 8) ^ (v4 - v15 - v16);
v18 = ((unsigned int)v17 >> 13) ^ (v15 - v16 - v17);
v19 = ((unsigned int)v18 >> 12) ^ (v16 - v17 - v18);
v20 = (v19 << 16) ^ (v17 - v18 - v19);
v21 = ((unsigned int)v20 >> 5) ^ (v18 - v19 - v20);
v22 = ((unsigned int)v21 >> 3) ^ (v19 - v20 - v21);
return (((v22 << 10) ^
(unsigned int)(v20 - v21 - v22)) >> 15) ^
(v21 - v22 - ((v22 << 10) ^ (v20 - v21 - v22)));
}
a1是地址位置
a2是要哈希的文件的长度
零我重命名了,因为它总是出于任何原因发送零。 />现在要问的问题:
首先,这是像CRC或
之类的标准算法吗?
是否有理由将v4和v5变量设置为-1640531527?
(*(_BYTE *)(content + 7) << 24)
的用途不是仅8位字节,所以每次都不为0吗?我查看了操作顺序,似乎先是强制转换,然后是位操作,因此这意味着它将转换为文件中的第8个字节,然后将其移位24位,对吗?为什么?为什么有些位是带符号的而有些则是无符号的,如果有混合,为什么会改变结果?个字节并求出总数来找出文件的“哈希”,我知道切换情况正在考虑文件不能被12整除的情况。我想一旦我了解了按位运算背后的逻辑,会更清楚。
#1 楼
-1640531527是十六进制的'0x9e3779b9'。此数字用于boost哈希函数。
函数
ub4 hash( k, length, initval)
中的代码至少与最后一部分类似。我认为
据我所知,它可能是Jenkins Hash的中间变体(lookup2)。
#2 楼
一些更底层的细节:(*(_ BYTE *)(content + 7)<< 24)的目的不是只有8位字节,所以赢得了是不是每次都是0?在C语言中,移位将操作数隐式提升为至少一个int / unsigned int,因此_BYTE值被提升为一个unsigned int。这可能是因为大多数处理器只支持单个字长而不是字节的移位。
还有另一个问题,将结果分配给int而不是unsigned int,这将带您进入下一个问题...
为什么
有符号左移和无符号左移的汇编器是相同的,因为移到寄存器外部的位会消失。这意味着反编译器无法确定左移是否为无符号,因此使用了安全的int猜测。
有符号右移和无符号右移是不同的,因为必须填充符号位正确地。这样,反编译器仅可在右移时正确猜测未签名。
通常,反编译器无法检测到变量是否为无符号变量,因为有许多操作与对有符号变量相同。
#3 楼
以下移位构造(在3中提出)是将字节流转换为32位整数的一种广泛使用的方法。
(*(_BYTE *)(content + 7) << 24)
+ (*(_BYTE *)(content + 6) << 16)
+ (*(_BYTE *)(content + 5) << 8)
+ *(_BYTE *)(content + 4)
31 24 23 16 15 8 7 0
AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
^^^ ^^^ ^^^ ^^^
content[7] content[6] content[5] content[4]
如果
content
是字节数组的地址,则可以简单地将*(_BYTE *)(content+7)
写为
content[7]
但是,当然,您应该以与反编译器相同的方式声明
content
,但是反编译器仅看到一个指针,并不知道它实际上是字节数组。评论
我发现它获取了不同的字节,我只是不了解该位移位是在int而不是8位字节上,并且由于从字节到int的转换始终将其放在右边,因此他们将其移位。因此,似乎它们在int中被反转了,对吗? 7是在左侧而不是在右侧?
– Krum110487
15年5月13日在14:19
反转取决于当前架构的字节序。由于该示例似乎是x86,所以它是little-endian,因此字节移位的结果最终将不会反转int。因此,也可以以更简单的方式((int *)content)[1]提取int,但这是独立于平台的方式。
– ebux
2015年5月14日在7:25
评论
我也想投票给您,并给您正确的答案!!!但是我不能投票,所以如果有人看到这个,请为我投票:)
– Krum110487
15年5月12日在17:42
不,它始终会提升为int,无论其是否有符号,除非sizeof(_BYTE)> = sizeof(int)
–phuclv
15年5月14日在7:54