aboutsummaryrefslogtreecommitdiff
path: root/client/src/injection
diff options
context:
space:
mode:
authorauth12 <[email protected]>2020-07-24 10:56:14 -0700
committerauth12 <[email protected]>2020-07-24 10:56:14 -0700
commite487ffe1671ba807528d4039ef66f8f8f7eeb853 (patch)
treec65cc4dd529f8e37f9cca81d38c749dece13a574 /client/src/injection
parentInjection and server changes. (diff)
downloadloader-e487ffe1671ba807528d4039ef66f8f8f7eeb853.tar.xz
loader-e487ffe1671ba807528d4039ef66f8f8f7eeb853.zip
Injection process changes and server improvements.
Diffstat (limited to 'client/src/injection')
-rw-r--r--client/src/injection/mapper.cpp46
-rw-r--r--client/src/injection/pe.h55
-rw-r--r--client/src/injection/process.cpp99
-rw-r--r--client/src/injection/process.h9
4 files changed, 167 insertions, 42 deletions
diff --git a/client/src/injection/mapper.cpp b/client/src/injection/mapper.cpp
index 570155e..68f0f6e 100644
--- a/client/src/injection/mapper.cpp
+++ b/client/src/injection/mapper.cpp
@@ -9,23 +9,24 @@ void mmap::thread(tcp::client& client) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
- util::fetch_processes();
+ std::vector<util::process> process_list;
+ util::fetch_processes(process_list);
- auto needle = std::find_if(util::process_list.begin(), util::process_list.end(), [&](util::process& proc) {
- return strcmp(proc.name().c_str(), "notepad++.exe") == 0;
+ auto needle = std::find_if(process_list.begin(), process_list.end(), [&](util::process& proc) {
+ return proc.name() == "notepad++.exe";
});
- while (needle == util::process_list.end()) {
- std::this_thread::sleep_for(std::chrono::seconds(5));
+ while (needle == process_list.end()) {
+ std::this_thread::sleep_for(std::chrono::seconds(2));
- util::fetch_processes();
-
- io::logger->info("size {}", util::process_list.size());
+ util::fetch_processes(process_list);
+
+ io::logger->info("size {}", process_list.size());
io::logger->info("waiting for process..");
- needle = std::find_if(util::process_list.begin(), util::process_list.end(), [&](util::process& proc) {
- return strcmp(proc.name().c_str(), "notepad++.exe") == 0;
+ needle = std::find_if(process_list.begin(), process_list.end(), [&](util::process& proc) {
+ return proc.name() == "notepad++.exe";
});
}
@@ -44,27 +45,25 @@ void mmap::thread(tcp::client& client) {
return;
}
+ client.mapper_data.image_size = 0;
+
io::logger->info("image base : {:x}", image);
auto imports = nlohmann::json::parse(client.mapper_data.imports);
nlohmann::json final_imports;
for (auto& [key, value] : imports.items()) {
- auto mod = key;
- std::transform(mod.begin(), mod.end(), mod.begin(), ::tolower);
- auto base = needle->load(mod);
+ auto base = needle->load(key);
if (!base) {
- io::logger->error("failed to load {}", mod);
+ io::logger->error("failed to load {}", key);
continue;
}
for (auto& i : value) {
auto name = i.get<std::string>();
- auto func = needle->module_export(mod, name);
-
- final_imports[name] = func;
+ final_imports[name] = needle->module_export(base, name);
}
}
@@ -76,6 +75,11 @@ void mmap::thread(tcp::client& client) {
auto proc_imports = final_imports.dump();
client.stream(proc_imports);
+ proc_imports.clear();
+ final_imports.clear();
+ imports.clear();
+ client.mapper_data.imports.clear();
+
io::logger->info("please wait...");
while (client.mapper_data.image.empty()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
@@ -86,6 +90,8 @@ void mmap::thread(tcp::client& client) {
return;
}
+ client.mapper_data.image.clear();
+
auto entry = image + client.mapper_data.entry;
io::logger->info("entry : {:x}", entry);
@@ -96,6 +102,12 @@ void mmap::thread(tcp::client& client) {
*reinterpret_cast<uint32_t*>(&shellcode[8]) = image;
*reinterpret_cast<uint32_t*>(&shellcode[13]) = entry;
+ /*static std::vector<uint8_t> shellcode = { 0x48, 0x83, 0xEC, 0x28, 0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC2, 0x01,
+ 0x00, 0x00, 0x00, 0x4D, 0x31, 0xC0, 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x48, 0x83, 0xC4, 0x28, 0xC3 };
+
+ *reinterpret_cast<uint64_t*>(&shellcode[6]) = image;
+ *reinterpret_cast<uint32_t*>(&shellcode[26]) = entry;*/
+
auto code = needle->allocate(shellcode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!needle->write(code, shellcode.data(), shellcode.size())) {
io::logger->error("failed to write shellcode.");
diff --git a/client/src/injection/pe.h b/client/src/injection/pe.h
new file mode 100644
index 0000000..b5f9faa
--- /dev/null
+++ b/client/src/injection/pe.h
@@ -0,0 +1,55 @@
+#pragma once
+
+namespace pe {
+
+ class virtual_image {
+ std::unordered_map<std::string, uintptr_t> m_exports;
+
+ IMAGE_NT_HEADERS64* m_nt;
+ uintptr_t m_base;
+ bool m_valid;
+
+ public:
+ virtual_image() : m_nt{ nullptr }, m_valid{ false }, m_base{ 0 } {};
+ virtual_image(const uintptr_t base) : m_valid{ false }, m_base{ base }, m_nt{ nullptr } {
+ auto dos = reinterpret_cast<IMAGE_DOS_HEADER*>(base);
+ if (!dos || dos->e_magic != IMAGE_DOS_SIGNATURE) {
+ return;
+ }
+
+ m_nt = reinterpret_cast<IMAGE_NT_HEADERS64*>(base + dos->e_lfanew);
+ if (m_nt->Signature != IMAGE_NT_SIGNATURE) {
+ return;
+ }
+
+ m_valid = true;
+ }
+
+ void parse_exports() {
+ auto dir = m_nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ auto exp =
+ reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(m_base + dir.VirtualAddress);
+
+ if (exp->NumberOfFunctions == 0) return;
+
+ auto names = reinterpret_cast<uint32_t*>(m_base + exp->AddressOfNames);
+ auto funcs = reinterpret_cast<uint32_t*>(m_base + exp->AddressOfFunctions);
+ auto ords =
+ reinterpret_cast<uint16_t*>(m_base + exp->AddressOfNameOrdinals);
+
+ if (!names || !funcs || !ords) return;
+
+ for (size_t i{}; i < exp->NumberOfFunctions; i++) {
+ uintptr_t va = m_base + funcs[ords[i]];
+ std::string name = reinterpret_cast<const char*>(m_base + names[i]);
+
+ m_exports[name] = va;
+ }
+ }
+
+ auto& exports() { return m_exports; }
+
+ operator bool() { return m_valid; }
+ };
+
+}; // namespace pe \ No newline at end of file
diff --git a/client/src/injection/process.cpp b/client/src/injection/process.cpp
index 6552d3c..06e5ea8 100644
--- a/client/src/injection/process.cpp
+++ b/client/src/injection/process.cpp
@@ -35,6 +35,7 @@ bool util::process::open() {
io::logger->info("opened handle to {}.", m_name);
+
return true;
}
@@ -81,14 +82,14 @@ bool util::process::free(const uintptr_t addr, size_t size) {
bool util::process::thread(const uintptr_t start) {
static auto nt_create = g_syscalls.get<native::NtCreateThreadEx>("NtCreateThreadEx");
static auto nt_wait = g_syscalls.get<native::NtWaitForSingleObject>("NtWaitForSingleObject");
-
+
HANDLE out;
auto status = nt_create(&out, THREAD_ALL_ACCESS, nullptr, m_handle, reinterpret_cast<LPTHREAD_START_ROUTINE>(start), 0, 0x4, 0, 0, 0, 0);
if (!NT_SUCCESS(status)) {
io::logger->error("failed to create thread in {}, status {:#X}.", m_name, (status & 0xFFFFFFFF));
return false;
}
-
+
status = nt_wait(out, false, nullptr);
if (!NT_SUCCESS(status)) {
io::logger->error("failed to wait for handle {}, status {:#X}.", out, (status & 0xFFFFFFFF));
@@ -110,7 +111,7 @@ uintptr_t util::process::load(const std::string_view mod) {
return base;
}
- static auto loaddll = module_export("ntdll.dll", "LdrLoadDll");
+ static auto loaddll = module_export(m_modules["ntdll.dll"], "LdrLoadDll");
auto name = allocate(0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
@@ -169,7 +170,62 @@ uintptr_t util::process::load(const std::string_view mod) {
return m_modules[mod.data()];
}
+uintptr_t util::process::map(const std::string_view mod) {
+ auto base = m_modules[mod.data()];
+ if (base) {
+ return base;
+ }
+
+ std::string path{ "C:\\Windows\\SysWOW64\\" };
+ path.append(mod.data());
+
+ std::vector<char> buf;
+ if (!io::read_file(path, buf)) {
+ return {};
+ }
+
+ std::vector<char> final_image;
+
+ auto dos = reinterpret_cast<IMAGE_DOS_HEADER*>(buf.data());
+ auto nt = reinterpret_cast<IMAGE_NT_HEADERS32*>(buf.data() + dos->e_lfanew);
+
+
+ final_image.resize(nt->OptionalHeader.SizeOfImage);
+
+ // headers
+ std::memcpy(&final_image[0], &buf[0], nt->OptionalHeader.SizeOfHeaders);
+
+ // copy image
+ auto secs = IMAGE_FIRST_SECTION(nt);
+ for (int i = 0; i < nt->FileHeader.NumberOfSections; i++) {
+ auto sec = secs[i];
+ std::memcpy(&final_image[sec.VirtualAddress], &buf[sec.PointerToRawData], sec.SizeOfRawData);
+ }
+
+ auto image = allocate(final_image.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if (!image) {
+ io::logger->error("failed to alloc buffer for {}.", path);
+ return {};
+ }
+
+ io::logger->info("{:x}->{}", image, mod);
+
+ // fix relocations
+
+
+ if (!write(image, final_image.data(), final_image.size())) {
+ io::logger->error("failed to write final image.");
+ return {};
+ }
+
+ m_modules[mod.data()] = image;
+
+ return image;
+}
+
bool util::process::enum_modules() {
+ m_modules.clear();
+
static auto peb_addr = peb();
uint32_t ldr;
@@ -238,16 +294,15 @@ uintptr_t util::process::allocate(size_t size, uint32_t type, uint32_t protectio
return uintptr_t(alloc);
}
-uintptr_t util::process::module_export(const std::string_view name, const std::string_view func) {
- auto base = m_modules[name.data()];
+uintptr_t util::process::module_export(const uintptr_t base, const std::string_view func) {
if (!base) {
- io::logger->error("module {} isnt loaded.", name);
+ io::logger->error("module {} isnt loaded.", m_name);
return {};
}
IMAGE_DOS_HEADER dos{};
if (!read(base, &dos, sizeof(dos))) {
- io::logger->info("failed to read dos header for {}", name);
+ io::logger->info("failed to read dos header for {}", m_name);
return {};
}
@@ -256,7 +311,7 @@ uintptr_t util::process::module_export(const std::string_view name, const std::s
IMAGE_NT_HEADERS32 nt{};
if (!read(base + dos.e_lfanew, &nt, sizeof(nt))) {
- io::logger->info("failed to read nt header for {}", name);
+ io::logger->info("failed to read nt header for {}", m_name);
return {};
}
@@ -273,7 +328,7 @@ uintptr_t util::process::module_export(const std::string_view name, const std::s
auto exp_dir_end = exp_dir_start + exp_dir_size;
if (!read(exp_dir_start, &exp_dir, sizeof(exp_dir))) {
- io::logger->info("failed to read export dir for {}", name);
+ io::logger->info("failed to read export dir for {}", m_name);
return {};
}
@@ -322,7 +377,7 @@ uintptr_t util::process::module_export(const std::string_view name, const std::s
std::string fwd_func_name = name_str.substr(delim + 1);
- return module_export(fwd_mod_name, fwd_func_name);
+ return module_export(load(fwd_mod_name), fwd_func_name);
}
return proc_addr;
@@ -341,14 +396,11 @@ bool util::process::close() {
return ret;
}
-std::vector<util::process> util::process_list;
-
-bool util::fetch_processes() {
- process_list.clear();
-
+bool util::fetch_processes(std::vector<process> &out) {
static auto info = g_syscalls.get<native::NtQuerySystemInformation>("NtQuerySystemInformation");
- std::vector<char> buf(1);
+ std::vector<uint8_t> buf(1);
+
ULONG size_needed = 0;
NTSTATUS status;
while ((status = info(SystemProcessInformation, buf.data(), buf.size(), &size_needed)) == STATUS_INFO_LENGTH_MISMATCH) {
@@ -360,12 +412,19 @@ bool util::fetch_processes() {
return false;
}
+ out.clear();
auto pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(buf.data());
- for (auto info_casted = reinterpret_cast<uintptr_t>(pi); pi->NextEntryOffset;
- pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(info_casted + pi->NextEntryOffset), info_casted = reinterpret_cast<uintptr_t>(pi)) {
-
- process_list.emplace_back(util::process(pi));
+ while (pi->NextEntryOffset) {
+ out.emplace_back(util::process(pi));
+ pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(uintptr_t(pi) + pi->NextEntryOffset);
}
+ /*std::set_difference(new_list.begin(), new_list.end(), process_list.begin(), process_list.end(), std::inserter(diff, diff.begin()), [&](util::process &l, util::process &r) {
+ return l.id() != r.id();
+ });
+
+ for (auto& p : diff) {
+ io::logger->info("{} is new", p.name());
+ }*/
return true;
}
diff --git a/client/src/injection/process.h b/client/src/injection/process.h
index ddbadf5..8e2c4f1 100644
--- a/client/src/injection/process.h
+++ b/client/src/injection/process.h
@@ -8,7 +8,7 @@ namespace util {
HANDLE m_handle;
public:
- process() : m_handle{ INVALID_HANDLE_VALUE } {};
+ process() : m_handle{ INVALID_HANDLE_VALUE }, m_id{ -1 } {};
process(const SYSTEM_PROCESS_INFORMATION* info);
~process();
@@ -21,8 +21,9 @@ namespace util {
uintptr_t peb();
uintptr_t load(const std::string_view mod);
+ uintptr_t map(const std::string_view path);
uintptr_t allocate(size_t size, uint32_t type, uint32_t protection);
- uintptr_t module_export(const std::string_view name, const std::string_view func);
+ uintptr_t module_export(const uintptr_t base, const std::string_view func);
bool close();
@@ -33,7 +34,5 @@ namespace util {
auto& handle() { return m_handle; }
};
- extern std::vector<process> process_list;
-
- bool fetch_processes();
+ bool fetch_processes(std::vector<process> &out);
};