添加项目文件。
This commit is contained in:
31
Etw Syscall.sln
Normal file
31
Etw Syscall.sln
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31729.503
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Etw Syscall", "Etw Syscall\Etw Syscall.vcxproj", "{BA6E6161-8930-47CA-B77A-3ED745455174}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{BA6E6161-8930-47CA-B77A-3ED745455174}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BA6E6161-8930-47CA-B77A-3ED745455174}.Debug|x64.Build.0 = Debug|x64
|
||||
{BA6E6161-8930-47CA-B77A-3ED745455174}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{BA6E6161-8930-47CA-B77A-3ED745455174}.Debug|x86.Build.0 = Debug|Win32
|
||||
{BA6E6161-8930-47CA-B77A-3ED745455174}.Release|x64.ActiveCfg = Release|x64
|
||||
{BA6E6161-8930-47CA-B77A-3ED745455174}.Release|x64.Build.0 = Release|x64
|
||||
{BA6E6161-8930-47CA-B77A-3ED745455174}.Release|x86.ActiveCfg = Release|Win32
|
||||
{BA6E6161-8930-47CA-B77A-3ED745455174}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9D6C13D0-304E-4F4C-9D6D-0800B6C18219}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
384
Etw Syscall/Etw Syscall.cpp
Normal file
384
Etw Syscall/Etw Syscall.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
// Etw Syscall.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
|
||||
//
|
||||
|
||||
#include "head.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
int g_iNumOfThreads = 0;
|
||||
DWORD* g_lpdwThreadsIdArray = NULL;
|
||||
/*
|
||||
* 维护两个个状态表
|
||||
* thread id <-> 处理器id[0],切换状态[1]
|
||||
*/
|
||||
//std::map<int, std::vector<int>> g_dwThreadsWithProcesserMap;
|
||||
/*
|
||||
* 处理器id <-> threadid[0]
|
||||
*/
|
||||
std::map<int, int> g_dwProcesserWithThreadsMap;
|
||||
/*
|
||||
* 线程id <-> 进程id
|
||||
*/
|
||||
std::map<int, DWORD> g_dwProcessWithThreadidsMap;
|
||||
/*
|
||||
* 进程pid <-> 进程名字
|
||||
*/
|
||||
std::map<DWORD, std::wstring> g_dwProcessNameWithProcessIdMap;
|
||||
BOOLEAN
|
||||
WINAPI
|
||||
Initialize(
|
||||
VOID
|
||||
);
|
||||
BOOL
|
||||
WINAPI
|
||||
GetSystemFunctionName(
|
||||
IN ULONG64 pAddress,
|
||||
OUT CHAR* pName
|
||||
);
|
||||
enum SwitchState
|
||||
{
|
||||
_SwitchState_Initialized = 0,
|
||||
_SwitchState_Ready = 1,
|
||||
_SwitchState_Running = 2,
|
||||
_SwitchState_Standby = 3,
|
||||
_SwitchState_Terminated = 4,
|
||||
_SwitchState_Waiting = 5,
|
||||
_SwitchState_Transition = 6,
|
||||
_SwitchState_DeferredReady = 6,
|
||||
};
|
||||
|
||||
std::wstring GetProcessNameByPid(DWORD pPid) {
|
||||
HANDLE hProceesSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (hProceesSnap != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
PROCESSENTRY32 pe32;
|
||||
pe32.dwSize = sizeof(pe32);
|
||||
BOOL hProcess = Process32First(hProceesSnap, &pe32);
|
||||
while (hProcess)
|
||||
{
|
||||
//printf("%ws %d\n", pe32.szExeFile, pe32.th32ProcessID);
|
||||
if (pe32.th32ProcessID == pPid) {
|
||||
CloseHandle(hProceesSnap);
|
||||
return std::wstring(pe32.szExeFile);
|
||||
}
|
||||
hProcess = Process32Next(hProceesSnap, &pe32);
|
||||
}
|
||||
CloseHandle(hProceesSnap);
|
||||
}
|
||||
return std::wstring(L"unknown");
|
||||
}
|
||||
/*
|
||||
* 这个没用,因为只有在线程为等待状态并且是阻塞的情况下才有效
|
||||
*/
|
||||
/*
|
||||
* VOID initFunctions()
|
||||
{
|
||||
HMODULE hModule = LoadLibrary(L"ntdll.dll");
|
||||
ZwQueryInformationThread = (ZWQUERYINFORMATIONTHREAD)GetProcAddress(hModule, "ZwQueryInformationThread");
|
||||
}
|
||||
DWORD GetThreadSysCallNumByHandle(DWORD pThreadId) {
|
||||
typedef struct _THREAD_LAST_SYSCALL_INFORMATION
|
||||
{
|
||||
PVOID FirstArgument;
|
||||
USHORT SystemCallNumber;
|
||||
} THREAD_LAST_SYSCALL_INFORMATION, * PTHREAD_LAST_SYSCALL_INFORMATION;
|
||||
THREAD_LAST_SYSCALL_INFORMATION lastSystemCall = {0};
|
||||
|
||||
HANDLE ThreadHandle = OpenThread(THREAD_QUERY_INFORMATION, FALSE, pThreadId);
|
||||
if (ThreadHandle != INVALID_HANDLE_VALUE && ThreadHandle != NULL) {
|
||||
ZwQueryInformationThread(
|
||||
ThreadHandle,
|
||||
ThreadLastSystemCall,
|
||||
&lastSystemCall,
|
||||
sizeof(THREAD_LAST_SYSCALL_INFORMATION),
|
||||
NULL
|
||||
);
|
||||
CloseHandle(ThreadHandle);
|
||||
printf("lastSystemCall.SystemCallNumber: %d thread id %d \n", lastSystemCall.SystemCallNumber, pThreadId);
|
||||
return lastSystemCall.SystemCallNumber;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
std::map<std::wstring, bool> g_StopDetectList;
|
||||
std::map<DWORD, std::map<std::string, bool>> g_injectList;
|
||||
VOID WINAPI NewProcessAdd(DWORD pThreadId) {
|
||||
HANDLE ThreadHandle = OpenThread(THREAD_QUERY_INFORMATION, FALSE, pThreadId);
|
||||
if (ThreadHandle != INVALID_HANDLE_VALUE && ThreadHandle != NULL) {
|
||||
DWORD ProcessId = GetProcessIdOfThread(ThreadHandle);
|
||||
if (ProcessId != NULL) {
|
||||
std::wstring TempStr = GetProcessNameByPid(ProcessId);
|
||||
if (TempStr.find(L"unknown") == std::wstring::npos) {
|
||||
g_dwProcessWithThreadidsMap[pThreadId] = ProcessId;
|
||||
g_dwProcessNameWithProcessIdMap[ProcessId] = TempStr;
|
||||
g_StopDetectList[TempStr] = false;
|
||||
}
|
||||
}
|
||||
CloseHandle(ThreadHandle);
|
||||
}
|
||||
}
|
||||
|
||||
VOID WINAPI EtwEventCallback(PEVENT_RECORD EventRecord) {
|
||||
EVENT_HEADER& hdr = EventRecord->EventHeader;
|
||||
std::string lpOldThrState = std::string();
|
||||
|
||||
UCHAR cpuId = EventRecord->BufferContext.ProcessorNumber;
|
||||
ULONG dwOldThrId = 0, dwNewThrId = 0;
|
||||
INT64 CycleTime = hdr.TimeStamp.QuadPart;
|
||||
if (EventRecord->EventHeader.EventDescriptor.Opcode == 36) {
|
||||
if (EventRecord->UserData) {
|
||||
CSwitch* pThrSwitch = (CSwitch*)EventRecord->UserData;
|
||||
_ASSERT(EventRecord->UserDataLength == sizeof(CSwitch));
|
||||
dwNewThrId = pThrSwitch->NewThreadId;
|
||||
dwOldThrId = pThrSwitch->OldThreadId;
|
||||
|
||||
g_dwProcesserWithThreadsMap[cpuId] = dwNewThrId;
|
||||
if (g_dwProcessWithThreadidsMap.count(dwNewThrId) == 0) {
|
||||
NewProcessAdd(dwNewThrId);
|
||||
}
|
||||
if (g_dwProcessWithThreadidsMap.count(dwOldThrId) == 0) {
|
||||
NewProcessAdd(dwOldThrId);
|
||||
}
|
||||
if (g_dwProcessWithThreadidsMap.count(dwOldThrId) != 0 && pThrSwitch->OldThreadState == _SwitchState_Terminated) {
|
||||
if (g_dwProcessNameWithProcessIdMap.count(g_dwProcessWithThreadidsMap[dwOldThrId]) != 0) {
|
||||
g_dwProcessNameWithProcessIdMap.erase(g_dwProcessWithThreadidsMap[dwOldThrId]);
|
||||
}
|
||||
g_dwProcessWithThreadidsMap.erase(dwOldThrId);
|
||||
}
|
||||
/*
|
||||
switch (pThrSwitch->OldThreadState)
|
||||
{
|
||||
case 0: lpOldThrState = std::string("Initialized"); break;
|
||||
case 1: lpOldThrState = std::string("Ready"); break;
|
||||
case 2: lpOldThrState = std::string("Running"); break;
|
||||
case 3: lpOldThrState = std::string("Standby"); break;
|
||||
case 4: lpOldThrState = std::string("Terminated"); break;
|
||||
case 5: lpOldThrState = std::string("Waiting"); break;
|
||||
case 6: lpOldThrState = std::string("Transition"); break;
|
||||
case 7: lpOldThrState = std::string("DeferredReady"); break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
//这边维护一个容器状态
|
||||
if (g_dwThreadsWithProcesserMap.count(dwNewThrId) == 0) {
|
||||
//没有被记录的,创建新线程
|
||||
g_dwThreadsWithProcesserMap[dwNewThrId].push_back(cpuId);
|
||||
g_dwThreadsWithProcesserMap[dwNewThrId].push_back(_SwitchState_Running);
|
||||
}
|
||||
else if (g_dwThreadsWithProcesserMap.count(dwOldThrId) == 0 && pThrSwitch->OldThreadState != _SwitchState_Terminated) {
|
||||
//老的没有被记录
|
||||
g_dwThreadsWithProcesserMap[dwOldThrId].push_back(cpuId);
|
||||
g_dwThreadsWithProcesserMap[dwOldThrId].push_back(pThrSwitch->OldThreadState);
|
||||
}
|
||||
else if (g_dwThreadsWithProcesserMap.count(dwOldThrId) != 0 && pThrSwitch->OldThreadState != _SwitchState_Terminated) {
|
||||
//更新老的状态
|
||||
g_dwThreadsWithProcesserMap[dwOldThrId][0] = -1;
|
||||
g_dwThreadsWithProcesserMap[dwOldThrId][1] = pThrSwitch->OldThreadState;
|
||||
}
|
||||
else if (g_dwThreadsWithProcesserMap.count(dwOldThrId) != 0 && pThrSwitch->OldThreadState == _SwitchState_Terminated) {
|
||||
//老的线程结束了,删除这个hashmap
|
||||
g_dwThreadsWithProcesserMap.erase(dwOldThrId);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
for (int i = 0; i < g_iNumOfThreads; i++) {
|
||||
if (g_lpdwThreadsIdArray[i] == dwNewThrId || g_lpdwThreadsIdArray[i] == dwOldThrId) {
|
||||
printf("[EtwContextSwitch] Processor: %i, New thread ID: %i, Old thread ID: %i (state: %s).\r\n", cpuId, dwNewThrId, dwOldThrId, lpOldThrState.c_str());
|
||||
//DebugBreak();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
else if (EventRecord->EventHeader.EventDescriptor.Opcode == 51) {
|
||||
//syscall enter
|
||||
if (g_dwProcesserWithThreadsMap.count(cpuId) == 0 ||
|
||||
g_dwProcessWithThreadidsMap.count(g_dwProcesserWithThreadsMap[cpuId]) == 0 ||
|
||||
g_dwProcessNameWithProcessIdMap.count(g_dwProcessWithThreadidsMap[g_dwProcesserWithThreadsMap[cpuId]]) == 0)
|
||||
return;
|
||||
DWORD ThreadId = g_dwProcesserWithThreadsMap[cpuId];
|
||||
std::wstring ProcessName = g_dwProcessNameWithProcessIdMap[g_dwProcessWithThreadidsMap[ThreadId]];
|
||||
PVOID* SsdtFucntionName = (PVOID*)EventRecord->UserData;
|
||||
|
||||
if (g_StopDetectList[ProcessName])
|
||||
return;
|
||||
|
||||
if (ProcessName.find(L"Toy") == std::wstring::npos)
|
||||
return;
|
||||
//printf("SsdtFucntionName: %p \n", SsdtFucntionName[0]);
|
||||
//DWORD SysCallNum = GetThreadSysCallNumByHandle(ThreadId);
|
||||
char NameStack[100];
|
||||
memset(NameStack, 0x0, sizeof(NameStack));
|
||||
if (GetSystemFunctionName((ULONG64)SsdtFucntionName[0], NameStack)) {
|
||||
std::string StringNameStack = std::string(NameStack);
|
||||
if (strcmp("NtCreateFile", NameStack) == 0 ||
|
||||
strcmp("NtCreateThreadEx", NameStack) == 0 ||
|
||||
strcmp("NtAllocateVirtualMemory", NameStack) == 0 ||
|
||||
strcmp("NtWriteVirtualMemory", NameStack) == 0 ||
|
||||
strcmp("NtOpenProcess", NameStack) == 0 ||
|
||||
strcmp("NtOpenProcessToken", NameStack) == 0 ||
|
||||
strcmp("NtCreateThread", NameStack) == 0) {
|
||||
int iter_num = 0;
|
||||
for (auto& value : g_injectList[g_dwProcessWithThreadidsMap[ThreadId]]) {
|
||||
if (StringNameStack == value.first) {
|
||||
g_injectList[g_dwProcessWithThreadidsMap[ThreadId]][value.first] = true;
|
||||
}
|
||||
// if(g_injectList[g_dwProcessWithThreadidsMap[ThreadId]][value.first])
|
||||
// iter_num += 1;
|
||||
}
|
||||
//if (iter_num == g_injectList[g_dwProcessWithThreadidsMap[ThreadId]].size())
|
||||
// g_StopDetectList[ProcessName] = true,
|
||||
// printf("检测到注入 进程名字: %ws \n", ProcessName.c_str());
|
||||
printf("cpuid: %d Process: %ws ThreadId: %d syscall: %s \n", cpuId, ProcessName.c_str(), ThreadId, NameStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DWORD WINAPI TraceThread(LPVOID lpParam) {
|
||||
TRACEHANDLE hConsumer = (TRACEHANDLE)lpParam;
|
||||
BOOL bRetVal = FALSE;
|
||||
DWORD dwCurProcId = GetCurrentProcessId();
|
||||
if (!hConsumer) return -1;
|
||||
|
||||
// Enumerate all the threads of this process and add it to the global list
|
||||
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
THREADENTRY32 te = { 0 };
|
||||
int count = 0;
|
||||
te.dwSize = sizeof(te);
|
||||
bRetVal = Thread32First(h, &te);
|
||||
|
||||
while (bRetVal) {
|
||||
te.dwSize = sizeof(te);
|
||||
bRetVal = Thread32Next(h, &te);
|
||||
}
|
||||
|
||||
// Allocate enough memory
|
||||
//g_lpdwThreadsIdArray = new DWORD[dwNumOfThreads];
|
||||
//g_iNumOfThreads = dwNumOfThreads;
|
||||
|
||||
bRetVal = Thread32First(h, &te);
|
||||
while (bRetVal) {
|
||||
//if (te.th32OwnerProcessID == dwCurProcId)
|
||||
// g_lpdwThreadsIdArray[count++] = te.th32ThreadID;
|
||||
if (te.th32OwnerProcessID != NULL) {
|
||||
if (g_dwProcessWithThreadidsMap.count(te.th32ThreadID) == 0) {
|
||||
std::wstring TempStr = GetProcessNameByPid(te.th32OwnerProcessID);
|
||||
if (TempStr.find(L"unknown") == std::wstring::npos) {
|
||||
g_dwProcessWithThreadidsMap[te.th32ThreadID] = te.th32OwnerProcessID;
|
||||
g_dwProcessNameWithProcessIdMap[te.th32OwnerProcessID] = TempStr;
|
||||
g_StopDetectList[TempStr] = false;
|
||||
|
||||
g_injectList[te.th32OwnerProcessID]["NtOpenProcessToken"] = 0;
|
||||
g_injectList[te.th32OwnerProcessID]["NtCreateFile"] = 0;
|
||||
g_injectList[te.th32OwnerProcessID]["NtOpenProcess"] = 0;
|
||||
g_injectList[te.th32OwnerProcessID]["NtAllocateVirtualMemory"] = 0;
|
||||
g_injectList[te.th32OwnerProcessID]["NtWriteVirtualMemory"] = 0;
|
||||
g_injectList[te.th32OwnerProcessID]["NtCreateThreadEx"] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
te.dwSize = sizeof(te);
|
||||
bRetVal = Thread32Next(h, &te);
|
||||
}
|
||||
CloseHandle(h);
|
||||
}
|
||||
|
||||
printf("开始trace");
|
||||
ProcessTrace(&hConsumer, 1, NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
DWORD WINAPI TestThread1(LPVOID lpParam) {
|
||||
LARGE_INTEGER curTime = { 0 };
|
||||
while (TRUE) {
|
||||
DWORD dwKey = 0;
|
||||
QueryPerformanceCounter(&curTime);
|
||||
dwKey = _rotr(curTime.LowPart, curTime.HighPart) * 56 / 11;
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
bool StartEtwTrace() {
|
||||
PEVENT_TRACE_PROPERTIES pEtwProp = NULL;
|
||||
EVENT_TRACE_LOGFILE etwLogFile = { 0 };
|
||||
wchar_t providerName[] = KERNEL_LOGGER_NAME;
|
||||
DWORD dwCbProvName = 0,
|
||||
dwEtwPropSize = 0;
|
||||
TRACEHANDLE hTrace = NULL;
|
||||
TRACEHANDLE hConsumerTrace = NULL;
|
||||
BOOL bRetVal = FALSE;
|
||||
DWORD dwLastErr = 0;
|
||||
|
||||
dwCbProvName = (DWORD)(wcslen(providerName) + 1) * sizeof(TCHAR);
|
||||
|
||||
// Allocate the memory for the ETW data structure
|
||||
dwEtwPropSize = sizeof(EVENT_TRACE_PROPERTIES) + dwCbProvName;
|
||||
pEtwProp = (PEVENT_TRACE_PROPERTIES)new BYTE[dwEtwPropSize];
|
||||
RtlZeroMemory(pEtwProp, dwEtwPropSize);
|
||||
|
||||
pEtwProp->Wnode.ClientContext = 1;
|
||||
pEtwProp->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
||||
pEtwProp->Wnode.Guid = SystemTraceControlGuid;
|
||||
pEtwProp->Wnode.BufferSize = dwEtwPropSize;
|
||||
RtlCopyMemory(((LPBYTE)pEtwProp + sizeof(EVENT_TRACE_PROPERTIES)), providerName, dwCbProvName);
|
||||
|
||||
bRetVal = ControlTrace(NULL, providerName, pEtwProp, EVENT_TRACE_CONTROL_STOP);
|
||||
if (bRetVal != ERROR_WMI_INSTANCE_NOT_FOUND) {
|
||||
DWORD dwOffset = FIELD_OFFSET(EVENT_TRACE_PROPERTIES, BufferSize);
|
||||
RtlZeroMemory((LPBYTE)pEtwProp + dwOffset, dwEtwPropSize - dwOffset);
|
||||
}
|
||||
pEtwProp->EnableFlags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_SYSTEMCALL;
|
||||
pEtwProp->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
|
||||
pEtwProp->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
|
||||
|
||||
|
||||
wprintf(L"Initializing the ETW Consumer... ");
|
||||
bRetVal = StartTrace(&hTrace, providerName, pEtwProp);
|
||||
|
||||
if (bRetVal == ERROR_SUCCESS) {
|
||||
RtlZeroMemory(&etwLogFile, sizeof(EVENT_TRACE_LOGFILE));
|
||||
etwLogFile.LoggerName = (LPWSTR)providerName;
|
||||
etwLogFile.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_REAL_TIME;
|
||||
etwLogFile.EventRecordCallback = EtwEventCallback;
|
||||
|
||||
hConsumerTrace = OpenTrace(&etwLogFile);
|
||||
dwLastErr = GetLastError();
|
||||
bRetVal = (hConsumerTrace != (TRACEHANDLE)INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : dwLastErr;
|
||||
}
|
||||
|
||||
if (bRetVal == ERROR_SUCCESS) {
|
||||
DWORD dwThrId = 0;
|
||||
HANDLE hThread = NULL;
|
||||
printf("Success.\r\n");
|
||||
|
||||
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TestThread1, (LPVOID)NULL, 0, &dwThrId);
|
||||
CloseHandle(hThread);
|
||||
|
||||
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TraceThread, (LPVOID)hConsumerTrace, 0, &dwThrId);
|
||||
CloseHandle(hThread);
|
||||
|
||||
printf("Press ENTER key to stop the trace and exit...");
|
||||
rewind(stdin);
|
||||
getwchar();
|
||||
}
|
||||
else
|
||||
printf("Error %i.\r\n", (LPVOID)bRetVal);
|
||||
|
||||
|
||||
// Stop our Kernel Logger consumer
|
||||
if (hConsumerTrace != (TRACEHANDLE)INVALID_HANDLE_VALUE)
|
||||
bRetVal = ControlTrace(hConsumerTrace, NULL, pEtwProp, EVENT_TRACE_CONTROL_STOP);
|
||||
return bRetVal == ERROR_SUCCESS;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
Initialize();
|
||||
//SYSCALL::Resolve_sys_Call();
|
||||
//initFunctions();
|
||||
StartEtwTrace();
|
||||
//printf("GetProcessNameByPid(ProcessId) %ws \n", GetProcessNameByPid(25560).c_str());
|
||||
std::cout << "Hello World!\n";
|
||||
}
|
||||
155
Etw Syscall/Etw Syscall.vcxproj
Normal file
155
Etw Syscall/Etw Syscall.vcxproj
Normal file
@@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{ba6e6161-8930-47ca-b77a-3ed745455174}</ProjectGuid>
|
||||
<RootNamespace>EtwSyscall</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Etw Syscall.cpp" />
|
||||
<ClCompile Include="symbols.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="head.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
30
Etw Syscall/Etw Syscall.vcxproj.filters
Normal file
30
Etw Syscall/Etw Syscall.vcxproj.filters
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Etw Syscall.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="symbols.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="head.h">
|
||||
<Filter>源文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
88
Etw Syscall/head.h
Normal file
88
Etw Syscall/head.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <iostream>
|
||||
#include <crtdbg.h>
|
||||
|
||||
#define INITGUID // Causes definition of SystemTraceControlGuid in evntrace.h. Has to be done once per executable/library.
|
||||
|
||||
#include <Evntrace.h>
|
||||
#include <Evntcons.h>
|
||||
|
||||
#include <crtdbg.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <tdh.h>
|
||||
#pragma comment(lib, "tdh.lib")
|
||||
|
||||
#include "dbghelp.h"
|
||||
#pragma comment(lib, "Dbghelp.lib")
|
||||
|
||||
#include "psapi.h"
|
||||
#pragma comment(lib, "Psapi.lib")
|
||||
|
||||
#include <direct.h>
|
||||
#pragma comment(lib,"URlmon")
|
||||
|
||||
struct CSwitch
|
||||
{
|
||||
UINT32 NewThreadId; // + 0x00
|
||||
UINT32 OldThreadId; // + 0x04
|
||||
INT8 NewThreadPriority; // + 0x08
|
||||
INT8 OldThreadPriority; // + 0x09
|
||||
UINT8 PreviousCState; // + 0x0A
|
||||
INT8 SpareByte; // + 0x0B
|
||||
INT8 OldThreadWaitReason; // + 0x0C
|
||||
INT8 OldThreadWaitMode; // + 0x0D
|
||||
INT8 OldThreadState; // + 0x0E
|
||||
INT8 OldThreadWaitIdealProcessor; // + 0x0F
|
||||
UINT32 NewThreadWaitTime; // + 0x10
|
||||
UINT32 Reserved; // + 0x14
|
||||
};
|
||||
C_ASSERT(sizeof(CSwitch) == 0x18);
|
||||
typedef enum _THREADINFOCLASS {
|
||||
ThreadBasicInformation = 0,
|
||||
ThreadTimes = 1,
|
||||
ThreadPriority = 2,
|
||||
ThreadBasePriority = 3,
|
||||
ThreadAffinityMask = 4,
|
||||
ThreadImpersonationToken = 5,
|
||||
ThreadDescriptorTableEntry = 6,
|
||||
ThreadEnableAlignmentFaultFixup = 7,
|
||||
ThreadEventPair_Reusable = 8,
|
||||
ThreadQuerySetWin32StartAddress = 9,
|
||||
ThreadZeroTlsCell = 10,
|
||||
ThreadPerformanceCount = 11,
|
||||
ThreadAmILastThread = 12,
|
||||
ThreadIdealProcessor = 13,
|
||||
ThreadPriorityBoost = 14,
|
||||
ThreadSetTlsArrayAddress = 15, // Obsolete
|
||||
ThreadIsIoPending = 16,
|
||||
ThreadHideFromDebugger = 17,
|
||||
ThreadBreakOnTermination = 18,
|
||||
ThreadSwitchLegacyState = 19,
|
||||
ThreadIsTerminated = 20,
|
||||
ThreadLastSystemCall = 21,
|
||||
ThreadIoPriority = 22,
|
||||
ThreadCycleTime = 23,
|
||||
ThreadPagePriority = 24,
|
||||
ThreadActualBasePriority = 25,
|
||||
ThreadTebInformation = 26,
|
||||
ThreadCSwitchMon = 27, // Obsolete
|
||||
ThreadCSwitchPmu = 28,
|
||||
ThreadWow64Context = 29,
|
||||
ThreadGroupInformation = 30,
|
||||
ThreadUmsInformation = 31, // UMS
|
||||
ThreadCounterProfiling = 32,
|
||||
ThreadIdealProcessorEx = 33,
|
||||
ThreadCpuAccountingInformation = 34,
|
||||
ThreadSuspendCount = 35,
|
||||
ThreadActualGroupAffinity = 41,
|
||||
ThreadDynamicCodePolicyInfo = 42,
|
||||
MaxThreadInfoClass = 45,
|
||||
} THREADINFOCLASS;
|
||||
typedef NTSTATUS(WINAPI* ZWQUERYINFORMATIONTHREAD)(
|
||||
_In_ HANDLE ThreadHandle,
|
||||
_In_ THREADINFOCLASS ThreadInformationClass,
|
||||
_In_ PVOID ThreadInformation,
|
||||
_In_ ULONG ThreadInformationLength,
|
||||
_Out_opt_ PULONG ReturnLength
|
||||
);
|
||||
55
Etw Syscall/libpeconv-master/.appveyor.yml
Normal file
55
Etw Syscall/libpeconv-master/.appveyor.yml
Normal file
@@ -0,0 +1,55 @@
|
||||
shallow_clone: true
|
||||
|
||||
os:
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2019
|
||||
|
||||
platform: x64
|
||||
- x64
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
install:
|
||||
- set PATH=C:\Program Files\CMake\bin;%PATH%
|
||||
|
||||
build:
|
||||
verbosity: detailed
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
- Debug
|
||||
|
||||
environment:
|
||||
artifactName: $(APPVEYOR_PROJECT_NAME)-$(APPVEYOR_REPO_COMMIT)-$(CONFIGURATION)
|
||||
matrix:
|
||||
- env_arch: "x64"
|
||||
- env_arch: "x86"
|
||||
|
||||
before_build:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if [%env_arch%]==[x64] (
|
||||
cmake .. -A x64 )
|
||||
- if [%env_arch%]==[x86] (
|
||||
cmake .. -A Win32 )
|
||||
- cmake -DCMAKE_INSTALL_PREFIX:PATH=%APPVEYOR_BUILD_FOLDER%/%APPVEYOR_REPO_COMMIT% ..
|
||||
|
||||
build_script:
|
||||
- cmake --build . --config %CONFIGURATION% --target install
|
||||
|
||||
test_script:
|
||||
- cp "..\tests\test_case3\bin\test_case3_32.exe" %APPVEYOR_BUILD_FOLDER%/%APPVEYOR_REPO_COMMIT%/
|
||||
- cp "..\tests\test_case3\bin\test_case3_64.exe" %APPVEYOR_BUILD_FOLDER%/%APPVEYOR_REPO_COMMIT%/
|
||||
- if [%env_arch%]==[x64] (
|
||||
cp "..\tests\test_case2\payload.dll" %APPVEYOR_BUILD_FOLDER%/%APPVEYOR_REPO_COMMIT%/ )
|
||||
- ctest -V
|
||||
|
||||
after_test:
|
||||
- mkdir %artifactName%
|
||||
- cp -r %APPVEYOR_BUILD_FOLDER%/%APPVEYOR_REPO_COMMIT%/* %artifactName%
|
||||
|
||||
artifacts:
|
||||
- path: build\%artifactName%
|
||||
|
||||
38
Etw Syscall/libpeconv-master/.github/workflows/main.yml
vendored
Normal file
38
Etw Syscall/libpeconv-master/.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# This is a basic workflow to help you get started with Actions
|
||||
|
||||
name: Doxygen Action
|
||||
|
||||
# Controls when the action will run. Triggers the workflow on push or pull request
|
||||
# events but only for the master branch
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
build:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Doxygen Action
|
||||
uses: mattnotmitt/doxygen-action@v1.1.0
|
||||
with:
|
||||
# Path to Doxyfile
|
||||
doxyfile-path: "./Doxyfile" # default is ./Doxyfile
|
||||
# Working directory
|
||||
working-directory: "." # default is .
|
||||
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./docs/html
|
||||
1
Etw Syscall/libpeconv-master/.gitignore
vendored
Normal file
1
Etw Syscall/libpeconv-master/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
docs
|
||||
38
Etw Syscall/libpeconv-master/CMakeLists.txt
Normal file
38
Etw Syscall/libpeconv-master/CMakeLists.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
|
||||
project ( peconv )
|
||||
option(PECONV_BUILD_TESTING "enable testing for peconv" ON)
|
||||
option(PECONV_LIB_INSTALL "Enable install" ON )
|
||||
|
||||
# modules:
|
||||
set ( M_PECONV_LIB "libpeconv" )
|
||||
set ( M_PECONV_TEST "tests" )
|
||||
set ( M_PE_UNMAPPER "pe_unmapper" )
|
||||
set ( M_RUN_PE "run_pe" )
|
||||
|
||||
# modules paths:
|
||||
set ( PECONV_DIR "${CMAKE_SOURCE_DIR}/${M_PECONV_LIB}" CACHE PATH "PEConvLib main path" )
|
||||
set ( UNMAPPER_DIR "${CMAKE_SOURCE_DIR}/${M_PE_UNMAPPER}" CACHE PATH "PEUnmapper main path" )
|
||||
set ( RUNPE_DIR "${CMAKE_SOURCE_DIR}/${M_RUN_PE}" CACHE PATH "RunPE main path" )
|
||||
|
||||
# Add sub-directories
|
||||
#
|
||||
# libs
|
||||
add_subdirectory ( libpeconv )
|
||||
set ( PECONV_LIB $<TARGET_FILE:libpeconv> CACHE PATH "PEConvLib library path" )
|
||||
|
||||
#demos:
|
||||
add_subdirectory ( pe_unmapper )
|
||||
add_dependencies ( pe_unmapper libpeconv )
|
||||
|
||||
add_subdirectory ( run_pe )
|
||||
add_dependencies ( run_pe libpeconv )
|
||||
|
||||
# Setup testing
|
||||
if(PECONV_BUILD_TESTING)
|
||||
enable_testing()
|
||||
|
||||
# executables
|
||||
add_subdirectory ( ${M_PECONV_TEST} )
|
||||
add_dependencies ( ${M_PECONV_TEST} libpeconv )
|
||||
endif()
|
||||
2568
Etw Syscall/libpeconv-master/Doxyfile
Normal file
2568
Etw Syscall/libpeconv-master/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
25
Etw Syscall/libpeconv-master/LICENSE
Normal file
25
Etw Syscall/libpeconv-master/LICENSE
Normal file
@@ -0,0 +1,25 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017-2021, hasherezade
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
77
Etw Syscall/libpeconv-master/README.md
Normal file
77
Etw Syscall/libpeconv-master/README.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# libPeConv
|
||||
[](https://ci.appveyor.com/project/hasherezade/libpeconv)
|
||||
[](https://www.codacy.com/manual/hasherezade/libpeconv?utm_source=github.com&utm_medium=referral&utm_content=hasherezade/libpeconv&utm_campaign=Badge_Grade)
|
||||
|
||||
[](https://opensource.org/licenses/BSD-2-Clause)
|
||||
[](https://github.com/hasherezade/libpeconv)
|
||||
|
||||
*A library to load and manipulate PE files.*
|
||||
|
||||
### Objectives
|
||||
|
||||
The goal of libPEConv was to create a "swiss army knife" for custom loading of PE files. It gathers various helper functions that you can quickly integrate in your own loader. For example: remapping sections, applying relocations, loading imports, parsing resources.
|
||||
|
||||
Not only it allows for loading PE files, but also for customizing of some steps, i.e. IAT hooking (by providing custom IAT resolvers), and functions redirection. Yet, it is NOT focused on inline hooking and should not be confused with libraries such as MS Detours or MinHook.
|
||||
|
||||
LibPeConv can be used for creating PE binders, as it allows to load a PE directly from the resource, and integrate it as if it was a local code.
|
||||
|
||||
As well it can help you in dumping PEs from the memory, and rebuilding their IATs.
|
||||
|
||||
### Basic example
|
||||
|
||||
*The simplest usecase*: use libPeConv to manually load and run an EXE of you choice.
|
||||
|
||||
```C
|
||||
#include <Windows.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <peconv.h> // include libPeConv header
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::cout << "Args: <path to the exe>" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
LPCSTR pe_path = argv[1];
|
||||
|
||||
// manually load the PE file using libPeConv:
|
||||
size_t v_size = 0;
|
||||
#ifdef LOAD_FROM_PATH
|
||||
//if the PE is dropped on the disk, you can load it from the file:
|
||||
BYTE* my_pe = peconv::load_pe_executable(pe_path, v_size);
|
||||
#else
|
||||
size_t bufsize = 0;
|
||||
BYTE *buffer = peconv::load_file(pe_path, bufsize);
|
||||
|
||||
// if the file is NOT dropped on the disk, you can load it directly from a memory buffer:
|
||||
BYTE* my_pe = peconv::load_pe_executable(buffer, bufsize, v_size);
|
||||
#endif
|
||||
if (!my_pe) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if the loaded PE needs to access resources, you may need to connect it to the PEB:
|
||||
peconv::set_main_module_in_peb((HMODULE)my_pe);
|
||||
|
||||
//calculate the Entry Point of the manually loaded module
|
||||
DWORD ep_rva = peconv::get_entry_point_rva(my_pe);
|
||||
if (!ep_rva) {
|
||||
return -2;
|
||||
}
|
||||
ULONG_PTR ep_va = ep_rva + (ULONG_PTR) my_pe;
|
||||
//assuming that the payload is an EXE file (not DLL) this will be the simplest prototype of the main:
|
||||
int (*new_main)() = (int(*)())ep_va;
|
||||
|
||||
//call the Entry Point of the manually loaded PE:
|
||||
return new_main();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Read more
|
||||
+ [Wiki](https://github.com/hasherezade/libpeconv/wiki)
|
||||
+ [Docs](https://hasherezade.github.io/libpeconv/)
|
||||
+ [Examples](https://github.com/hasherezade/libpeconv/tree/master/tests)
|
||||
+ [Tutorials](https://hshrzd.wordpress.com/tag/libpeconv/)
|
||||
+ [Project template](https://github.com/hasherezade/libpeconv_project_template)
|
||||
83
Etw Syscall/libpeconv-master/libpeconv/CMakeLists.txt
Normal file
83
Etw Syscall/libpeconv-master/libpeconv/CMakeLists.txt
Normal file
@@ -0,0 +1,83 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
project ( libpeconv )
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
|
||||
include_directories (
|
||||
include
|
||||
)
|
||||
|
||||
set (srcs
|
||||
src/pe_hdrs_helper.cpp
|
||||
src/pe_mode_detector.cpp
|
||||
src/pe_raw_to_virtual.cpp
|
||||
src/pe_virtual_to_raw.cpp
|
||||
src/relocate.cpp
|
||||
src/buffer_util.cpp
|
||||
src/remote_pe_reader.cpp
|
||||
src/imports_loader.cpp
|
||||
src/delayed_imports_loader.cpp
|
||||
src/fix_imports.cpp
|
||||
src/pe_loader.cpp
|
||||
src/pe_dumper.cpp
|
||||
src/exports_lookup.cpp
|
||||
src/function_resolver.cpp
|
||||
src/hooks.cpp
|
||||
src/exported_func.cpp
|
||||
src/exports_mapper.cpp
|
||||
src/resource_parser.cpp
|
||||
src/file_util.cpp
|
||||
src/resource_util.cpp
|
||||
src/imports_uneraser.cpp
|
||||
src/load_config_util.cpp
|
||||
src/caves.cpp
|
||||
src/util.cpp
|
||||
src/fix_dot_net_ep.cpp
|
||||
src/find_base.cpp
|
||||
src/peb_lookup.cpp
|
||||
)
|
||||
|
||||
set (hdrs
|
||||
include/peconv.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/util.h
|
||||
include/peconv/buffer_util.h
|
||||
include/peconv/remote_pe_reader.h
|
||||
include/peconv/imports_loader.h
|
||||
include/peconv/delayed_imports_loader.h
|
||||
include/peconv/fix_imports.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/exported_func.h
|
||||
include/peconv/exports_mapper.h
|
||||
include/peconv/resource_parser.h
|
||||
include/peconv/file_util.h
|
||||
include/peconv/resource_util.h
|
||||
include/peconv/imports_uneraser.h
|
||||
include/peconv/load_config_util.h
|
||||
include/peconv/load_config_defs.h
|
||||
include/peconv/caves.h
|
||||
include/peconv/find_base.h
|
||||
include/peconv/peb_lookup.h
|
||||
src/fix_dot_net_ep.h #not in API
|
||||
)
|
||||
|
||||
add_library ( ${PROJECT_NAME} STATIC ${hdrs} ${srcs} )
|
||||
|
||||
if(PECONV_LIB_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
install(DIRECTORY "include/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
endif()
|
||||
30
Etw Syscall/libpeconv-master/libpeconv/include/peconv.h
Normal file
30
Etw Syscall/libpeconv-master/libpeconv/include/peconv.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @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"
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Definitions of the used buffer types. Functions for their allocation and deallocation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
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, ULONGLONG desired_base=NULL);
|
||||
|
||||
/**
|
||||
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, ULONGLONG desired_base=NULL);
|
||||
|
||||
/**
|
||||
Free the memory allocated with alloc_pe_buffer.
|
||||
*/
|
||||
bool free_pe_buffer(ALIGNED_BUF buffer, size_t buffer_size=0);
|
||||
|
||||
}; //namespace peconv
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @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);
|
||||
|
||||
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
|
||||
|
||||
@@ -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, LPSTR 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(LPSTR lib_name, LPSTR func_name);
|
||||
};
|
||||
|
||||
/**
|
||||
Read the DLL name from the Export Table.
|
||||
*/
|
||||
LPSTR read_dll_name(HMODULE modulePtr);
|
||||
|
||||
}; //namespace peconv
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @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 {
|
||||
|
||||
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 moduleBase : a base address to which the given DLL was relocated
|
||||
*/
|
||||
size_t add_to_lookup(std::string moduleName, HMODULE modulePtr, ULONGLONG 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 full path of the DLL with the given short name.
|
||||
*/
|
||||
std::string get_dll_path(std::string short_name) const
|
||||
{
|
||||
std::map<std::string, std::string>::const_iterator found = this->dll_shortname_to_path.find(short_name);
|
||||
if (found == dll_shortname_to_path.end()) {
|
||||
return "";
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
/**
|
||||
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 full path to the DLL.
|
||||
*/
|
||||
std::map<std::string, std::string> dll_shortname_to_path;
|
||||
};
|
||||
|
||||
}; //namespace peconv
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @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::ALIGNED_BUF load_file(IN const char *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::ALIGNED_BUF read_from_file(IN const char *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 const char *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::ALIGNED_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);
|
||||
|
||||
}; //namespace peconv
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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(ULONGLONG thunk, ULONGLONG searchedAddr);
|
||||
|
||||
std::map<ULONGLONG, 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;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @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>
|
||||
|
||||
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(LPSTR lib_name, LPSTR 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(LPSTR lib_name, LPSTR func_name);
|
||||
};
|
||||
|
||||
}; //namespace peconv
|
||||
135
Etw Syscall/libpeconv-master/libpeconv/include/peconv/hooks.h
Normal file
135
Etw Syscall/libpeconv-master/libpeconv/include/peconv/hooks.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* @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(std::string name, FARPROC function)
|
||||
{
|
||||
hooks_map[name] = function;
|
||||
}
|
||||
|
||||
/**
|
||||
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(LPSTR lib_name, LPSTR func_name);
|
||||
|
||||
private:
|
||||
std::map<std::string, FARPROC> hooks_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
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Parsing and filling the Import Table.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "pe_hdrs_helper.h"
|
||||
#include "function_resolver.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;
|
||||
};
|
||||
|
||||
/**
|
||||
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);
|
||||
|
||||
}; // namespace peconv
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @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 const char *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
|
||||
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* @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
|
||||
|
||||
#define MASK_TO_DWORD(val) (val & 0xffffffff)
|
||||
#define MASK_TO_WORD(val) (val & 0xffff)
|
||||
|
||||
namespace peconv {
|
||||
/**
|
||||
Maximal size of the PE header.
|
||||
*/
|
||||
const ULONGLONG MAX_HEADER_SIZE = PAGE_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
|
||||
@@ -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 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(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, bool executable, bool relocate);
|
||||
|
||||
/**
|
||||
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(const char *filename, OUT size_t &v_size, bool executable, bool relocate);
|
||||
|
||||
/**
|
||||
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* dllRawData, size_t r_size, OUT size_t &v_size, t_function_resolver* import_resolver=NULL);
|
||||
|
||||
/**
|
||||
Loads full PE from file 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(const char *filename, OUT size_t &v_size, t_function_resolver* import_resolver=NULL);
|
||||
|
||||
};// namespace peconv
|
||||
@@ -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
|
||||
@@ -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 ULONGLONG desired_base = 0
|
||||
);
|
||||
|
||||
}; // namespace peconv
|
||||
@@ -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
|
||||
@@ -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 LPWSTR 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();
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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 §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 const char *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
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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
|
||||
41
Etw Syscall/libpeconv-master/libpeconv/include/peconv/util.h
Normal file
41
Etw Syscall/libpeconv-master/libpeconv/include/peconv/util.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Miscellaneous utility functions.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "file_util.h"
|
||||
#include "resource_util.h"
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
88
Etw Syscall/libpeconv-master/libpeconv/src/buffer_util.cpp
Normal file
88
Etw Syscall/libpeconv-master/libpeconv/src/buffer_util.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "peconv/buffer_util.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
//
|
||||
// validate pointer:
|
||||
//
|
||||
|
||||
bool peconv::validate_ptr(IN const void* buffer_bgn, IN SIZE_T buffer_size, IN const void* field_bgn, IN SIZE_T field_size)
|
||||
{
|
||||
if (buffer_bgn == nullptr || field_bgn == nullptr) {
|
||||
return false;
|
||||
}
|
||||
BYTE* _start = (BYTE*)buffer_bgn;
|
||||
BYTE* _end = _start + buffer_size;
|
||||
|
||||
BYTE* _field_start = (BYTE*)field_bgn;
|
||||
BYTE* _field_end = (BYTE*)field_bgn + field_size;
|
||||
|
||||
if (_field_start < _start) {
|
||||
return false;
|
||||
}
|
||||
if (_field_end > _end) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// alloc/free unaligned buffers:
|
||||
//
|
||||
|
||||
//allocates a buffer that does not have to start from the beginning of the section
|
||||
peconv::UNALIGNED_BUF peconv::alloc_unaligned(size_t buf_size)
|
||||
{
|
||||
if (!buf_size) return NULL;
|
||||
|
||||
UNALIGNED_BUF buf = (UNALIGNED_BUF) calloc(buf_size, sizeof(BYTE));
|
||||
return buf;
|
||||
}
|
||||
|
||||
void peconv::free_unaligned(peconv::UNALIGNED_BUF section_buffer)
|
||||
{
|
||||
free(section_buffer);
|
||||
}
|
||||
|
||||
//
|
||||
// alloc/free aligned buffers:
|
||||
//
|
||||
|
||||
peconv::ALIGNED_BUF peconv::alloc_aligned(size_t buffer_size, DWORD protect, ULONGLONG desired_base)
|
||||
{
|
||||
if (!buffer_size) return NULL;
|
||||
|
||||
ALIGNED_BUF buf = (ALIGNED_BUF) VirtualAlloc((LPVOID) desired_base, buffer_size, MEM_COMMIT | MEM_RESERVE, protect);
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool peconv::free_aligned(peconv::ALIGNED_BUF buffer, size_t buffer_size)
|
||||
{
|
||||
if (buffer == nullptr) return true;
|
||||
if (!VirtualFree(buffer, 0, MEM_RELEASE)) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Releasing failed" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// wrappers using appropriate buffer type according to the purpose:
|
||||
//
|
||||
|
||||
// allocate a buffer for PE module:
|
||||
peconv::ALIGNED_BUF peconv::alloc_pe_buffer(size_t buffer_size, DWORD protect, ULONGLONG desired_base)
|
||||
{
|
||||
return alloc_aligned(buffer_size, protect, desired_base);
|
||||
}
|
||||
|
||||
// Free loaded PE module
|
||||
bool peconv::free_pe_buffer(peconv::ALIGNED_BUF buffer, size_t buffer_size)
|
||||
{
|
||||
return peconv::free_aligned(buffer, buffer_size);
|
||||
}
|
||||
|
||||
139
Etw Syscall/libpeconv-master/libpeconv/src/caves.cpp
Normal file
139
Etw Syscall/libpeconv-master/libpeconv/src/caves.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "peconv/caves.h"
|
||||
#include "peconv/pe_hdrs_helper.h"
|
||||
#include "peconv/util.h"
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
PBYTE peconv::find_ending_cave(BYTE*modulePtr, size_t moduleSize, const DWORD minimal_size, const DWORD req_charact)
|
||||
{
|
||||
size_t sec_count = peconv::get_sections_count(modulePtr, moduleSize);
|
||||
if (sec_count == 0) return nullptr;
|
||||
|
||||
size_t last_sec = sec_count - 1;
|
||||
PIMAGE_SECTION_HEADER section_hdr = peconv::get_section_hdr(modulePtr, moduleSize, last_sec);
|
||||
if (section_hdr == nullptr) return nullptr;
|
||||
if (!(section_hdr->Characteristics & req_charact)) return nullptr;
|
||||
|
||||
DWORD raw_size = section_hdr->SizeOfRawData;
|
||||
DWORD virtual_size = (DWORD)moduleSize - section_hdr->VirtualAddress;
|
||||
|
||||
if (raw_size >= virtual_size) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Last section's raw_size: " << std::hex << raw_size << " >= virtual_size: " << virtual_size << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
DWORD cave_size = virtual_size - raw_size;
|
||||
if (cave_size < minimal_size) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Cave is too small" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
PBYTE cave_ptr = modulePtr + section_hdr->VirtualAddress + section_hdr->SizeOfRawData;
|
||||
if (!validate_ptr(modulePtr, moduleSize, cave_ptr, minimal_size)) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Invalid cave pointer" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
section_hdr->SizeOfRawData += minimal_size; //book this cave
|
||||
return cave_ptr;
|
||||
}
|
||||
|
||||
PBYTE peconv::find_alignment_cave(BYTE* modulePtr, size_t moduleSize, const DWORD minimal_size, const DWORD req_charact)
|
||||
{
|
||||
DWORD alignment = peconv::get_sec_alignment(modulePtr, true);
|
||||
if (alignment == 0) return nullptr;
|
||||
|
||||
size_t sec_count = peconv::get_sections_count(modulePtr, moduleSize);
|
||||
for (size_t i = 0; i < sec_count; i++) {
|
||||
PIMAGE_SECTION_HEADER section_hdr = peconv::get_section_hdr(modulePtr, moduleSize, i);
|
||||
if (section_hdr == nullptr) continue;
|
||||
if (!(section_hdr->Characteristics & req_charact)) continue;
|
||||
|
||||
DWORD rem = section_hdr->SizeOfRawData % alignment;
|
||||
if (rem == 0) continue;
|
||||
|
||||
DWORD div = (section_hdr->SizeOfRawData / alignment) + 1;
|
||||
DWORD new_size = div * alignment;
|
||||
DWORD cave_size = new_size - section_hdr->SizeOfRawData;
|
||||
if (cave_size < minimal_size) {
|
||||
#ifdef __DEBUG
|
||||
std::cout << "Cave is too small" << std::endl;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
DWORD sec_start = section_hdr->PointerToRawData;
|
||||
if (sec_start == 0) continue;
|
||||
|
||||
DWORD sec_end = sec_start + section_hdr->SizeOfRawData;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "section: " << std::hex << sec_start << " : " << sec_end << std::endl;
|
||||
#endif
|
||||
PBYTE cave_ptr = modulePtr + sec_end;
|
||||
if (!validate_ptr(modulePtr, moduleSize, cave_ptr, minimal_size)) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Invalid cave pointer" << std::endl;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
section_hdr->SizeOfRawData += minimal_size; //book this cave
|
||||
return cave_ptr;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Cave not found" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PBYTE peconv::find_padding_cave(BYTE* modulePtr, size_t moduleSize, const size_t minimal_size, const DWORD req_charact)
|
||||
{
|
||||
size_t sec_count = peconv::get_sections_count(modulePtr, moduleSize);
|
||||
for (size_t i = 0; i < sec_count; i++) {
|
||||
PIMAGE_SECTION_HEADER section_hdr = peconv::get_section_hdr(modulePtr, moduleSize, i);
|
||||
if (section_hdr == nullptr) continue;
|
||||
if (!(section_hdr->Characteristics & req_charact)) continue;
|
||||
|
||||
if (section_hdr->SizeOfRawData < minimal_size) continue;
|
||||
|
||||
// we will be searching in the loaded, virtual image:
|
||||
DWORD sec_start = section_hdr->VirtualAddress;
|
||||
if (sec_start == 0) continue;
|
||||
|
||||
DWORD sec_end = sec_start + section_hdr->SizeOfRawData;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "section: " << std::hex << sec_start << " : " << sec_end << std::endl;
|
||||
#endif
|
||||
//offset from the end of the section:
|
||||
size_t cave_offset = section_hdr->SizeOfRawData - minimal_size;
|
||||
PBYTE cave_ptr = modulePtr + sec_start + cave_offset;
|
||||
if (!validate_ptr(modulePtr, moduleSize, cave_ptr, minimal_size)) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Invalid cave pointer" << std::endl;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
bool found = false;
|
||||
if (is_padding(cave_ptr, minimal_size, 0)) {
|
||||
found = true;
|
||||
}
|
||||
//if the section is code, check also code padding:
|
||||
if (section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
||||
if (is_padding(cave_ptr, minimal_size, 0xCC)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return cave_ptr;
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Cave not found" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
#include "peconv/delayed_imports_loader.h"
|
||||
#include "peconv/imports_loader.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
IMAGE_DELAYLOAD_DESCRIPTOR* peconv::get_delayed_imps(IN const BYTE* modulePtr, IN const size_t moduleSize, OUT size_t &dir_size)
|
||||
{
|
||||
dir_size = 0;
|
||||
IMAGE_DATA_DIRECTORY *d_imps_dir = peconv::get_directory_entry(modulePtr, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
|
||||
if (!d_imps_dir) {
|
||||
return nullptr;
|
||||
}
|
||||
BYTE* dimps_table = (BYTE*)((ULONGLONG) modulePtr + d_imps_dir->VirtualAddress);
|
||||
const size_t min_size = sizeof(IMAGE_DELAYLOAD_DESCRIPTOR);
|
||||
if (d_imps_dir->Size < min_size) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!peconv::validate_ptr((LPVOID)modulePtr, moduleSize, dimps_table, min_size)) {
|
||||
return nullptr;
|
||||
}
|
||||
dir_size = d_imps_dir->Size;
|
||||
return reinterpret_cast<IMAGE_DELAYLOAD_DESCRIPTOR*> (dimps_table);
|
||||
}
|
||||
|
||||
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
|
||||
bool parse_delayed_desc(BYTE* modulePtr, const size_t moduleSize,
|
||||
const ULONGLONG img_base,
|
||||
LPSTR lib_name,
|
||||
const T_FIELD ordinal_flag,
|
||||
IMAGE_DELAYLOAD_DESCRIPTOR *desc,
|
||||
peconv::t_function_resolver* func_resolver
|
||||
)
|
||||
{
|
||||
ULONGLONG iat_addr = desc->ImportAddressTableRVA;
|
||||
|
||||
if (iat_addr > img_base) iat_addr -= img_base; // it may be either RVA or VA
|
||||
|
||||
ULONGLONG thunk_addr = desc->ImportNameTableRVA;
|
||||
if (thunk_addr > img_base) thunk_addr -= img_base; // it may be either RVA or VA
|
||||
|
||||
T_FIELD* record_va = (T_FIELD*)((ULONGLONG)modulePtr + iat_addr);
|
||||
T_IMAGE_THUNK_DATA* thunk_va = (T_IMAGE_THUNK_DATA*)((ULONGLONG)modulePtr + thunk_addr);
|
||||
|
||||
for (; *record_va != NULL && thunk_va != NULL; record_va++, thunk_va++) {
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, record_va, sizeof(T_FIELD))) {
|
||||
return false;
|
||||
}
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, thunk_va, sizeof(T_FIELD))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
T_FIELD iat_va = *record_va;
|
||||
ULONGLONG iat_rva = (ULONGLONG)iat_va;
|
||||
if (iat_va > img_base) iat_rva -= img_base; // it may be either RVA or VA
|
||||
#ifdef _DEBUG
|
||||
std::cout << std::hex << iat_rva << " : ";
|
||||
#endif
|
||||
T_FIELD* iat_record_ptr = (T_FIELD*)((ULONGLONG)modulePtr + iat_rva);
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, iat_record_ptr, sizeof(T_FIELD))) {
|
||||
return false;
|
||||
}
|
||||
FARPROC hProc = nullptr;
|
||||
if (thunk_va->u1.Ordinal & ordinal_flag) {
|
||||
T_FIELD raw_ordinal = thunk_va->u1.Ordinal & (~ordinal_flag);
|
||||
#ifdef _DEBUG
|
||||
std::cout << std::hex << "ord: " << raw_ordinal << " ";
|
||||
#endif
|
||||
hProc = func_resolver->resolve_func(lib_name, MAKEINTRESOURCEA(raw_ordinal));
|
||||
}
|
||||
else {
|
||||
ULONGLONG name_rva = thunk_va->u1.AddressOfData;
|
||||
if (name_rva > img_base) {
|
||||
name_rva -= img_base;
|
||||
}
|
||||
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + name_rva);
|
||||
LPSTR func_name = reinterpret_cast<LPSTR>(by_name->Name);
|
||||
if (!peconv::is_valid_import_name(modulePtr, moduleSize, func_name)) {
|
||||
continue;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << func_name << " ";
|
||||
#endif
|
||||
hProc = func_resolver->resolve_func(lib_name, func_name);
|
||||
}
|
||||
if (hProc) {
|
||||
//rather than loading it via proxy function, we just overwrite the thunk like normal IAT:
|
||||
*record_va = (T_FIELD) hProc;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[OK]\n";
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[NOPE]\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool peconv::load_delayed_imports(BYTE* modulePtr, ULONGLONG moduleBase, t_function_resolver* func_resolver)
|
||||
{
|
||||
const bool is_64bit = peconv::is64bit(modulePtr);
|
||||
bool is_loader64 = false;
|
||||
#ifdef _WIN64
|
||||
is_loader64 = true;
|
||||
#endif
|
||||
if (is_64bit != is_loader64) {
|
||||
std::cerr << "[ERROR] Loader/Payload bitness mismatch.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t module_size = peconv::get_image_size(modulePtr);
|
||||
default_func_resolver default_res;
|
||||
if (!func_resolver) {
|
||||
func_resolver = (t_function_resolver*)&default_res;
|
||||
}
|
||||
size_t table_size = 0;
|
||||
IMAGE_DELAYLOAD_DESCRIPTOR *first_desc = get_delayed_imps(modulePtr, module_size, table_size);
|
||||
if (!first_desc) {
|
||||
return false;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "OK, table_size = " << table_size << std::endl;
|
||||
#endif
|
||||
size_t max_count = table_size / sizeof(IMAGE_DELAYLOAD_DESCRIPTOR);
|
||||
for (size_t i = 0; i < max_count; i++) {
|
||||
IMAGE_DELAYLOAD_DESCRIPTOR *desc = &first_desc[i];
|
||||
if (!validate_ptr(modulePtr, module_size, desc, sizeof(IMAGE_DELAYLOAD_DESCRIPTOR))) break;
|
||||
if (desc->DllNameRVA == NULL) {
|
||||
break;
|
||||
}
|
||||
ULONGLONG dll_name_rva = desc->DllNameRVA;
|
||||
if (dll_name_rva > moduleBase) {
|
||||
dll_name_rva -= moduleBase;
|
||||
}
|
||||
char* dll_name = (char*)((ULONGLONG) modulePtr + dll_name_rva);
|
||||
if (!validate_ptr(modulePtr, module_size, dll_name, sizeof(char))) continue;
|
||||
#ifdef _DEBUG
|
||||
std::cout << dll_name << std::endl;
|
||||
#endif
|
||||
if (is_64bit) {
|
||||
#ifdef _WIN64
|
||||
parse_delayed_desc<ULONGLONG,IMAGE_THUNK_DATA64>(modulePtr, module_size, moduleBase, dll_name, IMAGE_ORDINAL_FLAG64, desc, func_resolver);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifndef _WIN64
|
||||
parse_delayed_desc<DWORD, IMAGE_THUNK_DATA32>(modulePtr, module_size, moduleBase, dll_name, IMAGE_ORDINAL_FLAG32, desc, func_resolver);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
176
Etw Syscall/libpeconv-master/libpeconv/src/exported_func.cpp
Normal file
176
Etw Syscall/libpeconv-master/libpeconv/src/exported_func.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "peconv/exported_func.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
std::string peconv::get_dll_shortname(const std::string& str)
|
||||
{
|
||||
std::size_t len = str.length();
|
||||
std::size_t found = str.find_last_of("/\\");
|
||||
std::size_t ext = str.find_last_of('.');
|
||||
if (ext >= len) return "";
|
||||
|
||||
std::string name = str.substr(found+1, ext - (found+1));
|
||||
std::transform(name.begin(), name.end(), name.begin(), tolower);
|
||||
return name;
|
||||
}
|
||||
|
||||
size_t peconv::forwarder_name_len(BYTE* fPtr)
|
||||
{
|
||||
// names can be also mangled, i.e. MSVCRT.??0__non_rtti_object@std@@QAE@ABV01@@Z
|
||||
bool has_dot = false;
|
||||
size_t len = 0;
|
||||
while ((*fPtr >= 'a' && *fPtr <= 'z')
|
||||
|| (*fPtr >= 'A' && *fPtr <= 'Z')
|
||||
|| (*fPtr >= '0' && *fPtr <= '9')
|
||||
|| (*fPtr == '.')
|
||||
|| (*fPtr == '_')
|
||||
|| (*fPtr == '#')
|
||||
|| (*fPtr == '@')
|
||||
|| (*fPtr == '?')
|
||||
|| (*fPtr == '-'))
|
||||
{
|
||||
if (*fPtr == '.') has_dot = true;
|
||||
len++;
|
||||
fPtr++;
|
||||
}
|
||||
if (*fPtr == '\0') {
|
||||
if (!has_dot) {
|
||||
return 0; //this is not a valid forwarder
|
||||
}
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string peconv::get_func_name(const std::string& str)
|
||||
{
|
||||
std::size_t len = str.length();
|
||||
std::size_t ext = str.find_last_of(".");
|
||||
if (ext >= len) return "";
|
||||
|
||||
std::string name = str.substr(ext+1, len - (ext+1));
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string peconv::ordinal_to_string(DWORD func_ordinal)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << "#";
|
||||
stream << std::dec << func_ordinal;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
bool peconv::is_ordinal_string(const std::string& func_name_str)
|
||||
{
|
||||
if (func_name_str.length() < 2) return false;
|
||||
return (func_name_str[0] == '#');
|
||||
}
|
||||
|
||||
DWORD peconv::ordinal_string_to_val(const std::string& func_name_str)
|
||||
{
|
||||
if (!is_ordinal_string(func_name_str)) return 0;
|
||||
const char* func_name = func_name_str.c_str();
|
||||
return atoi(func_name + 1);
|
||||
}
|
||||
|
||||
std::string peconv::format_dll_func(const std::string& str)
|
||||
{
|
||||
std::string dllName = get_dll_shortname(str);
|
||||
std::string funcName = get_func_name(str);
|
||||
if (dllName.length() == 0 || funcName.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
std::transform(dllName.begin(), dllName.end(), dllName.begin(), tolower);
|
||||
return dllName + "." + funcName;
|
||||
}
|
||||
|
||||
ExportedFunc::ExportedFunc(std::string libName, std::string funcName, DWORD funcOrdinal)
|
||||
{
|
||||
this->libName = ExportedFunc::formatName(libName);
|
||||
this->funcName = funcName;
|
||||
this->funcOrdinal = funcOrdinal;
|
||||
this->isByOrdinal = false;
|
||||
}
|
||||
|
||||
ExportedFunc::ExportedFunc(std::string libName, DWORD funcOrdinal)
|
||||
{
|
||||
this->libName = ExportedFunc::formatName(libName);
|
||||
this->funcOrdinal = funcOrdinal;
|
||||
this->isByOrdinal = true;
|
||||
}
|
||||
|
||||
ExportedFunc::ExportedFunc(const ExportedFunc& other)
|
||||
{
|
||||
this->libName = other.libName;
|
||||
this->funcName = other.funcName;
|
||||
this->funcOrdinal = other.funcOrdinal;
|
||||
this->isByOrdinal = other.isByOrdinal;
|
||||
}
|
||||
|
||||
ExportedFunc::ExportedFunc(const std::string &forwarderName)
|
||||
{
|
||||
this->libName = get_dll_shortname(forwarderName);
|
||||
std::string func_name_str = get_func_name(forwarderName);
|
||||
if (func_name_str.length() < 2) {
|
||||
this->funcOrdinal = -1;
|
||||
this->funcName = "";
|
||||
this->isByOrdinal = false;
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Invalid function data" << std::endl;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (is_ordinal_string(func_name_str)) {
|
||||
// it is an ordinal in a string form, i.e.: "COMBASE.#110"
|
||||
this->funcOrdinal = peconv::ordinal_string_to_val(func_name_str);
|
||||
this->isByOrdinal = true;
|
||||
this->funcName = "";
|
||||
//std::cout << "[O] Adding forwarded func: " << forwarderName << " parsed: " << this->toString() << std::endl;
|
||||
} else {
|
||||
this->funcName = func_name_str;
|
||||
this->isByOrdinal = false;
|
||||
this->funcOrdinal = 0;
|
||||
//std::cout << "[N] Adding forwarded func:" << this->toString() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string ExportedFunc::formatName(std::string name)
|
||||
{
|
||||
if (name.length() == 0 || name.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
std::transform(name.begin(), name.end(), name.begin(), tolower);
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string ExportedFunc::toString() const
|
||||
{
|
||||
if (!isValid()) {
|
||||
return "[Invalid func]";
|
||||
}
|
||||
std::stringstream stream;
|
||||
stream << this->libName;
|
||||
stream << ".";
|
||||
if (!this->isByOrdinal) {
|
||||
stream << this->funcName;
|
||||
stream << " ";
|
||||
}
|
||||
stream << ordinal_to_string(this->funcOrdinal);
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string ExportedFunc::nameToString() const
|
||||
{
|
||||
if (!isValid()) {
|
||||
return "";
|
||||
}
|
||||
if (this->isByOrdinal) {
|
||||
return ordinal_to_string(this->funcOrdinal);
|
||||
}
|
||||
return this->funcName;
|
||||
}
|
||||
194
Etw Syscall/libpeconv-master/libpeconv/src/exports_lookup.cpp
Normal file
194
Etw Syscall/libpeconv-master/libpeconv/src/exports_lookup.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
#include "peconv/exports_lookup.h"
|
||||
#include "peconv/util.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/*
|
||||
typedef struct _IMAGE_EXPORT_DIRECTORY {
|
||||
DWORD Characteristics;
|
||||
DWORD TimeDateStamp;
|
||||
WORD MajorVersion;
|
||||
WORD MinorVersion;
|
||||
DWORD Name;
|
||||
DWORD Base;
|
||||
DWORD NumberOfFunctions;
|
||||
DWORD NumberOfNames;
|
||||
DWORD AddressOfFunctions; // RVA from base of image
|
||||
DWORD AddressOfNames; // RVA from base of image
|
||||
DWORD AddressOfNameOrdinals; // RVA from base of image
|
||||
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
|
||||
*/
|
||||
|
||||
#ifndef TO_LOWERCASE
|
||||
#define TO_LOWERCASE(c1) c1 = (c1 <= 'Z' && c1 >= 'A') ? c1 = (c1 - 'A') + 'a': c1;
|
||||
#endif
|
||||
|
||||
bool is_wanted_func(LPSTR curr_name, LPSTR wanted_name)
|
||||
{
|
||||
if (curr_name == NULL || wanted_name == NULL) return false;
|
||||
|
||||
size_t wanted_name_len = strlen(wanted_name);
|
||||
size_t curr_name_len = strlen(curr_name);
|
||||
|
||||
if (curr_name_len != wanted_name_len) return false;
|
||||
|
||||
for (size_t i = 0; i < wanted_name_len; i++) {
|
||||
char c1 = curr_name[i];
|
||||
char c2 = wanted_name[i];
|
||||
TO_LOWERCASE(c1);
|
||||
TO_LOWERCASE(c2);
|
||||
if (c1 != c2) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_ordinal(IMAGE_EXPORT_DIRECTORY *exp, LPSTR func_name)
|
||||
{
|
||||
ULONGLONG base = exp->Base;
|
||||
ULONGLONG max_ord = base + exp->NumberOfFunctions;
|
||||
ULONGLONG name_ptr_val = (ULONGLONG)func_name;
|
||||
if (name_ptr_val >= base && name_ptr_val < max_ord) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FARPROC get_export_by_ord(PVOID modulePtr, IMAGE_EXPORT_DIRECTORY* exp, DWORD wanted_ordinal)
|
||||
{
|
||||
SIZE_T functCount = exp->NumberOfFunctions;
|
||||
DWORD funcsListRVA = exp->AddressOfFunctions;
|
||||
DWORD ordBase = exp->Base;
|
||||
|
||||
//go through names:
|
||||
for (DWORD i = 0; i < functCount; i++) {
|
||||
DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
|
||||
BYTE* fPtr = (BYTE*) modulePtr + (*funcRVA); //pointer to the function
|
||||
DWORD ordinal = ordBase + i;
|
||||
if (ordinal == wanted_ordinal) {
|
||||
if (peconv::forwarder_name_len(fPtr) > 1) {
|
||||
std::cerr << "[!] Forwarded function: ["<< wanted_ordinal << " -> "<< fPtr << "] cannot be resolved!" << std::endl;
|
||||
return NULL; // this function is forwarded, cannot be resolved
|
||||
}
|
||||
return (FARPROC) fPtr; //return the pointer to the found function
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t peconv::get_exported_names(PVOID modulePtr, std::vector<std::string> &names_list)
|
||||
{
|
||||
IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
|
||||
if (exp == 0) return 0;
|
||||
|
||||
SIZE_T namesCount = exp->NumberOfNames;
|
||||
DWORD funcNamesListRVA = exp->AddressOfNames;
|
||||
|
||||
//go through names:
|
||||
SIZE_T i = 0;
|
||||
for (i = 0; i < namesCount; i++) {
|
||||
DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
|
||||
|
||||
LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr);
|
||||
if (peconv::is_bad_read_ptr(name, 1)) break; // this shoudld not happen. maybe the PE file is corrupt?
|
||||
|
||||
names_list.push_back(name);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
//WARNING: doesn't work for the forwarded functions.
|
||||
FARPROC peconv::get_exported_func(PVOID modulePtr, LPSTR wanted_name)
|
||||
{
|
||||
IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
|
||||
if (exp == NULL) return NULL;
|
||||
|
||||
SIZE_T namesCount = exp->NumberOfNames;
|
||||
|
||||
DWORD funcsListRVA = exp->AddressOfFunctions;
|
||||
DWORD funcNamesListRVA = exp->AddressOfNames;
|
||||
DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals;
|
||||
|
||||
if (is_ordinal(exp, wanted_name)) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[*] Getting function by ordinal" << std::endl;
|
||||
#endif
|
||||
const DWORD ordinal = MASK_TO_DWORD((ULONG_PTR)wanted_name);
|
||||
return get_export_by_ord(modulePtr, exp, ordinal);
|
||||
}
|
||||
if (peconv::is_bad_read_ptr(wanted_name, 1)) {
|
||||
std::cerr << "[-] Invalid pointer to the name" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//go through names:
|
||||
for (SIZE_T i = 0; i < namesCount; i++) {
|
||||
DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
|
||||
WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*) modulePtr + i * sizeof(WORD));
|
||||
DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + (*nameIndex) * sizeof(DWORD));
|
||||
|
||||
LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr);
|
||||
BYTE* fPtr = (BYTE*) modulePtr + (*funcRVA); //pointer to the function
|
||||
|
||||
if (!is_wanted_func(name, wanted_name)) {
|
||||
continue; //this is not the function we are looking for
|
||||
}
|
||||
if (forwarder_name_len(fPtr) > 1) {
|
||||
std::cerr << "[!] Forwarded function: ["<< name << " -> "<< fPtr << "] cannot be resolved!" << std::endl;
|
||||
return NULL; // this function is forwarded, cannot be resolved
|
||||
}
|
||||
return (FARPROC) fPtr; //return the pointer to the found function
|
||||
}
|
||||
//function not found
|
||||
std::cerr << "Function not found!" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FARPROC peconv::export_based_resolver::resolve_func(LPSTR lib_name, LPSTR func_name)
|
||||
{
|
||||
HMODULE libBasePtr = LoadLibraryA(lib_name);
|
||||
if (libBasePtr == NULL) {
|
||||
std::cerr << "Could not load the library!" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FARPROC hProc = get_exported_func(libBasePtr, func_name);
|
||||
|
||||
if (hProc == NULL) {
|
||||
#ifdef _DEBUG
|
||||
if (!peconv::is_bad_read_ptr(func_name, 1)) {
|
||||
std::cerr << "[!] Cound not get the function: "<< func_name <<" from exports!" << std::endl;
|
||||
} else {
|
||||
std::cerr << "[!] Cound not get the function: "<< MASK_TO_DWORD((ULONG_PTR)func_name) <<" from exports!" << std::endl;
|
||||
}
|
||||
std::cerr << "[!] Falling back to the default resolver..." <<std::endl;
|
||||
#endif
|
||||
hProc = default_func_resolver::resolve_func(lib_name, func_name);
|
||||
if (hProc == NULL) {
|
||||
std::cerr << "[-] Loading function from " << lib_name << " failed!" << std::endl;
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
FARPROC defaultProc = default_func_resolver::resolve_func(lib_name, func_name);
|
||||
if (hProc != defaultProc) {
|
||||
std::cerr << "[-] Loaded proc is not matching the default one!" << std::endl;
|
||||
}
|
||||
#endif
|
||||
return hProc;
|
||||
}
|
||||
|
||||
LPSTR peconv::read_dll_name(HMODULE modulePtr)
|
||||
{
|
||||
IMAGE_EXPORT_DIRECTORY* exp = get_export_directory(modulePtr);
|
||||
if (exp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
LPSTR module_name = (char*)((ULONGLONG)modulePtr + exp->Name);
|
||||
if (peconv::is_bad_read_ptr(module_name, 1)) {
|
||||
return NULL;
|
||||
}
|
||||
size_t len = peconv::forwarder_name_len((BYTE*) module_name);
|
||||
if (len > 1) {
|
||||
return module_name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
265
Etw Syscall/libpeconv-master/libpeconv/src/exports_mapper.cpp
Normal file
265
Etw Syscall/libpeconv-master/libpeconv/src/exports_mapper.cpp
Normal file
@@ -0,0 +1,265 @@
|
||||
#include "peconv/exports_mapper.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
void ExportsMapper::print_va_to_func(std::stringstream &stream) const
|
||||
{
|
||||
std::map<ULONGLONG, std::set<ExportedFunc>>::const_iterator itr;
|
||||
|
||||
for (itr = va_to_func.begin(); itr != va_to_func.end(); ++itr) {
|
||||
|
||||
stream << std::hex << itr->first << " :\n";
|
||||
|
||||
std::set<ExportedFunc>::const_iterator itr2;
|
||||
const std::set<ExportedFunc> &funcs = itr->second;
|
||||
|
||||
for (itr2 = funcs.begin(); itr2 != funcs.end(); ++itr2) {
|
||||
stream << "\t" << itr2->toString() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExportsMapper::print_func_to_va(std::stringstream &stream) const
|
||||
{
|
||||
std::map<ExportedFunc, ULONGLONG>::const_iterator itr;
|
||||
for (itr = func_to_va.begin(); itr != func_to_va.end(); ++itr) {
|
||||
stream << itr->first.toString() << " : "
|
||||
<< std::hex << itr->second << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
ULONGLONG rebase_va(ULONGLONG va, ULONGLONG currBase, ULONGLONG targetBase)
|
||||
{
|
||||
if (currBase == targetBase) {
|
||||
return va;
|
||||
}
|
||||
ULONGLONG rva = va - (ULONGLONG) currBase;
|
||||
return rva + targetBase;
|
||||
}
|
||||
|
||||
size_t ExportsMapper::make_ord_lookup_tables(
|
||||
PVOID modulePtr,
|
||||
size_t moduleSize,
|
||||
std::map<PDWORD, DWORD> &va_to_ord
|
||||
)
|
||||
{
|
||||
IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
|
||||
if (exp == NULL) return 0;
|
||||
|
||||
SIZE_T functCount = exp->NumberOfFunctions;
|
||||
DWORD funcsListRVA = exp->AddressOfFunctions;
|
||||
DWORD ordBase = exp->Base;
|
||||
|
||||
//go through names:
|
||||
for (DWORD i = 0; i < functCount; i++) {
|
||||
DWORD* recordRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
|
||||
if (*recordRVA == 0) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << ">>> Skipping 0 function address at RVA:" << std::hex << (BYTE*)recordRVA - (BYTE*)modulePtr<< "(ord)\n";
|
||||
#endif
|
||||
//skip if the function RVA is 0 (empty export)
|
||||
continue;
|
||||
}
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, recordRVA, sizeof(DWORD))) {
|
||||
break;
|
||||
}
|
||||
DWORD ordinal = ordBase + i;
|
||||
va_to_ord[recordRVA] = ordinal;
|
||||
}
|
||||
return functCount;
|
||||
}
|
||||
|
||||
size_t ExportsMapper::resolve_forwarders(const ULONGLONG va, ExportedFunc &currFunc)
|
||||
{
|
||||
size_t resolved = 0;
|
||||
//resolve forwarders of this function (if any):
|
||||
std::map<ExportedFunc, std::set<ExportedFunc>>::iterator fItr = forwarders_lookup.find(currFunc);
|
||||
if (fItr != forwarders_lookup.end()) {
|
||||
//printf("[+] Forwarders (%d):\n", fItr->second.size());
|
||||
std::set<ExportedFunc>::iterator sItr;
|
||||
for (sItr = fItr->second.begin(); sItr != fItr->second.end(); ++sItr) {
|
||||
//printf("-> %s\n", sItr->c_str());
|
||||
associateVaAndFunc(va, *sItr);
|
||||
resolved++;
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
bool ExportsMapper::add_forwarded(ExportedFunc &currFunc, DWORD callRVA, PBYTE modulePtr, size_t moduleSize)
|
||||
{
|
||||
PBYTE fPtr = modulePtr + callRVA;
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, fPtr, 1)) {
|
||||
return false;
|
||||
}
|
||||
if (peconv::forwarder_name_len(fPtr) < 1) {
|
||||
return false; //not forwarded
|
||||
}
|
||||
std::string forwardedFunc = format_dll_func((char*)fPtr);
|
||||
if (forwardedFunc.length() == 0) {
|
||||
return false; //not forwarded
|
||||
}
|
||||
|
||||
ExportedFunc forwarder(forwardedFunc);
|
||||
if (!forwarder.isValid()) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Skipped invalid forwarder" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
forwarders_lookup[forwarder].insert(currFunc);
|
||||
|
||||
if (func_to_va[forwarder] != 0) {
|
||||
ULONGLONG va = func_to_va[forwarder];
|
||||
associateVaAndFunc(va, currFunc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD get_ordinal(PDWORD recordPtr, std::map<PDWORD, DWORD> &va_to_ord)
|
||||
{
|
||||
std::map<PDWORD, DWORD>::iterator ord_itr = va_to_ord.find(recordPtr);
|
||||
if (ord_itr == va_to_ord.end()) {
|
||||
//ordinal not found
|
||||
return -1;
|
||||
}
|
||||
DWORD ordinal = ord_itr->second;
|
||||
va_to_ord.erase(ord_itr);
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
bool ExportsMapper::add_to_maps(ULONGLONG va, ExportedFunc &currFunc)
|
||||
{
|
||||
associateVaAndFunc(va, currFunc);
|
||||
resolve_forwarders(va, currFunc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_valid_export_table(IMAGE_EXPORT_DIRECTORY* exp, HMODULE modulePtr, const size_t module_size)
|
||||
{
|
||||
if (exp == nullptr) return false;
|
||||
|
||||
const SIZE_T namesCount = exp->NumberOfNames;
|
||||
const SIZE_T funcCount = exp->NumberOfFunctions;
|
||||
|
||||
const DWORD funcsListRVA = exp->AddressOfFunctions;
|
||||
const DWORD funcNamesListRVA = exp->AddressOfNames;
|
||||
const DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals;
|
||||
|
||||
for (DWORD i = 0; i < funcCount; i++) {
|
||||
DWORD* recordRVA = (DWORD*)(funcsListRVA + (BYTE*)modulePtr + i * sizeof(DWORD));
|
||||
if (!peconv::validate_ptr(modulePtr, module_size, recordRVA, sizeof(DWORD))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (SIZE_T i = 0; i < namesCount; i++) {
|
||||
DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*)modulePtr + i * sizeof(DWORD));
|
||||
WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*)modulePtr + i * sizeof(WORD));
|
||||
if ((!peconv::validate_ptr(modulePtr, module_size, nameRVA, sizeof(DWORD)))
|
||||
|| (!peconv::validate_ptr(modulePtr, module_size, nameIndex, sizeof(WORD))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*)modulePtr + (*nameIndex) * sizeof(DWORD));
|
||||
if (!peconv::validate_ptr(modulePtr, module_size, funcRVA, sizeof(DWORD)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ExportsMapper::ADD_FUNC_RES ExportsMapper::add_function_to_lookup(HMODULE modulePtr, ULONGLONG moduleBase, size_t moduleSize, ExportedFunc &currFunc, DWORD callRVA)
|
||||
{
|
||||
if (add_forwarded(currFunc, callRVA, (BYTE*)modulePtr, moduleSize)) {
|
||||
#ifdef _DEBUG
|
||||
char* fPtr = (char*)modulePtr + callRVA;
|
||||
std::cout << "FWD " << currFunc.toString() << " -> " << fPtr << "\n";
|
||||
#endif
|
||||
return ExportsMapper::RES_FORWARDED;
|
||||
}
|
||||
|
||||
ULONGLONG callVa = callRVA + moduleBase;
|
||||
if (!peconv::validate_ptr((BYTE*)moduleBase, moduleSize, (BYTE*)callVa, sizeof(ULONGLONG))) {
|
||||
// this may happen when the function was forwarded and it is already filled
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Validation failed: " << currFunc.toString() << "\n";
|
||||
#endif
|
||||
return ExportsMapper::RES_INVALID;
|
||||
}
|
||||
//not forwarded, simple case:
|
||||
add_to_maps(callVa, currFunc);
|
||||
return ExportsMapper::RES_MAPPED;
|
||||
}
|
||||
|
||||
size_t ExportsMapper::add_to_lookup(std::string moduleName, HMODULE modulePtr, ULONGLONG moduleBase)
|
||||
{
|
||||
IMAGE_EXPORT_DIRECTORY* exp = get_export_directory(modulePtr);
|
||||
if (exp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
size_t module_size = peconv::get_image_size(reinterpret_cast<const PBYTE>(modulePtr));
|
||||
if (!is_valid_export_table(exp, modulePtr, module_size)) {
|
||||
return 0;
|
||||
}
|
||||
std::string dllName = get_dll_shortname(moduleName);
|
||||
this->dll_shortname_to_path[dllName] = moduleName;
|
||||
|
||||
std::map<PDWORD, DWORD> va_to_ord;
|
||||
size_t functCount = make_ord_lookup_tables(modulePtr, module_size, va_to_ord);
|
||||
|
||||
//go through names:
|
||||
|
||||
size_t forwarded_ctr = 0;
|
||||
SIZE_T namesCount = exp->NumberOfNames;
|
||||
|
||||
DWORD funcsListRVA = exp->AddressOfFunctions;
|
||||
DWORD funcNamesListRVA = exp->AddressOfNames;
|
||||
DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals;
|
||||
|
||||
size_t mapped_ctr = 0;
|
||||
|
||||
for (SIZE_T i = 0; i < namesCount; i++) {
|
||||
DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
|
||||
WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*) modulePtr + i * sizeof(WORD));
|
||||
DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + (*nameIndex) * sizeof(DWORD));
|
||||
if (*funcRVA == 0) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << ">>> Skipping 0 function address at RVA:" << std::hex << (BYTE*)funcRVA - (BYTE*)modulePtr << "(name)\n";
|
||||
#endif
|
||||
//skip if the function RVA is 0 (empty export)
|
||||
continue;
|
||||
}
|
||||
|
||||
LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr);
|
||||
if (!peconv::validate_ptr(modulePtr, module_size, name, sizeof(char))) break;
|
||||
|
||||
DWORD funcOrd = get_ordinal(funcRVA, va_to_ord);
|
||||
DWORD callRVA = *funcRVA;
|
||||
ExportedFunc currFunc(dllName, name, funcOrd);
|
||||
|
||||
int res = add_function_to_lookup(modulePtr, moduleBase, module_size, currFunc, callRVA);
|
||||
if (res == ExportsMapper::RES_FORWARDED) forwarded_ctr++;
|
||||
if (res == ExportsMapper::RES_MAPPED) mapped_ctr++;
|
||||
}
|
||||
//go through unnamed functions exported by ordinals:
|
||||
std::map<PDWORD, DWORD>::iterator ord_itr = va_to_ord.begin();
|
||||
for (;ord_itr != va_to_ord.end(); ++ord_itr) {
|
||||
|
||||
DWORD* funcRVA = ord_itr->first;
|
||||
DWORD callRVA = *funcRVA;
|
||||
ExportedFunc currFunc(dllName, ord_itr->second);
|
||||
|
||||
int res = add_function_to_lookup(modulePtr, moduleBase, module_size, currFunc, callRVA);
|
||||
if (res == ExportsMapper::RES_FORWARDED) forwarded_ctr++;
|
||||
if (res == ExportsMapper::RES_MAPPED) mapped_ctr++;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Finished exports parsing, mapped: "<< mapped_ctr << " forwarded: " << forwarded_ctr << std::endl;
|
||||
#endif
|
||||
return mapped_ctr;
|
||||
}
|
||||
148
Etw Syscall/libpeconv-master/libpeconv/src/file_util.cpp
Normal file
148
Etw Syscall/libpeconv-master/libpeconv/src/file_util.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "peconv/file_util.h"
|
||||
#include "peconv/buffer_util.h"
|
||||
#include "peconv/util.h"
|
||||
|
||||
#include <fstream>
|
||||
#ifdef _DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
//load file content using MapViewOfFile
|
||||
peconv::ALIGNED_BUF peconv::load_file(IN const char *filename, OUT size_t &read_size)
|
||||
{
|
||||
HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if(file == INVALID_HANDLE_VALUE) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Could not open file!" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
|
||||
if (!mapping) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Could not create mapping!" << std::endl;
|
||||
#endif
|
||||
CloseHandle(file);
|
||||
return nullptr;
|
||||
}
|
||||
BYTE *dllRawData = (BYTE*) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
|
||||
if (!dllRawData) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Could not map view of file" << std::endl;
|
||||
#endif
|
||||
CloseHandle(mapping);
|
||||
CloseHandle(file);
|
||||
return nullptr;
|
||||
}
|
||||
size_t r_size = GetFileSize(file, 0);
|
||||
if (read_size != 0 && read_size <= r_size) {
|
||||
r_size = read_size;
|
||||
}
|
||||
if (peconv::is_bad_read_ptr(dllRawData, r_size)) {
|
||||
std::cerr << "[-] Mapping of " << filename << " is invalid!" << std::endl;
|
||||
UnmapViewOfFile(dllRawData);
|
||||
CloseHandle(mapping);
|
||||
CloseHandle(file);
|
||||
return nullptr;
|
||||
}
|
||||
peconv::ALIGNED_BUF localCopyAddress = peconv::alloc_aligned(r_size, PAGE_READWRITE);
|
||||
if (localCopyAddress != nullptr) {
|
||||
memcpy(localCopyAddress, dllRawData, r_size);
|
||||
read_size = r_size;
|
||||
} else {
|
||||
read_size = 0;
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Could not allocate memory in the current process" << std::endl;
|
||||
#endif
|
||||
}
|
||||
UnmapViewOfFile(dllRawData);
|
||||
CloseHandle(mapping);
|
||||
CloseHandle(file);
|
||||
return localCopyAddress;
|
||||
}
|
||||
|
||||
//load file content using ReadFile
|
||||
peconv::ALIGNED_BUF peconv::read_from_file(IN const char *in_path, IN OUT size_t &read_size)
|
||||
{
|
||||
HANDLE file = CreateFileA(in_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Cannot open the file for reading!" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
size_t r_size = static_cast<size_t>(GetFileSize(file, 0));
|
||||
if (read_size != 0 && read_size <= r_size) {
|
||||
r_size = read_size;
|
||||
}
|
||||
PBYTE buffer = peconv::alloc_pe_buffer(r_size, PAGE_READWRITE);
|
||||
if (buffer == nullptr) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Allocation has failed!" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
DWORD out_size = 0;
|
||||
if (!ReadFile(file, buffer, r_size, &out_size, nullptr)) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Reading failed!" << std::endl;
|
||||
#endif
|
||||
peconv::free_pe_buffer(buffer, r_size);
|
||||
buffer = nullptr;
|
||||
read_size = 0;
|
||||
} else {
|
||||
read_size = r_size;
|
||||
}
|
||||
CloseHandle(file);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//save the given buffer into a file
|
||||
bool peconv::dump_to_file(IN const char *out_path, IN PBYTE dump_data, IN size_t dump_size)
|
||||
{
|
||||
if (!out_path || !dump_data || !dump_size) return false;
|
||||
|
||||
HANDLE file = CreateFileA(out_path, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Cannot open the file for writing!" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
DWORD written_size = 0;
|
||||
bool is_dumped = false;
|
||||
if (WriteFile(file, dump_data, (DWORD) dump_size, &written_size, nullptr)) {
|
||||
is_dumped = true;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
else {
|
||||
std::cerr << "Failed to write to the file : " << out_path << std::endl;
|
||||
}
|
||||
#endif
|
||||
CloseHandle(file);
|
||||
return is_dumped;
|
||||
}
|
||||
|
||||
//free the buffer allocated by load_file/read_from_file
|
||||
void peconv::free_file(IN peconv::ALIGNED_BUF buffer)
|
||||
{
|
||||
peconv::free_aligned(buffer);
|
||||
}
|
||||
|
||||
std::string peconv::get_file_name(IN const std::string str)
|
||||
{
|
||||
size_t found = str.find_last_of("/\\");
|
||||
if (found == std::string::npos) {
|
||||
return str;
|
||||
}
|
||||
return str.substr(found + 1);
|
||||
}
|
||||
|
||||
std::string peconv::get_directory_name(IN const std::string str)
|
||||
{
|
||||
size_t found = str.find_last_of("/\\");
|
||||
if (found == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
return str.substr(0, found);
|
||||
}
|
||||
125
Etw Syscall/libpeconv-master/libpeconv/src/find_base.cpp
Normal file
125
Etw Syscall/libpeconv-master/libpeconv/src/find_base.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include <peconv/find_base.h>
|
||||
#include <peconv/pe_hdrs_helper.h>
|
||||
#include <peconv/relocate.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
namespace peconv {
|
||||
|
||||
class CollectCodeRelocs : public RelocBlockCallback
|
||||
{
|
||||
public:
|
||||
CollectCodeRelocs(BYTE *pe_buffer, size_t buffer_size, IN bool _is64bit, OUT std::set<ULONGLONG> &_relocs)
|
||||
: RelocBlockCallback(_is64bit), relocs(_relocs),
|
||||
peBuffer(pe_buffer), bufferSize(buffer_size)
|
||||
{
|
||||
codeSec = getCodeSection(peBuffer, bufferSize);
|
||||
}
|
||||
|
||||
virtual bool processRelocField(ULONG_PTR relocField)
|
||||
{
|
||||
if (!codeSec) return false;
|
||||
|
||||
ULONGLONG reloc_addr = (relocField - (ULONGLONG)peBuffer);
|
||||
const bool is_in_code = (reloc_addr >= codeSec->VirtualAddress) && (reloc_addr < codeSec->Misc.VirtualSize);
|
||||
if (!is64bit && !is_in_code) {
|
||||
// in case of 32 bit PEs process only the relocations form the code section
|
||||
return true;
|
||||
}
|
||||
ULONGLONG rva = 0;
|
||||
if (is64bit) {
|
||||
ULONGLONG* relocateAddr = (ULONGLONG*)((ULONG_PTR)relocField);
|
||||
rva = (*relocateAddr);
|
||||
//std::cout << std::hex << (relocField - (ULONGLONG)peBuffer) << " : " << rva << std::endl;
|
||||
}
|
||||
else {
|
||||
DWORD* relocateAddr = (DWORD*)((ULONG_PTR)relocField);
|
||||
rva = ULONGLONG(*relocateAddr);
|
||||
//std::cout << std::hex << (relocField - (ULONGLONG)peBuffer) << " : " << rva << std::endl;
|
||||
}
|
||||
relocs.insert(rva);
|
||||
return true;
|
||||
}
|
||||
|
||||
static PIMAGE_SECTION_HEADER getCodeSection(BYTE *peBuffer, size_t bufferSize)
|
||||
{
|
||||
size_t sec_count = peconv::get_sections_count(peBuffer, bufferSize);
|
||||
for (size_t i = 0; i < sec_count; i++) {
|
||||
PIMAGE_SECTION_HEADER hdr = peconv::get_section_hdr(peBuffer, bufferSize, i);
|
||||
if (!hdr) break;
|
||||
if (hdr->VirtualAddress == 0 || hdr->SizeOfRawData == 0) {
|
||||
continue;
|
||||
}
|
||||
if (hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
||||
return hdr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::set<ULONGLONG> &relocs;
|
||||
PIMAGE_SECTION_HEADER codeSec;
|
||||
|
||||
BYTE *peBuffer;
|
||||
size_t bufferSize;
|
||||
};
|
||||
}
|
||||
|
||||
ULONGLONG peconv::find_base_candidate(IN BYTE* modulePtr, IN size_t moduleSize)
|
||||
{
|
||||
if (moduleSize == 0) {
|
||||
moduleSize = peconv::get_image_size((const BYTE*)modulePtr);
|
||||
}
|
||||
if (moduleSize == 0) return 0;
|
||||
|
||||
bool is64 = peconv::is64bit(modulePtr);
|
||||
std::set<ULONGLONG> relocs;
|
||||
peconv::CollectCodeRelocs callback(modulePtr, moduleSize, is64, relocs);
|
||||
if (!peconv::process_relocation_table(modulePtr, moduleSize, &callback)) {
|
||||
return 0;
|
||||
}
|
||||
if (relocs.size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PIMAGE_SECTION_HEADER hdr = peconv::CollectCodeRelocs::getCodeSection(modulePtr, moduleSize);
|
||||
if (!hdr) {
|
||||
return 0;
|
||||
}
|
||||
const ULONGLONG mask = ~ULONGLONG(0xFFFF);
|
||||
std::map<ULONGLONG, size_t>base_candidates;
|
||||
|
||||
std::set<ULONGLONG>::iterator itr = relocs.begin();
|
||||
|
||||
for (itr = relocs.begin(); itr != relocs.end(); ++itr) {
|
||||
const ULONGLONG guessed_base = (*itr) & mask;
|
||||
std::map<ULONGLONG, size_t>::iterator found = base_candidates.find(guessed_base);
|
||||
if (found == base_candidates.end()) {
|
||||
base_candidates[guessed_base] = 0;
|
||||
}
|
||||
base_candidates[guessed_base]++;
|
||||
}
|
||||
ULONGLONG most_freqent = 0;
|
||||
size_t max_freq = 0;
|
||||
std::map<ULONGLONG, size_t>::iterator mapItr;
|
||||
for (mapItr = base_candidates.begin(); mapItr != base_candidates.end(); ++mapItr) {
|
||||
if (mapItr->second >= max_freq) {
|
||||
most_freqent = mapItr->first;
|
||||
max_freq = mapItr->second;
|
||||
}
|
||||
}
|
||||
for (itr = relocs.begin(); itr != relocs.end(); ++itr) {
|
||||
ULONGLONG first = *itr;
|
||||
ULONGLONG first_base = first & mask;
|
||||
if (first_base > most_freqent) {
|
||||
break;
|
||||
}
|
||||
ULONGLONG delta = most_freqent - first_base;
|
||||
if (delta < moduleSize) {
|
||||
return first_base;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
137
Etw Syscall/libpeconv-master/libpeconv/src/fix_dot_net_ep.cpp
Normal file
137
Etw Syscall/libpeconv-master/libpeconv/src/fix_dot_net_ep.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "fix_dot_net_ep.h"
|
||||
#include <peconv.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class ListImportNames : public peconv::ImportThunksCallback
|
||||
{
|
||||
public:
|
||||
ListImportNames(BYTE* _modulePtr, size_t _moduleSize, std::map<std::string, DWORD> &name_to_addr)
|
||||
: ImportThunksCallback(_modulePtr, _moduleSize), nameToAddr(name_to_addr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr)
|
||||
{
|
||||
if (this->is64b) {
|
||||
IMAGE_THUNK_DATA64* desc = reinterpret_cast<IMAGE_THUNK_DATA64*>(origFirstThunkPtr);
|
||||
ULONGLONG* call_via = reinterpret_cast<ULONGLONG*>(firstThunkPtr);
|
||||
return processThunks_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG64);
|
||||
}
|
||||
IMAGE_THUNK_DATA32* desc = reinterpret_cast<IMAGE_THUNK_DATA32*>(origFirstThunkPtr);
|
||||
DWORD* call_via = reinterpret_cast<DWORD*>(firstThunkPtr);
|
||||
return processThunks_tpl<DWORD, IMAGE_THUNK_DATA32>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG32);
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
|
||||
bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA* desc, T_FIELD* call_via, T_FIELD ordinal_flag)
|
||||
{
|
||||
DWORD call_via_rva = static_cast<DWORD>((ULONG_PTR)call_via - (ULONG_PTR)this->modulePtr);
|
||||
#ifdef _DEBUG
|
||||
std::cout << "via RVA: " << std::hex << call_via_rva << " : ";
|
||||
#endif
|
||||
bool is_by_ord = (desc->u1.Ordinal & ordinal_flag) != 0;
|
||||
if (!is_by_ord) {
|
||||
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + desc->u1.AddressOfData);
|
||||
LPSTR func_name = reinterpret_cast<LPSTR>(by_name->Name);
|
||||
#ifdef _DEBUG
|
||||
std::cout << "name: " << func_name << std::endl;
|
||||
#endif
|
||||
nameToAddr[func_name] = call_via_rva;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::map<std::string, DWORD> &nameToAddr;
|
||||
};
|
||||
|
||||
DWORD find_corexemain(BYTE *buf, size_t buf_size)
|
||||
{
|
||||
std::map<std::string, DWORD> name_to_addr;
|
||||
ListImportNames callback(buf, buf_size, name_to_addr);
|
||||
if (!peconv::process_import_table(buf, buf_size, &callback)) return 0;
|
||||
|
||||
std::map<std::string, DWORD>::iterator found = name_to_addr.find("_CorExeMain");
|
||||
if (found != name_to_addr.end()) return found->second;
|
||||
|
||||
found = name_to_addr.find("_CorDllMain");
|
||||
if (found != name_to_addr.end()) return found->second;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BYTE* search_jump(BYTE *buf, size_t buf_size, const DWORD cor_exe_main_thunk, const ULONGLONG img_base)
|
||||
{
|
||||
// search the jump pattern, i.e.:
|
||||
//JMP DWORD NEAR [0X402000] : FF 25 00204000
|
||||
const size_t jmp_size = 2;
|
||||
const BYTE jmp_pattern[jmp_size] = { 0xFF, 0x25 };
|
||||
|
||||
const size_t arg_size = sizeof(DWORD);
|
||||
if ((jmp_size + arg_size) > buf_size) {
|
||||
return nullptr;
|
||||
}
|
||||
const size_t end_offset = buf_size - (jmp_size + arg_size);
|
||||
|
||||
for (size_t i = end_offset; // search backwards
|
||||
(i + 1) != 0; // this is unsigned comparison, so we cannot do: i >= 0
|
||||
i--) // go back by one BYTE
|
||||
{
|
||||
if (buf[i] == jmp_pattern[0] && buf[i + 1] == jmp_pattern[1]) { // JMP
|
||||
DWORD* addr = (DWORD*)(&buf[i + jmp_size]);
|
||||
DWORD rva = static_cast<DWORD>((*addr) - img_base);
|
||||
if (rva == cor_exe_main_thunk) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Found call to _CorExeMain\n";
|
||||
#endif
|
||||
return buf + i;
|
||||
}
|
||||
else {
|
||||
std::cerr << "[!] Mismatch: " << std::hex << rva << " vs _CorExeMain: " << cor_exe_main_thunk << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool fix_dot_net_ep(BYTE *pe_buffer, size_t pe_buffer_size)
|
||||
{
|
||||
if (!pe_buffer) return false;
|
||||
|
||||
if (peconv::is64bit(pe_buffer)) {
|
||||
//64bit .NET files have EP=0
|
||||
peconv::update_entry_point_rva(pe_buffer, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD ep_rva = peconv::get_entry_point_rva(pe_buffer);
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[*] This is a .NET payload and may require Enty Point correction. Current EP: " << std::hex << ep_rva << "\n";
|
||||
#endif
|
||||
PIMAGE_SECTION_HEADER sec_hdr = peconv::get_section_hdr(pe_buffer, pe_buffer_size, 0);
|
||||
if (!sec_hdr) {
|
||||
return false;
|
||||
}
|
||||
BYTE* sec_ptr = (BYTE*)((ULONG_PTR)pe_buffer + sec_hdr->VirtualAddress);
|
||||
if (!peconv::validate_ptr(pe_buffer, pe_buffer_size, sec_ptr, sec_hdr->SizeOfRawData)) {
|
||||
return false;
|
||||
}
|
||||
ULONGLONG img_base = peconv::get_image_base(pe_buffer);
|
||||
DWORD cor_exe_main_thunk = find_corexemain(pe_buffer, pe_buffer_size);
|
||||
if (!cor_exe_main_thunk) {
|
||||
return false;
|
||||
}
|
||||
BYTE* jump_ptr = search_jump(sec_ptr, sec_hdr->SizeOfRawData, cor_exe_main_thunk, img_base);
|
||||
if (!jump_ptr) {
|
||||
return false;
|
||||
}
|
||||
size_t offset = (ULONG_PTR)jump_ptr - (ULONG_PTR)pe_buffer;
|
||||
peconv::update_entry_point_rva(pe_buffer, static_cast<DWORD>(offset));
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[*] Found possible Entry Point: " << std::hex << offset << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
bool fix_dot_net_ep(BYTE *pe_buffer, size_t pe_buffer_size);
|
||||
|
||||
BYTE* search_jump(BYTE *buf, size_t buf_size, const DWORD cor_exe_main_thunk, const ULONGLONG img_base);
|
||||
306
Etw Syscall/libpeconv-master/libpeconv/src/fix_imports.cpp
Normal file
306
Etw Syscall/libpeconv-master/libpeconv/src/fix_imports.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
#include "peconv/fix_imports.h"
|
||||
#include "peconv/imports_uneraser.h"
|
||||
#include "peconv/file_util.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
template <typename FIELD_T>
|
||||
size_t find_addresses_to_fill(FIELD_T call_via, FIELD_T thunk_addr, LPVOID modulePtr, size_t moduleSize, IN const peconv::ExportsMapper& exportsMap, OUT std::set<ULONGLONG> &addresses)
|
||||
{
|
||||
size_t addrCounter = 0;
|
||||
do {
|
||||
LPVOID call_via_ptr = (LPVOID)((ULONGLONG)modulePtr + call_via);
|
||||
if (call_via_ptr == nullptr) break;
|
||||
|
||||
LPVOID thunk_ptr = (LPVOID)((ULONGLONG)modulePtr + thunk_addr);
|
||||
if (thunk_ptr == nullptr) break;
|
||||
|
||||
if (!validate_ptr(modulePtr, moduleSize, thunk_ptr, sizeof(FIELD_T))) {
|
||||
break;
|
||||
}
|
||||
if (!validate_ptr(modulePtr, moduleSize, call_via_ptr, sizeof(FIELD_T))) {
|
||||
break;
|
||||
}
|
||||
FIELD_T *thunk_val = reinterpret_cast<FIELD_T*>(thunk_ptr);
|
||||
FIELD_T *call_via_val = reinterpret_cast<FIELD_T*>(call_via_ptr);
|
||||
if (*call_via_val == 0) {
|
||||
//nothing to fill, probably the last record
|
||||
break;
|
||||
}
|
||||
|
||||
ULONGLONG searchedAddr = ULONGLONG(*call_via_val);
|
||||
if (exportsMap.find_export_by_va(searchedAddr) != nullptr) {
|
||||
addresses.insert(searchedAddr);
|
||||
addrCounter++;
|
||||
}
|
||||
//---
|
||||
call_via += sizeof(FIELD_T);
|
||||
thunk_addr += sizeof(FIELD_T);
|
||||
} while (true);
|
||||
|
||||
return addrCounter;
|
||||
}
|
||||
|
||||
std::set<std::string> get_all_dlls_exporting_function(ULONGLONG func_addr, const peconv::ExportsMapper& exportsMap)
|
||||
{
|
||||
std::set<std::string> currDllNames;
|
||||
//1. Get all the functions from all accessible DLLs that correspond to this address:
|
||||
const std::set<ExportedFunc>* exports_for_va = exportsMap.find_exports_by_va(func_addr);
|
||||
if (!exports_for_va) {
|
||||
std::cerr << "Cannot find any DLL exporting: " << std::hex << func_addr << std::endl;
|
||||
return currDllNames; //empty
|
||||
}
|
||||
//2. Iterate through their DLL names and add them to a set:
|
||||
for (std::set<ExportedFunc>::iterator strItr = exports_for_va->begin();
|
||||
strItr != exports_for_va->end();
|
||||
++strItr)
|
||||
{
|
||||
currDllNames.insert(strItr->libName);
|
||||
}
|
||||
return currDllNames;
|
||||
}
|
||||
|
||||
std::set<std::string> get_dlls_intersection(const std::set<std::string> &dllNames, const std::set<std::string> &currDllNames)
|
||||
{
|
||||
std::set<std::string> resultSet;
|
||||
std::set_intersection(dllNames.begin(), dllNames.end(),
|
||||
currDllNames.begin(), currDllNames.end(),
|
||||
std::inserter(resultSet, resultSet.begin())
|
||||
);
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
//find the name of the DLL that can cover all the addresses of imported functions
|
||||
std::string find_covering_dll(std::set<ULONGLONG> &addresses, const peconv::ExportsMapper& exportsMap)
|
||||
{
|
||||
std::set<std::string> mainDllsSet;
|
||||
std::set<std::string> reserveDllSet;
|
||||
bool isFresh = true;
|
||||
|
||||
// the earliest addresses are more significant for the final decision on what DLL to choose
|
||||
// so, they should be processed at the end
|
||||
std::set<ULONGLONG>::iterator addrItr;
|
||||
|
||||
for (addrItr = addresses.begin(); addrItr != addresses.end(); ++addrItr) {
|
||||
ULONGLONG searchedAddr = *addrItr;
|
||||
//---
|
||||
// 1. Find all the DLLs exporting this particular function (can be forwarded etc)
|
||||
std::set<std::string> currDllNames = get_all_dlls_exporting_function(searchedAddr, exportsMap);
|
||||
|
||||
//2. Which of those DLLs covers also previous functions from this series?
|
||||
if (isFresh) {
|
||||
//if no other function was processed before, set the current DLL set as the total set
|
||||
mainDllsSet = currDllNames;
|
||||
isFresh = false;
|
||||
continue;
|
||||
}
|
||||
// find the intersection between the total set and the current set
|
||||
std::set<std::string> resultSet = get_dlls_intersection(mainDllsSet, currDllNames);
|
||||
if (resultSet.size() > 0) {
|
||||
//found intersection, overwrite the main set
|
||||
mainDllsSet = resultSet;
|
||||
continue;
|
||||
}
|
||||
// if no intersection found in the main set, check if there is any in the reserved set:
|
||||
resultSet = get_dlls_intersection(reserveDllSet, currDllNames);
|
||||
if (resultSet.size() > 0) {
|
||||
//found intersection, overwrite the main set
|
||||
reserveDllSet = mainDllsSet; // move the current to the reserve
|
||||
mainDllsSet = resultSet;
|
||||
continue;
|
||||
}
|
||||
// no intersection found with any of the sets:
|
||||
reserveDllSet = currDllNames; //set is as a reserved DLL: to be used if it will reoccur
|
||||
}
|
||||
if (mainDllsSet.size() > 0) {
|
||||
const std::string main_dll = *(mainDllsSet.begin());
|
||||
return main_dll;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool ImportedDllCoverage::findCoveringDll()
|
||||
{
|
||||
std::string found_name = find_covering_dll(this->addresses, this->exportsMap);
|
||||
if (found_name.length() == 0) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Cannot find a covering DLL" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
this->dllName = found_name;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[+] Found DLL name: " << found_name << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t map_addresses_to_functions(std::set<ULONGLONG> &addresses,
|
||||
IN const std::string &chosenDll,
|
||||
IN const peconv::ExportsMapper& exportsMap,
|
||||
OUT std::map<ULONGLONG, std::set<ExportedFunc>> &addr_to_func,
|
||||
OUT std::set<ULONGLONG> ¬_found
|
||||
)
|
||||
{
|
||||
std::set<ULONGLONG> coveredAddresses;
|
||||
std::set<ULONGLONG>::iterator addrItr;
|
||||
for (addrItr = addresses.begin(); addrItr != addresses.end(); ++addrItr) {
|
||||
|
||||
ULONGLONG searchedAddr = *addrItr;
|
||||
|
||||
const std::set<ExportedFunc>* exports_for_va = exportsMap.find_exports_by_va(searchedAddr);
|
||||
if (exports_for_va == nullptr) {
|
||||
not_found.insert(searchedAddr);
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Cannot find any DLL exporting: " << std::hex << searchedAddr << std::endl;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
for (std::set<ExportedFunc>::iterator strItr = exports_for_va->begin();
|
||||
strItr != exports_for_va->end();
|
||||
++strItr)
|
||||
{
|
||||
std::string dll_name = strItr->libName;
|
||||
if (dll_name != chosenDll) {
|
||||
continue;
|
||||
}
|
||||
ExportedFunc func = *strItr;
|
||||
addr_to_func[searchedAddr].insert(func);
|
||||
coveredAddresses.insert(searchedAddr);
|
||||
}
|
||||
if (addr_to_func.find(searchedAddr) == addr_to_func.end()) {
|
||||
const ExportedFunc* func = exportsMap.find_export_by_va(searchedAddr);
|
||||
not_found.insert(searchedAddr);
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[WARNING] A function: " << func->toString() << " not found in the covering DLL: " << chosenDll << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return coveredAddresses.size();
|
||||
}
|
||||
|
||||
size_t ImportedDllCoverage::mapAddressesToFunctions(const std::string &dll)
|
||||
{
|
||||
//reset all stored info:
|
||||
this->mappedDllName = dll;
|
||||
if (this->addrToFunc.size() > 0) {
|
||||
this->addrToFunc.clear();
|
||||
}
|
||||
this->notFound.clear();
|
||||
|
||||
const size_t coveredCount = map_addresses_to_functions(this->addresses, dll, this->exportsMap, this->addrToFunc, this->notFound);
|
||||
#ifdef _DEBUG
|
||||
if (notFound.size()) {
|
||||
std::cout << "[-] Not all addresses are covered! Not found: " << std::dec << notFound.size() << std::endl;
|
||||
} else {
|
||||
|
||||
std::cout << "All covered!" << std::endl;
|
||||
}
|
||||
#endif
|
||||
return coveredCount;
|
||||
}
|
||||
|
||||
void ImpsNotCovered::insert(ULONGLONG thunk, ULONGLONG searchedAddr)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[-] Function not recovered: [" << std::hex << searchedAddr << "] " << std::endl;
|
||||
#endif
|
||||
thunkToAddr[thunk] = searchedAddr;
|
||||
}
|
||||
|
||||
|
||||
bool peconv::fix_imports(IN OUT PVOID modulePtr, IN size_t moduleSize, IN const peconv::ExportsMapper& exportsMap, OUT OPTIONAL peconv::ImpsNotCovered* notCovered)
|
||||
{
|
||||
bool skip_bound = false; // skip boud imports?
|
||||
IMAGE_DATA_DIRECTORY *importsDir = peconv::get_directory_entry((const BYTE*) modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
if (importsDir == NULL) {
|
||||
return true; // done! no imports -> nothing to fix
|
||||
}
|
||||
bool is64 = peconv::is64bit((BYTE*)modulePtr);
|
||||
DWORD maxSize = importsDir->Size;
|
||||
DWORD impAddr = importsDir->VirtualAddress;
|
||||
|
||||
IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL;
|
||||
DWORD parsedSize = 0;
|
||||
#ifdef _DEBUG
|
||||
printf("---IMP---\n");
|
||||
#endif
|
||||
|
||||
while (parsedSize < maxSize) {
|
||||
|
||||
lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR) modulePtr);
|
||||
if (!validate_ptr(modulePtr, moduleSize, lib_desc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
|
||||
printf("[-] Invalid descriptor pointer!\n");
|
||||
return false;
|
||||
}
|
||||
parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) {
|
||||
break;
|
||||
}
|
||||
const bool is_bound = (lib_desc->TimeDateStamp == (-1));
|
||||
if (is_bound && skip_bound) {
|
||||
continue;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("Imported Lib: %x : %x : %x\n", lib_desc->FirstThunk, lib_desc->OriginalFirstThunk, lib_desc->Name);
|
||||
#endif
|
||||
|
||||
std::string lib_name = "";
|
||||
if (lib_desc->Name != 0) {
|
||||
LPSTR name_ptr = (LPSTR)((ULONGLONG) modulePtr + lib_desc->Name);
|
||||
if (validate_ptr(modulePtr, moduleSize, name_ptr, sizeof(char) * MIN_DLL_LEN)) {
|
||||
lib_name = (LPSTR)((ULONGLONG) modulePtr + lib_desc->Name);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD call_via = lib_desc->FirstThunk;
|
||||
DWORD thunk_addr = lib_desc->OriginalFirstThunk; // warning: it can be NULL!
|
||||
std::set<ULONGLONG> addresses;
|
||||
if (!is64) {
|
||||
find_addresses_to_fill<DWORD>(call_via, thunk_addr, modulePtr, moduleSize, exportsMap, addresses);
|
||||
} else {
|
||||
find_addresses_to_fill<ULONGLONG>(call_via, thunk_addr, modulePtr, moduleSize, exportsMap, addresses);
|
||||
}
|
||||
ImportedDllCoverage dllCoverage(addresses, exportsMap);
|
||||
bool is_all_covered = dllCoverage.findCoveringDll();
|
||||
bool is_lib_erased = false;
|
||||
|
||||
lib_name = get_dll_shortname(lib_name); //without extension
|
||||
|
||||
if (lib_name.length() == 0) {
|
||||
is_lib_erased = true;
|
||||
if (is_all_covered) {
|
||||
// set a name of the covering DLL:
|
||||
lib_name = dllCoverage.dllName;
|
||||
}
|
||||
}
|
||||
if (lib_name.length() == 0) {
|
||||
//could not find a relevant DLL
|
||||
continue;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << lib_name << std::endl;
|
||||
#endif
|
||||
if (!dllCoverage.mapAddressesToFunctions(lib_name)) {
|
||||
// cannot find any functions imported from this DLL
|
||||
continue;
|
||||
}
|
||||
//everything mapped, now recover it:
|
||||
ImportsUneraser impUneraser(modulePtr, moduleSize);
|
||||
if (!impUneraser.uneraseDllImports(lib_desc, dllCoverage, notCovered)) {
|
||||
return false;
|
||||
}
|
||||
if (is_lib_erased) {
|
||||
const std::string dll_with_ext = exportsMap.get_dll_fullname(dllCoverage.dllName);
|
||||
impUneraser.uneraseDllName(lib_desc, dll_with_ext);
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "---------" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "peconv/function_resolver.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
FARPROC peconv::default_func_resolver::resolve_func(LPSTR lib_name, LPSTR func_name)
|
||||
{
|
||||
HMODULE libBasePtr = LoadLibraryA(lib_name);
|
||||
if (libBasePtr == NULL) {
|
||||
std::cerr << "Could not load the library!" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
FARPROC hProc = GetProcAddress(libBasePtr, func_name);
|
||||
if (hProc == NULL) {
|
||||
std::cerr << "Could not load the function!" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
return hProc;
|
||||
}
|
||||
224
Etw Syscall/libpeconv-master/libpeconv/src/hooks.cpp
Normal file
224
Etw Syscall/libpeconv-master/libpeconv/src/hooks.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
#include "peconv/hooks.h"
|
||||
#include "peconv.h"
|
||||
#include "peconv/peb_lookup.h"
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
namespace peconv {
|
||||
|
||||
bool is_pointer_in_ntdll(LPVOID lpAddress)
|
||||
{
|
||||
HMODULE mod = peconv::get_module_via_peb(L"ntdll.dll");
|
||||
size_t module_size = peconv::get_module_size_via_peb(mod);
|
||||
if (peconv::validate_ptr(mod, module_size, lpAddress, sizeof(BYTE))) {
|
||||
return true; //this address lies within NTDLL
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL nt_protect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
|
||||
{
|
||||
FARPROC proc = peconv::get_exported_func(
|
||||
peconv::get_module_via_peb(L"ntdll.dll"),
|
||||
"NtProtectVirtualMemory"
|
||||
);
|
||||
if (!proc) {
|
||||
return FALSE;
|
||||
}
|
||||
NTSTATUS(NTAPI *_NtProtectVirtualMemory)(
|
||||
IN HANDLE,
|
||||
IN OUT PVOID*,
|
||||
IN OUT PSIZE_T,
|
||||
IN DWORD,
|
||||
OUT PDWORD) =
|
||||
(NTSTATUS(NTAPI *)(
|
||||
IN HANDLE,
|
||||
IN OUT PVOID*,
|
||||
IN OUT PSIZE_T,
|
||||
IN DWORD,
|
||||
OUT PDWORD)) proc;
|
||||
|
||||
SIZE_T protect_size = dwSize;
|
||||
NTSTATUS status = _NtProtectVirtualMemory(GetCurrentProcess(), &lpAddress, &protect_size, flNewProtect, lpflOldProtect);
|
||||
if (status != S_OK) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
};
|
||||
|
||||
bool PatchBackup::makeBackup(BYTE *patch_ptr, size_t patch_size)
|
||||
{
|
||||
if (!patch_ptr) {
|
||||
return false;
|
||||
}
|
||||
deleteBackup();
|
||||
this->sourcePtr = patch_ptr;
|
||||
this->buffer = new BYTE[patch_size];
|
||||
this->bufferSize = patch_size;
|
||||
|
||||
memcpy(buffer, patch_ptr, patch_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PatchBackup::applyBackup()
|
||||
{
|
||||
if (!isBackup()) {
|
||||
return false;
|
||||
}
|
||||
DWORD oldProtect = 0;
|
||||
if (!nt_protect((LPVOID)sourcePtr, bufferSize, PAGE_EXECUTE_READWRITE, &oldProtect)) {
|
||||
return false;
|
||||
}
|
||||
memcpy(sourcePtr, buffer, bufferSize);
|
||||
nt_protect((LPVOID)sourcePtr, bufferSize, oldProtect, &oldProtect);
|
||||
|
||||
//flush cache:
|
||||
FlushInstructionCache(GetCurrentProcess(), sourcePtr, bufferSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
FARPROC peconv::hooking_func_resolver::resolve_func(LPSTR lib_name, LPSTR func_name)
|
||||
{
|
||||
//the name may be ordinal rather than string, so check if it is a valid pointer:
|
||||
if (!peconv::is_bad_read_ptr(func_name, 1)) {
|
||||
std::map<std::string, FARPROC>::iterator itr = hooks_map.find(func_name);
|
||||
if (itr != hooks_map.end()) {
|
||||
FARPROC hook = itr->second;
|
||||
#ifdef _DEBUG
|
||||
std::cout << ">>>>>>Replacing: " << func_name << " by: " << hook << std::endl;
|
||||
#endif
|
||||
return hook;
|
||||
}
|
||||
}
|
||||
return peconv::default_func_resolver::resolve_func(lib_name, func_name);
|
||||
}
|
||||
|
||||
size_t peconv::redirect_to_local64(void *ptr, ULONGLONG new_offset, PatchBackup* backup)
|
||||
{
|
||||
if (!ptr) return 0;
|
||||
|
||||
BYTE hook_64[] = {
|
||||
0x48, 0xB8, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xEE, 0xFF, //movabs rax,FFEE998877665544
|
||||
0xFF, 0xE0 //jmp rax
|
||||
};
|
||||
const size_t hook64_size = sizeof(hook_64);
|
||||
if (is_pointer_in_ntdll(ptr)) {
|
||||
std::cout << "[WARNING] Patching NTDLL is not allowed because of possible stability issues!\n";
|
||||
return 0;
|
||||
}
|
||||
DWORD oldProtect = 0;
|
||||
if (!nt_protect((LPVOID)ptr,
|
||||
hook64_size,
|
||||
PAGE_EXECUTE_READWRITE, //this must be executable if we are hooking kernel32.dll, because we are using VirtualProtect from kernel32 at the same time
|
||||
&oldProtect))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (backup != nullptr) {
|
||||
backup->makeBackup((BYTE*)ptr, hook64_size);
|
||||
}
|
||||
memcpy(hook_64 + 2, &new_offset, sizeof(ULONGLONG));
|
||||
memcpy(ptr, hook_64, hook64_size);
|
||||
|
||||
nt_protect((LPVOID)ptr, hook64_size, oldProtect, &oldProtect);
|
||||
|
||||
//flush cache:
|
||||
FlushInstructionCache(GetCurrentProcess(), ptr, hook64_size);
|
||||
return hook64_size;
|
||||
}
|
||||
|
||||
size_t peconv::redirect_to_local32(void *ptr, DWORD new_offset, PatchBackup* backup)
|
||||
{
|
||||
if (!ptr) return 0;
|
||||
|
||||
BYTE hook_32[] = {
|
||||
0xB8, 0xCC, 0xDD, 0xEE, 0xFF, // mov eax,FFEEDDCC
|
||||
0xFF, 0xE0 //jmp eax
|
||||
};
|
||||
const size_t hook32_size = sizeof(hook_32);
|
||||
if (is_pointer_in_ntdll(ptr)) {
|
||||
std::cout << "[WARNING] Patching NTDLL is not allowed because of possible stability issues!\n";
|
||||
return 0;
|
||||
}
|
||||
DWORD oldProtect = 0;
|
||||
if (!nt_protect((LPVOID)ptr,
|
||||
hook32_size,
|
||||
PAGE_EXECUTE_READWRITE, //this must be executable if we are hooking kernel32.dll, because we are using VirtualProtect from kernel32 at the same time
|
||||
&oldProtect))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (backup != nullptr) {
|
||||
backup->makeBackup((BYTE*)ptr, hook32_size);
|
||||
}
|
||||
memcpy(hook_32 + 1, &new_offset, sizeof(DWORD));
|
||||
memcpy(ptr, hook_32, hook32_size);
|
||||
|
||||
nt_protect((LPVOID)ptr, hook32_size, oldProtect, &oldProtect);
|
||||
|
||||
//flush cache:
|
||||
FlushInstructionCache(GetCurrentProcess(), ptr, hook32_size);
|
||||
return hook32_size;
|
||||
}
|
||||
|
||||
size_t peconv::redirect_to_local(void *ptr, void* new_function_ptr, PatchBackup* backup)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
return peconv::redirect_to_local64(ptr, (ULONGLONG)new_function_ptr, backup);
|
||||
#else
|
||||
return peconv::redirect_to_local32(ptr, (DWORD)new_function_ptr, backup);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline long long int get_jmp_delta(ULONGLONG currVA, int instrLen, ULONGLONG destVA)
|
||||
{
|
||||
long long int diff = destVA - (currVA + instrLen);
|
||||
return diff;
|
||||
}
|
||||
|
||||
inline bool is_valid_delta(long long int delta)
|
||||
{
|
||||
DWORD first_dw = delta >> sizeof(DWORD) * 8;
|
||||
if (first_dw == 0) {
|
||||
return true;
|
||||
}
|
||||
const DWORD max_dword = DWORD(-1);
|
||||
if (first_dw != max_dword) {
|
||||
return false;
|
||||
}
|
||||
DWORD delta_dw = DWORD(delta);
|
||||
if (delta_dw & 0x80000000) {
|
||||
return true;
|
||||
}
|
||||
//invalid, sign bit is missing
|
||||
return false;
|
||||
}
|
||||
|
||||
bool peconv::replace_target(BYTE *patch_ptr, ULONGLONG dest_addr)
|
||||
{
|
||||
typedef enum {
|
||||
OP_JMP = 0xE9,
|
||||
OP_CALL_DWORD = 0xE8
|
||||
} t_opcode;
|
||||
|
||||
if (patch_ptr[0] == OP_JMP || patch_ptr[0] == OP_CALL_DWORD) {
|
||||
ULONGLONG delta = get_jmp_delta(ULONGLONG(patch_ptr), 5, dest_addr);
|
||||
if (!is_valid_delta(delta)) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Cannot replace the target: too big delta: " << std::hex << delta << std::endl;
|
||||
#endif
|
||||
//too big delta, cannot be saved in a DWORD
|
||||
return false;
|
||||
}
|
||||
DWORD delta_dw = DWORD(delta);
|
||||
memcpy(patch_ptr + 1, &delta_dw, sizeof(DWORD));
|
||||
|
||||
//flush cache:
|
||||
FlushInstructionCache(GetCurrentProcess(), patch_ptr + 1, sizeof(DWORD));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
271
Etw Syscall/libpeconv-master/libpeconv/src/imports_loader.cpp
Normal file
271
Etw Syscall/libpeconv-master/libpeconv/src/imports_loader.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
#include "peconv/imports_loader.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
class FillImportThunks : public ImportThunksCallback
|
||||
{
|
||||
public:
|
||||
FillImportThunks(BYTE* _modulePtr, size_t _moduleSize, t_function_resolver* func_resolver)
|
||||
: ImportThunksCallback(_modulePtr, _moduleSize), funcResolver(func_resolver)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr)
|
||||
{
|
||||
if (this->is64b) {
|
||||
#ifdef _WIN64 // loader is 64 bit, allow to load imports for 64-bit payload:
|
||||
IMAGE_THUNK_DATA64* desc = reinterpret_cast<IMAGE_THUNK_DATA64*>(origFirstThunkPtr);
|
||||
ULONGLONG* call_via = reinterpret_cast<ULONGLONG*>(firstThunkPtr);
|
||||
return processThunks_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG64);
|
||||
#else
|
||||
std::cerr << "[!] Cannot fill imports into 64 bit PE via 32 bit loader!\n";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifndef _WIN64 // loader is 32 bit, allow to load imports for 32-bit payload:
|
||||
IMAGE_THUNK_DATA32* desc = reinterpret_cast<IMAGE_THUNK_DATA32*>(origFirstThunkPtr);
|
||||
DWORD* call_via = reinterpret_cast<DWORD*>(firstThunkPtr);
|
||||
return processThunks_tpl<DWORD, IMAGE_THUNK_DATA32>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG32);
|
||||
#else
|
||||
std::cerr << "[!] Cannot fill imports into 32 bit PE via 64 bit loader!\n";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
|
||||
bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA* desc, T_FIELD* call_via, T_FIELD ordinal_flag)
|
||||
{
|
||||
if (!this->funcResolver) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_by_ord = (desc->u1.Ordinal & ordinal_flag) != 0;
|
||||
|
||||
FARPROC hProc = nullptr;
|
||||
if (is_by_ord) {
|
||||
T_FIELD raw_ordinal = desc->u1.Ordinal & (~ordinal_flag);
|
||||
#ifdef _DEBUG
|
||||
std::cout << "raw ordinal: " << std::hex << raw_ordinal << std::endl;
|
||||
#endif
|
||||
hProc = funcResolver->resolve_func(lib_name, MAKEINTRESOURCEA(raw_ordinal));
|
||||
|
||||
}
|
||||
else {
|
||||
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + desc->u1.AddressOfData);
|
||||
LPSTR func_name = reinterpret_cast<LPSTR>(by_name->Name);
|
||||
#ifdef _DEBUG
|
||||
std::cout << "name: " << func_name << std::endl;
|
||||
#endif
|
||||
hProc = this->funcResolver->resolve_func(lib_name, func_name);
|
||||
}
|
||||
if (!hProc) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Could not resolve the function!" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
(*call_via) = reinterpret_cast<T_FIELD>(hProc);
|
||||
return true;
|
||||
}
|
||||
|
||||
//fields:
|
||||
t_function_resolver* funcResolver;
|
||||
};
|
||||
|
||||
|
||||
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
|
||||
bool process_imp_functions_tpl(BYTE* modulePtr, size_t module_size, LPSTR lib_name, DWORD call_via, DWORD thunk_addr, IN ImportThunksCallback *callback)
|
||||
{
|
||||
bool is_ok = true;
|
||||
|
||||
T_FIELD *thunks = (T_FIELD*)((ULONGLONG)modulePtr + thunk_addr);
|
||||
T_FIELD *callers = (T_FIELD*)((ULONGLONG)modulePtr + call_via);
|
||||
|
||||
for (size_t index = 0; true; index++) {
|
||||
if (!validate_ptr(modulePtr, module_size, &callers[index], sizeof(T_FIELD))) {
|
||||
break;
|
||||
}
|
||||
if (!validate_ptr(modulePtr, module_size, &thunks[index], sizeof(T_FIELD))) {
|
||||
break;
|
||||
}
|
||||
if (callers[index] == 0) {
|
||||
//nothing to fill, probably the last record
|
||||
return true;
|
||||
}
|
||||
LPVOID thunk_ptr = &thunks[index];
|
||||
T_IMAGE_THUNK_DATA* desc = reinterpret_cast<T_IMAGE_THUNK_DATA*>(thunk_ptr);
|
||||
if (!validate_ptr(modulePtr, module_size, desc, sizeof(T_IMAGE_THUNK_DATA))) {
|
||||
break;
|
||||
}
|
||||
if (desc->u1.Function == NULL) {
|
||||
break;
|
||||
}
|
||||
T_FIELD ordinal_flag = (sizeof(T_FIELD) == sizeof(ULONGLONG)) ? IMAGE_ORDINAL_FLAG64 : IMAGE_ORDINAL_FLAG32;
|
||||
bool is_by_ord = (desc->u1.Ordinal & ordinal_flag) != 0;
|
||||
if (!is_by_ord) {
|
||||
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + desc->u1.AddressOfData);
|
||||
if (!validate_ptr(modulePtr, module_size, by_name, sizeof(IMAGE_IMPORT_BY_NAME))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//when the callback is called, all the pointers should be already verified
|
||||
if (!callback->processThunks(lib_name, (ULONG_PTR)&thunks[index], (ULONG_PTR)&callers[index])) {
|
||||
is_ok = false;
|
||||
}
|
||||
}
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
//Walk through the table of imported DLLs (starting from the given descriptor) and execute the callback each time when the new record was found
|
||||
bool process_dlls(BYTE* modulePtr, size_t module_size, IMAGE_IMPORT_DESCRIPTOR *first_desc, IN ImportThunksCallback *callback)
|
||||
{
|
||||
bool isAllFilled = true;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "---IMP---" << std::endl;
|
||||
#endif
|
||||
const bool is64 = is64bit((BYTE*)modulePtr);
|
||||
IMAGE_IMPORT_DESCRIPTOR* lib_desc = nullptr;
|
||||
|
||||
for (size_t i = 0; true; i++) {
|
||||
lib_desc = &first_desc[i];
|
||||
if (!validate_ptr(modulePtr, module_size, lib_desc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
|
||||
break;
|
||||
}
|
||||
if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) {
|
||||
break;
|
||||
}
|
||||
LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->Name);
|
||||
if (!peconv::is_valid_import_name(modulePtr, module_size, lib_name)) {
|
||||
//invalid name
|
||||
return false;
|
||||
}
|
||||
DWORD call_via = lib_desc->FirstThunk;
|
||||
DWORD thunk_addr = lib_desc->OriginalFirstThunk;
|
||||
if (thunk_addr == NULL) {
|
||||
thunk_addr = lib_desc->FirstThunk;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Imported Lib: " << std::hex << lib_desc->FirstThunk << " : " << std::hex << lib_desc->OriginalFirstThunk << " : " << lib_desc->Name << std::endl;
|
||||
#endif
|
||||
size_t all_solved = false;
|
||||
if (is64) {
|
||||
all_solved = process_imp_functions_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(modulePtr, module_size, lib_name, call_via, thunk_addr, callback);
|
||||
}
|
||||
else {
|
||||
all_solved = process_imp_functions_tpl<DWORD, IMAGE_THUNK_DATA32>(modulePtr, module_size, lib_name, call_via, thunk_addr, callback);
|
||||
}
|
||||
if (!all_solved) {
|
||||
isAllFilled = false;
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("---------\n");
|
||||
#endif
|
||||
return isAllFilled;
|
||||
}
|
||||
|
||||
bool peconv::process_import_table(IN BYTE* modulePtr, IN SIZE_T moduleSize, IN ImportThunksCallback *callback)
|
||||
{
|
||||
if (moduleSize == 0) { //if not given, try to fetch
|
||||
moduleSize = peconv::get_image_size((const BYTE*)modulePtr);
|
||||
}
|
||||
if (moduleSize == 0) return false;
|
||||
|
||||
IMAGE_DATA_DIRECTORY *importsDir = get_directory_entry((BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
if (!importsDir) {
|
||||
return true; //no import table
|
||||
}
|
||||
const DWORD impAddr = importsDir->VirtualAddress;
|
||||
IMAGE_IMPORT_DESCRIPTOR *first_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + (ULONG_PTR)modulePtr);
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, first_desc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
|
||||
return false;
|
||||
}
|
||||
return process_dlls(modulePtr, moduleSize, first_desc, callback);
|
||||
}
|
||||
|
||||
bool peconv::load_imports(BYTE* modulePtr, t_function_resolver* func_resolver)
|
||||
{
|
||||
size_t moduleSize = peconv::get_image_size((const BYTE*)modulePtr);
|
||||
if (moduleSize == 0) return false;
|
||||
|
||||
bool is64 = is64bit((BYTE*)modulePtr);
|
||||
bool is_loader64 = false;
|
||||
#ifdef _WIN64
|
||||
is_loader64 = true;
|
||||
#endif
|
||||
if (is64 != is_loader64) {
|
||||
std::cerr << "[ERROR] Loader/Payload bitness mismatch.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
default_func_resolver default_res;
|
||||
if (!func_resolver) {
|
||||
func_resolver = (t_function_resolver*)&default_res;
|
||||
}
|
||||
|
||||
FillImportThunks callback(modulePtr, moduleSize, func_resolver);
|
||||
return peconv::process_import_table(modulePtr, moduleSize, &callback);
|
||||
}
|
||||
|
||||
// A valid name must contain printable characters. Empty name is also acceptable (may have been erased)
|
||||
bool peconv::is_valid_import_name(const PBYTE modulePtr, const size_t moduleSize, LPSTR lib_name)
|
||||
{
|
||||
while (true) {
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, lib_name, sizeof(char))) {
|
||||
return false;
|
||||
}
|
||||
char next_char = *lib_name;
|
||||
if (next_char == '\0') break;
|
||||
|
||||
if (next_char <= 0x20 || next_char >= 0x7E) {
|
||||
return false;
|
||||
}
|
||||
lib_name++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool peconv::has_valid_import_table(const PBYTE modulePtr, size_t moduleSize)
|
||||
{
|
||||
IMAGE_DATA_DIRECTORY *importsDir = get_directory_entry((BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
if (importsDir == NULL) return false;
|
||||
|
||||
const DWORD impAddr = importsDir->VirtualAddress;
|
||||
|
||||
IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL;
|
||||
DWORD parsedSize = 0;
|
||||
size_t valid_records = 0;
|
||||
|
||||
while (true) { //size of the import table doesn't matter
|
||||
lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR)modulePtr);
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, lib_desc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
|
||||
return false;
|
||||
}
|
||||
parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
|
||||
if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) {
|
||||
break;
|
||||
}
|
||||
LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->Name);
|
||||
if (!is_valid_import_name(modulePtr, moduleSize, lib_name)) return false;
|
||||
|
||||
DWORD call_via = lib_desc->FirstThunk;
|
||||
DWORD thunk_addr = lib_desc->OriginalFirstThunk;
|
||||
if (thunk_addr == NULL) thunk_addr = lib_desc->FirstThunk;
|
||||
|
||||
DWORD *thunks = (DWORD*)((ULONGLONG)modulePtr + thunk_addr);
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, thunks, sizeof(DWORD))) return false;
|
||||
|
||||
DWORD *callers = (DWORD*)((ULONGLONG)modulePtr + call_via);
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, callers, sizeof(DWORD))) return false;
|
||||
|
||||
valid_records++;
|
||||
}
|
||||
|
||||
return (valid_records > 0);
|
||||
}
|
||||
243
Etw Syscall/libpeconv-master/libpeconv/src/imports_uneraser.cpp
Normal file
243
Etw Syscall/libpeconv-master/libpeconv/src/imports_uneraser.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
#include "peconv/imports_uneraser.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
LPVOID search_name(std::string name, const char* modulePtr, size_t moduleSize)
|
||||
{
|
||||
const char* namec = name.c_str();
|
||||
const size_t searched_len = name.length() + 1; // with terminating NULL
|
||||
const char* found_ptr = std::search(modulePtr, modulePtr + moduleSize, namec, namec + searched_len);
|
||||
if (found_ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
size_t o = found_ptr - modulePtr;
|
||||
if (o < moduleSize) {
|
||||
return (LPVOID)(found_ptr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ImportsUneraser::writeFoundDllName(IMAGE_IMPORT_DESCRIPTOR* lib_desc, const std::string &found_name)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Found name:" << found_name << std::endl;
|
||||
#endif
|
||||
LPSTR name_ptr = (LPSTR)((ULONGLONG) modulePtr + lib_desc->Name);
|
||||
size_t full_name_len = found_name.length() + 1; // with terminating zero
|
||||
if (!validate_ptr(modulePtr, moduleSize, name_ptr, full_name_len)) {
|
||||
//corner case: allow to save the name at the very end of the buffer, without the terminating zero
|
||||
full_name_len--;
|
||||
if (!validate_ptr(modulePtr, moduleSize, name_ptr, full_name_len)) {
|
||||
return false; //invalid pointer, cannot save
|
||||
}
|
||||
}
|
||||
memcpy(name_ptr, found_name.c_str(), full_name_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImportsUneraser::uneraseDllName(IMAGE_IMPORT_DESCRIPTOR* lib_desc, const std::string &dll_name)
|
||||
{
|
||||
LPSTR name_ptr = nullptr;
|
||||
if (lib_desc->Name != 0) {
|
||||
name_ptr = (LPSTR)((ULONGLONG) modulePtr + lib_desc->Name);
|
||||
}
|
||||
if (name_ptr == nullptr || !validate_ptr(modulePtr, moduleSize, name_ptr, sizeof(char) * MIN_DLL_LEN)) {
|
||||
//try to get the cave:
|
||||
DWORD cave_size = DWORD(dll_name.length() + 1 + 5); //ending null + padding
|
||||
PBYTE ptr = find_ending_cave(modulePtr, moduleSize, cave_size);
|
||||
if (ptr == nullptr) {
|
||||
std::cerr << "Cannot save the DLL name: " << dll_name << std::endl;
|
||||
return false;
|
||||
}
|
||||
DWORD cave_rva = static_cast<DWORD>(ptr - modulePtr);
|
||||
lib_desc->Name = cave_rva;
|
||||
}
|
||||
|
||||
if (writeFoundDllName(lib_desc, dll_name)) {
|
||||
return true; // written the found name
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename FIELD_T>
|
||||
bool ImportsUneraser::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
|
||||
)
|
||||
{
|
||||
if (call_via_ptr == NULL || modulePtr == NULL || lib_desc == NULL) {
|
||||
return false; //malformed input
|
||||
}
|
||||
IMAGE_DATA_DIRECTORY *importsDir = get_directory_entry((BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
if (!importsDir) return false;
|
||||
|
||||
const DWORD impAddr = importsDir->VirtualAddress; //start of the import table
|
||||
|
||||
FIELD_T *call_via_val = (FIELD_T*)call_via_ptr;
|
||||
if (*call_via_val == 0) {
|
||||
//nothing to fill, probably the last record
|
||||
return false;
|
||||
}
|
||||
ULONGLONG searchedAddr = ULONGLONG(*call_via_val);
|
||||
bool is_name_saved = false;
|
||||
|
||||
FIELD_T lastOrdinal = 0; //store also ordinal of the matching function
|
||||
std::set<ExportedFunc>::iterator funcname_itr = addr_to_func[searchedAddr].begin();
|
||||
|
||||
for (funcname_itr = addr_to_func[searchedAddr].begin();
|
||||
funcname_itr != addr_to_func[searchedAddr].end();
|
||||
++funcname_itr)
|
||||
{
|
||||
const ExportedFunc &found_func = *funcname_itr;
|
||||
lastOrdinal = found_func.funcOrdinal;
|
||||
|
||||
const char* names_start = ((const char*) modulePtr + impAddr);
|
||||
BYTE* found_ptr = (BYTE*) search_name(found_func.funcName, names_start, moduleSize - (names_start - (const char*)modulePtr));
|
||||
if (!found_ptr) {
|
||||
//name not found in the binary
|
||||
//TODO: maybe it is imported by ordinal?
|
||||
continue;
|
||||
}
|
||||
|
||||
const ULONGLONG name_offset = (ULONGLONG)found_ptr - (ULONGLONG)modulePtr;
|
||||
#ifdef _DEBUG
|
||||
//if it is not the first name from the list, inform about it:
|
||||
if (funcname_itr != addr_to_func[searchedAddr].begin()) {
|
||||
std::cout << ">[*][" << std::hex << searchedAddr << "] " << found_func.toString() << std::endl;
|
||||
}
|
||||
std::cout <<"[+] Found the name at: " << std::hex << name_offset << std::endl;
|
||||
#endif
|
||||
PIMAGE_IMPORT_BY_NAME imp_field = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(name_offset - sizeof(WORD)); // substract the size of Hint
|
||||
//TODO: validate more...
|
||||
memcpy(thunk_ptr, &imp_field, sizeof(FIELD_T));
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[+] Wrote found to offset: " << std::hex << call_via_ptr << std::endl;
|
||||
#endif
|
||||
is_name_saved = true;
|
||||
break;
|
||||
}
|
||||
//name not found or could not be saved - fill the ordinal instead:
|
||||
if (!is_name_saved && lastOrdinal != 0) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[+] Filling ordinal: " << lastOrdinal << std::endl;
|
||||
#endif
|
||||
FIELD_T ord_thunk = lastOrdinal | ordinal_flag;
|
||||
memcpy(thunk_ptr, &ord_thunk, sizeof(FIELD_T));
|
||||
is_name_saved = true;
|
||||
}
|
||||
return is_name_saved;
|
||||
}
|
||||
|
||||
template <typename FIELD_T, typename IMAGE_THUNK_DATA_T>
|
||||
bool ImportsUneraser::writeFoundFunction(IMAGE_THUNK_DATA_T* desc, const FIELD_T ordinal_flag, const ExportedFunc &foundFunc)
|
||||
{
|
||||
if (foundFunc.isByOrdinal) {
|
||||
FIELD_T ordinal = foundFunc.funcOrdinal | ordinal_flag;
|
||||
FIELD_T* by_ord = (FIELD_T*) desc;
|
||||
*by_ord = ordinal;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[+] Saved ordinal" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME) ((ULONGLONG) modulePtr + desc->u1.AddressOfData);
|
||||
|
||||
LPSTR func_name_ptr = reinterpret_cast<LPSTR>(by_name->Name);
|
||||
std::string found_name = foundFunc.funcName;
|
||||
bool is_nameptr_valid = validate_ptr(modulePtr, moduleSize, func_name_ptr, found_name.length());
|
||||
// try to save the found name under the pointer:
|
||||
if (is_nameptr_valid) {
|
||||
by_name->Hint = MASK_TO_WORD(foundFunc.funcOrdinal);
|
||||
memcpy(func_name_ptr, found_name.c_str(), found_name.length() + 1); // with the ending '\0'
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[+] Saved name" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename FIELD_T, typename IMAGE_THUNK_DATA_T>
|
||||
bool ImportsUneraser::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* notCovered
|
||||
)
|
||||
{
|
||||
if (lib_desc == NULL) return false;
|
||||
|
||||
FIELD_T call_via = lib_desc->FirstThunk;
|
||||
if (call_via == NULL) return false;
|
||||
|
||||
size_t processed_imps = 0;
|
||||
size_t recovered_imps = 0;
|
||||
|
||||
FIELD_T thunk_addr = lib_desc->OriginalFirstThunk;
|
||||
if (thunk_addr == NULL) {
|
||||
thunk_addr = call_via;
|
||||
}
|
||||
|
||||
BYTE* call_via_ptr = (BYTE*)((ULONGLONG)modulePtr + call_via);
|
||||
BYTE* thunk_ptr = (BYTE*)((ULONGLONG)modulePtr + thunk_addr);
|
||||
for (;
|
||||
call_via_ptr != NULL && thunk_ptr != NULL;
|
||||
call_via_ptr += sizeof(FIELD_T), thunk_ptr += sizeof(FIELD_T)
|
||||
)
|
||||
{
|
||||
FIELD_T *thunk_val = (FIELD_T*)thunk_ptr;
|
||||
FIELD_T *call_via_val = (FIELD_T*)call_via_ptr;
|
||||
if (*call_via_val == 0) {
|
||||
//nothing to fill, probably the last record
|
||||
break;
|
||||
}
|
||||
IMAGE_THUNK_DATA_T* desc = (IMAGE_THUNK_DATA_T*)thunk_ptr;
|
||||
if (desc->u1.Function == NULL) {
|
||||
break;
|
||||
}
|
||||
ULONGLONG searchedAddr = ULONGLONG(*call_via_val);
|
||||
std::map<ULONGLONG,std::set<ExportedFunc>>::const_iterator found_itr = addr_to_func.find(searchedAddr);
|
||||
if (found_itr == addr_to_func.end() || found_itr->second.size() == 0) {
|
||||
//not found, move on
|
||||
if (notCovered) {
|
||||
notCovered->insert((call_via_ptr - modulePtr), searchedAddr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
std::set<ExportedFunc>::const_iterator funcname_itr = found_itr->second.begin();
|
||||
const peconv::ExportedFunc &foundFunc = *funcname_itr;
|
||||
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[*][" << std::hex << searchedAddr << "] " << funcname_itr->toString() << std::endl;
|
||||
#endif
|
||||
bool is_name_saved = writeFoundFunction<FIELD_T, IMAGE_THUNK_DATA_T>(desc, ordinal_flag, *funcname_itr);
|
||||
if (!is_name_saved) {
|
||||
is_name_saved = findNameInBinaryAndFill<FIELD_T>(lib_desc, call_via_ptr, thunk_ptr, ordinal_flag, addr_to_func);
|
||||
}
|
||||
processed_imps++;
|
||||
if (is_name_saved) recovered_imps++;
|
||||
}
|
||||
|
||||
return (recovered_imps == processed_imps);
|
||||
}
|
||||
|
||||
bool ImportsUneraser::uneraseDllImports(IN OUT IMAGE_IMPORT_DESCRIPTOR* lib_desc, IN ImportedDllCoverage &dllCoverage, OUT OPTIONAL ImpsNotCovered* notCovered)
|
||||
{
|
||||
//everything mapped, now recover it:
|
||||
bool is_filled = false;
|
||||
if (!is64) {
|
||||
is_filled = fillImportNames<DWORD, IMAGE_THUNK_DATA32>(lib_desc, IMAGE_ORDINAL_FLAG32, dllCoverage.addrToFunc, notCovered);
|
||||
} else {
|
||||
is_filled = fillImportNames<ULONGLONG, IMAGE_THUNK_DATA64>(lib_desc, IMAGE_ORDINAL_FLAG64, dllCoverage.addrToFunc, notCovered);
|
||||
}
|
||||
if (!is_filled) {
|
||||
std::cerr << "[-] Could not fill some import names!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return is_filled;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "peconv/load_config_util.h"
|
||||
#include "peconv/pe_hdrs_helper.h"
|
||||
|
||||
BYTE* peconv::get_load_config_ptr(BYTE* buffer, size_t buf_size)
|
||||
{
|
||||
if (!buffer || !buf_size) return nullptr;
|
||||
IMAGE_DATA_DIRECTORY* dir = peconv::get_directory_entry(buffer, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG);
|
||||
if (!dir) {
|
||||
return 0;
|
||||
}
|
||||
DWORD entry_rva = dir->VirtualAddress;
|
||||
DWORD entry_size = dir->Size;
|
||||
if (!peconv::validate_ptr(buffer, buf_size, buffer + entry_rva, entry_size)) {
|
||||
return 0;
|
||||
}
|
||||
IMAGE_LOAD_CONFIG_DIRECTORY32* ldc = reinterpret_cast<IMAGE_LOAD_CONFIG_DIRECTORY32*>((ULONG_PTR)buffer + entry_rva);
|
||||
return reinterpret_cast<BYTE*>(ldc);
|
||||
}
|
||||
|
||||
peconv::t_load_config_ver peconv::get_load_config_version(BYTE* buffer, size_t buf_size, BYTE* ld_config_ptr)
|
||||
{
|
||||
if (!buffer || !buf_size || !ld_config_ptr) peconv::LOAD_CONFIG_NONE;
|
||||
bool is64b = peconv::is64bit(buffer);
|
||||
|
||||
if (!peconv::validate_ptr(buffer, buf_size, ld_config_ptr, sizeof(peconv::IMAGE_LOAD_CONFIG_DIR32_W7))) {
|
||||
return peconv::LOAD_CONFIG_NONE;
|
||||
}
|
||||
|
||||
peconv::IMAGE_LOAD_CONFIG_DIR32_W7* smallest = (peconv::IMAGE_LOAD_CONFIG_DIR32_W7*)ld_config_ptr;
|
||||
const size_t curr_size = smallest->Size;
|
||||
|
||||
if (is64b) {
|
||||
switch (curr_size) {
|
||||
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR64_W7) :
|
||||
return peconv::LOAD_CONFIG_W7_VER;
|
||||
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR64_W8) :
|
||||
return peconv::LOAD_CONFIG_W8_VER;
|
||||
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR64_W10) :
|
||||
return peconv::LOAD_CONFIG_W10_VER;
|
||||
default:
|
||||
return LOAD_CONFIG_UNK_VER;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (curr_size) {
|
||||
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR32_W7) :
|
||||
return peconv::LOAD_CONFIG_W7_VER;
|
||||
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR32_W8) :
|
||||
return peconv::LOAD_CONFIG_W8_VER;
|
||||
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR32_W10) :
|
||||
return peconv::LOAD_CONFIG_W10_VER;
|
||||
default:
|
||||
return LOAD_CONFIG_UNK_VER;
|
||||
}
|
||||
}
|
||||
return LOAD_CONFIG_UNK_VER;
|
||||
}
|
||||
4300
Etw Syscall/libpeconv-master/libpeconv/src/ntddk.h
Normal file
4300
Etw Syscall/libpeconv-master/libpeconv/src/ntddk.h
Normal file
File diff suppressed because it is too large
Load Diff
73
Etw Syscall/libpeconv-master/libpeconv/src/pe_dumper.cpp
Normal file
73
Etw Syscall/libpeconv-master/libpeconv/src/pe_dumper.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "peconv/pe_dumper.h"
|
||||
|
||||
#include "peconv/pe_hdrs_helper.h"
|
||||
#include "peconv/pe_virtual_to_raw.h"
|
||||
#include "peconv/fix_imports.h"
|
||||
#include "peconv/file_util.h"
|
||||
#include "peconv/pe_mode_detector.h"
|
||||
#include "fix_dot_net_ep.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
t_pe_dump_mode peconv::detect_dump_mode(IN const BYTE* buffer, IN size_t mod_size)
|
||||
{
|
||||
const t_pe_dump_mode default_mode = peconv::PE_DUMP_UNMAP;
|
||||
if (peconv::is_pe_raw(buffer, mod_size)) {
|
||||
return peconv::PE_DUMP_VIRTUAL;
|
||||
}
|
||||
if (peconv::is_pe_expanded(buffer, mod_size)) {
|
||||
return peconv::PE_DUMP_REALIGN;
|
||||
}
|
||||
return default_mode;
|
||||
}
|
||||
|
||||
bool peconv::dump_pe(IN const char *out_path,
|
||||
IN OUT BYTE *buffer, IN size_t mod_size,
|
||||
IN const ULONGLONG start_addr,
|
||||
IN OUT t_pe_dump_mode &dump_mode,
|
||||
IN OPTIONAL const peconv::ExportsMapper* exportsMap
|
||||
)
|
||||
{
|
||||
// if the exportsMap is supplied, attempt to recover the (destroyed) import table:
|
||||
if (exportsMap != nullptr) {
|
||||
if (!peconv::fix_imports(buffer, mod_size, *exportsMap, NULL)) {
|
||||
std::cerr << "[-] Unable to fix imports!" << std::endl;
|
||||
}
|
||||
}
|
||||
if (dump_mode == PE_DUMP_AUTO || dump_mode >= PE_DUMP_MODES_COUNT) {
|
||||
dump_mode = detect_dump_mode(buffer, mod_size);
|
||||
}
|
||||
|
||||
BYTE* dump_data = buffer;
|
||||
size_t dump_size = mod_size;
|
||||
size_t out_size = 0;
|
||||
BYTE* unmapped_module = nullptr;
|
||||
|
||||
if (dump_mode == peconv::PE_DUMP_UNMAP || dump_mode == peconv::PE_DUMP_REALIGN) {
|
||||
//if the image base in headers is invalid, set the current base and prevent from relocating PE:
|
||||
if (peconv::get_image_base(buffer) == 0) {
|
||||
peconv::update_image_base(buffer, (ULONGLONG)start_addr);
|
||||
}
|
||||
if (is_dot_net(buffer, mod_size)) {
|
||||
fix_dot_net_ep(buffer, mod_size);
|
||||
}
|
||||
if (dump_mode == peconv::PE_DUMP_UNMAP) {
|
||||
unmapped_module = pe_virtual_to_raw(buffer, mod_size, (ULONGLONG)start_addr, out_size, false);
|
||||
}
|
||||
else if (dump_mode == peconv::PE_DUMP_REALIGN) {
|
||||
unmapped_module = peconv::pe_realign_raw_to_virtual(buffer, mod_size, (ULONGLONG)start_addr, out_size);
|
||||
}
|
||||
// unmap the PE file (convert from the Virtual Format into Raw Format)
|
||||
if (unmapped_module) {
|
||||
dump_data = unmapped_module;
|
||||
dump_size = out_size;
|
||||
}
|
||||
}
|
||||
// save the read module into a file
|
||||
const bool is_dumped = dump_to_file(out_path, dump_data, dump_size);
|
||||
|
||||
peconv::free_pe_buffer(unmapped_module, mod_size);
|
||||
return is_dumped;
|
||||
}
|
||||
652
Etw Syscall/libpeconv-master/libpeconv/src/pe_hdrs_helper.cpp
Normal file
652
Etw Syscall/libpeconv-master/libpeconv/src/pe_hdrs_helper.cpp
Normal file
@@ -0,0 +1,652 @@
|
||||
#include "peconv/pe_hdrs_helper.h"
|
||||
#include "peconv/util.h"
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
BYTE* peconv::get_nt_hdrs(IN const BYTE *pe_buffer, IN OPTIONAL size_t buffer_size)
|
||||
{
|
||||
if (!pe_buffer) return nullptr;
|
||||
|
||||
IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*)pe_buffer;
|
||||
if (buffer_size != 0) {
|
||||
if (!peconv::validate_ptr((LPVOID)pe_buffer, buffer_size, (LPVOID)idh, sizeof(IMAGE_DOS_HEADER))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (peconv::is_bad_read_ptr(idh, sizeof(IMAGE_DOS_HEADER))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (idh->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
return nullptr;
|
||||
}
|
||||
const LONG kMaxOffset = 1024;
|
||||
LONG pe_offset = idh->e_lfanew;
|
||||
|
||||
if (pe_offset > kMaxOffset) return nullptr;
|
||||
|
||||
IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)(pe_buffer + pe_offset);
|
||||
if (buffer_size != 0) {
|
||||
if (!peconv::validate_ptr((LPVOID)pe_buffer, buffer_size, (LPVOID)inh, sizeof(IMAGE_NT_HEADERS32))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (peconv::is_bad_read_ptr(inh, sizeof(IMAGE_NT_HEADERS32))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (inh->Signature != IMAGE_NT_SIGNATURE) {
|
||||
return nullptr;
|
||||
}
|
||||
return (BYTE*)inh;
|
||||
}
|
||||
|
||||
IMAGE_NT_HEADERS32* peconv::get_nt_hdrs32(IN const BYTE *payload)
|
||||
{
|
||||
if (!payload) return nullptr;
|
||||
|
||||
BYTE *ptr = get_nt_hdrs(payload);
|
||||
if (!ptr) return nullptr;
|
||||
|
||||
if (!is64bit(payload)) {
|
||||
return (IMAGE_NT_HEADERS32*)ptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IMAGE_NT_HEADERS64* peconv::get_nt_hdrs64(IN const BYTE *payload)
|
||||
{
|
||||
if (payload == nullptr) return nullptr;
|
||||
|
||||
BYTE *ptr = get_nt_hdrs(payload);
|
||||
if (!ptr) return nullptr;
|
||||
|
||||
if (is64bit(payload)) {
|
||||
return (IMAGE_NT_HEADERS64*)ptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DWORD peconv::get_image_size(IN const BYTE *payload)
|
||||
{
|
||||
if (!get_nt_hdrs(payload)) {
|
||||
return 0;
|
||||
}
|
||||
DWORD image_size = 0;
|
||||
if (is64bit(payload)) {
|
||||
IMAGE_NT_HEADERS64* nt64 = get_nt_hdrs64(payload);
|
||||
image_size = nt64->OptionalHeader.SizeOfImage;
|
||||
} else {
|
||||
IMAGE_NT_HEADERS32* nt32 = get_nt_hdrs32(payload);
|
||||
image_size = nt32->OptionalHeader.SizeOfImage;
|
||||
}
|
||||
return image_size;
|
||||
}
|
||||
|
||||
bool peconv::update_image_size(IN OUT BYTE* payload, IN DWORD image_size)
|
||||
{
|
||||
if (!get_nt_hdrs(payload)) {
|
||||
return false;
|
||||
}
|
||||
if (is64bit(payload)) {
|
||||
IMAGE_NT_HEADERS64* nt64 = get_nt_hdrs64(payload);
|
||||
nt64->OptionalHeader.SizeOfImage = image_size;
|
||||
}
|
||||
else {
|
||||
IMAGE_NT_HEADERS32* nt32 = get_nt_hdrs32(payload);
|
||||
nt32->OptionalHeader.SizeOfImage = image_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WORD peconv::get_nt_hdr_architecture(IN const BYTE *pe_buffer)
|
||||
{
|
||||
void *ptr = get_nt_hdrs(pe_buffer);
|
||||
if (!ptr) return 0;
|
||||
|
||||
IMAGE_NT_HEADERS32 *inh = static_cast<IMAGE_NT_HEADERS32*>(ptr);
|
||||
if (peconv::is_bad_read_ptr(inh, sizeof(IMAGE_NT_HEADERS32))) {
|
||||
return 0;
|
||||
}
|
||||
return inh->OptionalHeader.Magic;
|
||||
}
|
||||
|
||||
bool peconv::is64bit(IN const BYTE *pe_buffer)
|
||||
{
|
||||
WORD arch = get_nt_hdr_architecture(pe_buffer);
|
||||
if (arch == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IMAGE_DATA_DIRECTORY* peconv::get_directory_entry(IN const BYTE *pe_buffer, IN DWORD dir_id, IN bool allow_empty)
|
||||
{
|
||||
if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return nullptr;
|
||||
|
||||
BYTE* nt_headers = get_nt_hdrs((BYTE*)pe_buffer);
|
||||
if (!nt_headers) return nullptr;
|
||||
|
||||
IMAGE_DATA_DIRECTORY* peDir = nullptr;
|
||||
if (is64bit(pe_buffer)) {
|
||||
IMAGE_NT_HEADERS64* nt_headers64 = (IMAGE_NT_HEADERS64*)nt_headers;
|
||||
peDir = &(nt_headers64->OptionalHeader.DataDirectory[dir_id]);
|
||||
}
|
||||
else {
|
||||
IMAGE_NT_HEADERS32* nt_headers64 = (IMAGE_NT_HEADERS32*)nt_headers;
|
||||
peDir = &(nt_headers64->OptionalHeader.DataDirectory[dir_id]);
|
||||
}
|
||||
if (!allow_empty && peDir->VirtualAddress == NULL) {
|
||||
return nullptr;
|
||||
}
|
||||
return peDir;
|
||||
}
|
||||
|
||||
ULONGLONG peconv::get_image_base(IN const BYTE *pe_buffer)
|
||||
{
|
||||
bool is64b = is64bit(pe_buffer);
|
||||
//update image base in the written content:
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(pe_buffer);
|
||||
if (!payload_nt_hdr) {
|
||||
return 0;
|
||||
}
|
||||
ULONGLONG img_base = 0;
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
img_base = payload_nt_hdr64->OptionalHeader.ImageBase;
|
||||
} else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
img_base = static_cast<ULONGLONG>(payload_nt_hdr32->OptionalHeader.ImageBase);
|
||||
}
|
||||
return img_base;
|
||||
}
|
||||
|
||||
DWORD peconv::get_entry_point_rva(IN const BYTE *pe_buffer)
|
||||
{
|
||||
//update image base in the written content:
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(pe_buffer);
|
||||
if (!payload_nt_hdr) {
|
||||
return 0;
|
||||
}
|
||||
const bool is64b = is64bit(pe_buffer);
|
||||
DWORD value = 0;
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
value = payload_nt_hdr64->OptionalHeader.AddressOfEntryPoint;
|
||||
} else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
value = payload_nt_hdr32->OptionalHeader.AddressOfEntryPoint;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool peconv::update_entry_point_rva(IN OUT BYTE *pe_buffer, IN DWORD value)
|
||||
{
|
||||
bool is64b = is64bit(pe_buffer);
|
||||
//update image base in the written content:
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(pe_buffer);
|
||||
if (!payload_nt_hdr) {
|
||||
return false;
|
||||
}
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
payload_nt_hdr64->OptionalHeader.AddressOfEntryPoint = value;
|
||||
} else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
payload_nt_hdr32->OptionalHeader.AddressOfEntryPoint = value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD peconv::get_hdrs_size(IN const BYTE *pe_buffer)
|
||||
{
|
||||
bool is64b = is64bit(pe_buffer);
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(pe_buffer);
|
||||
if (!payload_nt_hdr) {
|
||||
return 0;
|
||||
}
|
||||
DWORD hdrs_size = 0;
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
hdrs_size = payload_nt_hdr64->OptionalHeader.SizeOfHeaders;
|
||||
} else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
hdrs_size = payload_nt_hdr32->OptionalHeader.SizeOfHeaders;
|
||||
}
|
||||
return hdrs_size;
|
||||
}
|
||||
|
||||
bool peconv::update_image_base(IN OUT BYTE* payload, IN ULONGLONG destImageBase)
|
||||
{
|
||||
bool is64b = is64bit(payload);
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
|
||||
if (!payload_nt_hdr) {
|
||||
return false;
|
||||
}
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
payload_nt_hdr64->OptionalHeader.ImageBase = (ULONGLONG)destImageBase;
|
||||
}
|
||||
else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
payload_nt_hdr32->OptionalHeader.ImageBase = (DWORD)destImageBase;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename IMAGE_NT_HEADERS_T>
|
||||
inline const IMAGE_FILE_HEADER* fetch_file_hdr(IN const BYTE* payload, IN const size_t buffer_size, IN const IMAGE_NT_HEADERS_T *payload_nt_hdr)
|
||||
{
|
||||
if (!payload || !payload_nt_hdr) return nullptr;
|
||||
|
||||
const IMAGE_FILE_HEADER *fileHdr = &(payload_nt_hdr->FileHeader);
|
||||
|
||||
if (!validate_ptr((const LPVOID)payload, buffer_size, (const LPVOID)fileHdr, sizeof(IMAGE_FILE_HEADER))) {
|
||||
return nullptr;
|
||||
}
|
||||
return fileHdr;
|
||||
}
|
||||
|
||||
const IMAGE_FILE_HEADER* peconv::get_file_hdr(IN const BYTE* payload, IN const size_t buffer_size)
|
||||
{
|
||||
if (!payload) return nullptr;
|
||||
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(payload, buffer_size);
|
||||
if (!payload_nt_hdr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (is64bit(payload)) {
|
||||
return fetch_file_hdr(payload, buffer_size, (IMAGE_NT_HEADERS64*)payload_nt_hdr);
|
||||
}
|
||||
return fetch_file_hdr(payload, buffer_size, (IMAGE_NT_HEADERS32*)payload_nt_hdr);
|
||||
}
|
||||
|
||||
template <typename IMAGE_NT_HEADERS_T>
|
||||
inline const LPVOID fetch_opt_hdr(IN const BYTE* payload, IN const size_t buffer_size, IN const IMAGE_NT_HEADERS_T *payload_nt_hdr)
|
||||
{
|
||||
if (!payload) return nullptr;
|
||||
|
||||
const IMAGE_FILE_HEADER *fileHdr = fetch_file_hdr<IMAGE_NT_HEADERS_T>(payload, buffer_size, payload_nt_hdr);
|
||||
if (!fileHdr) {
|
||||
return nullptr;
|
||||
}
|
||||
const LPVOID opt_hdr = (const LPVOID) &(payload_nt_hdr->OptionalHeader);
|
||||
const size_t opt_size = fileHdr->SizeOfOptionalHeader;
|
||||
if (!validate_ptr((const LPVOID)payload, buffer_size, opt_hdr, opt_size)) {
|
||||
return nullptr;
|
||||
}
|
||||
return opt_hdr;
|
||||
}
|
||||
|
||||
LPVOID peconv::get_optional_hdr(IN const BYTE* payload, IN const size_t buffer_size)
|
||||
{
|
||||
if (!payload) return nullptr;
|
||||
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(payload, buffer_size);
|
||||
const IMAGE_FILE_HEADER* fileHdr = get_file_hdr(payload, buffer_size);
|
||||
if (!payload_nt_hdr || !fileHdr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (is64bit(payload)) {
|
||||
return fetch_opt_hdr<IMAGE_NT_HEADERS64>(payload,buffer_size, (IMAGE_NT_HEADERS64*)payload_nt_hdr);
|
||||
}
|
||||
return fetch_opt_hdr<IMAGE_NT_HEADERS32>(payload, buffer_size, (IMAGE_NT_HEADERS32*)payload_nt_hdr);
|
||||
}
|
||||
|
||||
template <typename IMAGE_NT_HEADERS_T>
|
||||
inline LPVOID fetch_section_hdrs_ptr(IN const BYTE* payload, IN const size_t buffer_size, IN const IMAGE_NT_HEADERS_T *payload_nt_hdr)
|
||||
{
|
||||
const IMAGE_FILE_HEADER *fileHdr = fetch_file_hdr<IMAGE_NT_HEADERS_T>(payload, buffer_size, payload_nt_hdr);
|
||||
if (!fileHdr) {
|
||||
return nullptr;
|
||||
}
|
||||
const size_t opt_size = fileHdr->SizeOfOptionalHeader;
|
||||
BYTE* opt_hdr = (BYTE*)fetch_opt_hdr(payload, buffer_size, payload_nt_hdr);
|
||||
if (!validate_ptr((const LPVOID)payload, buffer_size, opt_hdr, opt_size)) {
|
||||
return nullptr;
|
||||
}
|
||||
//sections headers starts right after the end of the optional header
|
||||
return (LPVOID)(opt_hdr + opt_size);
|
||||
}
|
||||
|
||||
size_t peconv::get_sections_count(IN const BYTE* payload, IN const size_t buffer_size)
|
||||
{
|
||||
const IMAGE_FILE_HEADER* fileHdr = get_file_hdr(payload, buffer_size);
|
||||
if (!fileHdr) {
|
||||
return 0;
|
||||
}
|
||||
return fileHdr->NumberOfSections;
|
||||
}
|
||||
|
||||
bool peconv::is_valid_sections_hdr_offset(IN const BYTE* buffer, IN const size_t buffer_size)
|
||||
{
|
||||
size_t sec_count = peconv::get_sections_count(buffer, buffer_size);
|
||||
if (sec_count == 0) {
|
||||
//no sections found - a valid PE should have at least one section
|
||||
return false;
|
||||
}
|
||||
PIMAGE_SECTION_HEADER last_hdr = get_section_hdr(buffer, buffer_size, sec_count - 1);
|
||||
if (!last_hdr) {
|
||||
//could not fetch the last section
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PIMAGE_SECTION_HEADER peconv::get_section_hdr(IN const BYTE* payload, IN const size_t buffer_size, IN size_t section_num)
|
||||
{
|
||||
if (!payload) return nullptr;
|
||||
|
||||
const size_t sections_count = peconv::get_sections_count(payload, buffer_size);
|
||||
if (section_num >= sections_count) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LPVOID nt_hdrs = peconv::get_nt_hdrs(payload, buffer_size);
|
||||
if (!nt_hdrs) return nullptr; //this should never happened, because the get_sections_count did not fail
|
||||
|
||||
LPVOID secptr = nullptr;
|
||||
//get the beginning of sections headers:
|
||||
if (is64bit(payload)) {
|
||||
secptr = fetch_section_hdrs_ptr<IMAGE_NT_HEADERS64>(payload, buffer_size, (IMAGE_NT_HEADERS64*)nt_hdrs);
|
||||
}
|
||||
else {
|
||||
secptr = fetch_section_hdrs_ptr<IMAGE_NT_HEADERS32>(payload, buffer_size, (IMAGE_NT_HEADERS32*)nt_hdrs);
|
||||
}
|
||||
//get the section header of given number:
|
||||
PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)(
|
||||
(ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * section_num)
|
||||
);
|
||||
//validate pointer:
|
||||
if (!validate_ptr((const LPVOID) payload, buffer_size, (const LPVOID) next_sec, sizeof(IMAGE_SECTION_HEADER))) {
|
||||
return nullptr;
|
||||
}
|
||||
return next_sec;
|
||||
}
|
||||
|
||||
WORD peconv::get_file_characteristics(IN const BYTE* payload)
|
||||
{
|
||||
if (!payload) return 0;
|
||||
|
||||
bool is64b = is64bit(payload);
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
|
||||
if (!payload_nt_hdr) {
|
||||
return 0;
|
||||
}
|
||||
IMAGE_FILE_HEADER *fileHdr = nullptr;
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
fileHdr = &(payload_nt_hdr64->FileHeader);
|
||||
}
|
||||
else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
fileHdr = &(payload_nt_hdr32->FileHeader);
|
||||
}
|
||||
return fileHdr->Characteristics;
|
||||
}
|
||||
|
||||
bool peconv::is_module_dll(IN const BYTE* payload)
|
||||
{
|
||||
if (!payload) return false;
|
||||
WORD charact = get_file_characteristics(payload);
|
||||
return ((charact & IMAGE_FILE_DLL) != 0);
|
||||
}
|
||||
|
||||
bool peconv::is_dot_net(BYTE *pe_buffer, size_t pe_buffer_size)
|
||||
{
|
||||
if (!pe_buffer) return false;
|
||||
|
||||
IMAGE_DATA_DIRECTORY* dotnet_ptr = peconv::get_directory_entry(pe_buffer, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, false);
|
||||
if (!dotnet_ptr) return false;
|
||||
|
||||
if (peconv::get_dotnet_hdr(pe_buffer, pe_buffer_size, dotnet_ptr)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
WORD peconv::get_dll_characteristics(IN const BYTE* payload)
|
||||
{
|
||||
if (!payload) return 0;
|
||||
|
||||
bool is64b = is64bit(payload);
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
|
||||
if (!payload_nt_hdr) {
|
||||
return 0;
|
||||
}
|
||||
WORD charact = 0;
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
charact = payload_nt_hdr64->OptionalHeader.DllCharacteristics;
|
||||
}
|
||||
else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
charact = payload_nt_hdr32->OptionalHeader.DllCharacteristics;
|
||||
}
|
||||
return charact;
|
||||
}
|
||||
|
||||
bool peconv::set_subsystem(IN OUT BYTE* payload, IN WORD subsystem)
|
||||
{
|
||||
if (!payload) return false;
|
||||
|
||||
bool is64b = is64bit(payload);
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
|
||||
if (!payload_nt_hdr) {
|
||||
return false;
|
||||
}
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
payload_nt_hdr64->OptionalHeader.Subsystem = subsystem;
|
||||
} else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
payload_nt_hdr32->OptionalHeader.Subsystem = subsystem;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WORD peconv::get_subsystem(IN const BYTE* payload)
|
||||
{
|
||||
if (!payload) return 0;
|
||||
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
|
||||
if (payload_nt_hdr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
const bool is64b = is64bit(payload);
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
return payload_nt_hdr64->OptionalHeader.Subsystem;
|
||||
} else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
return payload_nt_hdr32->OptionalHeader.Subsystem;
|
||||
}
|
||||
}
|
||||
|
||||
bool peconv::has_relocations(IN const BYTE *pe_buffer)
|
||||
{
|
||||
IMAGE_DATA_DIRECTORY* relocDir = get_directory_entry(pe_buffer, IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
||||
if (!relocDir) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IMAGE_EXPORT_DIRECTORY* peconv::get_export_directory(IN HMODULE modulePtr)
|
||||
{
|
||||
return get_type_directory<IMAGE_EXPORT_DIRECTORY>(modulePtr, IMAGE_DIRECTORY_ENTRY_EXPORT);
|
||||
}
|
||||
|
||||
|
||||
IMAGE_COR20_HEADER * peconv::get_dotnet_hdr(IN const BYTE* module, IN size_t const module_size, IN const IMAGE_DATA_DIRECTORY * dotNetDir)
|
||||
{
|
||||
DWORD rva = dotNetDir->VirtualAddress;
|
||||
DWORD hdr_size = dotNetDir->Size;
|
||||
if (!peconv::validate_ptr(module, module_size, module + rva, hdr_size)) {
|
||||
return nullptr;
|
||||
}
|
||||
IMAGE_COR20_HEADER *dnet_hdr = (IMAGE_COR20_HEADER*)(module + rva);
|
||||
if (!peconv::validate_ptr(module, module_size, module + dnet_hdr->MetaData.VirtualAddress, dnet_hdr->MetaData.Size)) {
|
||||
return nullptr;
|
||||
}
|
||||
DWORD* signature_ptr = (DWORD*)(module + dnet_hdr->MetaData.VirtualAddress);
|
||||
const DWORD dotNetSign = 0x424A5342;
|
||||
if (*signature_ptr != dotNetSign) {
|
||||
//invalid header
|
||||
return nullptr;
|
||||
}
|
||||
return dnet_hdr;
|
||||
}
|
||||
|
||||
template <typename IMAGE_NT_HEADERS_T>
|
||||
DWORD* _get_sec_alignment_ptr(const BYTE* modulePtr, bool is_raw)
|
||||
{
|
||||
IMAGE_NT_HEADERS_T* hdrs = reinterpret_cast<IMAGE_NT_HEADERS_T*>(peconv::get_nt_hdrs(modulePtr));
|
||||
if (!hdrs) return nullptr;
|
||||
if (is_raw) {
|
||||
return &hdrs->OptionalHeader.FileAlignment;
|
||||
}
|
||||
return &hdrs->OptionalHeader.SectionAlignment;
|
||||
}
|
||||
|
||||
DWORD peconv::get_sec_alignment(IN const BYTE* modulePtr, IN bool is_raw)
|
||||
{
|
||||
DWORD* alignment = 0;
|
||||
if (peconv::is64bit(modulePtr)) {
|
||||
alignment = _get_sec_alignment_ptr<IMAGE_NT_HEADERS64>(modulePtr, is_raw);
|
||||
} else {
|
||||
alignment = _get_sec_alignment_ptr<IMAGE_NT_HEADERS32>(modulePtr, is_raw);
|
||||
}
|
||||
if (!alignment) return 0;
|
||||
return *alignment;
|
||||
}
|
||||
|
||||
bool peconv::set_sec_alignment(IN OUT BYTE* modulePtr, IN bool is_raw, IN DWORD new_alignment)
|
||||
{
|
||||
DWORD* alignment = 0;
|
||||
if (peconv::is64bit(modulePtr)) {
|
||||
alignment = _get_sec_alignment_ptr<IMAGE_NT_HEADERS64>(modulePtr, is_raw);
|
||||
}
|
||||
else {
|
||||
alignment = _get_sec_alignment_ptr<IMAGE_NT_HEADERS32>(modulePtr, is_raw);
|
||||
}
|
||||
if (!alignment) return false;
|
||||
|
||||
*alignment = new_alignment;
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD peconv::get_virtual_sec_size(IN const BYTE* pe_hdr, IN const PIMAGE_SECTION_HEADER sec_hdr, IN bool rounded)
|
||||
{
|
||||
if (!pe_hdr || !sec_hdr) {
|
||||
return 0;
|
||||
}
|
||||
if (!rounded) {
|
||||
return sec_hdr->Misc.VirtualSize;;
|
||||
}
|
||||
//TODO: calculate real size, round up to Virtual Alignment
|
||||
DWORD alignment = peconv::get_sec_alignment((const PBYTE)pe_hdr, false);
|
||||
DWORD vsize = sec_hdr->Misc.VirtualSize;
|
||||
|
||||
DWORD units = vsize / alignment;
|
||||
if ((vsize % alignment) > 0) units++;
|
||||
|
||||
vsize = units * alignment;
|
||||
|
||||
DWORD image_size = peconv::get_image_size(pe_hdr);
|
||||
//if it is bigger than the image size, use the size from the headers
|
||||
if ((sec_hdr->VirtualAddress + vsize) > image_size) {
|
||||
vsize = sec_hdr->Misc.VirtualSize;
|
||||
}
|
||||
return vsize;
|
||||
}
|
||||
|
||||
PIMAGE_SECTION_HEADER peconv::get_last_section(IN const PBYTE pe_buffer, IN size_t pe_size, IN bool is_raw)
|
||||
{
|
||||
SIZE_T module_end = peconv::get_hdrs_size(pe_buffer);
|
||||
const size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
|
||||
if (sections_count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
PIMAGE_SECTION_HEADER last_sec = nullptr;
|
||||
//walk through sections
|
||||
for (size_t i = 0; i < sections_count; i++) {
|
||||
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
|
||||
if (!sec) break;
|
||||
|
||||
size_t new_end = is_raw ? (sec->PointerToRawData + sec->SizeOfRawData) : (sec->VirtualAddress + sec->Misc.VirtualSize);
|
||||
if (new_end > module_end) {
|
||||
module_end = new_end;
|
||||
last_sec = sec;
|
||||
}
|
||||
}
|
||||
return last_sec;
|
||||
}
|
||||
|
||||
DWORD peconv::calc_pe_size(IN const PBYTE pe_buffer, IN size_t pe_size, IN bool is_raw)
|
||||
{
|
||||
DWORD module_end = peconv::get_hdrs_size(pe_buffer);
|
||||
const size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
|
||||
if (sections_count == 0) {
|
||||
return module_end;
|
||||
}
|
||||
//walk through sections
|
||||
for (size_t i = 0; i < sections_count; i++) {
|
||||
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
|
||||
if (!sec) break;
|
||||
|
||||
DWORD new_end = is_raw ? (sec->PointerToRawData + sec->SizeOfRawData) : (sec->VirtualAddress + sec->Misc.VirtualSize);
|
||||
if (new_end > module_end) module_end = new_end;
|
||||
}
|
||||
return module_end;
|
||||
}
|
||||
|
||||
bool peconv::is_valid_sectons_alignment(IN const BYTE* payload, IN const SIZE_T payload_size, IN bool is_raw)
|
||||
{
|
||||
if (payload == NULL) return false;
|
||||
|
||||
const DWORD my_align = peconv::get_sec_alignment(payload, is_raw);
|
||||
if (my_align == 0) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Section alignment cannot be 0\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
const size_t sections_count = peconv::get_sections_count(payload, payload_size);
|
||||
if (sections_count == 0) {
|
||||
//no sections
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < sections_count; i++) {
|
||||
PIMAGE_SECTION_HEADER next_sec = peconv::get_section_hdr(payload, payload_size, i);
|
||||
if (!next_sec) return false; //the number of the sections in header is out of scope
|
||||
|
||||
const DWORD next_sec_addr = is_raw ? (next_sec->PointerToRawData) : (next_sec->VirtualAddress);
|
||||
|
||||
SIZE_T sec_size = is_raw ? next_sec->SizeOfRawData : next_sec->Misc.VirtualSize;
|
||||
if (sec_size == 0) continue;
|
||||
if (next_sec->Misc.VirtualSize == 0) {
|
||||
continue; // if the VirtualSize == 0 the section will not be mapped anyways
|
||||
}
|
||||
if (next_sec_addr == 0) {
|
||||
//if cannot be 0 if the size is not 0
|
||||
return false;
|
||||
}
|
||||
|
||||
//check only if raw_align is non-zero
|
||||
if (my_align && next_sec_addr % my_align != 0) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Section is misaligned\n";
|
||||
#endif
|
||||
return false; //misaligned
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
122
Etw Syscall/libpeconv-master/libpeconv/src/pe_loader.cpp
Normal file
122
Etw Syscall/libpeconv-master/libpeconv/src/pe_loader.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "peconv/pe_loader.h"
|
||||
|
||||
#include "peconv/relocate.h"
|
||||
#include "peconv/imports_loader.h"
|
||||
#include "peconv/buffer_util.h"
|
||||
#include "peconv/function_resolver.h"
|
||||
#include "peconv/exports_lookup.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
namespace peconv {
|
||||
BYTE* load_no_sec_pe(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, bool executable)
|
||||
{
|
||||
ULONGLONG desired_base = 0;
|
||||
size_t out_size = (r_size < PAGE_SIZE) ? PAGE_SIZE : r_size;
|
||||
if (executable) {
|
||||
desired_base = get_image_base(dllRawData);
|
||||
out_size = peconv::get_image_size(dllRawData);
|
||||
}
|
||||
DWORD protect = (executable) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
||||
BYTE* mappedPE = peconv::alloc_pe_buffer(out_size, protect, desired_base);
|
||||
if (!mappedPE) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(mappedPE, dllRawData, r_size);
|
||||
v_size = out_size;
|
||||
return mappedPE;
|
||||
}
|
||||
};
|
||||
|
||||
BYTE* peconv::load_pe_module(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, bool executable, bool relocate)
|
||||
{
|
||||
if (!peconv::get_nt_hdrs(dllRawData, r_size)) {
|
||||
return NULL;
|
||||
}
|
||||
if (peconv::get_sections_count(dllRawData, r_size) == 0) {
|
||||
return load_no_sec_pe(dllRawData, r_size, v_size, executable);
|
||||
}
|
||||
// by default, allow to load the PE at any base:
|
||||
ULONGLONG desired_base = NULL;
|
||||
// if relocating is required, but the PE has no relocation table...
|
||||
if (relocate && !has_relocations(dllRawData)) {
|
||||
// ...enforce loading the PE image at its default base (so that it will need no relocations)
|
||||
desired_base = get_image_base(dllRawData);
|
||||
}
|
||||
// load a virtual image of the PE file at the desired_base address (random if desired_base is NULL):
|
||||
BYTE *mappedDLL = pe_raw_to_virtual(dllRawData, r_size, v_size, executable, desired_base);
|
||||
if (mappedDLL) {
|
||||
//if the image was loaded at its default base, relocate_module will return always true (because relocating is already done)
|
||||
if (relocate && !relocate_module(mappedDLL, v_size, (ULONGLONG)mappedDLL)) {
|
||||
// relocating was required, but it failed - thus, the full PE image is useless
|
||||
printf("Could not relocate the module!");
|
||||
free_pe_buffer(mappedDLL, v_size);
|
||||
mappedDLL = NULL;
|
||||
}
|
||||
} else {
|
||||
printf("Could not allocate memory at the desired base!\n");
|
||||
}
|
||||
return mappedDLL;
|
||||
}
|
||||
|
||||
BYTE* peconv::load_pe_module(const char *filename, OUT size_t &v_size, bool executable, bool relocate)
|
||||
{
|
||||
size_t r_size = 0;
|
||||
BYTE *dllRawData = load_file(filename, r_size);
|
||||
if (!dllRawData) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Cannot load the file: " << filename << std::endl;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
BYTE* mappedPE = load_pe_module(dllRawData, r_size, v_size, executable, relocate);
|
||||
free_pe_buffer(dllRawData);
|
||||
return mappedPE;
|
||||
}
|
||||
|
||||
BYTE* peconv::load_pe_executable(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, t_function_resolver* import_resolver)
|
||||
{
|
||||
BYTE* loaded_pe = load_pe_module(dllRawData, r_size, v_size, true, true);
|
||||
if (!loaded_pe) {
|
||||
printf("[-] Loading failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
#if _DEBUG
|
||||
printf("Loaded at: %p\n", loaded_pe);
|
||||
#endif
|
||||
if (has_valid_import_table(loaded_pe, v_size)) {
|
||||
if (!load_imports(loaded_pe, import_resolver)) {
|
||||
printf("[-] Loading imports failed!");
|
||||
free_pe_buffer(loaded_pe, v_size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("[-] PE doesn't have a valid Import Table!\n");
|
||||
}
|
||||
return loaded_pe;
|
||||
}
|
||||
|
||||
|
||||
BYTE* peconv::load_pe_executable(const char *my_path, OUT size_t &v_size, t_function_resolver* import_resolver)
|
||||
{
|
||||
#if _DEBUG
|
||||
printf("Module: %s\n", my_path);
|
||||
#endif
|
||||
BYTE* loaded_pe = load_pe_module(my_path, v_size, true, true);
|
||||
if (!loaded_pe) {
|
||||
printf("Loading failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
#if _DEBUG
|
||||
printf("Loaded at: %p\n", loaded_pe);
|
||||
#endif
|
||||
if (!load_imports(loaded_pe, import_resolver)) {
|
||||
printf("[-] Loading imports failed!");
|
||||
free_pe_buffer(loaded_pe, v_size);
|
||||
return NULL;
|
||||
}
|
||||
return loaded_pe;
|
||||
}
|
||||
196
Etw Syscall/libpeconv-master/libpeconv/src/pe_mode_detector.cpp
Normal file
196
Etw Syscall/libpeconv-master/libpeconv/src/pe_mode_detector.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
#include "peconv/pe_mode_detector.h"
|
||||
#include "peconv/util.h"
|
||||
#include "peconv/imports_loader.h"
|
||||
#include "peconv/relocate.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
// Check if gaps between sections are typical for Virtual Alignment.
|
||||
// Returns true if confirmed, false if not confirmed. False result can also mean that data was invalid/insufficient to decide.
|
||||
bool is_virtual_padding(const BYTE* pe_buffer, size_t pe_size)
|
||||
{
|
||||
const size_t r_align = peconv::get_sec_alignment((PBYTE)pe_buffer, true);
|
||||
|
||||
size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
|
||||
if (sections_count < 2) return false;
|
||||
|
||||
bool is_valid_padding = false;
|
||||
for (size_t i = 1; i < sections_count; i += 2) {
|
||||
PIMAGE_SECTION_HEADER sec1 = peconv::get_section_hdr(pe_buffer, pe_size, i-1);
|
||||
PIMAGE_SECTION_HEADER sec2 = peconv::get_section_hdr(pe_buffer, pe_size, i);
|
||||
if (!sec1 || !sec2) continue; //skip if fetching any of the sections failed
|
||||
|
||||
if (sec1->SizeOfRawData == 0) continue; //skip empty sections
|
||||
|
||||
const DWORD sec1_end_offset = sec1->VirtualAddress + sec1->SizeOfRawData;
|
||||
if (sec2->VirtualAddress == sec1_end_offset) continue;
|
||||
|
||||
if (sec2->VirtualAddress < sec1_end_offset) {
|
||||
//std::cout << "Invalid size of the section: " << std::hex << sec2->VirtualAddress << " vs "<< sec1_end_offset << std::endl;
|
||||
return false;
|
||||
}
|
||||
const size_t diff = sec2->VirtualAddress - sec1_end_offset;
|
||||
if (diff < r_align) continue; //to small to determine
|
||||
|
||||
BYTE* sec1_end_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec1_end_offset);
|
||||
if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec1_end_ptr, diff)) {
|
||||
//std::cout << "Invalid pointer to the section\n";
|
||||
return false;
|
||||
}
|
||||
if (peconv::is_padding(sec1_end_ptr, diff, 0)) {
|
||||
is_valid_padding = true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return is_valid_padding;
|
||||
}
|
||||
|
||||
// Check if the gap between the end of headers and the first section is typical for Virtual Alignment.
|
||||
// Returns true if confirmed, false if not confirmed. False result can also mean that data was invalid/insufficient to decide.
|
||||
bool is_hdr_virtual_align(const BYTE* pe_buffer, size_t pe_size)
|
||||
{
|
||||
const size_t v_align = peconv::get_sec_alignment((PBYTE)pe_buffer, false);
|
||||
if (peconv::get_hdrs_size(pe_buffer) >= v_align) {
|
||||
//undetermined for such case
|
||||
return false;
|
||||
}
|
||||
//walk through sections and check their sizes
|
||||
size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
|
||||
if (sections_count == 0) return false;
|
||||
for (size_t i = 0; i < sections_count; i++) {
|
||||
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
|
||||
if (!sec || sec->PointerToRawData == 0 || sec->SizeOfRawData == 0) {
|
||||
continue; // check next
|
||||
}
|
||||
if (sec->PointerToRawData >= v_align) continue;
|
||||
|
||||
size_t diff = v_align - sec->PointerToRawData;
|
||||
BYTE* sec_raw_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec->PointerToRawData);
|
||||
if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec_raw_ptr, diff)) {
|
||||
return false;
|
||||
}
|
||||
if (peconv::is_padding(sec_raw_ptr, diff, 0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sec_hdrs_erased(IN const BYTE* pe_buffer, IN size_t pe_size, bool is_raw)
|
||||
{
|
||||
const size_t count = peconv::get_sections_count(pe_buffer, pe_size);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const IMAGE_SECTION_HEADER* hdr = peconv::get_section_hdr(pe_buffer, pe_size, i);
|
||||
if (!hdr) continue;
|
||||
if (is_raw) {
|
||||
if (hdr->PointerToRawData != 0) return false;
|
||||
}
|
||||
else {
|
||||
if (hdr->VirtualAddress != 0) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool peconv::is_pe_raw_eq_virtual(IN const BYTE* pe_buffer, IN size_t pe_size)
|
||||
{
|
||||
const size_t count = peconv::get_sections_count(pe_buffer, pe_size);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const IMAGE_SECTION_HEADER* hdr = peconv::get_section_hdr(pe_buffer, pe_size, i);
|
||||
if (!hdr) continue;
|
||||
|
||||
if (hdr->VirtualAddress != hdr->PointerToRawData) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_pe_mapped(IN const BYTE* pe_buffer, IN size_t pe_size)
|
||||
{
|
||||
size_t v_score = 0;
|
||||
if (peconv::has_valid_import_table((const PBYTE)pe_buffer, pe_size)) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Valid Import Table found" << std::endl;
|
||||
#endif
|
||||
v_score++;
|
||||
}
|
||||
if (peconv::has_valid_relocation_table((const PBYTE)pe_buffer, pe_size)) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Valid Relocations Table found" << std::endl;
|
||||
#endif
|
||||
v_score++;
|
||||
}
|
||||
if (is_hdr_virtual_align(pe_buffer, pe_size)) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Header virtual align OK" << std::endl;
|
||||
#endif
|
||||
v_score++;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "TOTAL v_score: " << std::dec << v_score << std::endl;
|
||||
#endif
|
||||
if (v_score > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool peconv::is_pe_raw(IN const BYTE* pe_buffer, IN size_t pe_size)
|
||||
{
|
||||
if (peconv::get_sections_count(pe_buffer, pe_size) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (is_pe_mapped(pe_buffer, pe_size)) {
|
||||
// it has artefacts typical for a PE in a virtual alignment
|
||||
return false;
|
||||
}
|
||||
if (sec_hdrs_erased(pe_buffer, pe_size, true)) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Raw alignment is erased\n";
|
||||
#endif
|
||||
// the raw alignment of the sections is erased
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// checks if any sections has been expanded in the memory
|
||||
bool peconv::is_pe_expanded(IN const BYTE* pe_buffer, IN size_t pe_size)
|
||||
{
|
||||
//walk through sections and check their sizes
|
||||
size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
|
||||
for (size_t i = 0; i < sections_count; i++) {
|
||||
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
|
||||
if (is_section_expanded(pe_buffer, pe_size, sec)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// checks if the section's content in memory is bigger than in the raw format
|
||||
bool peconv::is_section_expanded(IN const BYTE* pe_buffer, IN size_t pe_size, IN const PIMAGE_SECTION_HEADER sec)
|
||||
{
|
||||
if (!sec) return false;
|
||||
|
||||
size_t sec_vsize = peconv::get_virtual_sec_size(pe_buffer, sec, true);
|
||||
size_t sec_rsize = sec->SizeOfRawData;
|
||||
|
||||
if (sec_rsize >= sec_vsize) return false;
|
||||
size_t diff = sec_vsize - sec_rsize;
|
||||
|
||||
BYTE* sec_raw_end_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec->VirtualAddress + sec_rsize);
|
||||
if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec_raw_end_ptr, diff)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_padding(sec_raw_end_ptr, diff, 0)) {
|
||||
//this is not padding: non-zero content detected
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
140
Etw Syscall/libpeconv-master/libpeconv/src/pe_raw_to_virtual.cpp
Normal file
140
Etw Syscall/libpeconv-master/libpeconv/src/pe_raw_to_virtual.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "peconv/pe_raw_to_virtual.h"
|
||||
|
||||
#include "peconv/util.h"
|
||||
#include "peconv/pe_hdrs_helper.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
// Map raw PE into virtual memory of local process:
|
||||
bool sections_raw_to_virtual(IN const BYTE* payload, IN SIZE_T payloadSize, OUT BYTE* destBuffer, IN SIZE_T destBufferSize)
|
||||
{
|
||||
if (!payload || !destBuffer) return false;
|
||||
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(payload, payloadSize);
|
||||
if (payload_nt_hdr == NULL) {
|
||||
std::cerr << "Invalid payload: " << std::hex << (ULONGLONG) payload << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool is64b = is64bit(payload);
|
||||
|
||||
IMAGE_FILE_HEADER *fileHdr = NULL;
|
||||
DWORD hdrsSize = 0;
|
||||
LPVOID secptr = NULL;
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
|
||||
fileHdr = &(payload_nt_hdr64->FileHeader);
|
||||
hdrsSize = payload_nt_hdr64->OptionalHeader.SizeOfHeaders;
|
||||
secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr64->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
|
||||
}
|
||||
else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
|
||||
fileHdr = &(payload_nt_hdr32->FileHeader);
|
||||
hdrsSize = payload_nt_hdr32->OptionalHeader.SizeOfHeaders;
|
||||
secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr32->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
|
||||
}
|
||||
|
||||
DWORD first_raw = 0;
|
||||
//copy all the sections, one by one:
|
||||
SIZE_T raw_end = 0;
|
||||
for (WORD i = 0; i < fileHdr->NumberOfSections; i++) {
|
||||
PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i));
|
||||
if (!validate_ptr((const LPVOID)payload, destBufferSize, next_sec, IMAGE_SIZEOF_SECTION_HEADER)) {
|
||||
return false;
|
||||
}
|
||||
if (next_sec->PointerToRawData == 0 || next_sec->SizeOfRawData == 0) {
|
||||
continue; //skipping empty
|
||||
}
|
||||
LPVOID section_mapped = destBuffer + next_sec->VirtualAddress;
|
||||
LPVOID section_raw_ptr = (BYTE*)payload + next_sec->PointerToRawData;
|
||||
SIZE_T sec_size = next_sec->SizeOfRawData;
|
||||
raw_end = next_sec->SizeOfRawData + next_sec->PointerToRawData;
|
||||
|
||||
if ((next_sec->VirtualAddress + sec_size) > destBufferSize) {
|
||||
std::cerr << "[!] Virtual section size is out ouf bounds: " << std::hex << sec_size << std::endl;
|
||||
sec_size = (destBufferSize > next_sec->VirtualAddress) ? SIZE_T(destBufferSize - next_sec->VirtualAddress) : 0;
|
||||
std::cerr << "[!] Truncated to maximal size: " << std::hex << sec_size << ", buffer size:" << destBufferSize << std::endl;
|
||||
}
|
||||
if (next_sec->VirtualAddress >= destBufferSize && sec_size != 0) {
|
||||
std::cerr << "[-] VirtualAddress of section is out ouf bounds: " << std::hex << next_sec->VirtualAddress << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (next_sec->PointerToRawData + sec_size > destBufferSize) {
|
||||
std::cerr << "[-] Raw section size is out ouf bounds: " << std::hex << sec_size << std::endl;
|
||||
return false;
|
||||
}
|
||||
// validate source:
|
||||
if (!validate_ptr((const LPVOID)payload, payloadSize, section_raw_ptr, sec_size)) {
|
||||
std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
|
||||
continue;
|
||||
}
|
||||
// validate destination:
|
||||
if (!peconv::validate_ptr(destBuffer, destBufferSize, section_mapped, sec_size)) {
|
||||
std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
|
||||
continue;
|
||||
}
|
||||
memcpy(section_mapped, section_raw_ptr, sec_size);
|
||||
if (first_raw == 0 || (next_sec->PointerToRawData < first_raw)) {
|
||||
first_raw = next_sec->PointerToRawData;
|
||||
}
|
||||
}
|
||||
|
||||
//copy payload's headers:
|
||||
if (hdrsSize == 0) {
|
||||
hdrsSize= first_raw;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "hdrsSize not filled, using calculated size: " << std::hex << hdrsSize << "\n";
|
||||
#endif
|
||||
}
|
||||
if (!validate_ptr((const LPVOID)payload, destBufferSize, (const LPVOID)payload, hdrsSize)) {
|
||||
return false;
|
||||
}
|
||||
memcpy(destBuffer, payload, hdrsSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
BYTE* peconv::pe_raw_to_virtual(
|
||||
IN const BYTE* payload,
|
||||
IN size_t in_size,
|
||||
OUT size_t &out_size,
|
||||
IN OPTIONAL bool executable,
|
||||
IN OPTIONAL ULONGLONG desired_base
|
||||
)
|
||||
{
|
||||
//check payload:
|
||||
BYTE* nt_hdr = get_nt_hdrs(payload);
|
||||
if (nt_hdr == NULL) {
|
||||
std::cerr << "Invalid payload: " << std::hex << (ULONGLONG) payload << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
DWORD payloadImageSize = 0;
|
||||
|
||||
bool is64 = is64bit(payload);
|
||||
if (is64) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr = (IMAGE_NT_HEADERS64*)nt_hdr;
|
||||
payloadImageSize = payload_nt_hdr->OptionalHeader.SizeOfImage;
|
||||
}
|
||||
else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr = (IMAGE_NT_HEADERS32*)nt_hdr;
|
||||
payloadImageSize = payload_nt_hdr->OptionalHeader.SizeOfImage;
|
||||
}
|
||||
|
||||
DWORD protect = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
||||
|
||||
//first we will prepare the payload image in the local memory, so that it will be easier to edit it, apply relocations etc.
|
||||
//when it will be ready, we will copy it into the space reserved in the target process
|
||||
BYTE* localCopyAddress = alloc_pe_buffer(payloadImageSize, protect, desired_base);
|
||||
if (localCopyAddress == NULL) {
|
||||
std::cerr << "Could not allocate memory in the current process" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
//printf("Allocated local memory: %p size: %x\n", localCopyAddress, payloadImageSize);
|
||||
if (!sections_raw_to_virtual(payload, in_size, (BYTE*)localCopyAddress, payloadImageSize)) {
|
||||
std::cerr << "Could not copy PE file" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
out_size = payloadImageSize;
|
||||
return localCopyAddress;
|
||||
}
|
||||
213
Etw Syscall/libpeconv-master/libpeconv/src/pe_virtual_to_raw.cpp
Normal file
213
Etw Syscall/libpeconv-master/libpeconv/src/pe_virtual_to_raw.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
#include "peconv/pe_virtual_to_raw.h"
|
||||
|
||||
#include "peconv/util.h"
|
||||
#include "peconv/pe_hdrs_helper.h"
|
||||
#include "peconv/relocate.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
bool sections_virtual_to_raw(BYTE* payload, SIZE_T payload_size, OUT BYTE* destAddress, OUT SIZE_T *raw_size_ptr)
|
||||
{
|
||||
if (!payload || !destAddress) return false;
|
||||
|
||||
BYTE* payload_nt_hdr = get_nt_hdrs(payload, payload_size);
|
||||
if (payload_nt_hdr == NULL) {
|
||||
std::cerr << "Invalid payload: " << std::hex << (ULONGLONG) payload << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool is64b = is64bit(payload);
|
||||
|
||||
IMAGE_FILE_HEADER *fileHdr = NULL;
|
||||
DWORD hdrsSize = 0;
|
||||
LPVOID secptr = NULL;
|
||||
if (is64b) {
|
||||
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*) payload_nt_hdr;
|
||||
fileHdr = &(payload_nt_hdr64->FileHeader);
|
||||
hdrsSize = payload_nt_hdr64->OptionalHeader.SizeOfHeaders;
|
||||
secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr64->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
|
||||
} else {
|
||||
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*) payload_nt_hdr;
|
||||
fileHdr = &(payload_nt_hdr32->FileHeader);
|
||||
hdrsSize = payload_nt_hdr32->OptionalHeader.SizeOfHeaders;
|
||||
secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr32->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
|
||||
}
|
||||
|
||||
//copy all the sections, one by one:
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Coping sections:" << std::endl;
|
||||
#endif
|
||||
DWORD first_raw = 0;
|
||||
SIZE_T raw_end = hdrsSize;
|
||||
for (WORD i = 0; i < fileHdr->NumberOfSections; i++) {
|
||||
PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i));
|
||||
if (!validate_ptr(payload, payload_size, next_sec, IMAGE_SIZEOF_SECTION_HEADER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LPVOID section_mapped = (BYTE*) payload + next_sec->VirtualAddress;
|
||||
LPVOID section_raw_ptr = destAddress + next_sec->PointerToRawData;
|
||||
SIZE_T sec_size = next_sec->SizeOfRawData;
|
||||
|
||||
size_t new_end = sec_size + next_sec->PointerToRawData;
|
||||
if (new_end > raw_end) raw_end = new_end;
|
||||
|
||||
if ((next_sec->VirtualAddress + sec_size) > payload_size) {
|
||||
std::cerr << "[!] Virtual section size is out ouf bounds: " << std::hex << sec_size << std::endl;
|
||||
sec_size = (payload_size > next_sec->VirtualAddress) ? SIZE_T(payload_size - next_sec->VirtualAddress) : 0;
|
||||
std::cerr << "[!] Truncated to maximal size: " << std::hex << sec_size << ", buffer size: " << payload_size << std::endl;
|
||||
}
|
||||
if (next_sec->VirtualAddress > payload_size && sec_size != 0) {
|
||||
std::cerr << "[-] VirtualAddress of section is out ouf bounds: " << std::hex << next_sec->VirtualAddress << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (next_sec->PointerToRawData + sec_size > payload_size) {
|
||||
std::cerr << "[-] Raw section size is out ouf bounds: " << std::hex << sec_size << std::endl;
|
||||
return false;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[+] " << next_sec->Name << " to: " << std::hex << section_raw_ptr << std::endl;
|
||||
#endif
|
||||
//validate source:
|
||||
if (!peconv::validate_ptr(payload, payload_size, section_mapped, sec_size)) {
|
||||
std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
|
||||
continue;
|
||||
}
|
||||
//validate destination:
|
||||
if (!peconv::validate_ptr(destAddress, payload_size, section_raw_ptr, sec_size)) {
|
||||
std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
|
||||
continue;
|
||||
}
|
||||
memcpy(section_raw_ptr, section_mapped, sec_size);
|
||||
if (first_raw == 0 || (next_sec->PointerToRawData < first_raw)) {
|
||||
first_raw = next_sec->PointerToRawData;
|
||||
}
|
||||
}
|
||||
if (raw_end > payload_size) raw_end = payload_size;
|
||||
if (raw_size_ptr != NULL) {
|
||||
(*raw_size_ptr) = raw_end;
|
||||
}
|
||||
|
||||
//copy payload's headers:
|
||||
if (hdrsSize == 0) {
|
||||
hdrsSize = first_raw;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "hdrsSize not filled, using calculated size: " << std::hex << hdrsSize << "\n";
|
||||
#endif
|
||||
}
|
||||
if (!validate_ptr(payload, payload_size, payload, hdrsSize)) {
|
||||
return false;
|
||||
}
|
||||
memcpy(destAddress, payload, hdrsSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
BYTE* peconv::pe_virtual_to_raw(
|
||||
IN BYTE* payload,
|
||||
IN size_t in_size,
|
||||
IN ULONGLONG loadBase,
|
||||
OUT size_t &out_size,
|
||||
IN OPTIONAL bool rebuffer
|
||||
)
|
||||
{
|
||||
BYTE* out_buf = (BYTE*)alloc_pe_buffer(in_size, PAGE_READWRITE);
|
||||
if (out_buf == NULL) return NULL; //could not allocate output buffer
|
||||
|
||||
BYTE* in_buf = payload;
|
||||
if (rebuffer) {
|
||||
in_buf = (BYTE*) alloc_pe_buffer(in_size, PAGE_READWRITE);
|
||||
if (in_buf == NULL) {
|
||||
free_pe_buffer(out_buf, in_size);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(in_buf, payload, in_size);
|
||||
}
|
||||
|
||||
ULONGLONG oldBase = get_image_base(in_buf);
|
||||
bool isOk = true;
|
||||
// from the loadBase go back to the original base
|
||||
if (!relocate_module(in_buf, in_size, oldBase, loadBase)) {
|
||||
//Failed relocating the module! Changing image base instead...
|
||||
if (!update_image_base(in_buf, (ULONGLONG)loadBase)) {
|
||||
std::cerr << "[-] Failed relocating the module!" << std::endl;
|
||||
isOk = false;
|
||||
} else {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[!] WARNING: The module could not be relocated, so the ImageBase has been changed instead!" << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
SIZE_T raw_size = 0;
|
||||
if (isOk) {
|
||||
if (!sections_virtual_to_raw(in_buf, in_size, out_buf, &raw_size)) {
|
||||
isOk = false;
|
||||
}
|
||||
}
|
||||
if (rebuffer && in_buf != NULL) {
|
||||
free_pe_buffer(in_buf, in_size);
|
||||
in_buf = NULL;
|
||||
}
|
||||
if (!isOk) {
|
||||
free_pe_buffer(out_buf, in_size);
|
||||
out_buf = NULL;
|
||||
raw_size = 0;
|
||||
}
|
||||
out_size = raw_size;
|
||||
return out_buf;
|
||||
}
|
||||
|
||||
BYTE* peconv::pe_realign_raw_to_virtual(
|
||||
IN const BYTE* payload,
|
||||
IN size_t in_size,
|
||||
IN ULONGLONG loadBase,
|
||||
OUT size_t &out_size
|
||||
)
|
||||
{
|
||||
out_size = in_size;
|
||||
BYTE* out_buf = (BYTE*)alloc_pe_buffer(out_size, PAGE_READWRITE);
|
||||
if (!out_buf) {
|
||||
out_size = 0;
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(out_buf, payload, in_size);
|
||||
|
||||
ULONGLONG oldBase = get_image_base(out_buf);
|
||||
bool isOk = true;
|
||||
// from the loadBase go back to the original base
|
||||
if (!relocate_module(out_buf, out_size, oldBase, loadBase)) {
|
||||
//Failed relocating the module! Changing image base instead...
|
||||
if (!update_image_base(out_buf, (ULONGLONG)loadBase)) {
|
||||
std::cerr << "[-] Failed relocating the module!" << std::endl;
|
||||
isOk = false;
|
||||
} else {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[!] WARNING: The module could not be relocated, so the ImageBase has been changed instead!" << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
//---
|
||||
//set raw alignment the same as virtual
|
||||
DWORD v_alignment = peconv::get_sec_alignment((const PBYTE)payload, false);
|
||||
if (!peconv::set_sec_alignment(out_buf, true, v_alignment)) {
|
||||
isOk = false;
|
||||
}
|
||||
//set Raw pointers and sizes of the sections same as Virtual
|
||||
size_t sections_count = peconv::get_sections_count(out_buf, out_size);
|
||||
for (size_t i = 0; i < sections_count; i++) {
|
||||
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(out_buf, out_size, i);
|
||||
if (!sec) break;
|
||||
|
||||
sec->Misc.VirtualSize = peconv::get_virtual_sec_size(out_buf, sec, true);
|
||||
sec->SizeOfRawData = sec->Misc.VirtualSize;
|
||||
sec->PointerToRawData = sec->VirtualAddress;
|
||||
}
|
||||
//!---
|
||||
if (!isOk) {
|
||||
free_pe_buffer(out_buf);
|
||||
out_buf = nullptr;
|
||||
out_size = 0;
|
||||
}
|
||||
return out_buf;
|
||||
}
|
||||
178
Etw Syscall/libpeconv-master/libpeconv/src/peb_lookup.cpp
Normal file
178
Etw Syscall/libpeconv-master/libpeconv/src/peb_lookup.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#include "ntddk.h"
|
||||
|
||||
#include <peconv/peb_lookup.h>
|
||||
|
||||
class SectionLocker {
|
||||
public:
|
||||
SectionLocker(RTL_CRITICAL_SECTION &_section)
|
||||
: section(_section)
|
||||
{
|
||||
RtlEnterCriticalSection(§ion);
|
||||
}
|
||||
|
||||
~SectionLocker()
|
||||
{
|
||||
RtlLeaveCriticalSection(§ion);
|
||||
}
|
||||
|
||||
protected:
|
||||
RTL_CRITICAL_SECTION §ion;
|
||||
};
|
||||
|
||||
//here we don't want to use any functions imported form extenal modules
|
||||
|
||||
typedef struct _LDR_MODULE {
|
||||
LIST_ENTRY InLoadOrderModuleList;// +0x00
|
||||
LIST_ENTRY InMemoryOrderModuleList;// +0x08
|
||||
LIST_ENTRY InInitializationOrderModuleList;// +0x10
|
||||
void* BaseAddress; // +0x18
|
||||
void* EntryPoint; // +0x1c
|
||||
ULONG SizeOfImage;
|
||||
UNICODE_STRING FullDllName;
|
||||
UNICODE_STRING BaseDllName;
|
||||
ULONG Flags;
|
||||
SHORT LoadCount;
|
||||
SHORT TlsIndex;
|
||||
HANDLE SectionHandle;
|
||||
ULONG CheckSum;
|
||||
ULONG TimeDateStamp;
|
||||
} LDR_MODULE, *PLDR_MODULE;
|
||||
|
||||
inline PPEB get_peb()
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
return (PPEB)__readgsqword(0x60);
|
||||
#else
|
||||
return (PPEB)__readfsdword(0x30);
|
||||
/*
|
||||
//alternative way to fetch it:
|
||||
LPVOID PEB = NULL;
|
||||
__asm {
|
||||
mov eax, fs:[30h]
|
||||
mov PEB, eax
|
||||
};
|
||||
return (PPEB)PEB;
|
||||
|
||||
or:
|
||||
LPVOID PEB = RtlGetCurrentPeb();
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
inline WCHAR to_lowercase(WCHAR c1)
|
||||
{
|
||||
if (c1 <= L'Z' && c1 >= L'A') {
|
||||
c1 = (c1 - L'A') + L'a';
|
||||
}
|
||||
return c1;
|
||||
}
|
||||
|
||||
bool is_wanted_module(LPWSTR curr_name, LPWSTR wanted_name)
|
||||
{
|
||||
if (wanted_name == NULL || curr_name == NULL) return false;
|
||||
|
||||
WCHAR *curr_end_ptr = curr_name;
|
||||
while (*curr_end_ptr != L'\0') {
|
||||
curr_end_ptr++;
|
||||
}
|
||||
if (curr_end_ptr == curr_name) return false;
|
||||
|
||||
WCHAR *wanted_end_ptr = wanted_name;
|
||||
while (*wanted_end_ptr != L'\0') {
|
||||
wanted_end_ptr++;
|
||||
}
|
||||
if (wanted_end_ptr == wanted_name) return false;
|
||||
|
||||
while ((curr_end_ptr != curr_name) && (wanted_end_ptr != wanted_name)) {
|
||||
|
||||
if (to_lowercase(*wanted_end_ptr) != to_lowercase(*curr_end_ptr)) {
|
||||
return false;
|
||||
}
|
||||
wanted_end_ptr--;
|
||||
curr_end_ptr--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
HMODULE peconv::get_module_via_peb(IN OPTIONAL LPWSTR module_name)
|
||||
{
|
||||
PPEB peb = get_peb();
|
||||
if (!peb) {
|
||||
return NULL;
|
||||
}
|
||||
SectionLocker locker(*peb->LoaderLock);
|
||||
LIST_ENTRY head = peb->Ldr->InLoadOrderModuleList;
|
||||
|
||||
const PLDR_MODULE first_module = *((PLDR_MODULE *)(&head));
|
||||
PLDR_MODULE curr_module = first_module;
|
||||
if (!module_name) {
|
||||
return (HMODULE)(curr_module->BaseAddress);
|
||||
}
|
||||
|
||||
// it is a cyclic list, so if the next record links to the initial one, it means we went throught the full loop
|
||||
do {
|
||||
// this should also work as a terminator, because the BaseAddress of the last module in the cycle is NULL
|
||||
if (curr_module == NULL || curr_module->BaseAddress == NULL) {
|
||||
break;
|
||||
}
|
||||
if (is_wanted_module(curr_module->BaseDllName.Buffer, module_name)) {
|
||||
return (HMODULE)(curr_module->BaseAddress);
|
||||
}
|
||||
curr_module = (PLDR_MODULE)curr_module->InLoadOrderModuleList.Flink;
|
||||
|
||||
} while (curr_module != first_module);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t peconv::get_module_size_via_peb(IN OPTIONAL HMODULE hModule)
|
||||
{
|
||||
PPEB peb = get_peb();
|
||||
if (!peb) {
|
||||
return 0;
|
||||
}
|
||||
SectionLocker locker(*peb->LoaderLock);
|
||||
LIST_ENTRY head = peb->Ldr->InLoadOrderModuleList;
|
||||
|
||||
const PLDR_MODULE first_module = *((PLDR_MODULE *)(&head));
|
||||
PLDR_MODULE curr_module = first_module;
|
||||
if (!hModule) {
|
||||
return (size_t)(curr_module->SizeOfImage);
|
||||
}
|
||||
|
||||
// it is a cyclic list, so if the next record links to the initial one, it means we went throught the full loop
|
||||
do {
|
||||
// this should also work as a terminator, because the BaseAddress of the last module in the cycle is NULL
|
||||
if (curr_module == NULL || curr_module->BaseAddress == NULL) {
|
||||
break;
|
||||
}
|
||||
if (hModule == (HMODULE)(curr_module->BaseAddress)) {
|
||||
return (size_t)(curr_module->SizeOfImage);
|
||||
}
|
||||
curr_module = (PLDR_MODULE)curr_module->InLoadOrderModuleList.Flink;
|
||||
|
||||
} while (curr_module != first_module);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool peconv::set_main_module_in_peb(HMODULE module_ptr)
|
||||
{
|
||||
PPEB peb = get_peb();
|
||||
if (peb == NULL) {
|
||||
return false;
|
||||
}
|
||||
SectionLocker locker(*peb->FastPebLock);
|
||||
peb->ImageBaseAddress = module_ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
HMODULE peconv::get_main_module_via_peb()
|
||||
{
|
||||
PPEB peb = get_peb();
|
||||
if (peb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
SectionLocker locker(*peb->FastPebLock);
|
||||
return (HMODULE) peb->ImageBaseAddress;
|
||||
}
|
||||
193
Etw Syscall/libpeconv-master/libpeconv/src/relocate.cpp
Normal file
193
Etw Syscall/libpeconv-master/libpeconv/src/relocate.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
#include "peconv/relocate.h"
|
||||
|
||||
#include "peconv/pe_hdrs_helper.h"
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
#define RELOC_32BIT_FIELD 3
|
||||
#define RELOC_64BIT_FIELD 0xA
|
||||
|
||||
class ApplyRelocCallback : public RelocBlockCallback
|
||||
{
|
||||
public:
|
||||
ApplyRelocCallback(bool _is64bit, ULONGLONG _oldBase, ULONGLONG _newBase)
|
||||
: RelocBlockCallback(_is64bit), oldBase(_oldBase), newBase(_newBase)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool processRelocField(ULONG_PTR relocField)
|
||||
{
|
||||
if (is64bit) {
|
||||
ULONGLONG* relocateAddr = (ULONGLONG*)((ULONG_PTR)relocField);
|
||||
ULONGLONG rva = (*relocateAddr) - oldBase;
|
||||
(*relocateAddr) = rva + newBase;
|
||||
}
|
||||
else {
|
||||
DWORD* relocateAddr = (DWORD*)((ULONG_PTR)relocField);
|
||||
ULONGLONG rva = ULONGLONG(*relocateAddr) - oldBase;
|
||||
(*relocateAddr) = static_cast<DWORD>(rva + newBase);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
ULONGLONG oldBase;
|
||||
ULONGLONG newBase;
|
||||
};
|
||||
|
||||
bool is_empty_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, PVOID modulePtr, SIZE_T moduleSize)
|
||||
{
|
||||
if (entriesNum == 0) {
|
||||
return true; // nothing to process
|
||||
}
|
||||
BASE_RELOCATION_ENTRY* entry = block;
|
||||
for (SIZE_T i = 0; i < entriesNum; i++) {
|
||||
if (!validate_ptr(modulePtr, moduleSize, entry, sizeof(BASE_RELOCATION_ENTRY))) {
|
||||
return false;
|
||||
}
|
||||
DWORD type = entry->Type;
|
||||
if (type != 0) {
|
||||
//non empty block found
|
||||
return false;
|
||||
}
|
||||
entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)entry + sizeof(WORD));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool process_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, PVOID modulePtr, SIZE_T moduleSize, bool is64bit, RelocBlockCallback *callback)
|
||||
{
|
||||
if (entriesNum == 0) {
|
||||
return true; // nothing to process
|
||||
}
|
||||
BASE_RELOCATION_ENTRY* entry = block;
|
||||
SIZE_T i = 0;
|
||||
for (i = 0; i < entriesNum; i++) {
|
||||
if (!validate_ptr(modulePtr, moduleSize, entry, sizeof(BASE_RELOCATION_ENTRY))) {
|
||||
break;
|
||||
}
|
||||
DWORD offset = entry->Offset;
|
||||
DWORD type = entry->Type;
|
||||
if (type == 0) {
|
||||
break;
|
||||
}
|
||||
if (type != RELOC_32BIT_FIELD && type != RELOC_64BIT_FIELD) {
|
||||
if (callback) { //print debug messages only if the callback function was set
|
||||
printf("[-] Not supported relocations format at %d: %d\n", (int)i, (int)type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
DWORD reloc_field = page + offset;
|
||||
if (reloc_field >= moduleSize) {
|
||||
if (callback) { //print debug messages only if the callback function was set
|
||||
printf("[-] Malformed field: %lx\n", reloc_field);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (callback) {
|
||||
bool isOk = callback->processRelocField(((ULONG_PTR)modulePtr + reloc_field));
|
||||
if (!isOk) {
|
||||
std::cout << "[-] Failed processing reloc field at: " << std::hex << reloc_field << "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)entry + sizeof(WORD));
|
||||
}
|
||||
return (i != 0);
|
||||
}
|
||||
|
||||
bool peconv::process_relocation_table(IN PVOID modulePtr, IN SIZE_T moduleSize, IN RelocBlockCallback *callback)
|
||||
{
|
||||
IMAGE_DATA_DIRECTORY* relocDir = peconv::get_directory_entry((const BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
||||
if (relocDir == NULL) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "[!] WARNING: no relocation table found!\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
if (!validate_ptr(modulePtr, moduleSize, relocDir, sizeof(IMAGE_DATA_DIRECTORY))) {
|
||||
std::cerr << "[!] Invalid relocDir pointer\n";
|
||||
return false;
|
||||
}
|
||||
DWORD maxSize = relocDir->Size;
|
||||
DWORD relocAddr = relocDir->VirtualAddress;
|
||||
bool is64b = is64bit((BYTE*)modulePtr);
|
||||
|
||||
IMAGE_BASE_RELOCATION* reloc = NULL;
|
||||
|
||||
DWORD parsedSize = 0;
|
||||
DWORD validBlocks = 0;
|
||||
while (parsedSize < maxSize) {
|
||||
reloc = (IMAGE_BASE_RELOCATION*)(relocAddr + parsedSize + (ULONG_PTR)modulePtr);
|
||||
if (!validate_ptr(modulePtr, moduleSize, reloc, sizeof(IMAGE_BASE_RELOCATION))) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[-] Invalid address of relocations\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
if (reloc->SizeOfBlock == 0) {
|
||||
break;
|
||||
}
|
||||
size_t entriesNum = (reloc->SizeOfBlock - 2 * sizeof(DWORD)) / sizeof(WORD);
|
||||
DWORD page = reloc->VirtualAddress;
|
||||
|
||||
BASE_RELOCATION_ENTRY* block = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)reloc + sizeof(DWORD) + sizeof(DWORD));
|
||||
if (!validate_ptr(modulePtr, moduleSize, block, sizeof(BASE_RELOCATION_ENTRY))) {
|
||||
std::cerr << "[-] Invalid address of relocations block\n";
|
||||
return false;
|
||||
}
|
||||
if (!is_empty_reloc_block(block, entriesNum, page, modulePtr, moduleSize)) {
|
||||
if (process_reloc_block(block, entriesNum, page, modulePtr, moduleSize, is64b, callback)) {
|
||||
validBlocks++;
|
||||
}
|
||||
else {
|
||||
// the block was malformed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
parsedSize += reloc->SizeOfBlock;
|
||||
}
|
||||
return (validBlocks != 0);
|
||||
}
|
||||
|
||||
bool apply_relocations(PVOID modulePtr, SIZE_T moduleSize, ULONGLONG newBase, ULONGLONG oldBase)
|
||||
{
|
||||
const bool is64b = is64bit((BYTE*)modulePtr);
|
||||
ApplyRelocCallback callback(is64b, oldBase, newBase);
|
||||
return process_relocation_table(modulePtr, moduleSize, &callback);
|
||||
}
|
||||
|
||||
bool peconv::relocate_module(IN BYTE* modulePtr, IN SIZE_T moduleSize, IN ULONGLONG newBase, IN ULONGLONG oldBase)
|
||||
{
|
||||
if (modulePtr == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (oldBase == 0) {
|
||||
oldBase = get_image_base(modulePtr);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("New Base: %llx\n", newBase);
|
||||
printf("Old Base: %llx\n", oldBase);
|
||||
#endif
|
||||
if (newBase == oldBase) {
|
||||
#ifdef _DEBUG
|
||||
printf("Nothing to relocate! oldBase is the same as the newBase!\n");
|
||||
#endif
|
||||
return true; //nothing to relocate
|
||||
}
|
||||
if (apply_relocations(modulePtr, moduleSize, newBase, oldBase)) {
|
||||
return true;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("Could not relocate the module!\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool peconv::has_valid_relocation_table(IN const PBYTE modulePtr, IN const size_t moduleSize)
|
||||
{
|
||||
return process_relocation_table(modulePtr, moduleSize, nullptr);
|
||||
}
|
||||
|
||||
421
Etw Syscall/libpeconv-master/libpeconv/src/remote_pe_reader.cpp
Normal file
421
Etw Syscall/libpeconv-master/libpeconv/src/remote_pe_reader.cpp
Normal file
@@ -0,0 +1,421 @@
|
||||
#include "peconv/remote_pe_reader.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "peconv/util.h"
|
||||
#include "peconv/fix_imports.h"
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
bool peconv::fetch_region_info(HANDLE processHandle, LPVOID moduleBase, MEMORY_BASIC_INFORMATION &page_info)
|
||||
{
|
||||
memset(&page_info, 0, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
SIZE_T out = VirtualQueryEx(processHandle, moduleBase, &page_info, sizeof(page_info));
|
||||
if (out != sizeof(page_info)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t _fetch_region_size(MEMORY_BASIC_INFORMATION &page_info, LPVOID moduleBase)
|
||||
{
|
||||
if (page_info.Type == 0) {
|
||||
return false; //invalid type, skip it
|
||||
}
|
||||
if ((BYTE*)page_info.BaseAddress > moduleBase) {
|
||||
return 0; //should never happen
|
||||
}
|
||||
const size_t offset = (ULONG_PTR)moduleBase - (ULONG_PTR)page_info.BaseAddress;
|
||||
const size_t area_size = page_info.RegionSize - offset;
|
||||
return area_size;
|
||||
}
|
||||
|
||||
size_t peconv::fetch_region_size(HANDLE processHandle, LPVOID moduleBase)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION page_info = { 0 };
|
||||
if (!peconv::fetch_region_info(processHandle, moduleBase, page_info)) {
|
||||
return 0;
|
||||
}
|
||||
const size_t area_size = _fetch_region_size(page_info, moduleBase);
|
||||
return area_size;
|
||||
}
|
||||
|
||||
ULONGLONG peconv::fetch_alloc_base(HANDLE processHandle, LPVOID moduleBase)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION page_info = { 0 };
|
||||
if (!peconv::fetch_region_info(processHandle, moduleBase, page_info)) {
|
||||
return 0;
|
||||
}
|
||||
if (page_info.Type == 0) {
|
||||
return 0; //invalid type, skip it
|
||||
}
|
||||
return (ULONGLONG) page_info.AllocationBase;
|
||||
}
|
||||
|
||||
namespace peconv {
|
||||
/**
|
||||
Performs a binary search along with ReadProcessMemory, trying to find the biggest size of memory (within the buffer_size) that can be read. The search stops when the minimal_size was reached.
|
||||
The given minimal_size must be non-zero, and smaller than the buffer_size.
|
||||
If the size matching the constraints was found, it reads that many bytes to the buffer.
|
||||
*/
|
||||
SIZE_T _search_readable_size(HANDLE processHandle, LPVOID start_addr, OUT BYTE* buffer, const size_t buffer_size, const SIZE_T minimal_size)
|
||||
{
|
||||
if (!buffer || buffer_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
if ((buffer_size < minimal_size) || minimal_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
SIZE_T last_failed_size = buffer_size;
|
||||
SIZE_T last_success_size = 0;
|
||||
|
||||
SIZE_T test_read_size = 0;
|
||||
if (!ReadProcessMemory(processHandle, start_addr, buffer, minimal_size, &test_read_size)) {
|
||||
//cannot read even the minimal size, quit trying
|
||||
return test_read_size;
|
||||
}
|
||||
last_success_size = minimal_size;
|
||||
|
||||
SIZE_T read_size = 0;
|
||||
SIZE_T to_read_size = buffer_size/2;
|
||||
|
||||
while (to_read_size > minimal_size && to_read_size < buffer_size)
|
||||
{
|
||||
read_size = 0;
|
||||
if (ReadProcessMemory(processHandle, start_addr, buffer, to_read_size, &read_size)) {
|
||||
last_success_size = to_read_size;
|
||||
}
|
||||
else {
|
||||
last_failed_size = to_read_size;
|
||||
}
|
||||
const size_t delta = (last_failed_size - last_success_size) / 2;
|
||||
if (delta == 0) break;
|
||||
to_read_size = last_success_size + delta;
|
||||
}
|
||||
if (last_success_size) {
|
||||
read_size = 0;
|
||||
memset(buffer, 0, buffer_size);
|
||||
ReadProcessMemory(processHandle, start_addr, buffer, last_success_size, &read_size);
|
||||
return read_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
size_t peconv::read_remote_memory(HANDLE processHandle, LPVOID start_addr, OUT BYTE* buffer, const size_t buffer_size, const SIZE_T minimal_size)
|
||||
{
|
||||
if (!buffer || buffer_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
memset(buffer, 0, buffer_size);
|
||||
|
||||
SIZE_T read_size = 0;
|
||||
DWORD last_error = ERROR_SUCCESS;
|
||||
|
||||
while (buffer_size > 0)
|
||||
{
|
||||
if (ReadProcessMemory(processHandle, start_addr, buffer, buffer_size, &read_size)) {
|
||||
break;
|
||||
}
|
||||
last_error = GetLastError();
|
||||
if (last_error != ERROR_SUCCESS) {
|
||||
if (read_size == 0 && (last_error != ERROR_PARTIAL_COPY)) {
|
||||
break; // break
|
||||
}
|
||||
}
|
||||
if (last_error == ERROR_PARTIAL_COPY) {
|
||||
read_size = peconv::_search_readable_size(processHandle, start_addr, buffer, buffer_size, minimal_size);
|
||||
#ifdef _DEBUG
|
||||
std::cout << "peconv::search_readable_size res: " << std::hex << read_size << std::endl;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (read_size == 0) {
|
||||
std::cerr << "[WARNING] Cannot read memory. Last Error : " << last_error << std::endl;
|
||||
}
|
||||
else if (read_size < buffer_size) {
|
||||
std::cerr << "[WARNING] Read size: " << std::hex << read_size
|
||||
<< " is smaller than the requested size: " << std::hex << buffer_size
|
||||
<< ". Last Error: " << last_error << std::endl;
|
||||
|
||||
}
|
||||
#endif
|
||||
return static_cast<size_t>(read_size);
|
||||
}
|
||||
|
||||
size_t peconv::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)
|
||||
{
|
||||
if (!buffer || buffer_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
MEMORY_BASIC_INFORMATION page_info = { 0 };
|
||||
if (!peconv::fetch_region_info(processHandle, start_addr, page_info)) {
|
||||
return 0;
|
||||
}
|
||||
if ((page_info.State & MEM_COMMIT) == 0) {
|
||||
return 0;
|
||||
}
|
||||
size_t region_size = _fetch_region_size(page_info, start_addr);
|
||||
if (region_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const size_t size_to_read = (region_size > buffer_size) ? buffer_size : region_size;
|
||||
|
||||
const bool is_accessible = (page_info.Protect & PAGE_NOACCESS) == 0;
|
||||
BOOL access_changed = FALSE;
|
||||
DWORD oldProtect = 0;
|
||||
|
||||
// check the access right and eventually try to change it
|
||||
if (force_access && !is_accessible) {
|
||||
access_changed = VirtualProtectEx(processHandle, start_addr, region_size, PAGE_READONLY, &oldProtect);
|
||||
#ifdef _DEBUG
|
||||
if (!access_changed) {
|
||||
DWORD err = GetLastError();
|
||||
if (err != ERROR_ACCESS_DENIED) {
|
||||
std::cerr << "[!] " << std::hex << start_addr << " : " << region_size << " inaccessible area, changing page access failed: " << std::dec << err << "\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t size_read = 0;
|
||||
if (is_accessible || access_changed) {
|
||||
size_read = peconv::read_remote_memory(processHandle, start_addr, buffer, size_to_read, minimal_size);
|
||||
if ((size_read == 0) && (page_info.Protect & PAGE_GUARD)) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Warning: guarded page, trying to read again..." << std::endl;
|
||||
#endif
|
||||
size_read = peconv::read_remote_memory(processHandle, start_addr, buffer, size_to_read, minimal_size);
|
||||
}
|
||||
}
|
||||
// if the access rights were changed, change it back:
|
||||
if (access_changed) {
|
||||
VirtualProtectEx(processHandle, start_addr, region_size, oldProtect, &oldProtect);
|
||||
}
|
||||
return size_read;
|
||||
}
|
||||
|
||||
size_t peconv::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)
|
||||
{
|
||||
if (!buffer || !start_addr || buffer_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
memset(buffer, 0, buffer_size);
|
||||
|
||||
size_t real_read = 0; // how many bytes has been realy read (not counting the skipped areas)
|
||||
size_t last_valid = 0; // the last chunk that was really read (don't count the last skipped ones)
|
||||
|
||||
size_t buf_index = 0;
|
||||
for (buf_index = 0; buf_index < buffer_size; ) {
|
||||
LPVOID remote_chunk = LPVOID((ULONG_PTR)start_addr + buf_index);
|
||||
|
||||
MEMORY_BASIC_INFORMATION page_info = { 0 };
|
||||
if (!peconv::fetch_region_info(processHandle, remote_chunk, page_info)) {
|
||||
break;
|
||||
}
|
||||
const size_t region_size = _fetch_region_size(page_info, remote_chunk);
|
||||
if (region_size == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// read the memory:
|
||||
const size_t read_chunk = read_remote_region(
|
||||
processHandle,
|
||||
remote_chunk,
|
||||
(BYTE*)((ULONG_PTR)buffer + buf_index),
|
||||
buffer_size - buf_index,
|
||||
force_access,
|
||||
minimal_size
|
||||
);
|
||||
if (read_chunk == 0) {
|
||||
//skip the region that could not be read, and proceed to the next:
|
||||
buf_index += region_size;
|
||||
continue;
|
||||
}
|
||||
buf_index += read_chunk;
|
||||
real_read += read_chunk; // total sum of the read content
|
||||
last_valid = buf_index; // the last chunk that was really read
|
||||
}
|
||||
if (real_read == 0) {
|
||||
return 0;
|
||||
}
|
||||
return last_valid;
|
||||
}
|
||||
|
||||
bool peconv::read_remote_pe_header(HANDLE processHandle, LPVOID start_addr, OUT BYTE* buffer, const size_t buffer_size, bool force_access)
|
||||
{
|
||||
if (buffer == nullptr) {
|
||||
return false;
|
||||
}
|
||||
SIZE_T read_size = read_remote_area(processHandle, start_addr, buffer, buffer_size, force_access);
|
||||
if (read_size == 0) {
|
||||
return false;
|
||||
}
|
||||
BYTE *nt_ptr = get_nt_hdrs(buffer, buffer_size);
|
||||
if (nt_ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const size_t nt_offset = nt_ptr - buffer;
|
||||
const size_t nt_size = peconv::is64bit(buffer) ? sizeof(IMAGE_NT_HEADERS64) : sizeof(IMAGE_NT_HEADERS32);
|
||||
const size_t min_size = nt_offset + nt_size;
|
||||
|
||||
if (read_size < min_size) {
|
||||
std::cerr << "[-] [" << std::dec << get_process_id(processHandle)
|
||||
<< " ][" << std::hex << (ULONGLONG) start_addr
|
||||
<< "] Read size: " << std::hex << read_size
|
||||
<< " is smaller that the minimal size:" << get_hdrs_size(buffer)
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
//reading succeeded and the header passed the checks:
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace peconv {
|
||||
inline size_t roundup_to_unit(size_t size, size_t unit)
|
||||
{
|
||||
if (unit == 0) {
|
||||
return size;
|
||||
}
|
||||
size_t parts = size / unit;
|
||||
if (size % unit) parts++;
|
||||
return parts * unit;
|
||||
}
|
||||
};
|
||||
|
||||
peconv::UNALIGNED_BUF peconv::get_remote_pe_section(HANDLE processHandle, LPVOID start_addr, const size_t section_num, OUT size_t §ion_size, bool roundup, bool force_access)
|
||||
{
|
||||
BYTE header_buffer[MAX_HEADER_SIZE] = { 0 };
|
||||
|
||||
if (!read_remote_pe_header(processHandle, start_addr, header_buffer, MAX_HEADER_SIZE)) {
|
||||
return NULL;
|
||||
}
|
||||
PIMAGE_SECTION_HEADER section_hdr = get_section_hdr(header_buffer, MAX_HEADER_SIZE, section_num);
|
||||
if (section_hdr == NULL || section_hdr->Misc.VirtualSize == 0) {
|
||||
return NULL;
|
||||
}
|
||||
size_t buffer_size = section_hdr->Misc.VirtualSize;
|
||||
if (roundup) {
|
||||
DWORD va = peconv::get_sec_alignment(header_buffer, false);
|
||||
if (va == 0) va = PAGE_SIZE;
|
||||
buffer_size = roundup_to_unit(section_hdr->Misc.VirtualSize, va);
|
||||
}
|
||||
UNALIGNED_BUF module_code = peconv::alloc_unaligned(buffer_size);
|
||||
if (module_code == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
size_t read_size = peconv::read_remote_memory(processHandle, LPVOID((ULONG_PTR)start_addr + section_hdr->VirtualAddress), module_code, buffer_size);
|
||||
if (read_size == 0) {
|
||||
// this function is slower, so use it only if the normal read has failed:
|
||||
read_size = read_remote_area(processHandle, LPVOID((ULONG_PTR)start_addr + section_hdr->VirtualAddress), module_code, buffer_size, force_access);
|
||||
}
|
||||
if (read_size == 0) {
|
||||
peconv::free_unaligned(module_code);
|
||||
return NULL;
|
||||
}
|
||||
section_size = buffer_size;
|
||||
return module_code;
|
||||
}
|
||||
|
||||
size_t peconv::read_remote_pe(const HANDLE processHandle, LPVOID start_addr, const size_t mod_size, OUT BYTE* buffer, const size_t bufferSize)
|
||||
{
|
||||
if (buffer == nullptr) {
|
||||
std::cerr << "[-] Invalid output buffer: NULL pointer" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
if (bufferSize < mod_size || bufferSize < MAX_HEADER_SIZE ) {
|
||||
std::cerr << "[-] Invalid output buffer: too small size!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
// read PE section by section
|
||||
PBYTE hdr_buffer = buffer;
|
||||
//try to read headers:
|
||||
if (!read_remote_pe_header(processHandle, start_addr, hdr_buffer, MAX_HEADER_SIZE)) {
|
||||
std::cerr << "[-] Failed to read the module header" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
if (!is_valid_sections_hdr_offset(hdr_buffer, MAX_HEADER_SIZE)) {
|
||||
std::cerr << "[-] Sections headers are invalid or atypically aligned" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
size_t sections_count = get_sections_count(hdr_buffer, MAX_HEADER_SIZE);
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Sections: " << sections_count << std::endl;
|
||||
#endif
|
||||
size_t read_size = MAX_HEADER_SIZE;
|
||||
|
||||
for (size_t i = 0; i < sections_count; i++) {
|
||||
PIMAGE_SECTION_HEADER hdr = get_section_hdr(hdr_buffer, MAX_HEADER_SIZE, i);
|
||||
if (!hdr) {
|
||||
std::cerr << "[-] Failed to read the header of section: " << i << std::endl;
|
||||
break;
|
||||
}
|
||||
const DWORD sec_va = hdr->VirtualAddress;
|
||||
const DWORD sec_vsize = get_virtual_sec_size(hdr_buffer, hdr, true);
|
||||
if (sec_va + sec_vsize > bufferSize) {
|
||||
std::cerr << "[-] No more space in the buffer!" << std::endl;
|
||||
break;
|
||||
}
|
||||
if (sec_vsize > 0 && !read_remote_memory(processHandle, LPVOID((ULONG_PTR)start_addr + sec_va), buffer + sec_va, sec_vsize)) {
|
||||
std::cerr << "[-] Failed to read the module section " << i <<" : at: " << std::hex << (ULONG_PTR)start_addr + sec_va << std::endl;
|
||||
}
|
||||
// update the end of the read area:
|
||||
size_t new_end = sec_va + sec_vsize;
|
||||
if (new_end > read_size) read_size = new_end;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Total read size: " << read_size << std::endl;
|
||||
#endif
|
||||
return read_size;
|
||||
}
|
||||
|
||||
DWORD peconv::get_remote_image_size(IN const HANDLE processHandle, IN LPVOID start_addr)
|
||||
{
|
||||
BYTE hdr_buffer[MAX_HEADER_SIZE] = { 0 };
|
||||
if (!read_remote_pe_header(processHandle, start_addr, hdr_buffer, MAX_HEADER_SIZE)) {
|
||||
return 0;
|
||||
}
|
||||
return peconv::get_image_size(hdr_buffer);
|
||||
}
|
||||
|
||||
bool peconv::dump_remote_pe(IN const char *out_path,
|
||||
IN const HANDLE processHandle,
|
||||
IN LPVOID start_addr,
|
||||
IN OUT t_pe_dump_mode &dump_mode,
|
||||
IN OPTIONAL peconv::ExportsMapper* exportsMap)
|
||||
{
|
||||
DWORD mod_size = get_remote_image_size(processHandle, start_addr);
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Module Size: " << mod_size << std::endl;
|
||||
#endif
|
||||
if (mod_size == 0) {
|
||||
return false;
|
||||
}
|
||||
BYTE* buffer = peconv::alloc_pe_buffer(mod_size, PAGE_READWRITE);
|
||||
if (buffer == nullptr) {
|
||||
std::cerr << "[-] Failed allocating buffer. Error: " << GetLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
//read the module that it mapped in the remote process:
|
||||
const size_t read_size = read_remote_pe(processHandle, start_addr, mod_size, buffer, mod_size);
|
||||
if (read_size == 0) {
|
||||
std::cerr << "[-] Failed reading module. Error: " << GetLastError() << std::endl;
|
||||
peconv::free_pe_buffer(buffer, mod_size);
|
||||
buffer = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool is_dumped = peconv::dump_pe(out_path,
|
||||
buffer, mod_size,
|
||||
reinterpret_cast<ULONGLONG>(start_addr),
|
||||
dump_mode, exportsMap);
|
||||
|
||||
peconv::free_pe_buffer(buffer, mod_size);
|
||||
buffer = nullptr;
|
||||
return is_dumped;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#include "peconv/resource_parser.h"
|
||||
#include "peconv/pe_hdrs_helper.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
bool parse_resource_dir(BYTE* modulePtr, const size_t moduleSize,
|
||||
IMAGE_RESOURCE_DIRECTORY_ENTRY *root_dir,
|
||||
const IMAGE_RESOURCE_DIRECTORY *upper_dir,
|
||||
IMAGE_RESOURCE_DIRECTORY* curr_dir,
|
||||
peconv::t_on_res_entry_found on_entry);
|
||||
|
||||
bool parse_resource_entry(BYTE* modulePtr, const size_t moduleSize,
|
||||
IMAGE_RESOURCE_DIRECTORY_ENTRY *root_dir,
|
||||
const IMAGE_RESOURCE_DIRECTORY *upper_dir,
|
||||
IMAGE_RESOURCE_DIRECTORY_ENTRY* entry,
|
||||
peconv::t_on_res_entry_found on_entry)
|
||||
{
|
||||
if (!entry->DataIsDirectory) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Entry is NOT a directory\n";
|
||||
#endif
|
||||
DWORD offset = entry->OffsetToData;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Offset: " << offset << std::endl;
|
||||
#endif
|
||||
IMAGE_RESOURCE_DATA_ENTRY *data_entry = (IMAGE_RESOURCE_DATA_ENTRY*)(offset + (ULONGLONG)upper_dir);
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, data_entry, sizeof(IMAGE_RESOURCE_DATA_ENTRY))) {
|
||||
return false;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Data Offset: " << data_entry->OffsetToData << " : " << data_entry->Size << std::endl;
|
||||
#endif
|
||||
BYTE* data_ptr = (BYTE*)((ULONGLONG)modulePtr + data_entry->OffsetToData);
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, data_ptr, data_entry->Size)) {
|
||||
return false;
|
||||
}
|
||||
on_entry(modulePtr, root_dir, data_entry);
|
||||
return true;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Entry is a directory\n";
|
||||
#endif
|
||||
//else: it is a next level directory
|
||||
DWORD offset = entry->OffsetToDirectory;
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Offset: " << offset << std::endl;
|
||||
#endif
|
||||
IMAGE_RESOURCE_DIRECTORY *next_dir = (IMAGE_RESOURCE_DIRECTORY*)(offset + (ULONGLONG)upper_dir);
|
||||
if (!peconv::validate_ptr(modulePtr, moduleSize, next_dir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
|
||||
return false;
|
||||
}
|
||||
return parse_resource_dir(modulePtr, moduleSize, root_dir, upper_dir, next_dir, on_entry);
|
||||
}
|
||||
|
||||
bool parse_resource_dir(BYTE* modulePtr, const size_t moduleSize,
|
||||
IMAGE_RESOURCE_DIRECTORY_ENTRY *root_dir,
|
||||
const IMAGE_RESOURCE_DIRECTORY *upper_dir,
|
||||
IMAGE_RESOURCE_DIRECTORY* curr_dir,
|
||||
peconv::t_on_res_entry_found on_entry)
|
||||
{
|
||||
size_t total_entries = curr_dir->NumberOfIdEntries + curr_dir->NumberOfNamedEntries;
|
||||
IMAGE_RESOURCE_DIRECTORY_ENTRY* first_entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((ULONGLONG)&curr_dir->NumberOfIdEntries + sizeof(WORD));
|
||||
for (size_t i = 0; i < total_entries; i++) {
|
||||
IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = &first_entry[i];
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Entry:" << std::hex << i << " ; " << "Id: " << entry->Id << " ; dataOffset:" << entry->OffsetToData << "\n";
|
||||
#endif
|
||||
if (root_dir == nullptr) {
|
||||
root_dir = entry;
|
||||
}
|
||||
parse_resource_entry(modulePtr, moduleSize, root_dir, upper_dir, entry, on_entry);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool peconv::parse_resources(BYTE* modulePtr, t_on_res_entry_found on_entry)
|
||||
{
|
||||
const size_t module_size = peconv::get_image_size(modulePtr);
|
||||
IMAGE_DATA_DIRECTORY *dir = peconv::get_directory_entry(modulePtr, IMAGE_DIRECTORY_ENTRY_RESOURCE);
|
||||
if (!dir || dir->VirtualAddress == 0 || dir->Size == 0) {
|
||||
return false;
|
||||
}
|
||||
IMAGE_RESOURCE_DIRECTORY *res_dir = (IMAGE_RESOURCE_DIRECTORY*)(dir->VirtualAddress + (ULONGLONG)modulePtr);
|
||||
if (!peconv::validate_ptr(modulePtr, module_size, res_dir, sizeof(IMAGE_DEBUG_DIRECTORY))) {
|
||||
return false;
|
||||
}
|
||||
return parse_resource_dir(modulePtr, module_size, nullptr, res_dir, res_dir, on_entry);
|
||||
}
|
||||
56
Etw Syscall/libpeconv-master/libpeconv/src/resource_util.cpp
Normal file
56
Etw Syscall/libpeconv-master/libpeconv/src/resource_util.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "peconv/resource_util.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
HMODULE peconv::get_current_module_handle()
|
||||
{
|
||||
HMODULE hMod = NULL;
|
||||
GetModuleHandleExW(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
reinterpret_cast<LPCWSTR>(&peconv::get_current_module_handle),
|
||||
&hMod);
|
||||
return hMod;
|
||||
}
|
||||
|
||||
peconv::ALIGNED_BUF peconv::load_resource_data(OUT size_t &out_size, int res_id, const LPSTR res_type, HMODULE hInstance)
|
||||
{
|
||||
if (hInstance == nullptr) {
|
||||
hInstance = GetModuleHandleA(NULL);
|
||||
}
|
||||
HRSRC res = FindResourceA(hInstance, MAKEINTRESOURCEA(res_id), res_type);
|
||||
if (!res) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Cannot find resource" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
HGLOBAL res_handle = LoadResource(hInstance, res);
|
||||
if (res_handle == nullptr) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Cannot get resource handle" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
BYTE* res_data = (BYTE*) LockResource(res_handle);
|
||||
size_t r_size = static_cast<size_t>(SizeofResource(hInstance, res));
|
||||
if (out_size != 0 && out_size <= r_size) {
|
||||
r_size = out_size;
|
||||
}
|
||||
|
||||
peconv::ALIGNED_BUF out_buf = peconv::alloc_aligned(r_size, PAGE_READWRITE);
|
||||
if (out_buf != nullptr) {
|
||||
memcpy(out_buf, res_data, r_size);
|
||||
out_size = r_size;
|
||||
} else {
|
||||
out_size = 0;
|
||||
}
|
||||
FreeResource(res_handle);
|
||||
return out_buf;
|
||||
}
|
||||
|
||||
void peconv::free_resource_data(peconv::ALIGNED_BUF buffer)
|
||||
{
|
||||
peconv::free_aligned(buffer);
|
||||
}
|
||||
163
Etw Syscall/libpeconv-master/libpeconv/src/util.cpp
Normal file
163
Etw Syscall/libpeconv-master/libpeconv/src/util.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "peconv/util.h"
|
||||
#include <iostream>
|
||||
|
||||
#define USE_OLD_BADPTR
|
||||
|
||||
namespace peconv {
|
||||
|
||||
HMODULE g_kernel32Hndl = nullptr;
|
||||
HMODULE g_ntdllHndl = nullptr;
|
||||
|
||||
HMODULE get_kernel32_hndl()
|
||||
{
|
||||
if (g_kernel32Hndl == nullptr) {
|
||||
g_kernel32Hndl = LoadLibraryA("kernel32.dll");
|
||||
}
|
||||
return g_kernel32Hndl;
|
||||
}
|
||||
|
||||
HMODULE get_ntdll_hndl()
|
||||
{
|
||||
if (g_ntdllHndl == nullptr) {
|
||||
g_ntdllHndl = LoadLibraryA("ntdll.dll");
|
||||
}
|
||||
return g_ntdllHndl;
|
||||
}
|
||||
};
|
||||
|
||||
DWORD ntdll_get_process_id(HANDLE hProcess)
|
||||
{
|
||||
#if !defined PROCESSINFOCLASS
|
||||
typedef LONG PROCESSINFOCLASS;
|
||||
#endif
|
||||
|
||||
NTSTATUS(WINAPI *_ZwQueryInformationProcess)(
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PROCESSINFOCLASS ProcessInformationClass,
|
||||
OUT PVOID ProcessInformation,
|
||||
IN ULONG ProcessInformationLength,
|
||||
OUT PULONG ReturnLength
|
||||
) = NULL;
|
||||
|
||||
HINSTANCE hNtDll = peconv::get_ntdll_hndl();
|
||||
if (!hNtDll) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
FARPROC procPtr = GetProcAddress(hNtDll, "ZwQueryInformationProcess");
|
||||
if (!procPtr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_ZwQueryInformationProcess = (NTSTATUS(WINAPI *)(
|
||||
HANDLE,
|
||||
PROCESSINFOCLASS,
|
||||
PVOID,
|
||||
ULONG,
|
||||
PULONG)
|
||||
) procPtr;
|
||||
|
||||
typedef struct _PROCESS_BASIC_INFORMATION {
|
||||
PVOID Reserved1;
|
||||
PVOID PebBaseAddress;
|
||||
PVOID Reserved2[2];
|
||||
ULONG_PTR UniqueProcessId;
|
||||
PVOID Reserved3;
|
||||
} PROCESS_BASIC_INFORMATION;
|
||||
|
||||
PROCESS_BASIC_INFORMATION pbi = { 0 };
|
||||
if (_ZwQueryInformationProcess(hProcess, 0, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL) == S_OK) {
|
||||
const DWORD pid = static_cast<DWORD>(pbi.UniqueProcessId);
|
||||
return pid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD peconv::get_process_id(HANDLE hProcess)
|
||||
{
|
||||
static DWORD(WINAPI *_GetProcessId)(IN HANDLE Process) = nullptr;
|
||||
|
||||
DWORD processID = 0;
|
||||
if (!_GetProcessId) {
|
||||
HMODULE kernelLib = peconv::get_kernel32_hndl();
|
||||
if (kernelLib) {
|
||||
FARPROC procPtr = GetProcAddress(kernelLib, "GetProcessId");
|
||||
if (procPtr) {
|
||||
_GetProcessId = (DWORD(WINAPI *) (IN HANDLE))procPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_GetProcessId) {
|
||||
processID = _GetProcessId(hProcess);
|
||||
}
|
||||
if (processID == 0) {
|
||||
//could not retrieve Pid using GetProcessId, try using NTDLL:
|
||||
processID = ntdll_get_process_id(hProcess);
|
||||
}
|
||||
return processID;
|
||||
}
|
||||
|
||||
bool peconv::is_padding(const BYTE *cave_ptr, size_t cave_size, const BYTE padding)
|
||||
{
|
||||
for (size_t i = 0; i < cave_size; i++) {
|
||||
if (cave_ptr[i] != padding) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool peconv::is_mem_accessible(LPCVOID areaStart, SIZE_T areaSize, DWORD dwAccessRights)
|
||||
{
|
||||
if (!areaSize) return false; // zero-sized areas are not allowed
|
||||
|
||||
const DWORD dwForbiddenArea = PAGE_GUARD | PAGE_NOACCESS;
|
||||
|
||||
MEMORY_BASIC_INFORMATION mbi = { 0 };
|
||||
const size_t mbiSize = sizeof(MEMORY_BASIC_INFORMATION);
|
||||
|
||||
SIZE_T sizeToCheck = areaSize;
|
||||
LPCVOID areaPtr = areaStart;
|
||||
|
||||
while (sizeToCheck > 0) {
|
||||
//reset area
|
||||
memset(&mbi, 0, mbiSize);
|
||||
|
||||
// query the next area
|
||||
if (VirtualQuery(areaPtr, &mbi, mbiSize) != mbiSize) {
|
||||
return false; // could not query the area, assume it is bad
|
||||
}
|
||||
// check the privileges
|
||||
bool isOk = (mbi.State & MEM_COMMIT) // memory allocated and
|
||||
&& !(mbi.Protect & dwForbiddenArea) // access to page allowed and
|
||||
&& (mbi.Protect & dwAccessRights); // the required rights
|
||||
if (!isOk) {
|
||||
return false; //invalid access
|
||||
}
|
||||
SIZE_T offset = (ULONG_PTR)areaPtr - (ULONG_PTR)mbi.BaseAddress;
|
||||
SIZE_T queriedSize = mbi.RegionSize - offset;
|
||||
if (queriedSize >= sizeToCheck) {
|
||||
return true; // it is fine
|
||||
}
|
||||
// move to the next region
|
||||
sizeToCheck -= queriedSize;
|
||||
areaPtr = LPCVOID((ULONG_PTR)areaPtr + queriedSize);
|
||||
}
|
||||
// by default assume it is inaccessible
|
||||
return false;
|
||||
}
|
||||
|
||||
bool peconv::is_bad_read_ptr(LPCVOID areaStart, SIZE_T areaSize)
|
||||
{
|
||||
#ifdef USE_OLD_BADPTR // classic IsBadReadPtr is much faster than the version using VirtualQuery
|
||||
return IsBadReadPtr(areaStart, areaSize);
|
||||
#else
|
||||
const DWORD dwReadRights = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
|
||||
bool isAccessible = peconv::is_mem_accessible(areaStart, areaSize, dwReadRights);
|
||||
if (isAccessible) {
|
||||
// the area has read access rights: not a bad read pointer
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
23
Etw Syscall/libpeconv-master/pe_unmapper/CMakeLists.txt
Normal file
23
Etw Syscall/libpeconv-master/pe_unmapper/CMakeLists.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
project (pe_unmapper)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
|
||||
message (STATUS "parser_dir='${PECONV_DIR}'")
|
||||
message (STATUS "parser_lib='${PECONV_LIB}'")
|
||||
|
||||
include_directories ( ${PECONV_DIR}/include )
|
||||
|
||||
set (srcs
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable ( ${PROJECT_NAME} ${srcs} )
|
||||
target_link_libraries ( ${PROJECT_NAME} ${PECONV_LIB} )
|
||||
add_dependencies( ${PROJECT_NAME} libpeconv)
|
||||
|
||||
if(PECONV_LIB_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
31
Etw Syscall/libpeconv-master/pe_unmapper/README.md
Normal file
31
Etw Syscall/libpeconv-master/pe_unmapper/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# pe_unmapper
|
||||
|
||||
Small tool to convert beteween the PE alignments (raw and virtual).
|
||||
|
||||
Allows for easy PE unmapping: useful in recovering executables dumped from the memory.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
Args:
|
||||
|
||||
Required:
|
||||
/in : Input file name
|
||||
|
||||
Optional:
|
||||
/base : Base address where the image was loaded: in hex
|
||||
/out : Output file name
|
||||
/mode : Choose the conversion mode:
|
||||
U: UNMAP (Virtual to Raw) [DEFAULT]
|
||||
M: MAP (Raw to Virtual)
|
||||
R: REALIGN (Virtual to Raw, where: Raw == Virtual)
|
||||
```
|
||||
Example:
|
||||
|
||||
```
|
||||
pe_unmapper.exe /in _02660000.mem /base 02660000 /out payload.dll
|
||||
```
|
||||
Compiled version available:
|
||||
+ [here](https://drive.google.com/uc?export=download&id=1hJMHFYXxcW1w14KFhlVZ3PbHuOc6pbN4)
|
||||
+ via [AppVeyor build server](https://ci.appveyor.com/project/hasherezade/libpeconv) (click on the build and choose the "Artifacts" tab)
|
||||
|
||||
189
Etw Syscall/libpeconv-master/pe_unmapper/main.cpp
Normal file
189
Etw Syscall/libpeconv-master/pe_unmapper/main.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <peconv.h>
|
||||
using namespace peconv;
|
||||
|
||||
#define VERSION "1.0"
|
||||
|
||||
#define PARAM_OUT_FILE "/out"
|
||||
#define PARAM_BASE "/base"
|
||||
#define PARAM_IN_FILE "/in"
|
||||
#define PARAM_MODE "/mode"
|
||||
|
||||
typedef enum {
|
||||
MODE_VIRTUAL_TO_RAW = 'U',
|
||||
MODE_RAW_TO_VIRTUAL = 'M',
|
||||
MODE_REALIGN = 'R',
|
||||
MODES_COUNT = 3
|
||||
} t_map_modes;
|
||||
|
||||
typedef struct {
|
||||
std::string in_file;
|
||||
std::string out_file;
|
||||
ULONGLONG load_base;
|
||||
t_map_modes mode;
|
||||
} t_unmapper_params;
|
||||
|
||||
void init_params(t_unmapper_params ¶ms)
|
||||
{
|
||||
params.in_file = "";
|
||||
params.out_file = "out.exe";
|
||||
params.load_base = 0;
|
||||
params.mode = MODE_VIRTUAL_TO_RAW;
|
||||
}
|
||||
|
||||
std::string mode_to_string(const t_map_modes mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case MODE_VIRTUAL_TO_RAW:
|
||||
return "UNMAP (Virtual to Raw)";
|
||||
case MODE_RAW_TO_VIRTUAL:
|
||||
return "MAP (Raw to Virtual)";
|
||||
case MODE_REALIGN:
|
||||
return "REALIGN (Virtual to Raw, where: Raw == Virtual)";
|
||||
}
|
||||
return "Undefined";
|
||||
}
|
||||
|
||||
t_map_modes parse_mode(char *arg)
|
||||
{
|
||||
if (!arg) return MODE_VIRTUAL_TO_RAW;
|
||||
char mode_val = toupper(arg[0]);
|
||||
return t_map_modes(mode_val);
|
||||
}
|
||||
|
||||
|
||||
bool remap_pe_file(t_unmapper_params ¶ms)
|
||||
{
|
||||
if (params.in_file.length() == 0 || params.out_file.length() == 0) return false;
|
||||
//Read input module:
|
||||
std::cout << "Input file: " << params.in_file << "\n";
|
||||
|
||||
size_t in_size = 0;
|
||||
BYTE* in_buf = peconv::read_from_file(params.in_file.c_str(), in_size);
|
||||
if (!in_buf) {
|
||||
std::cerr << "[-] Cannot load file: " << params.in_file << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
BYTE* out_buf = nullptr;
|
||||
size_t out_size = 0;
|
||||
std::cout << "[*] Mode: " << mode_to_string(params.mode) << "\n";
|
||||
switch (params.mode) {
|
||||
case MODE_VIRTUAL_TO_RAW:
|
||||
{
|
||||
ULONGLONG load_base = params.load_base;
|
||||
if (!load_base) {
|
||||
load_base = peconv::find_base_candidate(in_buf, in_size);
|
||||
std::cout << "[!] Load base not supplied! Using autosearch...\n";
|
||||
std::cout << "[*] Found possible relocation base: " << std::hex << load_base << "\n";
|
||||
}
|
||||
out_buf = peconv::pe_virtual_to_raw(in_buf, in_size, load_base, out_size, false);
|
||||
};
|
||||
break;
|
||||
case MODE_RAW_TO_VIRTUAL:
|
||||
{
|
||||
out_buf = peconv::load_pe_module(in_buf, in_size, out_size, false, false);
|
||||
if (out_buf) {
|
||||
ULONGLONG base = peconv::get_image_base(out_buf);
|
||||
if (!relocate_module(out_buf, out_size, (ULONGLONG)base)) {
|
||||
std::cout << "Could not relocate the module!\n";
|
||||
}
|
||||
if (params.load_base) {
|
||||
if (relocate_module(out_buf, out_size, (ULONGLONG)params.load_base)) {
|
||||
peconv::update_image_base(out_buf, params.load_base);
|
||||
std::cout << "[*] Changed image base to: " << std::hex << params.load_base << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
break;
|
||||
case MODE_REALIGN:
|
||||
{
|
||||
if (peconv::is_pe_raw(in_buf, in_size)) {
|
||||
std::cout << "[!] First you need to convert your PE to Virtual format\n";
|
||||
}
|
||||
else {
|
||||
out_buf = peconv::pe_realign_raw_to_virtual(in_buf, in_size, params.load_base, out_size);
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
if (!out_buf) {
|
||||
std::cerr << "Failed to convert!\n";
|
||||
peconv::free_pe_buffer(in_buf, in_size);
|
||||
return false;
|
||||
}
|
||||
// Write output
|
||||
bool isOk = peconv::dump_to_file(params.out_file.c_str(), out_buf, out_size);
|
||||
if (!isOk) {
|
||||
std::cerr << "Failed to save file: " << params.out_file << "\n";
|
||||
}
|
||||
peconv::free_pe_buffer(in_buf, in_size);
|
||||
peconv::free_pe_buffer(out_buf, out_size);
|
||||
|
||||
return isOk;
|
||||
}
|
||||
|
||||
void print_help()
|
||||
{
|
||||
std::cout << "Required: \n";
|
||||
|
||||
std::cout << PARAM_IN_FILE;
|
||||
std::cout << "\t: Input file name\n";
|
||||
|
||||
std::cout << "\nOptional: \n";
|
||||
|
||||
std::cout << PARAM_BASE;
|
||||
std::cout << "\t: Base address where the image was loaded: in hex\n";
|
||||
|
||||
std::cout << PARAM_OUT_FILE;
|
||||
std::cout << "\t: Output file name\n";
|
||||
|
||||
std::cout << PARAM_MODE;
|
||||
std::cout << "\t: Choose the conversion mode:\n";
|
||||
std::cout << "\t " << (char) MODE_VIRTUAL_TO_RAW << ": " << mode_to_string(MODE_VIRTUAL_TO_RAW) << " [DEFAULT]\n";
|
||||
std::cout << "\t " << (char) MODE_RAW_TO_VIRTUAL << ": " << mode_to_string(MODE_RAW_TO_VIRTUAL) << "\n";
|
||||
std::cout << "\t " << (char) MODE_REALIGN << ": " << mode_to_string(MODE_REALIGN) << "\n";
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
t_unmapper_params params;
|
||||
init_params(params);
|
||||
|
||||
if (argc < 3) {
|
||||
std::cout << "PE Unmapper v" << VERSION << "\n"
|
||||
<< "URL: https://github.com/hasherezade/libpeconv\n";
|
||||
std::cout << "Args:\n\n";
|
||||
print_help();
|
||||
std::cout << "---" << std::endl;
|
||||
system("pause");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], PARAM_MODE) && ((i + 1) < argc) && argv[i + 1] != NULL) {
|
||||
params.mode = parse_mode(argv[i + 1]);
|
||||
}
|
||||
else if (!strcmp(argv[i], PARAM_OUT_FILE) && (i + 1) < argc) {
|
||||
params.out_file = argv[i + 1];
|
||||
}
|
||||
else if (!strcmp(argv[i], PARAM_IN_FILE) && (i + 1) < argc) {
|
||||
params.in_file = argv[i + 1];
|
||||
}
|
||||
else if (!strcmp(argv[i], PARAM_BASE) && (i + 1) < argc) {
|
||||
ULONGLONG loadBase = 0;
|
||||
if (sscanf(argv[i + 1], "%llX", &loadBase) == 0) {
|
||||
sscanf(argv[i + 1], "%#llX", &loadBase);
|
||||
}
|
||||
params.load_base = loadBase;
|
||||
}
|
||||
}
|
||||
|
||||
if (remap_pe_file(params)) {
|
||||
std::cout << "Saved output to: " << params.out_file << std::endl;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
28
Etw Syscall/libpeconv-master/run_pe/CMakeLists.txt
Normal file
28
Etw Syscall/libpeconv-master/run_pe/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
project (run_pe)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
|
||||
message (STATUS "parser_dir='${PECONV_DIR}'")
|
||||
message (STATUS "parser_lib='${PECONV_LIB}'")
|
||||
|
||||
include_directories ( ${PECONV_DIR}/include )
|
||||
|
||||
set (srcs
|
||||
main.cpp
|
||||
run_pe.cpp
|
||||
)
|
||||
|
||||
set (hdrs
|
||||
run_pe.h
|
||||
)
|
||||
|
||||
add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs} )
|
||||
target_link_libraries ( ${PROJECT_NAME} ${PECONV_LIB} )
|
||||
add_dependencies( ${PROJECT_NAME} libpeconv)
|
||||
|
||||
if(PECONV_LIB_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
30
Etw Syscall/libpeconv-master/run_pe/README.md
Normal file
30
Etw Syscall/libpeconv-master/run_pe/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Demo: RunPE
|
||||
|
||||
This is a demo project using _libpeconv_.<br/>
|
||||
RunPE (aka Process Hollowing) is a well known technique allowing to injecting a new PE into a remote processes, imprersonating this process.
|
||||
|
||||

|
||||
|
||||
The given implementation works for PE 32bit as well as 64bit.<br/>
|
||||
|
||||
Supported injections:
|
||||
-
|
||||
If the loader was built as 32 bit:
|
||||
```
|
||||
32 bit payload -> 32 bit target
|
||||
```
|
||||
If the loader was built as 64 bit:
|
||||
```
|
||||
64 bit payload -> 64 bit target
|
||||
32 bit payload -> 32 bit target
|
||||
```
|
||||
|
||||
How to use the app:
|
||||
-
|
||||
Supply 2 commandline arguments:
|
||||
|
||||
```
|
||||
[payload_path] [target_path]
|
||||
```
|
||||
|
||||
Payload is the PE to be executed impersonating the Target.
|
||||
36
Etw Syscall/libpeconv-master/run_pe/main.cpp
Normal file
36
Etw Syscall/libpeconv-master/run_pe/main.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include <peconv.h>
|
||||
|
||||
#include "run_pe.h"
|
||||
|
||||
const char* version = "0.1.7";
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char* payload_path = NULL;
|
||||
char *target_path = NULL;
|
||||
|
||||
if (argc < 3) {
|
||||
std::cout << "[ run_pe v" << version << " ]\n"
|
||||
<< "Args: <payload_path> <target_path>\n";
|
||||
system("pause");
|
||||
return -1;
|
||||
}
|
||||
|
||||
payload_path = argv[1];
|
||||
target_path = argv[2];
|
||||
|
||||
std::string cmdLine = GetCommandLineA();
|
||||
size_t found = cmdLine.find(target_path);
|
||||
|
||||
// cut out the parameters that are dedicated to the run_pe app only
|
||||
std::string trimmedCmdLine = cmdLine.substr(found, cmdLine.length());
|
||||
|
||||
std::cout << "Payload: " << payload_path << "\n";
|
||||
std::cout << "Target: " << target_path << "\n";
|
||||
|
||||
run_pe(payload_path, target_path, trimmedCmdLine.c_str());
|
||||
|
||||
system("pause");
|
||||
return 0;
|
||||
}
|
||||
318
Etw Syscall/libpeconv-master/run_pe/run_pe.cpp
Normal file
318
Etw Syscall/libpeconv-master/run_pe/run_pe.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
#include "run_pe.h"
|
||||
|
||||
#include <peconv.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace peconv;
|
||||
|
||||
bool create_suspended_process(IN const char* path, IN const char* cmdLine, OUT PROCESS_INFORMATION &pi)
|
||||
{
|
||||
STARTUPINFO si;
|
||||
memset(&si, 0, sizeof(STARTUPINFO));
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
|
||||
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
if (!CreateProcessA(
|
||||
path,
|
||||
(LPSTR)cmdLine,
|
||||
NULL, //lpProcessAttributes
|
||||
NULL, //lpThreadAttributes
|
||||
FALSE, //bInheritHandles
|
||||
CREATE_SUSPENDED, //dwCreationFlags
|
||||
NULL, //lpEnvironment
|
||||
NULL, //lpCurrentDirectory
|
||||
&si, //lpStartupInfo
|
||||
&pi //lpProcessInformation
|
||||
))
|
||||
{
|
||||
std::cerr << "[ERROR] CreateProcess failed, Error = " << std::hex << GetLastError() << "\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool terminate_process(DWORD pid)
|
||||
{
|
||||
bool is_killed = false;
|
||||
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||
if (!hProcess) {
|
||||
return false;
|
||||
}
|
||||
if (TerminateProcess(hProcess, 0)) {
|
||||
is_killed = true;
|
||||
}
|
||||
else {
|
||||
std::cerr << "[ERROR] Could not terminate the process. PID = " << std::dec << pid << std::endl;
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
return is_killed;
|
||||
}
|
||||
|
||||
bool read_remote_mem(HANDLE hProcess, ULONGLONG remote_addr, OUT void* buffer, const size_t buffer_size)
|
||||
{
|
||||
memset(buffer, 0, buffer_size);
|
||||
if (!ReadProcessMemory(hProcess, LPVOID(remote_addr), buffer, buffer_size, NULL)) {
|
||||
std::cerr << "[ERROR] Cannot read from the remote memory!\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL update_remote_entry_point(PROCESS_INFORMATION &pi, ULONGLONG entry_point_va, bool is32bit)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("Writing new EP: %x\n", entry_point_va);
|
||||
#endif
|
||||
#if defined(_WIN64)
|
||||
if (is32bit) {
|
||||
// The target is a 32 bit executable while the loader is 64bit,
|
||||
// so, in order to access the target we must use Wow64 versions of the functions:
|
||||
|
||||
// 1. Get initial context of the target:
|
||||
WOW64_CONTEXT context = { 0 };
|
||||
memset(&context, 0, sizeof(WOW64_CONTEXT));
|
||||
context.ContextFlags = CONTEXT_INTEGER;
|
||||
if (!Wow64GetThreadContext(pi.hThread, &context)) {
|
||||
return FALSE;
|
||||
}
|
||||
// 2. Set the new Entry Point in the context:
|
||||
context.Eax = static_cast<DWORD>(entry_point_va);
|
||||
|
||||
// 3. Set the changed context into the target:
|
||||
return Wow64SetThreadContext(pi.hThread, &context);
|
||||
}
|
||||
#endif
|
||||
// 1. Get initial context of the target:
|
||||
CONTEXT context = { 0 };
|
||||
memset(&context, 0, sizeof(CONTEXT));
|
||||
context.ContextFlags = CONTEXT_INTEGER;
|
||||
if (!GetThreadContext(pi.hThread, &context)) {
|
||||
return FALSE;
|
||||
}
|
||||
// 2. Set the new Entry Point in the context:
|
||||
#if defined(_WIN64)
|
||||
context.Rcx = entry_point_va;
|
||||
#else
|
||||
context.Eax = static_cast<DWORD>(entry_point_va);
|
||||
#endif
|
||||
// 3. Set the changed context into the target:
|
||||
return SetThreadContext(pi.hThread, &context);
|
||||
}
|
||||
|
||||
ULONGLONG get_remote_peb_addr(PROCESS_INFORMATION &pi, bool is32bit)
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
if (is32bit) {
|
||||
//get initial context of the target:
|
||||
WOW64_CONTEXT context;
|
||||
memset(&context, 0, sizeof(WOW64_CONTEXT));
|
||||
context.ContextFlags = CONTEXT_INTEGER;
|
||||
if (!Wow64GetThreadContext(pi.hThread, &context)) {
|
||||
printf("Wow64 cannot get context!\n");
|
||||
return 0;
|
||||
}
|
||||
//get remote PEB from the context
|
||||
return static_cast<ULONGLONG>(context.Ebx);
|
||||
}
|
||||
#endif
|
||||
ULONGLONG PEB_addr = 0;
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(CONTEXT));
|
||||
context.ContextFlags = CONTEXT_INTEGER;
|
||||
if (!GetThreadContext(pi.hThread, &context)) {
|
||||
return 0;
|
||||
}
|
||||
#if defined(_WIN64)
|
||||
PEB_addr = context.Rdx;
|
||||
#else
|
||||
PEB_addr = context.Ebx;
|
||||
#endif
|
||||
return PEB_addr;
|
||||
}
|
||||
|
||||
inline ULONGLONG get_img_base_peb_offset(bool is32bit)
|
||||
{
|
||||
/*
|
||||
We calculate this offset in relation to PEB,
|
||||
that is defined in the following way
|
||||
(source "ntddk.h"):
|
||||
|
||||
typedef struct _PEB
|
||||
{
|
||||
BOOLEAN InheritedAddressSpace; // size: 1
|
||||
BOOLEAN ReadImageFileExecOptions; // size : 1
|
||||
BOOLEAN BeingDebugged; // size : 1
|
||||
BOOLEAN SpareBool; // size : 1
|
||||
// on 64bit here there is a padding to the sizeof ULONGLONG (DWORD64)
|
||||
HANDLE Mutant; // this field have DWORD size on 32bit, and ULONGLONG (DWORD64) size on 64bit
|
||||
|
||||
PVOID ImageBaseAddress;
|
||||
[...]
|
||||
*/
|
||||
ULONGLONG img_base_offset = is32bit ?
|
||||
sizeof(DWORD) * 2
|
||||
: sizeof(ULONGLONG) * 2;
|
||||
|
||||
return img_base_offset;
|
||||
}
|
||||
|
||||
bool redirect_to_payload(BYTE* loaded_pe, PVOID load_base, PROCESS_INFORMATION &pi, bool is32bit)
|
||||
{
|
||||
//1. Calculate VA of the payload's EntryPoint
|
||||
DWORD ep = get_entry_point_rva(loaded_pe);
|
||||
ULONGLONG ep_va = (ULONGLONG)load_base + ep;
|
||||
|
||||
//2. Write the new Entry Point into context of the remote process:
|
||||
if (update_remote_entry_point(pi, ep_va, is32bit) == FALSE) {
|
||||
std::cerr << "Cannot update remote EP!\n";
|
||||
return false;
|
||||
}
|
||||
//3. Get access to the remote PEB:
|
||||
ULONGLONG remote_peb_addr = get_remote_peb_addr(pi, is32bit);
|
||||
if (!remote_peb_addr) {
|
||||
std::cerr << "Failed getting remote PEB address!\n";
|
||||
return false;
|
||||
}
|
||||
// get the offset to the PEB's field where the ImageBase should be saved (depends on architecture):
|
||||
LPVOID remote_img_base = (LPVOID)(remote_peb_addr + get_img_base_peb_offset(is32bit));
|
||||
//calculate size of the field (depends on architecture):
|
||||
const size_t img_base_size = is32bit ? sizeof(DWORD) : sizeof(ULONGLONG);
|
||||
|
||||
SIZE_T written = 0;
|
||||
//4. Write the payload's ImageBase into remote process' PEB:
|
||||
if (!WriteProcessMemory(pi.hProcess, remote_img_base,
|
||||
&load_base, img_base_size,
|
||||
&written))
|
||||
{
|
||||
std::cerr << "Cannot update ImageBaseAddress!\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _run_pe(BYTE *loaded_pe, size_t payloadImageSize, PROCESS_INFORMATION &pi, bool is32bit)
|
||||
{
|
||||
if (loaded_pe == NULL) return false;
|
||||
|
||||
//1. Allocate memory for the payload in the remote process:
|
||||
LPVOID remoteBase = VirtualAllocEx(pi.hProcess, NULL, payloadImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (remoteBase == NULL) {
|
||||
std::cerr << "Could not allocate memory in the remote process\n";
|
||||
return false;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("Allocated remote ImageBase: %p size: %lx\n", remoteBase, static_cast<ULONG>(payloadImageSize));
|
||||
#endif
|
||||
//2. Relocate the payload (local copy) to the Remote Base:
|
||||
if (!relocate_module(loaded_pe, payloadImageSize, (ULONGLONG) remoteBase)) {
|
||||
std::cout << "Could not relocate the module!\n";
|
||||
return false;
|
||||
}
|
||||
//3. Update the image base of the payload (local copy) to the Remote Base:
|
||||
update_image_base(loaded_pe, (ULONGLONG) remoteBase);
|
||||
|
||||
//4. Write the payload to the remote process, at the Remote Base:
|
||||
SIZE_T written = 0;
|
||||
if (!WriteProcessMemory(pi.hProcess, remoteBase, loaded_pe, payloadImageSize, &written)) {
|
||||
std::cout << "Writing to the remote process failed!\n";
|
||||
return false;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("Loaded at: %p\n", loaded_pe);
|
||||
#endif
|
||||
//5. Redirect the remote structures to the injected payload (EntryPoint and ImageBase must be changed):
|
||||
if (!redirect_to_payload(loaded_pe, remoteBase, pi, is32bit)) {
|
||||
std::cerr << "Redirecting failed!\n";
|
||||
return false;
|
||||
}
|
||||
//6. Resume the thread and let the payload run:
|
||||
ResumeThread(pi.hThread);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_target_compatibile(BYTE *payload_buf, size_t payload_size, const char *targetPath)
|
||||
{
|
||||
if (!payload_buf) {
|
||||
return false;
|
||||
}
|
||||
const WORD payload_subs = peconv::get_subsystem(payload_buf);
|
||||
|
||||
size_t target_size = 0;
|
||||
BYTE* target_pe = load_pe_module(targetPath, target_size, false, false);
|
||||
if (!target_pe) {
|
||||
return false;
|
||||
}
|
||||
const WORD target_subs = peconv::get_subsystem(target_pe);
|
||||
const bool is64bit_target = peconv::is64bit(target_pe);
|
||||
peconv::free_pe_buffer(target_pe); target_pe = NULL; target_size = 0;
|
||||
|
||||
if (is64bit_target != peconv::is64bit(payload_buf)) {
|
||||
std::cerr << "Incompatibile target bitness!\n";
|
||||
return false;
|
||||
}
|
||||
if (payload_subs != IMAGE_SUBSYSTEM_WINDOWS_GUI //only a payload with GUI subsystem can be run by both GUI and CLI
|
||||
&& target_subs != payload_subs)
|
||||
{
|
||||
std::cerr << "Incompatibile target subsystem!\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run_pe(IN const char *payloadPath, IN const char *targetPath, IN const char *cmdLine)
|
||||
{
|
||||
//1. Load the payload:
|
||||
size_t payloadImageSize = 0;
|
||||
// Load the current executable from the file with the help of libpeconv:
|
||||
BYTE* loaded_pe = peconv::load_pe_module(payloadPath, payloadImageSize, false, false);
|
||||
if (!loaded_pe) {
|
||||
std::cerr << "Loading failed!\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the payload's architecture and check if it is compatibile with the loader:
|
||||
const WORD payload_arch = get_nt_hdr_architecture(loaded_pe);
|
||||
if (payload_arch != IMAGE_NT_OPTIONAL_HDR32_MAGIC && payload_arch != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
std::cerr << "Not supported paylad architecture!\n";
|
||||
return false;
|
||||
}
|
||||
const bool is32bit_payload = !peconv::is64bit(loaded_pe);
|
||||
#ifndef _WIN64
|
||||
if (!is32bit_payload) {
|
||||
std::cerr << "Incompatibile payload architecture!\n"
|
||||
<< "Only 32 bit payloads can be injected from 32bit loader!\n";
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// 2. Prepare the taget
|
||||
if (targetPath == NULL) {
|
||||
std::cerr << "No target supplied!\n";
|
||||
return false;
|
||||
}
|
||||
if (!is_target_compatibile(loaded_pe, payloadImageSize, targetPath)) {
|
||||
free_pe_buffer(loaded_pe, payloadImageSize);
|
||||
return false;
|
||||
}
|
||||
// Create the target process (suspended):
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
bool is_created = create_suspended_process(targetPath, cmdLine, pi);
|
||||
if (!is_created) {
|
||||
std::cerr << "Creating target process failed!\n";
|
||||
free_pe_buffer(loaded_pe, payloadImageSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
//3. Perform the actual RunPE:
|
||||
bool isOk = _run_pe(loaded_pe, payloadImageSize, pi, is32bit_payload);
|
||||
|
||||
//4. Cleanup:
|
||||
if (!isOk) { //if injection failed, kill the process
|
||||
terminate_process(pi.dwProcessId);
|
||||
}
|
||||
free_pe_buffer(loaded_pe, payloadImageSize);
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
//---
|
||||
return isOk;
|
||||
}
|
||||
8
Etw Syscall/libpeconv-master/run_pe/run_pe.h
Normal file
8
Etw Syscall/libpeconv-master/run_pe/run_pe.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/**
|
||||
Perform the RunPE injection of the payload into the target.
|
||||
*/
|
||||
bool run_pe(IN const char *payloadPath, IN const char *targetPath, IN const char* cmdLine);
|
||||
154
Etw Syscall/libpeconv-master/tests/CMakeLists.txt
Normal file
154
Etw Syscall/libpeconv-master/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,154 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
project (tests)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
|
||||
message (STATUS "parser_dir='${PECONV_DIR}'")
|
||||
message (STATUS "parser_lib='${PECONV_LIB}'")
|
||||
|
||||
include_directories ( ${PECONV_DIR}/include )
|
||||
|
||||
set (srcs
|
||||
main.cpp
|
||||
test_loading.cpp
|
||||
test_loading_imps.cpp
|
||||
test_crackme_f4_3.cpp
|
||||
test_hooking_imps.cpp
|
||||
test_crackme_f4_6.cpp
|
||||
test_load_ntdll.cpp
|
||||
test_replacing_func.cpp
|
||||
test_delayed_imps.cpp
|
||||
test_imp_list.cpp
|
||||
test_hooking_local.cpp
|
||||
test_peb_lookup.cpp
|
||||
test_imports_mix.cpp
|
||||
test_found_base.cpp
|
||||
test_fix_dotnet.cpp
|
||||
test_format_detect.cpp
|
||||
)
|
||||
|
||||
set (hdrs
|
||||
test_loading.h
|
||||
test_loading_imps.h
|
||||
test_crackme_f4_3.h
|
||||
test_hooking_imps.h
|
||||
test_crackme_f4_6.h
|
||||
test_load_ntdll.h
|
||||
test_replacing_func.h
|
||||
test_delayed_imps.h
|
||||
test_imp_list.h
|
||||
test_hooking_local.h
|
||||
test_peb_lookup.h
|
||||
test_imports_mix.h
|
||||
test_found_base.h
|
||||
test_fix_dotnet.h
|
||||
test_format_detect.h
|
||||
resource.h
|
||||
shellcodes.h
|
||||
shellc32.h
|
||||
shellc64.h
|
||||
)
|
||||
|
||||
set (rsrc
|
||||
resource.rc
|
||||
)
|
||||
|
||||
add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs} ${rsrc} )
|
||||
target_link_libraries ( ${PROJECT_NAME} ${PECONV_LIB} )
|
||||
add_dependencies( ${PROJECT_NAME} libpeconv test_case1 test_case3 )
|
||||
|
||||
#add the application that will be used for tests:
|
||||
add_subdirectory ( test_case1 )
|
||||
add_subdirectory ( test_case3 )
|
||||
add_subdirectory ( test_case4 )
|
||||
add_subdirectory ( test_case5 )
|
||||
|
||||
#install
|
||||
INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} )
|
||||
|
||||
enable_testing()
|
||||
|
||||
# 0) does the application run
|
||||
add_test (TestRuns ${CMAKE_INSTALL_PREFIX}/tests)
|
||||
|
||||
# 1) compare relocations applied by the loader with relocations applied by Windows Loader
|
||||
add_test (TestLoadSelf ${CMAKE_INSTALL_PREFIX}/tests 1)
|
||||
set_tests_properties (TestLoadSelf PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
|
||||
# 2) load the image of the current process from the disk and deploy it:
|
||||
add_test (TestDeploySelf ${CMAKE_INSTALL_PREFIX}/tests 2)
|
||||
set_tests_properties (TestDeploySelf PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
|
||||
#only for 32bit:
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
# 3) Deploys a brutforcer for FlareOn4 Crackme 3
|
||||
add_test (TestCrackmeF4_3 ${CMAKE_INSTALL_PREFIX}/tests 3)
|
||||
set_tests_properties (TestCrackmeF4_3 PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
endif()
|
||||
|
||||
# 4) load the image of the current process from the disk and deploy it. Imports are resolved by exports lookup (custom recolver).
|
||||
add_test (TestDeploySelfExpResolver ${CMAKE_INSTALL_PREFIX}/tests 4)
|
||||
set_tests_properties (TestDeploySelfExpResolver PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
set_tests_properties (TestDeploySelfExpResolver PROPERTIES FAIL_REGULAR_EXPRESSION "Loaded proc is not matching the default one!")
|
||||
|
||||
# 5) test hooking a test_case1 application
|
||||
add_test (TestHookMessageBox ${CMAKE_INSTALL_PREFIX}/tests 5 ${CMAKE_INSTALL_PREFIX}/test_case1.exe )
|
||||
set_tests_properties (TestHookMessageBox PROPERTIES PASS_REGULAR_EXPRESSION "Hooking test passed")
|
||||
|
||||
#only for 64bit:
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# 6) Solve FlareOn2017 Challenge6
|
||||
add_test (TestCrackmeF4_6 ${CMAKE_INSTALL_PREFIX}/tests 6 ${CMAKE_INSTALL_PREFIX}/payload.dll )
|
||||
set_tests_properties (TestCrackmeF4_6 PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
endif()
|
||||
|
||||
# 8) Test replacing and redirecting functions
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
add_test (TestReplaceFunc64 ${CMAKE_INSTALL_PREFIX}/tests 8 ${CMAKE_INSTALL_PREFIX}/test_case3_64.exe )
|
||||
set_tests_properties (TestReplaceFunc64 PROPERTIES PASS_REGULAR_EXPRESSION "Passed!")
|
||||
set_tests_properties (TestReplaceFunc64 PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
else()
|
||||
add_test (TestReplaceFunc32 tests 8 ${CMAKE_INSTALL_PREFIX}/test_case3_32.exe )
|
||||
set_tests_properties (TestReplaceFunc32 PROPERTIES PASS_REGULAR_EXPRESSION "Passed!")
|
||||
set_tests_properties (TestReplaceFunc32 PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
endif()
|
||||
|
||||
# 9) test replacing Delay-Load Imports
|
||||
add_test (TestDelayedImps ${CMAKE_INSTALL_PREFIX}/tests 9 ${CMAKE_INSTALL_PREFIX}/test_case4.exe )
|
||||
set_tests_properties (TestDelayedImps PROPERTIES PASS_REGULAR_EXPRESSION "Hooking test passed")
|
||||
set_tests_properties (TestDelayedImps PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
|
||||
# 11) test redirecting local functions (and undoing the redirection)
|
||||
add_test (TestLocalRedirect tests 11 )
|
||||
set_tests_properties (TestLocalRedirect PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
set_tests_properties (TestLocalRedirect PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
|
||||
# 12) test PEB lookup
|
||||
add_test (TestPEBLookup ${CMAKE_INSTALL_PREFIX}/tests 12 )
|
||||
set_tests_properties (TestPEBLookup PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
set_tests_properties (TestPEBLookup PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
|
||||
# 13) test mixed imports
|
||||
add_test (TestMixImp ${CMAKE_INSTALL_PREFIX}/tests 13 ${CMAKE_INSTALL_PREFIX}/test_case5_exe.exe )
|
||||
set_tests_properties (TestMixImp PROPERTIES PASS_REGULAR_EXPRESSION "Test Case 5 finished, checks: a0caa919")
|
||||
set_tests_properties (TestMixImp PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
|
||||
# 14) test finding base
|
||||
add_test (TestFindBase ${CMAKE_INSTALL_PREFIX}/tests 14 ${CMAKE_INSTALL_PREFIX}/test_case5_exe.exe )
|
||||
set_tests_properties (TestFindBase PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
set_tests_properties (TestFindBase PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
|
||||
# 15) test finding jumps
|
||||
add_test (TestFindJumpToDotNet ${CMAKE_INSTALL_PREFIX}/tests 15 )
|
||||
set_tests_properties (TestFindJumpToDotNet PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
set_tests_properties (TestFindJumpToDotNet PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
|
||||
# 16.1) test detect virtual/raw: 32
|
||||
add_test (TestDetectMode32 tests 16 ${CMAKE_INSTALL_PREFIX}/test_case3_32.exe )
|
||||
set_tests_properties (TestDetectMode32 PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
set_tests_properties (TestDetectMode32 PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
|
||||
# 16.2) test detect virtual/raw: 64
|
||||
add_test (TestDetectMode64 tests 16 ${CMAKE_INSTALL_PREFIX}/test_case3_64.exe )
|
||||
set_tests_properties (TestDetectMode64 PROPERTIES PASS_REGULAR_EXPRESSION "Test passed")
|
||||
set_tests_properties (TestDetectMode64 PROPERTIES FAIL_REGULAR_EXPRESSION "Failed")
|
||||
BIN
Etw Syscall/libpeconv-master/tests/greek_to_me.bin
Normal file
BIN
Etw Syscall/libpeconv-master/tests/greek_to_me.bin
Normal file
Binary file not shown.
77
Etw Syscall/libpeconv-master/tests/main.cpp
Normal file
77
Etw Syscall/libpeconv-master/tests/main.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "test_loading.h"
|
||||
#include "test_loading_imps.h"
|
||||
#include "test_crackme_f4_3.h"
|
||||
#include "test_hooking_imps.h"
|
||||
#include "test_crackme_f4_6.h"
|
||||
#include "test_load_ntdll.h"
|
||||
#include "test_replacing_func.h"
|
||||
#include "test_delayed_imps.h"
|
||||
#include "test_imp_list.h"
|
||||
#include "test_hooking_local.h"
|
||||
#include "test_peb_lookup.h"
|
||||
#include "test_imports_mix.h"
|
||||
#include "test_found_base.h"
|
||||
#include "test_fix_dotnet.h"
|
||||
#include "test_format_detect.h"
|
||||
|
||||
int make_test(int test_id, char *test_arg)
|
||||
{
|
||||
switch (test_id) {
|
||||
case 1: return tests::load_self();
|
||||
case 2: return tests::deploy_self();
|
||||
case 3: return tests::brutforce_crackme_f4_3();
|
||||
case 4:
|
||||
{
|
||||
peconv::export_based_resolver *exp_res = new peconv::export_based_resolver();
|
||||
int res = tests::deploy_self_ex((peconv::t_function_resolver*)exp_res);
|
||||
delete exp_res;
|
||||
return res;
|
||||
}
|
||||
case 5: return tests::hook_testcase(test_arg);
|
||||
case 6: return tests::decode_crackme_f4_6(test_arg);
|
||||
case 7: return tests::test_ntdll(NULL); //manual test
|
||||
case 8: return tests::replace_func_testcase(test_arg);
|
||||
case 9: return tests::replace_delayed_imps(test_arg);
|
||||
case 10: return tests::imp_list(test_arg); //manual test
|
||||
case 11: return tests::hook_self_local();
|
||||
case 12: return tests::check_modules();
|
||||
case 13: return tests::imports_mix(test_arg);
|
||||
case 14: return tests::load_and_check_base(test_arg);
|
||||
case 15: return tests::check_finding_jumps();
|
||||
case 16: return tests::check_pe_format(test_arg);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void print_banner()
|
||||
{
|
||||
printf("---------------\n");
|
||||
printf("TESTS DEPLOYED!\n");
|
||||
printf("---------------\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
print_banner();
|
||||
if (argc < 2) {
|
||||
printf("Supply the test id!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_id = atoi(argv[1]);
|
||||
printf("Test ID: %d\n", test_id);
|
||||
|
||||
char *test_arg = NULL;
|
||||
if (argc > 2) {
|
||||
test_arg = argv[2];
|
||||
}
|
||||
int res = make_test(test_id, test_arg);
|
||||
|
||||
if (res == 0) {
|
||||
printf("[+] Test passed!\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
3
Etw Syscall/libpeconv-master/tests/resource.h
Normal file
3
Etw Syscall/libpeconv-master/tests/resource.h
Normal file
@@ -0,0 +1,3 @@
|
||||
// resource.h
|
||||
|
||||
#define CRACKME_F4_3_32 101
|
||||
56
Etw Syscall/libpeconv-master/tests/resource.rc
Normal file
56
Etw Syscall/libpeconv-master/tests/resource.rc
Normal file
@@ -0,0 +1,56 @@
|
||||
// resource.rc :
|
||||
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "windows.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_PLK)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""windows.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RCDATA
|
||||
//
|
||||
|
||||
CRACKME_F4_3_32 RCDATA "greek_to_me.bin"
|
||||
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
94
Etw Syscall/libpeconv-master/tests/shellc32.h
Normal file
94
Etw Syscall/libpeconv-master/tests/shellc32.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
unsigned char messageBox32bit_sc[] = {
|
||||
0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x1C, 0xE8, 0x1C, 0x00, 0x00, 0x00, 0x6B,
|
||||
0x00, 0x65, 0x00, 0x72, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x33,
|
||||
0x00, 0x32, 0x00, 0x2E, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xE8, 0x60, 0x02, 0x00, 0x00, 0x83, 0xC4, 0x04, 0x89,
|
||||
0x45, 0xFC, 0x83, 0x7D, 0xFC, 0x00, 0x75, 0x0A, 0xB8, 0x01, 0x00, 0x00,
|
||||
0x00, 0xE9, 0xEC, 0x00, 0x00, 0x00, 0xE8, 0x10, 0x00, 0x00, 0x00, 0x4C,
|
||||
0x6F, 0x61, 0x64, 0x4C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x41, 0x00,
|
||||
0x00, 0x00, 0x00, 0x8B, 0x45, 0xFC, 0x50, 0xE8, 0xD2, 0x00, 0x00, 0x00,
|
||||
0x83, 0xC4, 0x08, 0x89, 0x45, 0xF8, 0x83, 0x7D, 0xF8, 0x00, 0x75, 0x0A,
|
||||
0xB8, 0x02, 0x00, 0x00, 0x00, 0xE9, 0xB8, 0x00, 0x00, 0x00, 0xE8, 0x10,
|
||||
0x00, 0x00, 0x00, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6F, 0x63, 0x41, 0x64,
|
||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x00, 0x00, 0x8B, 0x4D, 0xFC, 0x51, 0xE8,
|
||||
0x9E, 0x00, 0x00, 0x00, 0x83, 0xC4, 0x08, 0x89, 0x45, 0xF4, 0x83, 0x7D,
|
||||
0xF4, 0x00, 0x75, 0x0A, 0xB8, 0x03, 0x00, 0x00, 0x00, 0xE9, 0x84, 0x00,
|
||||
0x00, 0x00, 0x8B, 0x55, 0xF8, 0x89, 0x55, 0xEC, 0x8B, 0x45, 0xF4, 0x89,
|
||||
0x45, 0xE4, 0xE8, 0x0C, 0x00, 0x00, 0x00, 0x75, 0x73, 0x65, 0x72, 0x33,
|
||||
0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x00, 0xFF, 0x55, 0xEC, 0x89, 0x45,
|
||||
0xE8, 0xE8, 0x0C, 0x00, 0x00, 0x00, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x42, 0x6F, 0x78, 0x57, 0x00, 0x8B, 0x4D, 0xE8, 0x51, 0xFF, 0x55,
|
||||
0xE4, 0x89, 0x45, 0xF0, 0x83, 0x7D, 0xF0, 0x00, 0x75, 0x07, 0xB8, 0x04,
|
||||
0x00, 0x00, 0x00, 0xEB, 0x39, 0x6A, 0x00, 0xE8, 0x0C, 0x00, 0x00, 0x00,
|
||||
0x44, 0x00, 0x65, 0x00, 0x6D, 0x00, 0x6F, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0xE8, 0x1A, 0x00, 0x00, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C,
|
||||
0x00, 0x6F, 0x00, 0x20, 0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C,
|
||||
0x00, 0x64, 0x00, 0x21, 0x00, 0x00, 0x00, 0x6A, 0x00, 0xFF, 0x55, 0xF0,
|
||||
0x33, 0xC0, 0x8B, 0xE5, 0x5D, 0xC3, 0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x3C,
|
||||
0x8B, 0x45, 0x08, 0x89, 0x45, 0xEC, 0x8B, 0x4D, 0xEC, 0x0F, 0xB7, 0x11,
|
||||
0x81, 0xFA, 0x4D, 0x5A, 0x00, 0x00, 0x74, 0x07, 0x33, 0xC0, 0xE9, 0x35,
|
||||
0x01, 0x00, 0x00, 0x8B, 0x45, 0xEC, 0x8B, 0x4D, 0x08, 0x03, 0x48, 0x3C,
|
||||
0x89, 0x4D, 0xE4, 0xBA, 0x08, 0x00, 0x00, 0x00, 0x6B, 0xC2, 0x00, 0x8B,
|
||||
0x4D, 0xE4, 0x8D, 0x54, 0x01, 0x78, 0x89, 0x55, 0xE8, 0x8B, 0x45, 0xE8,
|
||||
0x83, 0x38, 0x00, 0x75, 0x07, 0x33, 0xC0, 0xE9, 0x08, 0x01, 0x00, 0x00,
|
||||
0x8B, 0x4D, 0xE8, 0x8B, 0x11, 0x89, 0x55, 0xE0, 0x8B, 0x45, 0xE0, 0x03,
|
||||
0x45, 0x08, 0x89, 0x45, 0xF4, 0x8B, 0x4D, 0xF4, 0x8B, 0x51, 0x18, 0x89,
|
||||
0x55, 0xDC, 0x8B, 0x45, 0xF4, 0x8B, 0x48, 0x1C, 0x89, 0x4D, 0xD0, 0x8B,
|
||||
0x55, 0xF4, 0x8B, 0x42, 0x20, 0x89, 0x45, 0xD8, 0x8B, 0x4D, 0xF4, 0x8B,
|
||||
0x51, 0x24, 0x89, 0x55, 0xD4, 0xC7, 0x45, 0xF8, 0x00, 0x00, 0x00, 0x00,
|
||||
0xEB, 0x09, 0x8B, 0x45, 0xF8, 0x83, 0xC0, 0x01, 0x89, 0x45, 0xF8, 0x8B,
|
||||
0x4D, 0xF8, 0x3B, 0x4D, 0xDC, 0x0F, 0x83, 0xB3, 0x00, 0x00, 0x00, 0x8B,
|
||||
0x55, 0x08, 0x03, 0x55, 0xD8, 0x8B, 0x45, 0xF8, 0x8D, 0x0C, 0x82, 0x89,
|
||||
0x4D, 0xC8, 0x8B, 0x55, 0x08, 0x03, 0x55, 0xD4, 0x8B, 0x45, 0xF8, 0x8D,
|
||||
0x0C, 0x42, 0x89, 0x4D, 0xCC, 0x8B, 0x55, 0x08, 0x03, 0x55, 0xD0, 0x8B,
|
||||
0x45, 0xCC, 0x0F, 0xB7, 0x08, 0x8D, 0x14, 0x8A, 0x89, 0x55, 0xC4, 0x8B,
|
||||
0x45, 0xC8, 0x8B, 0x4D, 0x08, 0x03, 0x08, 0x89, 0x4D, 0xF0, 0xC7, 0x45,
|
||||
0xFC, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
0xEB, 0x09, 0x8B, 0x55, 0xFC, 0x83, 0xC2, 0x01, 0x89, 0x55, 0xFC, 0x8B,
|
||||
0x45, 0x0C, 0x03, 0x45, 0xFC, 0x0F, 0xBE, 0x08, 0x85, 0xC9, 0x74, 0x27,
|
||||
0x8B, 0x55, 0xF0, 0x03, 0x55, 0xFC, 0x0F, 0xBE, 0x02, 0x85, 0xC0, 0x74,
|
||||
0x1A, 0x8B, 0x4D, 0x0C, 0x03, 0x4D, 0xFC, 0x0F, 0xBE, 0x11, 0x8B, 0x45,
|
||||
0xF0, 0x03, 0x45, 0xFC, 0x0F, 0xBE, 0x08, 0x3B, 0xD1, 0x74, 0x02, 0xEB,
|
||||
0x02, 0xEB, 0xC3, 0x8B, 0x55, 0x0C, 0x03, 0x55, 0xFC, 0x0F, 0xBE, 0x02,
|
||||
0x85, 0xC0, 0x75, 0x19, 0x8B, 0x4D, 0xF0, 0x03, 0x4D, 0xFC, 0x0F, 0xBE,
|
||||
0x11, 0x85, 0xD2, 0x75, 0x0C, 0x8B, 0x45, 0xC4, 0x8B, 0x4D, 0x08, 0x03,
|
||||
0x08, 0x8B, 0xC1, 0xEB, 0x07, 0xE9, 0x38, 0xFF, 0xFF, 0xFF, 0x33, 0xC0,
|
||||
0x8B, 0xE5, 0x5D, 0xC3, 0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x34, 0xC7, 0x45,
|
||||
0xE4, 0x00, 0x00, 0x00, 0x00, 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0x89,
|
||||
0x45, 0xE4, 0x8B, 0x4D, 0xE4, 0x8B, 0x51, 0x0C, 0x89, 0x55, 0xD8, 0x8B,
|
||||
0x45, 0xD8, 0x8B, 0x48, 0x0C, 0x8B, 0x50, 0x10, 0x89, 0x4D, 0xCC, 0x89,
|
||||
0x55, 0xD0, 0x8B, 0x45, 0xCC, 0x89, 0x45, 0xD4, 0x8B, 0x4D, 0xD4, 0x89,
|
||||
0x4D, 0xE8, 0x83, 0x7D, 0xE8, 0x00, 0x0F, 0x84, 0x5A, 0x01, 0x00, 0x00,
|
||||
0x8B, 0x55, 0xE8, 0x83, 0x7A, 0x18, 0x00, 0x0F, 0x84, 0x4D, 0x01, 0x00,
|
||||
0x00, 0x8B, 0x45, 0xE8, 0x83, 0x78, 0x30, 0x00, 0x75, 0x02, 0xEB, 0xDE,
|
||||
0x8B, 0x4D, 0xE8, 0x8B, 0x51, 0x30, 0x89, 0x55, 0xEC, 0xC7, 0x45, 0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0xC7, 0x45, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xEB,
|
||||
0x09, 0x8B, 0x45, 0xF0, 0x83, 0xC0, 0x01, 0x89, 0x45, 0xF0, 0x8B, 0x4D,
|
||||
0xF0, 0x8B, 0x55, 0x08, 0x0F, 0xB7, 0x04, 0x4A, 0x85, 0xC0, 0x0F, 0x84,
|
||||
0xDD, 0x00, 0x00, 0x00, 0x8B, 0x4D, 0xF0, 0x8B, 0x55, 0xEC, 0x0F, 0xB7,
|
||||
0x04, 0x4A, 0x85, 0xC0, 0x0F, 0x84, 0xCB, 0x00, 0x00, 0x00, 0x8B, 0x4D,
|
||||
0xF0, 0x8B, 0x55, 0x08, 0x0F, 0xB7, 0x04, 0x4A, 0x83, 0xF8, 0x5A, 0x7F,
|
||||
0x37, 0x8B, 0x4D, 0xF0, 0x8B, 0x55, 0x08, 0x0F, 0xB7, 0x04, 0x4A, 0x83,
|
||||
0xF8, 0x41, 0x7C, 0x28, 0x8B, 0x4D, 0xF0, 0x8B, 0x55, 0x08, 0x0F, 0xB7,
|
||||
0x04, 0x4A, 0x83, 0xC0, 0x20, 0x89, 0x45, 0xE0, 0x8B, 0x4D, 0xF0, 0x8B,
|
||||
0x55, 0x08, 0x66, 0x8B, 0x45, 0xE0, 0x66, 0x89, 0x04, 0x4A, 0x66, 0x8B,
|
||||
0x4D, 0xE0, 0x66, 0x89, 0x4D, 0xFE, 0xEB, 0x0E, 0x8B, 0x55, 0xF0, 0x8B,
|
||||
0x45, 0x08, 0x66, 0x8B, 0x0C, 0x50, 0x66, 0x89, 0x4D, 0xFE, 0x66, 0x8B,
|
||||
0x55, 0xFE, 0x66, 0x89, 0x55, 0xF8, 0x8B, 0x45, 0xF0, 0x8B, 0x4D, 0xEC,
|
||||
0x0F, 0xB7, 0x14, 0x41, 0x83, 0xFA, 0x5A, 0x7F, 0x37, 0x8B, 0x45, 0xF0,
|
||||
0x8B, 0x4D, 0xEC, 0x0F, 0xB7, 0x14, 0x41, 0x83, 0xFA, 0x41, 0x7C, 0x28,
|
||||
0x8B, 0x45, 0xF0, 0x8B, 0x4D, 0xEC, 0x0F, 0xB7, 0x14, 0x41, 0x83, 0xC2,
|
||||
0x20, 0x89, 0x55, 0xDC, 0x8B, 0x45, 0xF0, 0x8B, 0x4D, 0xEC, 0x66, 0x8B,
|
||||
0x55, 0xDC, 0x66, 0x89, 0x14, 0x41, 0x66, 0x8B, 0x45, 0xDC, 0x66, 0x89,
|
||||
0x45, 0xFC, 0xEB, 0x0E, 0x8B, 0x4D, 0xF0, 0x8B, 0x55, 0xEC, 0x66, 0x8B,
|
||||
0x04, 0x4A, 0x66, 0x89, 0x45, 0xFC, 0x66, 0x8B, 0x4D, 0xFC, 0x66, 0x89,
|
||||
0x4D, 0xF4, 0x0F, 0xB7, 0x55, 0xF8, 0x0F, 0xB7, 0x45, 0xF4, 0x3B, 0xD0,
|
||||
0x74, 0x02, 0xEB, 0x05, 0xE9, 0x08, 0xFF, 0xFF, 0xFF, 0x8B, 0x4D, 0xF0,
|
||||
0x8B, 0x55, 0x08, 0x0F, 0xB7, 0x04, 0x4A, 0x85, 0xC0, 0x75, 0x16, 0x8B,
|
||||
0x4D, 0xF0, 0x8B, 0x55, 0xEC, 0x0F, 0xB7, 0x04, 0x4A, 0x85, 0xC0, 0x75,
|
||||
0x08, 0x8B, 0x4D, 0xE8, 0x8B, 0x41, 0x18, 0xEB, 0x0F, 0x8B, 0x55, 0xE8,
|
||||
0x8B, 0x02, 0x89, 0x45, 0xE8, 0xE9, 0x9C, 0xFE, 0xFF, 0xFF, 0x33, 0xC0,
|
||||
0x8B, 0xE5, 0x5D, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
132
Etw Syscall/libpeconv-master/tests/shellc64.h
Normal file
132
Etw Syscall/libpeconv-master/tests/shellc64.h
Normal file
@@ -0,0 +1,132 @@
|
||||
#pragma once
|
||||
|
||||
unsigned char messageBox64bit_sc[] = {
|
||||
0x56, 0x48, 0x8B, 0xF4, 0x48, 0x83, 0xE4, 0xF0, 0x48, 0x83, 0xEC, 0x20,
|
||||
0xE8, 0x05, 0x00, 0x00, 0x00, 0x48, 0x8B, 0xE6, 0x5E, 0xC3, 0x48, 0x83,
|
||||
0xEC, 0x68, 0xE8, 0x20, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x65, 0x00, 0x72,
|
||||
0x00, 0x6E, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2E,
|
||||
0x00, 0x64, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x59, 0xE8, 0x6A, 0x03, 0x00, 0x00, 0x48, 0x89, 0x44,
|
||||
0x24, 0x20, 0x48, 0x83, 0x7C, 0x24, 0x20, 0x00, 0x75, 0x0A, 0xB8, 0x01,
|
||||
0x00, 0x00, 0x00, 0xE9, 0x16, 0x01, 0x00, 0x00, 0xE8, 0x10, 0x00, 0x00,
|
||||
0x00, 0x4C, 0x6F, 0x61, 0x64, 0x4C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79,
|
||||
0x41, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x48, 0x8B, 0x4C, 0x24, 0x20, 0xE8,
|
||||
0xFB, 0x00, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0x83, 0x7C,
|
||||
0x24, 0x28, 0x00, 0x75, 0x0A, 0xB8, 0x02, 0x00, 0x00, 0x00, 0xE9, 0xDF,
|
||||
0x00, 0x00, 0x00, 0xE8, 0x10, 0x00, 0x00, 0x00, 0x47, 0x65, 0x74, 0x50,
|
||||
0x72, 0x6F, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x00, 0x00,
|
||||
0x5A, 0x48, 0x8B, 0x4C, 0x24, 0x20, 0xE8, 0xC4, 0x00, 0x00, 0x00, 0x48,
|
||||
0x89, 0x44, 0x24, 0x30, 0x48, 0x83, 0x7C, 0x24, 0x30, 0x00, 0x75, 0x0A,
|
||||
0xB8, 0x03, 0x00, 0x00, 0x00, 0xE9, 0xA8, 0x00, 0x00, 0x00, 0x48, 0x8B,
|
||||
0x44, 0x24, 0x28, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0x8B, 0x44, 0x24,
|
||||
0x30, 0x48, 0x89, 0x44, 0x24, 0x50, 0xE8, 0x10, 0x00, 0x00, 0x00, 0x75,
|
||||
0x73, 0x65, 0x72, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x59, 0xFF, 0x54, 0x24, 0x40, 0x48, 0x89, 0x44, 0x24,
|
||||
0x48, 0xE8, 0x10, 0x00, 0x00, 0x00, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x42, 0x6F, 0x78, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x48,
|
||||
0x8B, 0x4C, 0x24, 0x48, 0xFF, 0x54, 0x24, 0x50, 0x48, 0x89, 0x44, 0x24,
|
||||
0x38, 0x48, 0x83, 0x7C, 0x24, 0x38, 0x00, 0x75, 0x07, 0xB8, 0x04, 0x00,
|
||||
0x00, 0x00, 0xEB, 0x42, 0x45, 0x33, 0xC9, 0xE8, 0x10, 0x00, 0x00, 0x00,
|
||||
0x44, 0x00, 0x65, 0x00, 0x6D, 0x00, 0x6F, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x41, 0x58, 0xE8, 0x1A, 0x00, 0x00, 0x00, 0x48,
|
||||
0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x20, 0x00, 0x57,
|
||||
0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00, 0x21, 0x00, 0x00,
|
||||
0x00, 0x5A, 0x33, 0xC9, 0xFF, 0x54, 0x24, 0x38, 0x33, 0xC0, 0x48, 0x83,
|
||||
0xC4, 0x68, 0xC3, 0x48, 0x89, 0x54, 0x24, 0x10, 0x48, 0x89, 0x4C, 0x24,
|
||||
0x08, 0x48, 0x83, 0xEC, 0x78, 0x48, 0x8B, 0x84, 0x24, 0x80, 0x00, 0x00,
|
||||
0x00, 0x48, 0x89, 0x44, 0x24, 0x30, 0x48, 0x8B, 0x44, 0x24, 0x30, 0x0F,
|
||||
0xB7, 0x00, 0x3D, 0x4D, 0x5A, 0x00, 0x00, 0x74, 0x07, 0x33, 0xC0, 0xE9,
|
||||
0x02, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x30, 0x48, 0x63, 0x40,
|
||||
0x3C, 0x48, 0x8B, 0x8C, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x03, 0xC8,
|
||||
0x48, 0x8B, 0xC1, 0x48, 0x89, 0x44, 0x24, 0x40, 0xB8, 0x08, 0x00, 0x00,
|
||||
0x00, 0x48, 0x6B, 0xC0, 0x00, 0x48, 0x8B, 0x4C, 0x24, 0x40, 0x48, 0x8D,
|
||||
0x84, 0x01, 0x88, 0x00, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x38, 0x48,
|
||||
0x8B, 0x44, 0x24, 0x38, 0x83, 0x38, 0x00, 0x75, 0x07, 0x33, 0xC0, 0xE9,
|
||||
0xBA, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x8B, 0x00, 0x89,
|
||||
0x44, 0x24, 0x18, 0x8B, 0x44, 0x24, 0x18, 0x48, 0x03, 0x84, 0x24, 0x80,
|
||||
0x00, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x10, 0x48, 0x8B, 0x44, 0x24,
|
||||
0x10, 0x8B, 0x40, 0x18, 0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x44,
|
||||
0x24, 0x10, 0x8B, 0x40, 0x1C, 0x89, 0x44, 0x24, 0x24, 0x48, 0x8B, 0x44,
|
||||
0x24, 0x10, 0x8B, 0x40, 0x20, 0x89, 0x44, 0x24, 0x1C, 0x48, 0x8B, 0x44,
|
||||
0x24, 0x10, 0x8B, 0x40, 0x24, 0x89, 0x44, 0x24, 0x20, 0x48, 0xC7, 0x44,
|
||||
0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0D, 0x48, 0x8B, 0x44, 0x24,
|
||||
0x08, 0x48, 0xFF, 0xC0, 0x48, 0x89, 0x44, 0x24, 0x08, 0x48, 0x8B, 0x44,
|
||||
0x24, 0x48, 0x48, 0x39, 0x44, 0x24, 0x08, 0x0F, 0x83, 0x43, 0x01, 0x00,
|
||||
0x00, 0x8B, 0x44, 0x24, 0x1C, 0x48, 0x8B, 0x8C, 0x24, 0x80, 0x00, 0x00,
|
||||
0x00, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x8B, 0x4C, 0x24, 0x08,
|
||||
0x48, 0x8D, 0x04, 0x88, 0x48, 0x89, 0x44, 0x24, 0x58, 0x8B, 0x44, 0x24,
|
||||
0x20, 0x48, 0x8B, 0x8C, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x03, 0xC8,
|
||||
0x48, 0x8B, 0xC1, 0x48, 0x8B, 0x4C, 0x24, 0x08, 0x48, 0x8D, 0x04, 0x48,
|
||||
0x48, 0x89, 0x44, 0x24, 0x50, 0x8B, 0x44, 0x24, 0x24, 0x48, 0x8B, 0x8C,
|
||||
0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48,
|
||||
0x8B, 0x4C, 0x24, 0x50, 0x0F, 0xB7, 0x09, 0x48, 0x8D, 0x04, 0x88, 0x48,
|
||||
0x89, 0x44, 0x24, 0x60, 0x48, 0x8B, 0x44, 0x24, 0x58, 0x8B, 0x00, 0x48,
|
||||
0x8B, 0x8C, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x03, 0xC8, 0x48, 0x8B,
|
||||
0xC1, 0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0xC7, 0x04, 0x24, 0x00, 0x00,
|
||||
0x00, 0x00, 0x48, 0xC7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0B,
|
||||
0x48, 0x8B, 0x04, 0x24, 0x48, 0xFF, 0xC0, 0x48, 0x89, 0x04, 0x24, 0x48,
|
||||
0x8B, 0x04, 0x24, 0x48, 0x8B, 0x8C, 0x24, 0x88, 0x00, 0x00, 0x00, 0x48,
|
||||
0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x0F, 0xBE, 0x00, 0x85, 0xC0, 0x74, 0x45,
|
||||
0x48, 0x8B, 0x04, 0x24, 0x48, 0x8B, 0x4C, 0x24, 0x28, 0x48, 0x03, 0xC8,
|
||||
0x48, 0x8B, 0xC1, 0x0F, 0xBE, 0x00, 0x85, 0xC0, 0x74, 0x2F, 0x48, 0x8B,
|
||||
0x04, 0x24, 0x48, 0x8B, 0x8C, 0x24, 0x88, 0x00, 0x00, 0x00, 0x48, 0x03,
|
||||
0xC8, 0x48, 0x8B, 0xC1, 0x0F, 0xBE, 0x00, 0x48, 0x8B, 0x0C, 0x24, 0x48,
|
||||
0x8B, 0x54, 0x24, 0x28, 0x48, 0x03, 0xD1, 0x48, 0x8B, 0xCA, 0x0F, 0xBE,
|
||||
0x09, 0x3B, 0xC1, 0x74, 0x02, 0xEB, 0x02, 0xEB, 0x97, 0x48, 0x8B, 0x04,
|
||||
0x24, 0x48, 0x8B, 0x8C, 0x24, 0x88, 0x00, 0x00, 0x00, 0x48, 0x03, 0xC8,
|
||||
0x48, 0x8B, 0xC1, 0x0F, 0xBE, 0x00, 0x85, 0xC0, 0x75, 0x2D, 0x48, 0x8B,
|
||||
0x04, 0x24, 0x48, 0x8B, 0x4C, 0x24, 0x28, 0x48, 0x03, 0xC8, 0x48, 0x8B,
|
||||
0xC1, 0x0F, 0xBE, 0x00, 0x85, 0xC0, 0x75, 0x17, 0x48, 0x8B, 0x44, 0x24,
|
||||
0x60, 0x8B, 0x00, 0x48, 0x8B, 0x8C, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48,
|
||||
0x03, 0xC8, 0x48, 0x8B, 0xC1, 0xEB, 0x07, 0xE9, 0xA0, 0xFE, 0xFF, 0xFF,
|
||||
0x33, 0xC0, 0x48, 0x83, 0xC4, 0x78, 0xC3, 0x48, 0x89, 0x4C, 0x24, 0x08,
|
||||
0x56, 0x57, 0x48, 0x83, 0xEC, 0x68, 0x48, 0xC7, 0x44, 0x24, 0x30, 0x00,
|
||||
0x00, 0x00, 0x00, 0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, 0x00, 0x00, 0x00,
|
||||
0x48, 0x89, 0x44, 0x24, 0x30, 0x48, 0x8B, 0x44, 0x24, 0x30, 0x48, 0x8B,
|
||||
0x40, 0x18, 0x48, 0x89, 0x44, 0x24, 0x38, 0x48, 0x8D, 0x44, 0x24, 0x48,
|
||||
0x48, 0x8B, 0x4C, 0x24, 0x38, 0x48, 0x8B, 0xF8, 0x48, 0x8D, 0x71, 0x10,
|
||||
0xB9, 0x10, 0x00, 0x00, 0x00, 0xF3, 0xA4, 0x48, 0x8B, 0x44, 0x24, 0x48,
|
||||
0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x48, 0x89,
|
||||
0x44, 0x24, 0x20, 0x48, 0x83, 0x7C, 0x24, 0x20, 0x00, 0x0F, 0x84, 0xC6,
|
||||
0x01, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x20, 0x48, 0x83, 0x78, 0x30,
|
||||
0x00, 0x0F, 0x84, 0xB6, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x20,
|
||||
0x48, 0x83, 0x78, 0x60, 0x00, 0x75, 0x02, 0xEB, 0xD6, 0x48, 0x8B, 0x44,
|
||||
0x24, 0x20, 0x48, 0x8B, 0x40, 0x60, 0x48, 0x89, 0x44, 0x24, 0x18, 0x48,
|
||||
0xC7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7, 0x04, 0x24, 0x00,
|
||||
0x00, 0x00, 0x00, 0xEB, 0x0B, 0x48, 0x8B, 0x04, 0x24, 0x48, 0xFF, 0xC0,
|
||||
0x48, 0x89, 0x04, 0x24, 0x48, 0x8B, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00,
|
||||
0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7, 0x04, 0x48, 0x85, 0xC0, 0x0F, 0x84,
|
||||
0x23, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x18, 0x48, 0x8B, 0x0C,
|
||||
0x24, 0x0F, 0xB7, 0x04, 0x48, 0x85, 0xC0, 0x0F, 0x84, 0x0E, 0x01, 0x00,
|
||||
0x00, 0x48, 0x8B, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x0C,
|
||||
0x24, 0x0F, 0xB7, 0x04, 0x48, 0x83, 0xF8, 0x5A, 0x7F, 0x50, 0x48, 0x8B,
|
||||
0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7,
|
||||
0x04, 0x48, 0x83, 0xF8, 0x41, 0x7C, 0x3B, 0x48, 0x8B, 0x84, 0x24, 0x80,
|
||||
0x00, 0x00, 0x00, 0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7, 0x04, 0x48, 0x83,
|
||||
0xE8, 0x41, 0x83, 0xC0, 0x61, 0x89, 0x44, 0x24, 0x28, 0x48, 0x8B, 0x84,
|
||||
0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7, 0x54,
|
||||
0x24, 0x28, 0x66, 0x89, 0x14, 0x48, 0x0F, 0xB7, 0x44, 0x24, 0x28, 0x66,
|
||||
0x89, 0x44, 0x24, 0x08, 0xEB, 0x15, 0x48, 0x8B, 0x84, 0x24, 0x80, 0x00,
|
||||
0x00, 0x00, 0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7, 0x04, 0x48, 0x66, 0x89,
|
||||
0x44, 0x24, 0x08, 0x0F, 0xB7, 0x44, 0x24, 0x08, 0x66, 0x89, 0x44, 0x24,
|
||||
0x0C, 0x48, 0x8B, 0x44, 0x24, 0x18, 0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7,
|
||||
0x04, 0x48, 0x83, 0xF8, 0x5A, 0x7F, 0x47, 0x48, 0x8B, 0x44, 0x24, 0x18,
|
||||
0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7, 0x04, 0x48, 0x83, 0xF8, 0x41, 0x7C,
|
||||
0x35, 0x48, 0x8B, 0x44, 0x24, 0x18, 0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7,
|
||||
0x04, 0x48, 0x83, 0xE8, 0x41, 0x83, 0xC0, 0x61, 0x89, 0x44, 0x24, 0x2C,
|
||||
0x48, 0x8B, 0x44, 0x24, 0x18, 0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7, 0x54,
|
||||
0x24, 0x2C, 0x66, 0x89, 0x14, 0x48, 0x0F, 0xB7, 0x44, 0x24, 0x2C, 0x66,
|
||||
0x89, 0x44, 0x24, 0x0A, 0xEB, 0x12, 0x48, 0x8B, 0x44, 0x24, 0x18, 0x48,
|
||||
0x8B, 0x0C, 0x24, 0x0F, 0xB7, 0x04, 0x48, 0x66, 0x89, 0x44, 0x24, 0x0A,
|
||||
0x0F, 0xB7, 0x44, 0x24, 0x0A, 0x66, 0x89, 0x44, 0x24, 0x10, 0x0F, 0xB7,
|
||||
0x44, 0x24, 0x0C, 0x0F, 0xB7, 0x4C, 0x24, 0x10, 0x3B, 0xC1, 0x74, 0x02,
|
||||
0xEB, 0x05, 0xE9, 0xBA, 0xFE, 0xFF, 0xFF, 0x48, 0x8B, 0x84, 0x24, 0x80,
|
||||
0x00, 0x00, 0x00, 0x48, 0x8B, 0x0C, 0x24, 0x0F, 0xB7, 0x04, 0x48, 0x85,
|
||||
0xC0, 0x75, 0x1C, 0x48, 0x8B, 0x44, 0x24, 0x18, 0x48, 0x8B, 0x0C, 0x24,
|
||||
0x0F, 0xB7, 0x04, 0x48, 0x85, 0xC0, 0x75, 0x0B, 0x48, 0x8B, 0x44, 0x24,
|
||||
0x20, 0x48, 0x8B, 0x40, 0x30, 0xEB, 0x14, 0x48, 0x8B, 0x44, 0x24, 0x20,
|
||||
0x48, 0x8B, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0xE9, 0x2E, 0xFE, 0xFF,
|
||||
0xFF, 0x33, 0xC0, 0x48, 0x83, 0xC4, 0x68, 0x5F, 0x5E, 0xC3, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
4
Etw Syscall/libpeconv-master/tests/shellcodes.h
Normal file
4
Etw Syscall/libpeconv-master/tests/shellcodes.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "shellc32.h"
|
||||
#include "shellc64.h"
|
||||
16
Etw Syscall/libpeconv-master/tests/test_case1/CMakeLists.txt
Normal file
16
Etw Syscall/libpeconv-master/tests/test_case1/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
project (test_case1)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
|
||||
set (srcs
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set (hdrs
|
||||
)
|
||||
|
||||
add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs})
|
||||
|
||||
#install
|
||||
INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} )
|
||||
29
Etw Syscall/libpeconv-master/tests/test_case1/main.cpp
Normal file
29
Etw Syscall/libpeconv-master/tests/test_case1/main.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int popup_message1()
|
||||
{
|
||||
SYSTEMTIME SystemTime;
|
||||
GetSystemTime(&SystemTime);
|
||||
|
||||
TCHAR pszDate[200];
|
||||
GetDateFormatA( LOCALE_USER_DEFAULT, DATE_LONGDATE, &SystemTime, NULL, pszDate, 200 );
|
||||
|
||||
return MessageBoxA(NULL, pszDate, "Test Case 1", MB_OK);
|
||||
}
|
||||
|
||||
int popup_message2()
|
||||
{
|
||||
return MessageBoxW(NULL, L"Checking wide strings", L"Test Case 1", MB_OK);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if (popup_message1() == 1337) {
|
||||
if (popup_message2() == 1338) {
|
||||
return MessageBoxW(NULL, L"Hooking test passed", L"Test Case 1", MB_OK);
|
||||
}
|
||||
}
|
||||
printf("Test Case 1 finished\n");
|
||||
return 0;
|
||||
}
|
||||
5
Etw Syscall/libpeconv-master/tests/test_case2/README.md
Normal file
5
Etw Syscall/libpeconv-master/tests/test_case2/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# FlareOn2017 Challenge 6
|
||||
|
||||
### Writeup
|
||||
|
||||
+ [Solving Flare-On 2017, Challenge 6 with libPeConv](https://hshrzd.wordpress.com/2017/12/01/hook-the-planet-solving-flareon4-challenge6-with-libpeconv/)
|
||||
BIN
Etw Syscall/libpeconv-master/tests/test_case2/payload.dll
Normal file
BIN
Etw Syscall/libpeconv-master/tests/test_case2/payload.dll
Normal file
Binary file not shown.
18
Etw Syscall/libpeconv-master/tests/test_case3/CMakeLists.txt
Normal file
18
Etw Syscall/libpeconv-master/tests/test_case3/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
project (test_case3)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
|
||||
set (srcs
|
||||
main.cpp
|
||||
checksum.cpp
|
||||
)
|
||||
|
||||
set (hdrs
|
||||
checksum.h
|
||||
)
|
||||
|
||||
add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs})
|
||||
|
||||
#install
|
||||
INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} )
|
||||
35
Etw Syscall/libpeconv-master/tests/test_case3/checksum.cpp
Normal file
35
Etw Syscall/libpeconv-master/tests/test_case3/checksum.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "checksum.h"
|
||||
|
||||
inline DWORD rotl32a(DWORD x, DWORD n)
|
||||
{
|
||||
return (x << n) | (x >> (32 - n));
|
||||
}
|
||||
|
||||
inline char to_lower(char c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
c = c - 'A' + 'a';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
DWORD calc_checksum(BYTE *str, size_t buf_size, bool enable_tolower)
|
||||
{
|
||||
if (str == NULL) return 0;
|
||||
|
||||
DWORD checksum = 0;
|
||||
for (size_t i = 0; i < buf_size; i++) {
|
||||
checksum = rotl32a(checksum, 7);
|
||||
char c = str[i];
|
||||
if (enable_tolower) {
|
||||
c = to_lower(c);
|
||||
}
|
||||
checksum ^= c;
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
DWORD calc_checksum(char *str, bool enable_tolower)
|
||||
{
|
||||
return calc_checksum((BYTE*)str, strlen(str), enable_tolower);
|
||||
}
|
||||
7
Etw Syscall/libpeconv-master/tests/test_case3/checksum.h
Normal file
7
Etw Syscall/libpeconv-master/tests/test_case3/checksum.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
DWORD calc_checksum(char *str, bool enable_tolower);
|
||||
DWORD calc_checksum(BYTE *str, size_t buf_size, bool enable_tolower);
|
||||
|
||||
46
Etw Syscall/libpeconv-master/tests/test_case3/main.cpp
Normal file
46
Etw Syscall/libpeconv-master/tests/test_case3/main.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "checksum.h"
|
||||
|
||||
bool get_rand_string(char *buffer, size_t buffer_size)
|
||||
{
|
||||
const char charset[] = "ABCDEFGHIJKLMNOPQRSTUWVXYZabcdefghijklmnopqrstuwvxyz1234567890";
|
||||
size_t charset_len = strlen(charset);
|
||||
|
||||
srand(GetTickCount());
|
||||
for (size_t i = 0; i < buffer_size - 1; i++) {
|
||||
size_t c_indx = rand() % charset_len;
|
||||
buffer[i] = charset[c_indx];
|
||||
Sleep(1000);
|
||||
}
|
||||
buffer[buffer_size - 1] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_password_valid(char *str)
|
||||
{
|
||||
DWORD checksum = calc_checksum(str, true);
|
||||
if (checksum == 0x1f561e6a) { //calc_checksum("my_demo_password", true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
char str[14] = { 0 };
|
||||
get_rand_string(str, 12);
|
||||
|
||||
std::cout << str << std::endl;
|
||||
|
||||
if (is_password_valid(str)) {
|
||||
MessageBoxA(NULL, "Passed!", "Test Case 3", MB_OK);
|
||||
} else {
|
||||
std::cout << "Failed!" << std::endl;
|
||||
MessageBoxA(NULL, "Failed!", "Test Case 3", MB_OK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
19
Etw Syscall/libpeconv-master/tests/test_case4/CMakeLists.txt
Normal file
19
Etw Syscall/libpeconv-master/tests/test_case4/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
project (test_case4)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
set(DELAYLOAD_FLAG "/DELAYLOAD:\"user32.dll\"" )
|
||||
|
||||
set (srcs
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set (hdrs
|
||||
)
|
||||
|
||||
add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs} )
|
||||
target_link_libraries(${PROJECT_NAME} "delayimp.lib" )
|
||||
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS " ${DELAYLOAD_FLAG}")
|
||||
|
||||
#install
|
||||
INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} )
|
||||
29
Etw Syscall/libpeconv-master/tests/test_case4/main.cpp
Normal file
29
Etw Syscall/libpeconv-master/tests/test_case4/main.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int popup_message1()
|
||||
{
|
||||
SYSTEMTIME SystemTime;
|
||||
GetSystemTime(&SystemTime);
|
||||
|
||||
TCHAR pszDate[200];
|
||||
GetDateFormatA( LOCALE_USER_DEFAULT, DATE_LONGDATE, &SystemTime, NULL, pszDate, 200 );
|
||||
|
||||
return MessageBoxA(NULL, pszDate, "Test Case 1", MB_OK);
|
||||
}
|
||||
|
||||
int popup_message2()
|
||||
{
|
||||
return MessageBoxW(NULL, L"Checking wide strings", L"Test Case 1", MB_OK);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if (popup_message1() == 1337) {
|
||||
if (popup_message2() == 1338) {
|
||||
return MessageBoxW(NULL, L"Hooking test passed", L"Test Case 1", MB_OK);
|
||||
}
|
||||
}
|
||||
printf("Test Case 4 finished\n");
|
||||
return 0;
|
||||
}
|
||||
21
Etw Syscall/libpeconv-master/tests/test_case5/CMakeLists.txt
Normal file
21
Etw Syscall/libpeconv-master/tests/test_case5/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
project (test_case5_exe)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
|
||||
set (srcs
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set (hdrs
|
||||
)
|
||||
|
||||
# libs
|
||||
add_subdirectory (test_case5_dll)
|
||||
include_directories ( test_case5_dll/include )
|
||||
|
||||
add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs} )
|
||||
target_link_libraries(${PROJECT_NAME} "test_case5_dll" )
|
||||
|
||||
#install
|
||||
INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} )
|
||||
16
Etw Syscall/libpeconv-master/tests/test_case5/main.cpp
Normal file
16
Etw Syscall/libpeconv-master/tests/test_case5/main.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <Windows.h>
|
||||
#include <iostream>
|
||||
#include "api.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "Test Case 5 started..." << std::endl;
|
||||
DWORD checks = test_checksum1();
|
||||
checks += test_checksum2();
|
||||
checks += test_checksum3();
|
||||
checks += test_checksum4();
|
||||
checks += test_checksum5();
|
||||
|
||||
std::cout << "Test Case 5 finished, checks: " << std::hex << checks << std::endl;
|
||||
return checks;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
cmake_minimum_required ( VERSION 2.8...3.21 )
|
||||
project (test_case5_dll)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
include_directories ( include )
|
||||
|
||||
set (srcs
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set (dll_hdrs
|
||||
include/api.h
|
||||
)
|
||||
|
||||
add_library ( ${PROJECT_NAME} SHARED ${dll_hdrs} ${srcs} main.def)
|
||||
|
||||
#install
|
||||
INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} )
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef DLL_EXPORTS
|
||||
#define DLL_API __declspec(dllexport) __stdcall
|
||||
#else
|
||||
#define DLL_API __declspec(dllimport) __stdcall
|
||||
#endif
|
||||
|
||||
int DLL_API test_checksum1();
|
||||
int DLL_API test_checksum2();
|
||||
int DLL_API test_checksum3();
|
||||
int DLL_API test_checksum4();
|
||||
int DLL_API test_checksum5();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user