win10 Dynamic Value Relocation Table Retpoline解析

Posted zhuhuibeishadiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了win10 Dynamic Value Relocation Table Retpoline解析相关的知识,希望对你有一定的参考价值。

前言:

   在CVE-2017-5715漏洞曝出之后,微软做了一系列的措施来缓解,并在win10 1809(17763)之后会默认启用了Retpoline或导入优化,这取决于用户设置或cpu支持情况,也有两个都不启动的,但KASLR总是启动的,启动KASLR,会替换pte的旧值到随机化后的值,不过即使不能启用Retpoline,也会启动导入优化(1809之后),启用RetPoline或导入优化之后,winload.exe在加载ntos和hal.dll时,会替换一些指令,pe格式也发生了部分改变(win8.1已改变,后续只是增加).获取启用状态可调用ZwQuerySystemInformation的201号功能查询(>=1803版本),结构体定义如下:

typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION

    struct
    
        ULONG BpbEnabled : 1;
        ULONG BpbDisabledSystemPolicy : 1;
        ULONG BpbDisabledNoHardwareSupport : 1;
        ULONG SpecCtrlEnumerated : 1;
        ULONG SpecCmdEnumerated : 1;
        ULONG IbrsPresent : 1;
        ULONG StibpPresent : 1;
        ULONG SmepPresent : 1;
        ULONG SpeculativeStoreBypassDisableAvailable : 1;
        ULONG SpeculativeStoreBypassDisableSupported : 1;
        ULONG SpeculativeStoreBypassDisabledSystemWide : 1;
        ULONG SpeculativeStoreBypassDisabledKernel : 1;
        ULONG SpeculativeStoreBypassDisableRequired : 1;
        ULONG BpbDisabledKernelToUser : 1;
        ULONG SpecCtrlRetpolineEnabled : 1;
        ULONG SpecCtrlImportOptimizationEnabled : 1;
        ULONG Reserved : 24;
     SpeculationControlFlags;
 SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION;

 

DVRT:

    全名Dynamic Value Relocation Table,此表记录需要替换的指令的指针,当然,系统也可以选择不进行替换,因为这些镜像在编译时,会留出一些空隙,比如:

call qword ptr[__imp__func]
nop

即使不替换,也不会影响正常执行.

在开启pchunter,windows kernel explorer 内核钩子扫描时,会扫出大量钩子(pchunter最新版已不再扫ntos).

查看sdk 1909 ntimage.h(win8.1时就存在一些),可发现有新的结构体,如下

typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 
    xxxxxxxxxxxxx
    DWORD      GuardFlags;
    IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;
    ULONGLONG  GuardAddressTakenIatEntryTable; // VA
    ULONGLONG  GuardAddressTakenIatEntryCount;
    ULONGLONG  GuardLongJumpTargetTable;       // VA
    ULONGLONG  GuardLongJumpTargetCount;
    ULONGLONG  DynamicValueRelocTable;         // VA
    ULONGLONG  CHPEMetadataPointer;            // VA
    ULONGLONG  GuardRFFailureRoutine;          // VA
    ULONGLONG  GuardRFFailureRoutineFunctionPointer; // VA
    DWORD      DynamicValueRelocTableOffset;
    WORD       DynamicValueRelocTableSection;
    WORD       Reserved2;
    ULONGLONG  GuardRFVerifyStackPointerFunctionPointer; // VA
    DWORD      HotPatchTableOffset;
    DWORD      Reserved3;
    ULONGLONG  EnclaveConfigurationPointer;     // VA
    ULONGLONG  VolatileMetadataPointer;         // VA
    ULONGLONG  GuardEHContinuationTable;        // VA
    ULONGLONG  GuardEHContinuationCount;
 IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;

typedef struct _IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER 
    BYTE       PrologueByteCount;
    // BYTE    PrologueBytes[PrologueByteCount];
 IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER;
typedef IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER UNALIGNED * PIMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER;

typedef struct _IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER 
    DWORD      EpilogueCount;
    BYTE       EpilogueByteCount;
    BYTE       BranchDescriptorElementSize;
    WORD       BranchDescriptorCount;
    // BYTE    BranchDescriptors[...];
    // BYTE    BranchDescriptorBitMap[...];
 IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER;
typedef IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER UNALIGNED * PIMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER;

typedef struct _IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION 
    DWORD       PageRelativeOffset : 12;
    DWORD       IndirectCall       : 1;
    DWORD       IATIndex           : 19;
 IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION;
