日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

编译原理实验语义分析_Windows MVSC编译器实现Xtended Flow Guard(XFG)保护机制的原理分析...

發(fā)布時間:2025/3/15 windows 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编译原理实验语义分析_Windows MVSC编译器实现Xtended Flow Guard(XFG)保护机制的原理分析... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、前言

近期,微軟正在開發(fā)Xtended Flow Guard(XFG),這是Control Flow Guard(控制流防護(hù),CFG)的演進(jìn)版本,作為其自身的控制流完整性實(shí)現(xiàn)。XFG通過不同類型函數(shù)原型的哈希值,限制間接控制流的轉(zhuǎn)移。在這篇文章中,深入討論了MSVC編譯器是如何生成XFG函數(shù)的原型哈希值。

二、概述

2014年,微軟推出了名為“Control Flow Integrity”(控制流防護(hù),CFG)的控制流完整性(CFI)解決方案。在此前,已經(jīng)有很多研究人員對CFG展開了廣泛的研究。隨著時間的推移,接連發(fā)現(xiàn)了許多繞過CFG的方法。其中一些繞過依賴于實(shí)現(xiàn)上的問題(例如JIT編譯器的集成,或可以濫用敏感的API),但最終都得到了解決。但是,有一個設(shè)計上的問題始終存在——CFG沒有提供有效調(diào)用目標(biāo)的任何粒度。任何受保護(hù)的間接調(diào)用都被允許去調(diào)用任何有效的調(diào)用目標(biāo)。在體積較大的二進(jìn)制文件中,有效的調(diào)用目標(biāo)可能會達(dá)到上千個,這就讓攻擊者擁有了足夠的靈活性,可以通過串聯(lián)有效的C++虛擬函數(shù)來繞過CFG(例如:偽造的面向?qū)ο缶幊淘O(shè)計,COOP)。

我們把時間線快進(jìn)幾年。微軟一直在開發(fā)CFG的改進(jìn)版本,被稱為“Xtended Flow Guard”(XFG)。XFG通過類型簽名檢查限制間接調(diào)用或跳轉(zhuǎn),從而提供了更細(xì)粒度的CFI。XFG背后的一個關(guān)鍵概念是,在編譯時將基于類型簽名的哈希分配給那些可以作為間接調(diào)用/跳轉(zhuǎn)目標(biāo)的函數(shù)。然后,在XFG指示的間接調(diào)用點(diǎn)上,進(jìn)行哈希檢查,僅允許具有預(yù)期簽名哈希的函數(shù)。

幾周前,研究員Connor McGarr發(fā)表了一篇文章,名為《漏洞利用開發(fā):在巖石和XFG之間》,文章說明了XFG的工作方式及其潛在弱點(diǎn)。這篇文章激發(fā)了我的好奇心,因此我希望使用IDA Pro和Windbg,以了解XFG哈希是如何生成的。

在撰寫本文時,Windows 10 Insider Preview(開發(fā)者)版本中已經(jīng)應(yīng)用了XFG。如果想要編譯支持XFG的程序,需要使用Visual Studio 2019預(yù)覽版。

本文的分析基于Visual Studio 2019 16.8.0版本 Preview 2.1的二進(jìn)制文件:

· c1.dll version 19.28.29213.0

· c2.dll version 19.28.29213.0

這篇文章重點(diǎn)介紹如何針對C語言源代碼生成XFG哈希。盡管初步看起來C++代碼的哈希算法看起來非常相似,但是我們尚未研究其具體細(xì)節(jié)。由于這篇文章篇幅較長,所以分為了幾個部分。首先,從XFG哈希的快速入門開始。然后,分析如何對函數(shù)進(jìn)行哈希處理,詳細(xì)介紹如何對不同的C類型進(jìn)行哈希處理。最后,我們檢查應(yīng)用于計算哈希的一些最終轉(zhuǎn)換,并通過嘗試計算哈希來得出結(jié)論。

三、XFG哈希快速入門

我們先從一個非常簡單的C語言程序開始,定義一個名為FPTR ([1])的函數(shù)指針類型,該函數(shù)聲明一個帶有兩個float參數(shù)并返回另一個float的函數(shù)。函數(shù)main聲明一個類型為FPTR、名為fptr的函數(shù)指針變量,該變量設(shè)置為函數(shù)foo ([2])的地址,該函數(shù)的原型與FPTR類型匹配。最后,在[3]的位置,調(diào)用fptr指向的函數(shù),并將值1.00001和2.00002作為參數(shù)傳遞。

? ? #include ?< stdio.h >?

[1] typedef float (* FPTR)(float, float);

? ? float foo(float val1, float val2){

? ? ? ? printf("I received float values %f and %f\n", val1, val2);

? ? ? ? return (val2 - val1);

? ? }

? ? int main(int argc, char **argv){

[2] ? ? FPTR fptr = foo;

? ? ? ? printf("Calling function pointer...\n");

[3] ? ? fptr(1.00001, 2.00002);

? ? ? ? return 0;

? ? }

我們使用以下命令行,用VS 2019 Preview的x64本地工具命令提示符中編譯了上述源代碼。這里使用到了/guard:xfg標(biāo)志,以啟用XFG。

> ?cl /Zi /guard:xfg example1.c

反匯編后的主要函數(shù)如下所示:

main ? ? ?; int __cdecl main(int argc, const char **argv, const char **envp)

main

main ? ? ?var_18 ? ? ? ? ?= qword ptr -18h

main ? ? ?var_10 ? ? ? ? ?= qword ptr -10h

main ? ? ?arg_0 ? ? ? ? ? = dword ptr ?8

main ? ? ?arg_8 ? ? ? ? ? = qword ptr ?10h

main

main ? ? ? ? ?mov ? ? [rsp+arg_8], rdx

main+5 ? ? ? ?mov ? ? [rsp+arg_0], ecx

main+9 ? ? ? ?sub ? ? rsp, 38h

main+D ? ? ? ?lea ? ? rax, foo

main+14 ? ? ? mov ? ? [rsp+38h+var_18], rax

main+19 ? ? ? lea ? ? rcx, aCallingFunctio ; "Calling function pointer...\n"

main+20 ? ? ? call ? ?printf

main+25 ? ? ? mov ? ? rax, [rsp+38h+var_18]

main+2A ? ? ? mov ? ? [rsp+38h+var_10], rax

main+2F ? ? ? mov ? ? r10, 99743F3270D52870h

main+39 ? ? ? movss ? xmm1, cs:__real@40000054

main+41 ? ? ? movss ? xmm0, cs:__real@3f800054

main+49 ? ? ? mov ? ? rax, [rsp+38h+var_10]

main+4E ? ? ? call ? ?cs:__guard_xfg_dispatch_icall_fptr

main+54 ? ? ? xor ? ? eax, eax

main+56 ? ? ? add ? ? rsp, 38h

main+5A ? ? ? retn

main+5A ? main ? ? ? ? ? ?endp

我們可以在main+0x2F處看到,對于在main + 0x4E處之后的函數(shù)指針調(diào)用,R10寄存器被設(shè)置為預(yù)期的基于類型的哈希(0x99743F3270D52870)。通過函數(shù)指針調(diào)用的函數(shù)是foo,我們可以驗(yàn)證其原型哈希(由函數(shù)開頭的前8個字節(jié)表示)是否與預(yù)期的哈希匹配。這意味著,函數(shù)foo是main+0x4E上間接調(diào)用的有效目標(biāo)。準(zhǔn)確的說,原型哈希位于foo函數(shù)(0x99743F3270D52871)之前的8個字節(jié),與我們在R10寄存器(0x99743F3270D52870)中看到的預(yù)期哈希相匹配,除了第0位之外。

