XFG函数原型哈希值生成原理(二)

  • A+

原文地址:https://blog.quarkslab.com/how-the-msvc-compiler-generates-xfg-function-prototype-hashes.html

在本文中,我们将为读者详细介绍MVSC编译器是如何为XFG函数原型生成哈希值的。

在上一篇文章中,我们首先对XFG哈希值的生成方法进行了概述,然后,深入介绍了函数类型哈希值的生成方法。在本文中,我们将继续为读者深入分析各种类型的哈希值是如何生成的。

(接上文)
组成部分3:变参函数(Variadic function

下一步是向std::vector添加一个字节,指示该函数是否接受可变数量的参数。在大多数情况下,当函数不包含来自__declspec的虚信息时,将使用下面的代码:

XFGHelper::XFGHasher::add_function_type+D9 mov rcx, rsi ; this = functioninfo
XFGHelper::XFGHasher::add_function_type+DC call FunctionTypeInfo_t::IsVarArgsFunction(void)
XFGHelper::XFGHasher::add_function_type+E1 mov r8b, al ; r8b = is_var_args_function
XFGHelper::XFGHasher::add_function_type+E4 test r14b, r14b ; contains virtual info from __declspec?
XFGHelper::XFGHasher::add_function_type+E7 jz short loc_1801055EB
[...]
XFGHelper::XFGHasher::add_function_type+163 loc_1801055EB:
XFGHelper::XFGHasher::add_function_type+163 mov rdx, [rbx+8]
XFGHelper::XFGHasher::add_function_type+167 lea r9, [rsp+48h+arg_10+1]
XFGHelper::XFGHasher::add_function_type+16C mov byte ptr [rsp+48h+arg_10], r8b ; value to add = is_var_args_function (byte)
XFGHelper::XFGHasher::add_function_type+16C ; [step 3]
XFGHelper::XFGHasher::add_function_type+171 mov rcx, rbx
XFGHelper::XFGHasher::add_function_type+174 lea r8, [rsp+48h+arg_10]
XFGHelper::XFGHasher::add_function_type+179 call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const ,uchar const ,std::forward_iterator_tag)

组成部分4:调用约定

最后,XFGHelper::XFGHasher::add_function_type会在std::vector中添加一个占用4字节的值,表示函数使用的调用约定。实际上,英特尔x64架构上的调用约定并不多(与x86对应的架构不同):对于默认的x64调用约定来说,将通过寄存器RCX、RDX、R8和R9传递整数参数,而浮点参数则通过XMM0-XMM3进行传递。这个默认的调用约定在内部是由值0x201来表示的,但由于它在保存到std::vector之前会使用掩码&0x0F进行处理(见下面通过反汇编得到的代码),因此,对于该调用约定来说,对应的是一个值为0x00000001的DWORD变量。

郑重声明,虽然MSVC x64编译器通常会忽略诸如__cdecl和__stdcall这样的限定符,但至少有一种方法可以为调用约定获得不同于0x201的值:__vectorcall调用约定在内部用值0x208表示,这意味着使用掩码&0x0F进行相应的处理后,会将一个值为0x00000008的DWORD写入到std::vector中。

负责将调用约定数据添加到std::vector的代码如下所示:

XFGHelper::XFGHasher::add_function_type+17E mov eax, [r15+4] ; eax = function_info->calling_convention
XFGHelper::XFGHasher::add_function_type+182 lea r9, [rsp+48h+arg_14]
XFGHelper::XFGHasher::add_function_type+187 mov rdx, [rbx+8]
XFGHelper::XFGHasher::add_function_type+18B lea r8, [rsp+48h+arg_10]
XFGHelper::XFGHasher::add_function_type+190 and eax, 0Fh ; eax = calling_convention & 0xF
XFGHelper::XFGHasher::add_function_type+193 mov rcx, rbx
XFGHelper::XFGHasher::add_function_type+196 mov [rsp+48h+arg_10], eax ; value to add = calling_convention & 0xF (size = dword)
XFGHelper::XFGHasher::add_function_type+196 ; [step 4]
XFGHelper::XFGHasher::add_function_type+19A call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const ,uchar const ,std::forward_iterator_tag)

