Feature: Support converting PE using pe_to_shellcode

This commit is contained in:
yuanyuanxiang
2025-11-13 05:23:01 +08:00
parent 924aa1d7e1
commit 086afb36b4
49 changed files with 2664 additions and 10 deletions

View File

@@ -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*

View File

@@ -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)

Binary file not shown.

View File

@@ -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);
}

View File

@@ -346,4 +346,5 @@ public:
afx_msg void OnObfsShellcodeBin();
afx_msg void OnShellcodeAesBin();
afx_msg void OnShellcodeTestAesBin();
afx_msg void OnToolReloadPlugins();
};

View File

@@ -79,7 +79,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(IncludePath)</IncludePath>
<IncludePath>$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(ProjectDir)libpeconv;$(IncludePath)</IncludePath>
<LibraryPath>$(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(SolutionDir);$(SolutionDir)..\SimpleRemoter;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -90,7 +90,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<LibraryPath>$(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(SolutionDir);$(SolutionDir)..\SimpleRemoter;$(LibraryPath)</LibraryPath>
<IncludePath>$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(IncludePath)</IncludePath>
<IncludePath>$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(ProjectDir)libpeconv;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -250,6 +250,8 @@
<None Include="res\rcedit.exe" />
<None Include="res\string.ico" />
<None Include="res\upx.exe" />
<None Include="stub2\stub32.bin" />
<None Include="stub2\stub64.bin" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\client\Audio.h" />
@@ -365,6 +367,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="main.cpp" />
<ClCompile Include="proxy\ProxyConnectServer.cpp" />
<ClCompile Include="proxy\ProxyMapDlg.cpp" />
<ClCompile Include="pwd_gen.cpp">

View File

@@ -55,6 +55,7 @@
<ClCompile Include="CGridDialog.cpp" />
<ClCompile Include="CWalletDlg.cpp" />
<ClCompile Include="CRcEditDlg.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\client\Audio.h" />
@@ -203,6 +204,8 @@
<None Include="..\..\Release\SCLoader.exe" />
<None Include="..\..\x64\Release\SCLoader.exe" />
<None Include="res\rcedit.exe" />
<None Include="stub2\stub32.bin" />
<None Include="stub2\stub64.bin" />
</ItemGroup>
<ItemGroup>
<Text Include="..\..\ReadMe.md" />

View File

@@ -64,6 +64,7 @@ CBuildDlg::CBuildDlg(CWnd* pParent)
, m_strPort(_T(""))
, m_strFindden(FLAG_FINDEN)
, m_sGroupName(_T("default"))
, m_strEncryptIP(_T("<EFBFBD><EFBFBD>"))
{
}
@@ -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("<EFBFBD><EFBFBD>");
if (encrypt && startup != Startup_InjSC)
g_ConnectAddress.Encrypt();
try {
// <20><><EFBFBD>±<EFBFBD>ʶ
@@ -290,7 +293,7 @@ void CBuildDlg::OnBnClickedOk()
run_upx_async(GetParent()->GetSafeHwnd(), upx, strSeverFile.GetString(), true);
MessageBox("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>UPXѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>Ϣ<EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD>\r\n<EFBFBD>ļ<EFBFBD>λ<EFBFBD><EFBFBD>: " + strSeverFile + tip, "<EFBFBD><EFBFBD>ʾ", 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 ת<><D7AA><EFBFBD>쳣, <20><EFBFBD><ECB3A3><EFBFBD><EFBFBD>: ") + CString(std::to_string(ret).c_str()),
"<EFBFBD><EFBFBD>ʾ", MB_ICONINFORMATION);
}
MessageBox("<EFBFBD><EFBFBD><EFBFBD>ɳɹ<EFBFBD>! <20>ļ<EFBFBD>λ<EFBFBD><CEBB>:\r\n" + strSeverFile + tip, "<EFBFBD><EFBFBD>ʾ", MB_ICONINFORMATION);
}
SAFE_DELETE_ARRAY(szBuffer);
@@ -382,7 +391,8 @@ BOOL CBuildDlg::OnInitDialog()
m_ComboCompress.InsertString(CLIENT_COMPRESS_NONE, "<EFBFBD><EFBFBD>");
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("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD>̵<EFBFBD>ַ", "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǻ<EFBFBD><EFBFBD>߷<EFBFBD>:");
if (dlg.DoModal() == IDOK ) {
if (m_strEncryptIP != "<EFBFBD><EFBFBD>" && m_strEncryptIP != "<EFBFBD><EFBFBD>") {
MessageBoxA("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǻ<EFBFBD><EFBFBD>߷<EFBFBD>!", "<EFBFBD><EFBFBD>ʾ", MB_ICONINFORMATION);
}else
m_strEncryptIP = dlg.m_str;
}
}