.text:0000000140001008 ? ? ? ? ? ? ? ? dq 99743F3270D52871h

foo

foo ? ? ?; =============== S U B R O U T I N E ================================

foo ? ? ?; float __fastcall foo(float val1, float val2)

foo ? ? ?foo ? ? ? ? ? ? proc near ? ? ? ? ? ? ? ; DATA XREF: main+D

foo

foo ? ? ?arg_0 ? ? ? ? ? = dword ptr ?8

foo ? ? ?arg_8 ? ? ? ? ? = dword ptr ?10h

foo

foo ? ? ? ? ?movss ? [rsp+arg_8], xmm1

foo+6 ? ? ? ?movss ? [rsp+arg_0], xmm0

foo+C ? ? ? ?sub ? ? rsp, 28h

foo+10 ? ? ? cvtss2sd xmm0, [rsp+28h+arg_8]

foo+16 ? ? ? cvtss2sd xmm1, [rsp+28h+arg_0]

foo+1C ? ? ? movaps ?xmm2, xmm0

foo+1F ? ? ? movq ? ?r8, xmm2

foo+24 ? ? ? movq ? ?rdx, xmm1

foo+29 ? ? ? lea ? ? rcx, _Format ? ?; "I received float values %f and %f\n"

foo+30 ? ? ? call ? ?printf

foo+35 ? ? ? movss ? xmm0, [rsp+28h+arg_8]

foo+3B ? ? ? subss ? xmm0, [rsp+28h+arg_0]

foo+41 ? ? ? add ? ? rsp, 28h

foo+45 ? ? ? retn

foo+45 ? foo ? ? ? ? ? ? endp

但是無需擔(dān)心這里的差異,因?yàn)樵赬FG調(diào)度函數(shù)(ntdll!LdrpDispatchUserCallTargetXFG)的開始處,R10的第0位被設(shè)置了,導(dǎo)致預(yù)期哈希值和函數(shù)哈希值在第0位上的差異沒有意義。

LdrpDispatchUserCallTargetXFG ? ? ?LdrpDispatchUserCallTargetXFG proc near

LdrpDispatchUserCallTargetXFG ? ? ?; __unwind { // LdrpICallHandler

LdrpDispatchUserCallTargetXFG ? ? ? ? ?or ? ? ?r10, 1

LdrpDispatchUserCallTargetXFG+4 ? ? ? ?test ? ?al, 0Fh

LdrpDispatchUserCallTargetXFG+6 ? ? ? ?jnz ? ? short loc_180094337

LdrpDispatchUserCallTargetXFG+8 ? ? ? ?test ? ?ax, 0FFFh

LdrpDispatchUserCallTargetXFG+C ? ? ? ?jz ? ? ?short loc_180094337

LdrpDispatchUserCallTargetXFG+E ? ? ? ?cmp ? ? r10, [rax-8]

LdrpDispatchUserCallTargetXFG+12 ? ? ? jnz ? ? short loc_180094337

LdrpDispatchUserCallTargetXFG+14 ? ? ? jmp ? ? rax

四、哈希函數(shù)類型

MSVC編譯器由兩個部分組成——前端和后端。前端是特定于某一語言的,負(fù)責(zé)讀取源代碼、詞法、解析、進(jìn)行語義分析和發(fā)出IL(中間語言)。后端是特定于某一目標(biāo)體系結(jié)構(gòu)的,它讀取前端生成的IL,進(jìn)行優(yōu)化,并為特定體系結(jié)構(gòu)生成代碼。

函數(shù)原型哈希的生成是由語言前端進(jìn)行的。這意味著在編譯C語言代碼時,C語言前端(c1.dll)負(fù)責(zé)生成原型哈希,而在編譯C++代碼時,C++前端(c1xx.dll)負(fù)責(zé)這個任務(wù)。

一旦相應(yīng)的語言前端生成了原型哈希,就會由編譯器后端(在這里是x64的后端c2.dll)執(zhí)行一些最終轉(zhuǎn)換。接下來,我們將詳細(xì)介紹在編譯C代碼時創(chuàng)建原型哈希的每個步驟。

在使用/guard:xfg標(biāo)志編譯C語言源代碼時,編譯器前端會調(diào)用c1!XFGHelper__ComputeHash_1函數(shù),以計算要處理的函數(shù)的原型哈希。

c1!XFGHelper__ComputeHash_1函數(shù)創(chuàng)建一個類型為XFGHelper::XFGHasher的對象,該對象負(fù)責(zé)收集正在處理的函數(shù)的類型信息,并根據(jù)收集的類型信息生成原型哈希。XFGHelper::XFGHasher使用std::vector的實(shí)例存儲所有即將被計算哈希的類型信息,并且提供了在計算哈希的整個過程中調(diào)用的多個方法:

? ? XFGHelper::XFGHasher::add_function_type()

? ? XFGHelper::XFGHasher::add_type()

? ? XFGHelper::XFGHasher::get_hash()

? ? XFGHelper::XFGTypeHasher::compute_hash()

? ? XFGHelper::XFGTypeHasher::hash_indirection()

? ? XFGHelper::XFGTypeHasher::hash_tag()

? ? XFGHelper::XFGTypeHasher::hash_primitive()

在初始化XFGHelper::XFGHasher的實(shí)例后,XFGHelper__ComputeHash_1函數(shù)調(diào)用XFGHelper::XFGHasher::add_function_type(),將XFGHelper::XFGHasher實(shí)例和一個Type_t對象作為參數(shù)傳遞,該對象包含有關(guān)哈希函數(shù)的類型信息。

XFGHelper__ComputeHash_1 ? ? ?XFGHelper__ComputeHash_1 proc near

XFGHelper__ComputeHash_1

XFGHelper__ComputeHash_1 ? ? ?arg_0 ? ? ? ? ? = qword ptr ?8

XFGHelper__ComputeHash_1 ? ? ?arg_8 ? ? ? ? ? = qword ptr ?10h

XFGHelper__ComputeHash_1 ? ? ?arg_10 ? ? ? ? ?= qword ptr ?18h

[...]

XFGHelper__ComputeHash_1+79 ? ? ? ?xorps ? xmm0, xmm0

XFGHelper__ComputeHash_1+7C ? ? ? ?movdqu ?cs:xfg_hasher, xmm0 ; zero inits xfg_hasher

[...]

XFGHelper__ComputeHash_1+B1 ? ? ? ?mov ? ? rdx, rbp ? ? ? ?; rdx = Type_t containing function information

XFGHelper__ComputeHash_1+B4 ? ? ? ?lea ? ? rbp, xfg_hasher

XFGHelper__ComputeHash_1+BB ? ? ? ?mov ? ? rcx, rbp

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)

函數(shù)XFGHelper::XFGHasher::add_function_type將檢索有關(guān)哈希函數(shù)的4條信息,從XFGHelper::XFGHasher::add_function_type返回后,通過調(diào)用XFGHelper::XFGHasher::add_type可以再添加一條信息,如上面的反匯編列出的XFGHelper__ComputeHash_1+C9所示。這些信息存儲在XFGHelper::XFGHasher實(shí)例的std::vector中:

(1)4個字節(jié),指示函數(shù)的參數(shù)數(shù)量;

