PE-sieve
Scans all running processes. Recognizes and dumps a variety of potentially malicious implants (replaced/implanted PEs, shellcodes, hooks, in-memory patches).
Loading...
Searching...
No Matches
process_symbols.h
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4#include <iostream>
5
6#include <dbghelp.h>
7#include "dbg_help_wrapper.h"
8
9#ifdef _MSC_VER
10 #define ALIGNED8 __declspec(align(8))
11#else
12 #define ALIGNED8 __attribute__((aligned(8)))
13#endif
14
15//---
17{
18public:
19
21 : hProcess(NULL), isInit(false)
22 {
23 }
24
29
31
33
34 //---
35#ifdef _TEST
36 void ForceRealSymbolDownload(HANDLE hProcess)
37 {
38 HMODULE ntdll_hndl = GetModuleHandleA("ntdll.dll");
39 std::cout << "\n[+] Try export first...\n";
40 dumpSymbolInfo((DWORD64)GetProcAddress(ntdll_hndl, "NtLoadKeyEx"));
41 std::cout << "\n[+] Forcing SymFromAddr on non-export address...\n";
42 dumpSymbolInfo((DWORD64)GetModuleHandleA("kernel32.dll") + 0x20000);
43 dumpSymbolInfo((DWORD64)ntdll_hndl + 0x7A80);
44
45 }
46#endif //_TEST
47 //---
48
49 static DWORD BuildSymOptions()
50 {
51 DWORD symOptions =
52 SYMOPT_CASE_INSENSITIVE |
53 SYMOPT_UNDNAME |
54 SYMOPT_FAIL_CRITICAL_ERRORS |
55 SYMOPT_AUTO_PUBLICS |
56 SYMOPT_INCLUDE_32BIT_MODULES |
57 SYMOPT_NO_PROMPTS;
58//#ifdef _DEBUG
59 symOptions |= SYMOPT_DEBUG;
60//#endif
61 return symOptions;
62 }
63
64 static std::string FilterSymbolPath(const std::string& input, bool allowDownload)
65 {
66 std::string result;
67
68 size_t start = 0;
69
70 while (start < input.size()) {
71 size_t end =
72 input.find(';', start);
73
74 if (end == std::string::npos) {
75 end = input.size();
76 }
77
78 std::string token = input.substr(start, end - start);
79 token.erase(0, token.find_first_not_of(" \t"));
80
81 size_t last = token.find_last_not_of(" \t");
82 if (last != std::string::npos) {
83 token.erase(last + 1);
84 }
85 else {
86 token.clear();
87 }
88
89 if (token.empty()) {
90 start = end + 1;
91 continue;
92 }
93
94 const bool isSrv = (_strnicmp(token.c_str(), "srv*", 4) == 0);
95 if (isSrv) {
96 if (allowDownload) {
97 if (!result.empty()) {
98 result += ";";
99 }
100 result += token;
101 }
102 else {
103 size_t first = token.find('*');
104 size_t second = token.find('*', first + 1);
105
106 if (first != std::string::npos &&
107 second != std::string::npos &&
108 second > first + 1)
109 {
110 std::string cache =
111 token.substr(
112 first + 1,
113 second - first - 1);
114
115 if (!cache.empty()) {
116 if (!result.empty()) {
117 result += ";";
118 }
119 result += cache;
120 }
121 }
122 }
123 }
124 else {
125 if (!result.empty()) {
126 result += ";";
127 }
128 result += token;
129 }
130 start = end + 1;
131 }
132 return result;
133 }
134
135 static std::string BuildSymbolPath(bool enableAutoDownload)
136 {
137 const DWORD bufferSize = 4096;
138 char envBuffer[bufferSize] = { 0 };
139 std::string path;
140
141 if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", envBuffer, bufferSize)) {
142 path += FilterSymbolPath(envBuffer, enableAutoDownload);
143 }
144
145 if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", envBuffer, bufferSize)) {
146 const std::string filtered = FilterSymbolPath(envBuffer, enableAutoDownload);
147 if (!filtered.empty()) {
148 if (!path.empty()) {
149 path += ";";
150 }
151 path += filtered;
152 }
153 }
154 return path;
155 }
156
157 bool InitSymbols(HANDLE process, bool enableAutoDownload, bool lazy)
158 {
159 if (!process || process == INVALID_HANDLE_VALUE) {
160 return false;
161 }
162
163 if (isInit) {
164 return true;
165 }
166
167 DWORD options = BuildSymOptions();
168
169 if (enableAutoDownload) {
170 options &= ~SYMOPT_DISABLE_SYMSRV_AUTODETECT;
171 }
172 else {
173 options |= SYMOPT_DISABLE_SYMSRV_AUTODETECT;
174 }
175
176 if (lazy) {
177 options |= SYMOPT_DEFERRED_LOADS;
178 }
179 else {
180 options &= ~SYMOPT_DEFERRED_LOADS;
181 }
182
183 const std::string path = BuildSymbolPath(enableAutoDownload);
184
185 if (!DbgHelpWrapper::InitializeProcess(process, path, options)) {
186 return false;
187 }
188
190
191 hProcess = process;
192 isInit = true;
193#ifdef _TEST
194 ForceRealSymbolDownload(process);
195#endif
196 return true;
197 }
198
200 {
201 if (!isInit) {
202 return false;
203 }
205 }
206
208 _In_ DWORD MachineType,
209 _In_ HANDLE hThread,
210 _Inout_ LPSTACKFRAME64 StackFrame,
211 _Inout_ PVOID ContextRecord,
212 _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
213 _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
214 _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
215 _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
216 )
217 {
218 if (!isInit) {
219 return false;
220 }
221 return DbgHelpWrapper::RunStackWalk64(MachineType,
222 this->hProcess,
223 hThread,
224 StackFrame,
225 ContextRecord,
226 ReadMemoryRoutine,
227 FunctionTableAccessRoutine,
228 GetModuleBaseRoutine,
229 TranslateAddress);
230 }
231
232 bool IsInitialized() const
233 {
234 return isInit;
235 }
236
237 void NormalizeNtZwPrefix(std::string& funcName)
238 {
239 if (funcName.size() < 2) {
240 return;
241 }
242
243 if (funcName[0] == 'Z' && funcName[1] == 'w') {
244 funcName[0] = 'N';
245 funcName[1] = 't';
246 }
247 }
248
249 std::string funcNameFromAddr(ULONG_PTR addr, size_t* displacement = NULL)
250 {
251 if (!isInit) {
252 return "";
253 }
254
255 ALIGNED8 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME] = { 0 };
256
257 PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
258 symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
259 symbol->MaxNameLen =MAX_SYM_NAME;
260
261 DWORD64 disp = 0;
262
263 if (!DbgHelpWrapper::FromAddress(hProcess, static_cast<DWORD64>(addr),symbol, &disp)) {
264 return "";
265 }
266
267 if (displacement) {
268 *displacement = static_cast<size_t>(disp);
269 }
270
271 std::string funcName(symbol->Name);
272
273 NormalizeNtZwPrefix(funcName);
274 return funcName;
275 }
276
277 bool dumpSymbolInfo(ULONG_PTR va)
278 {
279 if (!isInit) {
280 return false;
281 }
282
283 ALIGNED8 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME ] = { 0 };
284
285 PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
286 symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
287 symbol->MaxNameLen = MAX_SYM_NAME;
288
289 DWORD64 displacement = 0;
290
291 BOOL result = DbgHelpWrapper::FromAddress(hProcess, static_cast<DWORD64>(va), symbol, &displacement);
292 std::cout << std::dec << "[" << GetProcessId(hProcess) << "] " << std::hex << va;
293
294 if (result) {
295 std::cout << " Base: " << symbol->ModBase << " : " << symbol->Name
296 << " +0x" << displacement << " Flags: " << symbol->Flags << " Tag: " << symbol->Tag << std::endl;
297 }
298 else {
299 std::cout << " UNK" << std::endl;
300 }
301 return result == TRUE;
302 }
303
304protected:
305
307 {
308 if (!isInit) {
309 return true;
310 }
312 return false;
313 }
314 isInit = false;
315 hProcess = NULL;
316 return true;
317 }
318
319protected:
320
321 HANDLE hProcess;
322 bool isInit;
323};
static bool FromAddress(HANDLE hProcess, DWORD64 address, PSYMBOL_INFO symbol, DWORD64 *displacement)
static bool CleanupProcess(HANDLE hProcess)
static bool RefreshModuleList(HANDLE hProcess)
static bool InitializeProcess(HANDLE hProcess, const std::string &symbolPath, DWORD symOptions)
static bool RunStackWalk64(_In_ DWORD MachineType, _In_ HANDLE hProcess, _In_ HANDLE hThread, _Inout_ LPSTACKFRAME64 StackFrame, _Inout_ PVOID ContextRecord, _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress)
ProcessSymbolsManager & operator=(const ProcessSymbolsManager &)=delete
static std::string BuildSymbolPath(bool enableAutoDownload)
std::string funcNameFromAddr(ULONG_PTR addr, size_t *displacement=NULL)
static std::string FilterSymbolPath(const std::string &input, bool allowDownload)
bool dumpSymbolInfo(ULONG_PTR va)
static DWORD BuildSymOptions()
bool RunStackWalk64(_In_ DWORD MachineType, _In_ HANDLE hThread, _Inout_ LPSTACKFRAME64 StackFrame, _Inout_ PVOID ContextRecord, _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress)
ProcessSymbolsManager(const ProcessSymbolsManager &)=delete
void NormalizeNtZwPrefix(std::string &funcName)
bool InitSymbols(HANDLE process, bool enableAutoDownload, bool lazy)
pesieve::ModulesCache cache
#define ALIGNED8