typedef IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION UNALIGNED * PIMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION;

typedef struct _IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION 
    WORD        PageRelativeOffset : 12;
    WORD        IndirectCall       : 1;
    WORD        RexWPrefix         : 1;
    WORD        CfgCheck           : 1;
    WORD        Reserved           : 1;
 IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION;
typedef IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION UNALIGNED * PIMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION;

typedef struct _IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION 
    WORD        PageRelativeOffset : 12;
    WORD        RegisterNumber     : 4;
 IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION;
typedef IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION UNALIGNED * PIMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION;

//
// Dynamic value relocation table in loadconfig
//

typedef struct _IMAGE_DYNAMIC_RELOCATION_TABLE 
    DWORD Version;
    DWORD Size;
//  IMAGE_DYNAMIC_RELOCATION DynamicRelocations[0];
 IMAGE_DYNAMIC_RELOCATION_TABLE, *PIMAGE_DYNAMIC_RELOCATION_TABLE;

//
// Dynamic value relocation entries following IMAGE_DYNAMIC_RELOCATION_TABLE
//

#include "pshpack1.h"

typedef struct _IMAGE_DYNAMIC_RELOCATION32 
    DWORD      Symbol;
    DWORD      BaseRelocSize;
//  IMAGE_BASE_RELOCATION BaseRelocations[0];
 IMAGE_DYNAMIC_RELOCATION32, *PIMAGE_DYNAMIC_RELOCATION32;

typedef struct _IMAGE_DYNAMIC_RELOCATION64 
    ULONGLONG  Symbol;
    DWORD      BaseRelocSize;
//  IMAGE_BASE_RELOCATION BaseRelocations[0];
 IMAGE_DYNAMIC_RELOCATION64, *PIMAGE_DYNAMIC_RELOCATION64;

可以发现有一个新的重定位表,也是DVRT.当我以旧重定位表的解析方式进行时,发现数据异常,于是就有这篇文章.

首先动态重定位表有两种方式进行定位,一是此表跟在重定位表之后,二是通过LOAD_CONFIG表得到offset,此offset为相对一个节的rva,节的索引在offset的下一个成员指出.

得到节base + rva + imagebase即可定位,另外判断镜像是否支持RetPoline,可通过LOAD_CONFIG下的GuardFlags标志进行判断,

得到DVRT表之后,Version表示版本号,动态重定位表有两个版本,由于在测试中没有发现版本号为2的镜像,故此文仅对v1版本进行解析.

size表示大小,接着跟着一个IMAGE_DYNAMIC_RELOCATION结构,

Symbol 定义如下:

#define IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE   0x00000001
#define IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE   0x00000002
#define IMAGE_DYNAMIC_RELOCATION_GUARD_IMPORT_CONTROL_TRANSFER  0x00000003
#define IMAGE_DYNAMIC_RELOCATION_GUARD_INDIR_CONTROL_TRANSFER   0x00000004
#define IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH       0x00000005

ntos的特殊一些,解析时会发现有一些Symbol对不上,实际上,ntos还包含了pte随机化,在实现pte随机化时,需要替换原定义的pte信息,定义如下:

#ifndef PXE_BASE
#define PXE_BASE    0xFFFFF6FB7DBED000UI64
#endif
#ifndef PXE_SELFMAP
#define PXE_SELFMAP 0xFFFFF6FB7DBEDF68UI64
#endif
#ifndef PPE_BASE
#define PPE_BASE    0xFFFFF6FB7DA00000UI64
#endif
#ifndef PDE_BASE
#define PDE_BASE    0xFFFFF6FB40000000UI64
#endif
#ifndef PTE_BASE
#define PTE_BASE    0xFFFFF68000000000UI64
#endif

#define PXE_TOP           0xFFFFF6FB7DBEDFFFUI64
#define PPE_TOP           0xFFFFF6FB7DBFFFFFUI64
#define PDE_TOP           0xFFFFF6FB7FFFFFFFUI64
#define PTE_TOP           0xFFFFF6FFFFFFFFFFUI64

#define MmPagedPoolStart  0xFFFFFA8000000000UI64

对于IMPORT_CONTROL:

call qword ptr [__imp_func]
nop

->

mov r10, qword ptr [__imp_func]
call _guard_retpoline_import_r10

也有可能替换为直接call r10,这种是因为启用了导入优化,