(2)每個函數(shù)參數(shù)有8個字節(jié),保存其參數(shù)的哈希值;

(3)1個字節(jié),指示函數(shù)是否是可變參數(shù)(是否使用可變數(shù)量的參數(shù));

(4)4個字節(jié),指示函數(shù)使用的調(diào)用約定;

(5)8個字節(jié),存保存函數(shù)返回類型的哈希值。

4.1 參數(shù)數(shù)量

XFGHelper::XFGHasher::add_function_type函數(shù)首先將一個DWORD添加到std::vector,以指示該函數(shù)的參數(shù)數(shù)量。這個數(shù)字可能會受到可變數(shù)量的參數(shù)、來自__declspec的虛擬信息的影響(我懷疑這可能是在C++的XFG實(shí)現(xiàn)中的一些重用代碼)。簡而言之,這里我們考慮的參數(shù)數(shù)量,就是在函數(shù)原型中聲明的實(shí)際參數(shù)數(shù)量,如果函數(shù)用到了可變數(shù)量的參數(shù),那么就是-1,如果函數(shù)具有來自__declspec的虛擬信息,則為-1。

XFGHelper::XFGHasher::add_function_type+18 ? ? ? ?mov ? ? rsi, [rdx+10h] ?; rsi = function_info- > FunctionTypeInfo

XFGHelper::XFGHasher::add_function_type+1C ? ? ? ?mov ? ? rbx, rcx

XFGHelper::XFGHasher::add_function_type+1F ? ? ? ?mov ? ? rcx, rsi ? ? ? ?; this

XFGHelper::XFGHasher::add_function_type+22 ? ? ? ?movzx ? r14d, r8b

XFGHelper::XFGHasher::add_function_type+26 ? ? ? ?mov ? ? r15, rdx

XFGHelper::XFGHasher::add_function_type+29 ? ? ? ?call ? ?FunctionTypeInfo_t::RealNumberOfParameters(void)

XFGHelper::XFGHasher::add_function_type+2E ? ? ? ?mov ? ? rcx, rsi ? ? ? ?; this

XFGHelper::XFGHasher::add_function_type+31 ? ? ? ?mov ? ? r9d, eax ? ? ? ?; r9 = real_number_of_params

XFGHelper::XFGHasher::add_function_type+34 ? ? ? ?call ? ?FunctionTypeInfo_t::IsVarArgsFunction(void)

XFGHelper::XFGHasher::add_function_type+39 ? ? ? ?mov ? ? rdx, [rbx+8]

XFGHelper::XFGHasher::add_function_type+3D ? ? ? ?lea ? ? rbp, [r9-1] ? ? ; rbp = real_number_of_params - 1

XFGHelper::XFGHasher::add_function_type+41 ? ? ? ?test ? ?al, al ? ? ? ? ?; is variadic function?

XFGHelper::XFGHasher::add_function_type+43 ? ? ? ?mov ? ? rcx, rbx

XFGHelper::XFGHasher::add_function_type+46 ? ? ? ?cmovz ? rbp, r9 ? ? ? ? ; if not variadic, rbp = real_number_of_params

XFGHelper::XFGHasher::add_function_type+4A ? ? ? ?test ? ?r8b, r8b ? ? ? ?; does it have virtual info from __declspec?

XFGHelper::XFGHasher::add_function_type+4D ? ? ? ?lea ? ? r9, [rsp+48h+arg_14]

XFGHelper::XFGHasher::add_function_type+52 ? ? ? ?lea ? ? r8, [rsp+48h+arg_10]

XFGHelper::XFGHasher::add_function_type+57 ? ? ? ?lea ? ? eax, [rbp-1] ? ?; number of params = rbp - 1

XFGHelper::XFGHasher::add_function_type+5A ? ? ? ?cmovz ? eax, ebp ? ? ? ?; if no virtual info from __declspec, number of params = rbp

XFGHelper::XFGHasher::add_function_type+5D ? ? ? ?mov ? ? [rsp+48h+arg_10], eax ; value to add = number of params (dword)

XFGHelper::XFGHasher::add_function_type+5D ? ? ? ? ? ? ? ? ? ? ; [step 1]

XFGHelper::XFGHasher::add_function_type+61 ? ? ? ?call ? ?std::vector < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

4.2 每個參數(shù)的類型哈希

接下來,XFGHelper::XFGHasher::add_function_type進(jìn)入一個循環(huán),在該循環(huán)中,它計算每個函數(shù)參數(shù)類型的哈希,然后將每個類型哈希(8個字節(jié))添加到std::vector。

對于集中特殊情況(類型& 0x10f == 0x103、類型& 0x103 == 0x101)有特殊處理,但是對于大多數(shù)參數(shù)類型,將返回到loc_180105541。在這個位置,如果需要(調(diào)用Type_t::clearModifiersAndQualifiers),則會清除表示要處理的參數(shù)類型的Type_t對象的限定符(例如const (0x800)和volatile (0x40)),然后清除8個字節(jié)的哈希。通過調(diào)用XFGHelper::XFGHasher::add_type,將參數(shù)類型添加到std::vector,我們可以在XFGHelper::XFGHasher::add_function_type+CC看到。至于XFGHelper::XFGHasher::add_type是如何精確計算給定Type_t的哈希,我們在后續(xù)章節(jié)進(jìn)行分析。

最后,如果還有更多參數(shù)需要哈希,就會跳轉(zhuǎn)到循環(huán)的開始部分。

XFGHelper::XFGHasher::add_function_type+6E ? loc_1801054F6:

XFGHelper::XFGHasher::add_function_type+6E ? ? ? ?mov ? ? rax, [rsi] ? ? ?; rax = &function_info- > params

XFGHelper::XFGHasher::add_function_type+71 ? ? ? ?mov ? ? rcx, [rax+rdi*8] ; rcx = function_info- > params[i] (Type_t)

XFGHelper::XFGHasher::add_function_type+75 ? ? ? ?mov ? ? edx, [rcx] ? ? ?; edx = params[i].type

XFGHelper::XFGHasher::add_function_type+77 ? ? ? ?mov ? ? eax, edx

XFGHelper::XFGHasher::add_function_type+79 ? ? ? ?and ? ? eax, 10Fh

XFGHelper::XFGHasher::add_function_type+7E ? ? ? ?cmp ? ? eax, 103h ? ? ? ; params[i].type & 0x10f == 0x103 ?

XFGHelper::XFGHasher::add_function_type+83 ? ? ? ?jnz ? ? short loc_18010552C

XFGHelper::XFGHasher::add_function_type+85 ? ? ? ?cmp ? ? edx, 8103h ? ? ?; params[i].type == 0x8103 ?

XFGHelper::XFGHasher::add_function_type+8B ? ? ? ?jz ? ? ?short loc_18010554E

XFGHelper::XFGHasher::add_function_type+8D ? ? ? ?mov ? ? r8d, [rcx+4]

XFGHelper::XFGHasher::add_function_type+91 ? ? ? ?lea ? ? edx, [rax-1]

XFGHelper::XFGHasher::add_function_type+94 ? ? ? ?mov ? ? rcx, [rcx+8]

XFGHelper::XFGHasher::add_function_type+98 ? ? ? ?btr ? ? r8d, 1Fh

XFGHelper::XFGHasher::add_function_type+9D ? ? ? ?call ? ?Type_t::createType(Type_t const *,uint,mod_t,bool)

XFGHelper::XFGHasher::add_function_type+A2 ? ? ? ?jmp ? ? short loc_18010554B