组成部分5:返回类型的哈希值

第五个也是最后一个组成部分的数据将用于获取函数原型的哈希值,不过,它并不是在XFGHelper::XFGHasher::add_function_type内部获取的,而是在从中返回后直接添加的。正如你在下面的代码中所看到的,它调用了XFGHelper::XFGHasher::add_type,为代表返回类型的Type_t生成了一个8字节的哈希值,并将其添加到std::vector中。

XFGHelper__ComputeHash_1+BE call XFGHelper::XFGHasher::add_function_type(Type_t const ,XFGHelper::VirtualInfoFromDeclspec)
XFGHelper__ComputeHash_1+C3 mov rdx, rsi ; rdx = function->return_type (struct Type_t
)
XFGHelper__ComputeHash_1+C6 mov rcx, rbp ; this
XFGHelper__ComputeHash_1+C9 call XFGHelper::XFGHasher::add_type(Type_t const *) ; (step 5)

最后一步:为收集到的原型数据生成哈希值

如果函数中包含了来自__declspec的虚信息,那么就会根据该信息额外生成一个8字节的类型哈希值,并添加到std::vector中。然而,在我的测试过程中,并没有遇到这种特殊情况;如前所述,虚信息可能不适用于C代码。

不管是否存在来自__declspec的虚信息,XFGHelper__ComputeHash_1函数都会以调用XFGHelper::XFGHasher::get_hash函数来结束:

XFGHelper__ComputeHash_1+CE test rbx, rbx ; contains virtual info from __declspec?
XFGHelper__ComputeHash_1+D1 jz short loc_1801052EF
[...]
XFGHelper__ComputeHash_1+103 loc_1801052EF:
XFGHelper__ComputeHash_1+103 mov rcx, rbp ; this
XFGHelper__ComputeHash_1+106 mov rbx, [rsp+38h+arg_0]
XFGHelper__ComputeHash_1+10B mov rbp, [rsp+38h+arg_8]
XFGHelper__ComputeHash_1+110 mov rsi, [rsp+38h+arg_10]
XFGHelper__ComputeHash_1+115 add rsp, 30h
XFGHelper__ComputeHash_1+119 pop rdi
XFGHelper__ComputeHash_1+11A jmp XFGHelper::XFGHasher::get_hash(void)
XFGHelper__ComputeHash_1+11A XFGHelper__ComputeHash_1 endp

XFGHelper::XFGHasher::get_hash方法用于生成已经收集到的std::vector中的类型数据的哈希值。在这里,使用的哈希算法是SHA256,正如在下面XFGHelper::XFGHasher::get_hash+5F处所看到的,它只返回生成的SHA256摘要的前8个字节:

