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
path_converter.cpp
Go to the documentation of this file.
1#include "path_converter.h"
2
3#include <windows.h>
4
5#include "ntddk.h"
6#pragma comment(lib, "Ntdll.lib")
7
8#include <shlwapi.h>
9#pragma comment (lib, "shlwapi.lib")
10
11#include <iostream>
12#include <string>
13#include <locale>
14#include <codecvt>
15
16#include "path_util.h"
17
18#define LONG_PATH_PREFIX "\\\\?\\"
19#define GLOBALROOT_NAME "GLOBALROOT"
20
21char g_System32Path[MAX_PATH] = { 0 }; //= "C:\\Windows\\system32";
22char g_Syswow64Path[MAX_PATH] = { 0 }; //= "C:\\Windows\\SysWOW64";
23
24namespace pesieve {
25 namespace util {
26
28 {
29 if (!g_System32Path[0]) {
30 memset(g_System32Path, 0, MAX_PATH);
31 ExpandEnvironmentStringsA("%SystemRoot%\\system32", g_System32Path, MAX_PATH);
32 }
33 if (!g_Syswow64Path[0]) {
34 memset(g_Syswow64Path, 0, MAX_PATH);
35 ExpandEnvironmentStringsA("%SystemRoot%\\SysWoW64", g_Syswow64Path, MAX_PATH);
36 }
37 }
38
39 HANDLE nt_create_file(PCWSTR filePath)
40 {
41 HANDLE hFile;
42 OBJECT_ATTRIBUTES objAttribs = { 0 };
43
44 UNICODE_STRING unicodeString;
45 RtlInitUnicodeString(&unicodeString, filePath);
46
47 InitializeObjectAttributes(&objAttribs, &unicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
48
49 const int allocSize = 2048;
50 LARGE_INTEGER largeInteger;
51 largeInteger.QuadPart = allocSize;
52
53 IO_STATUS_BLOCK ioStatusBlock = { 0 };
54 NTSTATUS status = NtCreateFile(&hFile,
55 STANDARD_RIGHTS_READ,
56 &objAttribs,
57 &ioStatusBlock,
58 &largeInteger,
59 FILE_ATTRIBUTE_NORMAL,
60 FILE_SHARE_READ,
61 FILE_OPEN,
62 FILE_NON_DIRECTORY_FILE,
63 NULL,
64 NULL
65 );
66 if (status != STATUS_SUCCESS) {
67 std::wcerr << "Cannot open file: " << filePath << ". Error: " << std::hex << status << std::endl;
68 return nullptr;
69 }
70 return hFile;
71 }
72
73 std::string nt_retrieve_file_path(HANDLE hFile)
74 {
75 IO_STATUS_BLOCK status_block = { 0 };
76
77 struct MY_FILE_NAME_INFORMATION {
78 ULONG FileNameLength;
79 WCHAR FileName[MAX_PATH];
80 } name_info;
81
82 memset(&name_info, 0, sizeof(MY_FILE_NAME_INFORMATION));
83
84 NTSTATUS status = ZwQueryInformationFile(hFile, &status_block, &name_info, sizeof(MY_FILE_NAME_INFORMATION), FileNameInformation);
85 if (status != STATUS_SUCCESS) {
86 return "";
87 }
88 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
89 std::string my_string = converter.to_bytes(name_info.FileName);
90
91 my_string = get_system_drive() + my_string;
92 return my_string;
93 }
94
95 bool is_relative(const char *path, size_t path_len)
96 {
97 if (path_len < 2) {
98 return true;
99 }
100 // i.e. "c:\"
101 if (path[1] == ':') {
102 return false;
103 }
104 // i.e. "\\path1\" or "\\?\UNC\"
105 if (path[0] == '\\' && path[1] == '\\') {
106 return false;
107 }
108 return true;
109 }
110
111 bool is_disk_relative(const char *path, size_t path_len)
112 {
113 if (path_len < 2) {
114 return true;
115 }
116 //check format:
117 if ((path[0] >= 'a' && path[0] <= 'z')
118 || (path[0] >= 'A' && path[0] <= 'Z'))
119 {
120 if (path[1] == ':') {
121 // format i.e: C:\...
122 return true;
123 }
124 }
125 return false;
126 }
127
128 std::string remap_to_drive_letter(const std::string &full_path)
129 {
130 size_t full_path_size = full_path.length();
131 if (full_path_size == 0) {
132 return full_path;
133 }
134
135 DWORD drives_bitmask = GetLogicalDrives();
136 //std::cout << "Drives: " << std::hex << drives_bitmask << std::endl;
137
138 for (DWORD i = 0; i < 32; i += 1, drives_bitmask >>= 1) {
139 if ((drives_bitmask & 1) == 1) {
140 char letter[] = "?:";
141 letter[0] = 'A' + (char)i;
142 //std::cout << "Drive: " << letter << std::endl;
143 char out_path[MAX_PATH] = { 0 };
144 if (!QueryDosDeviceA(letter, out_path, MAX_PATH)) {
145 return full_path;
146 }
147 //QueryDosDeviceA returns all possible mappings pointing to this drive letter, divided by a delimiter: ";"
148 //sometimes one device letter is mapped to several paths
149 // i.e. "\Device\VBoxMiniRdr\;E:\vboxsrv\vm_shared"
150 const char delim[] = ";";
151 char *next_token = nullptr;
152
153 char * pch = strtok_s(out_path, delim, &next_token);
154 while (pch != nullptr) {
155 // check if the current path starts from any of the mapped paths
156 std::size_t found = full_path.find(pch);
157 if (found != std::string::npos && found == 0) {
158 size_t dir_len = strlen(pch);
159 //if so, cut out the mappining path/device path and replace it with a drive letter
160 std::string str2 = full_path.substr(dir_len, full_path_size);
161 if (str2[0] != '/' && str2[0] != '\\') {
162 str2 = "\\" + str2;
163 }
164 return letter + str2;
165 }
166 pch = strtok_s(nullptr, delim, &next_token);
167 }
168 }
169 }
170 return full_path;
171 }
172
173 std::string relative_to_absolute_path(std::string path)
174 {
175 if (is_relative(path.c_str(), path.length())) {
176 char current_dir[MAX_PATH] = { 0 };
177 GetCurrentDirectoryA(MAX_PATH, current_dir);
178 path = std::string(current_dir) + "\\" + path;
179 }
180 char out_path[MAX_PATH] = { 0 };
181 PathCanonicalizeA(out_path, path.c_str());
182 return std::string(out_path);
183 }
184
185 std::string replace_char(std::string &str, char ch1, char ch2) {
186 for (size_t i = 0; i < str.length(); ++i) {
187 if (str[i] == ch1)
188 str[i] = ch2;
189 }
190 return str;
191 }
192 };
193};
194
196{
198 if (!get_subpath_ptr(szModName, g_System32Path)) {
199 return false;
200 }
201 size_t sysPathLen = strlen(g_Syswow64Path);
202 memcpy(szModName, g_Syswow64Path, sysPathLen);
203 return true;
204}
205
206std::string pesieve::util::convert_to_win32_path(const std::string &path)
207{
208 std::string stripped_path = strip_prefix(path, LONG_PATH_PREFIX);
209 if (stripped_path.length() < 3) {
210 return "";
211 }
212 //check format:
213 if (is_disk_relative(stripped_path.c_str(), stripped_path.length())) {
214 return stripped_path;
215 }
216 stripped_path = strip_prefix(stripped_path, GLOBALROOT_NAME);
217 const char *szModName = stripped_path.c_str();
218 std::wstring unicode_name(szModName, szModName + strlen(szModName));
219 HANDLE hFile = nt_create_file(unicode_name.c_str());
220 if (hFile == nullptr) {
221 return "";
222 }
223 std::string my_path = nt_retrieve_file_path(hFile);
224 CloseHandle(hFile);
225 return my_path;
226}
227
228std::string pesieve::util::device_path_to_win32_path(const std::string &full_path)
229{
230 std::string path = full_path;
231 //sometimes mapping can be recursive, so resolve it till the root
232 do {
233 std::string remapped_path = remap_to_drive_letter(path);
234 if (remapped_path == path) break;
235 path = remapped_path;
236 } while (true);
237 return path;
238}
239
240bool is_device_path(const std::string &path)
241{
242 const std::string device_path = "\\Device\\";
243 if (path.length() < device_path.length() || path[0] !='\\') {
244 return false;
245 }
246 if (path.compare(0, device_path.length(), device_path) == 0){
247 return true;
248 }
249 return false;
250}
251
252std::string pesieve::util::expand_path(const std::string &path)
253{
254 std::string basic_path = pesieve::util::device_path_to_win32_path(path);
255 if (is_device_path(basic_path)) {
256 // Could not normalize it: it is still a device path. Return as is.
257 return path;
258 }
259 // normalize path sepators: use '/' not '\'
260 replace_char(basic_path, '/', '\\');
261
262 std::string abs_path = relative_to_absolute_path(basic_path);
263
264 char filename[MAX_PATH] = { 0 };
265 if (GetLongPathNameA(abs_path.c_str(), filename, MAX_PATH) == 0) {
266 size_t len = abs_path.length();
267 if (len > MAX_PATH) len = MAX_PATH;
268 //if could not retrieve, process what you have:
269 memcpy(filename, abs_path.c_str(), len);
270 }
271 return strip_prefix(filename, LONG_PATH_PREFIX);
272}
std::string replace_char(std::string &str, char ch1, char ch2)
std::string nt_retrieve_file_path(HANDLE hFile)
std::string expand_path(const std::string &path)
char * get_subpath_ptr(char *modulePath, char *searchedPath)
Definition path_util.cpp:5
std::string strip_prefix(std::string path, std::string prefix)
Definition path_util.cpp:94
std::string remap_to_drive_letter(const std::string &full_path)
NTSTATUS(NTAPI *_RtlCreateProcessReflection)(HANDLE ProcessHandle
std::string convert_to_win32_path(const std::string &path)
std::string device_path_to_win32_path(const std::string &full_path)
bool is_relative(const char *path, size_t path_len)
bool is_disk_relative(const char *path, size_t path_len)
HANDLE nt_create_file(PCWSTR filePath)
DWORD HANDLE hFile
std::string get_system_drive()
Definition path_util.cpp:46
DWORD(__stdcall *_PssCaptureSnapshot)(HANDLE ProcessHandle
bool convert_to_wow64_path(char *szModName)
std::string relative_to_absolute_path(std::string path)
int MAX_PATH
Definition pesieve.py:10
bool is_device_path(const std::string &path)
#define LONG_PATH_PREFIX
#define GLOBALROOT_NAME
char g_Syswow64Path[MAX_PATH]
char g_System32Path[MAX_PATH]