XFGHelper::XFGHasher::add_function_type+A4 ? ; --------------------------------------------------------------

XFGHelper::XFGHasher::add_function_type+A4

XFGHelper::XFGHasher::add_function_type+A4 ? loc_18010552C:

XFGHelper::XFGHasher::add_function_type+A4 ? ? ? ?and ? ? edx, 103h

XFGHelper::XFGHasher::add_function_type+AA ? ? ? ?cmp ? ? edx, 101h ? ? ? ; params[i].type & 0x103 == 0x101 ?

XFGHelper::XFGHasher::add_function_type+B0 ? ? ? ?jnz ? ? short loc_180105541

XFGHelper::XFGHasher::add_function_type+B2 ? ? ? ?call ? ?Type_t::decayFunctionType(void)

XFGHelper::XFGHasher::add_function_type+B7 ? ? ? ?jmp ? ? short loc_18010554B

XFGHelper::XFGHasher::add_function_type+B9 ? ; --------------------------------------------------------------

XFGHelper::XFGHasher::add_function_type+B9

XFGHelper::XFGHasher::add_function_type+B9 ? loc_180105541:

XFGHelper::XFGHasher::add_function_type+B9 ? ? ? ?mov ? ? edx, 8C0h ? ? ? ; discards qualifiers 0x800 (const) | 0x80 | 0x40 (volatile)

XFGHelper::XFGHasher::add_function_type+BE ? ? ? ?call ? ?Type_t::clearModifiersAndQualifiers(mod_t)

XFGHelper::XFGHasher::add_function_type+C3

XFGHelper::XFGHasher::add_function_type+C3 ? loc_18010554B:

XFGHelper::XFGHasher::add_function_type+C3 ? ? ? ? ? ? ? ? ? ? ; XFGHelper::XFGHasher::add_function_type+B7↑j

XFGHelper::XFGHasher::add_function_type+C3 ? ? ? ?mov ? ? rcx, rax

XFGHelper::XFGHasher::add_function_type+C6

XFGHelper::XFGHasher::add_function_type+C6 ? loc_18010554E:

XFGHelper::XFGHasher::add_function_type+C6 ? ? ? ?mov ? ? rdx, rcx ? ? ? ?; struct Type_t *

XFGHelper::XFGHasher::add_function_type+C9 ? ? ? ?mov ? ? rcx, rbx ? ? ? ?; this

XFGHelper::XFGHasher::add_function_type+CC ? ? ? ?call ? ?XFGHelper::XFGHasher::add_type(Type_t const *) ; adds hash of params[i] type

XFGHelper::XFGHasher::add_function_type+CC ? ? ? ? ? ? ? ? ? ? ; [step 2]

XFGHelper::XFGHasher::add_function_type+D1 ? ? ? ?inc ? ? rdi

XFGHelper::XFGHasher::add_function_type+D4 ? ? ? ?cmp ? ? rdi, rbp ? ? ? ?; counter ?< ?number_of_params ?

XFGHelper::XFGHasher::add_function_type+D7 ? ? ? ?jb ? ? ?short loc_1801054F6 ; if so, loop

4.3 可變參數(shù)函數(shù)

下一步是向std::vector添加一個字節(jié),指示該函數(shù)是否可接受可變數(shù)量的參數(shù)。在大多數(shù)情況下,當(dāng)函數(shù)不包含來自__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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

4.4 調(diào)用約定

最后,XFGHelper::XFGHasher::add_function_type將一個4字節(jié)的值添加到std::vector,以指示該函數(shù)使用的調(diào)用約定。在Intel x64體系結(jié)構(gòu)中沒有太多的調(diào)用約定,這一點(diǎn)與x86不太一樣。默認(rèn)的x64調(diào)用約定在寄存器RCX、RDX、R8和R9中傳遞整數(shù)型參數(shù),而浮點(diǎn)型參數(shù)通過XMM0-XMM3傳遞。該默認(rèn)調(diào)用約定在內(nèi)部用0x201值來表示,但是由于在將其保存到std::vector之前,使用& 0x0F進(jìn)行了屏蔽(請參考下面的反匯編),因此我們很可能會看到一個值為0x00000001的DWORD寫入std::vector。

下面展示了將調(diào)用約定數(shù)據(jù)添加到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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

4.5 返回類型的哈希

數(shù)據(jù)的第五部分,也是最后一個組成部分,用于獲取函數(shù)原型哈希,它無法在XFGHelper::XFGHasher::add_function_type中檢索到,而是在返回后立即添加的。在下面的代碼中我們看到,它調(diào)用XFGHelper::XFGHasher::add_type,為表示返回類型的Type_t計算8字節(jié)的哈希,并將計算出來的8字節(jié)哈希值添加到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)

4.6 最后一步:計算收集的原型數(shù)據(jù)的哈希值

如果該函數(shù)包含來自__declspec的虛擬信息,則會從該信息中生成一個附加的8字節(jié)類型的哈希,并將其添加到std::vector。但是,在測試期間,我沒能實(shí)現(xiàn)這種特殊情況。如前所述,虛擬信息可能不適用于C語言代碼。
無論是否存在來自__declspec的虛擬信息,XFGHelper__ComputeHash_1函數(shù)都可以通過調(diào)用XFGHelper::XFGHasher::get_hash函數(shù)來完成:

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中收集的類型數(shù)據(jù)進(jìn)行哈希處理。我們在XFGHelper::XFGHasher::get_hash+5F中看到,選擇的哈希算法是SHA256,僅返回生成的SHA256摘要的前8個字節(jié):

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

五、哈希類型

到目前為止,我們知道函數(shù)原型哈希是基于五個信息構(gòu)建的。其中三個是普通值(參數(shù)數(shù)量、一個布爾值用于標(biāo)識函數(shù)是否參數(shù)可變、一個數(shù)字值表示正在使用的調(diào)用約定),而另外兩個是類型哈希(每個函數(shù)參數(shù)的類型哈希,以及返回類型的哈希)。在這一章中,我們將了解如何對類型(編譯器內(nèi)部使用Type_t對象表示)進(jìn)行哈希處理。

類型在XFGHelper::XFGHasher::add_type函數(shù)中計算哈希。它調(diào)用XFGHelper__GetHashForType,隨后返回該類型的8字節(jié)哈希,然后通過調(diào)用std::vector::_Insert_range()將8字節(jié)哈希存儲在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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,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字節(jié)哈希的。首先,它通過對std:Tree::emplace()的調(diào)用,來檢查指定類型的哈希是否存在于它保存的緩存中,我們可以在XFGHelper__GetHashForType+AF發(fā)現(xiàn)這一點(diǎn)。如果滿足條件,則只返回緩存的類型哈希。這樣,就可以避免一遍又一遍地計算已知類型的哈希值。

如果在緩存中沒有找到類型哈希,則通過調(diào)用XFGHelper::XFGTypeHasher::compute_hash從頭開始計算哈希,將會使用要計算哈希的類型數(shù)據(jù)構(gòu)建std::vector,最后調(diào)用XFGHelper::XFGHasher::get_hash,它會生成std::vector中包含的數(shù)據(jù)的SHA256摘要,并返回這個摘要的前8個字節(jié)。

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::_Tmap_traits < Type_t const *,unsigned __int64,std::less < Type_t const * > ,std::allocator < std::pair < Type_t const * const,unsigned __int64 > ?> ,0 > ?> ::_Emplace < Type_t const * &,int > (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)從類型限定符得到的1個字節(jié)(從Type_t對象的偏移量4處獲取);