XFGHelper::XFGHasher::get_hash(void) public: unsigned __int64 XFGHelper::XFGHasher::get_hash(void)const proc near
[...]
XFGHelper::XFGHasher::get_hash(void)+18 mov dl, 3 ; algorithm_ids[3] == CALG_SHA_256
XFGHelper::XFGHasher::get_hash(void)+1A lea rcx, [rsp+58h+hHash] ; phHash
XFGHelper::XFGHasher::get_hash(void)+1F call HashAPIWrapper::HashAPIWrapper(uchar)
XFGHelper::XFGHasher::get_hash(void)+24 nop
XFGHelper::XFGHasher::get_hash(void)+25 mov r8, [rbx+8]
XFGHelper::XFGHasher::get_hash(void)+29 sub r8, [rbx] ; dwDataLen
XFGHelper::XFGHasher::get_hash(void)+2C xor r9d, r9d ; dwFlags
XFGHelper::XFGHasher::get_hash(void)+2F mov rdx, [rbx] ; pbData
XFGHelper::XFGHasher::get_hash(void)+32 mov rcx, [rsp+58h+hHash] ; hHash
XFGHelper::XFGHasher::get_hash(void)+37 call cs:__imp_CryptHashData
XFGHelper::XFGHasher::get_hash(void)+3D test eax, eax
XFGHelper::XFGHasher::get_hash(void)+3F jnz short loc_180105822
[...]
XFGHelper::XFGHasher::get_hash(void)+4A loc_180105822:
XFGHelper::XFGHasher::get_hash(void)+4A mov r8d, 20h ; ' ' ; unsigned int
XFGHelper::XFGHasher::get_hash(void)+50 lea rdx, [rsp+58h+sha256_digest] ; unsigned __int8 *
XFGHelper::XFGHasher::get_hash(void)+55 lea rcx, [rsp+58h+hHash] ; this
XFGHelper::XFGHasher::get_hash(void)+5A call HashAPIWrapper::GetHash(uchar ,ulong)
XFGHelper::XFGHasher::get_hash(void)+5F mov rbx, qword ptr [rsp+58h+sha256_digest] ;
** only returns first 8 bytes of SHA256 hash
XFGHelper::XFGHasher::get_hash(void)+64 mov rcx, [rsp+58h+hHash] ; hHash
XFGHelper::XFGHasher::get_hash(void)+69 call cs:__imp_CryptDestroyHash
XFGHelper::XFGHasher::get_hash(void)+6F test eax, eax
XFGHelper::XFGHasher::get_hash(void)+71 jnz short loc_180105854
[...]
XFGHelper::XFGHasher::get_hash(void)+7C loc_180105854:
XFGHelper::XFGHasher::get_hash(void)+7C mov rax, rbx
XFGHelper::XFGHasher::get_hash(void)+7F mov rcx, [rsp+58h+var_10]
XFGHelper::XFGHasher::get_hash(void)+84 xor rcx, rsp ; StackCookie
XFGHelper::XFGHasher::get_hash(void)+87 call __security_check_cookie
XFGHelper::XFGHasher::get_hash(void)+8C add rsp, 50h
XFGHelper::XFGHasher::get_hash(void)+90 pop rbx
XFGHelper::XFGHasher::get_hash(void)+91 retn

为各种类型生成哈希值

到目前为止,我们知道一个函数原型的哈希值是根据5段信息创建的。其中3段信息是普通的数值(一个表示参数数量的值,一个表示函数参数是否可变的布尔值,以及一个代表调用约定的数字),但另外2段信息则来自类型哈希值本身(每个函数参数的类型哈希值,以及返回类型的哈希值)。在本节中,我们将介绍各种类型(由编译器内部用Type_t对象表示)的哈希值是如何生成的。

类型的哈希值是通过XFGHelper::XFGHasher::add_type函数进行处理的。实际上,该函数会调用XFGHelper__GetHashForType,后者会返回一个8字节的类型哈希值,然后,通过调用std::vector::_Insert_range()将这个8字节的哈希值存储到std::vector中。

.text:00000001801056A0 public: void XFGHelper::XFGHasher::add_type(class Type_t const ) proc near
.text:00000001801056A0 arg_0 = qword ptr 8
.text:00000001801056A0 arg_8 = byte ptr 10h
.text:00000001801056A0
.text:00000001801056A0 push rbx
.text:00000001801056A2 sub rsp, 30h
.text:00000001801056A6 mov rbx, rcx
.text:00000001801056A9 mov rcx, rdx ; rcx = Type_t
.text:00000001801056AC call XFGHelper__GetHashForType
.text:00000001801056B1 mov rdx, [rbx+8]
.text:00000001801056B5 lea r9, [rsp+38h+arg_8]
.text:00000001801056BA lea r8, [rsp+38h+arg_0]
.text:00000001801056BF mov [rsp+38h+arg_0], rax ; value to add = hash (qword)
.text:00000001801056C4 mov rcx, rbx
.text:00000001801056C7 call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const
,uchar const *,std::forward_iterator_tag)
.text:00000001801056CC add rsp, 30h
.text:00000001801056D0 pop rbx
.text:00000001801056D1 retn

现在,让我们看看XFGHelper__GetHashForType是如何为给定的Type_t生成一个8字节的哈希值的。首先,它通过调用std:Tree::emplace()来检查给定类型的哈希值是否已经存在于其缓存中,这一点可以在XFGHelper__GetHashForType+AF处看到。如果已存在的话,它会直接返回缓存的类型哈希值,从而避免重复计算。

