diff --git a/Dependencies.md b/Dependencies.md index 781849e..c59478e 100644 --- a/Dependencies.md +++ b/Dependencies.md @@ -17,6 +17,7 @@ - [clip v1.11](https://github.com/dacap/clip) - [PrivateDesktop v0.0.1](https://github.com/yuanyuanxiang/SimplePlugins) - [FileUpload v0.0.1](https://github.com/yuanyuanxiang/SimplePlugins) +- [libpeconv](https://github.com/hasherezade/libpeconv) (c7d1e48) ## *Note* diff --git a/common/commands.h b/common/commands.h index 567b697..04bccd7 100644 --- a/common/commands.h +++ b/common/commands.h @@ -577,7 +577,8 @@ enum ProtocolEncType { enum ClientCompressType { CLIENT_COMPRESS_NONE = 0, CLIENT_COMPRESS_UPX = 1, - CLIENT_COMPRESS_SC = 2, + CLIENT_COMPRESS_SC_AES = 2, + CLIENT_PE_TO_SEHLLCODE = 3, }; #pragma pack(push, 4) diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 36b4dc5..9a87297 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 2e7e377..5192e45 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -503,7 +503,8 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_COMMAND(ID_OBFS_SHELLCODE_BIN, &CMy2015RemoteDlg::OnObfsShellcodeBin) ON_COMMAND(ID_SHELLCODE_AES_BIN, &CMy2015RemoteDlg::OnShellcodeAesBin) ON_COMMAND(ID_SHELLCODE_TEST_AES_BIN, &CMy2015RemoteDlg::OnShellcodeTestAesBin) -END_MESSAGE_MAP() + ON_COMMAND(ID_TOOL_RELOAD_PLUGINS, &CMy2015RemoteDlg::OnToolReloadPlugins) + END_MESSAGE_MAP() // CMy2015RemoteDlg 消息处理程序 @@ -1119,6 +1120,9 @@ BOOL CMy2015RemoteDlg::OnInitDialog() return FALSE; } THIS_CFG.SetStr("settings", "MainWnd", std::to_string((uint64_t)GetSafeHwnd())); + THIS_CFG.SetStr("settings", "SN", getDeviceID()); + THIS_CFG.SetStr("settings", "PwdHash", GetPwdHash()); + THIS_CFG.SetStr("settings", "MasterHash", GetMasterHash()); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } @@ -3739,3 +3743,15 @@ LRESULT CMy2015RemoteDlg::OnSessionActivatedMsg(WPARAM wParam, LPARAM lParam) return 0; } + + +void CMy2015RemoteDlg::OnToolReloadPlugins() +{ + if (IDYES!=MessageBoxA("请将64位的DLL放于主控程序的 'Plugins' 目录,是否继续?" + "\n执行未经测试的代码可能造成程序崩溃。", "提示", MB_ICONINFORMATION | MB_YESNO)) + return; + char path[_MAX_PATH]; + GetModuleFileNameA(NULL, path, _MAX_PATH); + GET_FILEPATH(path, "Plugins"); + m_DllList = ReadAllDllFilesWindows(path); +} diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 98655a4..ed209aa 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -346,4 +346,5 @@ public: afx_msg void OnObfsShellcodeBin(); afx_msg void OnShellcodeAesBin(); afx_msg void OnShellcodeTestAesBin(); + afx_msg void OnToolReloadPlugins(); }; diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 2e69a4a..e078b0c 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -79,7 +79,7 @@ true - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(IncludePath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(ProjectDir)libpeconv;$(IncludePath) $(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(SolutionDir);$(SolutionDir)..\SimpleRemoter;$(LibraryPath) @@ -90,7 +90,7 @@ false $(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(SolutionDir);$(SolutionDir)..\SimpleRemoter;$(LibraryPath) - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(IncludePath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(ProjectDir)libpeconv;$(IncludePath) @@ -250,6 +250,8 @@ + + @@ -365,6 +367,7 @@ NotUsing NotUsing + diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters index 41f9a4d..c9ddb6e 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters @@ -55,6 +55,7 @@ + @@ -203,6 +204,8 @@ + + diff --git a/server/2015Remote/BuildDlg.cpp b/server/2015Remote/BuildDlg.cpp index ebfdbd8..ed129c9 100644 --- a/server/2015Remote/BuildDlg.cpp +++ b/server/2015Remote/BuildDlg.cpp @@ -64,6 +64,7 @@ CBuildDlg::CBuildDlg(CWnd* pParent) , m_strPort(_T("")) , m_strFindden(FLAG_FINDEN) , m_sGroupName(_T("default")) + , m_strEncryptIP(_T("")) { } @@ -95,6 +96,7 @@ BEGIN_MESSAGE_MAP(CBuildDlg, CDialog) ON_CBN_SELCHANGE(IDC_COMBO_EXE, &CBuildDlg::OnCbnSelchangeComboExe) ON_COMMAND(ID_HELP_PARAMETERS, &CBuildDlg::OnHelpParameters) ON_COMMAND(ID_HELP_FINDDEN, &CBuildDlg::OnHelpFindden) + ON_COMMAND(ID_MENU_ENCRYPT_IP, &CBuildDlg::OnMenuEncryptIp) END_MESSAGE_MAP() @@ -232,7 +234,8 @@ void CBuildDlg::OnBnClickedOk() SAFE_DELETE_ARRAY(szBuffer); return; } - if (startup != Startup_InjSC) + bool encrypt = m_strEncryptIP == _T(""); + if (encrypt && startup != Startup_InjSC) g_ConnectAddress.Encrypt(); try { // ±ʶ @@ -290,7 +293,7 @@ void CBuildDlg::OnBnClickedOk() run_upx_async(GetParent()->GetSafeHwnd(), upx, strSeverFile.GetString(), true); MessageBox("UPXѹעϢʾ\r\nļλ: " + strSeverFile + tip, "ʾ", MB_ICONINFORMATION); } else { - if (m_ComboCompress.GetCurSel() == CLIENT_COMPRESS_SC) { + if (m_ComboCompress.GetCurSel() == CLIENT_COMPRESS_SC_AES) { DWORD dwSize = 0; LPBYTE data = ReadResource(is64bit ? IDR_SCLOADER_X64 : IDR_SCLOADER_X86, dwSize); if (data) { @@ -323,6 +326,12 @@ void CBuildDlg::OnBnClickedOk() } SAFE_DELETE_ARRAY(data); } + else if (m_ComboCompress.GetCurSel() == CLIENT_PE_TO_SEHLLCODE) { + int pe_2_shellcode(const std::string & in_path, const std::string & out_str); + int ret = pe_2_shellcode(strSeverFile.GetString(), strSeverFile.GetString()); + if (ret)MessageBox(CString("ShellCode ת쳣, 쳣: ") + CString(std::to_string(ret).c_str()), + "ʾ", MB_ICONINFORMATION); + } MessageBox("ɳɹ! ļλ:\r\n" + strSeverFile + tip, "ʾ", MB_ICONINFORMATION); } SAFE_DELETE_ARRAY(szBuffer); @@ -382,7 +391,8 @@ BOOL CBuildDlg::OnInitDialog() m_ComboCompress.InsertString(CLIENT_COMPRESS_NONE, ""); m_ComboCompress.InsertString(CLIENT_COMPRESS_UPX, "UPX"); - m_ComboCompress.InsertString(CLIENT_COMPRESS_SC, "SHELLCODE"); + m_ComboCompress.InsertString(CLIENT_COMPRESS_SC_AES, "ShellCode AES"); + m_ComboCompress.InsertString(CLIENT_PE_TO_SEHLLCODE, "PE->ShellCode"); m_ComboCompress.SetCurSel(CLIENT_COMPRESS_NONE); m_OtherItem.ShowWindow(SW_HIDE); @@ -454,3 +464,17 @@ void CBuildDlg::OnHelpFindden() m_strFindden = dlg.m_str; } } + + +void CBuildDlg::OnMenuEncryptIp() +{ + CInputDialog dlg(this); + dlg.m_str = m_strEncryptIP; + dlg.Init("Զ̵ַ", "ǻ߷:"); + if (dlg.DoModal() == IDOK ) { + if (m_strEncryptIP != "" && m_strEncryptIP != "") { + MessageBoxA("ǻ߷!", "ʾ", MB_ICONINFORMATION); + }else + m_strEncryptIP = dlg.m_str; + } +} diff --git a/server/2015Remote/BuildDlg.h b/server/2015Remote/BuildDlg.h index 89c1118..1f0b9ca 100644 --- a/server/2015Remote/BuildDlg.h +++ b/server/2015Remote/BuildDlg.h @@ -42,4 +42,6 @@ public: afx_msg void OnHelpFindden(); CEdit m_EditGroup; CString m_sGroupName; + CString m_strEncryptIP; + afx_msg void OnMenuEncryptIp(); }; diff --git a/server/2015Remote/ScreenSpyDlg.cpp b/server/2015Remote/ScreenSpyDlg.cpp index 31eb587..04bf36a 100644 --- a/server/2015Remote/ScreenSpyDlg.cpp +++ b/server/2015Remote/ScreenSpyDlg.cpp @@ -201,6 +201,8 @@ BOOL CScreenSpyDlg::OnInitDialog() SetWindowText(strString); m_hFullDC = ::GetDC(m_hWnd); + SetStretchBltMode(m_hFullDC, HALFTONE); + SetBrushOrgEx(m_hFullDC, 0, 0, NULL); m_hFullMemDC = CreateCompatibleDC(m_hFullDC); m_BitmapHandle = CreateDIBSection(m_hFullDC, m_BitmapInfor_Full, DIB_RGB_COLORS, &m_BitmapData_Full, NULL, NULL); //创建应用程序可以直接写入的、与设备无关的位图 diff --git a/server/2015Remote/libpeconv/libpeconv_x64.lib b/server/2015Remote/libpeconv/libpeconv_x64.lib new file mode 100644 index 0000000..5f9c4cf Binary files /dev/null and b/server/2015Remote/libpeconv/libpeconv_x64.lib differ diff --git a/server/2015Remote/libpeconv/libpeconv_x64d.lib b/server/2015Remote/libpeconv/libpeconv_x64d.lib new file mode 100644 index 0000000..e1f5421 Binary files /dev/null and b/server/2015Remote/libpeconv/libpeconv_x64d.lib differ diff --git a/server/2015Remote/libpeconv/peconv.h b/server/2015Remote/libpeconv/peconv.h new file mode 100644 index 0000000..cdee177 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv.h @@ -0,0 +1,32 @@ +/** +* @file +* @brief Master include file, including everything else. +*/ + +#pragma once + +#include "peconv/buffer_util.h" +#include "peconv/util.h" +#include "peconv/pe_hdrs_helper.h" +#include "peconv/pe_mode_detector.h" +#include "peconv/pe_raw_to_virtual.h" +#include "peconv/pe_virtual_to_raw.h" +#include "peconv/relocate.h" +#include "peconv/remote_pe_reader.h" +#include "peconv/imports_loader.h" +#include "peconv/pe_loader.h" +#include "peconv/pe_dumper.h" +#include "peconv/exports_lookup.h" +#include "peconv/function_resolver.h" +#include "peconv/hooks.h" +#include "peconv/exports_mapper.h" +#include "peconv/caves.h" +#include "peconv/fix_imports.h" +#include "peconv/delayed_imports_loader.h" +#include "peconv/resource_parser.h" +#include "peconv/load_config_util.h" +#include "peconv/peb_lookup.h" +#include "peconv/find_base.h" +#include "peconv/tls_parser.h" +#include "peconv/exceptions_parser.h" +#include "peconv/unicode.h" diff --git a/server/2015Remote/libpeconv/peconv/buffer_util.h b/server/2015Remote/libpeconv/peconv/buffer_util.h new file mode 100644 index 0000000..89cce48 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/buffer_util.h @@ -0,0 +1,88 @@ +/** +* @file +* @brief Definitions of the used buffer types. Functions for their allocation and deallocation. +*/ + +#pragma once + +#include + +#define MAX_DWORD 0xffffffff +#define MAX_WORD 0xffff +#define MASK_TO_DWORD(val) ((val < MAX_DWORD) ? (val & MAX_DWORD) : MAX_DWORD) +#define MASK_TO_WORD(val) ((val < MAX_WORD) ? (val & MAX_WORD) : MAX_WORD) + +namespace peconv { + + /** + Validates pointers, checks if the particular field is inside the given buffer. Sizes must be given in bytes. + \param buffer_bgn : the start address of the buffer + \param buffer_size : the size of the buffer + \param field_bgn : the start address of the field + \param field_size : the size of the field + \return true if the field (defined by its start address: field_bgn, and size: field_size) is contained within the given buffer + (defined by its start address: buffer_bgn, and size: buffer_size). + false otherwise + */ + bool validate_ptr( + IN const void* buffer_bgn, + IN size_t buffer_size, + IN const void* field_bgn, + IN size_t field_size + ); + +//----------------------------------------------------------------------------------- +// +// supported buffers: +// + /** + A buffer allocated on the heap of a process, not aligned to the beginning of a memory page. + */ + typedef PBYTE UNALIGNED_BUF; + + /** + A buffer allocated in a virtual space of a process, aligned to the beginning of a memory page. + */ + typedef PBYTE ALIGNED_BUF; + +// +// alloc/free unaligned buffers: +// + /** + Allocates a buffer on the heap. Can be used in the cases when the buffer does not have to start at the beginning of a page. + */ + UNALIGNED_BUF alloc_unaligned(size_t buf_size); + + // + /** + Frees buffer allocated by alloc_unaligned. + */ + void free_unaligned(UNALIGNED_BUF section_buffer); + +// +// alloc/free aligned buffers: +// + + /** + Allocates a buffer of a virtual memory (using VirtualAlloc). Can be used in the cases when the buffer have to be aligned to the beginning of a page. + */ + ALIGNED_BUF alloc_aligned(size_t buffer_size, DWORD protect, void* desired_base=nullptr); + + /** + Frees buffer allocated by alloc_aligned. + */ + bool free_aligned(ALIGNED_BUF buffer, size_t buffer_size=0); + + //PE buffers (wrappers) + + /** + Allocates an aligned buffer for a PE file. + */ + ALIGNED_BUF alloc_pe_buffer(size_t buffer_size, DWORD protect, void* desired_base=nullptr); + + /** + Free the memory allocated with alloc_pe_buffer. + */ + bool free_pe_buffer(ALIGNED_BUF buffer, size_t buffer_size=0); + +}; //namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/caves.h b/server/2015Remote/libpeconv/peconv/caves.h new file mode 100644 index 0000000..7b5b5d7 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/caves.h @@ -0,0 +1,27 @@ +/** +* @file +* @brief Functions related to finding caves in the loaded PE file. +*/ + +#pragma once + +#include + +namespace peconv { + + /** + Finds cave at the end of the image (extend last section's raw size without extending the full image size) + */ + PBYTE find_ending_cave(BYTE* module_ptr, size_t module_size, const DWORD cave_size, const DWORD cave_charact=IMAGE_SCN_MEM_READ); + + /** + Finds cave in the difference between the original raw size, and the raw size rounded to the aligmnent + */ + PBYTE find_alignment_cave(BYTE* modulePtr, size_t moduleSize, const DWORD cave_size, const DWORD req_charact = IMAGE_SCN_MEM_READ); + + /** + Finds cave at the end of the section, that comes from a NULL padding or INT3 padding + */ + PBYTE find_padding_cave(BYTE* modulePtr, size_t moduleSize, const size_t minimal_size, const DWORD req_charact = IMAGE_SCN_MEM_READ); + +};//namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/delayed_imports_loader.h b/server/2015Remote/libpeconv/peconv/delayed_imports_loader.h new file mode 100644 index 0000000..7c875f9 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/delayed_imports_loader.h @@ -0,0 +1,61 @@ +/** +* @file +* @brief Parsing and filling the Delayload Import Table. +*/ + +#pragma once + +#include + +#include "pe_hdrs_helper.h" +#include "function_resolver.h" + +#if (defined(_WIN32_WINNT) && _WIN32_WINNT > 0x0601) || __MINGW32__ //Windows SDK version 6.1 (Windows 7) +#define DELAYLOAD_IMPORTS_DEFINED +#endif + +#ifndef DELAYLOAD_IMPORTS_DEFINED +#include "pshpack4.h" + +typedef struct _IMAGE_DELAYLOAD_DESCRIPTOR { + union { + DWORD AllAttributes; + struct { + DWORD RvaBased : 1; // Delay load version 2 + DWORD ReservedAttributes : 31; + } DUMMYSTRUCTNAME; + } Attributes; + + DWORD DllNameRVA; // RVA to the name of the target library (NULL-terminate ASCII string) + DWORD ModuleHandleRVA; // RVA to the HMODULE caching location (PHMODULE) + DWORD ImportAddressTableRVA; // RVA to the start of the IAT (PIMAGE_THUNK_DATA) + DWORD ImportNameTableRVA; // RVA to the start of the name table (PIMAGE_THUNK_DATA::AddressOfData) + DWORD BoundImportAddressTableRVA; // RVA to an optional bound IAT + DWORD UnloadInformationTableRVA; // RVA to an optional unload info table + DWORD TimeDateStamp; // 0 if not bound, + // Otherwise, date/time of the target DLL + +} IMAGE_DELAYLOAD_DESCRIPTOR, *PIMAGE_DELAYLOAD_DESCRIPTOR; + +typedef const IMAGE_DELAYLOAD_DESCRIPTOR *PCIMAGE_DELAYLOAD_DESCRIPTOR; + +#include "poppack.h" +#endif + +namespace peconv { + + /** + Get the Delayload Imports directory. Returns the pointer to the first descriptor. The size of the directory is passed via variable dir_size. + */ + IMAGE_DELAYLOAD_DESCRIPTOR* get_delayed_imps(IN const BYTE* modulePtr, IN const size_t moduleSize, OUT size_t &dir_size); + + /** + Fill the Delayload Imports in the given module. + \param modulePtr : the pointer to the module where the imports needs to be filled. + \param moduleBase : the base to which the module was relocated, it may (or not) be the same as modulePtr + \param func_resolver : the resolver that will be used for loading the imports + \return : true if resolving all succeeded, false otherwise + */ + bool load_delayed_imports(BYTE* modulePtr, const ULONGLONG moduleBase, t_function_resolver* func_resolver = nullptr); + +}; // namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/exceptions_parser.h b/server/2015Remote/libpeconv/peconv/exceptions_parser.h new file mode 100644 index 0000000..547ef75 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/exceptions_parser.h @@ -0,0 +1,21 @@ +/** +* @file +* @brief Functions related to Exceptions Table +*/ + +#pragma once + +#include "peconv/buffer_util.h" + +namespace peconv { + + /** + Allows to activate the Exception table from the manually loaded module. + For 32-bits the loaded image should enable /SAFESEH linker option, + otherwise the exception handler cannot pass the RtlIsValidHandler() check + when an exception occurs + */ + bool setup_exceptions(IN BYTE* modulePtr, IN size_t moduleSize); + +}; + diff --git a/server/2015Remote/libpeconv/peconv/exported_func.h b/server/2015Remote/libpeconv/peconv/exported_func.h new file mode 100644 index 0000000..9724b3f --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/exported_func.h @@ -0,0 +1,132 @@ +/** +* @file +* @brief A definition of ExportedFunc class - used for storing the details of the exported function. Helper functions related to the export parsing. +*/ + +#pragma once + +#include +#include +#include +#include + +namespace peconv { + + /** + Check if the pointer redirects to a forwarder - if so, return the length, otherwise return 0. + */ + size_t forwarder_name_len(BYTE* fPtr); + + /** + get the DLL name without the extension + */ + std::string get_dll_shortname(const std::string& str); + + /** + Get the function name from the string in a format: DLL_name.function_name + */ + std::string get_func_name(const std::string& str); + + /** + Convert ordinal value to the ordinal string (in a format #[ordinal]) + */ + std::string ordinal_to_string(DWORD func_ordinal); + + /** + Check if the given string is in a format typical for storing ordinals (#[ordinal]) + */ + bool is_ordinal_string(const std::string& str); + + /** + Get the ordinal value from the ordinal string (in a format #[ordinal]) + */ + DWORD ordinal_string_to_val(const std::string& str); + + /** + Convert the function in a format: DLL_name.function_name into a normalized form (DLL name in lowercase). + */ + std::string format_dll_func(const std::string& str); + + /** + A class storing the information about the exported function. + */ + class ExportedFunc + { + public: + /** + Converts the name to the normalized format. + */ + static std::string formatName(std::string name); + + //! Compares functions' names. If function is defined by an ordinal, compares ordinals. Does not include the DLL name in the comparison. + static bool isTheSameFuncName(const peconv::ExportedFunc& func1, const peconv::ExportedFunc& func2); + + //! Compares functions' DLL names. + static bool isTheSameDllName(const peconv::ExportedFunc& func1, const peconv::ExportedFunc& func2); + + //! Compares functions' names. If function is defined by an ordinal, compares ordinals. Includes the DLL name in the comparison. + static bool isTheSameFunc(const peconv::ExportedFunc& func1, const peconv::ExportedFunc& func2); + + std::string libName; + std::string funcName; + DWORD funcOrdinal; + bool isByOrdinal; + + //default constructor: + ExportedFunc() : funcOrdinal(0), isByOrdinal(false) {} + + ExportedFunc(const ExportedFunc& other); + ExportedFunc(std::string libName, std::string funcName, DWORD funcOrdinal); + ExportedFunc(std::string libName, DWORD funcOrdinal); + ExportedFunc(const std::string &forwarderName); + + /** + Compare two functions with each other. + Gives the priority to the named functions: if one of the compared functions is unnamed, the named one is treated as smaller. + If both functions are unnamed, the function with the smaller ordinal is treated as smaller. + Otherwise, the function with the shorter name is treated as smaller. + */ + bool operator < (const ExportedFunc& other) const + { + //if only one function is named, give the preference to the named one: + const size_t thisNameLen = this->funcName.length(); + const size_t otherNameLen = other.funcName.length(); + if (thisNameLen == 0 && otherNameLen > 0) { + return false; + } + if (thisNameLen > 0 && otherNameLen == 0) { + return true; + } + //select by shorter lib name: + int cmp = libName.compare(other.libName); + if (cmp != 0) { + return cmp < 0; + } + if (thisNameLen == 0 || otherNameLen == 0) { + return this->funcOrdinal < other.funcOrdinal; + } + if (thisNameLen != otherNameLen) { + return thisNameLen < otherNameLen; + } + cmp = funcName.compare(other.funcName); + return cmp < 0; + } + + /** + Gets a string representation of the variable. Full info about the function: library, name, ordinal. + */ + std::string toString() const; + + /** + Gets a string representation of the variable. Short info about the function: only function name or ordinal (if the name is missing). + */ + std::string nameToString() const; + + bool isValid() const + { + return (funcName != "" || funcOrdinal != -1); + } + }; + +}; //namespace peconv + diff --git a/server/2015Remote/libpeconv/peconv/exports_lookup.h b/server/2015Remote/libpeconv/peconv/exports_lookup.h new file mode 100644 index 0000000..ee89084 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/exports_lookup.h @@ -0,0 +1,50 @@ +/** +* @file +* @brief Searching specific functions in PE's Exports Table. +*/ + +#pragma once +#include + +#include "pe_hdrs_helper.h" +#include "function_resolver.h" +#include "exports_mapper.h" + +#include +#include +#include + +namespace peconv { + + /** + Gets the function address by the name. Uses Export Table lookup. + WARNING: doesn't work for the forwarded functions. + */ + FARPROC get_exported_func(PVOID modulePtr, LPCSTR wanted_name); + + /** + Gets list of all the functions from a given module that are exported by names. + */ + size_t get_exported_names(PVOID modulePtr, std::vector &names_list); + + /** + Function resolver using Export Table lookup. + */ + class export_based_resolver : default_func_resolver { + public: + /** + Get the address (VA) of the function with the given name, from the given DLL. + Uses Export Table lookup as a primary method of finding the import. On failure it falls back to the default Functions Resolver. + \param func_name : the name of the function + \param lib_name : the name of the DLL + \return Virtual Address of the exported function + */ + virtual FARPROC resolve_func(LPCSTR lib_name, LPCSTR func_name); + }; + + /** + Read the DLL name from the Export Table. + */ + LPSTR read_dll_name(HMODULE modulePtr); + +}; //namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/exports_mapper.h b/server/2015Remote/libpeconv/peconv/exports_mapper.h new file mode 100644 index 0000000..70d212a --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/exports_mapper.h @@ -0,0 +1,224 @@ +/** +* @file +* @brief A definition of ExportsMapper class. Creates a lookup of all the exported functions from the supplied DLLs. Allows to associate an address with a corresponding function. +*/ + +#pragma once + +#include + +#include +#include +#include +#include + +#include "pe_hdrs_helper.h" +#include "pe_raw_to_virtual.h" +#include "peconv/exported_func.h" +#include "peconv/file_util.h" + +namespace peconv { + + struct DllInfo { + DllInfo() + : moduleBase(0), moduelSize(0), is64b(false) + { + } + + DllInfo(ULONGLONG _moduleBase, size_t _moduelSize, bool _is64b, std::string _moduleName) + { + moduleBase = _moduleBase; + moduelSize = _moduelSize; + moduleName = _moduleName; + is64b = _is64b; + shortName = get_dll_shortname(moduleName); + } + + DllInfo(const DllInfo &other) + { + moduleBase = other.moduleBase; + moduelSize = other.moduelSize; + moduleName = other.moduleName; + shortName = other.shortName; + is64b = other.is64b; + } + + bool operator<(const DllInfo &other) const + { + return this->moduleBase < other.moduleBase; + } + + protected: + ULONGLONG moduleBase; + size_t moduelSize; + std::string moduleName; + std::string shortName; + bool is64b; + + friend class ExportsMapper; + }; + + class ExportsMapper { + + public: + + /** + Appends the given DLL to the lookup table of exported functions. Returns the number of functions exported from this DLL (not forwarded). + \param moduleName : name of the DLL + \param modulePtr : buffer containing the DLL in a Virtual format + \param moduleSize : size of the DLL buffer. If moduleSize == 0, the ImageSize from the PE headers will be used. + \param moduleBase : a base address to which the given DLL was relocated + */ + size_t add_to_lookup(std::string moduleName, HMODULE modulePtr, size_t moduleSize, ULONGLONG moduleBase); + + /** + Appends the given DLL to the lookup table of exported functions. Returns the number of functions exported from this DLL (not forwarded). + \param moduleName : name of the DLL + \param modulePtr : buffer containing the DLL in a Virtual format + \param moduleBase : a base address to which the given DLL was relocated + */ + size_t add_to_lookup(std::string moduleName, HMODULE modulePtr, ULONGLONG moduleBase) + { + return add_to_lookup(moduleName, modulePtr, 0, moduleBase); + } + + /** + Appends the given DLL to the lookup table of exported functions. Returns the number of functions exported from this DLL (not forwarded). + Assumes that the module was relocated to the same address as is the address of the given buffer (modulePtr). + (A wrapper for the case if we are adding a DLL that was loaded within the current process.) + \param moduleName : name of the DLL + \param modulePtr : buffer containing the DLL in a Virtual format. + */ + size_t add_to_lookup(std::string moduleName, HMODULE modulePtr) + { + return add_to_lookup(moduleName, modulePtr, reinterpret_cast(modulePtr)); + } + + /** + Find the set of Exported Functions that can be mapped to the given VA. Includes forwarders, and function aliases. + */ + const std::set* find_exports_by_va(ULONGLONG va) const + { + std::map>::const_iterator itr = va_to_func.find(va); + if (itr != va_to_func.end()) { + const std::set &fSet = itr->second; + return &fSet; + } + return NULL; + } + + /** + Retrieve the base of the DLL containing the given function. If not found, returns 0. + */ + ULONGLONG find_dll_base_by_func_va(ULONGLONG func_rva) const + { + // the first element that is greater than the start address + std::map::const_iterator firstGreater = dll_base_to_info.upper_bound(func_rva); + + std::map::const_iterator itr; + for (itr = dll_base_to_info.begin(); itr != firstGreater; ++itr) { + const DllInfo& module = itr->second; + + if (func_rva >= module.moduleBase && func_rva <= (module.moduleBase + module.moduelSize)) { + // Address found in module: + return module.moduleBase; + } + } + return 0; + } + + /** + Retrieve the full path of the DLL with the given module base. + */ + std::string get_dll_path(ULONGLONG base) const + { + std::map::const_iterator found = this->dll_base_to_info.find(base); + if (found == this->dll_base_to_info.end()) { // no DLL found at this base + return ""; + } + const DllInfo& info = found->second; + return info.moduleName; + } + + /** + Retrieve the path of the DLL with the given short name. If multiple paths are mapped to the same short name, it retrieves the first one. + */ + std::string get_dll_path(std::string short_name) const; + + /** + Retrieve the paths of the DLL with the given short name. + */ + size_t get_dll_paths(IN std::string short_name, OUT std::set& paths) const; + + /** + Retrieve the full name of the DLL (including the extension) using its short name (without the extension). + */ + std::string get_dll_fullname(std::string short_name) const + { + std::string dll_path = get_dll_path(short_name); + if (dll_path.length() == 0) return ""; + + return get_file_name(dll_path); + } + + /** + Find an Exported Function that can be mapped to the given VA, + */ + const ExportedFunc* find_export_by_va(ULONGLONG va) const + { + const std::set* exp_set = find_exports_by_va(va); + if (exp_set == NULL) return NULL; + + std::set::iterator fItr = exp_set->begin(); + const ExportedFunc* func = &(*fItr); + return func; + } + + void print_va_to_func(std::stringstream &stream) const; + void print_func_to_va(std::stringstream &stream) const; + + + private: + enum ADD_FUNC_RES { RES_INVALID = 0, RES_MAPPED = 1, RES_FORWARDED = 2 }; + ADD_FUNC_RES add_function_to_lookup(HMODULE modulePtr, ULONGLONG moduleBase, size_t moduleSize, ExportedFunc &currFunc, DWORD callRVA); + + bool add_forwarded(ExportedFunc &currFunc, DWORD callRVA, PBYTE modulePtr, size_t moduleSize); + bool add_to_maps(ULONGLONG va, ExportedFunc &currFunc); + + size_t resolve_forwarders(const ULONGLONG va, ExportedFunc &currFunc); + size_t make_ord_lookup_tables(PVOID modulePtr, size_t moduleSize, std::map &va_to_ord); + + protected: + /** + Add a function and a VA into a mutual mapping. + */ + void associateVaAndFunc(ULONGLONG va, const ExportedFunc& func) + { + va_to_func[va].insert(func); + func_to_va[func] = va; + } + + /** + A map associating VA of the function with the related exports. + */ + std::map> va_to_func; + + /** + A map associating an exported functions with its forwarders. + */ + std::map> forwarders_lookup; + + /** + A map associating an exported functions with its VA. + */ + std::map func_to_va; + + /** + A map associating DLL shortname with the base(s) at which it was mapped + */ + std::map> dll_shortname_to_base; + + std::map dll_base_to_info; + }; + +}; //namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/file_util.h b/server/2015Remote/libpeconv/peconv/file_util.h new file mode 100644 index 0000000..1592661 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/file_util.h @@ -0,0 +1,60 @@ +/** +* @file +* @brief Functions related to operations on files. Wrappers for read/write. +*/ + +#pragma once + +#include +#include + +#include "buffer_util.h" + +namespace peconv { + + /** + Maps a file with the given path and copies its raw content into the output buffer. + If read_size is not zero, it reads maximum read_size of bytes. If read_size is zero, it reads the full file. + The actual read size is returned back in read_size. + Automatically allocates a buffer of the required size. + */ + peconv::UNALIGNED_BUF load_file(IN LPCTSTR filename, OUT size_t &r_size); + + /** + Reads a raw content of the file with the given path. + If read_size is not zero, it reads maximum read_size of bytes. If read_size is zero, it reads the full file. + The actual read size is returned back in read_size. + Automatically allocates a buffer of the required size. + */ + peconv::UNALIGNED_BUF read_from_file(IN LPCTSTR path, IN OUT size_t &read_size); + + /** + Writes a buffer of bytes into a file of given path. + \param path : the path to the output file + \param dump_data : the buffer to be dumped + \param dump_size : the size of data to be dumped (in bytes) + \return true if succeeded, false if failed + */ + bool dump_to_file(IN LPCTSTR path, IN PBYTE dump_data, IN size_t dump_size); + + /** + Free the buffer allocated by load_file/read_from_file + */ + void free_file(IN peconv::UNALIGNED_BUF buffer); + + /** + Get the file name from the given path. + */ + std::string get_file_name(IN const std::string full_path); + + /** + Get the directory name from the given path. It assumes that a directory name always ends with a separator ("/" or "\") + */ + std::string get_directory_name(IN const std::string full_path); + + /** + Find a position of possible file extension. If not found, gives string length. + */ + size_t find_extension_pos(IN const std::string str); + +}; //namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/find_base.h b/server/2015Remote/libpeconv/peconv/find_base.h new file mode 100644 index 0000000..f49b030 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/find_base.h @@ -0,0 +1,20 @@ +/** +* @file +* @brief Functions related to finding a base to which the module was relocated. +*/ + +#pragma once + +#include + +namespace peconv { + + /** + Try to find a base to which the PE file was relocated, basing on the filled relocations. + WARNING: the found base is an estimate, and sometimes may not be fully accurate. + \param module_ptr : the module which's base is being searched + \param module_size : the size of the given module + \return the base to which the module was relocated + */ + ULONGLONG find_base_candidate(IN BYTE *module_ptr, IN size_t module_size); +}; diff --git a/server/2015Remote/libpeconv/peconv/fix_imports.h b/server/2015Remote/libpeconv/peconv/fix_imports.h new file mode 100644 index 0000000..d758711 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/fix_imports.h @@ -0,0 +1,119 @@ +/** +* @file +* @brief Functions and classes responsible for fixing Import Table. A definition of ImportedDllCoverage class. +*/ + +#pragma once + +#include + +#include + +#include +#include + +#include + +#include "pe_hdrs_helper.h" +#include "exports_lookup.h" +#include "exports_mapper.h" + +#define MIN_DLL_LEN 5 + +namespace peconv { + + /** + a helper class that allows to store information about functions that could not be covered by the given mapping + */ + class ImpsNotCovered + { + public: + ImpsNotCovered() {} + ~ImpsNotCovered() {} + + /* + Number of stored records + */ + size_t count() { return thunkToAddr.size(); } + + void insert(DWORD thunkRVA, ULONGLONG searchedAddr); + + std::map thunkToAddr; //addresses of not recovered functions with their thunks (call_via) + }; + + /** + fix imports in the given module, using the given map of all available exports + */ + bool fix_imports(IN OUT PVOID modulePtr, IN size_t moduleSize, IN const peconv::ExportsMapper& exportsMap, OUT OPTIONAL peconv::ImpsNotCovered* notCovered); + + /** + a helper class that allows to find out where the functions are imported from + */ + class ImportedDllCoverage + { + public: + /** + A constructor of an object of ImportedDllCoverage class. + \param _addresses : the list of filled imports (VAs): the addresses to be covered + \param _exportsMap : the map of the exports of all the loaded DLLs (the space in which we will be searching) + */ + ImportedDllCoverage(std::set& _addresses, const peconv::ExportsMapper& _exportsMap) + : addresses(_addresses), exportsMap(_exportsMap) + { + } + + /** + Checks if all the addresses can be covered by one DLL. If yes, this dll will be saved into: dllName. + \return true if the covering DLL for the addresses was found. false otherwise. + */ + bool findCoveringDll(); + + /** + Maps the addresses from the set to functions from the given DLL. + Results are saved into: addrToFunc. + Addresses that could not be covered by the given DLL are saved into notFound. + Before each execution, the content of involved variables is erased. + \param _mappedDllName : the name of the DLL that we will be used to mapping. This DLL is saved into mappedDllName. + \return a number of covered functions + */ + size_t mapAddressesToFunctions(const std::string &_mappedDllName); + + /** + Check if the functions mapping is complete. + \return the status: true if all the addresses are mapped to specific exports, false if not + */ + bool isMappingComplete() { return (addresses.size() == addrToFunc.size()) ? true : false; } + + /** + A mapping associating each of the covered function addresses with the set of exports (from mapped DLL) that cover this address + */ + std::map> addrToFunc; + + /** + Addresses of the functions not found in the mapped DLL + */ + std::set notFound; + + /** + Name of the covering DLL + */ + std::string dllName; + + protected: + /** + A name of the DLL that was used for mapping. In a typical scenario it will be the same as covering DLL, but may be set different. + */ + std::string mappedDllName; + + /** + A supplied set of the addresses of imported functions. + Those addressed will be covered (associated with the corresponding exports from available DLLs, defined by exportsMap). + */ + std::set &addresses; + + /** + A supplied exportsMap. Only used as a lookup, no changes applied. + */ + const peconv::ExportsMapper& exportsMap; + }; +} diff --git a/server/2015Remote/libpeconv/peconv/function_resolver.h b/server/2015Remote/libpeconv/peconv/function_resolver.h new file mode 100644 index 0000000..f207442 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/function_resolver.h @@ -0,0 +1,50 @@ +/** +* @file +* @brief Definitions of basic Imports Resolver classes. They can be used for filling imports when the PE is loaded. +*/ + +#pragma once + +#include +#include +#include + +namespace peconv { + /** + A base class for functions resolver. + */ + class t_function_resolver { + public: + /** + Get the address (VA) of the function with the given name, from the given DLL. + \param func_name : the name of the function + \param lib_name : the name of the DLL + \return Virtual Address of the exported function + */ + virtual FARPROC resolve_func(LPCSTR lib_name, LPCSTR func_name) = 0; + }; + + /** + A default functions resolver, using LoadLibraryA and GetProcAddress. + */ + class default_func_resolver : t_function_resolver { + public: + /** + Get the address (VA) of the function with the given name, from the given DLL, using LoadLibraryA and GetProcAddress. + \param func_name : the name of the function + \param lib_name : the name of the DLL + \return Virtual Address of the exported function + */ + virtual FARPROC resolve_func(LPCSTR lib_name, LPCSTR func_name); + + /** + Load the DLL using LoadLibraryA. + \param lib_name : the name of the DLL + \return base of the loaded module + */ + virtual HMODULE load_library(LPCSTR lib_name); + + std::map nameToModule; + }; + +}; //namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/hooks.h b/server/2015Remote/libpeconv/peconv/hooks.h new file mode 100644 index 0000000..dd95a33 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/hooks.h @@ -0,0 +1,146 @@ +/** +* @file +* @brief Functions related to hooking the loaded PE. Reditecting/replacing a functions with another. +*/ + +#pragma once + +#include +#include "function_resolver.h" + +#include +#include +#include +#include "peconv/buffer_util.h" + +namespace peconv { + + /** + A buffer storing a binary patch, that can be applied on a module. Used as a restorable backup in case of function patching. + */ + class PatchBackup { + public: + /** + Creates an empty backup. + */ + PatchBackup() + : buffer(nullptr), bufferSize(0), sourcePtr(nullptr) + { + } + + ~PatchBackup() { + deleteBackup(); + } + + /** + Destroys the backup and resets internal fields. + */ + void deleteBackup() + { + if (buffer) { + delete[] buffer; + bufferSize = 0; + sourcePtr = nullptr; + } + } + + /** + Reads bytes from the binary to the backup. The source buffer must be within the current process. + */ + bool makeBackup(BYTE *patch_ptr, size_t patch_size); + + /** + Applies the backup back to the pointer from which it was read. + */ + bool applyBackup(); + + /** + Checks if the buffer was filled. + */ + bool isBackup() + { + return buffer != nullptr; + } + + protected: + BYTE *buffer; + size_t bufferSize; + + BYTE *sourcePtr; + }; + + + /** + A functions resolver that can be used for hooking IAT. Allows for defining functions that are supposed to be replaced. + */ + class hooking_func_resolver : peconv::default_func_resolver { + public: + /** + Define a function that will be replaced. + \param name : a name of the function that will be replaced + \param function : an address of the replacement function + */ + void add_hook(const std::string &name, FARPROC function) + { + hooks_map[name] = function; + } + + /** + Define a DLL that will be replaced. + \param dll_name : a name of the DLL to be replaced + \param new_dll : a name of the new DLL that will be loaded instead + */ + void replace_dll(std::string dll_name, const std::string &new_dll) + { + dll_replacements_map[dll_name] = new_dll; + } + + /** + Get the address (VA) of the function with the given name, from the given DLL. If the function was hooked, it retrieves the address of the replacement function instead. + \param func_name : the name of the function + \param lib_name : the name of the DLL + \return Virtual Address of the exported function, or the address of the replacement function. + */ + virtual FARPROC resolve_func(LPCSTR lib_name, LPCSTR func_name); + + private: + std::map hooks_map; + std::map dll_replacements_map; + }; + + /** + Installs inline hook at the given ptr. Returns the number of bytes overwriten. + 64 bit version. + \param ptr : pointer to the function to be replaced + \param new_offset : VA of the new function + \param backup : (optional) backup that can be used to reverse the changes + \return size of the applied patch + */ + size_t redirect_to_local64(void *ptr, ULONGLONG new_offset, PatchBackup* backup = nullptr); + + /** + Installs inline hook at the given ptr. Returns the number of bytes overwriten. + 32 bit version. + \param ptr : pointer to the function to be replaced + \param new_offset : VA of the new function + \param backup : (optional) backup that can be used to reverse the changes + \return size of the applied patch + */ + size_t redirect_to_local32(void *ptr, DWORD new_offset, PatchBackup* backup = nullptr); + + /** + Installs inline hook at the given ptr. Returns the number of bytes overwriten. + Uses bitness of the current applications for the bitness of the intalled hook. + \param ptr : pointer to the function to be replaced + \param new_function_ptr : pointer to the new function + \param backup : (optional) backup that can be used to reverse the changes + \return size of the applied patch + */ + size_t redirect_to_local(void *ptr, void* new_function_ptr, PatchBackup* backup = nullptr); + + /** + Replaces a target address of JMP [DWORD] or CALL [DWORD] + */ + bool replace_target(BYTE *ptr, ULONGLONG dest_addr); + +};//namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/imports_loader.h b/server/2015Remote/libpeconv/peconv/imports_loader.h new file mode 100644 index 0000000..9dc6096 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/imports_loader.h @@ -0,0 +1,103 @@ +/** +* @file +* @brief Parsing and filling the Import Table. +*/ + +#pragma once + +#include +#include + +#include "pe_hdrs_helper.h" +#include "function_resolver.h" +#include "exports_mapper.h" + +namespace peconv { + + /** + A class defining a callback that will be executed when the next imported function was found + */ + class ImportThunksCallback + { + public: + ImportThunksCallback(BYTE* _modulePtr, size_t _moduleSize) + : modulePtr(_modulePtr), moduleSize(_moduleSize) + { + this->is64b = is64bit((BYTE*)modulePtr); + } + + /** + A callback that will be executed by process_import_table when the next imported function was found + \param libName : the pointer to the DLL name + \param origFirstThunkPtr : the pointer to the Original First Thunk + \param firstThunkPtr : the pointer to the First Thunk + \return : true if processing succeeded, false otherwise + */ + virtual bool processThunks(LPSTR libName, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr) = 0; + + protected: + BYTE* modulePtr; + size_t moduleSize; + bool is64b; + }; + + + struct ImportsCollection + { + public: + ImportsCollection() {}; + ~ImportsCollection() + { + std::map::iterator itr; + for (itr = thunkToFunc.begin(); itr != thunkToFunc.end(); ++itr) { + peconv::ExportedFunc* exp = itr->second; + if (!exp) continue; + delete exp; + } + thunkToFunc.clear(); + } + + size_t size() + { + return thunkToFunc.size(); + } + + std::map thunkToFunc; + }; + + /** + Process the given PE's import table and execute the callback each time when the new imported function was found + \param modulePtr : a pointer to the loded PE (in virtual format) + \param moduleSize : a size of the supplied PE + \param callback : a callback that will be executed to process each imported function + \return : true if processing succeeded, false otherwise + */ + bool process_import_table(IN BYTE* modulePtr, IN SIZE_T moduleSize, IN ImportThunksCallback *callback); + + /** + Fills imports of the given PE with the help of the defined functions resolver. + \param modulePtr : a pointer to the loded PE (in virtual format) + \param func_resolver : a resolver that will be used to fill the thunk of the import + \return : true if loading all functions succeeded, false otherwise + */ + bool load_imports(BYTE* modulePtr, t_function_resolver* func_resolver=nullptr); + + /** + Checks if the given PE has a valid import table. + */ + bool has_valid_import_table(const PBYTE modulePtr, size_t moduleSize); + + /** + Checks if the given lib_name is a valid DLL name. + A valid name must contain printable characters. Empty name is also acceptable (may have been erased). + */ + bool is_valid_import_name(const PBYTE modulePtr, const size_t moduleSize, LPSTR lib_name); + + /** + * Collects all the Import Thunks RVAs (via which Imports are called) + */ + bool collect_thunks(IN BYTE* modulePtr, IN SIZE_T moduleSize, OUT std::set& thunk_rvas); + + bool collect_imports(IN BYTE* modulePtr, IN SIZE_T moduleSize, OUT ImportsCollection &collection); + +}; // namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/imports_uneraser.h b/server/2015Remote/libpeconv/peconv/imports_uneraser.h new file mode 100644 index 0000000..274bfc7 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/imports_uneraser.h @@ -0,0 +1,94 @@ +/** +* @file +* @brief A definition of ImportsUneraser class - for recovery of a partialy erased Import Table. +*/ + +#pragma once + +#include + +#include + +#include +#include + +#include +#include "fix_imports.h" +#include "caves.h" + +namespace peconv { + + /** + A class responsible for recovering the partially erased Import Table from the PE. + */ + class ImportsUneraser + { + public: + ImportsUneraser(PVOID _modulePtr, size_t _moduleSize) + : modulePtr((PBYTE)_modulePtr), moduleSize(_moduleSize) + { + is64 = peconv::is64bit((BYTE*)modulePtr); + } + + /** + Fill the imported functions' names in the given Import Descriptor, using the given coverage. + Collect addressees of functions that couldn't be filled with the given mapping. + \param lib_desc : the IMAGE_IMPORT_DESCRIPTOR where the functions' names should be set + \param dllCoverage : a mapping associating addresses with the corresponding exports from available DLLs + \param not_covered : a set of addresses that could not be found in the supplied mapping + \return true if succeeded + */ + bool uneraseDllImports(IN OUT IMAGE_IMPORT_DESCRIPTOR* lib_desc, IN ImportedDllCoverage &dllCoverage, OUT OPTIONAL ImpsNotCovered* not_covered); + + /** + Recover the imported DLL name in the given Import Descriptor, filling it with the given dll_name. + */ + bool uneraseDllName(IMAGE_IMPORT_DESCRIPTOR* lib_desc, const std::string &dll_name); + + protected: + /** + Copy the given DLL name into the given IMAGE_IMPORT_DESCRIPTOR. Validates the data correctness before writing. + \param lib_desc : the IMAGE_IMPORT_DESCRIPTOR where the DLL name should be set + \param dll_name : the DLL name that needs to be written into the lib_desc + \return true if succeeded + */ + bool writeFoundDllName(IMAGE_IMPORT_DESCRIPTOR* lib_desc, const std::string &dll_name); + + /** + Fill the names of imported functions with names of the prepared mapping. + Collect addressees of functions that couldn't be filled with the given mapping. + \param lib_desc : the IMAGE_IMPORT_DESCRIPTOR where the functions' names should be set + \param ordinal_flag : the flag that is used to recognize import by ordinal (32 or 64 bit) + \param addr_to_func : a mapping assigning functions' addresses to their definitions (names etc.) + \param not_covered : a set of addresses that could not be found in the supplied mapping + \return true if succeeded + */ + template + bool fillImportNames(IN OUT IMAGE_IMPORT_DESCRIPTOR* lib_desc, + IN const FIELD_T ordinal_flag, + IN std::map> &addr_to_func, + OUT OPTIONAL ImpsNotCovered* not_covered + ); + + template + bool findNameInBinaryAndFill(IMAGE_IMPORT_DESCRIPTOR* lib_desc, + LPVOID call_via_ptr, + LPVOID thunk_ptr, + const FIELD_T ordinal_flag, + std::map> &addr_to_func + ); + + /** + Fill the function data into the given IMAGE_THUNK_DATA. + \param desc : the poiner to IMAGE_THUNK_DATA that will be filled + \param ordinal_flag : an ordinal flag: 32 or 64 bit + \param foundFunc : the ExportedFunc that will be used for filling the desc + */ + template + bool writeFoundFunction(IMAGE_THUNK_DATA_T* desc, const FIELD_T ordinal_flag, const ExportedFunc &foundFunc); + + PBYTE modulePtr; + size_t moduleSize; + bool is64; + }; +} diff --git a/server/2015Remote/libpeconv/peconv/load_config_defs.h b/server/2015Remote/libpeconv/peconv/load_config_defs.h new file mode 100644 index 0000000..8402ec9 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/load_config_defs.h @@ -0,0 +1,233 @@ +/** +* @file +* @brief Definitions of various versions of Load Config Directory (new fields added with new versions for Windows). +*/ + +#pragma once + +#include +#include + +namespace peconv { + + /** + IMAGE_LOAD_CONFIG_CODE_INTEGRITY: a structure used by IMAGE_LOAD_CONFIG_DIR - the Windows 10 version. + */ + typedef struct _IMAGE_LOAD_CONFIG_CODE_INTEGRITY_W10 { + WORD Flags; // Flags to indicate if CI information is available, etc. + WORD Catalog; // 0xFFFF means not available + DWORD CatalogOffset; + DWORD Reserved; // Additional bitmask to be defined later + } IMAGE_LOAD_CONFIG_CODE_INTEGRITY_W10; + + /** + IMAGE_LOAD_CONFIG_DIR32: the Windows 10 version. + */ + typedef struct _IMAGE_LOAD_CONFIG_DIR32_W10 { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + DWORD DeCommitFreeBlockThreshold; + DWORD DeCommitTotalFreeThreshold; + DWORD LockPrefixTable; // VA + DWORD MaximumAllocationSize; + DWORD VirtualMemoryThreshold; + DWORD ProcessHeapFlags; + DWORD ProcessAffinityMask; + WORD CSDVersion; + WORD DependentLoadFlags; + DWORD EditList; // VA + DWORD SecurityCookie; // VA + DWORD SEHandlerTable; // VA + DWORD SEHandlerCount; + DWORD GuardCFCheckFunctionPointer; // VA + DWORD GuardCFDispatchFunctionPointer; // VA + DWORD GuardCFFunctionTable; // VA + DWORD GuardCFFunctionCount; + DWORD GuardFlags; + IMAGE_LOAD_CONFIG_CODE_INTEGRITY_W10 CodeIntegrity; + DWORD GuardAddressTakenIatEntryTable; // VA + DWORD GuardAddressTakenIatEntryCount; + DWORD GuardLongJumpTargetTable; // VA + DWORD GuardLongJumpTargetCount; + DWORD DynamicValueRelocTable; // VA + DWORD CHPEMetadataPointer; + DWORD GuardRFFailureRoutine; // VA + DWORD GuardRFFailureRoutineFunctionPointer; // VA + DWORD DynamicValueRelocTableOffset; + WORD DynamicValueRelocTableSection; + WORD Reserved2; + DWORD GuardRFVerifyStackPointerFunctionPointer; // VA + DWORD HotPatchTableOffset; + DWORD Reserved3; + DWORD EnclaveConfigurationPointer; // VA + } IMAGE_LOAD_CONFIG_DIR32_W10; + + /** + IMAGE_LOAD_CONFIG_DIR64: the Windows 10 version. + */ + typedef struct _IMAGE_LOAD_CONFIG_DIR64_W10 { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + ULONGLONG DeCommitFreeBlockThreshold; + ULONGLONG DeCommitTotalFreeThreshold; + ULONGLONG LockPrefixTable; // VA + ULONGLONG MaximumAllocationSize; + ULONGLONG VirtualMemoryThreshold; + ULONGLONG ProcessAffinityMask; + DWORD ProcessHeapFlags; + WORD CSDVersion; + WORD DependentLoadFlags; + ULONGLONG EditList; // VA + ULONGLONG SecurityCookie; // VA + ULONGLONG SEHandlerTable; // VA + ULONGLONG SEHandlerCount; + ULONGLONG GuardCFCheckFunctionPointer; // VA + ULONGLONG GuardCFDispatchFunctionPointer; // VA + ULONGLONG GuardCFFunctionTable; // VA + ULONGLONG GuardCFFunctionCount; + DWORD GuardFlags; + IMAGE_LOAD_CONFIG_CODE_INTEGRITY_W10 CodeIntegrity; + ULONGLONG GuardAddressTakenIatEntryTable; // VA + ULONGLONG GuardAddressTakenIatEntryCount; + ULONGLONG GuardLongJumpTargetTable; // VA + ULONGLONG GuardLongJumpTargetCount; + ULONGLONG DynamicValueRelocTable; // VA + ULONGLONG CHPEMetadataPointer; // VA + ULONGLONG GuardRFFailureRoutine; // VA + ULONGLONG GuardRFFailureRoutineFunctionPointer; // VA + DWORD DynamicValueRelocTableOffset; + WORD DynamicValueRelocTableSection; + WORD Reserved2; + ULONGLONG GuardRFVerifyStackPointerFunctionPointer; // VA + DWORD HotPatchTableOffset; + DWORD Reserved3; + ULONGLONG EnclaveConfigurationPointer; // VA + } IMAGE_LOAD_CONFIG_DIR64_W10; + + /** + IMAGE_LOAD_CONFIG_DIR32: the Windows 8 version. + */ + typedef struct _IMAGE_LOAD_CONFIG_DIR32_W8 { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + DWORD DeCommitFreeBlockThreshold; + DWORD DeCommitTotalFreeThreshold; + DWORD LockPrefixTable; // VA + DWORD MaximumAllocationSize; + DWORD VirtualMemoryThreshold; + DWORD ProcessHeapFlags; + DWORD ProcessAffinityMask; + WORD CSDVersion; + WORD DependentLoadFlags; + DWORD EditList; // VA + DWORD SecurityCookie; // VA + DWORD SEHandlerTable; // VA + DWORD SEHandlerCount; + DWORD GuardCFCheckFunctionPointer; // VA + DWORD GuardCFDispatchFunctionPointer; // VA + DWORD GuardCFFunctionTable; // VA + DWORD GuardCFFunctionCount; + DWORD GuardFlags; + } IMAGE_LOAD_CONFIG_DIR32_W8; + + /** + IMAGE_LOAD_CONFIG_DIR64: the Windows 8 version. + */ + typedef struct _IMAGE_LOAD_CONFIG_DIR64_W8 { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + ULONGLONG DeCommitFreeBlockThreshold; + ULONGLONG DeCommitTotalFreeThreshold; + ULONGLONG LockPrefixTable; // VA + ULONGLONG MaximumAllocationSize; + ULONGLONG VirtualMemoryThreshold; + ULONGLONG ProcessAffinityMask; + DWORD ProcessHeapFlags; + WORD CSDVersion; + WORD DependentLoadFlags; + ULONGLONG EditList; // VA + ULONGLONG SecurityCookie; // VA + ULONGLONG SEHandlerTable; // VA + ULONGLONG SEHandlerCount; + ULONGLONG GuardCFCheckFunctionPointer; // VA + ULONGLONG GuardCFDispatchFunctionPointer; // VA + ULONGLONG GuardCFFunctionTable; // VA + ULONGLONG GuardCFFunctionCount; + DWORD GuardFlags; + } IMAGE_LOAD_CONFIG_DIR64_W8; + + + /** + IMAGE_LOAD_CONFIG_DIR32: the Windows 7 version. + */ + typedef struct _IMAGE_LOAD_CONFIG_DIR32_W7 { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + DWORD DeCommitFreeBlockThreshold; + DWORD DeCommitTotalFreeThreshold; + DWORD LockPrefixTable; // VA + DWORD MaximumAllocationSize; + DWORD VirtualMemoryThreshold; + DWORD ProcessHeapFlags; + DWORD ProcessAffinityMask; + WORD CSDVersion; + WORD DependentLoadFlags; + DWORD EditList; // VA + DWORD SecurityCookie; // VA + DWORD SEHandlerTable; // VA + DWORD SEHandlerCount; + } IMAGE_LOAD_CONFIG_DIR32_W7; + + /** + IMAGE_LOAD_CONFIG_DIR64: the Windows 7 version. + */ + typedef struct _IMAGE_LOAD_CONFIG_DIR64_W7 { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + ULONGLONG DeCommitFreeBlockThreshold; + ULONGLONG DeCommitTotalFreeThreshold; + ULONGLONG LockPrefixTable; // VA + ULONGLONG MaximumAllocationSize; + ULONGLONG VirtualMemoryThreshold; + ULONGLONG ProcessAffinityMask; + DWORD ProcessHeapFlags; + WORD CSDVersion; + WORD DependentLoadFlags; + ULONGLONG EditList; // VA + ULONGLONG SecurityCookie; // VA + ULONGLONG SEHandlerTable; // VA + ULONGLONG SEHandlerCount; + } IMAGE_LOAD_CONFIG_DIR64_W7; +}; //namespace peconv + +#include diff --git a/server/2015Remote/libpeconv/peconv/load_config_util.h b/server/2015Remote/libpeconv/peconv/load_config_util.h new file mode 100644 index 0000000..52b01be --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/load_config_util.h @@ -0,0 +1,42 @@ +/** +* @file +* @brief Fetching Load Config Directory and recognizing its version. +*/ + +#pragma once +#include + +#include "buffer_util.h" +#include "load_config_defs.h" + +namespace peconv { + + /** + A version of Load Config Directory. + */ + typedef enum { + LOAD_CONFIG_NONE = 0, /**< Load Config Directory not found */ + LOAD_CONFIG_W7_VER = 7, /**< Load Config Directory in the Windows 7 version */ + LOAD_CONFIG_W8_VER = 8, /**< Load Config Directory in the Windows 8 version */ + LOAD_CONFIG_W10_VER = 10, /**< Load Config Directory in the Windows 10 version */ + LOAD_CONFIG_UNK_VER = -1 /**< Load Config Directory in an unknown version */ + } t_load_config_ver; + + /** + Get a pointer to the Load Config Directory within the given PE. + \param buffer : a buffer containing the PE file in a Virtual format + \param buf_size : size of the buffer + \return a pointer to the Load Config Directory, NULL if the given PE does not have this directory + */ + BYTE* get_load_config_ptr(BYTE* buffer, size_t buf_size); + + /** + Detect which version of Load Config Directory was used in the given PE. + \param buffer : a buffer containing the PE file in a Virtual format + \param buf_size : size of the buffer + \param ld_config_ptr : pointer to the Load Config Directory within the given PE + \return detected version of Load Config Directory + */ + t_load_config_ver get_load_config_version(BYTE* buffer, size_t buf_size, BYTE* ld_config_ptr); + +}; // namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/pe_dumper.h b/server/2015Remote/libpeconv/peconv/pe_dumper.h new file mode 100644 index 0000000..156caa6 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/pe_dumper.h @@ -0,0 +1,49 @@ +/** +* @file +* @brief Dumping PE from the memory buffer into a file. +*/ + +#pragma once + +#include +#include "exports_mapper.h" + +namespace peconv { + + /** + A mode in which the PE fille be dumped. + */ + typedef enum { + PE_DUMP_AUTO = 0, /**< autodetect which dump mode is the most suitable for the given input */ + PE_DUMP_VIRTUAL,/**< dump as it is in the memory (virtual) */ + PE_DUMP_UNMAP, /**< convert to the raw format: using raw sections' headers */ + PE_DUMP_REALIGN, /**< convert to the raw format: by realigning raw sections' headers to be the same as virtual (useful if the PE was unpacked in memory) */ + PE_DUMP_MODES_COUNT /**< total number of the dump modes */ + } t_pe_dump_mode; + + /** + Detect dump mode that is the most suitable for the given input. + \param buffer : the buffer containing the PE to be dumped. + \param buffer_size : the size of the given buffer + */ + t_pe_dump_mode detect_dump_mode(IN const BYTE* buffer, IN size_t buffer_size); + + /** + Dumps PE from the fiven buffer into a file. It expects the module base and size to be given. + \param outputFilePath : name of the file where the dump should be saved + \param buffer : the buffer containing the PE to be dumped. WARNING: the buffer may be preprocessed before dumping. + \param buffer_size : the size of the given buffer + \param module_base : the base to which the PE buffer was relocated + \param dump_mode : specifies in which format the PE should be dumped. If the mode was set to PE_DUMP_AUTO, it autodetects mode and returns the detected one. + \param exportsMap : optional. If exportsMap is supplied, it will try to recover destroyed import table of the PE, basing on the supplied map of exported functions. + */ + bool dump_pe( + IN LPCTSTR outputFilePath, + IN OUT BYTE* buffer, + IN size_t buffer_size, + IN const ULONGLONG module_base, + IN OUT t_pe_dump_mode &dump_mode, + IN OPTIONAL const peconv::ExportsMapper* exportsMap = nullptr + ); + +};// namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/pe_hdrs_helper.h b/server/2015Remote/libpeconv/peconv/pe_hdrs_helper.h new file mode 100644 index 0000000..ee957d4 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/pe_hdrs_helper.h @@ -0,0 +1,248 @@ +/** +* @file +* @brief Wrappers over various fields in the PE header. Read, write, parse PE headers. +*/ + +#pragma once + +#include +#include "buffer_util.h" + +#ifndef PAGE_SIZE +#define PAGE_SIZE 0x1000 +#endif + +namespace peconv { + /** + Maximal size of the PE header. + */ + const ULONGLONG MAX_HEADER_SIZE = PAGE_SIZE; + + template + INT_TYPE round_up_to_unit(const INT_TYPE size, const INT_TYPE unit) + { + if (unit == 0) { + return size; + } + INT_TYPE units_count = size / unit; + INT_TYPE rounded_size = units_count * unit; + if (rounded_size < size) { + rounded_size += unit; + } + return rounded_size; + } + + /** + Fetch image size from headers. + */ + DWORD get_image_size(IN const BYTE *payload); + + /** + Change the Image Size in Optional Header to the given one. + */ + bool update_image_size(IN OUT BYTE* payload, IN DWORD new_img_size); + + /** + Fetch architecture from the NT headers. Checks for bad pointers. + */ + WORD get_nt_hdr_architecture(IN const BYTE *pe_buffer); + + /** + Wrapper for get_nt_hdr_architecture. Returns true if the PE file is 64 bit. + */ + bool is64bit(IN const BYTE *pe_buffer); + + /** + Fetch pointer to the NT headers of the PE file. + Checks for bad pointers. If buffer_size is set, validates pointers against the buffer size. + */ + BYTE* get_nt_hdrs( + IN const BYTE *pe_buffer, + IN OPTIONAL size_t buffer_size=0 //if buffer_size=0 means size unknown + ); + + /** + Wrapper for get_nt_headers. Automatically detects if the PE is 32 bit - if not, returns null pointer. + */ + IMAGE_NT_HEADERS32* get_nt_hdrs32(IN const BYTE *pe_buffer); + + /** + Wrapper for get_nt_headers. Automatically detects if the PE is 64 bit - if not, returns null pointer. + */ + IMAGE_NT_HEADERS64* get_nt_hdrs64(IN const BYTE *pe_buffer); + + /** + Fetches optional header of the PE. Validates pointers against buffer size. + */ + LPVOID get_optional_hdr(IN const BYTE* payload, IN const size_t buffer_size); + + /** + Fetches file header of the PE. Validates pointers against buffer size. + */ + const IMAGE_FILE_HEADER* get_file_hdr( + IN const BYTE* payload, + IN const size_t buffer_size + ); + + /** + Fetch the size of headers (from Optional Header). + */ + DWORD get_hdrs_size(IN const BYTE *pe_buffer); + + /** + get Data Directory entry of the given number. If the entry is not filled and allow_empty is not set, it returns null pointer. + */ + IMAGE_DATA_DIRECTORY* get_directory_entry(IN const BYTE* pe_buffer, IN DWORD dir_id, IN bool allow_empty = false); + + /** + Get pointer to the Data Directory content of the given number. Automatically cast to the chosen type. + */ + template + IMAGE_TYPE_DIRECTORY* get_type_directory(IN HMODULE modulePtr, IN DWORD dir_id) + { + IMAGE_DATA_DIRECTORY *my_dir = peconv::get_directory_entry((const BYTE*)modulePtr, dir_id); + if (!my_dir) return nullptr; + + DWORD dir_addr = my_dir->VirtualAddress; + if (dir_addr == 0) return nullptr; + + return (IMAGE_TYPE_DIRECTORY*)(dir_addr + (ULONG_PTR)modulePtr); + } + + /** + Get pointer to the Export Directory. + */ + IMAGE_EXPORT_DIRECTORY* get_export_directory(IN HMODULE modulePtr); + + // Fetch Image Base from Optional Header. + ULONGLONG get_image_base(IN const BYTE *pe_buffer); + + /** + Change the Image Base in Optional Header to the given one. + */ + bool update_image_base(IN OUT BYTE* payload, IN ULONGLONG destImageBase); + + /** + Get RVA of the Entry Point from the Optional Header. + */ + DWORD get_entry_point_rva(IN const BYTE *pe_buffer); + + /** + Change the Entry Point RVA in the Optional Header to the given one. + */ + bool update_entry_point_rva(IN OUT BYTE *pe_buffer, IN DWORD ep); + + /** + Get number of sections from the File Header. It does not validate if this the actual number. + */ + size_t get_sections_count( + IN const BYTE* buffer, + IN const size_t buffer_size + ); + + /** + Checks if the section headers are reachable. It does not validate sections alignment. + */ + bool is_valid_sections_hdr_offset(IN const BYTE* buffer, IN const size_t buffer_size); + + /** + Gets pointer to the section header of the given number. + */ + PIMAGE_SECTION_HEADER get_section_hdr( + IN const BYTE* pe_buffer, + IN const size_t buffer_size, + IN size_t section_num + ); + + /** + Fetch the PE Characteristics from the File Header. + */ + WORD get_file_characteristics(IN const BYTE* payload); + + /** + Check if the module is a DLL (basing on the Characteristcs in the header). + */ + bool is_module_dll(IN const BYTE* payload); + + /** + Check if the module is a .NET executable + */ + bool is_dot_net(BYTE *pe_buffer, size_t pe_buffer_size); + + /** + Fetch the DLL Characteristics from the Optional Header. + */ + WORD get_dll_characteristics(IN const BYTE* payload); + + /** + Set the PE subsystem in the header. + */ + bool set_subsystem(IN OUT BYTE* payload, IN WORD subsystem); + + /** + Get the PE subsystem from the header. + */ + WORD get_subsystem(IN const BYTE* payload); + + /** + Check if the PE has relocations Data Directory. + */ + bool has_relocations(IN const BYTE *pe_buffer); + + /** + Fetch the pointer to the .NET header (if exist). + */ + IMAGE_COR20_HEADER* get_dotnet_hdr( + IN const BYTE* pe_buffer, + IN size_t const buffer_size, + IN const IMAGE_DATA_DIRECTORY* dotNetDir + ); + + /** + Fetch section aligmenent from headers. Depending on the flag, it fetches either Raw Alignment or Virtual Alignment. + */ + DWORD get_sec_alignment(IN const BYTE* modulePtr, IN bool is_raw); + + /** + Change section aligmenent in headers. Depending on the flag, it sets either Raw Alignment or Virtual Alignment. + */ + bool set_sec_alignment(IN OUT BYTE* pe_buffer, IN bool is_raw, IN DWORD new_alignment); + + /** + Get size of virtual section from the headers (optionaly rounds it up to the Virtual Alignment) + */ + DWORD get_virtual_sec_size( + IN const BYTE* pe_hdr, + IN const PIMAGE_SECTION_HEADER sec_hdr, + IN bool rounded //if set, it rounds it up to the Virtual Alignment + ); + + /** + Get the last section (in a raw or virtual alignment) + \param pe_buffer : buffer with a PE + \param pe_size : size of the given PE + \param is_raw : If true, give the section with the highest Raw offset. If false, give the section with the highest Virtual offset. + */ + PIMAGE_SECTION_HEADER get_last_section(IN const PBYTE pe_buffer, IN size_t pe_size, IN bool is_raw); + + /** + Calculate full PE size (raw or virtual) using information from sections' headers. WARNING: it drops an overlay. + \param pe_buffer : a buffer containing a PE + \param pe_size : the size of the given buffer + \param is_raw : If true, the Raw alignment is used. If false, the Virtual alignment is used. + */ + DWORD calc_pe_size( + IN const PBYTE pe_buffer, + IN size_t pe_size, + IN bool is_raw + ); + + /** + Walk through sections headers checking if the sections beginnings and sizes are fitting the alignment (Virtual or Raw) + \param buffer : a buffer containing a PE + \param buffer_size : the size of the given buffer + \param is_raw : If true, the Raw alignment is checked. If false, the Virtual alignment is checked. + */ + bool is_valid_sectons_alignment(IN const BYTE* buffer, IN const SIZE_T buffer_size, IN bool is_raw); + +}; // namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/pe_loader.h b/server/2015Remote/libpeconv/peconv/pe_loader.h new file mode 100644 index 0000000..dda5cc4 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/pe_loader.h @@ -0,0 +1,42 @@ +/** +* @file +* @brief Loading PE from a file with the help of the custom loader. +*/ + +#pragma once + +#include "pe_raw_to_virtual.h" +#include "function_resolver.h" + +namespace peconv { + /** + Reads PE from the given buffer into memory and maps it into virtual format. + (Automatic raw to virtual conversion). + If the executable flag is true, the PE file is loaded into executable memory. + If the relocate flag is true, applies relocations. Does not load imports. + Automatically allocates buffer of the needed size (the size is returned in outputSize). The buffer can be freed by the function free_pe_buffer. + */ + BYTE* load_pe_module(BYTE* payload_raw, size_t r_size, OUT size_t &v_size, bool executable, bool relocate, ULONG_PTR desired_base = 0); + + /** + Reads PE from the given file into memory and maps it into vitual format. + (Automatic raw to virtual conversion). + If the executable flag is true, the PE file is loaded into executable memory. + If the relocate flag is true, applies relocations. Does not load imports. + Automatically allocates buffer of the needed size (the size is returned in outputSize). The buffer can be freed by the function free_pe_buffer. + */ + BYTE* load_pe_module(LPCTSTR filename, OUT size_t &v_size, bool executable, bool relocate, ULONG_PTR desired_base = 0); + + /** + Loads full PE from the raw buffer in a way in which it can be directly executed: remaps to virual format, applies relocations, loads imports. + Allows for supplying custom function resolver. + */ + BYTE* load_pe_executable(BYTE* payload_raw, size_t r_size, OUT size_t &v_size, t_function_resolver* import_resolver = nullptr, ULONG_PTR desired_base = 0); + + /** + Loads full PE from file in a way in which it can be directly executed: remaps to virtual format, applies relocations, loads imports. + Allows for supplying custom function resolver. + */ + BYTE* load_pe_executable(LPCTSTR filename, OUT size_t &v_size, t_function_resolver* import_resolver = nullptr); + +};// namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/pe_mode_detector.h b/server/2015Remote/libpeconv/peconv/pe_mode_detector.h new file mode 100644 index 0000000..0cbaff7 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/pe_mode_detector.h @@ -0,0 +1,46 @@ +/** +* @file +* @brief Detecting in which mode is the PE in the supplied buffer (i.e. raw, virtual). Analyzes PE features typical for particular modes. +*/ + +#pragma once + +#include + +#include "pe_hdrs_helper.h" + +namespace peconv { + + /** + check if the PE in the memory is in raw format + */ + bool is_pe_raw( + IN const BYTE* pe_buffer, + IN size_t pe_size + ); + + /** + check if Virtual section addresses are identical to Raw addresses (i.e. if the PE was realigned) + */ + bool is_pe_raw_eq_virtual( + IN const BYTE* pe_buffer, + IN size_t pe_size + ); + + /** + checks if the PE has sections that were unpacked/expanded in the memory + */ + bool is_pe_expanded( + IN const BYTE* pe_buffer, + IN size_t pe_size + ); + + /** + checks if the given section was unpacked in the memory + */ + bool is_section_expanded(IN const BYTE* pe_buffer, + IN size_t pe_size, + IN const PIMAGE_SECTION_HEADER sec + ); + +};// namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/pe_raw_to_virtual.h b/server/2015Remote/libpeconv/peconv/pe_raw_to_virtual.h new file mode 100644 index 0000000..9cfa2e3 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/pe_raw_to_virtual.h @@ -0,0 +1,30 @@ +/** +* @file +* @brief Converting PE from raw to virtual format. +*/ + +#pragma once + +#include +#include + +#include "buffer_util.h" + +namespace peconv { + + /** + Converts a raw PE supplied in a buffer to a virtual format. + If the executable flag is true (default), the PE file is loaded into executable memory. + Does not apply relocations. Does not load imports. + Automatically allocates buffer of the needed size (the size is returned in outputSize). The buffer can be freed by the function free_pe_module. + If the desired_base is defined (0 by default), it enforces allocation at the particular base. + */ + BYTE* pe_raw_to_virtual( + IN const BYTE* rawPeBuffer, + IN size_t rawPeSize, + OUT size_t &outputSize, + IN OPTIONAL bool executable = true, + IN OPTIONAL ULONG_PTR desired_base = 0 + ); + +}; // namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/pe_virtual_to_raw.h b/server/2015Remote/libpeconv/peconv/pe_virtual_to_raw.h new file mode 100644 index 0000000..fbecf3e --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/pe_virtual_to_raw.h @@ -0,0 +1,47 @@ +/** +* @file +* @brief Converting PE from virtual to raw format. +*/ + +#pragma once + +#include + +#include "buffer_util.h" + +namespace peconv { + + /** + Maps virtual image of PE to into raw. Automaticaly applies relocations. + Automatically allocates buffer of the needed size (the size is returned in outputSize). + \param payload : the PE in the Virtual format that needs to be converted into the Raw format + \param in_size : size of the input buffer (the PE in the Virtual format) + \param loadBase : the base to which the given PE was relocated + \param outputSize : the size of the output buffer (the PE in the Raw format) + \param rebuffer : if set (default), the input buffer is rebuffered and the original buffer is not modified. + \return a buffer of the outputSize, containing the Raw PE. The buffer can be freed by the function free_pe_module. + */ + BYTE* pe_virtual_to_raw( + IN BYTE* payload, + IN size_t in_size, + IN ULONGLONG loadBase, + OUT size_t &outputSize, + IN OPTIONAL bool rebuffer=true + ); + + /* + Modifies raw alignment of the PE to be the same as virtual alignment. + \param payload : the PE in the Virtual format that needs to be realigned + \param in_size : size of the input buffer + \param loadBase : the base to which the given PE was relocated + \param outputSize : the size of the output buffer (the PE in the Raw format) + \return a buffer of the outputSize, containing the realigned PE. The buffer can be freed by the function free_pe_module. + */ + BYTE* pe_realign_raw_to_virtual( + IN const BYTE* payload, + IN size_t in_size, + IN ULONGLONG loadBase, + OUT size_t &outputSize + ); + +};//namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/peb_lookup.h b/server/2015Remote/libpeconv/peconv/peb_lookup.h new file mode 100644 index 0000000..c7ae2e7 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/peb_lookup.h @@ -0,0 +1,40 @@ +/** +* @file +* @brief Functions for retrieving process information from PEB. +*/ + +#pragma once + +#include + +namespace peconv { + + /** + Gets handle to the given module via PEB. A low-level equivalent of `GetModuleHandleW`. + \param module_name : (optional) the name of the DLL loaded within the current process. If not set, the main module of the current process is used. + \return the handle of the DLL with given name, or, if the name was not given, the handle of the main module of the current process. + */ + HMODULE get_module_via_peb(IN OPTIONAL LPCWSTR module_name = nullptr); + + + /** + Gets size of the given module via PEB. + \param hModule : (optional) the base of the module which's size we want to retrieve. If not set, the main module of the current process is used. + \return the size of the given module. + */ + size_t get_module_size_via_peb(IN OPTIONAL HMODULE hModule = nullptr); + + /** + Sets the given module as the main module in the current PEB. + \param hModule : the module to be connected to the current PEB. + \return true if succeeded, false if failed + */ + bool set_main_module_in_peb(HMODULE hModule); + + /** + Gets the main module from the current PEB. + \return the main module connected to the current PEB. + */ + HMODULE get_main_module_via_peb(); +}; + diff --git a/server/2015Remote/libpeconv/peconv/relocate.h b/server/2015Remote/libpeconv/peconv/relocate.h new file mode 100644 index 0000000..7a7a2af --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/relocate.h @@ -0,0 +1,51 @@ +/** +* @file +* @brief Operating on PE file's relocations table. +*/ + +#pragma once + +#include + +namespace peconv { + + typedef struct _BASE_RELOCATION_ENTRY { + WORD Offset : 12; + WORD Type : 4; + } BASE_RELOCATION_ENTRY; + + class RelocBlockCallback + { + public: + RelocBlockCallback(bool _is64bit) + : is64bit(_is64bit) + { + } + + virtual bool processRelocField(ULONG_PTR relocField) = 0; + + protected: + bool is64bit; + }; + + // Processs the relocation table and make your own callback on each relocation field + bool process_relocation_table(IN PVOID modulePtr, IN SIZE_T moduleSize, IN RelocBlockCallback *callback); + + /** + Applies relocations on the PE in virtual format. Relocates it from the old base given to the new base given. + If 0 was supplied as the old base, it assumes that the old base is the ImageBase given in the header. + \param modulePtr : a buffer containing the PE to be relocated + \param moduleSize : the size of the given PE buffer + \param newBase : a base to which the PE should be relocated + \param oldBase : a base to which the PE is currently relocated (if not set, the imageBase from the header will be used) + */ + bool relocate_module(IN BYTE* modulePtr, IN SIZE_T moduleSize, IN ULONGLONG newBase, IN ULONGLONG oldBase = 0); + + /** + Checks if the given PE has a valid relocations table. + \param modulePtr : a buffer containing the PE to be checked + \param moduleSize : the size of the given PE buffer + */ + bool has_valid_relocation_table(IN const PBYTE modulePtr, IN const size_t moduleSize); + +};//namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/remote_pe_reader.h b/server/2015Remote/libpeconv/peconv/remote_pe_reader.h new file mode 100644 index 0000000..071f583 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/remote_pe_reader.h @@ -0,0 +1,134 @@ +/** +* @file +* @brief Reading from a PE module that is loaded within a remote process. +*/ + +#pragma once + +#include + +#include "pe_hdrs_helper.h" +#include "pe_virtual_to_raw.h" +#include "exports_mapper.h" +#include "pe_dumper.h" + +namespace peconv { + + bool fetch_region_info(HANDLE processHandle, LPVOID start_addr, MEMORY_BASIC_INFORMATION &page_info); + + /** + Fetch size of the memory region starting from the given address. + */ + size_t fetch_region_size(HANDLE processHandle, LPVOID start_addr); + + /** + Fetch the allocation base of the memory region with the supplied start address. + \param processHandle : handle of the process where the region of interest belongs + \param start_addr : the address inside the region of interest + \return the allocation base address of the memory region, or 0 if not found + */ + ULONGLONG fetch_alloc_base(HANDLE processHandle, LPVOID start_addr); + + /** + Wrapper over ReadProcessMemory. Requires a handle with privilege PROCESS_VM_READ. + If reading of the full buffer_size was not possible, it will keep trying to read a smaller chunk, decreasing requested size on each attempt, + till the minimal_size is reached (it is a workaround for errors such as FAULTY_HARDWARE_CORRUPTED_PAGE). + Returns how many bytes were successfuly read. + \param processHandle : handle of the process where the memory of interest belongs + \param start_addr : the address within the remote process to start reading from + \param buffer : the buffer where the read data will be stored + \param buffer_size : the size of the buffer, and the size that will be attempted to read + \param minimal_size : the minimal size that has to be read in order to consider the read successful + \return the number of bytes successfuly read + */ + size_t read_remote_memory(HANDLE processHandle, LPVOID start_addr, OUT BYTE* buffer, const size_t buffer_size, const SIZE_T minimal_size = 0x100); + + /** + Reads a single memory region (continuous, with the same access rights) within a given process, starting at the start_addr. + In case if it is inaccessible, if the flag force_access was set, it tries to force the access by temporarly changing the permissions. + Requires a handle with privilege PROCESS_QUERY_INFORMATION. In order for force_access to work, PROCESS_VM_OPERATION is additionally required. + step_size is passed to the underlying read_remote_memory. + \param processHandle : handle of the process where the memory of interest belongs + \param start_addr : the address within the remote process to start reading from + \param buffer : the buffer where the read data will be stored + \param buffer_size : the size of the buffer + \param force_access : if this flag is set, in case if the region is inaccassible (PAGE_NOACCESS) it will try to force the the read by changing the permissions, and applying the old ones back after reading. + WARNING: force_access should be used only on a suspended process, or a process relection, otherwise it may cause instability. + \param minimal_size : the minimal size that has to be read in order to consider the read successful (passed to read_remote_memory) + \return the number of bytes successfuly read + */ + size_t read_remote_region(HANDLE processHandle, LPVOID start_addr, OUT BYTE* buffer, const size_t buffer_size, const bool force_access, const SIZE_T minimal_size = 0x100); + + /** + Reads a full memory area within a given process, starting at the start_addr, till the buffer_size is exceeded. + The memory area can consist of multiple regions with various access rights. + In case if the region is inaccessible, if the flag force_access was set, it tries to force the access by temporarly changing the permissions. + On read failure the region is skipped, and the read is moving to the next one, leaving in the output buffer an empty space of the region size. + Requires a handle with privilege PROCESS_QUERY_INFORMATION. In order for force_access to work, PROCESS_VM_OPERATION is additionally required. + step_size is passed to the underlying read_remote_memory. + \param processHandle : handle of the process where the memory of interest belongs + \param start_addr : the address within the remote process to start reading from + \param buffer : the buffer where the read data will be stored + \param buffer_size : the size of the buffer + \param force_access : if this flag is set, in case if the region is inaccassible (PAGE_NOACCESS) it will try to force the the read by changing the permissions, and applying the old ones back after reading. + WARNING: force_access should be used only on a suspended process, or a process relection, otherwise it may cause instability. + \param minimal_size : the minimal size that has to be read in order to consider the read successful (passed to read_remote_memory) + \return the number of bytes successfuly read + */ + size_t read_remote_area(HANDLE processHandle, LPVOID start_addr, OUT BYTE* buffer, const size_t buffer_size, const bool force_access, const SIZE_T minimal_size = 0x100); + + /** + Reads a PE header of the remote module within the given process. Requires a valid output buffer to be supplied (buffer). + \param processHandle : handle of the process where the memory of interest belongs + \param moduleBase : the base address of the module within the remote process + \param buffer : the buffer where the read data will be stored + \param buffer_size : the size of the buffer + \param force_access : if this flag is set, in case if the region is inaccassible (PAGE_NOACCESS) it will try to force the the read by changing the permissions, and applying the old ones back after reading. + WARNING: force_access should be used only on a suspended process, or a process relection, otherwise it may cause instability. + */ + bool read_remote_pe_header(HANDLE processHandle, LPVOID moduleBase, OUT BYTE* buffer, const size_t bufferSize, bool force_access = false); + + /** + Reads a PE section with a given number (sectionNum) from the remote module within the given process. + The buffer of appropriate size is automatically allocated. After use, it should be freed by the function free_unaligned. + The size of the buffer is writen into sectionSize. + \param processHandle : the handle to the remote process + \param moduleBase : the base address of the module + \param sectionNum : number of the section to be read + \param sectionSize : the size of the read section (output) + \param roundup : if set, the section size is roundup to the alignment unit + \param force_access : if this flag is set, in case if the region is inaccassible (PAGE_NOACCESS) it will try to force the the read by changing the permissions, and applying the old ones back after reading. + WARNING: force_access should be used only on a suspended process, or a process relection, otherwise it may cause instability. + \return a buffer containing a copy of the section. + */ + peconv::UNALIGNED_BUF get_remote_pe_section(HANDLE processHandle, LPVOID moduleBase, const size_t sectionNum, OUT size_t §ionSize, bool roundup, bool force_access = false); + + /** + Reads PE file from the remote process into the supplied buffer. It expects the module base and size to be given. + */ + size_t read_remote_pe(const HANDLE processHandle, LPVOID moduleBase, const size_t moduleSize, OUT BYTE* buffer, const size_t bufferSize); + + /** + Dumps PE from the remote process into a file. It expects the module base and size to be given. + \param outputFilePath : the path where the dump will be saved + \param processHandle : the handle to the remote process + \param moduleBase : the base address of the module that needs to be dumped + \param dump_mode : specifies in which format the PE should be dumped. If the mode was set to PE_DUMP_AUTO, it autodetects mode and returns the detected one. + \param exportsMap : optional. If exportsMap is supplied, it will try to recover destroyed import table of the PE, basing on the supplied map of exported functions. + */ + bool dump_remote_pe( + IN LPCTSTR outputFilePath, + IN const HANDLE processHandle, + IN LPVOID moduleBase, + IN OUT t_pe_dump_mode &dump_mode, + IN OPTIONAL peconv::ExportsMapper* exportsMap = nullptr + ); + + /** + Retrieve the Image Size saved in the header of the remote PE. + \param processHandle : process from where we are reading + \param start_addr : a base address of the PE within the given process + */ + DWORD get_remote_image_size(IN const HANDLE processHandle, IN LPVOID start_addr); + +}; //namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/resource_parser.h b/server/2015Remote/libpeconv/peconv/resource_parser.h new file mode 100644 index 0000000..d9d85d1 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/resource_parser.h @@ -0,0 +1,25 @@ +/** +* @file +* @brief Parsing PE's resource directory. +*/ + +#pragma once +#include + +namespace peconv { + /** + A callback that will be executed by the function parse_resources when the Resource Entry was found. + */ + typedef bool(*t_on_res_entry_found) ( + BYTE* modulePtr, + IMAGE_RESOURCE_DIRECTORY_ENTRY *root_dir, + IMAGE_RESOURCE_DATA_ENTRY *curr_entry + ); + + /** + A function walking through the Resource Tree of the given PE. On each Resource Entry found, the callback is executed. + \param modulePtr : pointer to the buffer with the PE in a Virtual format + \param on_entry : a callback function executed on each Resource Entry + */ + bool parse_resources(BYTE* modulePtr, t_on_res_entry_found on_entry); +}; diff --git a/server/2015Remote/libpeconv/peconv/resource_util.h b/server/2015Remote/libpeconv/peconv/resource_util.h new file mode 100644 index 0000000..8b02fd5 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/resource_util.h @@ -0,0 +1,34 @@ +/** +* @file +* @brief Functions related to manual retrieving of PE resources. +*/ + +#pragma once + +#include +#include "buffer_util.h" + +namespace peconv { + + const LPSTR RT_RCDATA_A = MAKEINTRESOURCEA(10); + + /** + Maps a resource with the given id + type and copies its raw content into the output buffer. + If out_size is not zero, it reads maximum out_size of bytes. If out_size is zero, it reads the full resource. + The actual read size is returned back in out_size. + Automatically allocates a buffer of the required size. + If hInstance is NULL, it search the resource in the current module. Otherwise, it search in the given module. + */ + peconv::ALIGNED_BUF load_resource_data(OUT size_t &out_size, const int res_id, const LPSTR res_type = RT_RCDATA_A, HMODULE hInstance = nullptr); + + /** + Free the buffer with PE Resources, mapped by the function load_resource_data. + */ + void free_resource_data(peconv::ALIGNED_BUF buffer); + + /** + a helper function to get the module handle of the current DLL + */ + HMODULE get_current_module_handle(); + +}; //namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/tls_parser.h b/server/2015Remote/libpeconv/peconv/tls_parser.h new file mode 100644 index 0000000..10f3beb --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/tls_parser.h @@ -0,0 +1,41 @@ +/** +* @file +* @brief Functions related to TLS Callbacks +*/ + +#pragma once + +#include +#include + +namespace peconv { + + /** + A helper function, normalizing virtual addresses. It automatically detects if the given virtual address is VA or RVA, and converts it into RVA + \param imgBase : the base address to which the module was relocated + \param imgSize : the size of the image + \param virtualAddr : the virtual address (RVA or VA) that we want to convert (within the module described by imgBase and imgSize) + \param outRVA : the output of the conversion (RVA) + \return true if the conversion was successful, false otherwise + */ + bool virtual_addr_to_rva(IN const ULONGLONG imgBase, IN const DWORD imgSize, IN ULONGLONG virtualAddr, OUT DWORD &outRVA); + + /** + A function listing RVAs of all TLS callbacks that are present in the given module. + \param modulePtr : pointer to the buffer with the PE in a Virtual format, relocated to the load base + \param moduleSize : size of the given module (if 0 given, the imageSize from the PE headers will be used) + \param tls_callbacks : a vector of TLS callbacks addresses (as given in the TLS table) + \return number of TLS callbacks added to the list + */ + size_t list_tls_callbacks(IN PVOID modulePtr, IN size_t moduleSize, OUT std::vector &tls_callbacks); + + /** + A function running all the TLS callbacks that are present in the given module, one by one. + \param modulePtr : pointer to the buffer with the PE in a Virtual format, relocated to the load base + \param moduleSize : size of the given module (if 0 given, the imageSize from the PE headers will be used) + \param dwReason : a parameter (dwReason) that will be passed to the callback function + \return number of TLS callbacks executed + */ + size_t run_tls_callbacks(IN PVOID modulePtr, IN size_t moduleSize=0, IN DWORD dwReason = DLL_PROCESS_ATTACH); + +}; //namespace peconv diff --git a/server/2015Remote/libpeconv/peconv/unicode.h b/server/2015Remote/libpeconv/peconv/unicode.h new file mode 100644 index 0000000..a440176 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/unicode.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef UNICODE +#define tcout wcout +#define tcerr wcerr +#define tstring wstring +#else +#define tcout cout +#define tcerr cerr +#define tstring string +#endif // UNICODE diff --git a/server/2015Remote/libpeconv/peconv/util.h b/server/2015Remote/libpeconv/peconv/util.h new file mode 100644 index 0000000..9ee7d87 --- /dev/null +++ b/server/2015Remote/libpeconv/peconv/util.h @@ -0,0 +1,51 @@ +/** +* @file +* @brief Miscellaneous utility functions. +*/ + +#pragma once + +#include "file_util.h" +#include "resource_util.h" + +#ifdef _MSC_VER +#define PECONV_FORCEINLINE __forceinline +#define PECONV_TRY_EXCEPT_BLOCK_START __try { +#define PECONV_TRY_EXCEPT_BLOCK_END __except (EXCEPTION_EXECUTE_HANDLER) { +#else +#define PECONV_FORCEINLINE __attribute__((always_inline)) inline +#define PECONV_TRY_EXCEPT_BLOCK_START try { +#define PECONV_TRY_EXCEPT_BLOCK_END catch (...) { +#endif + + +namespace peconv { + /** + Checks if the given buffer is fully filled with the specified character. + \param cave_ptr : pointer to the buffer to be checked + \param cave_size : size of the buffer to be checked + \param padding_char : the required character + */ + bool is_padding(const BYTE* cave_ptr, size_t cave_size, const BYTE padding_char); + + /** + Wrapper for GetProcessId - for a backward compatibility with old versions of Windows + */ + DWORD get_process_id(HANDLE hProcess); + + /** + Verifies if the calling process has a defined access to the specified continuous range of memory, defined by areaStart and areaSize. + If the area includes pages that are not commited, or pages with access rights PAGE_GUARD | PAGE_NOACCESS, it is treated as inaccessible. + \param areaStart : A pointer to the first byte of the memory block + \param areaSize : The size of the memory block, in bytes. If this parameter is zero, the return value is false. + \param accessRights : The access rights to be checked + */ + bool is_mem_accessible(LPCVOID areaStart, SIZE_T areaSize, DWORD accessRights); + + /** + Verifies that the calling process has read access to the specified range of memory. + \param areaStart : A pointer to the first byte of the memory block + \param areaSize : The size of the memory block, in bytes. If this parameter is zero, the return value is true (bad pointer). + */ + bool is_bad_read_ptr(LPCVOID areaStart, SIZE_T areaSize); +}; \ No newline at end of file diff --git a/server/2015Remote/main.cpp b/server/2015Remote/main.cpp new file mode 100644 index 0000000..48c6668 --- /dev/null +++ b/server/2015Remote/main.cpp @@ -0,0 +1,236 @@ +#include "stdafx.h" +#ifdef _WIN64 +// Source code: https://github.com/hasherezade/pe_to_shellcode +#include +#include + +#include "peconv.h" +#include "resource.h" + +#define VERSION "1.2" +#include "peloader.h" + +#ifdef _DEBUG +#pragma comment(lib, "libpeconv/libpeconv_x64d.lib") +#else +#pragma comment(lib, "libpeconv/libpeconv_x64.lib") +#endif + +bool overwrite_hdr(BYTE *my_exe, size_t exe_size, DWORD raw, bool is64b) +{ + const size_t value_pos = 8; + size_t redir_size = 0; + BYTE* redir_code = nullptr; + + BYTE redir_code32_64[] = "\x4D" //dec ebp + "\x5A" //pop edx + "\x45" //inc ebp + "\x52" //push edx + "\xE8\x00\x00\x00\x00" //call + "\x5B" // pop ebx + "\x48\x83\xEB\x09" // sub ebx,9 + "\x53" // push ebx (Image Base) + "\x48\x81\xC3" // add ebx, + "\x59\x04\x00\x00" // value + "\xFF\xD3" // call ebx + "\xc3"; // ret + + BYTE redir_code32[] = "\x4D" //dec ebp + "\x5A" //pop edx + "\x45" //inc ebp + "\x52" //push edx + "\xE8\x00\x00\x00\x00" //call + "\x58" // pop eax + "\x83\xE8\x09" // sub eax,9 + "\x50" // push eax (Image Base) + "\x05" // add eax, + "\x59\x04\x00\x00" // value + "\xFF\xD0" // call eax + "\xc3"; // ret + + BYTE redir_code64[] = "\x4D\x5A" //pop r10 + "\x45\x52" //push r10 + "\xE8\x00\x00\x00\x00" //call + "\x59" // pop rcx + "\x48\x83\xE9\x09" // sub rcx,9 (rcx -> Image Base) + "\x48\x8B\xC1" // mov rax,rcx + "\x48\x05" // add eax, + "\x59\x04\x00\x00" // value + "\xFF\xD0" // call eax + "\xc3"; // ret + +#ifdef OLD_LOADER + redir_code = redir_code32_64; + redir_size = sizeof(redir_code32_64); +#else + redir_code = redir_code32; + redir_size = sizeof(redir_code32); + + if (is64b) { + redir_code = redir_code64; + redir_size = sizeof(redir_code64); + } +#endif + if (!redir_code) return false; + if (redir_size > MAX_REDIR_SIZE) { + std::cerr << "The selected redir stub exceed the maximal size: " << std::dec << MAX_REDIR_SIZE << "\n"; + return false; + } + size_t offset = redir_size - value_pos; + memcpy(redir_code + offset, &raw, sizeof(DWORD)); + + min_hdr_t* my_hdr = (min_hdr_t*)my_exe; + memcpy(my_hdr->redir, redir_code, redir_size); + my_hdr->load_status = LDS_CLEAN; + return true; +} + +BYTE* shellcodify(BYTE *my_exe, size_t exe_size, size_t &out_size, bool is64b) +{ + out_size = 0; + size_t stub_size = 0; + int res_id = is64b ? STUB64 : STUB32; + BYTE *stub = peconv::load_resource_data(stub_size, res_id); + if (!stub) { + std::cerr << "[ERROR] Stub not loaded" << std::endl; + return nullptr; + } + size_t ext_size = exe_size + stub_size; + BYTE *ext_buf = peconv::alloc_aligned(ext_size, PAGE_READWRITE); + if (!ext_buf) { + return nullptr; + } + memcpy(ext_buf, my_exe, exe_size); + memcpy(ext_buf + exe_size, stub, stub_size); + + DWORD raw_addr = exe_size; + overwrite_hdr(ext_buf, ext_size, raw_addr, is64b); + + out_size = ext_size; + return ext_buf; +} + +template +bool has_tls_callbacks(BYTE *my_exe, size_t exe_size) +{ + IMAGE_DATA_DIRECTORY* tls_dir = peconv::get_directory_entry(my_exe, IMAGE_DIRECTORY_ENTRY_TLS); + if (!tls_dir) return false; + + IMAGE_TLS_DIRECTORY* tls = peconv::get_type_directory((HMODULE)my_exe, IMAGE_DIRECTORY_ENTRY_TLS); + if (!tls) return false; + + ULONGLONG base = peconv::get_image_base(my_exe); + ULONGLONG callback_rva = tls->AddressOfCallBacks; + if (callback_rva > base) { + callback_rva -= base; + } + if (!peconv::validate_ptr(my_exe, exe_size, my_exe + callback_rva, sizeof(ULONGLONG))) { + return false; + } + ULONGLONG *callback_addr = (ULONGLONG *)(my_exe + callback_rva); + if (callback_addr == 0) { + return false; + } + if (*callback_addr == 0) { + return false; + } + return true; +} + +bool is_supported_pe(BYTE *my_exe, size_t exe_size) +{ + if (!my_exe) return false; + if (!peconv::has_relocations(my_exe)) { + std::cerr << "[ERROR] The PE must have relocations!" << std::endl; + return false; + } + if (peconv::get_subsystem(my_exe) != IMAGE_SUBSYSTEM_WINDOWS_GUI) { + std::cout << "[INFO] This is a console application." << std::endl; + } + IMAGE_DATA_DIRECTORY* dotnet_dir = peconv::get_directory_entry(my_exe, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR); + if (dotnet_dir) { + std::cerr << "[ERROR] .NET applications are not supported!" << std::endl; + return false; + } + IMAGE_DATA_DIRECTORY* tls_dir = peconv::get_directory_entry(my_exe, IMAGE_DIRECTORY_ENTRY_TLS); + if (tls_dir) { + bool has_callback = false; + if (!peconv::is64bit(my_exe)) { + if (has_tls_callbacks(my_exe, exe_size)) { + has_callback = true; + } + } + else { + if (has_tls_callbacks(my_exe, exe_size)) { + has_callback = true; + } + } + if (has_callback) { + std::cout << "[INFO] This application has TLS callbacks." << std::endl; + } + } + return true; +} + +bool is_supported_pe(const std::string &in_path) +{ + std::cout << "Reading module from: " << in_path << std::endl; + size_t exe_size = 0; + BYTE *my_exe = peconv::load_pe_module(in_path.c_str(), exe_size, false, false); + if (!my_exe) { + std::cerr << "[ERROR] Could not read the input file!" << std::endl; + return false; + } + + bool is_ok = is_supported_pe(my_exe, exe_size); + peconv::free_pe_buffer(my_exe); + + if (!is_ok) { + std::cerr << "[ERROR] Not supported input file!" << std::endl; + return false; + } + return true; +} + +int pe_2_shellcode(const std::string &in_path, const std::string &out_str) +{ + if (!is_supported_pe(in_path)) { + return -2; + } + + size_t exe_size = 0; + BYTE *my_exe = peconv::load_pe_module(in_path.c_str(), exe_size, false, false); + if (!my_exe) { + std::cout << "[-] Could not read the input file!" << std::endl; + return -1; + } + + bool is64b = peconv::is64bit(my_exe); + size_t ext_size = 0; + BYTE *ext_buf = shellcodify(my_exe, exe_size, ext_size, is64b); + if (!ext_buf) { + std::cerr << "[ERROR] Adding the stub failed!" << std::endl; + peconv::free_pe_buffer(my_exe); + return -3; + } + // remap pe to raw == virtual, so that remapping on load will not be required + peconv::t_pe_dump_mode dump_mode = peconv::PE_DUMP_REALIGN; + ULONGLONG current_base = peconv::get_image_base(ext_buf); + if (peconv::dump_pe(out_str.c_str(), ext_buf, ext_size, current_base, dump_mode)) { + std::cout << "[INFO] Saved as: " << out_str << std::endl; + } + else { + std::cerr << "[ERROR] Failed to save the output!" << std::endl; + } + peconv::free_pe_buffer(my_exe); + peconv::free_aligned(ext_buf); + return 0; +} + +#else + +int pe_2_shellcode(const std::string& in_path, const std::string& out_str) { + return -1; // Don't support x86 master program +} + +#endif diff --git a/server/2015Remote/peloader.h b/server/2015Remote/peloader.h new file mode 100644 index 0000000..222e273 --- /dev/null +++ b/server/2015Remote/peloader.h @@ -0,0 +1,14 @@ +#pragma once +#include + +#define MAX_REDIR_SIZE 32 + +#define LDS_CLEAN 0 +#define LDS_LOADED 1 +#define LDS_RUN 2 +#define LDS_ATTACHED 3 + +typedef struct _min_hdr { + BYTE redir[MAX_REDIR_SIZE]; + BYTE load_status; +} min_hdr_t; diff --git a/server/2015Remote/pwd_gen.cpp b/server/2015Remote/pwd_gen.cpp index 3a71186..58259e1 100644 --- a/server/2015Remote/pwd_gen.cpp +++ b/server/2015Remote/pwd_gen.cpp @@ -146,9 +146,9 @@ std::string deriveKey(const std::string& password, const std::string& hardwareID std::string getDeviceID() { - std::string hardwareID = getHardwareID(); - std::string hashedID = hashSHA256(hardwareID); - std::string deviceID = getFixedLengthID(hashedID); + static std::string hardwareID = getHardwareID(); + static std::string hashedID = hashSHA256(hardwareID); + static std::string deviceID = getFixedLengthID(hashedID); return deviceID; } diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index 19b1f66..76d52b1 100644 Binary files a/server/2015Remote/resource.h and b/server/2015Remote/resource.h differ diff --git a/server/2015Remote/stub2/stub32.bin b/server/2015Remote/stub2/stub32.bin new file mode 100644 index 0000000..a1b78c0 Binary files /dev/null and b/server/2015Remote/stub2/stub32.bin differ diff --git a/server/2015Remote/stub2/stub64.bin b/server/2015Remote/stub2/stub64.bin new file mode 100644 index 0000000..c7240f3 Binary files /dev/null and b/server/2015Remote/stub2/stub64.bin differ