(2)指示類型的1個字節(jié)(指針、union/struct/enum、原始類型);

(3)一些特定于類型的數(shù)據(jù),具體取決于類型屬于(2)中的哪一個類型。

接下來,我們將詳細(xì)分析這三部分信息。

5.1 類型限定符

第一部分是限定符,作為DWORD存儲在Type_t對象的偏移量4的位置。關(guān)于const (0x800)和volatile (0x40)限定符的信息將被組合寫入到std::vector單字節(jié)中。這個新字節(jié)的第一位負(fù)責(zé)指示是否存在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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

5.2 類型組

如果存儲在Type_t中的類型值設(shè)置為0x100,則它是一個指針。通過將值為3的字節(jié)寫入到std::vector來發(fā)出信號。

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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

如果類型不是指針,則會檢查存儲在Type_t & 0x600的值是否為0,以確認(rèn)它是union、struct還是enum。請注意,0x600是0x200 | 0x400,其中0x200表示enum類型,0x400表示union和struct。如果滿足這個條件,會將值為2的字節(jié)寫入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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

最后,如果類型既不是指針,也不是union/struct/enum,則采用默認(rèn)情況。如果類型是泛型的,則不會將任何內(nèi)容寫入到std::vector(但這是一種邊界情況,僅影響設(shè)置了值0x1000的類型,以及標(biāo)識為值0x8103的類型)。否則,如果是絕大多數(shù)的基本類型,會將值為1的字節(jié)添加到std::vector。

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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

5.3 特定類型的數(shù)據(jù)

5.3.1 指針類型的哈希

對于指針類型,在將值為3的字節(jié)寫入std::vector后,將調(diào)用XFGHelper::XFGTypeHasher::hash_indirection函數(shù)。這里的指針定義要更為寬泛,因?yàn)槠渲邪ㄋ兄禐?x100的Type_t對象。除了常規(guī)的C指針外,還包括一種內(nèi)部函數(shù)對象(由函數(shù)指針引用)和數(shù)組。

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

顧名思義,函數(shù)XFGHelper::XFGTypeHasher::hash_indirection將由指向std::vector的指針引用的類型的哈希值添加。其行為取決于所處理的指針的類型:

(1)如果是函數(shù)指針(Type_t值為0x106),或Type_t值為0x102的通用指針,則通過調(diào)用XFGHelper::XFGHasher::add_type添加指針引用的Type_t的哈希,再加上值為2的字節(jié)。對于函數(shù)指針,指針引用的Type_t是一種內(nèi)部函數(shù)對象,Type_t值為0x101,這意味著它也在XFGHelper::XFGTypeHasher::hash_indirection中進(jìn)行處理。

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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

如果它是一個函數(shù)對象(Type_t值為0x101,通常由Type_t值為0x106的函數(shù)指針引用),它通過調(diào)用XFGHelper::XFGHasher::add_function_type函數(shù)以及函數(shù)返回類型的哈希值來添加函數(shù)原型的哈希值,再加上一個值為1的字節(jié)。

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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

最后,如果它是一個數(shù)組(Type_t值為0x103),則會寫入一個QWORD,其中包含數(shù)組中元素的數(shù)量、數(shù)組元素類型的哈希、值為6的單字節(jié)。

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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,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 < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

5.3.2 union/struct/enum類型的哈希

在處理union/struct/enum時,將值為2的字節(jié)寫入std::vector后,函數(shù)XFGHelper::XFGTypeHasher::compute_hash調(diào)用XFGHelper::XFGTypeHasher::hash_tag,在RDX中將指向Symbol_t的指針作為參數(shù)傳遞,其中包括union/struct/enum類型的可讀名稱的對象。

XFGHelper::XFGTypeHasher::compute_hash+AE ? ? ? ?mov ? ? rdx, [rdi+10h] ?; struct Symbol_t *

XFGHelper::XFGTypeHasher::compute_hash+B2 ? ? ? ?mov ? ? rcx, rbx ? ? ? ?; this

XFGHelper::XFGTypeHasher::compute_hash+B5 ? ? ? ?call ? ?XFGHelper::XFGTypeHasher::hash_tag(Symbol_t *)

XFGHelper::XFGTypeHasher::hash_tag調(diào)用XFGHelper::XFGHasher::add_string,將union/struct/enum的名稱添加到std::vector(命名情況下)。如果union/struct/enum是匿名的,則會將字符串“ < unnamed > ”添加到std::vector。

XFGHelper::XFGHasher::add_string ? ? ?public: void XFGHelper::XFGHasher::add_string(class Symbol_t *) proc near

XFGHelper::XFGHasher::add_string ? ? ? ? ? sub ? ? rsp, 38h

XFGHelper::XFGHasher::add_string+4 ? ? ? ? cmp ? ? byte ptr [rdx+11h], 4

XFGHelper::XFGHasher::add_string+8 ? ? ? ? jnz ? ? short loc_18010568B

XFGHelper::XFGHasher::add_string+A ? ? ? ? mov ? ? r8, [rdx]

XFGHelper::XFGHasher::add_string+D ? ? ? ? mov ? ? eax, [r8+10h]

XFGHelper::XFGHasher::add_string+11 ? ? ? ?shr ? ? eax, 16h

XFGHelper::XFGHasher::add_string+14 ? ? ? ?test ? ?al, 1 ? ? ? ? ? ; union/struct/enum is named?

XFGHelper::XFGHasher::add_string+16 ? ? ? ?jz ? ? ?short loc_180105674

XFGHelper::XFGHasher::add_string+18 ? ? ? ?lea ? ? r9, aUnnamed+9 ?; ""

XFGHelper::XFGHasher::add_string+1F ? ? ? ?lea ? ? r8, aUnnamed ? ?; " < unnamed > "

XFGHelper::XFGHasher::add_string+26

XFGHelper::XFGHasher::add_string+26 ? loc_180105666:

XFGHelper::XFGHasher::add_string+26 ? ? ? ?mov ? ? rdx, [rcx+8]

XFGHelper::XFGHasher::add_string+2A ? ? ? ?call ? ?std::vector < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

XFGHelper::XFGHasher::add_string+2F ? ? ? ?add ? ? rsp, 38h

XFGHelper::XFGHasher::add_string+33 ? ? ? ?retn

XFGHelper::XFGHasher::add_string+34 ? ; ---------------------------------------------------------------------------

XFGHelper::XFGHasher::add_string+34

XFGHelper::XFGHasher::add_string+34 ? loc_180105674:

XFGHelper::XFGHasher::add_string+34 ? ? ? ?mov ? ? r8, [r8+8] ? ? ?; r8 = union/struct/enum name

XFGHelper::XFGHasher::add_string+38 ? ? ? ?or ? ? ?r9, 0FFFFFFFFFFFFFFFFh

XFGHelper::XFGHasher::add_string+3C

XFGHelper::XFGHasher::add_string+3C ? loc_18010567C:

XFGHelper::XFGHasher::add_string+3C ? ? ? ?inc ? ? r9

XFGHelper::XFGHasher::add_string+3F ? ? ? ?cmp ? ? byte ptr [r8+r9], 0

XFGHelper::XFGHasher::add_string+44 ? ? ? ?jnz ? ? short loc_18010567C

XFGHelper::XFGHasher::add_string+46 ? ? ? ?add ? ? r9, r8 ? ? ? ? ?; r9 points to end of string

