└── client
├── client.sln
└── client
├── client.vcxproj
├── client.vcxproj.filters
├── client.vcxproj.user
├── driver.cpp
├── driver.hpp
├── encryption.hpp
├── main.cpp
├── nt.hpp
├── portable_executable.cpp
├── portable_executable.hpp
├── process.cpp
├── process.hpp
├── utils.cpp
└── utils.hpp
/client/client.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28803.202
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client\client.vcxproj", "{99882DD6-DF3E-4415-BFCA-83A5395BC465}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Debug|x64.ActiveCfg = Debug|x64
17 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Debug|x64.Build.0 = Debug|x64
18 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Debug|x86.ActiveCfg = Debug|Win32
19 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Debug|x86.Build.0 = Debug|Win32
20 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Release|x64.ActiveCfg = Release|x64
21 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Release|x64.Build.0 = Release|x64
22 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Release|x86.ActiveCfg = Release|Win32
23 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {A5EBC2E1-E5A7-4D64-832E-0C547027322D}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/client/client/client.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | {99882DD6-DF3E-4415-BFCA-83A5395BC465}
24 | client
25 | 10.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v142
32 | MultiByte
33 |
34 |
35 | Application
36 | false
37 | v142
38 | true
39 | MultiByte
40 |
41 |
42 | Application
43 | true
44 | v142
45 | MultiByte
46 |
47 |
48 | Application
49 | false
50 | v142
51 | true
52 | MultiByte
53 | false
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | ..\..\drvout
75 |
76 |
77 |
78 | Level4
79 | Disabled
80 | true
81 | true
82 | true
83 | stdcpp17
84 |
85 |
86 | Console
87 |
88 |
89 |
90 |
91 | Level4
92 | Disabled
93 | true
94 | true
95 | true
96 | stdcpp17
97 |
98 |
99 | Console
100 |
101 |
102 |
103 |
104 | Level3
105 | MaxSpeed
106 | true
107 | true
108 | true
109 | true
110 |
111 |
112 | Console
113 | true
114 | true
115 |
116 |
117 |
118 |
119 | Level4
120 | MaxSpeed
121 | true
122 | true
123 | true
124 | true
125 | true
126 | stdcpp17
127 |
128 |
129 | Console
130 | true
131 | true
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/client/client/client.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 |
35 |
36 | Source Files
37 |
38 |
39 | Source Files
40 |
41 |
42 | Source Files
43 |
44 |
45 | Source Files
46 |
47 |
48 | Source Files
49 |
50 |
51 | Source Files
52 |
53 |
54 |
--------------------------------------------------------------------------------
/client/client/client.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/client/client/driver.cpp:
--------------------------------------------------------------------------------
1 | #include "driver.hpp"
2 |
3 | NTSTATUS driver::CallDriverControl(PIO_BUFFER io_buffer)
4 | {
5 | using NtUserGetAutoRotationStateFn = bool(__stdcall*)(PIO_BUFFER);
6 | const auto NtUserGetAutoRotationState = reinterpret_cast(GetProcAddress(LoadLibrary(encryption::XorString("win32u.dll")), encryption::XorString("NtUserGetAutoRotationState")));
7 |
8 | NtUserGetAutoRotationState(io_buffer);
9 |
10 | if (!NT_SUCCESS(io_buffer->status))
11 | return STATUS_UNSUCCESSFUL;
12 |
13 | return io_buffer->driver_operation_status;
14 | }
15 |
16 | bool driver::ReadMemory(uint32_t process_id, uint64_t address, void* buffer, size_t size)
17 | {
18 | IO_BUFFER io_buffer = { 0 };
19 |
20 | io_buffer.driver_operation = COPY_MEMORY;
21 | io_buffer.ul1 = process_id; // source process id
22 | io_buffer.ull1 = address; // source address
23 | io_buffer.ul2 = GetCurrentProcessId(); // target process id
24 | io_buffer.ull2 = reinterpret_cast(buffer); // target address
25 | io_buffer.size = size;
26 |
27 | return NT_SUCCESS(CallDriverControl(&io_buffer));
28 | }
29 |
30 | bool driver::WriteMemory(uint32_t process_id, uint64_t address, void* buffer, size_t size)
31 | {
32 | IO_BUFFER io_buffer = { 0 };
33 |
34 | io_buffer.driver_operation = COPY_MEMORY;
35 | io_buffer.ul1 = GetCurrentProcessId(); // source process id
36 | io_buffer.ull1 = reinterpret_cast(buffer); // source address
37 | io_buffer.ul2 = process_id; // target process id
38 | io_buffer.ull2 = address; // target address
39 | io_buffer.size = size;
40 |
41 | return NT_SUCCESS(CallDriverControl(&io_buffer));
42 | }
43 |
44 | uint64_t driver::AllocateMemory(uint32_t process_id, size_t size, uint32_t protect)
45 | {
46 | IO_BUFFER io_buffer = { 0 };
47 |
48 | io_buffer.driver_operation = ALLOCATE_MEMORY;
49 | io_buffer.ul1 = process_id;
50 | io_buffer.size = size;
51 | io_buffer.ul2 = protect;
52 |
53 | if (!NT_SUCCESS(CallDriverControl(&io_buffer)))
54 | return 0;
55 |
56 | return io_buffer.result;
57 | }
58 |
59 | bool driver::FreeMemory(uint32_t process_id, uint64_t address)
60 | {
61 | IO_BUFFER io_buffer = { 0 };
62 |
63 | io_buffer.driver_operation = FREE_MEMORY;
64 | io_buffer.ul1 = process_id;
65 | io_buffer.ull1 = address;
66 |
67 | return NT_SUCCESS(CallDriverControl(&io_buffer));
68 | }
69 |
70 | bool driver::ChangeMemoryProtection(uint32_t process_id, uint64_t address, size_t size, uint32_t new_protection, uint32_t* old_protection)
71 | {
72 | IO_BUFFER io_buffer = { 0 };
73 |
74 | io_buffer.driver_operation = PROTECT_MEMORY;
75 | io_buffer.ul1 = process_id;
76 | io_buffer.ull1 = address;
77 | io_buffer.size = size;
78 | io_buffer.ul2 = new_protection;
79 |
80 | if (!NT_SUCCESS(CallDriverControl(&io_buffer)))
81 | return false;
82 |
83 | *old_protection = io_buffer.result;
84 | return true;
85 | }
86 |
87 | uint64_t driver::GetPebBase(uint32_t process_id)
88 | {
89 | IO_BUFFER io_buffer = { 0 };
90 |
91 | io_buffer.driver_operation = GET_PROCESS_PEB_BASE;
92 | io_buffer.ul1 = process_id;
93 |
94 | if (!NT_SUCCESS(CallDriverControl(&io_buffer)))
95 | return 0;
96 |
97 | return io_buffer.result;
98 | }
--------------------------------------------------------------------------------
/client/client/driver.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma warning( disable : 4244 )
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "nt.hpp"
11 | #include "encryption.hpp"
12 | #include "utils.hpp"
13 | #pragma comment(lib, "user32.lib")
14 |
15 | namespace driver
16 | {
17 | enum DRIVER_OPERATION
18 | {
19 | IDLE,
20 | COPY_MEMORY,
21 | ALLOCATE_MEMORY,
22 | FREE_MEMORY,
23 | PROTECT_MEMORY,
24 | GET_PROCESS_PEB_BASE
25 | };
26 |
27 |
28 | typedef struct _IO_BUFFER
29 | {
30 | NTSTATUS status;
31 | NTSTATUS driver_operation_status;
32 | DRIVER_OPERATION driver_operation;
33 | uint64_t result;
34 | uint32_t ul1;
35 | uint32_t ul2;
36 | uint64_t ull1;
37 | uint64_t ull2;
38 | SIZE_T size;
39 | }IO_BUFFER, * PIO_BUFFER;
40 |
41 | NTSTATUS CallDriverControl(PIO_BUFFER io_buffer);
42 |
43 | bool ReadMemory(uint32_t process_id, uint64_t address, void* buffer, size_t size);
44 | bool WriteMemory(uint32_t process_id, uint64_t address, void* buffer, size_t size);
45 | uint64_t AllocateMemory(uint32_t process_id, size_t size, uint32_t protect);
46 | bool FreeMemory(uint32_t process_id, uint64_t address);
47 | bool ChangeMemoryProtection(uint32_t process_id, uint64_t address, size_t size, uint32_t new_protection, uint32_t* old_protection);
48 | uint64_t GetPebBase(uint32_t process_id);
49 | }
--------------------------------------------------------------------------------
/client/client/encryption.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma warning( disable : 4172 )
3 | #include
4 |
5 | // Credits: kwezee
6 |
7 | namespace encryption
8 | {
9 | template< class _t, const size_t _s, const _t _k = 'L' >
10 | class xstr {
11 | std::array< _t, _s > buffer;
12 |
13 | constexpr auto enc(const _t ch) const noexcept -> _t {
14 | return ch ^ _k;
15 | }
16 |
17 | auto dec(const _t ch) const noexcept -> _t {
18 | return ch ^ _k;
19 | }
20 |
21 | public:
22 | auto data() noexcept {
23 | for (auto i = _s; i--; ) {
24 | buffer[i] = dec(buffer[i]);
25 | }
26 |
27 | return buffer.data();
28 | }
29 |
30 | template< size_t... _i >
31 | constexpr __forceinline xstr(const _t(&s)[_s], std::index_sequence< _i... >) noexcept
32 | : buffer{ enc(s[_i])... } {}
33 | };
34 |
35 | template< class _t, size_t _s >
36 | constexpr __forceinline auto XorString(const _t(&s)[_s]) {
37 | return xstr< _t, _s >{ s, std::make_index_sequence< _s >() }.data();
38 | }
39 | }
--------------------------------------------------------------------------------
/client/client/main.cpp:
--------------------------------------------------------------------------------
1 | #include "driver.hpp"
2 | #include "utils.hpp"
3 | #include "encryption.hpp"
4 | #include
5 | #include "process.hpp"
6 | #include
7 |
8 | int main()
9 | {
10 | Process process;
11 | std::string cmd_line;
12 |
13 | while (std::getline(std::cin, cmd_line))
14 | {
15 | std::istringstream iss(cmd_line);
16 | std::vectorargs(std::istream_iterator{ iss }, std::istream_iterator());
17 |
18 | if (args.empty())
19 | continue;
20 |
21 | const std::string command = args[0];
22 |
23 | if (!command.compare("a"))
24 | {
25 | // ATTACH TO A PROCESS
26 |
27 | if (args.size() != 2)
28 | {
29 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
30 | continue;
31 | }
32 |
33 | const std::string attach_arg = args[1];
34 | /*
35 | if (std::experimental::filesystem::path(attach_arg).has_extension())
36 | {
37 | const std::string process_name = attach_arg;
38 | process.Attach(process_name);
39 | }
40 | else
41 | {
42 | const std::uint32_t pid = std::stoul(attach_arg);
43 | process.Attach(pid);
44 | }
45 | */
46 |
47 | const std::string process_name = attach_arg;
48 | process.Attach(process_name);
49 | }
50 | else if (!command.compare("d"))
51 | {
52 | // DETACH FROM A PROCESS
53 |
54 | process.Deattach();
55 | }
56 | else if (!command.compare("db"))
57 | {
58 | // READ N BYTES
59 |
60 | if (args.size() != 3)
61 | {
62 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
63 | continue;
64 | }
65 |
66 | const uint64_t address = std::stoull(args[1], nullptr, 16);
67 | const size_t size = std::stoull(args[2]);
68 |
69 | size_t aligned_size = 0;
70 |
71 | if (!(size % 16))
72 | aligned_size = size;
73 | else
74 | aligned_size = (size / 16) * 16 + 16;
75 |
76 | auto buffer = new uint8_t[aligned_size];
77 |
78 | if (!process.ReadMemory(address, buffer, aligned_size))
79 | {
80 | std::cout << encryption::XorString("[-] failed to read address 0x") << reinterpret_cast(address) << std::endl;
81 | delete[] buffer;
82 | continue;
83 | }
84 |
85 | for (auto i = 0u; i <= aligned_size - 16; i += 16)
86 | {
87 | std::cout << std::setw(16) << std::setfill('0') << std::hex << address + i << '\t';
88 |
89 | for (auto j = 0u; j < 16; ++j)
90 | {
91 | std::cout << std::setw(2) << std::setfill('0') << std::hex << uint32_t(buffer[i + j]) << ' ';
92 | }
93 |
94 | std::cout << '\t';
95 |
96 | for (auto k = 0u; k < 16; ++k)
97 | {
98 | if (isprint(buffer[i + k]))
99 | {
100 | std::cout << std::dec << buffer[i + k];
101 | }
102 | else
103 | {
104 | std::cout << std::dec << '.';
105 | }
106 | }
107 |
108 | std::cout << std::endl;
109 | }
110 |
111 | delete[] buffer;
112 | }
113 | else if (!command.compare("dc"))
114 | {
115 | // READ N DWORD ADDRESSES
116 |
117 | if (args.size() != 3)
118 | {
119 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
120 | continue;
121 | }
122 |
123 | const uint64_t address = std::stoull(args[1], nullptr, 16);
124 | const size_t count = std::stoull(args[2]);
125 |
126 | const size_t size = count * 4;
127 | size_t aligned_size = 0;
128 |
129 | if (!(size % 16))
130 | aligned_size = size;
131 | else
132 | aligned_size = (size / 16) * 16 + 16;
133 |
134 | auto buffer = new uint8_t[aligned_size];
135 |
136 | if (!process.ReadMemory(address, buffer, aligned_size))
137 | {
138 | std::cout << encryption::XorString("[-] failed to read address 0x") << reinterpret_cast(address) << std::endl;
139 | delete[] buffer;
140 | continue;
141 | }
142 |
143 | for (auto i = 0u; i <= aligned_size - 16; i += 16)
144 | {
145 | std::cout << std::setw(16) << std::setfill('0') << std::hex << address + i << '\t';
146 |
147 | for (auto j = 0u; j < 16; j += 4)
148 | {
149 | std::cout << std::setw(8) << std::setfill('0') << std::hex << *reinterpret_cast(reinterpret_cast(buffer) + i + j) << ' ';
150 | }
151 |
152 | std::cout << std::dec << std::endl;
153 | }
154 |
155 | delete[] buffer;
156 | }
157 | else if (!command.compare("dq"))
158 | {
159 | // READ N DWORD ADDRESSES
160 |
161 | if (args.size() != 3)
162 | {
163 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
164 | continue;
165 | }
166 |
167 | const uint64_t address = std::stoull(args[1], nullptr, 16);
168 | const size_t count = std::stoull(args[2]);
169 |
170 | const size_t size = count * 8;
171 | size_t aligned_size = 0;
172 |
173 | if (!(size % 16))
174 | aligned_size = size;
175 | else
176 | aligned_size = (size / 16) * 16 + 16;
177 |
178 | auto buffer = new uint8_t[aligned_size];
179 |
180 | if(!process.ReadMemory(address, buffer, aligned_size))
181 | {
182 | std::cout << encryption::XorString("[-] failed to read address 0x") << reinterpret_cast(address) << std::endl;
183 | delete[] buffer;
184 | continue;
185 | }
186 |
187 | for (auto i = 0u; i <= aligned_size - 16; i += 16)
188 | {
189 | std::cout << std::setw(16) << std::setfill('0') << std::hex << address + i << '\t';
190 |
191 | for (auto j = 0u; j < 16; j += 8)
192 | {
193 | std::cout << std::setw(16) << std::setfill('0') << std::hex << *reinterpret_cast(reinterpret_cast(buffer) + i + j) << ' ';
194 | }
195 |
196 | std::cout << std::dec << std::endl;
197 | }
198 |
199 | delete[] buffer;
200 | }
201 | else if (!command.compare("eb"))
202 | {
203 | // WRITE BYTE
204 |
205 | if (args.size() != 3)
206 | {
207 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
208 | continue;
209 | }
210 |
211 | const uint64_t address = std::stoull(args[1], nullptr, 16);
212 | uint8_t val = std::stoul(args[2], nullptr, 16);
213 |
214 | uint32_t new_protection = PAGE_EXECUTE_READWRITE, old_protection = 0;
215 |
216 | if (!process.ChangeMemoryProtection(address, sizeof(val), new_protection, &old_protection))
217 | {
218 | std::cout << encryption::XorString("[-] failed to change memory protection of address 0x") << reinterpret_cast(address) << std::endl;
219 | continue;
220 | }
221 |
222 | if (!process.WriteMemory(address, &val, sizeof(val)))
223 | {
224 | std::cout << encryption::XorString("[-] failed to write to address 0x") << reinterpret_cast(address) << std::endl;
225 | continue;
226 | }
227 |
228 | process.ChangeMemoryProtection(address, sizeof(val), old_protection, &new_protection);
229 | }
230 | else if (!command.compare("ed"))
231 | {
232 | // WRITE DWORD
233 |
234 | if (args.size() != 3)
235 | {
236 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
237 | continue;
238 | }
239 |
240 | const uint64_t address = std::stoull(args[1], nullptr, 16);
241 | uint32_t val = std::stoul(args[2], nullptr, 16);
242 |
243 | uint32_t new_protection = PAGE_EXECUTE_READWRITE, old_protection = 0;
244 |
245 | if (!process.ChangeMemoryProtection(address, sizeof(val), new_protection, &old_protection))
246 | {
247 | std::cout << encryption::XorString("[-] failed to change memory protection of address 0x") << reinterpret_cast(address) << std::endl;
248 | continue;
249 | }
250 |
251 | if (!process.WriteMemory(address, &val, sizeof(val)))
252 | {
253 | std::cout << encryption::XorString("[-] failed to write to address 0x") << reinterpret_cast(address) << std::endl;
254 | continue;
255 | }
256 |
257 | process.ChangeMemoryProtection(address, sizeof(val), old_protection, &new_protection);
258 | }
259 | else if (!command.compare("eq"))
260 | {
261 | // WRITE QWORD
262 |
263 | if (args.size() != 3)
264 | {
265 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
266 | continue;
267 | }
268 |
269 | const uint64_t address = std::stoull(args[1], nullptr, 16);
270 | uint64_t val = std::stoull(args[2], nullptr, 16);
271 |
272 | uint32_t new_protection = PAGE_EXECUTE_READWRITE, old_protection = 0;
273 |
274 | if(!process.ChangeMemoryProtection(address, sizeof(val), new_protection, &old_protection))
275 | {
276 | std::cout << encryption::XorString("[-] failed to change memory protection of address 0x") << reinterpret_cast(address) << std::endl;
277 | continue;
278 | }
279 |
280 | if(!process.WriteMemory(address, &val, sizeof(val)))
281 | {
282 | std::cout << encryption::XorString("[-] failed to write to address 0x") << reinterpret_cast(address) << std::endl;
283 | continue;
284 | }
285 |
286 | process.ChangeMemoryProtection(address, sizeof(val), old_protection, &new_protection);
287 | }
288 | else if (!command.compare("b"))
289 | {
290 | // GET IMAGE BASE
291 |
292 | std::cout << std::setw(16) << std::setfill('0') << std::hex << process.GetImageBase() << std::endl;
293 | }
294 | else if (!command.compare("lm"))
295 | {
296 | // GET LOADED MODULES
297 |
298 | for (const auto& [module_name, base] : process.GetLoadedModules())
299 | {
300 | std::cout << std::setw(16) << std::setfill('0') << std::hex << base << '\t' << std::dec << module_name << std::endl;
301 | }
302 | }
303 | else if (!command.compare("mb"))
304 | {
305 | // GET MODULE BASE
306 |
307 | if (args.size() != 2)
308 | {
309 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
310 | continue;
311 | }
312 |
313 | const std::string module_name = args[1];
314 | const auto module_base = process.GetModuleBase(module_name);
315 |
316 | if (!module_base)
317 | {
318 | std::cout << encryption::XorString("[-] failed to get module base of ") << module_name << std::endl;
319 | continue;
320 | }
321 |
322 | std::cout << std::setw(16) << std::setfill('0') << std::hex << process.GetModuleBase(module_name) << std::dec << std::endl;
323 | }
324 | else if (!command.compare("me"))
325 | {
326 | // GET MODULE EXPORT
327 |
328 | if (args.size() != 3)
329 | {
330 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
331 | continue;
332 | }
333 |
334 | const std::string export_name = args[2];
335 | uint64_t module_base = 0;
336 |
337 | if (std::experimental::filesystem::path(args[1]).has_extension())
338 | {
339 | module_base = process.GetModuleBase(args[1]);
340 |
341 | if (!module_base)
342 | {
343 | std::cout << encryption::XorString("[-] failed to get module base of ") << args[1] << std::endl;
344 | continue;
345 | }
346 | }
347 | else
348 | {
349 | module_base = std::stoull(args[1], nullptr, 16);
350 | }
351 |
352 | const uint64_t module_export = process.GetModuleExport(module_base, export_name);
353 |
354 | if (!module_export)
355 | {
356 | std::cout << encryption::XorString("[-] failed to get module base of ") << export_name << ' ' << args[1] << std::endl;
357 | continue;
358 | }
359 |
360 | std::cout << std::setw(16) << std::setfill('0') << std::hex << module_export << std::dec << std::endl;
361 | }
362 | else if (!command.compare("mm"))
363 | {
364 | // MANUAL MAP
365 |
366 | if (args.size() != 2)
367 | {
368 | std::cout << encryption::XorString("[-] invalid usage") << std::endl;
369 | continue;
370 | }
371 |
372 | const std::string path = args[1];
373 |
374 | if (!process.MapModule(path))
375 | {
376 | std::cout << encryption::XorString("[-] failed to manual map ") << path << std::endl;
377 | }
378 | }
379 | else
380 | {
381 | std::cout << encryption::XorString("[-] unknown command \"") << command << '\"' << std::endl;
382 | }
383 | }
384 |
385 | }
386 |
--------------------------------------------------------------------------------
/client/client/nt.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #pragma comment(lib, "ntdll.lib")
5 |
6 | #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
7 |
8 | namespace nt
9 | {
10 | constexpr auto STATUS_SUCCESS = 0;
11 |
12 | constexpr auto SE_DEBUG_PRIVILEGE = 20;
13 | constexpr auto STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
14 |
15 | constexpr auto SystemModuleInformation = 11;
16 |
17 | typedef struct _PEB_LDR_DATA {
18 | ULONG Length;
19 | BOOLEAN Initialized;
20 | PVOID SsHandle;
21 | LIST_ENTRY InLoadOrderModuleList;
22 | LIST_ENTRY InMemoryOrderModuleList;
23 | LIST_ENTRY InInitializationOrderModuleList;
24 | } PEB_LDR_DATA, *PPEB_LDR_DATA;
25 |
26 | typedef struct _LDR_MODULE {
27 | LIST_ENTRY InLoadOrderModuleList;
28 | LIST_ENTRY InMemoryOrderModuleList;
29 | LIST_ENTRY InInitializationOrderModuleList;
30 | PVOID BaseAddress;
31 | PVOID EntryPoint;
32 | ULONG SizeOfImage;
33 | UNICODE_STRING FullDllName;
34 | UNICODE_STRING BaseDllName;
35 | ULONG Flags;
36 | SHORT LoadCount;
37 | SHORT TlsIndex;
38 | LIST_ENTRY HashTableEntry;
39 | ULONG TimeDateStamp;
40 | } LDR_MODULE, *PLDR_MODULE;
41 |
42 | typedef struct _PEB {
43 | BOOLEAN InheritedAddressSpace;
44 | BOOLEAN ReadImageFileExecOptions;
45 | BOOLEAN BeingDebugged;
46 | BOOLEAN Spare;
47 | HANDLE Mutant;
48 | PVOID ImageBaseAddress;
49 | PPEB_LDR_DATA LoaderData;
50 | PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
51 | PVOID SubSystemData;
52 | PVOID ProcessHeap;
53 | PVOID FastPebLock;
54 | PVOID FastPebLockRoutine;
55 | PVOID FastPebUnlockRoutine;
56 | ULONG EnvironmentUpdateCount;
57 | PVOID* KernelCallbackTable;
58 | PVOID EventLogSection;
59 | PVOID EventLog;
60 | PVOID FreeList;
61 | ULONG TlsExpansionCounter;
62 | PVOID TlsBitmap;
63 | ULONG TlsBitmapBits[0x2];
64 | PVOID ReadOnlySharedMemoryBase;
65 | PVOID ReadOnlySharedMemoryHeap;
66 | PVOID* ReadOnlyStaticServerData;
67 | PVOID AnsiCodePageData;
68 | PVOID OemCodePageData;
69 | PVOID UnicodeCaseTableData;
70 | ULONG NumberOfProcessors;
71 | ULONG NtGlobalFlag;
72 | BYTE Spare2[0x4];
73 | LARGE_INTEGER CriticalSectionTimeout;
74 | ULONG HeapSegmentReserve;
75 | ULONG HeapSegmentCommit;
76 | ULONG HeapDeCommitTotalFreeThreshold;
77 | ULONG HeapDeCommitFreeBlockThreshold;
78 | ULONG NumberOfHeaps;
79 | ULONG MaximumNumberOfHeaps;
80 | PVOID* *ProcessHeaps;
81 | PVOID GdiSharedHandleTable;
82 | PVOID ProcessStarterHelper;
83 | PVOID GdiDCAttributeList;
84 | PVOID LoaderLock;
85 | ULONG OSMajorVersion;
86 | ULONG OSMinorVersion;
87 | ULONG OSBuildNumber;
88 | ULONG OSPlatformId;
89 | ULONG ImageSubSystem;
90 | ULONG ImageSubSystemMajorVersion;
91 | ULONG ImageSubSystemMinorVersion;
92 | ULONG GdiHandleBuffer[0x22];
93 | ULONG PostProcessInitRoutine;
94 | ULONG TlsExpansionBitmap;
95 | BYTE TlsExpansionBitmapBits[0x80];
96 | ULONG SessionId;
97 | } PEB, *PPEB;
98 |
99 | typedef struct _RTL_PROCESS_MODULE_INFORMATION
100 | {
101 | HANDLE Section;
102 | PVOID MappedBase;
103 | PVOID ImageBase;
104 | ULONG ImageSize;
105 | ULONG Flags;
106 | USHORT LoadOrderIndex;
107 | USHORT InitOrderIndex;
108 | USHORT LoadCount;
109 | USHORT OffsetToFileName;
110 | UCHAR FullPathName[256];
111 | } RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
112 |
113 | typedef struct _RTL_PROCESS_MODULES
114 | {
115 | ULONG NumberOfModules;
116 | RTL_PROCESS_MODULE_INFORMATION Modules[1];
117 | } RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
118 | }
--------------------------------------------------------------------------------
/client/client/portable_executable.cpp:
--------------------------------------------------------------------------------
1 | #include "portable_executable.hpp"
2 |
3 | PIMAGE_NT_HEADERS64 portable_executable::GetNtHeaders(void* image_base)
4 | {
5 | const auto dos_header = reinterpret_cast(image_base);
6 |
7 | if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
8 | return nullptr;
9 |
10 | const auto nt_headers = reinterpret_cast(reinterpret_cast(image_base) + dos_header->e_lfanew);
11 |
12 | if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
13 | return nullptr;
14 |
15 | return nt_headers;
16 | }
17 |
18 | portable_executable::vec_relocs portable_executable::GetRelocs(void* image_base)
19 | {
20 | const PIMAGE_NT_HEADERS64 nt_headers = GetNtHeaders(image_base);
21 |
22 | if (!nt_headers)
23 | return {};
24 |
25 | const auto reloc_data_directory = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
26 |
27 | if (!reloc_data_directory.VirtualAddress || !reloc_data_directory.Size)
28 | return {};
29 |
30 | vec_relocs relocs;
31 |
32 | auto current_base_relocation = reinterpret_cast(reinterpret_cast(image_base) + reloc_data_directory.VirtualAddress);
33 | const auto reloc_end = reinterpret_cast(current_base_relocation) + reloc_data_directory.Size;
34 |
35 | while (current_base_relocation->VirtualAddress && current_base_relocation->VirtualAddress < reloc_end && current_base_relocation->SizeOfBlock)
36 | {
37 | RelocInfo reloc_info;
38 |
39 | reloc_info.address = reinterpret_cast(image_base) + current_base_relocation->VirtualAddress;
40 | reloc_info.item = reinterpret_cast(reinterpret_cast(current_base_relocation) + sizeof(IMAGE_BASE_RELOCATION));
41 | reloc_info.count = (current_base_relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t);
42 |
43 | relocs.push_back(reloc_info);
44 |
45 | current_base_relocation = reinterpret_cast(reinterpret_cast(current_base_relocation) + current_base_relocation->SizeOfBlock);
46 | }
47 |
48 | return relocs;
49 | }
50 |
51 | portable_executable::vec_imports portable_executable::GetImports(void* image_base)
52 | {
53 | const PIMAGE_NT_HEADERS64 nt_headers = GetNtHeaders(image_base);
54 |
55 | if (!nt_headers)
56 | return {};
57 |
58 | const auto import_data_directory = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
59 |
60 | if (!import_data_directory.VirtualAddress || !import_data_directory.Size)
61 | return {};
62 |
63 | vec_imports imports;
64 |
65 | auto current_import_descriptor = reinterpret_cast(reinterpret_cast(image_base) + import_data_directory.VirtualAddress);
66 |
67 | while (current_import_descriptor->FirstThunk)
68 | {
69 | ImportInfo import_info;
70 |
71 | import_info.module_name = std::string(reinterpret_cast(reinterpret_cast(image_base) + current_import_descriptor->Name));
72 |
73 | auto current_first_thunk = reinterpret_cast(reinterpret_cast(image_base) + current_import_descriptor->FirstThunk);
74 | auto current_originalFirstThunk = reinterpret_cast(reinterpret_cast(image_base) + current_import_descriptor->OriginalFirstThunk);
75 |
76 | while (current_originalFirstThunk->u1.Function)
77 | {
78 | ImportFunctionInfo import_function_data;
79 |
80 | auto thunk_data = reinterpret_cast(reinterpret_cast(image_base) + current_originalFirstThunk->u1.AddressOfData);
81 |
82 | import_function_data.name = thunk_data->Name;
83 | import_function_data.address = ¤t_first_thunk->u1.Function;
84 |
85 | import_info.function_datas.push_back(import_function_data);
86 |
87 | ++current_originalFirstThunk;
88 | ++current_first_thunk;
89 | }
90 |
91 | imports.push_back(import_info);
92 | ++current_import_descriptor;
93 | }
94 |
95 | return imports;
96 | }
97 |
98 | uint32_t portable_executable::GetSectionProtection(uint32_t section_characteristics)
99 | {
100 | uint32_t result = 0;
101 |
102 | if (section_characteristics & IMAGE_SCN_MEM_NOT_CACHED)
103 | result |= PAGE_NOCACHE;
104 |
105 | if (section_characteristics & IMAGE_SCN_MEM_EXECUTE)
106 | {
107 | if (section_characteristics & IMAGE_SCN_MEM_READ)
108 | {
109 | if (section_characteristics & IMAGE_SCN_MEM_WRITE)
110 | result |= PAGE_EXECUTE_READWRITE;
111 | else
112 | result |= PAGE_EXECUTE_READ;
113 | }
114 | else
115 | {
116 | if (section_characteristics & IMAGE_SCN_MEM_WRITE)
117 | result |= PAGE_EXECUTE_WRITECOPY;
118 | else
119 | result |= PAGE_EXECUTE;
120 | }
121 | }
122 | else
123 | {
124 | if (section_characteristics & IMAGE_SCN_MEM_READ)
125 | {
126 | if (section_characteristics & IMAGE_SCN_MEM_WRITE)
127 | result |= PAGE_READWRITE;
128 | else
129 | result |= PAGE_READONLY;
130 | }
131 | else
132 | {
133 | if (section_characteristics & IMAGE_SCN_MEM_WRITE)
134 | result |= PAGE_WRITECOPY;
135 | else
136 | result |= PAGE_NOACCESS;
137 | }
138 | }
139 |
140 | return result;
141 | }
--------------------------------------------------------------------------------
/client/client/portable_executable.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma warning( disable : 4244 )
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | namespace portable_executable
9 | {
10 | struct RelocInfo
11 | {
12 | uint64_t address;
13 | uint16_t* item;
14 | uint32_t count;
15 | };
16 |
17 | struct ImportFunctionInfo
18 | {
19 | std::string name;
20 | uint64_t* address;
21 | };
22 |
23 | struct ImportInfo
24 | {
25 | std::string module_name;
26 | std::vector function_datas;
27 | };
28 |
29 | using vec_sections = std::vector;
30 | using vec_relocs = std::vector;
31 | using vec_imports = std::vector;
32 |
33 | PIMAGE_NT_HEADERS64 GetNtHeaders(void* image_base);
34 | vec_relocs GetRelocs(void* image_base);
35 | vec_imports GetImports(void* image_base);
36 | uint32_t GetSectionProtection(uint32_t section_characteristics);
37 | }
--------------------------------------------------------------------------------
/client/client/process.cpp:
--------------------------------------------------------------------------------
1 | #include "process.hpp"
2 |
3 | bool Process::Attach(uint32_t pid)
4 | {
5 | Deattach();
6 |
7 | m_pid = pid;
8 |
9 | if (!utils::ProcessExists(m_pid))
10 | {
11 | std::cerr << encryption::XorString("[-] Process doesn't exist") << std::endl;
12 | return false;
13 | }
14 |
15 | m_process_name = utils::GetProcessNameById(m_pid);
16 |
17 | m_is_attached = true;
18 | return true;
19 | }
20 |
21 | bool Process::Attach(std::string process_name)
22 | {
23 | Deattach();
24 |
25 | m_process_name = process_name;
26 |
27 | if (!utils::ProcessExists(m_process_name))
28 | {
29 | std::cerr << encryption::XorString("[-] Process doesn't exist") << std::endl;
30 | return false;
31 | }
32 |
33 | m_pid = utils::GetProcessIdByName(m_process_name);
34 |
35 | if (!m_pid)
36 | {
37 | std::cerr << encryption::XorString("[-] Failed to get process id") << std::endl;
38 | return false;
39 | }
40 |
41 | m_is_attached = true;
42 | return true;
43 | }
44 |
45 | bool Process::IsAttached()
46 | {
47 | return m_is_attached;
48 | }
49 |
50 | void Process::Deattach()
51 | {
52 | m_pid = 0;
53 | m_process_name.clear();
54 | m_mapped_modules.clear();
55 | m_is_attached = false;
56 | }
57 |
58 | bool Process::ReadMemory(uint64_t address, void* buffer, size_t size)
59 | {
60 | if (!m_is_attached)
61 | {
62 | return false;
63 | }
64 |
65 | return driver::ReadMemory(m_pid, address, buffer, size);
66 | }
67 |
68 | bool Process::WriteMemory(uint64_t address, void* buffer, size_t size)
69 | {
70 | if (!m_is_attached)
71 | {
72 | return false;
73 | }
74 |
75 | return driver::WriteMemory(m_pid, address, buffer, size);
76 | }
77 |
78 | uint64_t Process::AllocateMemory(size_t size, uint32_t protect)
79 | {
80 | if (!m_is_attached)
81 | {
82 | return false;
83 | }
84 |
85 | return driver::AllocateMemory(m_pid, size, protect);
86 | }
87 | bool Process::FreeMemory(uint64_t address)
88 | {
89 | if (!m_is_attached)
90 | {
91 | return false;
92 | }
93 |
94 | return driver::FreeMemory(m_pid, address);
95 | }
96 |
97 | bool Process::ChangeMemoryProtection(uint64_t address, size_t size, uint32_t new_protection, uint32_t* old_protection)
98 | {
99 | if (!m_is_attached)
100 | {
101 | return false;
102 | }
103 |
104 | return driver::ChangeMemoryProtection(m_pid, address, size, new_protection, old_protection);
105 | }
106 |
107 | uint64_t Process::GetImageBase()
108 | {
109 | if (!m_is_attached)
110 | {
111 | return false;
112 | }
113 |
114 | nt::PEB peb = { 0 };
115 |
116 | const uint64_t peb_base = driver::GetPebBase(m_pid);
117 |
118 | if (!peb_base)
119 | {
120 | std::cerr << encryption::XorString("[-] Failed to get PEB base of ") << m_pid << std::endl;
121 | return 0;
122 | }
123 |
124 | if (!driver::ReadMemory(m_pid, peb_base, &peb, sizeof(peb)))
125 | {
126 | std::cerr << encryption::XorString("[-] Failed to read PEB of ") << m_pid << std::endl;
127 | return 0;
128 | }
129 |
130 | return reinterpret_cast(peb.ImageBaseAddress);
131 | }
132 |
133 | vec_modules Process::GetLoadedModules()
134 | {
135 | if (!m_is_attached)
136 | {
137 | return {};
138 | }
139 |
140 | vec_modules result = {};
141 |
142 | nt::PEB peb = { 0 };
143 |
144 | const uint64_t peb_base = driver::GetPebBase(m_pid);
145 |
146 | if (!peb_base)
147 | {
148 | std::cout << encryption::XorString("[-] Failed to get PEB base of ") << m_pid << std::endl;
149 | return {};
150 | }
151 |
152 | if (!ReadMemory(peb_base, &peb, sizeof(peb)))
153 | {
154 | std::cout << encryption::XorString("[-] Failed to read PEB of ") << m_pid << std::endl;
155 | return {};
156 | }
157 |
158 | nt::PEB_LDR_DATA ldr_data;
159 |
160 | if (!ReadMemory(reinterpret_cast(peb.LoaderData), &ldr_data, sizeof(ldr_data)))
161 | {
162 | return {};
163 | }
164 |
165 | const LIST_ENTRY* flink_start = ldr_data.InLoadOrderModuleList.Flink;
166 | LIST_ENTRY* flink_current = ldr_data.InLoadOrderModuleList.Flink;
167 |
168 | nt::LDR_MODULE current_module = { 0 };
169 |
170 | do
171 | {
172 | if (!ReadMemory(reinterpret_cast(flink_current), ¤t_module, sizeof(current_module)))
173 | {
174 | return result;
175 | }
176 |
177 | wchar_t buffer[MAX_PATH] = { 0 };
178 |
179 | if (!ReadMemory(reinterpret_cast(current_module.BaseDllName.Buffer), buffer, current_module.BaseDllName.Length))
180 | {
181 | return result;
182 | }
183 |
184 | std::wstring wcurrent_module_name = buffer;
185 | std::string current_module_name = std::string(wcurrent_module_name.begin(), wcurrent_module_name.end());
186 |
187 | Module mod = { current_module_name, reinterpret_cast(current_module.BaseAddress) };
188 | result.push_back(mod);
189 |
190 | flink_current = current_module.InLoadOrderModuleList.Flink;
191 |
192 | } while (flink_current != flink_start);
193 |
194 | return result;
195 | }
196 |
197 | uint64_t Process::GetModuleExport(uint64_t module_base, const std::string& function_name)
198 | {
199 | if (!m_is_attached)
200 | {
201 | return 0;
202 | }
203 |
204 | IMAGE_DOS_HEADER dos_header = { 0 };
205 | IMAGE_NT_HEADERS64 nt_headers = { 0 };
206 |
207 | if (!ReadMemory(module_base, &dos_header, sizeof(dos_header)) || dos_header.e_magic != IMAGE_DOS_SIGNATURE ||
208 | !ReadMemory(module_base + dos_header.e_lfanew, &nt_headers, sizeof(nt_headers)) || nt_headers.Signature != IMAGE_NT_SIGNATURE)
209 | return 0;
210 |
211 | const auto export_base = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
212 | const auto export_base_size = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
213 |
214 | if (!export_base)
215 | return 0;
216 |
217 | const auto export_data = reinterpret_cast(VirtualAlloc(nullptr, export_base_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
218 |
219 | if (!ReadMemory(module_base + export_base, export_data, export_base_size))
220 | {
221 | VirtualFree(export_data, 0, MEM_RELEASE);
222 | return 0;
223 | }
224 |
225 | const auto delta = reinterpret_cast(export_data) - export_base;
226 |
227 | const auto name_table = reinterpret_cast(export_data->AddressOfNames + delta);
228 | const auto ordinal_table = reinterpret_cast(export_data->AddressOfNameOrdinals + delta);
229 | const auto function_table = reinterpret_cast(export_data->AddressOfFunctions + delta);
230 |
231 | for (auto i = 0u; i < export_data->NumberOfNames; ++i)
232 | {
233 | const std::string current_function_name = std::string(reinterpret_cast(name_table[i] + delta));
234 |
235 | if (!_stricmp(current_function_name.c_str(), function_name.c_str()))
236 | {
237 | const auto current_ordinal_ = ordinal_table[i];
238 | const auto current_address = module_base + function_table[current_ordinal_];
239 |
240 | if (current_address >= module_base + export_base && current_address <= module_base + export_base + export_base_size)
241 | {
242 | char buffer[MAX_PATH];
243 | ReadMemory(current_address, buffer, sizeof(buffer));
244 |
245 | const std::string forwaded_name(buffer);
246 |
247 | const std::string forwaded_module_name = forwaded_name.substr(0, forwaded_name.find(".")) + encryption::XorString(".dll");
248 | const std::string forwaded_function_name = forwaded_name.substr(forwaded_name.find(".") + 1, forwaded_function_name.npos);
249 |
250 | VirtualFree(export_data, 0, MEM_RELEASE);
251 | return GetModuleExport(GetModuleBase(forwaded_module_name), forwaded_function_name);
252 | }
253 |
254 | VirtualFree(export_data, 0, MEM_RELEASE);
255 | return current_address;
256 | }
257 | }
258 |
259 | VirtualFree(export_data, 0, MEM_RELEASE);
260 | return 0;
261 | }
262 |
263 | uint64_t Process::GetModuleBase(const std::string& module_name)
264 | {
265 | if (!m_is_attached)
266 | {
267 | return 0;
268 | }
269 |
270 | nt::PEB peb = { 0 };
271 |
272 | const uint64_t peb_base = driver::GetPebBase(m_pid);
273 |
274 | if (!peb_base)
275 | {
276 | std::cout << encryption::XorString("[-] Failed to get PEB base of ") << m_pid << std::endl;
277 | return false;
278 | }
279 |
280 | if (!ReadMemory(peb_base, &peb, sizeof(peb)))
281 | {
282 | std::cout << encryption::XorString("[-] Failed to read PEB of ") << m_pid << std::endl;
283 | return false;
284 | }
285 |
286 | nt::PEB_LDR_DATA ldr_data;
287 |
288 | if (!ReadMemory(reinterpret_cast(peb.LoaderData), &ldr_data, sizeof(ldr_data)))
289 | return 0;
290 |
291 | const LIST_ENTRY* flink_start = ldr_data.InLoadOrderModuleList.Flink;
292 | LIST_ENTRY* flink_current = ldr_data.InLoadOrderModuleList.Flink;
293 |
294 | nt::LDR_MODULE current_module = { 0 };
295 |
296 | do
297 | {
298 | if (!ReadMemory(reinterpret_cast(flink_current), ¤t_module, sizeof(current_module)))
299 | return 0;
300 |
301 | wchar_t buffer[MAX_PATH] = { 0 };
302 |
303 | if (!ReadMemory(reinterpret_cast(current_module.BaseDllName.Buffer), buffer, current_module.BaseDllName.Length))
304 | return false;
305 |
306 | std::wstring wcurrent_module_name = buffer;
307 | std::string current_module_name = std::string(wcurrent_module_name.begin(), wcurrent_module_name.end());
308 |
309 | if (!_stricmp(current_module_name.c_str(), module_name.c_str()))
310 | return reinterpret_cast(current_module.BaseAddress);
311 |
312 | flink_current = current_module.InLoadOrderModuleList.Flink;
313 |
314 | } while (flink_current != flink_start);
315 |
316 | return 0;
317 | }
318 |
319 | uint64_t Process::GetIATAddress(uint64_t module_base, const std::string& import_module_name, const std::string& import_name)
320 | {
321 | if (!m_is_attached)
322 | {
323 | return 0;
324 | }
325 |
326 | IMAGE_DOS_HEADER dos_header = { 0 };
327 | IMAGE_NT_HEADERS64 nt_headers = { 0 };
328 |
329 | if (!ReadMemory(module_base, &dos_header, sizeof(dos_header)) || dos_header.e_magic != IMAGE_DOS_SIGNATURE ||
330 | !ReadMemory(module_base + dos_header.e_lfanew, &nt_headers, sizeof(nt_headers)) || nt_headers.Signature != IMAGE_NT_SIGNATURE)
331 | return 0;
332 |
333 | const uint64_t import_directory_entry = module_base + nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
334 | const uint32_t import_directory_size = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
335 |
336 | auto buffer = VirtualAlloc(nullptr, import_directory_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
337 |
338 | if (!ReadMemory(import_directory_entry, buffer, import_directory_size))
339 | {
340 | VirtualFree(buffer, 0, MEM_RELEASE);
341 | return 0;
342 | }
343 |
344 | auto current_import_descriptor = static_cast(buffer);
345 |
346 | while (current_import_descriptor->FirstThunk)
347 | {
348 | char current_import_module_name[MAX_PATH] = { 0 };
349 |
350 | if (!ReadMemory(module_base + current_import_descriptor->Name, current_import_module_name, sizeof(current_import_module_name)))
351 | {
352 | VirtualFree(buffer, 0, MEM_RELEASE);
353 | return 0;
354 | }
355 |
356 | if (_stricmp(import_module_name.c_str(), current_import_module_name))
357 | {
358 | ++current_import_descriptor;
359 | continue;
360 | }
361 |
362 | auto buffer2 = VirtualAlloc(nullptr, 0x2000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
363 |
364 | if (!ReadMemory(module_base + current_import_descriptor->OriginalFirstThunk, buffer2, 0x2000))
365 | {
366 | VirtualFree(buffer2, 0, MEM_RELEASE);
367 | VirtualFree(buffer, 0, MEM_RELEASE);
368 |
369 | return 0;
370 | }
371 |
372 | auto current_original_first_thunk = static_cast(buffer2);
373 | auto function_index = 0u;
374 |
375 | while (current_original_first_thunk->u1.Function)
376 | {
377 | auto thunk_data = static_cast(VirtualAlloc(nullptr, 0x2000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
378 |
379 | if (!ReadMemory(module_base + current_original_first_thunk->u1.AddressOfData, thunk_data, 0x2000))
380 | {
381 | VirtualFree(thunk_data, 0, MEM_RELEASE);
382 | VirtualFree(buffer2, 0, MEM_RELEASE);
383 | VirtualFree(buffer, 0, MEM_RELEASE);
384 |
385 | return 0;
386 | }
387 |
388 | if (!_stricmp(import_name.c_str(), thunk_data->Name))
389 | {
390 | VirtualFree(thunk_data, 0, MEM_RELEASE);
391 | break;
392 | }
393 |
394 | VirtualFree(thunk_data, 0, MEM_RELEASE);
395 |
396 | ++current_original_first_thunk;
397 | ++function_index;
398 | }
399 |
400 | VirtualFree(buffer2, 0, MEM_RELEASE);
401 |
402 | if (!function_index)
403 | {
404 | VirtualFree(buffer, 0, MEM_RELEASE);
405 | return 0;
406 | }
407 |
408 | uint32_t first_thunk = current_import_descriptor->FirstThunk;
409 | VirtualFree(buffer, 0, MEM_RELEASE);
410 |
411 | return reinterpret_cast(function_index + reinterpret_cast(module_base + first_thunk));
412 | }
413 |
414 | VirtualFree(buffer, 0, MEM_RELEASE);
415 | return 0;
416 | }
417 |
418 | uint64_t Process::MapModule(const std::string& module_path)
419 | {
420 | if (!m_is_attached)
421 | {
422 | return 0;
423 | }
424 |
425 | if (!std::experimental::filesystem::exists(module_path))
426 | {
427 | std::cout << encryption::XorString("[-] ") << module_path << encryption::XorString(" doensn't exist") << std::endl;
428 | return false;
429 | }
430 |
431 | std::cout << encryption::XorString("Mapping module ") << module_path << std::endl;
432 |
433 | const std::string module_name = std::experimental::filesystem::path(module_path).filename().string();
434 | std::vectorraw_image = { 0 };
435 |
436 | if (!utils::ReadFileToMemory(module_path, &raw_image))
437 | {
438 | std::cout << encryption::XorString("[-] Failed to read the module to memory") << std::endl;
439 | return false;
440 | }
441 |
442 | const PIMAGE_NT_HEADERS64 nt_headers = portable_executable::GetNtHeaders(raw_image.data());
443 |
444 | if (!nt_headers)
445 | {
446 | std::cout << encryption::XorString("[-] Invalid image format") << std::endl;
447 | return 0;
448 | }
449 |
450 | if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
451 | {
452 | std::cout << encryption::XorString("[-] Image is not 64 bit") << std::endl;
453 | return 0;
454 | }
455 |
456 | const uint32_t image_size = nt_headers->OptionalHeader.SizeOfImage;
457 |
458 | const auto local_image_base = VirtualAlloc(nullptr, image_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
459 |
460 | if (!local_image_base)
461 | {
462 | std::cout << encryption::XorString("[-] Failed to allocate local image base") << std::endl;
463 | return 0;
464 | }
465 |
466 | const uint64_t remote_image_base = AllocateMemory(image_size, PAGE_EXECUTE_READWRITE);
467 |
468 | if (!remote_image_base)
469 | {
470 | std::cout << encryption::XorString("[-] Failed to allocate memory for image in remote process") << std::endl;
471 |
472 | VirtualFree(local_image_base, 0, MEM_RELEASE);
473 | return 0;
474 | }
475 |
476 | std::cout << encryption::XorString("[+] Image base of ") << module_name << encryption::XorString(" has been allocated at 0x") << reinterpret_cast(remote_image_base) << std::endl;
477 |
478 | // Copy image headers
479 |
480 | memcpy(local_image_base, raw_image.data(), nt_headers->OptionalHeader.SizeOfHeaders);
481 |
482 | // Copy image sections
483 |
484 | const PIMAGE_SECTION_HEADER image_sections = IMAGE_FIRST_SECTION(nt_headers);
485 |
486 | for (auto i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i)
487 | {
488 | auto local_section = reinterpret_cast(reinterpret_cast(local_image_base) + image_sections[i].VirtualAddress);
489 | memcpy(local_section, reinterpret_cast(reinterpret_cast(raw_image.data()) + image_sections[i].PointerToRawData), image_sections[i].SizeOfRawData);
490 | }
491 |
492 | // Resolve relocs and imports
493 |
494 | RelocateImageByDelta(portable_executable::GetRelocs(local_image_base), remote_image_base - nt_headers->OptionalHeader.ImageBase);
495 |
496 | if (!ResolveImports(portable_executable::GetImports(local_image_base)))
497 | {
498 | std::cout << encryption::XorString("[-] Failed to resolve imports") << std::endl;
499 |
500 | VirtualFree(local_image_base, 0, MEM_RELEASE);
501 | FreeMemory(remote_image_base);
502 |
503 | return 0;
504 | }
505 |
506 | // Write fixed image in remote process
507 |
508 | if (!WriteMemory(remote_image_base, local_image_base, image_size))
509 | {
510 | std::cout << encryption::XorString("[-] Failed to write fixed image in remote process") << std::endl;
511 |
512 | VirtualFree(local_image_base, 0, MEM_RELEASE);
513 | FreeMemory(remote_image_base);
514 |
515 | return 0;
516 | }
517 |
518 | VirtualFree(local_image_base, 0, MEM_RELEASE);
519 |
520 | // Set memory protection
521 |
522 | for (auto i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i)
523 | {
524 | uint32_t old_protection = 0;
525 |
526 | if (!ChangeMemoryProtection(remote_image_base + image_sections[i].VirtualAddress, image_sections[i].SizeOfRawData,
527 | portable_executable::GetSectionProtection(image_sections[i].Characteristics), &old_protection))
528 | {
529 | std::cout << image_sections[i].SizeOfRawData << std::endl;
530 | std::cout << encryption::XorString("[-] Failed to set memory protection") << std::endl;
531 | FreeMemory(remote_image_base);
532 |
533 | return 0;
534 | }
535 | }
536 |
537 | // Call entry point
538 |
539 | const uint64_t address_of_entry_point = remote_image_base + nt_headers->OptionalHeader.AddressOfEntryPoint;
540 |
541 | std::cout << encryption::XorString("Calling entry point of ") << module_name << encryption::XorString(" 0x") << reinterpret_cast(address_of_entry_point) << std::endl;
542 |
543 | if (!CallDllMain(remote_image_base, address_of_entry_point))
544 | {
545 | std::cout << encryption::XorString("[-] Failed to call DllMain") << std::endl;
546 | FreeMemory(remote_image_base);
547 |
548 | return 0;
549 | }
550 |
551 | MappedModule mapped_module = { module_name, remote_image_base };
552 | m_mapped_modules.push_back(mapped_module);
553 |
554 | return remote_image_base;
555 | }
556 |
557 | void Process::RelocateImageByDelta(portable_executable::vec_relocs relocs, const uint64_t delta)
558 | {
559 | for (const auto& current_reloc : relocs)
560 | {
561 | for (auto i = 0u; i < current_reloc.count; ++i)
562 | {
563 | const uint16_t type = current_reloc.item[i] >> 12;
564 | const uint16_t offset = current_reloc.item[i] & 0xFFF;
565 |
566 | if (type == IMAGE_REL_BASED_DIR64)
567 | * reinterpret_cast(current_reloc.address + offset) += delta;
568 | }
569 | }
570 | }
571 |
572 | bool Process::ResolveImports(portable_executable::vec_imports imports)
573 | {
574 | for (const auto& current_import : imports)
575 | {
576 | char module_path[MAX_PATH];
577 |
578 | if (!GetModuleFileName(LoadLibrary(current_import.module_name.c_str()), module_path, sizeof(module_path)))
579 | {
580 | std::cout << encryption::XorString("[-] Failed to get location of dependency ") << current_import.module_name << std::endl;
581 | return false;
582 | }
583 |
584 | const std::string resolved_module_name = std::experimental::filesystem::path(module_path).filename().string();
585 | uint64_t module_base = 0;
586 |
587 | for (const auto& mapped_module : m_mapped_modules)
588 | {
589 | if (!resolved_module_name.compare(mapped_module.module_name))
590 | {
591 | module_base = mapped_module.module_base;
592 | break;
593 | }
594 | }
595 |
596 | if (!module_base)
597 | {
598 | module_base = GetModuleBase(resolved_module_name);
599 |
600 | if (!module_base)
601 | {
602 | module_base = MapModule(module_path);
603 |
604 | if (!module_base)
605 | {
606 | std::cout << encryption::XorString("[-] Failed to load dependency ") << current_import.module_name << " (" << module_path << ")" << std::endl;
607 | return false;
608 | }
609 | }
610 | }
611 |
612 | for (auto& current_function_data : current_import.function_datas)
613 | {
614 | const uint64_t function_address = GetModuleExport(module_base, current_function_data.name);
615 |
616 | if (!function_address)
617 | {
618 | std::cout << encryption::XorString("[-] Failed to resolve import: ") << current_import.module_name << '!' << current_function_data.name << std::endl;
619 | return false;
620 | }
621 |
622 | //std::cout << encryption::XorString("[?] Export ") << resolved_module_name << '!' << current_function_data.name << encryption::XorString(": 0x") << reinterpret_cast(function_address) << std::endl;
623 |
624 | *current_function_data.address = function_address;
625 | }
626 | }
627 |
628 | return true;
629 | }
630 |
631 | bool Process::CallDllMain(uint64_t module_base, uint64_t entry_point_address)
632 | {
633 | const uint64_t NtUserGetMessage = GetModuleExport(GetModuleBase(encryption::XorString("win32u.dll")), encryption::XorString("NtUserGetMessage"));
634 |
635 | if (!NtUserGetMessage)
636 | {
637 | std::cout << encryption::XorString("[-] Failed to get export win32u!NtUserGetMessage") << std::endl;
638 | return false;
639 | }
640 |
641 | const uint64_t function_iat_address = GetIATAddress(GetModuleBase(encryption::XorString(("user32.dll"))), encryption::XorString("win32u.dll"), encryption::XorString("NtUserGetMessage"));
642 |
643 | if (!function_iat_address)
644 | {
645 | std::cout << encryption::XorString("[-] Failed to get IAT address of NtUserGetMessage") << std::endl;
646 | return false;
647 | }
648 |
649 | uint8_t shellcode[] = {
650 | 0x48, 0x83, 0xEC, 0x28, // sub rsp, 0x28
651 | 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, 0x0000000000000000
652 | 0x48, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rdi, 0x0000000000000000
653 | 0x48, 0x89, 0x38, // mov [rax], rdi
654 | 0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rcx, 0x0000000000000000
655 | 0x48, 0xC7, 0xC2, 0x01, 0x00, 0x00, 0x00, // mov rdx, 0x01
656 | 0x4D, 0x31, 0xC0, // xor r8, r8
657 | 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, 0x0000000000000000
658 | 0xFF, 0xD0, // call rax
659 | 0x48, 0x83, 0xC4, 0x28, // add rsp, 0x28
660 | 0xC3 // ret
661 | };
662 |
663 | *reinterpret_cast(shellcode + 0x6) = function_iat_address;
664 | *reinterpret_cast(shellcode + 0x10) = NtUserGetMessage;
665 | *reinterpret_cast(shellcode + 0x1D) = module_base;
666 | *reinterpret_cast(shellcode + 0x31) = entry_point_address;
667 |
668 | uint64_t remote_shellcode = AllocateMemory(sizeof(shellcode), PAGE_EXECUTE_READWRITE);
669 |
670 | if (!remote_shellcode)
671 | return false;
672 |
673 | if (!WriteMemory(remote_shellcode, shellcode, sizeof(shellcode)))
674 | {
675 | FreeMemory(remote_shellcode);
676 | return false;
677 | }
678 |
679 | uint32_t old_protection = 0;
680 | uint32_t new_protection = PAGE_READWRITE;
681 |
682 | if (!ChangeMemoryProtection(function_iat_address, sizeof(uint64_t), new_protection, &old_protection))
683 | {
684 | FreeMemory(remote_shellcode);
685 | return false;
686 | }
687 |
688 | if (!WriteMemory(function_iat_address, &remote_shellcode, sizeof(remote_shellcode)))
689 | {
690 | ChangeMemoryProtection(function_iat_address, sizeof(uint64_t), old_protection, &new_protection);
691 | FreeMemory(remote_shellcode);
692 | return false;
693 | }
694 |
695 | const auto thread_id = utils::GetThreadIdFromProcessId(m_pid);
696 | const bool result = PostThreadMessageW(thread_id, WM_USER + 400, 0, 0) != 0;
697 |
698 | Sleep(200);
699 |
700 | ChangeMemoryProtection(function_iat_address, sizeof(uint64_t), old_protection, &new_protection);
701 | FreeMemory(remote_shellcode);
702 |
703 | return result;
704 | }
--------------------------------------------------------------------------------
/client/client/process.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "utils.hpp"
7 | #include "driver.hpp"
8 | #include "portable_executable.hpp"
9 | #include "encryption.hpp"
10 |
11 | struct Module
12 | {
13 | std::string name;
14 | uint64_t image_base;
15 | };
16 |
17 | struct MappedModule
18 | {
19 | std::string module_name;
20 | uint64_t module_base;
21 | };
22 |
23 | using vec_mapped_modules = std::vector;
24 | using vec_modules = std::vector;
25 |
26 | class Process
27 | {
28 | public:
29 | Process() : m_pid(0), m_process_name(""), m_is_attached(false) { }
30 | public:
31 | bool Attach(uint32_t pid);
32 | bool Attach(std::string process_name);
33 | bool IsAttached();
34 | void Deattach();
35 | bool ReadMemory(uint64_t address, void* buffer, size_t size);
36 | bool WriteMemory(uint64_t address, void* buffer, size_t size);
37 | uint64_t AllocateMemory(size_t size, uint32_t protect);
38 | bool FreeMemory(uint64_t address);
39 | bool ChangeMemoryProtection(uint64_t address, size_t size, uint32_t new_protection, uint32_t* old_protection);
40 | uint64_t GetImageBase();
41 | vec_modules GetLoadedModules();
42 | uint64_t GetModuleExport(uint64_t module_base, const std::string& function_name);
43 | uint64_t GetModuleBase(const std::string& module_name);
44 | uint64_t GetIATAddress(uint64_t module_base, const std::string& import_module_name, const std::string& import_name);
45 | uint64_t MapModule(const std::string& module_path);
46 | private:
47 | void RelocateImageByDelta(portable_executable::vec_relocs relocs, const uint64_t delta);
48 | bool ResolveImports(portable_executable::vec_imports imports);
49 | bool CallDllMain(uint64_t module_base, uint64_t entry_point_address);
50 | private:
51 | uint32_t m_pid;
52 | std::string m_process_name;
53 | bool m_is_attached;
54 | vec_mapped_modules m_mapped_modules;
55 | };
--------------------------------------------------------------------------------
/client/client/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.hpp"
2 |
3 | bool utils::ReadFileToMemory(const std::string& file_path, std::vector* out_buffer)
4 | {
5 | std::ifstream file_ifstream(file_path, std::ios::binary);
6 |
7 | if (!file_ifstream)
8 | return false;
9 |
10 | out_buffer->assign((std::istreambuf_iterator(file_ifstream)), std::istreambuf_iterator());
11 | file_ifstream.close();
12 |
13 | return true;
14 | }
15 |
16 | uint32_t utils::GetProcessIdByName(const std::string &process_name)
17 | {
18 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
19 |
20 | if (snapshot == INVALID_HANDLE_VALUE)
21 | return 0;
22 |
23 | PROCESSENTRY32 processEntry;
24 | processEntry.dwSize = sizeof(PROCESSENTRY32);
25 |
26 | if (!Process32First(snapshot, &processEntry))
27 | {
28 | CloseHandle(snapshot);
29 | return 0;
30 | }
31 |
32 | do
33 | {
34 | if (!process_name.compare(processEntry.szExeFile))
35 | {
36 | CloseHandle(snapshot);
37 | return processEntry.th32ProcessID;
38 | }
39 | } while (Process32Next(snapshot, &processEntry));
40 |
41 | CloseHandle(snapshot);
42 | return 0;
43 | }
44 |
45 | std::string utils::GetProcessNameById(uint32_t pid)
46 | {
47 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
48 |
49 | if (snapshot == INVALID_HANDLE_VALUE)
50 | return "";
51 |
52 | PROCESSENTRY32 processEntry;
53 | processEntry.dwSize = sizeof(PROCESSENTRY32);
54 |
55 | if (!Process32First(snapshot, &processEntry))
56 | {
57 | CloseHandle(snapshot);
58 | return 0;
59 | }
60 |
61 | do
62 | {
63 | if (processEntry.th32ProcessID == pid)
64 | {
65 | CloseHandle(snapshot);
66 | return processEntry.szExeFile;
67 | }
68 | } while (Process32Next(snapshot, &processEntry));
69 |
70 | CloseHandle(snapshot);
71 | return "";
72 | }
73 |
74 | bool utils::ProcessExists(uint32_t pid)
75 | {
76 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
77 |
78 | if (snapshot == INVALID_HANDLE_VALUE)
79 | {
80 | return false;
81 | }
82 |
83 | PROCESSENTRY32 process_entry;
84 | process_entry.dwSize = sizeof(PROCESSENTRY32);
85 |
86 | if (!Process32First(snapshot, &process_entry))
87 | {
88 | CloseHandle(snapshot);
89 | return false;
90 | }
91 |
92 | do
93 | {
94 | if (process_entry.th32ProcessID == pid)
95 | {
96 | return true;
97 | }
98 | } while (Process32Next(snapshot, &process_entry));
99 |
100 | CloseHandle(snapshot);
101 | return false;
102 | }
103 |
104 | bool utils::ProcessExists(const std::string& process_name)
105 | {
106 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
107 |
108 | if (snapshot == INVALID_HANDLE_VALUE)
109 | {
110 | return false;
111 | }
112 |
113 | PROCESSENTRY32 process_entry;
114 | process_entry.dwSize = sizeof(PROCESSENTRY32);
115 |
116 | if (!Process32First(snapshot, &process_entry))
117 | {
118 | CloseHandle(snapshot);
119 | return false;
120 | }
121 |
122 | do
123 | {
124 | if (!process_name.compare(process_entry.szExeFile))
125 | {
126 | return true;
127 | }
128 | } while (Process32Next(snapshot, &process_entry));
129 |
130 | CloseHandle(snapshot);
131 | return false;
132 | }
133 |
134 | uint64_t utils::GetKernelModuleAddress(const std::string& module_name)
135 | {
136 | void* buffer = nullptr;
137 | DWORD buffer_size = 0;
138 |
139 | NTSTATUS status = NtQuerySystemInformation(static_cast(nt::SystemModuleInformation), buffer, buffer_size, &buffer_size);
140 |
141 | while (status == nt::STATUS_INFO_LENGTH_MISMATCH)
142 | {
143 | VirtualFree(buffer, 0, MEM_RELEASE);
144 |
145 | buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
146 | status = NtQuerySystemInformation(static_cast(nt::SystemModuleInformation), buffer, buffer_size, &buffer_size);
147 | }
148 |
149 | if (!NT_SUCCESS(status))
150 | {
151 | VirtualFree(buffer, 0, MEM_RELEASE);
152 | return 0;
153 | }
154 |
155 | const auto modules = static_cast(buffer);
156 |
157 | for (auto i = 0u; i < modules->NumberOfModules; ++i)
158 | {
159 | const std::string current_module_name = std::string(reinterpret_cast(modules->Modules[i].FullPathName) + modules->Modules[i].OffsetToFileName);
160 |
161 | if (!_stricmp(current_module_name.c_str(), module_name.c_str()))
162 | {
163 | const uint64_t result = reinterpret_cast(modules->Modules[i].ImageBase);
164 |
165 | VirtualFree(buffer, 0, MEM_RELEASE);
166 | return result;
167 | }
168 | }
169 |
170 | VirtualFree(buffer, 0, MEM_RELEASE);
171 | return 0;
172 | }
173 |
174 | DWORD utils::GetThreadIdFromProcessId(uint32_t process_id)
175 | {
176 | HWND current_window = NULL;
177 |
178 | do
179 | {
180 | current_window = FindWindowEx(NULL, current_window, NULL, NULL);
181 |
182 | DWORD current_pid = 0;
183 | uint32_t thread_id = GetWindowThreadProcessId(current_window, ¤t_pid);
184 |
185 | if (current_pid == process_id)
186 | return thread_id;
187 |
188 | } while (current_window != NULL);
189 |
190 | return 0;
191 | }
192 |
--------------------------------------------------------------------------------
/client/client/utils.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "nt.hpp"
10 |
11 | namespace utils
12 | {
13 | bool ReadFileToMemory(const std::string& file_path, std::vector* out_buffer);
14 | uint32_t GetProcessIdByName(const std::string& process_name);
15 | std::string GetProcessNameById(uint32_t pid);
16 | bool ProcessExists(uint32_t pid);
17 | bool ProcessExists(const std::string& process_name);
18 | uint64_t GetKernelModuleAddress(const std::string& module_name);
19 | DWORD GetThreadIdFromProcessId(uint32_t process_id);
20 | }
--------------------------------------------------------------------------------