另一方面,如果在缓存中没有找到类型的哈希值,它就会通过调用XFGHelper::XFGTypeHasher::compute_hash从头开始计算,这时会先给需要计算哈希值的类型数据建立一个std::vector,然后,调用XFGHelper::XFGHasher::get_hash(我们已经在上一节见过它),为存放在std::vector中的数据产生一个SHA256摘要,并只返回该摘要的前8个字节。

XFGHelper__GetHashForType XFGHelper__GetHashForType proc near
[...]
XFGHelper__GetHashForType+A3 lea r9, [rbp+arg_8]
XFGHelper__GetHashForType+A7 lea r8, [rbp+Type_t]
XFGHelper__GetHashForType+AB lea rdx, [rbp+xfg_type_hasher]
XFGHelper__GetHashForType+AF call std::_Tree,std::allocator>,0>>::_Emplace(Type_t const * &,int &&)
XFGHelper__GetHashForType+B4 mov rbx, qword ptr [rbp+xfg_type_hasher]
XFGHelper__GetHashForType+B8 cmp byte ptr [rbp+xfg_type_hasher+8], 0 ; hash for type was found in cache?
XFGHelper__GetHashForType+BC jz short loc_18010544D ; if so, just return the cached hash
XFGHelper__GetHashForType+BE xor edi, edi ; otherwise, compute the hash of the type
XFGHelper__GetHashForType+C0 xorps xmm0, xmm0
XFGHelper__GetHashForType+C3 movdqu [rbp+xfg_type_hasher], xmm0
XFGHelper__GetHashForType+C8 and [rbp+var_10], rdi
XFGHelper__GetHashForType+CC mov [rbp+var_8], 1
XFGHelper__GetHashForType+D0 mov rdx, [rbp+Type_t] ; struct Type_t *
XFGHelper__GetHashForType+D4 lea rcx, [rbp+xfg_type_hasher] ; this
XFGHelper__GetHashForType+D8 call XFGHelper::XFGTypeHasher::compute_hash(Type_t const *)
XFGHelper__GetHashForType+DD nop
XFGHelper__GetHashForType+DE cmp [rbp+var_8], dil
XFGHelper__GetHashForType+E2 jz short loc_180105434
XFGHelper__GetHashForType+E4 lea rcx, [rbp+xfg_type_hasher] ; this
XFGHelper__GetHashForType+E8 call XFGHelper::XFGHasher::get_hash(void)
[...]

下面是XFGHelper::XFGTypeHasher::compute_hash需要为给定类型收集的相关信息:

1个由类型限定符导出的字节值(从Type_t对象的偏移量4处获取)。
1个字节,表示该类型所属种类(指针、联合体/结构体/枚举或基本类型)。
一些特定于类型的数据,它们取决于该类型属于2)中提到的三个大类(指针、联合体/结构体/枚举或基本类型)中的哪一类。

我们将在下面的小节中详细介绍这三种信息。

组成部分1:类型限定符

关于类型的第一种信息是它的限定符,它以DWORD形式存储在Type_t对象的偏移量4处。需要注意的是,const (0x800)和volatile (0x40)限定符的信息会被合并为一个字节写入std::vector中。这个新字节的第一个位表示const限定符是否存在,而第二个位表示volatile限定符是否存在。

