├── hook.png ├── VanguardTrace ├── Signature Scan.hpp ├── VanguardTrace.vcxproj.user ├── Include.hpp ├── Hooks.hpp ├── Vanguard.hpp ├── Native.hpp ├── Hooks.cpp ├── Main.cpp ├── Native.cpp ├── Signature Scan.cpp ├── VanguardTrace.vcxproj.filters ├── Vanguard.cpp └── VanguardTrace.vcxproj ├── VanguardTrace.sln ├── LICENSE └── README.md /hook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/armvirus/VanguardTrace/HEAD/hook.png -------------------------------------------------------------------------------- /VanguardTrace/Signature Scan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Scanner 4 | { 5 | PVOID FindPatternImage(PCHAR base, PCHAR pattern, PCHAR mask); 6 | PVOID FindPatternImageExec(PCHAR base, PCHAR pattern, PCHAR mask); 7 | PVOID FindPattern(PCHAR base, DWORD length, PCHAR pattern, PCHAR mask); 8 | } -------------------------------------------------------------------------------- /VanguardTrace/VanguardTrace.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Off 5 | 6 | -------------------------------------------------------------------------------- /VanguardTrace/Include.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "Native.hpp" 11 | #include "Signature Scan.hpp" 12 | #include "Vanguard.hpp" 13 | #include "Hooks.hpp" 14 | 15 | #define RVA(Instr, InstrSize) ((ULONG64)Instr + InstrSize + *(LONG*)((ULONG64)Instr + (InstrSize - sizeof(LONG)))) 16 | #define DebugPrint(fmt, ...) DbgPrintEx(0, 0, "[VanguardStackTrace] " fmt, ##__VA_ARGS__) -------------------------------------------------------------------------------- /VanguardTrace/Hooks.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Hooks 4 | { 5 | inline NTSTATUS(*CiCheckSignedFileOg)(void* Buf1, size_t Size, unsigned int a3, __int64 a4, unsigned int a5, __int64 a6, __int64* a7, __int64* a8); 6 | 7 | NTSTATUS CiCheckSignedFileHookVgk(void* Buf1, size_t Size, unsigned int a3, __int64 a4, unsigned int a5, __int64 a6, __int64* a7, __int64* a8); 8 | NTSTATUS ZwDeviceIoControlFileHook(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength); 9 | } -------------------------------------------------------------------------------- /VanguardTrace/Vanguard.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct KeyOffsets { 4 | __int64 wordOffset; // Previously key1 5 | __int64 qwordPtrOffset; // Previously key2 6 | __int64 qwordOffset; // Previously key3 7 | __int64 byteCountOffset; // Previously key4 8 | }; 9 | 10 | namespace Vanguard 11 | { 12 | void HookVgkImportFunction(std::uintptr_t VanguardBase, std::uintptr_t ImportOffset, std::uintptr_t originalFunctionPtr); 13 | std::uintptr_t DecryptVGKImportFunction(std::uintptr_t VanguardBase, std::uintptr_t ImportOffset); 14 | std::uint32_t findImportOffset(std::uintptr_t VanguardBase, const char* ImportModule, const char* ImportName, std::uint32_t startOffset); 15 | std::uint32_t getImportStartOffset(std::uintptr_t VanguardBase, std::size_t VanguardSize); 16 | } -------------------------------------------------------------------------------- /VanguardTrace/Native.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern "C" 4 | { 5 | NTSTATUS NTAPI ZwQuerySystemInformation(ULONG SystemInformationClass, PVOID SystemInformation, 6 | ULONG SystemInformationLength, PULONG ReturnLength); 7 | 8 | extern "C" NTKERNELAPI 9 | PVOID 10 | NTAPI 11 | RtlFindExportedRoutineByName( 12 | _In_ PVOID ImageBase, 13 | _In_ PCCH RoutineNam 14 | ); 15 | } 16 | 17 | namespace Native 18 | { 19 | NTSTATUS getKernelModuleByName(const char *moduleName, std::uintptr_t *moduleStart, std::size_t *moduleSize); 20 | } 21 | 22 | typedef struct _SYSTEM_MODULE_ENTRY { 23 | HANDLE Section; 24 | PVOID MappedBase; 25 | PVOID ImageBase; 26 | ULONG ImageSize; 27 | ULONG Flags; 28 | USHORT LoadOrderIndex; 29 | USHORT InitOrderIndex; 30 | USHORT LoadCount; 31 | USHORT OffsetToFileName; 32 | UCHAR FullPathName[256]; 33 | } SYSTEM_MODULE_ENTRY, * PSYSTEM_MODULE_ENTRY; 34 | 35 | typedef struct _SYSTEM_MODULE_INFORMATION { 36 | ULONG Count; 37 | SYSTEM_MODULE_ENTRY Module[1]; 38 | } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION; -------------------------------------------------------------------------------- /VanguardTrace.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32901.215 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VanguardTrace", "VanguardTrace\VanguardTrace.vcxproj", "{1E272B48-82A2-4222-97C4-BC6D4FA1CBF6}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|x64 = Release|x64 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {1E272B48-82A2-4222-97C4-BC6D4FA1CBF6}.Release|x64.ActiveCfg = Release|x64 14 | {1E272B48-82A2-4222-97C4-BC6D4FA1CBF6}.Release|x64.Build.0 = Release|x64 15 | {1E272B48-82A2-4222-97C4-BC6D4FA1CBF6}.Release|x64.Deploy.0 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {FF68B84B-D997-4FA3-8258-A9B5E5967AFF} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 armvirus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /VanguardTrace/Hooks.cpp: -------------------------------------------------------------------------------- 1 | #include "Include.hpp" 2 | 3 | namespace Hooks 4 | { 5 | NTSTATUS CiCheckSignedFileHookVgk(void* Buf1, size_t Size, unsigned int a3, __int64 a4, unsigned int a5, __int64 a6, __int64* a7, __int64* a8) 6 | { 7 | auto ret = CiCheckSignedFileOg(Buf1, Size, a3, a4, a5, a6, a7, a8); 8 | 9 | DebugPrint("[%p] CiCheckSignedFile Called with Buf %p\n", _ReturnAddress(), Buf1); 10 | 11 | return ret == STATUS_INVALID_IMAGE_HASH ? STATUS_SUCCESS : ret; 12 | } 13 | 14 | NTSTATUS ZwDeviceIoControlFileHook(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength) 15 | { 16 | DebugPrint("ZwDeviceIoControlFile Called From 0x%p\n", _ReturnAddress()); 17 | DebugPrint(" - IoControlCode: 0x%p\n", IoControlCode); 18 | 19 | return ZwDeviceIoControlFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /VanguardTrace/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "Include.hpp" 2 | 3 | NTSTATUS DriverEntry(const PDRIVER_OBJECT driverObject, const PUNICODE_STRING registryPath) 4 | { 5 | DebugPrint("Vanguard Trace Hook Initiating...\n"); 6 | 7 | std::uintptr_t moduleBase = 0; 8 | std::size_t moduleSize = 0; 9 | 10 | if (Native::getKernelModuleByName("vgk.sys", &moduleBase, &moduleSize)) 11 | return STATUS_NOT_FOUND; 12 | 13 | std::uint32_t startOffset = Vanguard::getImportStartOffset(moduleBase, moduleSize); // 0x816a0; 14 | 15 | DebugPrint("Found startOffset @ 0x%x", startOffset); 16 | 17 | std::uint32_t ExCreateCallbackOffset = Vanguard::findImportOffset(moduleBase, "ntoskrnl.exe", "ExCreateCallback", startOffset); 18 | 19 | DebugPrint("Found ExCreateCallbackOffset @ 0x%x", ExCreateCallbackOffset); 20 | 21 | std::uint32_t CiCheckSignedFileOffset = Vanguard::findImportOffset(moduleBase, "CI.dll", "CiCheckSignedFile", startOffset); 22 | 23 | DebugPrint("Found CiCheckSignedFileOffset @ 0x%x", CiCheckSignedFileOffset); 24 | 25 | *reinterpret_cast(&Hooks::CiCheckSignedFileOg) = Vanguard::DecryptVGKImportFunction(moduleBase, CiCheckSignedFileOffset); 26 | 27 | Vanguard::HookVgkImportFunction(moduleBase, CiCheckSignedFileOffset, reinterpret_cast(&Hooks::CiCheckSignedFileHookVgk)); 28 | 29 | return STATUS_SUCCESS; 30 | } -------------------------------------------------------------------------------- /VanguardTrace/Native.cpp: -------------------------------------------------------------------------------- 1 | #include "Include.hpp" 2 | 3 | namespace Native 4 | { 5 | NTSTATUS getKernelModuleByName(const char* moduleName, std::uintptr_t* moduleStart, std::size_t* moduleSize) 6 | { 7 | if (!moduleStart || !moduleSize) 8 | return STATUS_INVALID_PARAMETER; 9 | 10 | std::size_t size{}; 11 | ZwQuerySystemInformation(0xB, nullptr, size, reinterpret_cast(&size)); 12 | 13 | const auto listHeader = ExAllocatePool(NonPagedPool, size); 14 | if (!listHeader) 15 | return STATUS_MEMORY_NOT_ALLOCATED; 16 | 17 | if (const auto status = ZwQuerySystemInformation(0xB, listHeader, size, reinterpret_cast(&size))) 18 | return status; 19 | 20 | auto currentModule = reinterpret_cast(listHeader)->Module; 21 | for (std::size_t i{}; i < reinterpret_cast(listHeader)->Count; ++i, ++currentModule) 22 | { 23 | const auto currentModuleName = reinterpret_cast(currentModule->FullPathName + currentModule->OffsetToFileName); 24 | //DebugPrint("currentModuleName %s\n", currentModuleName); 25 | if (!strcmp(moduleName, currentModuleName)) 26 | { 27 | *moduleStart = reinterpret_cast(currentModule->ImageBase); 28 | *moduleSize = currentModule->ImageSize; 29 | return STATUS_SUCCESS; 30 | } 31 | } 32 | 33 | return STATUS_NOT_FOUND; 34 | } 35 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VanguardTrace 2 | 3 | ### Decrypting and Intercepting Encrypted Imports of Vanguard's Kernel Driver 4 | 5 | Welcome to VanguardTrace, a tool designed to decrypt and intercept encrypted imports within Vanguard's Kernel Driver. 6 | 7 | ## Overview 8 | 9 | I began my exploration of vgk.sys and its import protection mechanisms. One strategy that immediately occurred to me for gaining insight was to employ a patchguard bypass. By hooking potential imports and capturing their return addresses, I could trace back to where vgk.sys calls these imports. This approach led me directly to their decryption algorithm. With a clear understanding of this algorithm, I proceeded to rewrite it for readability and created the complementary encryption function. Additionally, I developed functions to determine the starting offset of the imports encryption "table" using a simple signature scan, and to retrieve the offset of specific imports of interest. 10 | 11 | ## Features 12 | 13 | - **Decryption**: Decrypt encrypted imports within Vanguard's Kernel Driver. 14 | - **Interception**: Intercept and manipulate encrypted imports. 15 | - **Pointer Encryption**: Encrypt pointers with their encryption routine to assist with intercepting. 16 | - **Automatic Import Table Location**: Automatically locate the start of the encrypted import table using a signature scan. 17 | - **Offset Identification**: Identify the offset of the desired import for easy manipulation/hooking. 18 | 19 | ## Example Usage 20 | 21 | ![CiCheckSignedFile](./hook.png) 22 | 23 | ## License 24 | 25 | This project is licensed under the [MIT License](LICENSE). 26 | -------------------------------------------------------------------------------- /VanguardTrace/Signature Scan.cpp: -------------------------------------------------------------------------------- 1 | #include "Include.hpp" 2 | 3 | namespace Scanner 4 | { 5 | BOOLEAN CheckMask(PCHAR base, PCHAR pattern, PCHAR mask) 6 | { 7 | for (; *mask; ++base, ++pattern, ++mask) 8 | { 9 | if (*mask == 'x' && *base != *pattern) 10 | { 11 | return FALSE; 12 | } 13 | } 14 | 15 | return TRUE; 16 | } 17 | 18 | PVOID FindPattern(PCHAR base, DWORD length, PCHAR pattern, PCHAR mask) 19 | { 20 | length -= (DWORD)strlen(mask); 21 | 22 | for (DWORD i = 0; i <= length; ++i) 23 | { 24 | PVOID addr = &base[i]; 25 | if (CheckMask((PCHAR)addr, pattern, mask)) 26 | { 27 | return addr; 28 | } 29 | } 30 | 31 | return 0; 32 | } 33 | 34 | PVOID FindPatternImage(PCHAR base, PCHAR pattern, PCHAR mask) 35 | { 36 | PVOID match = 0; 37 | 38 | PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)(base + ((PIMAGE_DOS_HEADER)base)->e_lfanew); 39 | PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(headers); 40 | 41 | for (DWORD i = 0; i < headers->FileHeader.NumberOfSections; ++i) 42 | { 43 | PIMAGE_SECTION_HEADER section = §ions[i]; 44 | 45 | if (memcmp(section->Name, ".text", 5) == 0) 46 | { 47 | match = FindPattern(base + section->VirtualAddress, section->Misc.VirtualSize, pattern, mask); 48 | if (match) 49 | { 50 | break; 51 | } 52 | } 53 | } 54 | 55 | return match; 56 | } 57 | 58 | PVOID FindPatternImageExec(PCHAR base, PCHAR pattern, PCHAR mask) 59 | { 60 | PVOID match = 0; 61 | 62 | PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)(base + ((PIMAGE_DOS_HEADER)base)->e_lfanew); 63 | PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(headers); 64 | 65 | for (DWORD i = 0; i < headers->FileHeader.NumberOfSections; ++i) 66 | { 67 | PIMAGE_SECTION_HEADER section = §ions[i]; 68 | 69 | if (*(PINT)section->Name == 'EGAP' || memcmp(section->Name, ".text", 5) == 0) 70 | { 71 | match = FindPattern(base + section->VirtualAddress, section->Misc.VirtualSize, pattern, mask); 72 | if (match) 73 | { 74 | break; 75 | } 76 | } 77 | } 78 | 79 | return match; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /VanguardTrace/VanguardTrace.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Source Files 24 | 25 | 26 | Source Files 27 | 28 | 29 | Source Files 30 | 31 | 32 | Source Files 33 | 34 | 35 | Source Files 36 | 37 | 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | -------------------------------------------------------------------------------- /VanguardTrace/Vanguard.cpp: -------------------------------------------------------------------------------- 1 | #include "Include.hpp" 2 | 3 | namespace Vanguard 4 | { 5 | void HookVgkImportFunction(std::uintptr_t VanguardBase, std::uintptr_t ImportOffset, std::uintptr_t originalFunctionPtr) 6 | { 7 | if (!VanguardBase || !ImportOffset || !originalFunctionPtr) 8 | return; 9 | 10 | KeyOffsets offsets = { 11 | ImportOffset, 12 | ImportOffset + 0x8, 13 | ImportOffset + 0x18, 14 | ImportOffset + 0x20 15 | }; 16 | 17 | // Retrieve the original values from the offsets 18 | uintptr_t& wordAtKey1 = *reinterpret_cast(VanguardBase + offsets.wordOffset); 19 | uintptr_t& functionXor = *reinterpret_cast(VanguardBase + offsets.qwordPtrOffset + 8 * HIBYTE(wordAtKey1)); 20 | uintptr_t& byteCount = *reinterpret_cast(VanguardBase + offsets.byteCountOffset); 21 | unsigned char byteCountValue = static_cast(byteCount); 22 | 23 | // Reverse the XOR operations for the byteCount part 24 | if (HIBYTE(byteCount) > 0) { 25 | uintptr_t valueAtKey3 = *reinterpret_cast(VanguardBase + offsets.qwordOffset); 26 | for (size_t i = 8 - HIBYTE(byteCount); i < 8; ++i) { 27 | reinterpret_cast(&originalFunctionPtr)[i] ^= reinterpret_cast(valueAtKey3)[i]; 28 | } 29 | } 30 | 31 | // Reverse the XOR operations for the main encryption loop 32 | for (int8_t i = byteCountValue - 1; i >= 0; --i) { 33 | uintptr_t xorValue = *reinterpret_cast(VanguardBase + offsets.qwordOffset + 8 * (i & 0xFF)); 34 | originalFunctionPtr ^= xorValue; 35 | } 36 | 37 | // Overwrite the original function pointer with the encrypted value 38 | functionXor = originalFunctionPtr; 39 | } 40 | 41 | std::uintptr_t DecryptVGKImportFunction(std::uintptr_t VanguardBase, std::uintptr_t ImportOffset) 42 | { 43 | if (!VanguardBase || !ImportOffset) 44 | return 0; 45 | 46 | KeyOffsets offsets = { 47 | ImportOffset, 48 | ImportOffset + 0x8, 49 | ImportOffset + 0x18, 50 | ImportOffset + 0x20 51 | }; 52 | 53 | uintptr_t wordAtKey1 = *reinterpret_cast(VanguardBase + offsets.wordOffset); 54 | if (!wordAtKey1) 55 | return 0; 56 | 57 | uintptr_t functionXor = *reinterpret_cast<__int64*>(VanguardBase + offsets.qwordPtrOffset + 8 * HIBYTE(wordAtKey1)); 58 | if (!functionXor) 59 | return 0; 60 | 61 | uintptr_t byteCount = *reinterpret_cast(VanguardBase + offsets.byteCountOffset); 62 | if (byteCount != 1) 63 | return 0; 64 | 65 | unsigned char byteCountValue = static_cast(byteCount); 66 | 67 | for (uint8_t i = 0; i < byteCountValue; ++i) { 68 | uintptr_t xorValue = *reinterpret_cast(VanguardBase + offsets.qwordOffset + 8 * (i & 0xFF)); 69 | functionXor ^= xorValue; 70 | } 71 | 72 | if (HIBYTE(byteCount) > 0) 73 | { 74 | uintptr_t valueAtKey3 = *reinterpret_cast(VanguardBase + offsets.qwordOffset); 75 | 76 | for (size_t i = 8 - HIBYTE(byteCount); i < 8; ++i) { 77 | reinterpret_cast(&functionXor)[i] ^= reinterpret_cast(valueAtKey3)[i]; 78 | } 79 | } 80 | 81 | return functionXor; 82 | } 83 | 84 | std::uint32_t getImportStartOffset(std::uintptr_t VanguardBase, std::size_t VanguardSize) 85 | { 86 | if (!VanguardBase || !VanguardSize) 87 | return 0; 88 | 89 | // [actual address in first opcode] 66 0F AB D3 44 38 1D ? ? ? ? 90 | // 66 C7 05 ? ? ? ? ? ? 48 63 D5 91 | // 4C 8D 05 ? ? ? ? 48 0F B7 CA 92 | 93 | std::uintptr_t leaStartOffset = reinterpret_cast(Scanner::FindPattern(reinterpret_cast(VanguardBase), VanguardSize, "\x8A\x15\x00\x00\x00\x00\xE9\x00\x00\x00\x00\x48\x98", "xx????x????xx")); 94 | if (!leaStartOffset || !MmIsAddressValid(reinterpret_cast(leaStartOffset))) 95 | return 0; 96 | 97 | std::uintptr_t startOffset = RVA(leaStartOffset, 6); 98 | if (!startOffset || !MmIsAddressValid(reinterpret_cast(startOffset))) 99 | return 0; 100 | 101 | std::uint32_t randomOffset = startOffset - VanguardBase - 1; 102 | 103 | std::uint32_t firstImport = 0; 104 | for (int i = 0;; i++) 105 | { 106 | std::uint32_t Offset = randomOffset - i * 0x28; 107 | std::uintptr_t DecryptedRoutine = Vanguard::DecryptVGKImportFunction(VanguardBase, Offset); 108 | if (!DecryptedRoutine || !MmIsAddressValid(reinterpret_cast(DecryptedRoutine))) 109 | break; 110 | 111 | firstImport = Offset; 112 | } 113 | 114 | return firstImport; 115 | } 116 | 117 | std::uint32_t findImportOffset(std::uintptr_t VanguardBase, const char* ImportModule, const char* ImportName, std::uint32_t startOffset) 118 | { 119 | if (!VanguardBase || !startOffset) 120 | return 0; 121 | 122 | std::uintptr_t importModuleBase{}; 123 | std::size_t importModuleSize{}; 124 | 125 | if (!NT_SUCCESS(Native::getKernelModuleByName(ImportModule, &importModuleBase, &importModuleSize))) 126 | return 0; 127 | 128 | std::uintptr_t importAddress = reinterpret_cast(RtlFindExportedRoutineByName(reinterpret_cast(importModuleBase), ImportName)); 129 | if (!importAddress) 130 | return 0; 131 | 132 | for (int i = 0; ; i++) 133 | { 134 | std::uint32_t Offset = startOffset + i * 0x28; 135 | std::uintptr_t DecryptedRoutine = Vanguard::DecryptVGKImportFunction(VanguardBase, Offset); 136 | if (!DecryptedRoutine || !MmIsAddressValid(reinterpret_cast(DecryptedRoutine))) 137 | break; 138 | 139 | if (importAddress == DecryptedRoutine) 140 | return Offset; 141 | } 142 | 143 | return 0; 144 | } 145 | } -------------------------------------------------------------------------------- /VanguardTrace/VanguardTrace.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | {1E272B48-82A2-4222-97C4-BC6D4FA1CBF6} 39 | {1bc93793-694f-48fe-9372-81e2b05556fd} 40 | v4.5 41 | 12.0 42 | Debug 43 | Win32 44 | VanguardTrace 45 | $(LatestTargetPlatformVersion) 46 | VanguardTrace 47 | 48 | 49 | 50 | Windows10 51 | true 52 | WindowsKernelModeDriver10.0 53 | Driver 54 | KMDF 55 | Universal 56 | 57 | 58 | Windows10 59 | false 60 | WindowsKernelModeDriver10.0 61 | Driver 62 | KMDF 63 | Universal 64 | 65 | 66 | Windows10 67 | true 68 | WindowsKernelModeDriver10.0 69 | Driver 70 | KMDF 71 | Universal 72 | 73 | 74 | Windows10 75 | false 76 | WindowsKernelModeDriver10.0 77 | Driver 78 | KMDF 79 | Universal 80 | false 81 | 1 82 | 83 | 84 | Windows10 85 | true 86 | WindowsKernelModeDriver10.0 87 | Driver 88 | KMDF 89 | Universal 90 | 91 | 92 | Windows10 93 | false 94 | WindowsKernelModeDriver10.0 95 | Driver 96 | KMDF 97 | Universal 98 | 99 | 100 | Windows10 101 | true 102 | WindowsKernelModeDriver10.0 103 | Driver 104 | KMDF 105 | Universal 106 | 107 | 108 | Windows10 109 | false 110 | WindowsKernelModeDriver10.0 111 | Driver 112 | KMDF 113 | Universal 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | DbgengKernelDebugger 124 | 125 | 126 | DbgengKernelDebugger 127 | 128 | 129 | DbgengKernelDebugger 130 | $(VC_IncludePath);$(IncludePath) 131 | 132 | 133 | DbgengKernelDebugger 134 | $(VC_IncludePath);$(IncludePath) 135 | $(SolutionDir)Output\ 136 | $(SolutionDir)VanguardTrace\Bin\ 137 | false 138 | 139 | 140 | DbgengKernelDebugger 141 | 142 | 143 | DbgengKernelDebugger 144 | 145 | 146 | DbgengKernelDebugger 147 | 148 | 149 | DbgengKernelDebugger 150 | 151 | 152 | 153 | stdcpp17 154 | TurnOffAllWarnings 155 | false 156 | true 157 | 158 | 159 | DriverEntry 160 | 161 | 162 | 163 | 164 | stdcpp17 165 | TurnOffAllWarnings 166 | false 167 | true 168 | ProgramDatabase 169 | 170 | 171 | 172 | DriverEntry 173 | true 174 | false 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | --------------------------------------------------------------------------------