├── .gitignore ├── cfgdump ├── cfg.def ├── cfgdump.vcxproj.filters ├── Helper.h ├── Helper.cpp ├── cfgdump.vcxproj └── cfgdump.cpp ├── README.md └── cfg.sln /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.sdf 3 | 4 | *.suo 5 | 6 | Debug/ 7 | 8 | *.opensdf 9 | -------------------------------------------------------------------------------- /cfgdump/cfg.def: -------------------------------------------------------------------------------- 1 | LIBRARY Cfg 2 | EXPORTS 3 | ExtensionApiVersion @1 4 | WinDbgExtensionDllInit @2 5 | cfgdump @3 6 | cfgrange @4 7 | cfgcover @5 8 | cfgmap @6 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cfgdump 2 | Windbg extension that allows you analyze Control Flow Guard map 3 | 4 | # commands 5 | 6 | !cfgcover - prints memory map that is covered by CFG map and shows which region are protected by CFG bits 7 | 8 | !cfgrange \ \ - prints CFG bits for specified address range 9 | 10 | !cfgdump - prints all CFG bits for whole address space 11 | 12 | !cfgmap - prints available CFG maps 13 | -------------------------------------------------------------------------------- /cfgdump/cfgdump.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /cfgdump/Helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Exception 7 | { 8 | std::string m_errorMessage; 9 | 10 | public: 11 | 12 | Exception(const char* Format, ...); 13 | 14 | const char* What(); 15 | }; 16 | 17 | class Arguments 18 | { 19 | std::vector m_arguments; 20 | unsigned int m_argPointer; 21 | 22 | public: 23 | 24 | Arguments(const char* commandLine); 25 | 26 | size_t ArgsCount(); 27 | 28 | bool Probe(std::string& arg); 29 | bool SwitchToNext(); 30 | bool GetNext(std::string& arg); 31 | }; 32 | -------------------------------------------------------------------------------- /cfg.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cfg", "cfgdump\cfgdump.vcxproj", "{76645DE8-8AE1-40F8-8796-AA45C2B063EB}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {76645DE8-8AE1-40F8-8796-AA45C2B063EB}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {76645DE8-8AE1-40F8-8796-AA45C2B063EB}.Debug|Win32.Build.0 = Debug|Win32 18 | {76645DE8-8AE1-40F8-8796-AA45C2B063EB}.Debug|x64.ActiveCfg = Debug|x64 19 | {76645DE8-8AE1-40F8-8796-AA45C2B063EB}.Debug|x64.Build.0 = Debug|x64 20 | {76645DE8-8AE1-40F8-8796-AA45C2B063EB}.Release|Win32.ActiveCfg = Release|Win32 21 | {76645DE8-8AE1-40F8-8796-AA45C2B063EB}.Release|Win32.Build.0 = Release|Win32 22 | {76645DE8-8AE1-40F8-8796-AA45C2B063EB}.Release|x64.ActiveCfg = Release|x64 23 | {76645DE8-8AE1-40F8-8796-AA45C2B063EB}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /cfgdump/Helper.cpp: -------------------------------------------------------------------------------- 1 | #include "Helper.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | // ================= 9 | 10 | Exception::Exception(const char* Format, ...) 11 | { 12 | char buffer[256]; 13 | 14 | va_list args; 15 | va_start(args, Format); 16 | _vsnprintf_s(buffer, _countof(buffer), _TRUNCATE, Format, args); 17 | va_end(args); 18 | 19 | m_errorMessage = buffer; 20 | } 21 | 22 | const char* Exception::What() 23 | { 24 | return m_errorMessage.c_str(); 25 | } 26 | 27 | // ================= 28 | 29 | 30 | Arguments::Arguments(const char* commandLine) : m_argPointer(0) 31 | { 32 | if (!commandLine) 33 | return; 34 | 35 | char* context; 36 | auto tokens = _strdup(commandLine); 37 | auto token = strtok_s(tokens, " ", &context); 38 | 39 | if (!token) 40 | return; 41 | 42 | do { 43 | m_arguments.push_back(token); 44 | } while (token = strtok_s(nullptr, " ", &context)); 45 | 46 | free(tokens); 47 | } 48 | 49 | size_t Arguments::ArgsCount() 50 | { 51 | return m_arguments.size(); 52 | } 53 | 54 | bool Arguments::Probe(std::string& arg) 55 | { 56 | if (m_argPointer >= m_arguments.size()) 57 | return false; 58 | 59 | arg = m_arguments[m_argPointer]; 60 | return true; 61 | } 62 | 63 | bool Arguments::SwitchToNext() 64 | { 65 | if (m_argPointer >= m_arguments.size()) 66 | return false; 67 | 68 | m_argPointer++; 69 | return true; 70 | } 71 | 72 | bool Arguments::GetNext(string& arg) 73 | { 74 | if (m_argPointer >= m_arguments.size()) 75 | return false; 76 | 77 | arg = m_arguments[m_argPointer++]; 78 | return true; 79 | } 80 | -------------------------------------------------------------------------------- /cfgdump/cfgdump.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {76645DE8-8AE1-40F8-8796-AA45C2B063EB} 23 | Win32Proj 24 | cfgdump 25 | cfg 26 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | DynamicLibrary 37 | true 38 | v142 39 | Unicode 40 | 41 | 42 | DynamicLibrary 43 | false 44 | v142 45 | true 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | true 73 | 74 | 75 | true 76 | 77 | 78 | false 79 | 80 | 81 | false 82 | 83 | 84 | 85 | 86 | 87 | Level3 88 | Disabled 89 | WIN32;_DEBUG;_WINDOWS;_USRDLL;CFGDUMP_EXPORTS;%(PreprocessorDefinitions) 90 | 91 | 92 | Windows 93 | true 94 | cfg.def 95 | 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | WIN32;_DEBUG;_WINDOWS;_USRDLL;CFGDUMP_EXPORTS;%(PreprocessorDefinitions) 104 | 105 | 106 | Windows 107 | true 108 | 109 | 110 | 111 | 112 | Level3 113 | 114 | 115 | MaxSpeed 116 | true 117 | true 118 | WIN32;NDEBUG;_WINDOWS;_USRDLL;CFGDUMP_EXPORTS;%(PreprocessorDefinitions) 119 | MultiThreaded 120 | 121 | 122 | Windows 123 | true 124 | true 125 | true 126 | cfg.def 127 | 128 | 129 | 130 | 131 | Level3 132 | 133 | 134 | MaxSpeed 135 | true 136 | true 137 | WIN32;NDEBUG;_WINDOWS;_USRDLL;CFGDUMP_EXPORTS;%(PreprocessorDefinitions) 138 | MultiThreaded 139 | 140 | 141 | Windows 142 | true 143 | true 144 | true 145 | cfg.def 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /cfgdump/cfgdump.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "Helper.h" 6 | #include 7 | #include 8 | 9 | //TODO: 10 | // - Add support of legacy CFG 2-bit 11 | // - Is it possible to use output prefix? 12 | 13 | #pragma comment(lib, "dbgeng.lib") 14 | 15 | struct MapChunk { 16 | ULONGLONG address; 17 | union { 18 | unsigned long cfg32; 19 | unsigned long long cfg64; 20 | }; 21 | }; 22 | 23 | EXT_API_VERSION ExtApiVersion = { 1, 1, EXT_API_VERSION_NUMBER, 0 }; 24 | 25 | WINDBG_EXTENSION_APIS ExtensionApis = { 0 }; 26 | 27 | IDebugClient* g_DebugClient = NULL; 28 | IDebugSymbols3* g_DebugSymbols = NULL; 29 | IDebugDataSpaces2* g_DebugDataSpaces = NULL; 30 | IDebugControl3* g_DebugControl = NULL; 31 | 32 | const auto VIRTUAL32_SIZE = 0x80000000ull; 33 | const auto VIRTUAL64_SIZE = 0x800000000000ull; 34 | const ULONGLONG MAX_CFGMAP32_SIZE = (VIRTUAL32_SIZE >> 8) * sizeof(ULONG); 35 | const ULONGLONG MAX_CFGMAP64_SIZE = (VIRTUAL64_SIZE >> 9) * sizeof(ULONGLONG); 36 | 37 | enum Platform { 38 | x86, 39 | x64 40 | }; 41 | 42 | enum MapType 43 | { 44 | Auto, 45 | Cfg32, 46 | Cfg64 47 | }; 48 | 49 | Platform g_currentPlatform = Platform::x86; 50 | bool g_isWow64Process = false; 51 | 52 | // --------------------------- 53 | 54 | VOID WDBGAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis, USHORT usMajorVersion, USHORT usMinorVersion) 55 | { 56 | ExtensionApis = *lpExtensionApis; 57 | 58 | if (::DebugCreate(__uuidof(IDebugClient), (void**)&g_DebugClient) != S_OK) 59 | { 60 | dprintf("Error, acuqiring IDebugClient failed\n\n"); 61 | return; 62 | } 63 | 64 | if (g_DebugClient->QueryInterface(__uuidof(IDebugSymbols3), (void**)&g_DebugSymbols) != S_OK) 65 | { 66 | dprintf("Error, acuqiring IDebugSymbols failed\n\n"); 67 | return; 68 | } 69 | 70 | if (g_DebugClient->QueryInterface(__uuidof(IDebugDataSpaces2), (void**)&g_DebugDataSpaces) != S_OK) 71 | { 72 | dprintf("Error, acuqiring IDebugDataSpaces2 failed\n\n"); 73 | return; 74 | } 75 | 76 | if (g_DebugClient->QueryInterface(__uuidof(IDebugControl3), (void**)&g_DebugControl) != S_OK) 77 | { 78 | dprintf("Error, acuqiring IDebugControl3 failed\n\n"); 79 | return; 80 | } 81 | } 82 | 83 | LPEXT_API_VERSION WDBGAPI ExtensionApiVersion(void) 84 | { 85 | return &ExtApiVersion; 86 | } 87 | 88 | // --------------------------- 89 | 90 | bool IsX64Platform() 91 | { 92 | return (g_currentPlatform == Platform::x64); 93 | } 94 | 95 | const char* GetSpaces(unsigned int level) 96 | { 97 | switch (level) 98 | { 99 | case 0: 100 | return ""; 101 | case 1: 102 | return " "; 103 | case 2: 104 | return " "; 105 | case 3: 106 | return " "; 107 | case 4: 108 | return " "; 109 | case 5: 110 | return " "; 111 | case 6: 112 | return " "; 113 | case 7: 114 | return " "; 115 | default: 116 | break; 117 | } 118 | return " "; 119 | } 120 | 121 | void PrintCFGMapInfo(ULONGLONG cfgmap) 122 | { 123 | if (IsX64Platform()) 124 | dprintf("CFG Map64: %llx - %llx (%llx)\n\n", cfgmap, cfgmap + MAX_CFGMAP64_SIZE, MAX_CFGMAP64_SIZE); 125 | else 126 | dprintf("CFG Map32: %llx - %llx (%llx)\n\n", cfgmap, cfgmap + MAX_CFGMAP32_SIZE, MAX_CFGMAP32_SIZE); 127 | } 128 | 129 | void PrintCFGChunkHeader(unsigned int level) 130 | { 131 | if (IsX64Platform()) 132 | dprintf("\n%s Address 0123456789abcdef 0123456789abcdef 0123456789abcdef 0123456789abcdef\n", GetSpaces(level)); 133 | else 134 | dprintf("\n%s Address 0123456789abcdef 0123456789abcdef 0123456789abcdef 0123456789abcdef\n", GetSpaces(level)); 135 | } 136 | 137 | void PrintCFGChunk(const MapChunk& chunk, unsigned int level, bool clipped, bool& skipped, bool& empty) 138 | { 139 | auto bits = chunk.cfg64; 140 | 141 | for (auto i = 0; i < 8; i++) 142 | { 143 | if (clipped && (bits & 0xFF) == 0) 144 | { 145 | skipped = true; 146 | bits >>= 8; 147 | continue; 148 | } 149 | 150 | if (empty) 151 | { 152 | PrintCFGChunkHeader(level); 153 | empty = false; 154 | } 155 | 156 | if (skipped) 157 | { 158 | dprintf("%s ...\n", GetSpaces(level)); 159 | skipped = false; 160 | } 161 | 162 | if (IsX64Platform()) 163 | dprintf("%s%016llx", GetSpaces(level), chunk.address + (i * 0x40)); 164 | else 165 | dprintf("%s%08llx", GetSpaces(level), chunk.address + (i * 0x40)); 166 | 167 | for (auto a = 0; a < 4; a++) 168 | { 169 | if ((bits & 2) != 0) 170 | dprintf(" | ++++++++++++++++"); 171 | else if ((bits & 1) != 0) 172 | dprintf(" | +..............."); 173 | else 174 | dprintf(" | ................"); 175 | 176 | bits >>= 2; 177 | } 178 | 179 | dprintf("\n"); 180 | } 181 | } 182 | 183 | const char* MemoryTypeToString(DWORD type) 184 | { 185 | switch (type) 186 | { 187 | case MEM_IMAGE: 188 | return "Image"; 189 | case MEM_MAPPED: 190 | return "Mapped"; 191 | case MEM_PRIVATE: 192 | return "Private"; 193 | case 0: 194 | return "None"; 195 | default: 196 | break; 197 | } 198 | 199 | return "Unknown"; 200 | } 201 | 202 | const char* MemoryStateToString(DWORD state) 203 | { 204 | switch (state) 205 | { 206 | case MEM_COMMIT: 207 | return "Commited"; 208 | case MEM_FREE: 209 | return "Free"; 210 | case MEM_RESERVE: 211 | return "Reserved"; 212 | default: 213 | break; 214 | } 215 | 216 | return "Unknown"; 217 | } 218 | 219 | std::string ConvertProtectionToString(DWORD protection) 220 | { 221 | std::stringstream out; 222 | 223 | if (protection & PAGE_NOACCESS) 224 | out << "NoAccess"; 225 | else if (protection & PAGE_READONLY) 226 | out << "ReadOnly"; 227 | else if (protection & PAGE_READWRITE) 228 | out << "ReadWrite"; 229 | else if (protection & PAGE_WRITECOPY) 230 | out << "WriteCopy"; 231 | else if (protection & PAGE_EXECUTE) 232 | out << "Execute"; 233 | else if (protection & PAGE_EXECUTE_READ) 234 | out << "ExecuteRead"; 235 | else if (protection & PAGE_EXECUTE_READWRITE) 236 | out << "ExecuteReadWrite"; 237 | else if (protection & PAGE_EXECUTE_WRITECOPY) 238 | out << "ExecuteWriteCopy"; 239 | 240 | if (protection & PAGE_GUARD) 241 | out << "|Guard"; 242 | if (protection & PAGE_NOCACHE) 243 | out << "|NoCache"; 244 | if (protection & PAGE_WRITECOMBINE) 245 | out << "|WriteCombine"; 246 | 247 | return out.str(); 248 | } 249 | 250 | void GetMemoryInfoString(const MEMORY_BASIC_INFORMATION64& info, char* buffer, size_t size) 251 | { 252 | if (size >= 1) 253 | buffer[0] = '\0'; 254 | 255 | if (info.Type != MEM_IMAGE) 256 | return; 257 | 258 | ULONGLONG base; 259 | HRESULT result = g_DebugSymbols->GetModuleByOffset(info.AllocationBase, 0, NULL, &base); 260 | if (result != S_OK) 261 | return; 262 | 263 | result = g_DebugSymbols->GetModuleNameString(DEBUG_MODNAME_IMAGE, DEBUG_ANY_ID, base, buffer, size, NULL); 264 | if (result != S_OK) 265 | return; 266 | } 267 | 268 | void PrintCFGRegionHeader() 269 | { 270 | if (IsX64Platform()) 271 | dprintf(" Start End Size CFGbits Type State Protection\n"); 272 | else 273 | dprintf(" Start End Size CFGbits Type State Protection\n");//TODO: 274 | } 275 | 276 | const char* GetCFGRangeState(ULONGLONG cfgmap, ULONGLONG address, ULONGLONG size); 277 | 278 | void PrintCFGRegion(ULONGLONG cfgmap, ULONGLONG ptr, ULONGLONG range, const MEMORY_BASIC_INFORMATION64& info) 279 | { 280 | //TODO: add support of Wow64 map 281 | char memory[MAX_PATH]; 282 | GetMemoryInfoString(info, memory, sizeof(memory)); 283 | 284 | if (IsX64Platform()) 285 | dprintf(" %016llx | %016llx | %016llx | %s | %-8s | %-8s | %-25s %s\n", 286 | ptr, 287 | ptr + range, 288 | range, 289 | GetCFGRangeState(cfgmap, ptr, range), 290 | MemoryTypeToString(info.Type), 291 | MemoryStateToString(info.State), 292 | ConvertProtectionToString(info.Protect).c_str(), 293 | memory 294 | ); 295 | else 296 | dprintf(" %08llx | %08llx | %08llx | %s | %-8s | %-8s | %-25s %s\n", 297 | ptr, 298 | ptr + range, 299 | range, 300 | GetCFGRangeState(cfgmap, ptr, range), 301 | MemoryTypeToString(info.Type), 302 | MemoryStateToString(info.State), 303 | ConvertProtectionToString(info.Protect).c_str(), 304 | memory 305 | ); 306 | } 307 | 308 | // --------------------------- 309 | 310 | ULONGLONG ConvertAddressToCfgMapAddress(ULONGLONG cfgmap, ULONGLONG address) 311 | { 312 | return cfgmap + ((address >> 9) * 8); 313 | } 314 | 315 | bool LoadMapChunk(ULONGLONG cfgmap, ULONGLONG address, ULONGLONG size, MapChunk& chunk) 316 | { 317 | ULONG readed; 318 | HRESULT result = g_DebugDataSpaces->ReadVirtual( 319 | ConvertAddressToCfgMapAddress(cfgmap, address), 320 | &chunk.cfg64, 321 | sizeof(chunk.cfg64), 322 | &readed 323 | ); 324 | if (result != S_OK) 325 | return false; 326 | 327 | if (readed != sizeof(chunk.cfg64)) 328 | return false; 329 | 330 | chunk.address = address; 331 | return true; 332 | } 333 | 334 | void FindCFGMap(ULONGLONG& cfgmap, MapType type) 335 | { 336 | 337 | ULONGLONG top, cfgsize, ptr = 0; 338 | 339 | if (type == MapType::Cfg32) 340 | { 341 | cfgsize = MAX_CFGMAP32_SIZE; 342 | top = VIRTUAL32_SIZE; 343 | } 344 | else if (type == MapType::Cfg64) 345 | { 346 | cfgsize = MAX_CFGMAP64_SIZE; 347 | top = VIRTUAL64_SIZE; 348 | } 349 | else 350 | { 351 | cfgsize = (IsX64Platform() ? MAX_CFGMAP64_SIZE : MAX_CFGMAP32_SIZE); 352 | top = (IsX64Platform() ? VIRTUAL64_SIZE : VIRTUAL32_SIZE); 353 | } 354 | 355 | ULONGLONG start = 0; 356 | bool calculation = false; 357 | 358 | while (ptr < top) 359 | { 360 | MEMORY_BASIC_INFORMATION64 info; 361 | HRESULT result = g_DebugDataSpaces->QueryVirtual(ptr, &info); 362 | if (result != S_OK) 363 | { 364 | ptr += 0x1000; 365 | continue; 366 | } 367 | 368 | // Fix for NULL allocation base on modern OS 369 | if (!info.AllocationBase) 370 | info.AllocationBase = ptr; 371 | 372 | ptr += info.RegionSize; 373 | 374 | if (calculation) 375 | { 376 | if (start == info.AllocationBase) 377 | continue; 378 | 379 | calculation = false; 380 | if (info.AllocationBase - start == cfgsize) 381 | { 382 | cfgmap = start; 383 | return; 384 | } 385 | } 386 | 387 | if (!calculation) 388 | { 389 | if (info.Type != MEM_MAPPED) 390 | continue; 391 | 392 | if (info.BaseAddress != info.AllocationBase) 393 | continue; 394 | 395 | calculation = true; 396 | start = info.AllocationBase; 397 | } 398 | } 399 | 400 | throw Exception("can't find CFG map"); 401 | } 402 | 403 | void SelectArchitecture() 404 | { 405 | ULONG qualifier, dbgclass; 406 | 407 | HRESULT result = g_DebugControl->GetDebuggeeType(&dbgclass, &qualifier); 408 | if (result != S_OK) 409 | throw Exception("can't retreive debuggee type, code: %x\n", result); 410 | 411 | if (dbgclass != DEBUG_CLASS_USER_WINDOWS) 412 | throw Exception("supported only usermode process debugging\n"); 413 | 414 | g_currentPlatform = (g_DebugControl->IsPointer64Bit() == S_OK ? Platform::x64 : Platform::x86); 415 | } 416 | 417 | // --------------------------- 418 | 419 | bool DumpCFGMapRange(ULONGLONG cfgmap, ULONGLONG address, ULONGLONG size, unsigned int level, bool clipped) 420 | { 421 | // Address 0123456789abcdef 0123456789abcdef 0123456789abcdef 0123456789abcdef 422 | // 0000000003fce800 | ................ | ++++++++++++++++ | ................ | ................ 423 | // 0000000003fce840 | ................ | +............... | ................ | ................ 424 | // 0000000003fce880 | ................ | ++++++++++++++++ | ................ | ................ 425 | // 0000000003fce8c0 | ................ | +............... | ................ | ................ 426 | // 0000000003fce900 | ................ | ++++++++++++++++ | ................ | ................ 427 | // 0000000003fce940 | ................ | +............... | ................ | ................ 428 | // 0000000003fce980 | ................ | ++++++++++++++++ | ................ | ................ 429 | // 0000000003fce9c0 | ................ | +............... | ................ | ................ 430 | // ... 431 | // 0000000003fce080 | ................ | ++++++++++++++++ | ................ | ................ 432 | // ... 433 | 434 | const auto chunkBlockSize = 0x200ul; 435 | 436 | auto start = address - (address % chunkBlockSize); 437 | auto delta = (address + size) - start; 438 | auto chunks = (delta / chunkBlockSize) + (delta % chunkBlockSize ? 1 : 0); 439 | 440 | bool skipped = false; 441 | bool empty = true; 442 | for (auto i = 0ull; i < chunks; i++) 443 | { 444 | MapChunk chunk; 445 | auto address = start + (i * chunkBlockSize); 446 | 447 | if (!LoadMapChunk(cfgmap, address, chunkBlockSize, chunk)) 448 | { 449 | //TODO: improve it, not need to print error message for each chunk 450 | //dprintf(" %016llx | failed, can't load map bits\n", address); 451 | continue; 452 | } 453 | 454 | PrintCFGChunk(chunk, level, clipped, skipped, empty); 455 | } 456 | 457 | return !empty; 458 | } 459 | 460 | DECLARE_API(cfgrange) 461 | { 462 | try 463 | { 464 | Arguments arguments(args); 465 | ULONGLONG cfgmap = 0, start = 0, size = 0; 466 | 467 | SelectArchitecture(); 468 | FindCFGMap(cfgmap, MapType::Auto); 469 | 470 | std::string arg; 471 | if (!arguments.GetNext(arg)) 472 | throw Exception("no address argument\n"); 473 | 474 | start = std::stoll(arg, 0, 16); 475 | 476 | if (!arguments.GetNext(arg)) 477 | size = 1; 478 | else 479 | size = std::stoll(arg, 0, 16); 480 | 481 | DumpCFGMapRange(cfgmap, start, size, 1, true); 482 | } 483 | catch (Exception& e) 484 | { 485 | dprintf("Error: %s\n", e.What()); 486 | } 487 | catch (std::exception& e) 488 | { 489 | dprintf("STDError: %s\n", e.what()); 490 | } 491 | } 492 | 493 | // --------------------------- 494 | 495 | void DumpMemoryInCFGRegion(ULONGLONG cfgmap, ULONGLONG address, ULONGLONG size, bool clipped) 496 | { 497 | auto ptr = address; 498 | auto top = address + size; 499 | 500 | while (ptr < top) 501 | { 502 | MEMORY_BASIC_INFORMATION64 info; 503 | HRESULT result = g_DebugDataSpaces->QueryVirtual(ptr, &info); 504 | if (result != S_OK) 505 | { 506 | dprintf("Warning: query virtual address %llx failed, code: %x\n", ptr, result); 507 | ptr += 0x1000; 508 | continue; 509 | } 510 | 511 | auto range = info.BaseAddress + info.RegionSize - ptr; 512 | 513 | if (ptr + range > top) 514 | range = top - ptr; 515 | 516 | dprintf(" Region: %llx - %llx (%llx), %s, %s\n", 517 | ptr, 518 | ptr + range, 519 | range, 520 | MemoryStateToString(info.State), 521 | MemoryTypeToString(info.Type) 522 | ); 523 | 524 | if (!DumpCFGMapRange(cfgmap, ptr, range, 3, clipped)) 525 | dprintf(" without cfg bits\n"); 526 | 527 | dprintf("\n"); 528 | ptr += range; 529 | } 530 | } 531 | 532 | void DumpFullCFGMap(ULONGLONG cfgmap) 533 | { 534 | auto cfgptr = cfgmap; 535 | auto cfgtop = cfgmap + (IsX64Platform() ? MAX_CFGMAP64_SIZE : MAX_CFGMAP32_SIZE); 536 | 537 | dprintf("\n"); 538 | 539 | PrintCFGMapInfo(cfgmap); 540 | 541 | while (cfgptr < cfgtop) 542 | { 543 | MEMORY_BASIC_INFORMATION64 info; 544 | HRESULT result = g_DebugDataSpaces->QueryVirtual(cfgptr, &info); 545 | if (result != S_OK) 546 | { 547 | dprintf("Warning: query virtual address %llx failed, code: %x\n", cfgptr, result); 548 | cfgptr += 0x1000; 549 | continue; 550 | } 551 | 552 | if (info.AllocationBase != cfgmap) 553 | { 554 | dprintf("Warning: allocation base missmatched %016llx != %016llx\n", info.AllocationBase, cfgmap); 555 | break; 556 | } 557 | 558 | if (info.State != MEM_COMMIT || (info.Protect & PAGE_NOACCESS) != 0) 559 | { 560 | //dprintf("Skip no access: %016llx, %016llx\n", cfgptr, info.RegionSize); 561 | cfgptr += info.RegionSize; 562 | continue; 563 | } 564 | 565 | auto address = ((cfgptr - cfgmap) << 9ull) / 8; 566 | auto size = (info.RegionSize / 8ull) * 0x200ull; 567 | 568 | dprintf(" CFG Region: %llx - %llx (%llx)\n\n", address, address + size, size); 569 | 570 | DumpMemoryInCFGRegion(cfgmap, address, size, true); 571 | 572 | cfgptr += info.RegionSize; 573 | dprintf("\n"); 574 | } 575 | } 576 | 577 | DECLARE_API(cfgdump) 578 | { 579 | try 580 | { 581 | ULONGLONG cfgmap; 582 | SelectArchitecture(); 583 | FindCFGMap(cfgmap, MapType::Auto); 584 | DumpFullCFGMap(cfgmap); 585 | } 586 | catch (Exception& e) 587 | { 588 | dprintf("Error: %s\n", e.What()); 589 | } 590 | catch (std::exception& e) 591 | { 592 | dprintf("STDError: %s\n", e.what()); 593 | } 594 | } 595 | 596 | // --------------------------- 597 | 598 | const char* GetCFGRangeState(ULONGLONG cfgmap, ULONGLONG address, ULONGLONG size) 599 | { 600 | const auto chunkBlockSize = 0x200ul; 601 | 602 | auto start = address - (address % chunkBlockSize); 603 | auto delta = (address + size) - start; 604 | auto chunks = (delta / chunkBlockSize) + (delta % chunkBlockSize ? 1 : 0); 605 | bool failed = false; 606 | 607 | for (auto i = 0ull; i < chunks; i++) 608 | { 609 | MapChunk chunk; 610 | auto address = start + (i * chunkBlockSize); 611 | 612 | if (!LoadMapChunk(cfgmap, address, chunkBlockSize, chunk)) 613 | { 614 | failed = true; 615 | continue; 616 | } 617 | 618 | if (chunk.cfg64) 619 | return "+"; 620 | } 621 | 622 | return (failed ? "?" : " "); 623 | } 624 | 625 | void DumpMemoryMapInCFGRegion(ULONGLONG cfgmap, ULONGLONG address, ULONGLONG size) 626 | { 627 | auto ptr = address; 628 | auto top = address + size; 629 | 630 | PrintCFGRegionHeader(); 631 | 632 | while (ptr < top) 633 | { 634 | MEMORY_BASIC_INFORMATION64 info; 635 | HRESULT result = g_DebugDataSpaces->QueryVirtual(ptr, &info); 636 | if (result != S_OK) 637 | { 638 | dprintf("Warning: query virtual address %llx failed, code: %x\n", ptr, result); 639 | ptr += 0x1000; 640 | continue; 641 | } 642 | 643 | auto range = info.BaseAddress + info.RegionSize - ptr; 644 | 645 | if (ptr + range > top) 646 | range = top - ptr; 647 | 648 | PrintCFGRegion(cfgmap, ptr, range, info); 649 | 650 | ptr += range; 651 | } 652 | } 653 | 654 | void DumpCFGCoveredMemory(ULONGLONG cfgmap) 655 | { 656 | auto cfgptr = cfgmap; 657 | auto cfgtop = cfgmap + (IsX64Platform() ? MAX_CFGMAP64_SIZE : MAX_CFGMAP32_SIZE); 658 | 659 | dprintf("\n"); 660 | 661 | PrintCFGMapInfo(cfgmap); 662 | 663 | while (cfgptr < cfgtop) 664 | { 665 | MEMORY_BASIC_INFORMATION64 info; 666 | HRESULT result = g_DebugDataSpaces->QueryVirtual(cfgptr, &info); 667 | if (result != S_OK) 668 | { 669 | dprintf("Warning: query virtual address %llx failed, code: %x\n", cfgptr, result); 670 | cfgptr += 0x1000; 671 | continue; 672 | } 673 | 674 | if (info.AllocationBase != cfgmap) 675 | { 676 | dprintf("Warning: allocation base missmatched %llx != %llx\n", info.AllocationBase, cfgmap); 677 | break; 678 | } 679 | 680 | if (info.State != MEM_COMMIT || (info.Protect & PAGE_NOACCESS) != 0) 681 | { 682 | //dprintf("Skip no access: %016llx, %016llx\n", cfgptr, info.RegionSize); 683 | cfgptr += info.RegionSize; 684 | continue; 685 | } 686 | 687 | auto address = ((cfgptr - cfgmap) << 9ull) / 8; 688 | auto size = (info.RegionSize / 8ull) * 0x200ull; 689 | 690 | dprintf(" CFG Region: %llx - %llx (%llx)\n\n", address, address + size, size); 691 | 692 | DumpMemoryMapInCFGRegion(cfgmap, address, size); 693 | 694 | cfgptr += info.RegionSize; 695 | dprintf("\n"); 696 | } 697 | } 698 | 699 | DECLARE_API(cfgcover) 700 | { 701 | try 702 | { 703 | ULONGLONG cfgmap; 704 | SelectArchitecture(); 705 | FindCFGMap(cfgmap, MapType::Auto); 706 | DumpCFGCoveredMemory(cfgmap); 707 | } 708 | catch (Exception& e) 709 | { 710 | dprintf("Error: %s\n", e.What()); 711 | } 712 | catch (std::exception& e) 713 | { 714 | dprintf("STDError: %s\n", e.what()); 715 | } 716 | } 717 | 718 | // --------------------------- 719 | 720 | void DumpProcessCFGMap(MapType type) 721 | { 722 | ULONGLONG cfgmap; 723 | 724 | if (type == MapType::Auto) 725 | return; 726 | 727 | try 728 | { 729 | FindCFGMap(cfgmap, type); 730 | } 731 | catch (...) 732 | { 733 | return; 734 | } 735 | 736 | dprintf( 737 | "CFG Map%s: %llx - %llx (%llx)\n", 738 | (type == MapType::Cfg32 ? "32" : "64"), 739 | cfgmap, 740 | cfgmap + (type == MapType::Cfg32 ? MAX_CFGMAP32_SIZE : MAX_CFGMAP64_SIZE), 741 | (type == MapType::Cfg32 ? MAX_CFGMAP32_SIZE : MAX_CFGMAP64_SIZE) 742 | ); 743 | } 744 | 745 | DECLARE_API(cfgmap) 746 | { 747 | try 748 | { 749 | DumpProcessCFGMap(MapType::Cfg32); 750 | DumpProcessCFGMap(MapType::Cfg64); 751 | } 752 | catch (Exception& e) 753 | { 754 | dprintf("Error: %s\n", e.What()); 755 | } 756 | catch (std::exception& e) 757 | { 758 | dprintf("STDError: %s\n", e.what()); 759 | } 760 | } --------------------------------------------------------------------------------