mirror of
https://github.com/hasherezade/pe-sieve.git
synced 2026-10-11 21:49:57 +00:00
[FEATURE] Allow to print full callstack in the report
This commit is contained in:
@@ -153,11 +153,11 @@ std::string pesieve::translate_json_level(const pesieve::t_json_level &mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case pesieve::JSON_BASIC:
|
||||
return "basic";
|
||||
return "basic (default)";
|
||||
case pesieve::JSON_DETAILS:
|
||||
return "details #1 (list patches)";
|
||||
return "details #1 (medium)";
|
||||
case pesieve::JSON_DETAILS2:
|
||||
return "details #2 (list patches: extended)";
|
||||
return "details #2 (verbose)";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
+29
-32
@@ -306,17 +306,16 @@ bool pesieve::ThreadScanner::checkReturnAddrIntegrity(IN const std::vector<ULONG
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t pesieve::ThreadScanner::_analyzeCallStack(IN const std::vector<ULONGLONG> &call_stack, IN OUT ctx_details& cDetails, OUT IN std::set<ULONGLONG> &shcCandidates)
|
||||
size_t pesieve::ThreadScanner::_analyzeCallStack(IN OUT ctx_details& cDetails, OUT IN std::set<ULONGLONG> &shcCandidates)
|
||||
{
|
||||
size_t processedCntr = 0;
|
||||
|
||||
cDetails.is_managed = false;
|
||||
cDetails.stackFramesCount = call_stack.size();
|
||||
cDetails.is_ret_in_frame = false;
|
||||
#ifdef _SHOW_THREAD_INFO
|
||||
std::cout << "\n" << "Stack frame Size: " << std::dec << call_stack.size() << "\n===\n";
|
||||
std::cout << "\n" << "Stack frame Size: " << std::dec << cDetails.callStack.size() << "\n===\n";
|
||||
#endif //_SHOW_THREAD_INFO
|
||||
for (auto itr = call_stack.rbegin(); itr != call_stack.rend() ;++itr, ++processedCntr) {
|
||||
for (auto itr = cDetails.callStack.rbegin(); itr != cDetails.callStack.rend() ;++itr, ++processedCntr) {
|
||||
const ULONGLONG next_return = *itr;
|
||||
if (cDetails.ret_on_stack == next_return) {
|
||||
cDetails.is_ret_in_frame = true;
|
||||
@@ -362,6 +361,15 @@ size_t pesieve::ThreadScanner::_analyzeCallStack(IN const std::vector<ULONGLONG>
|
||||
return processedCntr;
|
||||
}
|
||||
|
||||
size_t pesieve::ThreadScanner::analyzeCallStackInfo(IN OUT ThreadScanReport& my_report)
|
||||
{
|
||||
const size_t analyzedCount = _analyzeCallStack(my_report.cDetails, my_report.shcCandidates);
|
||||
if (!my_report.cDetails.is_managed) {
|
||||
my_report.cDetails.is_ret_as_syscall = checkReturnAddrIntegrity(my_report.cDetails.callStack);
|
||||
}
|
||||
return analyzedCount;
|
||||
}
|
||||
|
||||
size_t pesieve::ThreadScanner::fillCallStackInfo(IN HANDLE hProcess, IN HANDLE hThread, IN LPVOID ctx, IN OUT ThreadScanReport& my_report)
|
||||
{
|
||||
// do it in a new thread to prevent stucking...
|
||||
@@ -391,31 +399,22 @@ size_t pesieve::ThreadScanner::fillCallStackInfo(IN HANDLE hProcess, IN HANDLE h
|
||||
if (!args.is_ok) {
|
||||
return 0;
|
||||
}
|
||||
my_report.callStack = args.callStack;
|
||||
my_report.cDetails.callStack = args.callStack;
|
||||
return args.callStack.size();
|
||||
}
|
||||
|
||||
size_t pesieve::ThreadScanner::analyzeCallStackInfo(IN OUT ThreadScanReport& my_report)
|
||||
{
|
||||
const size_t analyzedCount = _analyzeCallStack(my_report.callStack, my_report.cDetails, my_report.shcCandidates);
|
||||
if (!my_report.cDetails.is_managed) {
|
||||
my_report.cDetails.is_ret_as_syscall = checkReturnAddrIntegrity(my_report.callStack);
|
||||
namespace pesieve {
|
||||
template <typename PTR_T>
|
||||
bool read_return_ptr(IN HANDLE hProcess, IN OUT ctx_details& cDetails) {
|
||||
PTR_T ret_addr = 0;
|
||||
cDetails.ret_on_stack = 0;
|
||||
if (peconv::read_remote_memory(hProcess, (LPVOID)cDetails.rsp, (BYTE*)&ret_addr, sizeof(ret_addr)) == sizeof(ret_addr)) {
|
||||
cDetails.ret_on_stack = (ULONGLONG)ret_addr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return analyzedCount;
|
||||
}
|
||||
|
||||
template <typename PTR_T>
|
||||
bool read_return_ptr(IN HANDLE hProcess, IN OUT ctx_details& cDetails) {
|
||||
PTR_T ret_addr = 0;
|
||||
cDetails.ret_on_stack = 0;
|
||||
if (peconv::read_remote_memory(hProcess, (LPVOID)cDetails.rsp, (BYTE*)&ret_addr, sizeof(ret_addr)) == sizeof(ret_addr)) {
|
||||
cDetails.ret_on_stack = (ULONGLONG)ret_addr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}; //namespace pesieve
|
||||
|
||||
bool pesieve::ThreadScanner::fetchThreadCtxDetails(IN HANDLE hProcess, IN HANDLE hThread, OUT ThreadScanReport& my_report)
|
||||
{
|
||||
@@ -610,14 +609,12 @@ bool pesieve::ThreadScanner::scanRemoteThreadCtx(HANDLE hThread, ThreadScanRepor
|
||||
my_report.status = SCAN_NOT_SUSPICIOUS;
|
||||
return false;
|
||||
}
|
||||
if (!is_ok) {
|
||||
if (!is_ok || !analyzeCallStackInfo(my_report)) {
|
||||
// could not fetch the thread context and information
|
||||
my_report.status = SCAN_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
analyzeCallStackInfo(my_report);
|
||||
|
||||
my_report.stack_ptr = cDetails.rsp;
|
||||
bool isModified = false;
|
||||
bool is_unnamed = !isAddrInNamedModule(cDetails.rip);
|
||||
@@ -692,7 +689,7 @@ bool pesieve::ThreadScanner::scanRemoteThreadCtx(HANDLE hThread, ThreadScanRepor
|
||||
}
|
||||
|
||||
if (hasEmptyGUI &&
|
||||
cDetails.stackFramesCount == 1
|
||||
cDetails.callStack.size() == 1
|
||||
&& this->info.is_extended && info.ext.state == Waiting && info.ext.wait_reason == UserRequest)
|
||||
{
|
||||
my_report.indicators.insert(THI_SUS_CALLSTACK_CORRUPT);
|
||||
@@ -743,14 +740,14 @@ ThreadScanReport* pesieve::ThreadScanner::scanRemote()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!should_scan_context(info)) {
|
||||
return my_report;
|
||||
}
|
||||
if (this->info.is_extended) {
|
||||
my_report->thread_state = info.ext.state;
|
||||
my_report->thread_wait_reason = info.ext.wait_reason;
|
||||
my_report->thread_wait_time = info.ext.wait_time;
|
||||
}
|
||||
if (!should_scan_context(info)) {
|
||||
return my_report;
|
||||
}
|
||||
// proceed with detailed checks:
|
||||
HANDLE hThread = OpenThread(
|
||||
THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | SYNCHRONIZE,
|
||||
|
||||
+30
-12
@@ -7,6 +7,7 @@
|
||||
#include "../utils/process_symbols.h"
|
||||
#include "../stats/stats.h"
|
||||
#include "../stats/entropy_stats.h"
|
||||
#include <vector>
|
||||
|
||||
namespace pesieve {
|
||||
|
||||
@@ -46,11 +47,10 @@ namespace pesieve {
|
||||
bool is_ret_as_syscall;
|
||||
bool is_ret_in_frame;
|
||||
bool is_managed; // does it contain .NET modules
|
||||
size_t stackFramesCount;
|
||||
std::vector<ULONGLONG> callStack;
|
||||
|
||||
_ctx_details(bool _is64b = false, ULONGLONG _rip = 0, ULONGLONG _rsp = 0, ULONGLONG _rbp = 0, ULONGLONG _ret_addr = 0)
|
||||
: is64b(_is64b), rip(_rip), rsp(_rsp), rbp(_rbp), last_ret(_ret_addr), ret_on_stack(0), is_ret_as_syscall(false), is_ret_in_frame(false),
|
||||
stackFramesCount(0),
|
||||
is_managed(false)
|
||||
{
|
||||
}
|
||||
@@ -87,6 +87,29 @@ namespace pesieve {
|
||||
{
|
||||
}
|
||||
|
||||
const virtual void callstackToJSON(std::stringstream& outs, size_t level, const pesieve::t_json_level& jdetails)
|
||||
{
|
||||
OUT_PADDED(outs, level, "\"stack_ptr\" : ");
|
||||
outs << "\"" << std::hex << stack_ptr << "\"";
|
||||
if (cDetails.callStack.size()) {
|
||||
outs << ",\n";
|
||||
OUT_PADDED(outs, level, "\"frames_count\" : ");
|
||||
outs << std::dec << cDetails.callStack.size();
|
||||
if (jdetails >= JSON_DETAILS) {
|
||||
outs << ",\n";
|
||||
OUT_PADDED(outs, level, "\"frames\" : [");
|
||||
for (auto itr = cDetails.callStack.begin(); itr != cDetails.callStack.end(); ++itr) {
|
||||
if (itr != cDetails.callStack.begin()) {
|
||||
outs << ", ";
|
||||
}
|
||||
const ULONGLONG addr = *itr;
|
||||
outs << "\"" << std::hex << addr << "\"";
|
||||
}
|
||||
outs << "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const virtual void fieldsToJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
|
||||
{
|
||||
ModuleScanReport::_toJSON(outs, level);
|
||||
@@ -105,13 +128,10 @@ namespace pesieve {
|
||||
outs << "]";
|
||||
if (stack_ptr) {
|
||||
outs << ",\n";
|
||||
OUT_PADDED(outs, level, "\"stack_ptr\" : ");
|
||||
outs << "\"" << std::hex << stack_ptr << "\"";
|
||||
}
|
||||
if (callStack.size()) {
|
||||
outs << ",\n";
|
||||
OUT_PADDED(outs, level, "\"frames_count\" : ");
|
||||
outs << std::dec << callStack.size();
|
||||
OUT_PADDED(outs, level, "\"callstack\" : {\n");
|
||||
callstackToJSON(outs, level + 1, jdetails);
|
||||
outs << "\n";
|
||||
OUT_PADDED(outs, level, "}");
|
||||
}
|
||||
if (thread_state != THREAD_STATE_UNKNOWN) {
|
||||
outs << ",\n";
|
||||
@@ -158,13 +178,11 @@ namespace pesieve {
|
||||
ULONGLONG susp_addr;
|
||||
DWORD protection;
|
||||
ULONGLONG stack_ptr;
|
||||
//size_t frames_count;
|
||||
DWORD thread_state;
|
||||
DWORD thread_wait_reason;
|
||||
DWORD thread_wait_time;
|
||||
|
||||
ctx_details cDetails;
|
||||
std::vector<ULONGLONG> callStack;
|
||||
std::set<ULONGLONG> shcCandidates;
|
||||
std::set<ThSusIndicator> indicators;
|
||||
|
||||
@@ -197,7 +215,7 @@ namespace pesieve {
|
||||
|
||||
size_t fillCallStackInfo(IN HANDLE hProcess, IN HANDLE hThread, IN LPVOID ctx, IN OUT ThreadScanReport& my_report);
|
||||
size_t analyzeCallStackInfo(IN OUT ThreadScanReport& my_report);
|
||||
size_t _analyzeCallStack(IN const std::vector<ULONGLONG>& call_stack, IN OUT ctx_details& cDetails, OUT IN std::set<ULONGLONG>& shcCandidates);
|
||||
size_t _analyzeCallStack(IN OUT ctx_details& cDetails, OUT IN std::set<ULONGLONG>& shcCandidates);
|
||||
|
||||
bool checkReturnAddrIntegrity(IN const std::vector<ULONGLONG>& callStack);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user