diff --git a/example/dllmain.cpp b/example/dllmain.cpp index fd1a3cc..d27ee11 100644 --- a/example/dllmain.cpp +++ b/example/dllmain.cpp @@ -3,5 +3,7 @@ void main(pimage_data this_image) { MessageBoxA(NULL, "Hello World!", "INFO", NULL); + + // only use this inside of main... ZERO_DLL(this_image->image_base, this_image->image_size); } \ No newline at end of file diff --git a/injector/injector.vcxproj b/injector/injector.vcxproj new file mode 100644 index 0000000..8c71839 --- /dev/null +++ b/injector/injector.vcxproj @@ -0,0 +1,151 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {50e65491-59af-43f8-a045-e66ae0676298} + injector + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/injector/injector.vcxproj.filters b/injector/injector.vcxproj.filters new file mode 100644 index 0000000..707cf08 --- /dev/null +++ b/injector/injector.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/injector/injector.vcxproj.user b/injector/injector.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/injector/injector.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/injector/main.cpp b/injector/main.cpp new file mode 100644 index 0000000..54f1627 --- /dev/null +++ b/injector/main.cpp @@ -0,0 +1,12 @@ +#include +#include "nozzle.hpp" + +int main() +{ + nozzle::injector injector("example.dll", nozzle::util::get_pid(L"notepad.exe")); + const auto module_base = injector.inject(); + const auto thread_handle = injector.call_entry(); + + std::printf("[+] module base => 0x%p, thread handle => 0x%x\n", module_base, thread_handle); + std::getchar(); +} \ No newline at end of file diff --git a/nozzle.hpp b/injector/nozzle.hpp similarity index 70% rename from nozzle.hpp rename to injector/nozzle.hpp index 37bddbd..0f5c688 100644 --- a/nozzle.hpp +++ b/injector/nozzle.hpp @@ -34,117 +34,109 @@ #include #include #include - #pragma comment(lib, "Dbghelp.lib") -#define FIND_NT_HEADER(x) reinterpret_cast( uint64_t(x) + reinterpret_cast(x)->e_lfanew ) -#define RET_CHK(x)\ -if (!x)\ -{\ -LOG_LAST_ERROR();\ -return false;\ -}\ - -// -// coded by paracord. -// see: https://github.com/haram/splendid_implanter/blob/master/splendid_implanter/win_utils.hpp -// -namespace util + +namespace nozzle { - using uq_handle = std::unique_ptr; - inline void open_binary_file(const std::string& file, std::vector& data) + // + // coded by paracord. + // see: https://github.com/haram/splendid_implanter/blob/master/splendid_implanter/win_utils.hpp + // + namespace util { - std::ifstream fstr(file, std::ios::binary); - fstr.unsetf(std::ios::skipws); - fstr.seekg(0, std::ios::end); - - const auto file_size = fstr.tellg(); + using uq_handle = std::unique_ptr; + inline void open_binary_file(const std::string& file, std::vector& data) + { + std::ifstream fstr(file, std::ios::binary); + fstr.unsetf(std::ios::skipws); + fstr.seekg(0, std::ios::end); - fstr.seekg(NULL, std::ios::beg); - data.reserve(static_cast(file_size)); - data.insert(data.begin(), std::istream_iterator(fstr), std::istream_iterator()); - } + const auto file_size = fstr.tellg(); - inline uint32_t get_process_id(const std::wstring_view process_name) - { - // open a system snapshot of all loaded processes - uq_handle snap_shot{ CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0), &CloseHandle }; - - if (snap_shot.get() == INVALID_HANDLE_VALUE) - return NULL; + fstr.seekg(NULL, std::ios::beg); + data.reserve(static_cast(file_size)); + data.insert(data.begin(), std::istream_iterator(fstr), std::istream_iterator()); + } - PROCESSENTRY32W process_entry{ sizeof(PROCESSENTRY32W) }; + inline uint32_t get_pid(const std::wstring_view process_name) + { + // open a system snapshot of all loaded processes + uq_handle snap_shot{ CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0), &CloseHandle }; - // enumerate through processes - for (Process32FirstW(snap_shot.get(), &process_entry); Process32NextW(snap_shot.get(), &process_entry); ) - if (std::wcscmp(process_name.data(), process_entry.szExeFile) == NULL) - return process_entry.th32ProcessID; + if (snap_shot.get() == INVALID_HANDLE_VALUE) + return NULL; - return NULL; - } + PROCESSENTRY32W process_entry{ sizeof(PROCESSENTRY32W) }; - inline std::pair get_module_data(HANDLE process_handle, const std::wstring_view module_name) - { - auto loaded_modules = std::make_unique(64); - DWORD loaded_module_sz = 0; + // enumerate through processes + for (Process32FirstW(snap_shot.get(), &process_entry); Process32NextW(snap_shot.get(), &process_entry); ) + if (std::wcscmp(process_name.data(), process_entry.szExeFile) == NULL) + return process_entry.th32ProcessID; - // enumerate all modules by handle, using size of 512 since the required size is in bytes, and an HMODULE is 8 bytes large. - if (!EnumProcessModules(process_handle, loaded_modules.get(), 512, &loaded_module_sz)) - return {}; + return NULL; + } - for (auto i = 0u; i < loaded_module_sz / 8u; i++) + inline std::pair get_module_data(HANDLE process_handle, const std::wstring_view module_name) { - wchar_t file_name[MAX_PATH] = L""; + auto loaded_modules = std::make_unique(64); + DWORD loaded_module_sz = 0; - // get the full working path for the current module - if (!GetModuleFileNameExW(process_handle, loaded_modules.get()[i], file_name, _countof(file_name))) - continue; + // enumerate all modules by handle, using size of 512 since the required size is in bytes, and an HMODULE is 8 bytes large. + if (!EnumProcessModules(process_handle, loaded_modules.get(), 512, &loaded_module_sz)) + return {}; - // module name returned will be a full path, check only for file name sub string. - if (std::wcsstr(file_name, module_name.data()) != nullptr) - return { loaded_modules.get()[i], file_name }; - } + for (auto i = 0u; i < loaded_module_sz / 8u; i++) + { + wchar_t file_name[MAX_PATH] = L""; - return {}; - } + // get the full working path for the current module + if (!GetModuleFileNameExW(process_handle, loaded_modules.get()[i], file_name, _countof(file_name))) + continue; - inline std::vector get_file_data(const HANDLE file_handle, const std::wstring_view file_path) - { - const auto file_size = std::filesystem::file_size(file_path); - std::vector file_bytes{}; - file_bytes.resize(file_size); + // module name returned will be a full path, check only for file name sub string. + if (std::wcsstr(file_name, module_name.data()) != nullptr) + return { loaded_modules.get()[i], file_name }; + } - DWORD bytes_read = 0; - if (!ReadFile(file_handle, file_bytes.data(), static_cast(file_size), &bytes_read, nullptr)) return {}; + } - return file_bytes; - } + inline std::vector get_file_data(const HANDLE file_handle, const std::wstring_view file_path) + { + const auto file_size = std::filesystem::file_size(file_path); + std::vector file_bytes{}; + file_bytes.resize(file_size); - inline bool enable_privilege(const std::wstring_view privilege_name) - { - HANDLE token_handle = nullptr; - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle)) - return false; + DWORD bytes_read = 0; + if (!ReadFile(file_handle, file_bytes.data(), static_cast(file_size), &bytes_read, nullptr)) + return {}; - LUID luid{}; - if (!LookupPrivilegeValueW(nullptr, privilege_name.data(), &luid)) - return false; + return file_bytes; + } + + inline bool enable_privilege(const std::wstring_view privilege_name) + { + HANDLE token_handle = nullptr; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle)) + return false; - TOKEN_PRIVILEGES token_state{}; - token_state.PrivilegeCount = 1; - token_state.Privileges[0].Luid = luid; - token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + LUID luid{}; + if (!LookupPrivilegeValueW(nullptr, privilege_name.data(), &luid)) + return false; - if (!AdjustTokenPrivileges(token_handle, FALSE, &token_state, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) - return false; + TOKEN_PRIVILEGES token_state{}; + token_state.PrivilegeCount = 1; + token_state.Privileges[0].Luid = luid; + token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - CloseHandle(token_handle); - return true; + if (!AdjustTokenPrivileges(token_handle, FALSE, &token_state, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) + return false; + + CloseHandle(token_handle); + return true; + } } -} -namespace nozzle -{ // // class programmed by wlan // link: https://github.com/not-wlan/drvmap/blob/master/drvmap/drv_image.hpp @@ -223,47 +215,43 @@ namespace nozzle bool pe_image::process_relocation(uintptr_t image_base_delta, uint16_t data, uint8_t* relocation_base) { #define IMR_RELOFFSET(x) (x & 0xFFF) - switch (data >> 12 & 0xF) { - case IMAGE_REL_BASED_HIGH: - { - const auto raw_address = reinterpret_cast(relocation_base + IMR_RELOFFSET(data)); - *raw_address += static_cast(HIWORD(image_base_delta)); - break; - } - case IMAGE_REL_BASED_LOW: - { - const auto raw_address = reinterpret_cast(relocation_base + IMR_RELOFFSET(data)); - *raw_address += static_cast(LOWORD(image_base_delta)); - break; - } - case IMAGE_REL_BASED_HIGHLOW: - { - const auto raw_address = reinterpret_cast(relocation_base + IMR_RELOFFSET(data)); - *raw_address += static_cast(image_base_delta); - break; - } - case IMAGE_REL_BASED_DIR64: - { - auto UNALIGNED raw_address = reinterpret_cast(relocation_base + IMR_RELOFFSET(data)); - *raw_address += image_base_delta; - break; - } - case IMAGE_REL_BASED_ABSOLUTE: // No action required - case IMAGE_REL_BASED_HIGHADJ: // no action required - { - break; - } - default: - { - throw std::runtime_error("gay relocation!"); - return false; - } - + case IMAGE_REL_BASED_HIGH: + { + const auto raw_address = reinterpret_cast(relocation_base + IMR_RELOFFSET(data)); + *raw_address += static_cast(HIWORD(image_base_delta)); + break; + } + case IMAGE_REL_BASED_LOW: + { + const auto raw_address = reinterpret_cast(relocation_base + IMR_RELOFFSET(data)); + *raw_address += static_cast(LOWORD(image_base_delta)); + break; + } + case IMAGE_REL_BASED_HIGHLOW: + { + const auto raw_address = reinterpret_cast(relocation_base + IMR_RELOFFSET(data)); + *raw_address += static_cast(image_base_delta); + break; + } + case IMAGE_REL_BASED_DIR64: + { + auto UNALIGNED raw_address = reinterpret_cast(relocation_base + IMR_RELOFFSET(data)); + *raw_address += image_base_delta; + break; + } + case IMAGE_REL_BASED_ABSOLUTE: // No action required + case IMAGE_REL_BASED_HIGHADJ: // no action required + { + break; + } + default: + { + return false; + } } #undef IMR_RELOFFSET - return true; } @@ -345,11 +333,9 @@ namespace nozzle class injector { public: - injector() - {}; injector(void* pe_image, std::size_t size, unsigned pid); injector(std::vector image_buffer, unsigned pid); - injector(char* path, unsigned pid); + injector(const char* path, unsigned pid); void* inject(); HANDLE call_entry(); @@ -394,7 +380,7 @@ namespace nozzle target_handle(::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid)) {} - injector::injector(char* path, unsigned pid) + injector::injector(const char* path, unsigned pid) : target_pid(pid), target_handle(::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid)) @@ -420,13 +406,6 @@ namespace nozzle // static const auto _get_module = [](std::string_view module_name) -> std::uintptr_t { - assert( - !stricmp(module_name, "kernel32.dll") || - !stricmp(module_name, "user32.dll") || - !stricmp(module_name, "ntdll.dll"), - "import from dll %s is invalid, only globally mapped dlls can be resolved!", - module_name - ); return reinterpret_cast(LoadLibraryA(module_name.data())); }; @@ -504,7 +483,7 @@ namespace nozzle void injector::set_target(std::wstring proc_name) { - target_pid = util::get_process_id(proc_name); + target_pid = util::get_pid(proc_name); } void* injector::get_pe_image() const