XFGHelper::XFGHasher::add_string+49 ? ? ? ?jmp ? ? short loc_180105666

之后,函數(shù)XFGHelper::XFGTypeHasher::hash_tag中有一個代碼分支,可以在某些情況下將字符串" < local > "添加到需要計算哈希的數(shù)據(jù)中。我們對此沒有進(jìn)行太多研究,但它可能處理了本地范圍的union/struct/enum的情況。

XFGHelper::XFGTypeHasher::hash_tag+4D ? ? ? ?mov ? ? rbx, [rbx+18h]

XFGHelper::XFGTypeHasher::hash_tag+51 ? ? ? ?test ? ?rbx, rbx

XFGHelper::XFGTypeHasher::hash_tag+54 ? ? ? ?jnz ? ? short loc_180105A16

XFGHelper::XFGTypeHasher::hash_tag+56 ? ? ? ?jmp ? ? short loc_180105A76

XFGHelper::XFGTypeHasher::hash_tag+58 ? ; ---------------------------------------------------------------------------

XFGHelper::XFGTypeHasher::hash_tag+58

XFGHelper::XFGTypeHasher::hash_tag+58 ? loc_180105A5C:

XFGHelper::XFGTypeHasher::hash_tag+58 ? ? ? ?mov ? ? rdx, [rdi+8]

XFGHelper::XFGTypeHasher::hash_tag+5C ? ? ? ?lea ? ? r9, aLocal+7 ? ?; ""

XFGHelper::XFGTypeHasher::hash_tag+63 ? ? ? ?lea ? ? r8, aLocal ? ? ?; " < local > "

XFGHelper::XFGTypeHasher::hash_tag+6A ? ? ? ?mov ? ? rcx, rdi

XFGHelper::XFGTypeHasher::hash_tag+6D ? ? ? ?call ? ?std::vector < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

5.3.3 原始類型的哈希

在處理原始類型時(在Type_t值中未設(shè)置0x100、0x200或0x400的原始類型),在將值為1的字節(jié)寫入std::vector后,函數(shù)XFGHelper::XFGTypeHasher::compute_hash會調(diào)用XFGHelper::XFGTypeHasher::hash_primitive。

XFGHelper::XFGTypeHasher::hash_primitive基本上是一個很大的switch語句,它將Type_t值映射到代表原始類型的一組不同常量。然后,將得到的常數(shù)(單個字節(jié))添加到std::vector。例如,對于以Type_t 0x26表示的浮點(diǎn)型,該函數(shù)將一個值為0x0B的字節(jié)添加到std::vector。

XFGHelper::XFGTypeHasher::hash_primitive ? ? ?private: void XFGHelper::XFGTypeHasher::hash_primitive(class Type_t const *) proc near

XFGHelper::XFGTypeHasher::hash_primitive ? ? ? ? ? sub ? ? rsp, 38h

XFGHelper::XFGTypeHasher::hash_primitive+4 ? ? ? ? mov ? ? eax, [rdx]

XFGHelper::XFGTypeHasher::hash_primitive+6 ? ? ? ? mov ? ? r10, rcx

XFGHelper::XFGTypeHasher::hash_primitive+9 ? ? ? ? and ? ? eax, 1FFFh

XFGHelper::XFGTypeHasher::hash_primitive+E ? ? ? ? cmp ? ? eax, 40h ; '@'

XFGHelper::XFGTypeHasher::hash_primitive+11 ? ? ? ?ja ? ? ?loc_1801059D4

XFGHelper::XFGTypeHasher::hash_primitive+17 ? ? ? ?jz ? ? ?loc_1801059D0 ? ; case 0x40:

XFGHelper::XFGTypeHasher::hash_primitive+1D ? ? ? ?cmp ? ? eax, 1Ah

XFGHelper::XFGTypeHasher::hash_primitive+20 ? ? ? ?ja ? ? ?short loc_18010599E

[...]

XFGHelper::XFGTypeHasher::hash_primitive+6E ? loc_18010599E:

XFGHelper::XFGTypeHasher::hash_primitive+6E ? ? ? ?sub ? ? eax, 1Bh ? ? ? ?; case 0x1B:

XFGHelper::XFGTypeHasher::hash_primitive+71 ? ? ? ?jz ? ? ?short loc_1801059CC

XFGHelper::XFGTypeHasher::hash_primitive+73 ? ? ? ?sub ? ? eax, 1 ? ? ? ? ?; case 0x1C:

XFGHelper::XFGTypeHasher::hash_primitive+76 ? ? ? ?jz ? ? ?short loc_1801059C8

XFGHelper::XFGTypeHasher::hash_primitive+78 ? ? ? ?sub ? ? eax, 2 ? ? ? ? ?; case 0x1E:

XFGHelper::XFGTypeHasher::hash_primitive+7B ? ? ? ?jz ? ? ?short loc_1801059C4

XFGHelper::XFGTypeHasher::hash_primitive+7D ? ? ? ?sub ? ? eax, 8 ? ? ? ? ?; case 0x26 (float):

XFGHelper::XFGTypeHasher::hash_primitive+80 ? ? ? ?jz ? ? ?short loc_1801059C0

[...]

XFGHelper::XFGTypeHasher::hash_primitive+90 ? loc_1801059C0:

XFGHelper::XFGTypeHasher::hash_primitive+90 ? ? ? ?mov ? ? cl, 0Bh ? ? ? ? ; primitive_type = 0xB (float)

XFGHelper::XFGTypeHasher::hash_primitive+92 ? ? ? ?jmp ? ? short loc_1801059DE

[...]

XFGHelper::XFGTypeHasher::hash_primitive+AE ? loc_1801059DE:

XFGHelper::XFGTypeHasher::hash_primitive+AE ? ? ? ?mov ? ? rdx, [r10+8]

XFGHelper::XFGTypeHasher::hash_primitive+B2 ? ? ? ?lea ? ? r9, [rsp+38h+arg_9]

XFGHelper::XFGTypeHasher::hash_primitive+B7 ? ? ? ?mov ? ? [rsp+38h+arg_8], cl ; value to add: primitive_type

XFGHelper::XFGTypeHasher::hash_primitive+BB ? ? ? ?lea ? ? r8, [rsp+38h+arg_8]

XFGHelper::XFGTypeHasher::hash_primitive+C0 ? ? ? ?mov ? ? rcx, r10

XFGHelper::XFGTypeHasher::hash_primitive+C3 ? ? ? ?call ? ?std::vector < uchar > ::_Insert_range < uchar const * > (std::_Vector_const_iterator < std::_Vector_val < std::_Simple_types < uchar > ?> ?> ,uchar const *,uchar const *,std::forward_iterator_tag)

六、最終轉(zhuǎn)換

到目前為止,我們已經(jīng)深入描述了C編譯器前端如何為XFG機(jī)制來計算函數(shù)原型的哈希。我們可以用類似Python的偽代碼來進(jìn)行概括,函數(shù)的哈希是通過以下方式構(gòu)建的:

hash = ?sha256(number_of_params +

? ? ? ? ? ? ? type_hash(params[0]) +

? ? ? ? ? ? ? type_hash(params[...]) +

? ? ? ? ? ? ? type_hash(params[n]) +

? ? ? ? ? ? ? is_variadic +

? ? ? ? ? ? ? calling_convention +

? ? ? ? ? ? ? type_hash(return_type)

? ? ? ? )[0:8]