XFGHelper::XFGTypeHasher::compute_hash+1B call Type_t::getFirstNonArrayType(void)
XFGHelper::XFGTypeHasher::compute_hash+20 mov rcx, rdi ; this
XFGHelper::XFGTypeHasher::compute_hash+23 mov r8d, [rax+4] ; r8d = Type_t->qualifiers
XFGHelper::XFGTypeHasher::compute_hash+27 shr r8d, 0Bh
XFGHelper::XFGTypeHasher::compute_hash+2B and r8b, 1
XFGHelper::XFGTypeHasher::compute_hash+2F movzx r9d, r8b ; r9d = (Type_t->qualifiers >> 0xB) & 1 (has_const_qualifier)
XFGHelper::XFGTypeHasher::compute_hash+33 call Type_t::getFirstNonArrayType(void)
XFGHelper::XFGTypeHasher::compute_hash+38 lea r8, [rbp+arg_0]
XFGHelper::XFGTypeHasher::compute_hash+3C mov edx, [rax+4] ; edx = Type_t->qualifiers
XFGHelper::XFGTypeHasher::compute_hash+3F mov al, r9b ; al = has_const_qualifier
XFGHelper::XFGTypeHasher::compute_hash+42 or al, 2 ; al = has_const_qualifier | 2
XFGHelper::XFGTypeHasher::compute_hash+44 and dl, 40h ; dl = Type_t->qualifiers & 0x40 (has_volatile_qualifier)
XFGHelper::XFGTypeHasher::compute_hash+47 movzx ecx, al ; qualifiers_info = has_const_qualifier | 2
XFGHelper::XFGTypeHasher::compute_hash+4A mov rdx, [rbx+8]
XFGHelper::XFGTypeHasher::compute_hash+4E cmovz ecx, r9d ; if it doesn't have volatile qualifier, then
XFGHelper::XFGTypeHasher::compute_hash+4E ; qualifiers_info = has_const_qualifier
XFGHelper::XFGTypeHasher::compute_hash+52 lea r9, [rbp+arg_1]
XFGHelper::XFGTypeHasher::compute_hash+56 mov [rbp+arg_0], cl ; value to insert (size = byte)
XFGHelper::XFGTypeHasher::compute_hash+59 mov rcx, rbx
XFGHelper::XFGTypeHasher::compute_hash+5C call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const ,uchar const ,std::forward_iterator_tag)

组成部分2:类型组

如果存储在Type_t中的类型值被设为0x100,那么它就是一个指针。这是通过向std::vector写入一个值为3的字节来表示的。

XFGHelper::XFGTypeHasher::compute_hash+61 test dword ptr [rdi], 100h ; Type_t & 0x100 == 0 ?
XFGHelper::XFGTypeHasher::compute_hash+67 jz short loc_180105762
XFGHelper::XFGTypeHasher::compute_hash+69 mov rdx, [rbx+8] ; if not, it's a pointer
XFGHelper::XFGTypeHasher::compute_hash+6D lea r9, [rbp+arg_1]
XFGHelper::XFGTypeHasher::compute_hash+71 lea r8, [rbp+arg_0]
XFGHelper::XFGTypeHasher::compute_hash+75 mov [rbp+arg_0], 3 ; value to insert: POINTER_TYPE (3)
XFGHelper::XFGTypeHasher::compute_hash+79 mov rcx, rbx
XFGHelper::XFGTypeHasher::compute_hash+7C call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const
,uchar const *,std::forward_iterator_tag)

如果类型不是指针,那么它就会通过检查存储在Type_t & 0x600中的类型值是否不是0来判断它是联合体类型、结构体类型还是枚举类型。请注意,0x600是通过0x200 | 0x400得到的,其中0x200代表枚举类型,0x400代表结构体和联合体类型。如果出现这种情况,一个值为2的字节将被写入std::vector中。

XFGHelper::XFGTypeHasher::compute_hash+8E loc_180105762:
XFGHelper::XFGTypeHasher::compute_hash+8E test dword ptr [rdi], 600h ; Type_t & (0x400 | 0x200) == 0 ?
XFGHelper::XFGTypeHasher::compute_hash+94 jz short loc_180105790
XFGHelper::XFGTypeHasher::compute_hash+96 mov rdx, [rbx+8] ; if not, it's a union/struct/enum
XFGHelper::XFGTypeHasher::compute_hash+9A lea r9, [rbp+arg_1]
XFGHelper::XFGTypeHasher::compute_hash+9E lea r8, [rbp+arg_0]
XFGHelper::XFGTypeHasher::compute_hash+A2 mov [rbp+arg_0], 2 ; value to insert: UNION_STRUCT_OR_ENUM_TYPE (2)
XFGHelper::XFGTypeHasher::compute_hash+A6 mov rcx, rbx
XFGHelper::XFGTypeHasher::compute_hash+A9 call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const
,uchar const *,std::forward_iterator_tag)