对于其它两个,windows并不一定会进行代码替换.

在较新的系统上,ntos的RtlPerformRetpolineRelocationsOnImageEx函数进行修改代码操作

对于pte随机化,只是将常量替换为新的地址

对于代码的修改

符号对应关系 未知为没有发现对应的要修改的地址

1->未知

2->未知

3->12字节 mov r10,[__imp___],call r10 or call retpoline_r1_guard

4->5字节或不修改

5->不修改

pte相关->8字节 直接将随机化后的pte相关地址替换

在支持Retpoline的pe文件中,有一个节叫RETPOL的节,

此节有替换时需要call的函数

此节类似于apiset,开头是一共结构体,此结构体定义如下:

struct _RETPOL_SECTION

	DWORD sizeOfSection;
	DWORD rva_switchtable_jmp_rax;
	DWORD rva_switchtable_jmp_rcx;
	DWORD rva_switchtable_jmp_rdx;
	DWORD rva_switchtable_jmp_rbx;
	DWORD rva_switchtable_jmp_rsp;
	DWORD rva_switchtable_jmp_rbp;
	DWORD rva_switchtable_jmp_rsi;
	DWORD rva_switchtable_jmp_rdi;
	DWORD rva_switchtable_jmp_r8;
	DWORD rva_switchtable_jmp_r9;
	DWORD rva_switchtable_jmp_r10;
	DWORD rva_switchtable_jmp_r11;
	DWORD rva_switchtable_jmp_r12;
	DWORD rva_switchtable_jmp_r13;
	DWORD rva_switchtable_jmp_r14;
	DWORD rva_switchtable_jmp_r15;
	DWORD rva_indirect_rax;
	DWORD rva_import_r10;
	DWORD unknow;
	DWORD unknow;
	DWORD unknow;
	DWORD unknow;

通过rva+节base就能得到函数的va,也在RETPOL节中

代码:

struct TypeOffset

    WORD Offset : 12;
    WORD Type : 4;
;

typedef struct _SYMBOL_NAME 
    ULONG sizeOfOneBlock;
    ULONGLONG base;
    const char* szName;
SYMBOL_NAME, *PSYMBOL_NAME;

union UNION_SYMBOL_DATA

    TypeOffset offset;
    IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER prologue;
    IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER epilogue;
    IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION imp;
    IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION inDir;
    IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION switchBranch;
;

SYMBOL_NAME pteSymbolName[10] = 
    sizeof(TypeOffset), PXE_BASE, "PXE_BASE",
    sizeof(TypeOffset), PXE_SELFMAP, "PXE_SELFMAP",
    sizeof(TypeOffset), PPE_BASE, "PPE_BASE",
    sizeof(TypeOffset), PDE_BASE, "PDE_BASE",
    sizeof(TypeOffset), PTE_BASE, "PTE_BASE",
    sizeof(TypeOffset), PXE_TOP, "PXE_TOP",
    sizeof(TypeOffset), PPE_TOP, "PPE_TOP",
    sizeof(TypeOffset), PDE_TOP, "PDE_TOP",
    sizeof(TypeOffset), PTE_TOP, "PTE_TOP",
    sizeof(TypeOffset), MmPagedPoolStart, "MmPagedPoolStart"
;

SYMBOL_NAME normalSymbolName[6] = 
    0, 0, "error symbol name",
    sizeof(IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER), IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE, "IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE",
    sizeof(IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER), IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE, "IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE",
    sizeof(IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION), IMAGE_DYNAMIC_RELOCATION_GUARD_IMPORT_CONTROL_TRANSFER, "IMAGE_DYNAMIC_RELOCATION_GUARD_IMPORT_CONTROL_TRANSFER (imp mov r10 call)",
    sizeof(IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION), IMAGE_DYNAMIC_RELOCATION_GUARD_INDIR_CONTROL_TRANSFER, "IMAGE_DYNAMIC_RELOCATION_GUARD_INDIR_CONTROL_TRANSFER (call rax)",
    sizeof(IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION), IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH, "IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH (jmp rcx)"
;

/*
* zero: invalid symbol
* >0 : sizeofOneBlock
*/
DWORD GetSymbolOneBlockSize(ULONG_PTR Symbol)

    if (Symbol == 0)
        return 0;

    if (Symbol > 5)
    
        for (size_t i = 0; i < sizeof(pteSymbolName); i++)
        
            if (Symbol == pteSymbolName[i].base)
                return pteSymbolName[i].sizeOfOneBlock;
        

        return 0;
    
    else
    
        return normalSymbolName[Symbol].sizeOfOneBlock;
    


