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
thread_scanner.cpp
Go to the documentation of this file.
1#include "thread_scanner.h"
2#include <peconv.h>
3#include "mempage_data.h"
5#include "../utils/ntddk.h"
6#include "../stats/stats.h"
9
11
12#define ENTROPY_TRESHOLD 3.0
13//#define NO_ENTROPY_CHECK
14
15#ifdef _DEBUG
16#define _SHOW_THREAD_INFO
17#endif
18
19using namespace pesieve;
20
21typedef struct _t_stack_enum_params {
22 bool is_ok;
23 HANDLE hProcess;
24 HANDLE hThread;
25 LPVOID ctx;
27 std::vector<ULONGLONG> callStack;
28
29 _t_stack_enum_params(IN HANDLE _hProcess = NULL, IN HANDLE _hThread = NULL, IN LPVOID _ctx = NULL, IN const pesieve::ctx_details* _cDetails = NULL)
30 : is_ok(false),
31 hProcess(_hProcess), hThread(_hThread), ctx(_ctx), cDetails(_cDetails)
32 {
33 }
34
36
37//---
38
39namespace pesieve {
40
41 bool is_thread_running(HANDLE hThread)
42 {
43 DWORD exit_code = 0;
44 if (GetExitCodeThread(hThread, &exit_code)) {
45 if (exit_code != STILL_ACTIVE) {
46#ifdef _DEBUG
47 std::cout << " Thread ExitCode: " << std::dec << exit_code << "\n";
48#endif
49 return false;
50 }
51 }
52 return true;
53 }
54
55};
56
57bool get_page_details(HANDLE processHandle, LPVOID start_va, MEMORY_BASIC_INFORMATION& page_info)
58{
59 size_t page_info_size = sizeof(MEMORY_BASIC_INFORMATION);
60 const SIZE_T out = VirtualQueryEx(processHandle, (LPCVOID)start_va, &page_info, page_info_size);
61 const bool is_read = (out == page_info_size) ? true : false;
62 const DWORD error = is_read ? ERROR_SUCCESS : GetLastError();
63 if (error != ERROR_SUCCESS) {
64 //nothing to read
65 return false;
66 }
67 return true;
68}
69
70DWORD WINAPI enum_stack_thread(LPVOID lpParam)
71{
72 t_stack_enum_params* args = static_cast<t_stack_enum_params*>(lpParam);
73 if (!args || !args->cDetails || !args->ctx) {
74 return STATUS_INVALID_PARAMETER;
75 }
76 size_t fetched = 0;
77 const pesieve::ctx_details& cDetails = *(args->cDetails);
78#ifdef _WIN64
79 if (cDetails.is64b) {
80 STACKFRAME64 frame = { 0 };
81
82 frame.AddrPC.Offset = cDetails.rip;
83 frame.AddrPC.Mode = AddrModeFlat;
84 frame.AddrStack.Offset = cDetails.rsp;
85 frame.AddrStack.Mode = AddrModeFlat;
86 frame.AddrFrame.Offset = cDetails.rbp;
87 frame.AddrFrame.Mode = AddrModeFlat;
88
89 while (StackWalk64(IMAGE_FILE_MACHINE_AMD64, args->hProcess, args->hThread, &frame, args->ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
90 const ULONGLONG next_addr = frame.AddrPC.Offset;
91 args->callStack.push_back(next_addr);
92 fetched++;
93 }
94 }
95#endif
96 if (!cDetails.is64b) {
97 STACKFRAME frame = { 0 };
98
99 frame.AddrPC.Offset = cDetails.rip;
100 frame.AddrPC.Mode = AddrModeFlat;
101 frame.AddrStack.Offset = cDetails.rsp;
102 frame.AddrStack.Mode = AddrModeFlat;
103 frame.AddrFrame.Offset = cDetails.rbp;
104 frame.AddrFrame.Mode = AddrModeFlat;
105
106 while (StackWalk(IMAGE_FILE_MACHINE_I386, args->hProcess, args->hThread, &frame, args->ctx, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL)) {
107 const ULONGLONG next_return = frame.AddrPC.Offset;
108 args->callStack.push_back(next_return);
109 fetched++;
110 }
111 }
112 if (fetched) {
113 args->is_ok = true;
114 return STATUS_SUCCESS;
115 }
116 return STATUS_UNSUCCESSFUL;
117}
118
119bool has_empty_gui_info(DWORD tid)
120{
121 GUITHREADINFO gui = { 0 };
122 gui.cbSize = sizeof(GUITHREADINFO);
123 if (!GetGUIThreadInfo(tid, &gui)) {
124 return false;
125 }
126 bool hasWindows = gui.hwndActive || gui.hwndCapture || gui.hwndCaret || gui.hwndMenuOwner || gui.hwndMoveSize;
127 bool hasRcCaret = gui.rcCaret.left || gui.rcCaret.right || gui.rcCaret.bottom || gui.rcCaret.top;
128 if (hasWindows || hasRcCaret) {
129 return false;
130 }
131 return true;
132}
133
134//---
135
136std::string ThreadScanReport::translate_wait_reason(DWORD thread_wait_reason)
137{
138 switch (thread_wait_reason) {
139 case DelayExecution: return "DelayExecution";
140 case Suspended: return "Suspended";
141 case Executive: return "Executive";
142 case UserRequest: return "UserRequest";
143 case WrUserRequest: return "WrUserRequest";
144 case WrEventPair: return "WrEventPair";
145 case WrQueue: return "WrQueue";
146 }
147 std::stringstream ss;
148 ss << "Other: " << std::dec << thread_wait_reason;
149 return ss.str();
150}
151
152std::string ThreadScanReport::translate_thread_state(DWORD thread_state)
153{
154 switch (thread_state) {
155 case Initialized: return "Initialized";
156 case Ready: return "Ready";
157 case Running: return "Running";
158 case Standby: return "Standby";
159 case Terminated: return "Terminated";
160 case Waiting: return "Waiting";
161 case Transition: return "Transition";
162 case DeferredReady: return "DeferredReady";
163 case GateWaitObsolete: return "GateWaitObsolete";
164 case WaitingForProcessInSwap: return "WaitingForProcessInSwap";
165 }
166 std::stringstream ss;
167 ss << "Other: " << std::dec << thread_state;
168 return ss.str();
169}
170
171//---
172
173bool pesieve::ThreadScanner::checkReturnAddrIntegrity(IN const std::vector<ULONGLONG>& callStack)
174{
175 if (this->info.last_syscall == INVALID_SYSCALL || !symbols || !callStack.size() || !info.is_extended || !g_SyscallTable.isReady()) {
176 return true; // skip the check
177 }
178 const std::string syscallFuncName = g_SyscallTable.getSyscallName(this->info.last_syscall);
179
180 const ULONGLONG lastCalled = *callStack.begin();
181 const std::string lastFuncCalled = symbols->funcNameFromAddr(lastCalled);
182 if (callStack.size() == 1) {
183 if (this->info.ext.wait_reason == Suspended && lastFuncCalled == "RtlUserThreadStart" && this->info.last_syscall == 0) {
184 return true; //normal for suspended threads
185 }
186 return false; // otherwise it is an anomaly
187 }
188#ifndef _WIN64
189 static bool isWow64 = util::is_current_wow64();
190 if (!isWow64 && lastFuncCalled == "KiFastSystemCallRet") {
191 return true;
192 }
193#endif
194 if (SyscallTable::isSameSyscallFunc(syscallFuncName, lastFuncCalled)) {
195 return true;
196 }
197
198 if (this->info.ext.wait_reason == UserRequest && syscallFuncName == "NtWaitForSingleObject") {
199 if (lastFuncCalled.rfind("NtQuery", 0) == 0 || lastFuncCalled.rfind("ZwQuery", 0) == 0) {
200 return true;
201 }
202 }
203 if (syscallFuncName == "NtCallbackReturn") {
204 const ScannedModule* mod = modulesInfo.findModuleContaining(lastCalled);
205 if (mod && mod->getModName() == "win32u.dll") return true;
206 }
207#ifdef _SHOW_THREAD_INFO
208 std::cout << "\n#### TID=" << std::dec <<info.tid << " " << syscallFuncName << " VS " << lastFuncCalled << " DIFFERENT"<< std::endl;
209 printThreadInfo(info);
210 std::cout << "STACK:\n";
211 for (auto itr = callStack.rbegin(); itr != callStack.rend(); ++itr) {
212 ULONGLONG next_return = *itr;
213 symbols->dumpSymbolInfo(next_return);
214 std::cout << "\t";
215 printResolvedAddr(next_return);
216 }
217 std::cout << std::endl;
218#endif //_SHOW_THREAD_INFO
219 return false;
220}
221
222size_t pesieve::ThreadScanner::analyzeCallStack(IN const std::vector<ULONGLONG> &call_stack, IN OUT ctx_details& cDetails)
223{
224 size_t processedCntr = 0;
225
226 cDetails.is_managed = false;
227 cDetails.stackFramesCount = call_stack.size();
228 cDetails.is_ret_in_frame = false;
229#ifdef _SHOW_THREAD_INFO
230 std::cout << "\n" << "Stack frame Size: " << std::dec << call_stack.size() << "\n===\n";
231#endif //_SHOW_THREAD_INFO
232 for (auto itr = call_stack.rbegin(); itr != call_stack.rend() ;++itr, ++processedCntr) {
233 const ULONGLONG next_return = *itr;
234 if (cDetails.ret_on_stack == next_return) {
235 cDetails.is_ret_in_frame = true;
236 }
237#ifdef _SHOW_THREAD_INFO
238 if (symbols) {
239 symbols->dumpSymbolInfo(next_return);
240 }
241 std::cout << "\t";
242 printResolvedAddr(next_return);
243#endif //_SHOW_THREAD_INFO
244 bool is_curr_shc = false;
245 const ScannedModule* mod = modulesInfo.findModuleContaining(next_return);
246 const std::string mod_name = mod ? mod->getModName() : "";
247 if (mod_name.length() == 0) {
248 if (!cDetails.is_managed) {
249 is_curr_shc = true;
250 cDetails.shcCandidates.insert(next_return);
251#ifdef _SHOW_THREAD_INFO
252 std::cout << "\t" << std::hex << next_return << " <=== SHELLCODE\n";
253#endif //_SHOW_THREAD_INFO
254 } else {
255#ifdef _SHOW_THREAD_INFO
256 std::cout << "\t" << std::hex << next_return << " <=== .NET JIT\n";
257#endif //_SHOW_THREAD_INFO
258 }
259 }
260 if (!is_curr_shc) {
261 // store the last address, till the first called shellcode:
262 cDetails.last_ret = next_return;
263 }
264 // check if the found shellcode is a .NET JIT:
265 if (mod_name == "clr.dll" || mod_name == "coreclr.dll") {
266 cDetails.is_managed = true;
267#ifdef _SHOW_THREAD_INFO
268 std::cout << "\t" << std::hex << next_return << " <--- .NET\n";
269#endif //_SHOW_THREAD_INFO
270 }
271 }
272#ifdef _SHOW_THREAD_INFO
273 std::cout << "\n===\n";
274#endif //_SHOW_THREAD_INFO
275 return processedCntr;
276}
277
278size_t pesieve::ThreadScanner::fillCallStackInfo(IN HANDLE hProcess, IN HANDLE hThread, IN LPVOID ctx, IN OUT ctx_details& cDetails)
279{
280 // do it in a new thread to prevent stucking...
281 t_stack_enum_params args(hProcess, hThread, ctx, &cDetails);
282
283 const size_t max_wait = 1000;
284 {
285 HANDLE enumThread = CreateThread(
286 NULL, // default security attributes
287 0, // use default stack size
288 enum_stack_thread, // thread function name
289 &args, // argument to thread function
290 0, // use default creation flags
291 0); // returns the thread identifiee
292
293 if (enumThread) {
294 DWORD wait_result = WaitForSingleObject(enumThread, max_wait);
295 if (wait_result == WAIT_TIMEOUT) {
296 std::cerr << "[!] Cannot retrieve stack frame: timeout passed!\n";
297 TerminateThread(enumThread, 0);
298 CloseHandle(enumThread);
299 return 0;
300 }
301 CloseHandle(enumThread);
302 }
303 }
304 if (!args.is_ok) {
305 return 0;
306 }
307#ifdef _SHOW_THREAD_INFO
308 std::cout << "\n=== TID " << std::dec << GetThreadId(hThread) << " ===\n";
309#endif //_SHOW_THREAD_INFO
310 const size_t analyzedCount = analyzeCallStack(args.callStack, cDetails);
311 if (!cDetails.is_managed) {
312 cDetails.is_ret_as_syscall = checkReturnAddrIntegrity(args.callStack);
313 }
314 return analyzedCount;
315}
316
317template <typename PTR_T>
318bool read_return_ptr(IN HANDLE hProcess, IN OUT ctx_details& cDetails) {
319 PTR_T ret_addr = 0;
320 cDetails.ret_on_stack = 0;
321 if (peconv::read_remote_memory(hProcess, (LPVOID)cDetails.rsp, (BYTE*)&ret_addr, sizeof(ret_addr)) == sizeof(ret_addr)) {
322 cDetails.ret_on_stack = (ULONGLONG)ret_addr;
323 return true;
324 }
325 return false;
326}
327
328bool pesieve::ThreadScanner::fetchThreadCtxDetails(IN HANDLE hProcess, IN HANDLE hThread, OUT ctx_details& cDetails)
329{
330 bool is_ok = false;
331 BOOL is_wow64 = FALSE;
332 size_t retrieved = 0;
333#ifdef _WIN64
334 pesieve::util::is_process_wow64(hProcess, &is_wow64);
335
336 if (is_wow64) {
337 WOW64_CONTEXT ctx = { 0 };
338 ctx.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
339 if (pesieve::util::wow64_get_thread_context(hThread, &ctx)) {
340 is_ok = true;
341 cDetails.init(false, ctx.Eip, ctx.Esp, ctx.Ebp);
342 read_return_ptr<DWORD>(hProcess, cDetails);
343 retrieved = fillCallStackInfo(hProcess, hThread, &ctx, cDetails);
344 }
345 }
346#endif
347 if (!is_ok) {
348
349 CONTEXT ctx = { 0 };
350 ctx.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
351 if (GetThreadContext(hThread, &ctx)) {
352 is_ok = true;
353#ifdef _WIN64
354 cDetails.init(true, ctx.Rip, ctx.Rsp, ctx.Rbp);
355 read_return_ptr<ULONGLONG>(hProcess, cDetails);
356#else
357 cDetails.init(false, ctx.Eip, ctx.Esp, ctx.Ebp);
358 read_return_ptr<DWORD>(hProcess, cDetails);
359#endif
360 retrieved = fillCallStackInfo(hProcess, hThread, &ctx, cDetails);
361 }
362 }
363 if (!retrieved) is_ok = false;
364 return is_ok;
365}
366
368{
369 ScannedModule* mod = modulesInfo.findModuleContaining(addr);
370 if (!mod) return true;
371
372 //the module is named
373 if (mod->getModName().length() > 0) {
374 return false;
375 }
376 return true;
377}
378
380{
381 bool is_resolved = false;
382 std::cout << std::hex << addr;
383 ScannedModule* mod = modulesInfo.findModuleContaining(addr);
384 if (mod) {
385 std::cout << " : " << mod->getModName();
386 is_resolved = true;
387 }
388 if (exportsMap && is_resolved) {
389 bool search_name = false;
390 if (mod->getModName() == "ntdll.dll" || mod->getModName() == "win32u.dll") {
391 search_name = true;
392 }
393 for (size_t i = 0; i < 25; i++) {
394 const peconv::ExportedFunc* exp = exportsMap->find_export_by_va(addr - i);
395 if (exp) {
396 std::cout << " : " << exp->toString();
397 is_resolved = true;
398 break;
399 }
400 if (!search_name) {
401 break;
402 }
403 }
404 }
405 std::cout << std::endl;
406 return is_resolved;
407}
408
410{
411 std::cout << std::dec << "TID: " << threadi.tid << "\n";
412 std::cout << std::hex << "\tStart : ";
413 printResolvedAddr(threadi.start_addr);
414
415 if (threadi.is_extended) {
416 std::cout << std::hex << "\tSysStart: ";
417 printResolvedAddr(threadi.ext.sys_start_addr);
418 if (threadi.last_syscall != INVALID_SYSCALL) {
419 std::cout << "\tLast Syscall: " << std::hex << threadi.last_syscall << " Func: " << g_SyscallTable.getSyscallName(threadi.last_syscall) << std::endl;
420 }
421 std::cout << "\tState: [" << ThreadScanReport::translate_thread_state(threadi.ext.state) << "]";
422 if (threadi.ext.state == Waiting) {
423 std::cout << " Reason: [" << ThreadScanReport::translate_wait_reason(threadi.ext.wait_reason) << "] Time: " << threadi.ext.wait_time;
424 }
425 std::cout << "\n";
426 }
427 std::cout << "\n";
428}
429
431{
432 if (!my_report) return false;
433
434 ULONG_PTR end_va = (ULONG_PTR)my_report->module + my_report->moduleSize;
435 MemPageData mem(this->processHandle, this->isReflection, (ULONG_PTR)my_report->module, end_va);
436 if (!mem.fillInfo() || !mem.load()) {
437 return false;
438 }
440 return calc.fill(my_report->stats, nullptr);
441}
442
444{
445 MEMORY_BASIC_INFORMATION page_info = { 0 };
446 if (!get_page_details(processHandle, (LPVOID)susp_addr, page_info)) {
447 return false;
448 }
449 if (page_info.State & MEM_FREE) {
450 return false;
451 }
452 ULONGLONG base = (ULONGLONG)page_info.BaseAddress;
453 if (this->info.is_extended) {
454 my_report->thread_state = info.ext.state;
455 my_report->thread_wait_reason = info.ext.wait_reason;
456 my_report->thread_wait_time = info.ext.wait_time;
457 }
458 my_report->module = (HMODULE)base;
459 my_report->moduleSize = page_info.RegionSize;
460 my_report->protection = page_info.AllocationProtect;
461
462 my_report->susp_addr = susp_addr;
463 my_report->status = SCAN_SUSPICIOUS;
464 const bool isStatFilled = fillAreaStats(my_report);
465#ifndef NO_ENTROPY_CHECK
466 if (isStatFilled && (my_report->stats.entropy < ENTROPY_TRESHOLD)) {
467 my_report->status = SCAN_NOT_SUSPICIOUS;
468 }
469#endif
470 return true;
471}
472
473// if extended info given, allow to filter out from the scan basing on the thread state and conditions
475{
476 if (!info.is_extended) {
477 return true;
478 }
479 const KTHREAD_STATE state = (KTHREAD_STATE)info.ext.state;
480 if (state == Ready) {
481 return true;
482 }
483 if (state == Terminated) {
484 return false;
485 }
486 if (state == Waiting && info.ext.wait_reason <= WrQueue) {
487 return true;
488 }
489 return false;
490}
491
493{
494 const DWORD tid = GetThreadId(hThread);
495 ctx_details cDetails;
496 const bool is_ok = fetchThreadCtxDetails(processHandle, hThread, cDetails);
497
498 if (!pesieve::is_thread_running(hThread)) {
499 my_report->status = SCAN_NOT_SUSPICIOUS;
500 return false;
501 }
502
503 if (!is_ok) {
504 // could not fetch the thread context and information
505 my_report->status = SCAN_ERROR;
506 return false;
507 }
508
509 bool is_shc = isAddrInShellcode(cDetails.rip);
510 if (is_shc) {
511 if (reportSuspiciousAddr(my_report, cDetails.rip)) {
512 if (my_report->status == SCAN_SUSPICIOUS) {
513 return true;
514 }
515 }
516 }
517
518 for (auto itr = cDetails.shcCandidates.begin(); itr != cDetails.shcCandidates.end(); ++itr) {
519 const ULONGLONG addr = *itr;
520#ifdef _SHOW_THREAD_INFO
521 std::cout << "Checking shc candidate: " << std::hex << addr << "\n";
522#endif //_SHOW_THREAD_INFO
523 //automatically verifies if the address is legit:
524 if (reportSuspiciousAddr(my_report, addr)) {
525 if (my_report->status == SCAN_SUSPICIOUS) {
526#ifdef _SHOW_THREAD_INFO
527 std::cout << "Found! " << std::hex << addr << "\n";
528#endif //_SHOW_THREAD_INFO
529 return true;
530 }
531 }
532 }
533
534 const bool hasEmptyGUI = has_empty_gui_info(tid);
535
536 if (this->info.is_extended && info.ext.state == Waiting && !cDetails.is_ret_in_frame)
537 {
538 const ULONGLONG ret_addr = cDetails.ret_on_stack;
539 is_shc = isAddrInShellcode(ret_addr);
540#ifdef _SHOW_THREAD_INFO
541 std::cout << "Return addr: " << std::hex << ret_addr << "\n";
542 printResolvedAddr(ret_addr);
543#endif //_SHOW_THREAD_INFO
544 if (is_shc && reportSuspiciousAddr(my_report, (ULONGLONG)ret_addr)) {
545 if (my_report->status == SCAN_SUSPICIOUS) {
546 return true;
547 }
548 my_report->status = SCAN_SUSPICIOUS;
549 my_report->stack_ptr = cDetails.rsp;
550 if (my_report->stats.entropy < 1) { // discard, do not dump
551 my_report->module = 0;
552 my_report->moduleSize = 0;
553 }
554 return true;
555 }
556 }
557 // other indicators of stack being corrupt:
558
559 bool isStackCorrupt = false;
560
561 if (this->info.is_extended && !cDetails.is_managed && !cDetails.is_ret_as_syscall)
562 {
563 isStackCorrupt = true;
564 }
565
566 if (hasEmptyGUI &&
567 cDetails.stackFramesCount == 1
568 && this->info.is_extended && info.ext.state == Waiting && info.ext.wait_reason == UserRequest)
569 {
570 isStackCorrupt = true;
571 }
572
573 if (isStackCorrupt) {
574 my_report->thread_state = info.ext.state;
575 my_report->thread_wait_reason = info.ext.wait_reason;
576 my_report->thread_wait_time = info.ext.wait_time;
577 my_report->stack_ptr = cDetails.rsp;
578 my_report->status = SCAN_SUSPICIOUS;
579 }
580 return true;
581}
582
583
585{
586 if (GetCurrentThreadId() == info.tid) {
587 return nullptr; // do not scan your own thread
588 }
589 ThreadScanReport* my_report = new (std::nothrow) ThreadScanReport(info.tid);
590 if (!my_report) {
591 return nullptr;
592 }
593#ifdef _SHOW_THREAD_INFO
594 printThreadInfo(info);
595#endif // _SHOW_THREAD_INFO
596
597 bool is_shc = isAddrInShellcode(info.start_addr);
598 if (is_shc) {
599 if (reportSuspiciousAddr(my_report, info.start_addr)) {
600 if (my_report->status == SCAN_SUSPICIOUS) {
601 return my_report;
602 }
603 }
604 }
606 my_report->status = SCAN_NOT_SUSPICIOUS;
607 return my_report;
608 }
609 // proceed with detailed checks:
610 HANDLE hThread = OpenThread(
611 THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | SYNCHRONIZE,
612 FALSE,
613 info.tid
614 );
615 if (!hThread) {
616#ifdef _DEBUG
617 std::cerr << "[-] Could not OpenThread. Error: " << GetLastError() << std::endl;
618#endif
619 my_report->status = SCAN_ERROR;
620 return my_report;
621 }
622 scanRemoteThreadCtx(hThread, my_report);
623 CloseHandle(hThread);
624 return my_report;
625}
A class responsible for filling in the statistics with the data from the particular buffer.
Definition stats.h:73
bool fill(AreaStats &stats, StatsSettings *settings)
Definition stats.h:80
util::ByteBuffer loadedData
Represents a basic info about the scanned module, such as its base offset, size, and the status.
std::string getModName() const
A report from the thread scan, generated by ThreadScanner.
static std::string translate_wait_reason(DWORD thread_wait_reason)
static std::string translate_thread_state(DWORD thread_state)
virtual ThreadScanReport * scanRemote()
bool reportSuspiciousAddr(ThreadScanReport *my_report, ULONGLONG susp_addr)
size_t fillCallStackInfo(IN HANDLE hProcess, IN HANDLE hThread, IN LPVOID ctx, IN OUT ctx_details &cDetails)
void printThreadInfo(const util::thread_info &threadi)
bool fillAreaStats(ThreadScanReport *my_report)
bool isAddrInShellcode(ULONGLONG addr)
size_t analyzeCallStack(IN const std::vector< ULONGLONG > &stack_frame, IN OUT ctx_details &cDetails)
bool fetchThreadCtxDetails(IN HANDLE hProcess, IN HANDLE hThread, OUT ctx_details &c)
bool printResolvedAddr(ULONGLONG addr)
bool scanRemoteThreadCtx(HANDLE hThread, ThreadScanReport *my_report)
bool checkReturnAddrIntegrity(IN const std::vector< ULONGLONG > &callStack)
BOOL is_process_wow64(IN HANDLE processHandle, OUT BOOL *isProcWow64)
bool is_current_wow64()
BOOL wow64_get_thread_context(IN HANDLE hThread, IN OUT PWOW64_CONTEXT lpContext)
bool is_thread_running(HANDLE hThread)
std::string info()
The string with the basic information about the scanner.
Definition pe_sieve.cpp:274
pesieve::SyscallTable g_SyscallTable
Definition pe_sieve.cpp:24
_t_stack_enum_params(IN HANDLE _hProcess=NULL, IN HANDLE _hThread=NULL, IN LPVOID _ctx=NULL, IN const pesieve::ctx_details *_cDetails=NULL)
const pesieve::ctx_details * cDetails
std::vector< ULONGLONG > callStack
A custom structure keeping a fragment of a thread context.
std::set< ULONGLONG > shcCandidates
static bool isSameSyscallFunc(std::string func1, std::string func2)
std::string getSyscallName(DWORD id)
bool has_empty_gui_info(DWORD tid)
struct _t_stack_enum_params t_stack_enum_params
bool get_page_details(HANDLE processHandle, LPVOID start_va, MEMORY_BASIC_INFORMATION &page_info)
bool read_return_ptr(IN HANDLE hProcess, IN OUT ctx_details &cDetails)
DWORD WINAPI enum_stack_thread(LPVOID lpParam)
#define ENTROPY_TRESHOLD
bool should_scan_context(const util::thread_info &info)
pesieve::SyscallTable g_SyscallTable
Definition pe_sieve.cpp:24
#define INVALID_SYSCALL
Definition threads_util.h:6