最后,如果该类型既不是指针,也不是联合体/结构体/枚举类型,则采用默认情况。如果该类型是泛型,则不会向std::vector写入任何内容(但这是一种边缘情况,只影响那些设置了值0x1000的类型,以及用值0x8103标识的类型)。否则,对于绝大多数基本类型来说,将向std::vector添加一个值为1的字节。

XFGHelper::XFGTypeHasher::compute_hash+BC loc_180105790:
XFGHelper::XFGTypeHasher::compute_hash+BC mov rcx, rdi ; this
XFGHelper::XFGTypeHasher::compute_hash+BF call Type_t::isGeneric(void)
XFGHelper::XFGTypeHasher::compute_hash+C4 test al, al
XFGHelper::XFGTypeHasher::compute_hash+C6 jz short loc_1801057A2
XFGHelper::XFGTypeHasher::compute_hash+C8 mov byte ptr [rbx+18h], 0
XFGHelper::XFGTypeHasher::compute_hash+CC jmp short epilog
XFGHelper::XFGTypeHasher::compute_hash+CE loc_1801057A2:
XFGHelper::XFGTypeHasher::compute_hash+CE mov rdx, [rbx+8]
XFGHelper::XFGTypeHasher::compute_hash+D2 lea r9, [rbp+arg_1]
XFGHelper::XFGTypeHasher::compute_hash+D6 lea r8, [rbp+arg_0]
XFGHelper::XFGTypeHasher::compute_hash+DA mov [rbp+arg_0], 1 ; value to insert: PRIMITIVE_TYPE (1)
XFGHelper::XFGTypeHasher::compute_hash+DE mov rcx, rbx
XFGHelper::XFGTypeHasher::compute_hash+E1 call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const ,uchar const ,std::forward_iterator_tag)

组成部分3:特定于类型的数据

生成指针类型的哈希值

对于指针类型,在向std::vector写入一个值为3的字节后,还会调用XFGHelper::XFGTypeHasher::hash_indirection函数。要知道,这里所说的“指针”的定义比较宽泛,因为它包括了所有那些值被设置为0x100的Type_t对象。除了常规的C指针,还包括一种内部函数对象(由函数指针引用)和数组。

XFGHelper::XFGTypeHasher::compute_hash+81 mov rdx, rdi ; struct Type_t *
XFGHelper::XFGTypeHasher::compute_hash+84 mov rcx, rbx ; this
XFGHelper::XFGTypeHasher::compute_hash+87 call XFGHelper::XFGTypeHasher::hash_indirection
XFGHelper::XFGTypeHasher::compute_hash+8C jmp short epilog

顾名思义,函数XFGHelper::XFGTypeHasher::hash_indirection的作用是将指针引用的类型的哈希值添加到std::vector中。它的行为取决于它所处理的指针类型。

如果它是函数指针(Type_t值为0x106)或Type_t值为0x102的“泛型”指针(用于大多数类型的指针,函数指针除外),它会通过调用XFGHelper::XFGHasher::add_type函数,添加该指针引用的Type_t的哈希值,并加上一个值为2的字节。对于函数指针情况而言,指针引用的Type_t是一种内部函数对象,Type_t值为0x101,这意味着它也在XFGHelper::XFGTypeHasher::hash_indirection内进行相应的处理。