View File

@@ -42,4 +42,6 @@ public:
afx_msg void OnHelpFindden();
CEdit m_EditGroup;
CString m_sGroupName;
CString m_strEncryptIP;
afx_msg void OnMenuEncryptIp();
};

View File

@@ -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); //创建应用程序可以直接写入的、与设备无关的位图

Binary file not shown.

Binary file not shown.

View File

@@ -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"

View File

@@ -0,0 +1,88 @@
/**
* @file
* @brief Definitions of the used buffer types. Functions for their allocation and deallocation.
*/
#pragma once
#include <windows.h>
#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

View File

@@ -0,0 +1,27 @@
/**
* @file
* @brief Functions related to finding caves in the loaded PE file.
*/
#pragma once
#include <windows.h>
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

View File

@@ -0,0 +1,61 @@
/**
* @file
* @brief Parsing and filling the Delayload Import Table.
*/
#pragma once
#include <windows.h>
#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

View File

@@ -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);
};

View File

@@ -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 <windows.h>
#include <string>
#include <algorithm>
#include <set>
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

View File

@@ -0,0 +1,50 @@
/**
* @file
* @brief Searching specific functions in PE's Exports Table.
*/
#pragma once
#include <windows.h>
#include "pe_hdrs_helper.h"
#include "function_resolver.h"
#include "exports_mapper.h"
#include <string>
#include <vector>
#include <map>
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<std::string> &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

View File

@@ -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 <windows.h>
#include <string>
#include <map>
#include <set>
#include <sstream>
#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<ULONGLONG>(modulePtr));
}
/**
Find the set of Exported Functions that can be mapped to the given VA. Includes forwarders, and function aliases.
*/
const std::set<ExportedFunc>* find_exports_by_va(ULONGLONG va) const
{
std::map<ULONGLONG, std::set<ExportedFunc>>::const_iterator itr = va_to_func.find(va);
if (itr != va_to_func.end()) {
const std::set<ExportedFunc> &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<ULONGLONG, DllInfo>::const_iterator firstGreater = dll_base_to_info.upper_bound(func_rva);
std::map<ULONGLONG, DllInfo>::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<ULONGLONG, DllInfo>::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<std::string>& 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<ExportedFunc>* exp_set = find_exports_by_va(va);
if (exp_set == NULL) return NULL;
std::set<ExportedFunc>::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<PDWORD, DWORD> &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<ULONGLONG, std::set<ExportedFunc>> va_to_func;
/**
A map associating an exported functions with its forwarders.
*/
std::map<ExportedFunc, std::set<ExportedFunc>> forwarders_lookup;
/**
A map associating an exported functions with its VA.
*/
std::map<ExportedFunc, ULONGLONG> func_to_va;
/**
A map associating DLL shortname with the base(s) at which it was mapped
*/
std::map<std::string, std::set<ULONGLONG>> dll_shortname_to_base;
std::map<ULONGLONG, DllInfo> dll_base_to_info;
};
}; //namespace peconv

View File

@@ -0,0 +1,60 @@
/**
* @file
* @brief Functions related to operations on files. Wrappers for read/write.
*/
#pragma once
#include <windows.h>
#include <iostream>
#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

View File

@@ -0,0 +1,20 @@
/**
* @file
* @brief Functions related to finding a base to which the module was relocated.
*/
#pragma once
#include <windows.h>
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);
};

View File

@@ -0,0 +1,119 @@
/**
* @file
* @brief Functions and classes responsible for fixing Import Table. A definition of ImportedDllCoverage class.
*/
#pragma once
#include <windows.h>
#include <string>
#include <set>
#include <map>
#include <iterator>
#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<DWORD, ULONGLONG> 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<ULONGLONG>& _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<ULONGLONG, std::set<ExportedFunc>> addrToFunc;
/**
Addresses of the functions not found in the mapped DLL
*/
std::set<ULONGLONG> 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<ULONGLONG> &addresses;
/**
A supplied exportsMap. Only used as a lookup, no changes applied.
*/
const peconv::ExportsMapper& exportsMap;
};
}

View File

@@ -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 <windows.h>
#include <string>
#include <map>
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<std::string, HMODULE> nameToModule;
};
}; //namespace peconv

View File

@@ -0,0 +1,146 @@
/**
* @file
* @brief Functions related to hooking the loaded PE. Reditecting/replacing a functions with another.
*/
#pragma once
#include <windows.h>
#include "function_resolver.h"
#include <iostream>
#include <string>
#include <map>
#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<std::string, FARPROC> hooks_map;
std::map<std::string, std::string> 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

View File