void Parsefunc(PIMAGE_DYNAMIC_RELOCATION pDvr, PVOID base, ULONG_PTR dqExistRealBase)

    if (pDvr == nullptr)
        return;

    auto sizeOfOne = GetSymbolOneBlockSize(pDvr->Symbol);

    if (sizeOfOne == 0)
        return;

    auto pBaseR = (PIMAGE_BASE_RELOCATION)(pDvr + 1);
    auto sizeOfReloca = pDvr->BaseRelocSize;

    while (pBaseR->SizeOfBlock && pBaseR->VirtualAddress && sizeOfReloca)
    
        auto diff = (ULONG_PTR)base + pBaseR->VirtualAddress;
        auto item = (UNION_SYMBOL_DATA*)(pBaseR + 1);
        auto count = (pBaseR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeOfOne;

        for (size_t i = 0; i < count; ++i)
        
            auto va = diff;
            switch (pDvr->Symbol)
            
            case 1:
                break;
            case 2:
                break;
            case 3:
                va = va + item->imp.PageRelativeOffset;
                break;
            case 4:
                va = va + item->inDir.PageRelativeOffset;
                break;
            case 5:
                va = va + item->switchBranch.PageRelativeOffset;
                break;
            default:
                // ntos kernel about the randomization of pte
                va = va + item->offset.Offset;
                break;
            

            item = (UNION_SYMBOL_DATA*)((PUCHAR)item + sizeOfOne);

            // end of block
            if (va == diff && i)
                continue;

            auto OriginVa = va - (ULONG_PTR)base + dqExistRealBase;

            if (g_bPdb)
            
                ULONG_PTR dwDisplacement = 0;
                auto strName = parseAddress(va, &dwDisplacement);
                std::cout << va << " name: " << strName << "+0x" << std::hex << dwDisplacement << " OriginVa: " << std::hex << OriginVa << std::endl;
            
            else
            
                std::cout << va << " OriginVa: " << std::hex << OriginVa << std::endl;
            
        

        sizeOfReloca -= pBaseR->SizeOfBlock;

        pBaseR = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)pBaseR + pBaseR->SizeOfBlock);
    
