Skip to content

Commit

Permalink
[BUGFIX] In ThreadScanner: keep and verify multiple shellcode candidates
Browse files Browse the repository at this point in the history
  • Loading branch information
hasherezade committed Sep 2, 2024
1 parent 6607a3e commit 92326e9
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 14 deletions.
38 changes: 27 additions & 11 deletions scanners/thread_scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,15 @@ std::string ThreadScanReport::translate_thread_state(DWORD thread_state)
size_t pesieve::ThreadScanner::analyzeStackFrames(IN const std::vector<ULONGLONG> stack_frame, IN OUT ctx_details& cDetails)
{
size_t processedCntr = 0;
bool has_shellcode = false;

cDetails.is_managed = false;
cDetails.stackFramesCount = stack_frame.size();
#ifdef _SHOW_THREAD_INFO
std::cout << "\n" << "Stack frame Size: " << std::dec << stack_frame.size() << "\n===\n";
#endif //_SHOW_THREAD_INFO
for (auto itr = stack_frame.rbegin();
itr != stack_frame.rend()
&& (!cDetails.is_managed && !has_shellcode) // break on first found shellcode, (for now) discontinue analysis if the module is .NET to avoid FP
&& (!cDetails.is_managed) // discontinue analysis if the module is .NET to avoid FP
;++itr, ++processedCntr)
{
const ULONGLONG next_return = *itr;
Expand All @@ -163,7 +163,8 @@ size_t pesieve::ThreadScanner::analyzeStackFrames(IN const std::vector<ULONGLONG
const std::string mod_name = mod ? mod->getModName() : "";
if (mod_name.length() == 0) {
if (!cDetails.is_managed) {
has_shellcode = is_curr_shc = true;
is_curr_shc = true;
cDetails.shcCandidates.insert(next_return);
#ifdef _SHOW_THREAD_INFO
std::cout << "\t" << std::hex << next_return << " <=== SHELLCODE\n";
#endif //_SHOW_THREAD_INFO
Expand All @@ -173,9 +174,9 @@ size_t pesieve::ThreadScanner::analyzeStackFrames(IN const std::vector<ULONGLONG
#endif //_SHOW_THREAD_INFO
}
}
if (!has_shellcode || is_curr_shc) {
if (!is_curr_shc) {
// store the last address, till the first called shellcode:
cDetails.ret_addr = next_return;
cDetails.last_ret = next_return;
}
// check if the found shellcode is a .NET JIT:
if (mod_name == "clr.dll") {
Expand Down Expand Up @@ -399,13 +400,17 @@ ThreadScanReport* pesieve::ThreadScanner::scanRemote()
{
ThreadScanReport* my_report = new ThreadScanReport(info.tid);
if (!my_report) return nullptr;

#ifdef _SHOW_THREAD_INFO
printThreadInfo(info);
#endif // _SHOW_THREAD_INFO

bool is_shc = isAddrInShellcode(info.start_addr);
if (is_shc) {
if (reportSuspiciousAddr(my_report, info.start_addr)) {
return my_report;
if (my_report->status == SCAN_SUSPICIOUS) {
return my_report;
}
}
}
#ifndef _DEBUG
Expand Down Expand Up @@ -468,17 +473,28 @@ ThreadScanReport* pesieve::ThreadScanner::scanRemote()
is_shc = isAddrInShellcode(cDetails.rip);
if (is_shc) {
if (reportSuspiciousAddr(my_report, cDetails.rip)) {
return my_report;
if (my_report->status == SCAN_SUSPICIOUS) {
return my_report;
}
}
}
if ((cDetails.ret_addr != 0) && (cDetails.is_managed == false)) {
is_shc = isAddrInShellcode(cDetails.ret_addr);
if (is_shc) {
if (reportSuspiciousAddr(my_report, cDetails.ret_addr)) {

for (auto itr = cDetails.shcCandidates.begin(); itr != cDetails.shcCandidates.end(); ++itr) {
const ULONGLONG addr = *itr;
#ifdef _SHOW_THREAD_INFO
std::cout << "Checking shc candidate: " << std::hex << addr << "\n";
#endif //_SHOW_THREAD_INFO
//automatically verifies if the address is legit
if (reportSuspiciousAddr(my_report, addr)) {
if (my_report->status == SCAN_SUSPICIOUS) {
#ifdef _SHOW_THREAD_INFO
std::cout << "Found! " << std::hex << addr << "\n";
#endif //_SHOW_THREAD_INFO
return my_report;
}
}
}

const bool hasEmptyGUI = has_empty_gui_info(tid);
if (hasEmptyGUI &&
cDetails.stackFramesCount == 1
Expand Down
7 changes: 4 additions & 3 deletions scanners/thread_scanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,13 @@ namespace pesieve {
ULONGLONG rip;
ULONGLONG rsp;
ULONGLONG rbp;
ULONGLONG ret_addr; // the last return address on the stack (or the address of the first shellcode)
ULONGLONG last_ret; // the last return address on the stack
bool is_managed; // does it contain .NET modules
size_t stackFramesCount;
std::set<ULONGLONG> shcCandidates;

_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), ret_addr(_ret_addr),
: is64b(_is64b), rip(_rip), rsp(_rsp), rbp(_rbp), last_ret(_ret_addr),
stackFramesCount(0),
is_managed(false)
{
Expand All @@ -112,7 +113,7 @@ namespace pesieve {
this->rip = _rip;
this->rsp = _rsp;
this->rbp = _rbp;
this->ret_addr = _ret_addr;
this->last_ret = _ret_addr;
}

} ctx_details;
Expand Down

0 comments on commit 92326e9

Please sign in to comment.