PE-sieve
Scans all running processes. Recognizes and dumps a variety of potentially malicious implants (replaced/implanted PEs, shellcodes, hooks, in-memory patches).
Toggle main menu visibility
Loading...
Searching...
No Matches
utils
threads_util.cpp
Go to the documentation of this file.
1
#include "
threads_util.h
"
2
3
#include <peconv.h>
4
#include <tlhelp32.h>
5
#include "../utils/ntddk.h"
6
#include "
custom_buffer.h
"
7
8
#ifdef _DEBUG
9
#include <iostream>
10
#endif
11
12
13
namespace
pesieve
{
14
namespace
util
{
15
16
// Thread info structures:
17
typedef
struct
_THREAD_LAST_SYSCALL_INFORMATION
18
{
19
PVOID
FirstArgument
;
20
USHORT
SystemCallNumber
;
21
}
THREAD_LAST_SYSCALL_INFORMATION
, *
PTHREAD_LAST_SYSCALL_INFORMATION
;
22
23
24
bool
query_thread_details
(IN
DWORD
tid, OUT
pesieve::util::thread_info
&
info
)
25
{
26
static
auto
mod = GetModuleHandleA(
"ntdll.dll"
);
27
if
(!mod)
return
false
;
28
29
static
auto
pNtQueryInformationThread =
reinterpret_cast<
decltype(&NtQueryInformationThread)
>
(GetProcAddress(mod,
"NtQueryInformationThread"
));
30
if
(!pNtQueryInformationThread)
return
false
;
31
32
const
DWORD
thAccess = THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT;
33
HANDLE hThread = OpenThread(thAccess, 0, tid);
34
if
(!hThread) {
35
hThread = OpenThread(THREAD_QUERY_INFORMATION, 0, tid);
36
if
(!hThread)
return
false
;
37
}
38
bool
isOk =
false
;
39
ULONG returnedLen = 0;
40
LPVOID startAddr = 0;
41
NTSTATUS
status = 0;
42
status = pNtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, &startAddr,
sizeof
(LPVOID), &returnedLen);
43
if
(status == 0 && returnedLen ==
sizeof
(startAddr)) {
44
info
.start_addr = (ULONGLONG)startAddr;
45
isOk =
true
;
46
}
47
returnedLen = 0;
48
THREAD_LAST_SYSCALL_INFORMATION
syscallInfo = { 0 };
49
status = pNtQueryInformationThread(hThread, ThreadLastSystemCall, &syscallInfo,
sizeof
(syscallInfo), &returnedLen);
50
if
(status == 0 && returnedLen >=
sizeof
(syscallInfo)) {
51
info
.last_syscall = syscallInfo.
SystemCallNumber
;
52
isOk =
true
;
53
}
54
CloseHandle(hThread);
55
info
.is_filled = isOk;
56
return
isOk;
57
}
58
59
};
// namespace util
60
};
// namespace pesieve
61
62
63
size_t
pesieve::util::query_threads_details
(IN OUT std::map<DWORD, pesieve::util::thread_info>& threads_info)
64
{
65
size_t
queried_count = 0;
66
for
(
auto
itr = threads_info.begin(); itr != threads_info.end(); ++itr) {
67
pesieve::util::thread_info
&
info
= itr->second;
68
if
(
query_thread_details
(
info
.tid, info)) queried_count++;
69
}
70
return
queried_count;
71
}
72
73
bool
pesieve::util::fetch_threads_info
(IN
DWORD
pid, OUT std::map<DWORD, thread_info>& threads_info)
74
{
75
AutoBuffer
bBuf;
76
NTSTATUS
status = STATUS_UNSUCCESSFUL;
77
78
while
(status != STATUS_SUCCESS) {
79
ULONG ret_len = 0;
80
status = NtQuerySystemInformation(SystemProcessInformation, bBuf.
buf
, bBuf.
buf_size
, &ret_len);
81
if
(status == STATUS_INFO_LENGTH_MISMATCH) {
82
if
(!bBuf.
alloc
(ret_len)) {
83
return
false
;
84
}
85
continue
;
// try again
86
}
87
break
;
//other error, or success
88
};
89
90
if
(status != STATUS_SUCCESS) {
91
return
false
;
92
}
93
94
bool
pid_found =
false
;
95
SYSTEM_PROCESS_INFORMATION*
info
= (SYSTEM_PROCESS_INFORMATION*)bBuf.
buf
;
96
while
(
info
) {
97
if
(
info
->UniqueProcessId == pid) {
98
pid_found =
true
;
99
break
;
100
}
101
if
(!
info
->NextEntryOffset) {
102
break
;
103
}
104
size_t
record_size =
info
->NextEntryOffset;
105
if
(record_size <
sizeof
(SYSTEM_PROCESS_INFORMATION)) {
106
// Record size smaller than expected, probably it is an old system that doesn not support the new version of this API
107
#ifdef _DEBUG
108
std::cout <<
"The new version of SYSTEM_PROCESS_INFORMATION is not supported!\n"
;
109
#endif
110
break
;
111
}
112
info
= (SYSTEM_PROCESS_INFORMATION*)((ULONG_PTR)
info
+
info
->NextEntryOffset);
113
if
(!peconv::validate_ptr(bBuf.
buf
, bBuf.
buf_size
,
info
,
sizeof
(SYSTEM_PROCESS_INFORMATION))) {
114
break
;
115
}
116
}
117
if
(!pid_found) {
118
return
false
;
119
}
120
const
size_t
thread_count =
info
->NumberOfThreads;
121
if
(!peconv::validate_ptr(bBuf.
buf
, bBuf.
buf_size
,
info
->Threads, thread_count *
sizeof
(
info
->Threads[0]))) {
122
return
false
;
123
}
124
bool
fetched =
false
;
125
for
(
size_t
i = 0; i < thread_count; i++) {
126
const
DWORD
tid =
MASK_TO_DWORD
((ULONGLONG)
info
->Threads[i].ClientId.UniqueThread);
127
auto
itr = threads_info.find(tid);
128
if
(itr == threads_info.end()) {
129
threads_info[tid] =
thread_info
(tid);
130
}
131
fetched =
true
;
132
thread_info
&threadi = threads_info[tid];
133
threadi.
is_extended
=
true
;
134
threadi.
ext
.
sys_start_addr
= (ULONG_PTR)
info
->Threads[i].StartAddress;
135
threadi.
ext
.
state
=
info
->Threads[i].ThreadState;
136
threadi.
ext
.
wait_reason
=
info
->Threads[i].WaitReason;
137
threadi.
ext
.
wait_time
=
info
->Threads[i].WaitTime;
138
threadi.
is_filled
=
true
;
139
}
140
return
fetched;
141
}
142
143
bool
pesieve::util::fetch_threads_by_snapshot
(IN
DWORD
pid, OUT std::map<DWORD, thread_info>& threads_info)
144
{
145
HANDLE hThreadSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
146
if
(hThreadSnapShot == INVALID_HANDLE_VALUE) {
147
#ifdef _DEBUG
148
const
DWORD
err = GetLastError();
149
std::cerr <<
"[-] Could not create threads snapshot. Error: "
<< std::dec << err << std::endl;
150
#endif
151
return
false
;
152
}
153
THREADENTRY32 th32 = { 0 };
154
th32.dwSize =
sizeof
(THREADENTRY32);
155
156
//check all threads in the process:
157
if
(!Thread32First(hThreadSnapShot, &th32)) {
158
CloseHandle(hThreadSnapShot);
159
#ifdef _DEBUG
160
std::cerr <<
"[-] Could not enumerate thread. Error: "
<< GetLastError() << std::endl;
161
#endif
162
return
false
;
163
}
164
165
bool
fetched =
false
;
166
do
{
167
if
(th32.th32OwnerProcessID != pid) {
168
continue
;
169
}
170
171
fetched =
true
;
172
173
const
DWORD
tid = th32.th32ThreadID;
174
auto
itr = threads_info.find(tid);
175
if
(itr == threads_info.end()) {
176
threads_info[tid] =
thread_info
(tid);
177
}
178
}
while
(Thread32Next(hThreadSnapShot, &th32));
179
180
CloseHandle(hThreadSnapShot);
181
return
fetched;
182
}
custom_buffer.h
MASK_TO_DWORD
#define MASK_TO_DWORD(val)
Definition
iat_finder.h:9
pesieve::util
Definition
artefact_scanner.cpp:12
pesieve::util::fetch_threads_by_snapshot
bool fetch_threads_by_snapshot(IN DWORD pid, OUT std::map< DWORD, thread_info > &threads_info)
Definition
threads_util.cpp:143
pesieve::util::NTSTATUS
NTSTATUS(NTAPI *_RtlCreateProcessReflection)(HANDLE ProcessHandle
pesieve::util::query_thread_details
bool query_thread_details(IN DWORD tid, OUT pesieve::util::thread_info &info)
Definition
threads_util.cpp:24
pesieve::util::THREAD_LAST_SYSCALL_INFORMATION
struct pesieve::util::_THREAD_LAST_SYSCALL_INFORMATION THREAD_LAST_SYSCALL_INFORMATION
pesieve::util::query_threads_details
size_t query_threads_details(IN OUT std::map< DWORD, thread_info > &threads_info)
pesieve::util::PTHREAD_LAST_SYSCALL_INFORMATION
struct pesieve::util::_THREAD_LAST_SYSCALL_INFORMATION * PTHREAD_LAST_SYSCALL_INFORMATION
pesieve::util::DWORD
DWORD(__stdcall *_PssCaptureSnapshot)(HANDLE ProcessHandle
pesieve::util::thread_info
struct pesieve::util::_thread_info thread_info
pesieve::util::fetch_threads_info
bool fetch_threads_info(IN DWORD pid, OUT std::map< DWORD, thread_info > &threads_info)
Definition
threads_util.cpp:73
pesieve
Definition
pesieve.py:1
pesieve::info
std::string info()
The string with the basic information about the scanner.
Definition
pe_sieve.cpp:276
pesieve::util::_THREAD_LAST_SYSCALL_INFORMATION
Definition
threads_util.cpp:18
pesieve::util::_THREAD_LAST_SYSCALL_INFORMATION::SystemCallNumber
USHORT SystemCallNumber
Definition
threads_util.cpp:20
pesieve::util::_THREAD_LAST_SYSCALL_INFORMATION::FirstArgument
PVOID FirstArgument
Definition
threads_util.cpp:19
pesieve::util::_thread_info_ext::sys_start_addr
ULONGLONG sys_start_addr
Definition
threads_util.h:13
pesieve::util::_thread_info_ext::wait_reason
DWORD wait_reason
Definition
threads_util.h:15
pesieve::util::_thread_info_ext::state
DWORD state
Definition
threads_util.h:14
pesieve::util::_thread_info_ext::wait_time
DWORD wait_time
Definition
threads_util.h:16
pesieve::util::_thread_info::is_filled
bool is_filled
Definition
threads_util.h:42
pesieve::util::_thread_info::is_extended
bool is_extended
Definition
threads_util.h:41
pesieve::util::_thread_info::ext
thread_info_ext ext
Definition
threads_util.h:43
pesieve::util::AutoBuffer
Definition
custom_buffer.h:8
pesieve::util::AutoBuffer::buf
BYTE * buf
Definition
custom_buffer.h:35
pesieve::util::AutoBuffer::alloc
BYTE * alloc(size_t _buf_size)
Definition
custom_buffer.h:20
pesieve::util::AutoBuffer::buf_size
size_t buf_size
Definition
custom_buffer.h:37
threads_util.h
Generated by
1.17.0