void Test(const wchar_t* szFileName, ULONG_PTR dqExistRealBase)

    HANDLE hFile = INVALID_HANDLE_VALUE;
    HANDLE hSection = nullptr;
    PVOID base = nullptr;

    do
    
        if (szFileName == nullptr)
            break;

        std::wcout << szFileName << std::endl;

        GetFileVersionOfPath(szFileName, nullptr, nullptr, nullptr, nullptr);

        hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);

        if (hFile == INVALID_HANDLE_VALUE)
        
            std::cout << "open file faild" << std::endl;
            break;
        

        if (!NT_SUCCESS(ZwCreateSection(&hSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_IMAGE, hFile)))
        
            std::cout << "create section faild" << std::endl;
            break;
        

        SIZE_T viewsize = 0;
        
        if (!NT_SUCCESS(ZwMapViewOfSection(hSection, ZwCurrentProcess(), &base, 0, 0, NULL, &viewsize, ViewUnmap, 0, PAGE_READONLY)))
        
            std::cout << "ZwMapViewOfSection faild" << std::endl;
            break;
        

        std::cout << "map at : " << base << std::endl;

        g_bPdb = pdbParseInitializing(szFileName, (ULONG_PTR)base);

        if (!g_bPdb)
            std::cout << "pdb Symbol Invalid" << std::endl;
        else
            std::cout << "pdb Symbol ok" << std::endl;

        ULONG size = 0;

        auto pLoadConfig = (PIMAGE_LOAD_CONFIG_DIRECTORY64)RtlImageDirectoryEntryToData(base, true, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size);

        if (pLoadConfig == nullptr)
        
            std::cout << "load config info is null" << std::endl;
            break;
        

        std::cout << "GuardFlags:" << std::hex << pLoadConfig->GuardFlags << std::endl;
        std::cout << GetGuardFlagsName(pLoadConfig->GuardFlags) << std::endl;

        if (!BooleanFlagOn(pLoadConfig->GuardFlags, IMAGE_GUARD_RETPOLINE_PRESENT))
        
            std::cout << "current file not enable retpoline " << std::endl;
            break;
        

        if (pLoadConfig->DynamicValueRelocTableOffset == 0)
        
            std::cout << "DynamicValueRelocTableOffset is null." << std::endl;
            break;
        

        // DVRT at reloc table later
        auto pOldRelocaTable = (PUCHAR)RtlImageDirectoryEntryToData(base, true, IMAGE_DIRECTORY_ENTRY_BASERELOC, &size);

        if (pOldRelocaTable == nullptr || size == 0)
        
            std::cout << "RelocTable is null." << std::endl;
            break;
        

        PIMAGE_DYNAMIC_RELOCATION_TABLE pdvrt = (PIMAGE_DYNAMIC_RELOCATION_TABLE)(pOldRelocaTable + size);

        if (IsBadReadPtr(pdvrt, sizeof(IMAGE_DYNAMIC_RELOCATION_TABLE)))
        
            std::cout << "DVRT is bad : " << std::hex << pdvrt << std::endl;
            break;
        

        std::cout << "version: " << pdvrt->Version << std::endl;
        std::cout << "size: " << std::hex << pdvrt->Size << std::endl;

        if (pdvrt->Version == 2)
        
            std::cout << "DVRT version is 2, current version not support parse" << std::endl;
            break;
        

        DWORD sizeOfDvr = 0;

        PIMAGE_DYNAMIC_RELOCATION pDvr = (PIMAGE_DYNAMIC_RELOCATION)(pdvrt + 1);

        while (sizeOfDvr < pdvrt->Size)
        
            if (IsBadReadPtr(pDvr, sizeof(IMAGE_DYNAMIC_RELOCATION)))
            
                std::cout << "bad read ptr of Dvr :" << std::hex << pDvr << " size: " << std::hex << sizeOfDvr << std::endl;
                break;
            

            if (pDvr->Symbol > IMAGE_DYNAMIC_RELOCATION_GUARD_SWITCHTABLE_BRANCH)
            
                auto bParsed = false;

                for (size_t i = 0; i < sizeof(pteSymbolName); i++)
                
                    if (pDvr->Symbol == pteSymbolName[i].base)
                    
                        std::cout << "Symbol : " << pDvr->Symbol << " parse: " << pteSymbolName[i].szName << std::endl;
                        bParsed = true;
                        break;
                    
                

                if(!bParsed)
                    std::cout << "Symbol : " << pDvr->Symbol << " parse: unknow" << std::endl;
            
            else
            
                std::cout << "Symbol : " << pDvr->Symbol << " parse: " << normalSymbolName[pDvr->Symbol].szName << std::endl;
            

            std::cout << "baseRelocSize : " << pDvr->BaseRelocSize << std::endl;

            // parse data
            Parsefunc(pDvr, base, dqExistRealBase);

            sizeOfDvr += pDvr->BaseRelocSize + sizeof(IMAGE_DYNAMIC_RELOCATION);

            auto tmp = pDvr->BaseRelocSize;

            pDvr = (PIMAGE_DYNAMIC_RELOCATION)((PUCHAR)(pDvr + 1) + tmp);
        

        std::cout << "TotalSize: " << std::hex << sizeOfDvr << std::endl;

        std::cout << "any key to unmap image" << std::endl;
        system("pause");

     while (false);

    if (g_bPdb && base)
        pdbParseTerminate((ULONG_PTR)base);

    g_bPdb = false;

    if (base)
        ZwUnmapViewOfSection(ZwCurrentProcess(), base);

    if (hSection)
        CloseHandle(hSection);

    if (hFile != INVALID_HANDLE_VALUE)
        CloseHandle(hFile);

 

https://techcommunity.microsoft.com/t5/windows-kernel-internals/mitigating-spectre-variant-2-with-retpoline-on-windows/ba-p/295618

https://xlab.tencent.com/en/2016/11/02/return-flow-guard/

 

 

以上是关于win10 Dynamic Value Relocation Table Retpoline解析的主要内容,如果未能解决你的问题,请参考以下文章

unexpected reloc type问题分析

BFD_RELOC_64:使用 C++ 在 32 位 linux 上编译汇编器指令

Ubuntu16 编译源码出错 unsupported reloc 43

Ubuntu16 编译源码出错 unsupported reloc 43

Ubuntu16 编译源码出错 unsupported reloc 43

lsnrctl: .... cannot restore segment prot after reloc: Permission denied