XFG函數(shù)哈希是SHA256摘要的一部分,僅保留了前8個字節(jié),因此與完整的SHA256哈希相比,它們的抗沖突性有所降低,但是我們可以預(yù)期,不同的XFG哈希可以在一定程度上保證哈希的功能。

但是,如果針對特定的二進(jìn)制文件,檢查其XFG哈希(這里選擇了ntdll.dll),我們會注意到,它們似乎沒有64位上熵:

function 0x180001a30 - > ?prototype hash: 0x8d952e0d365aa071

function 0x180001b50 - > ?prototype hash: 0xe2198f4a3c515871

function 0x180001dc0 - > ?prototype hash: 0xbeac2e06165fc871

function 0x180001de0 - > ?prototype hash: 0xfaec0e7f70d92371

function 0x180001fc0 - > ?prototype hash: 0xc5d11eb750d75871

function 0x180002030 - > ?prototype hash: 0xe8bcaf9a10586871

function 0x180002040 - > ?prototype hash: 0xc3110f087e584871

function 0x1800020b0 - > ?prototype hash: 0xdbc1261858d2f871

function 0x1800023a0 - > ?prototype hash: 0xda690f3e36531a71

其背后的原因是,由編譯器前端(c1.dll)生成的SHA256片段,在實(shí)際寫入到生成的目標(biāo)文件之前,會由編譯器后端(c2.dll)進(jìn)行最終轉(zhuǎn)換。確切的說,c2.dll中的XfgIlVisitor::visit_I_XFG_HASH函數(shù)將兩個掩碼應(yīng)用到了截斷的SHA256哈希上:

XfgIlVisitor::visit_I_XFG_HASH(tagILMAP *)+5B ? ? ? ?mov ? ? rcx, 8000060010500070h

XfgIlVisitor::visit_I_XFG_HASH(tagILMAP *)+65 ? ? ? ?mov ? ? r13, 0FFFDBFFF7EDFFB70h

[...]

XfgIlVisitor::visit_I_XFG_HASH(tagILMAP *)+E9 ? ? ? ?mov ? ? rdx, [rax] ? ? ?; rdx = 8 bytes of SHA256 hash

XfgIlVisitor::visit_I_XFG_HASH(tagILMAP *)+EC ? ? ? ?add ? ? rax, 8

XfgIlVisitor::visit_I_XFG_HASH(tagILMAP *)+F0 ? ? ? ?and ? ? rdx, r13 ? ? ? ?; hash &= 0FFFDBFFF7EDFFB70h

XfgIlVisitor::visit_I_XFG_HASH(tagILMAP *)+F3 ? ? ? ?mov ? ? [rbx], rax

XfgIlVisitor::visit_I_XFG_HASH(tagILMAP *)+F6 ? ? ? ?or ? ? ?rdx, rcx ? ? ? ?; hash |= 8000060010500070h

XfgIlVisitor::visit_I_XFG_HASH(tagILMAP *)+F9 ? ? ? ?mov ? ? ecx, r9d ? ? ? ?; this

XfgIlVisitor::visit_I_XFG_HASH(tagILMAP *)+FC ? ? ? ?call ? ?XFG::TiSetHash(ulong,unsigned __int64,tagMOD *)

這就是之所以XFG哈希基于SHA256,但看起來也不像完全隨機(jī)的原因。不過,我們不清楚為什么要使用這些掩碼。

七、嘗試進(jìn)行哈希計算

為了確保我們已經(jīng)正確理解了如何生成XFG哈希,我們嘗試進(jìn)行手動的哈希計算。假設(shè)我們使用以下原型計算函數(shù)的哈希值:

void *memcpy(

? ?void *dest,

? ?const void *src,

? ?size_t count

);

我們需要找出構(gòu)成函數(shù)原型的五條數(shù)據(jù):

(1)參數(shù)數(shù)量;

(2)為每個參數(shù)輸入哈希值;

(3)是否具有可變參數(shù)函數(shù);

(4)調(diào)用約定;

(5)返回類型的哈希值。

其中的1、3、4都很簡單:

(1)參數(shù)數(shù)量 - >? DWORD,值為3;

(3)是否具有可變參數(shù)函數(shù) - >? 值為0的字節(jié);

(4)調(diào)用約定 - >? 默認(rèn)值(值為0x201和0xF == 0x1的DWORD)。

因此,我們來計算更復(fù)雜的部分——每個參數(shù)的類型哈希,以及返回類型的類型哈希。

7.1 參數(shù)1的類型哈希

第一個參數(shù)的類型為void *,該類型由以下內(nèi)容的Type_t表示:

00000102 00000200 [+ pointer to referenced Type_t]

我們需要尋找3個數(shù)據(jù),來產(chǎn)生類型哈希:

(1)類型限定符 - >? 值為0的字節(jié);

(2)類型組:指針 - >? 值為3的字節(jié);

(3)特定類型的數(shù)據(jù):這是一個通用指針 - >? 引用類型的哈希(在這里有遞歸)+值為2的字節(jié)。

為了遞歸計算引用類型(void)的哈希,該類型由Type_t表示,其內(nèi)容如下:

00000040 00000000

我們需要構(gòu)建如下數(shù)據(jù):

(1)類型限定符 - >? 值為0的字節(jié);

(2)類型組:原始類型 - >? 值為1的字節(jié);

(3)特定類型的數(shù)據(jù):對于Type_t 0x40(void),XFGHelper::XFGTypeHasher::hash_primitive寫入一個值為0x0E的字節(jié)。

7.2 參數(shù)2的類型哈希

第二個參數(shù)的類型為const void *。該類型由具有以下內(nèi)容的Type_t表示:

00000102 00000200 [+ pointer to referenced Type_t]

我們需要構(gòu)建的數(shù)據(jù)如下:

(1)類型限定符 - >? 值為0的字節(jié);

(2)類型組:指針 - >? 值為3的字節(jié);

(3)特定類型的數(shù)據(jù):這是一個通用指針 - >? 引用類型的哈希(在這里有遞歸)+值為2的字節(jié)。

為了遞歸計算引用類型(void)的哈希,該類型由Type_t表示,其內(nèi)容如下:

00000040 00000000

我們需要構(gòu)建如下數(shù)據(jù):

(1)類型限定符:具有const限定符 - >? 編碼為值為1的字節(jié);

(2)類型組:原始類型 - >? 值為1的字節(jié);

(3)特定類型的數(shù)據(jù):對于Type_t 0x40(void),XFGHelper::XFGTypeHasher::hash_primitive寫入一個值為0x0E的字節(jié)。

7.3 參數(shù)3的類型哈希

第三個參數(shù)的類型為size_t。該類型由具有以下內(nèi)容的Type_t表示:

00004019 00000000

我們需要構(gòu)建的數(shù)據(jù)如下:

(1)類型限定符 - >? 值為0的字節(jié);

(2)類型組:原始類型 - >? 值為1的字節(jié);

(3)特定類型的數(shù)據(jù):對于Type_t 0x4019(無符號長長整型),XFGHelper::XFGTypeHasher::hash_primitive寫入一個值為0x88的字節(jié)。

7.4 返回類型的類型哈希

返回類型為void *,與該函數(shù)的第一個參數(shù)相同,因此這里只需要重復(fù)即可:

(1)類型限定符 - >? 值為0的字節(jié);

(2)類型組:指針 - >? 值為3的字節(jié);

(3)特定類型的數(shù)據(jù):這是一個通用指針 - >? 引用類型的哈希(在這里有遞歸)+值為2的字節(jié)。