XFGHelper::XFGTypeHasher::hash_indirection+15 mov ecx, [rdx] ; ecx = Type_t
XFGHelper::XFGTypeHasher::hash_indirection+17 mov eax, ecx
XFGHelper::XFGTypeHasher::hash_indirection+19 and eax, 10Fh
[...]
XFGHelper::XFGTypeHasher::hash_indirection+25 sub eax, 1 ; case 0x102 (general pointer):
XFGHelper::XFGTypeHasher::hash_indirection+28 jz short loc_1801058E3
[...]
XFGHelper::XFGTypeHasher::hash_indirection+2F cmp eax, 3 ; case 0x106 (function pointer):
XFGHelper::XFGTypeHasher::hash_indirection+32 jz short loc_1801058E3
[...]
XFGHelper::XFGTypeHasher::hash_indirection+6B loc_1801058E3:
XFGHelper::XFGTypeHasher::hash_indirection+6B mov dil, 2 ; will be written to std::vector
XFGHelper::XFGTypeHasher::hash_indirection+6E jmp short loc_1801058F6
[...]
XFGHelper::XFGTypeHasher::hash_indirection+7E loc_1801058F6:
XFGHelper::XFGTypeHasher::hash_indirection+7E mov rdx, [rsi+8] ; rdx = ptr to the Type_t referenced by the pointer
XFGHelper::XFGTypeHasher::hash_indirection+7E ; (return type in the case of functions)
XFGHelper::XFGTypeHasher::hash_indirection+82 mov rcx, rbx ; this
XFGHelper::XFGTypeHasher::hash_indirection+85 call XFGHelper::XFGHasher::add_type
XFGHelper::XFGTypeHasher::hash_indirection+8A mov rdx, [rbx+8]
XFGHelper::XFGTypeHasher::hash_indirection+8E lea r9, [rsp+38h+arg_8+1]
XFGHelper::XFGTypeHasher::hash_indirection+93 lea r8, [rsp+38h+arg_8]
XFGHelper::XFGTypeHasher::hash_indirection+98 mov byte ptr [rsp+38h+arg_8], dil ; value to insert (size = byte)
XFGHelper::XFGTypeHasher::hash_indirection+9D mov rcx, rbx
XFGHelper::XFGTypeHasher::hash_indirection+A0 call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const
,uchar const *,std::forward_iterator_tag)

如果它是一个函数对象(由Type_t值为0x101标识,通常被Type_t值为0x106的函数指针引用),则先通过调用XFGHelper::XFGHasher::add_function_type函数(其内部工作原理我们已经剖析过了)来添加函数原型的哈希值 ,然后加上函数返回类型的哈希值,再加上一个值为1的字节。

XFGHelper::XFGTypeHasher::hash_indirection+15 mov ecx, [rdx] ; ecx = Type_t
XFGHelper::XFGTypeHasher::hash_indirection+17 mov eax, ecx
XFGHelper::XFGTypeHasher::hash_indirection+19 and eax, 10Fh
XFGHelper::XFGTypeHasher::hash_indirection+1E sub eax, 101h ; case 0x101 (function):
XFGHelper::XFGTypeHasher::hash_indirection+23 jz short loc_1801058E8
[...]
XFGHelper::XFGTypeHasher::hash_indirection+70 xor r8d, r8d
XFGHelper::XFGTypeHasher::hash_indirection+73 mov rcx, rbx
XFGHelper::XFGTypeHasher::hash_indirection+76 mov dil, 1 ; this is written to std::vector at the end of this function
XFGHelper::XFGTypeHasher::hash_indirection+79 call XFGHelper::XFGHasher::add_function_type(Type_t const
,XFGHelper::VirtualInfoFromDeclspec)
XFGHelper::XFGTypeHasher::hash_indirection+7E
XFGHelper::XFGTypeHasher::hash_indirection+7E loc_1801058F6:
XFGHelper::XFGTypeHasher::hash_indirection+7E ; XFGHelper::XFGTypeHasher::hash_indirection+6E↑j
XFGHelper::XFGTypeHasher::hash_indirection+7E mov rdx, [rsi+8] ; rdx = ptr to the Type_t referenced by the pointer
XFGHelper::XFGTypeHasher::hash_indirection+7E ; (return type in the case of functions)
XFGHelper::XFGTypeHasher::hash_indirection+82 mov rcx, rbx ; this
XFGHelper::XFGTypeHasher::hash_indirection+85 call XFGHelper::XFGHasher::add_type
XFGHelper::XFGTypeHasher::hash_indirection+8A mov rdx, [rbx+8]
XFGHelper::XFGTypeHasher::hash_indirection+8E lea r9, [rsp+38h+arg_8+1]
XFGHelper::XFGTypeHasher::hash_indirection+93 lea r8, [rsp+38h+arg_8]
XFGHelper::XFGTypeHasher::hash_indirection+98 mov byte ptr [rsp+38h+arg_8], dil ; value to insert (size = byte)
XFGHelper::XFGTypeHasher::hash_indirection+9D mov rcx, rbx
XFGHelper::XFGTypeHasher::hash_indirection+A0 call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const ,uchar const ,std::forward_iterator_tag)

