├── .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 | }
--------------------------------------------------------------------------------