對于引用類型(void)的哈希進(jìn)行遞歸計算:

(1)類型限定符:值為0的字節(jié);

(2)類型組:原始類型 - >? 值為1的字節(jié);

(3)特定類型的數(shù)據(jù):對于Type_t 0x40(void),XFGHelper::XFGTypeHasher::hash_primitive寫入一個值為0x0E的字節(jié)。

7.5 組合

我們將所有數(shù)據(jù)組合到一起:

# Number of params

03 00 00 00

# type hash of param 1 (void *)

SHA256(

? ? 00 ?#qualifiers

? ? 03 ?# type group: pointer

? ? # type hash of referenced type (void)

? ? SHA256(

? ? ? ? 00 ?# qualifiers

? ? ? ? 01 ?# type group: primitive type

? ? ? ? 0E ?# hash of primitive type: void - > ?0x0E

? ? )[0:8]

? ? 02 ?# regular pointer

)[0:8]

# type hash of param 2 (const void *)

SHA256(

? ? 00 ?# qualifiers

? ? 03 ?# type group: pointer

? ? # type hash of referenced type (const void)

? ? SHA256(

? ? ? ? 01 ?# qualifiers: const

? ? ? ? 01 ?# type group: primitive type

? ? ? ? 0E ?# hash of primitive type: void - > ?0x0E

? ? )[0:8]

? ? 02 ?# regular pointer

)[0:8]

# type hash of param 3 (size_t)

SHA256(

? ? 00 ?# qualifiers

? ? 01 ?# type group: primitive type

? ? 88 ?# hash of primitive type: unsigned long long - > ?0x88

)[0:8]

# is variadic

00

# calling convention

01 00 00 00

# type hash of return value (void *)

SHA256(

? ? 00 ?# qualifiers

? ? 03 ?# type group: pointer

? ? # type hash of referenced type (void)

? ? SHA256(

? ? ? ? 00 ?# qualifiers

? ? ? ? 01 ?# type group: primitive type

? ? ? ? 0E ?# hash of primitive type: void - > ?0x0E

? ? )[0:8]

? ? 02 ?# regular pointer

)[0:8]

以下Python代碼獲取該數(shù)據(jù)的SHA256摘要,并將其截斷為前8個字節(jié),以獲取與編譯器前端發(fā)出的哈希相同的哈希值。最后,它將編譯器后端的兩個掩碼進(jìn)行應(yīng)用,形成最終形式的XFG哈希。

import struct

import hashlib

def truncated_hash(data):

? ? return hashlib.sha256(data).digest()[0:8]

def apply_backend_masks(hash):

? ? hash = hash & 0xFFFDBFFF7EDFFB70

? ? hash = hash | 0x8000060010500070

? ? return hash

def main():

? ? # number of params

? ? data ?= struct.pack(' < L', 3)

? ? # type hash of first param (void *)

? ? data += truncated_hash(b'\x00\x03' + truncated_hash(b'\x00\x01\x0e') + b'\x02')

? ? # type hash of second param (const void *)

? ? data += truncated_hash(b'\x00\x03' + truncated_hash(b'\x01\x01\x0e') + b'\x02')

? ? # type hash of third param (size_t)

? ? data += truncated_hash(b'\x00\x01\x88')

? ? # is variadic

? ? data += struct.pack(' < B', 0x0)

? ? # calling convention (default)

? ? data += struct.pack(' < L', 0x201 & 0x0F)

? ? # type hash of return type (void *)

? ? data += truncated_hash(b'\x00\x03' + truncated_hash(b'\x00\x01\x0e') + b'\x02')

? ? print(f'Data to be hashed: {data} ({len(data)} bytes)')

? ? frontend_hash = struct.unpack(' < Q', truncated_hash(data))[0]

? ? print(f'Hash generated by the frontend: 0x{frontend_hash:x}')

? ? final_hash = apply_backend_masks(frontend_hash)

? ? print(f'[*] Final XFG hash: 0x{final_hash:x}')

Python代碼的輸出結(jié)果如下:

> ?python test.py

Data to be hashed: b'\x03\x00\x00\x00\xf5\x97x > [J`\xb0\x17\x80\xb8\xc0[\x1b\xd0\xd8#\x14\xb4\xba\x91\xc7\xf6j\x00\x01\x00\x00\x00\xf5\x97x > [J`\xb0' (41 bytes)

Hash generated by the frontend: 0x1da7d393d6b63a72

[*] Final XFG hash: 0x9da5979356d63a70

如果我們使用函數(shù)指針編譯一些代碼,以調(diào)用其原型與我們在本章中討論過的原型相匹配的函數(shù),就會看到,我們手工計算的XFG哈希值與MSVC生成的哈希完全匹配(參閱分配的值)。在下面的反匯編中的main+0x8E處注冊了R10。

main+1C ? ? ? ?lea ? ? rax, my_memcpy

main+23 ? ? ? ?mov ? ? [rsp+78h+var_50], rax

[...]

main+6A ? ? ? ?lea ? ? rcx, aCallingFunctio ; "Calling function pointer...\n"

main+71 ? ? ? ?call ? ?printf

main+76 ? ? ? ?lea ? ? rcx, Str ? ? ? ?; "a test"

main+7D ? ? ? ?call ? ?strlen

main+82 ? ? ? ?cdqe

main+84 ? ? ? ?mov ? ? rcx, [rsp+78h+var_50]

main+89 ? ? ? ?mov ? ? [rsp+78h+var_48], rcx

main+8E ? ? ? ?mov ? ? r10, 9DA5979356D63A70h

main+98 ? ? ? ?mov ? ? r8, rax

main+9B ? ? ? ?lea ? ? rdx, aATest_0 ? ; "a test"

main+A2 ? ? ? ?lea ? ? rcx, [rsp+78h+var_28]

main+A7 ? ? ? ?mov ? ? rax, [rsp+78h+var_48]

main+AC ? ? ? ?call ? ?cs:__guard_xfg_dispatch_icall_fptr

八、總結(jié)

在這篇文章中,我們分享了MSVC編譯器是如何為C語言程序生成XFG哈希的所有詳細(xì)信息。除了探討后續(xù)的漏洞利用緩解措施細(xì)節(jié)外,我們還可以深入了解編譯器內(nèi)部原理。

請注意,目前XFG僅存在于Windows Insider Preview版本中,因此在這個CFI解決方案進(jìn)入到Windows 10正式版本之前,本文所描述的細(xì)節(jié)可能還會被微軟進(jìn)行調(diào)整。

目前暫時不清楚,為什么編譯器后端對前端生成的哈希要使用兩個位掩碼,為什么哈希在函數(shù)啟動前使用第0位存儲,而未設(shè)置第0位的就要存儲在XFG的調(diào)用目標(biāo)中。

最后,非常有趣的是,我們可以看看C++編譯器前端(c1xx.dll)計算XFG哈希值的方式的不同之處。如果迅速瀏覽這個二進(jìn)制文件,會發(fā)現(xiàn)哈希算法看起來與C語言的算法非常相似,但是考慮到繼承、C++類型限定符、修飾符這類獨(dú)有概念,還是有可能會進(jìn)行調(diào)整的。

參考及來源:https://blog.quarkslab.com/how-the-msvc-compiler-generates-xfg-function-prototype-hashes.html

總結(jié)

以上是生活随笔為你收集整理的编译原理实验语义分析_Windows MVSC编译器实现Xtended Flow Guard(XFG)保护机制的原理分析...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。