@@ -0,0 +1,103 @@
/**
* @file
* @brief Parsing and filling the Import Table.
*/
#pragma once
#include <windows.h>
#include <set>
#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<DWORD, peconv::ExportedFunc*>::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<DWORD, peconv::ExportedFunc*> 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<DWORD>& thunk_rvas);
bool collect_imports(IN BYTE* modulePtr, IN SIZE_T moduleSize, OUT ImportsCollection &collection);
}; // namespace peconv

View File

@@ -0,0 +1,94 @@
/**
* @file
* @brief A definition of ImportsUneraser class - for recovery of a partialy erased Import Table.
*/
#pragma once
#include <windows.h>
#include <string>
#include <set>
#include <map>
#include <iterator>
#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 <typename FIELD_T, typename IMAGE_THUNK_DATA_T>
bool fillImportNames(IN OUT IMAGE_IMPORT_DESCRIPTOR* lib_desc,
IN const FIELD_T ordinal_flag,
IN std::map<ULONGLONG, std::set<ExportedFunc>> &addr_to_func,
OUT OPTIONAL ImpsNotCovered* not_covered
);
template <typename FIELD_T>
bool findNameInBinaryAndFill(IMAGE_IMPORT_DESCRIPTOR* lib_desc,
LPVOID call_via_ptr,
LPVOID thunk_ptr,
const FIELD_T ordinal_flag,
std::map<ULONGLONG, std::set<ExportedFunc>> &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 <typename FIELD_T, typename IMAGE_THUNK_DATA_T>
bool writeFoundFunction(IMAGE_THUNK_DATA_T* desc, const FIELD_T ordinal_flag, const ExportedFunc &foundFunc);
PBYTE modulePtr;
size_t moduleSize;
bool is64;
};
}

View File

@@ -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 <windows.h>
#include <pshpack4.h>
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 <poppack.h>

View File

@@ -0,0 +1,42 @@
/**
* @file
* @brief Fetching Load Config Directory and recognizing its version.
*/
#pragma once
#include <windows.h>
#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

View File

@@ -0,0 +1,49 @@
/**
* @file
* @brief Dumping PE from the memory buffer into a file.
*/
#pragma once
#include <windows.h>
#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

View File

@@ -0,0 +1,248 @@
/**
* @file
* @brief Wrappers over various fields in the PE header. Read, write, parse PE headers.
*/
#pragma once
#include <windows.h>
#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 <typename INT_TYPE>
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 <typename IMAGE_TYPE_DIRECTORY>
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

View File

@@ -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

View File

@@ -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 <windows.h>
#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

View File

@@ -0,0 +1,30 @@
/**
* @file
* @brief Converting PE from raw to virtual format.
*/
#pragma once
#include <windows.h>
#include <stdio.h>
#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

View File

@@ -0,0 +1,47 @@
/**
* @file
* @brief Converting PE from virtual to raw format.
*/
#pragma once
#include <windows.h>
#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

View File

@@ -0,0 +1,40 @@
/**
* @file
* @brief Functions for retrieving process information from PEB.
*/
#pragma once
#include <windows.h>
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();
};

View File

@@ -0,0 +1,51 @@
/**
* @file
* @brief Operating on PE file's relocations table.
*/
#pragma once
#include <windows.h>
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

View File

@@ -0,0 +1,134 @@
/**
* @file
* @brief Reading from a PE module that is loaded within a remote process.
*/
#pragma once
#include <windows.h>
#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 &sectionSize, 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

View File

@@ -0,0 +1,25 @@
/**
* @file
* @brief Parsing PE's resource directory.
*/
#pragma once
#include <windows.h>
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);
};

View File

@@ -0,0 +1,34 @@
/**
* @file
* @brief Functions related to manual retrieving of PE resources.
*/
#pragma once
#include <windows.h>
#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

View File

@@ -0,0 +1,41 @@
/**
* @file
* @brief Functions related to TLS Callbacks
*/
#pragma once
#include <windows.h>
#include<vector>
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<ULONGLONG> &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

View File

@@ -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

View File

@@ -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);
};

236
server/2015Remote/main.cpp Normal file
View File

@@ -0,0 +1,236 @@
#include "stdafx.h"
#ifdef _WIN64
// Source code: https://github.com/hasherezade/pe_to_shellcode
#include <windows.h>
#include <iostream>
#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 <next_line>
"\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 <next_line>
"\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 <next_line>
"\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 <typename IMAGE_TLS_DIRECTORY>
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<IMAGE_TLS_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<IMAGE_TLS_DIRECTORY32>(my_exe, exe_size)) {
has_callback = true;
}
}
else {
if (has_tls_callbacks<IMAGE_TLS_DIRECTORY64>(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

View File

@@ -0,0 +1,14 @@
#pragma once
#include <Windows.h>
#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;

View File

@@ -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;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.