最后,如果是一个数组(用Type_t值0x103来标识),则写入一个QWORD,取值为数组元素的数量,加上数组元素的类型哈希值,再加上一个值为6的字节。

XFGHelper::XFGTypeHasher::hash_indirection+15 mov ecx, [rdx] ; ecx = Type_t
XFGHelper::XFGTypeHasher::hash_indirection+17 mov eax, ecx
XFGHelper::XFGTypeHasher::hash_indirection+19 and eax, 10Fh
[...]
XFGHelper::XFGTypeHasher::hash_indirection+2A sub eax, 1 ; case 0x103 (array passed by pointer):
XFGHelper::XFGTypeHasher::hash_indirection+2D jz short loc_1801058B2
[...]
XFGHelper::XFGTypeHasher::hash_indirection+3A loc_1801058B2:
XFGHelper::XFGTypeHasher::hash_indirection+3A lea eax, [rcx-4103h]
XFGHelper::XFGTypeHasher::hash_indirection+40 mov dil, 6 ; will be written to std::vector
XFGHelper::XFGTypeHasher::hash_indirection+43 test eax, 0FFFFBFFFh
XFGHelper::XFGTypeHasher::hash_indirection+48 jz short loc_1801058AC
XFGHelper::XFGTypeHasher::hash_indirection+4A mov rax, [rdx+10h] ; rax = number of elems in array
XFGHelper::XFGTypeHasher::hash_indirection+4E lea r9, [rsp+38h+arg_10]
XFGHelper::XFGTypeHasher::hash_indirection+53 mov rdx, [rbx+8]
XFGHelper::XFGTypeHasher::hash_indirection+57 lea r8, [rsp+38h+arg_8]
XFGHelper::XFGTypeHasher::hash_indirection+5C mov rcx, rbx
XFGHelper::XFGTypeHasher::hash_indirection+5F mov [rsp+38h+arg_8], rax ; value to insert: number of elems in array (size = qword)
XFGHelper::XFGTypeHasher::hash_indirection+64 call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const
,uchar const ,std::forward_iterator_tag)
XFGHelper::XFGTypeHasher::hash_indirection+69 jmp short loc_1801058F6
[...]
XFGHelper::XFGTypeHasher::hash_indirection+7E loc_1801058F6
XFGHelper::XFGTypeHasher::hash_indirection+7E mov rdx, [rsi+8] ; rdx = ptr to the Type_t referenced by the pointer
XFGHelper::XFGTypeHasher::hash_indirection+7E ; (return type in the case of functions)
XFGHelper::XFGTypeHasher::hash_indirection+82 mov rcx, rbx ; this
XFGHelper::XFGTypeHasher::hash_indirection+85 call XFGHelper::XFGHasher::add_type
XFGHelper::XFGTypeHasher::hash_indirection+8A mov rdx, [rbx+8]
XFGHelper::XFGTypeHasher::hash_indirection+8E lea r9, [rsp+38h+arg_8+1]
XFGHelper::XFGTypeHasher::hash_indirection+93 lea r8, [rsp+38h+arg_8]
XFGHelper::XFGTypeHasher::hash_indirection+98 mov byte ptr [rsp+38h+arg_8], dil ; value to insert (size = byte)
XFGHelper::XFGTypeHasher::hash_indirection+9D mov rcx, rbx
XFGHelper::XFGTypeHasher::hash_indirection+A0 call std::vector::_Insert_range(std::_Vector_const_iterator>>,uchar const
,uchar const *,std::forward_iterator_tag)

小结

在本文中,我们为读者深入分析各种类型的哈希值是如何生成的,在接下来的文章中,我们将通过手工方式计算一个XFG型哈希值,以验证我们是否真正理解了XFG型哈希值的生成方式。

(未完待续)