MMap: further arch unification

This commit is contained in:
DarthTon
2017-05-02 18:59:45 +03:00
parent 380c86083d
commit e22c56bbbf
21 changed files with 502 additions and 389 deletions
+1 -1
View File
@@ -170,7 +170,7 @@ void AsmHelper32::SaveRetValAndSignalEvent(
// Save last NT status
_assembler.mov( asmjit::host::edx, asmjit::host::dword_ptr_abs( 0x18 ).setSegment( asmjit::host::fs ) );
_assembler.add( asmjit::host::edx, LAST_STATUS_OFS );
_assembler.add( asmjit::host::edx, 0x598 + 0x197 * sizeof( uint32_t ) );
_assembler.mov( asmjit::host::edx, asmjit::host::dword_ptr( asmjit::host::edx ) );
_assembler.mov( asmjit::host::eax, errPtr );
_assembler.mov( asmjit::host::dword_ptr( asmjit::host::eax ), asmjit::host::edx );
+1 -1
View File
@@ -146,7 +146,7 @@ void AsmHelper64::SaveRetValAndSignalEvent(
// Save last NT status
_assembler.mov( asmjit::host::rdx, asmjit::host::dword_ptr_abs( 0x30 ).setSegment( asmjit::host::gs ) ); // TEB ptr
_assembler.add( asmjit::host::rdx, LAST_STATUS_OFS );
_assembler.add( asmjit::host::rdx, 0x598 + 0x197 * sizeof( uint64_t ) );
_assembler.mov( asmjit::host::rdx, asmjit::host::dword_ptr( asmjit::host::rdx ) );
_assembler.mov( asmjit::host::rax, lastStatusPtr );
_assembler.mov( asmjit::host::dword_ptr( asmjit::host::rax ), asmjit::host::rdx );
+15
View File
@@ -1,5 +1,6 @@
#pragma once
#include "../Config.h"
#include <stdint.h>
// Architecture-dependent pointer size
#define WordSize sizeof(void*)
@@ -71,6 +72,18 @@
template<int s>
struct CompileTimeSizeOf;
template<typename T, typename U>
constexpr size_t offsetOf( U T::*member )
{
return (size_t)&((T*)nullptr->*member);
}
template<typename T, typename U>
constexpr uint64_t fieldPtr( uint64_t base, U T::*member )
{
return base + offsetOf( member );
}
// Type-unsafe cast.
template<typename _Tgt, typename _Src>
inline _Tgt brutal_cast( const _Src& src )
@@ -110,3 +123,5 @@ inline NTSTATUS SetLastNtStatus( NTSTATUS status )
{
return *(NTSTATUS*)((unsigned char*)NtCurrentTeb() + LAST_STATUS_OFS) = status;
}
#define SharedUserData32 ((KUSER_SHARED_DATA* const)0x7FFE0000)
+47 -24
View File
@@ -445,6 +445,17 @@ namespace blackbone
ULONG NonPagedPoolUsage;
};
template<typename T>
struct _OBJECT_ATTRIBUTES_T
{
ULONG Length;
T RootDirectory;
T ObjectName;
ULONG Attributes;
T SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
T SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
};
struct _XSAVE_FORMAT64
{
WORD ControlWord;
@@ -679,37 +690,47 @@ namespace blackbone
T PatchInformation;
};
typedef struct _RTL_INVERTED_FUNCTION_TABLE_ENTRY
template<typename T>
struct _RTL_INVERTED_FUNCTION_TABLE_ENTRY
{
PIMAGE_RUNTIME_FUNCTION_ENTRY ExceptionDirectory;
PVOID ImageBase;
T ExceptionDirectory; // PIMAGE_RUNTIME_FUNCTION_ENTRY
T ImageBase;
ULONG ImageSize;
ULONG SizeOfTable;
} RTL_INVERTED_FUNCTION_TABLE_ENTRY, *PRTL_INVERTED_FUNCTION_TABLE_ENTRY;
};
typedef _UNICODE_STRING_T<DWORD> _UNICODE_STRING32;
typedef _UNICODE_STRING_T<DWORD64> _UNICODE_STRING64;
typedef _UNICODE_STRING_T<DWORD_PTR> UNICODE_STRING_T;
typedef _PEB_T<DWORD, DWORD64, 34> _PEB32;
typedef _PEB_T<DWORD64, DWORD, 30> _PEB64;
typedef _PEB_T<DWORD, DWORD64, 34> _PEB32;
typedef _PEB_T<DWORD64, DWORD, 30> _PEB64;
typedef _TEB_T<DWORD> _TEB32;
typedef _TEB_T<DWORD64> _TEB64;
typedef _TEB_T<DWORD_PTR> TEB_T;
#ifdef USE64
typedef _PEB64 PEB_T;
#else
typedef _PEB32 PEB_T;
#endif
typedef _PEB_LDR_DATA2<DWORD> _PEB_LDR_DATA232;
typedef _PEB_LDR_DATA2<DWORD64> _PEB_LDR_DATA264;
typedef _PEB_LDR_DATA2<DWORD_PTR> PEB_LDR_DATA_T;
typedef _TEB_T<DWORD> _TEB32;
typedef _TEB_T<DWORD64> _TEB64;
typedef _TEB_T<DWORD_PTR> TEB_T;
typedef _LDR_DATA_TABLE_ENTRY_BASE<DWORD> _LDR_DATA_TABLE_ENTRY_BASE32;
typedef _LDR_DATA_TABLE_ENTRY_BASE<DWORD64> _LDR_DATA_TABLE_ENTRY_BASE64;
typedef _LDR_DATA_TABLE_ENTRY_BASE<DWORD_PTR> LDR_DATA_TABLE_ENTRY_BASE_T;
typedef _PEB_LDR_DATA2<DWORD> _PEB_LDR_DATA232;
typedef _PEB_LDR_DATA2<DWORD64> _PEB_LDR_DATA264;
typedef _PEB_LDR_DATA2<DWORD_PTR> PEB_LDR_DATA_T;
typedef _CONTEXT_T<DWORD> _CONTEXT32;
typedef _CONTEXT_T<DWORD64> _CONTEXT64;
typedef _CONTEXT_T<DWORD_PTR> CONTEXT_T;
typedef _LDR_DATA_TABLE_ENTRY_BASE<DWORD> _LDR_DATA_TABLE_ENTRY_BASE32;
typedef _LDR_DATA_TABLE_ENTRY_BASE<DWORD64> _LDR_DATA_TABLE_ENTRY_BASE64;
typedef _LDR_DATA_TABLE_ENTRY_BASE<DWORD_PTR> LDR_DATA_TABLE_ENTRY_BASE_T;
typedef _CONTEXT_T<DWORD> _CONTEXT32;
typedef _CONTEXT_T<DWORD64> _CONTEXT64;
typedef _CONTEXT_T<DWORD_PTR> CONTEXT_T;
typedef _SECTION_BASIC_INFORMATION_T<DWORD> _SECTION_BASIC_INFORMATION32;
typedef _SECTION_BASIC_INFORMATION_T<DWORD64> _SECTION_BASIC_INFORMATION64;
typedef _SECTION_BASIC_INFORMATION_T<DWORD_PTR> SECTION_BASIC_INFORMATION_T;
typedef _SECTION_BASIC_INFORMATION_T<DWORD_PTR> SECTION_BASIC_INFORMATION_T;
typedef _SYSTEM_HANDLE_INFORMATION_T<DWORD> _SYSTEM_HANDLE_INFORMATION32;
typedef _SYSTEM_HANDLE_INFORMATION_T<DWORD64> _SYSTEM_HANDLE_INFORMATION64;
@@ -719,11 +740,13 @@ namespace blackbone
typedef _OBJECT_TYPE_INFORMATION_T<DWORD64> _OBJECT_TYPE_INFORMATION64;
typedef _OBJECT_TYPE_INFORMATION_T<DWORD_PTR> OBJECT_TYPE_INFORMATION_T;
#ifdef USE64
typedef _PEB64 PEB_T;
#else
typedef _PEB32 PEB_T;
#endif
typedef _OBJECT_ATTRIBUTES_T<DWORD> _OBJECT_ATTRIBUTES32;
typedef _OBJECT_ATTRIBUTES_T<DWORD64> _OBJECT_ATTRIBUTES64;
typedef _OBJECT_ATTRIBUTES_T<DWORD_PTR> OBJECT_ATTRIBUTES_T;
typedef _ACTCTXW_T<DWORD> _ACTCTXW32;
typedef _ACTCTXW_T<DWORD64> _ACTCTXW64;
typedef _ACTCTXW_T<DWORD_PTR> ACTCTXW_T;
}
#include "ApiSet.h"
+4 -4
View File
@@ -16,14 +16,14 @@ namespace blackbone
_LARGE_INTEGER LoadTime;
};
typedef struct _RTL_INVERTED_FUNCTION_TABLE7
template<typename T>
struct _RTL_INVERTED_FUNCTION_TABLE7
{
ULONG Count;
ULONG MaxCount;
ULONG Epoch;
RTL_INVERTED_FUNCTION_TABLE_ENTRY Entries[0x200];
} RTL_INVERTED_FUNCTION_TABLE7, *PRTL_INVERTED_FUNCTION_TABLE7;
_RTL_INVERTED_FUNCTION_TABLE_ENTRY<T> Entries[0x200];
};
#pragma warning(default : 4201)
}
+4 -4
View File
@@ -72,15 +72,15 @@ namespace blackbone
unsigned long ImplicitPathOptions;
};
typedef struct _RTL_INVERTED_FUNCTION_TABLE8
template<typename T>
struct _RTL_INVERTED_FUNCTION_TABLE8
{
ULONG Count;
ULONG MaxCount;
ULONG Epoch;
UCHAR Overflow;
RTL_INVERTED_FUNCTION_TABLE_ENTRY Entries[0x200];
} RTL_INVERTED_FUNCTION_TABLE8, *PRTL_INVERTED_FUNCTION_TABLE8;
_RTL_INVERTED_FUNCTION_TABLE_ENTRY<T> Entries[0x200];
};
#pragma warning(default : 4201)
}
+15 -7
View File
@@ -2,6 +2,7 @@
#include "../Process/Process.h"
#include "../Include/Macro.h"
#include "../Misc/Trace.hpp"
#include "../Misc/PattrernLoader.h"
#include "../Asm/LDasm.h"
namespace blackbone
@@ -217,7 +218,7 @@ MExcept::~MExcept()
/// <param name="mt">Mosule type</param>
/// <param name="partial">Partial exception support</param>
/// <returns>Error code</returns>
NTSTATUS MExcept::CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType mt, bool partial )
NTSTATUS MExcept::CreateVEH( ptr_t pTargetBase, size_t imageSize, eModType mt, bool partial )
{
auto a = AsmFactory::GetAssembler( mt );
uint64_t result = 0;
@@ -304,7 +305,7 @@ NTSTATUS MExcept::CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType m
// LdrpInvertedFunctionTable
if (*(uint32_t*)pData == 0xDEADDA7A)
{
*(uint32_t*)pData = static_cast<uint32_t>(_proc.nativeLdr().LdrpInvertedFunctionTable());
*(uint32_t*)pData = static_cast<uint32_t>(g_PatternLoader->data().LdrpInvertedFunctionTable32);
continue;
}
@@ -318,7 +319,7 @@ NTSTATUS MExcept::CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType m
// LdrProtectMrdata address
if (*(uint32_t*)pData == 0xDEADC0D2)
{
*(uint32_t*)pData = static_cast<uint32_t>(_proc.nativeLdr().LdrProtectMrdata());
*(uint32_t*)pData = static_cast<uint32_t>(g_PatternLoader->data().LdrProtectMrdata);
continue;
}
}
@@ -344,10 +345,17 @@ NTSTATUS MExcept::CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType m
_proc.remote().AddReturnWithEvent( *a, mt );
a->GenEpilogue();
_proc.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result );
_hVEH = result;
return (_hVEH == 0 ? STATUS_NOT_FOUND : STATUS_SUCCESS);
NTSTATUS status = _proc.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result );
if (result != 0)
{
_hVEH = result;
return STATUS_SUCCESS;
}
else
{
status = _proc.remote().GetLastStatus();
return status;
}
}
/// <summary>
+1 -1
View File
@@ -43,7 +43,7 @@ protected:
/// <param name="mt">Mosule type</param>
/// <param name="partial">Partial exception support</param>
/// <returns>Error code</returns>
BLACKBONE_API NTSTATUS CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType mt, bool partial );
BLACKBONE_API NTSTATUS CreateVEH( ptr_t pTargetBase, size_t imageSize, eModType mt, bool partial );
/// <summary>
/// Removes VEH from target process
+88 -56
View File
@@ -362,7 +362,7 @@ call_result_t<ModuleDataPtr> MMap::FindOrMapModule(
ldrEntry.baseAddress = pImage->imgMem.ptr();
ldrEntry.size = pImage->peImage.imageSize();
BLACKBONE_TRACE( L"ManualMap: Image base allocated at 0x%p", pImage->imgMem.ptr<uintptr_t>() );
BLACKBONE_TRACE( L"ManualMap: Image base allocated at 0x%016x", pImage->imgMem.ptr() );
// Create Activation context for SxS
if (pImage->peImage.manifestID() == 0)
@@ -661,7 +661,7 @@ NTSTATUS MMap::RelocateImage( ImageContext* pImage )
BLACKBONE_TRACE( L"ManualMap: Relocating image '%ls'", pImage->ldrEntry.fullPath.c_str() );
// Reloc delta
uintptr_t Delta = pImage->imgMem.ptr<uintptr_t>() - static_cast<uintptr_t>(pImage->peImage.imageBase());
ptr_t Delta = pImage->imgMem.ptr() - pImage->peImage.imageBase();
// No need to relocate
if (Delta == 0)
@@ -681,6 +681,10 @@ NTSTATUS MMap::RelocateImage( ImageContext* pImage )
return STATUS_INVALID_IMAGE_FORMAT;
}
size_t size = sizeof( ptr_t );
if (pImage->ldrEntry.type == mt_mod32)
size = sizeof( uint32_t );
while ((uintptr_t)fixrec < end && fixrec->BlockSize)
{
DWORD count = (fixrec->BlockSize - 8) >> 1; // records count
@@ -698,14 +702,15 @@ NTSTATUS MMap::RelocateImage( ImageContext* pImage )
if (fixtype == IMAGE_REL_BASED_HIGHLOW || fixtype == IMAGE_REL_BASED_DIR64)
{
uintptr_t fixRVA = fixoffset + fixrec->PageRVA;
uintptr_t val = *reinterpret_cast<uintptr_t*>(pImage->peImage.ResolveRVAToVA( fixoffset + fixrec->PageRVA )) + Delta;
ptr_t val = pImage->peImage.ResolveRVAToVA( fixoffset + fixrec->PageRVA );
val = pImage->ldrEntry.type == mt_mod64 ? *reinterpret_cast<uint64_t*>(val) : *reinterpret_cast<uint32_t*>(val);
val += Delta;
auto status = STATUS_SUCCESS;
if (pImage->flags & HideVAD)
status = Driver().WriteMem( _process.pid(), pImage->imgMem.ptr() + fixRVA, sizeof( val ), &val );
status = Driver().WriteMem( _process.pid(), pImage->imgMem.ptr() + fixRVA, size, &val );
else
status = pImage->imgMem.Write( fixRVA, val );
status = pImage->imgMem.Write( fixRVA, size, &val );
// Apply relocation
if (!NT_SUCCESS( status ))
@@ -744,11 +749,17 @@ call_result_t<ModuleDataPtr> MMap::FindOrMapDependency( ImageContext* pImage, st
BLACKBONE_TRACE( L"ManualMap: Loading new dependency '%ls'", path.c_str() );
auto flags = NameResolve::EnsureFullPath;
// Wow64 fs redirection
if (pImage->ldrEntry.type == mt_mod32 && !_process.barrier().sourceWow64)
flags = static_cast<NameResolve::eResolveFlag>(static_cast<int32_t>(flags) | NameResolve::Wow64);
auto basedir = pImage->peImage.noPhysFile() ? Utils::GetExeDirectory() : Utils::GetParent( pImage->ldrEntry.fullPath );
auto status = NameResolve::Instance().ResolvePath(
path, pImage->ldrEntry.name,
basedir,
NameResolve::EnsureFullPath,
path,
pImage->ldrEntry.name,
basedir, flags,
_process.pid(),
pImage->peImage.actx()
);
@@ -803,6 +814,10 @@ NTSTATUS MMap::ResolveImport( ImageContext* pImage, bool useDelayed /*= false */
if (imports.empty())
return STATUS_SUCCESS;
auto entrySize = sizeof( uint32_t );
if (pImage->ldrEntry.type == mt_mod64)
entrySize = sizeof( uint64_t );
// Traverse entries
for (auto& importMod : imports)
{
@@ -864,12 +879,9 @@ NTSTATUS MMap::ResolveImport( ImageContext* pImage, bool useDelayed /*= false */
auto status = STATUS_SUCCESS;
if (pImage->flags & HideVAD)
{
uintptr_t address = static_cast<uintptr_t>(expData->procAddress);
status = Driver().WriteMem( _process.pid(), pImage->imgMem.ptr() + importFn.ptrRVA, sizeof( address ), &address );
}
status = Driver().WriteMem( _process.pid(), pImage->imgMem.ptr() + importFn.ptrRVA, entrySize, &expData->procAddress );
else
status = pImage->imgMem.Write( importFn.ptrRVA, static_cast<uintptr_t>(expData->procAddress) );
status = pImage->imgMem.Write( importFn.ptrRVA, entrySize, &expData->procAddress );
// Write function address
if (!NT_SUCCESS( status ))
@@ -1012,44 +1024,54 @@ NTSTATUS MMap::InitStaticTLS( ImageContext* pImage )
/// <returns>Status code</returns>
NTSTATUS MMap::InitializeCookie( ImageContext* pImage )
{
auto pLoadConfig = reinterpret_cast<PIMAGE_LOAD_CONFIG_DIRECTORY>(pImage->peImage.DirectoryAddress( IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG ));
auto pLoadConfig32 = reinterpret_cast<PIMAGE_LOAD_CONFIG_DIRECTORY32>(pImage->peImage.DirectoryAddress( IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG ));
auto pLoadConfig64 = reinterpret_cast<PIMAGE_LOAD_CONFIG_DIRECTORY64>(pLoadConfig32);
ptr_t pCookie = pLoadConfig32->SecurityCookie;
if (pImage->ldrEntry.type == mt_mod64)
pCookie = pLoadConfig64->SecurityCookie;
//
// Cookie generation based on MSVC++ compiler
//
if (pLoadConfig && pLoadConfig->SecurityCookie)
if (pLoadConfig32 && pCookie)
{
BLACKBONE_TRACE( L"ManualMap: Performing security cookie initializtion for image '%ls'", pImage->ldrEntry.name.c_str() );
FILETIME systime = { 0 };
LARGE_INTEGER PerformanceCount = { { 0 } };
uintptr_t cookie = 0;
size_t size = sizeof( uint32_t );
GetSystemTimeAsFileTime( &systime );
QueryPerformanceCounter( &PerformanceCount );
cookie = _process.pid() ^ _process.remote().getWorker()->id() ^ reinterpret_cast<uintptr_t>(&cookie);
ptr_t cookie = _process.pid() ^ _process.remote().getWorker()->id() ^ reinterpret_cast<uintptr_t>(&cookie);
#ifdef USE64
cookie ^= *reinterpret_cast<uint64_t*>(&systime);
cookie ^= (PerformanceCount.QuadPart << 32) ^ PerformanceCount.QuadPart;
cookie &= 0xFFFFFFFFFFFF;
if (pImage->ldrEntry.type == mt_mod64)
{
size = sizeof( uint64_t );
if (cookie == 0x2B992DDFA232)
cookie++;
#else
cookie ^= *reinterpret_cast<uint64_t*>(&systime);
cookie ^= (PerformanceCount.QuadPart << 32) ^ PerformanceCount.QuadPart;
cookie &= 0xFFFFFFFFFFFF;
cookie ^= systime.dwHighDateTime ^ systime.dwLowDateTime;
cookie ^= PerformanceCount.LowPart;
cookie ^= PerformanceCount.HighPart;
if (cookie == 0x2B992DDFA232)
cookie++;
}
else
{
cookie &= 0xFFFFFFFF;
cookie ^= systime.dwHighDateTime ^ systime.dwLowDateTime;
cookie ^= PerformanceCount.LowPart;
cookie ^= PerformanceCount.HighPart;
if (cookie == 0xBB40E64E)
cookie++;
else if (!(cookie & 0xFFFF0000))
cookie |= (cookie | 0x4711) << 16;
#endif
if (cookie == 0xBB40E64E)
cookie++;
else if (!(cookie & 0xFFFF0000))
cookie |= (cookie | 0x4711) << 16;
}
return _process.memory().Write( REBASE( pLoadConfig->SecurityCookie, pImage->peImage.imageBase(), pImage->imgMem.ptr<ptr_t>() ), cookie );
return _process.memory().Write( REBASE( pCookie, pImage->peImage.imageBase(), pImage->imgMem.ptr() ), size, &cookie );
}
return STATUS_SUCCESS;
@@ -1106,7 +1128,7 @@ call_result_t<uint64_t> MMap::RunModuleInitializers( ImageContext* pImage, DWORD
if (!( pImage->flags & NoTLS ))
for (auto& pCallback : pImage->tlsCallbacks)
{
BLACKBONE_TRACE( L"ManualMap: Calling TLS callback at 0x%p for '%ls', Reason: %d",
BLACKBONE_TRACE( L"ManualMap: Calling TLS callback at 0x%016llx for '%ls', Reason: %d",
pCallback, pImage->ldrEntry.name.c_str(), dwReason );
a->GenCall( pCallback, { pImage->imgMem.ptr(), dwReason, customArgumentsAddress } );
@@ -1134,7 +1156,7 @@ call_result_t<uint64_t> MMap::RunModuleInitializers( ImageContext* pImage, DWORD
if (!( pImage->flags & NoTLS ))
for (auto& pCallback : pImage->tlsCallbacks)
{
BLACKBONE_TRACE( L"ManualMap: Calling TLS callback at 0x%p for '%ls', Reason: %d",
BLACKBONE_TRACE( L"ManualMap: Calling TLS callback at 0x%016llx for '%ls', Reason: %d",
pCallback, pImage->ldrEntry.name.c_str(), dwReason );
a->GenCall( pCallback, { pImage->imgMem.ptr(), dwReason, customArgumentsAddress } );
@@ -1180,7 +1202,6 @@ NTSTATUS MMap::CreateActx( const pe::PEImage& image )
NTSTATUS status = STATUS_SUCCESS;
uint64_t result = 0;
ACTCTXW act = { 0 };
auto mem = _process.memory().Allocate( 512, PAGE_READWRITE );
if (!mem)
@@ -1188,16 +1209,6 @@ NTSTATUS MMap::CreateActx( const pe::PEImage& image )
_pAContext = std::move( mem.result() );
act.cbSize = sizeof( act );
act.lpSource = reinterpret_cast<LPCWSTR>(_pAContext.ptr<uintptr_t>() + sizeof( ptr_t ) + sizeof( act ));
// Ignore some fields for pure manifest file
if (!image.noPhysFile())
{
act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
act.lpResourceName = MAKEINTRESOURCEW( image.manifestID() );
}
bool switchMode = image.mType() == mt_mod64 && _process.core().isWow64();
auto pCreateActx = _process.modules().GetExport( _process.modules().GetModule( L"kernel32.dll" ), "CreateActCtxW" );
if (!pCreateActx)
@@ -1251,8 +1262,37 @@ NTSTATUS MMap::CreateActx( const pe::PEImage& image )
// Native way
else
{
a->GenPrologue();
auto fillACTX = [this, &image]( auto&& act )
{
memset( &act, 0, sizeof( act ) );
act.cbSize = sizeof( act );
act.lpSource = static_cast<decltype(act.lpSource)>(this->_pAContext.ptr() + sizeof( ptr_t ) + sizeof( act ));
// Ignore some fields for pure manifest file
if (!image.noPhysFile())
{
act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
act.lpResourceName = static_cast<decltype(act.lpResourceName)>(image.manifestID());
}
// Write path to file
NTSTATUS status = this->_pAContext.Write( sizeof( ptr_t ), act );
status |= this->_pAContext.Write(
sizeof( ptr_t ) + sizeof( act ),
(image.manifestFile().length() + 1) * sizeof( wchar_t ),
image.manifestFile().c_str()
);
return status;
};
if (_process.core().isWow64())
status = fillACTX( _ACTCTXW32() );
else
status = fillACTX( _ACTCTXW64() );
a->GenPrologue();
a->GenCall( pCreateActx->procAddress, { _pAContext.ptr() + sizeof( ptr_t ) } );
(*a)->mov( (*a)->zdx, _pAContext.ptr() );
@@ -1261,14 +1301,6 @@ NTSTATUS MMap::CreateActx( const pe::PEImage& image )
_process.remote().AddReturnWithEvent( *a );
a->GenEpilogue();
// Write path to file
_pAContext.Write( sizeof( ptr_t ), act );
_pAContext.Write(
sizeof( ptr_t ) + sizeof(act),
(image.manifestFile().length() + 1) * sizeof(wchar_t),
image.manifestFile().c_str()
);
status = _process.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result );
if (!NT_SUCCESS( status ))
return status;
+201 -210
View File
@@ -32,7 +32,6 @@ bool NtLdr::Init()
if (IsWindows8OrGreater())
FindLdrpModuleIndexBase();
ScanPatterns();
_nodeMap.clear();
// Report errors
@@ -64,41 +63,42 @@ bool NtLdr::CreateNTReference( NtLdrEntry& mod )
// Win 8 and higher
if (IsWindows8OrGreater())
{
ULONG hash = 0;
_LDR_DATA_TABLE_ENTRY_W8 *pEntry = InitW8Node( mod );
_nodeMap.emplace( std::make_pair( mod.baseAddress, pEntry ) );
ptr_t entry = InitW8Node( mod );
_nodeMap.emplace( std::make_pair( mod.baseAddress, entry ) );
// Insert into LdrpHashTable
if (mod.flags & Ldr_HashTable)
InsertHashNode( GET_FIELD_PTR( pEntry, HashLinks ), hash );
InsertHashNode( fieldPtr( entry, &_LDR_DATA_TABLE_ENTRY_W8::HashLinks ), mod.hash );
// Insert into module graph
if (mod.flags & Ldr_ModList)
InsertTreeNode( pEntry, mod );
InsertTreeNode( entry, mod );
if (mod.flags & Ldr_ThdCall)
{
_process.memory().Write( GET_FIELD_PTR( pEntry, Flags ), 0x80004 );
InsertMemModuleNode( 0, GET_FIELD_PTR( pEntry, InLoadOrderLinks ),
GET_FIELD_PTR( pEntry, InInitializationOrderLinks ) );
_process.memory().Write( fieldPtr( entry, &_LDR_DATA_TABLE_ENTRY_W8::Flags ), 0x80004 );
InsertMemModuleNode<DWORD_PTR>(
0,
fieldPtr( entry, &_LDR_DATA_TABLE_ENTRY_W8::InLoadOrderLinks ),
fieldPtr( entry, &_LDR_DATA_TABLE_ENTRY_W8::InInitializationOrderLinks )
);
}
}
// Windows 7 and earlier
else
{
ULONG hash = 0;
_LDR_DATA_TABLE_ENTRY_W7 *pEntry = InitW7Node( mod );
_nodeMap.emplace( std::make_pair( mod.baseAddress, pEntry ) );
_nodeMap.emplace( std::make_pair( mod.baseAddress, reinterpret_cast<ptr_t>(pEntry) ) );
// Insert into LdrpHashTable
if (mod.flags & Ldr_HashTable)
InsertHashNode( GET_FIELD_PTR( pEntry, HashLinks ), hash );
InsertHashNode( GET_FIELD_PTR( pEntry, HashLinks ), mod.hash );
// Insert into LDR list
if (mod.flags & (Ldr_ModList | Ldr_ThdCall))
{
_process.memory().Write( GET_FIELD_PTR( pEntry, Flags ), 0x80004 );
InsertMemModuleNode( 0, GET_FIELD_PTR( pEntry, InLoadOrderLinks ), 0 );
InsertMemModuleNode<DWORD_PTR>( 0, GET_FIELD_PTR( pEntry, InLoadOrderLinks ), 0 );
}
}
@@ -111,16 +111,16 @@ bool NtLdr::CreateNTReference( NtLdrEntry& mod )
/// <param name="ptr">node pointer (if nullptr - new dummy node is allocated)</param>
/// <param name="pModule">Module base address</param>
/// <returns>Node address</returns>
template<typename T>
T* NtLdr::SetNode( T* ptr, void* pModule )
template<typename T, typename T2>
ptr_t NtLdr::SetNode( ptr_t ptr, T2 pModule )
{
if(ptr == nullptr)
if(ptr == 0)
{
auto mem = _process.memory().Allocate( sizeof( T ), PAGE_READWRITE, 0, false );
if (!mem)
return nullptr;
return 0;
ptr = mem->ptr<T*>();
ptr = mem->ptr();
mem->Write( FIELD_OFFSET2( T*, DllBase ), pModule );
}
@@ -136,20 +136,29 @@ T* NtLdr::SetNode( T* ptr, void* pModule )
NTSTATUS NtLdr::AddStaticTLSEntry( NtLdrEntry& mod, IMAGE_TLS_DIRECTORY *pTls )
{
bool wxp = IsWindowsXPOrGreater() && !IsWindowsVistaOrGreater();
void* pNode = _nodeMap.count( mod.baseAddress ) ? _nodeMap[mod.baseAddress] : nullptr;
ptr_t pNode = _nodeMap.count( mod.baseAddress ) ? _nodeMap[mod.baseAddress] : 0;
// Allocate appropriate structure
if ((pNode = SetNode( reinterpret_cast<PLDR_DATA_TABLE_ENTRY>(pNode), reinterpret_cast<void*>(mod.baseAddress) )) == nullptr)
ptr_t LdrpHandleTlsData = 0;
if (mod.type == mt_mod64)
{
LdrpHandleTlsData = g_PatternLoader->data().LdrpHandleTlsData64;
pNode = SetNode<_LDR_DATA_TABLE_ENTRY_BASE64>( pNode, mod.baseAddress );
}
else
{
LdrpHandleTlsData = g_PatternLoader->data().LdrpHandleTlsData32;
pNode = SetNode<_LDR_DATA_TABLE_ENTRY_BASE32>( pNode, mod.baseAddress );
}
if (pNode == 0)
return STATUS_NO_MEMORY;
// Manually add TLS table
if ((wxp || _process.barrier().type == wow_64_32) && pTls != nullptr)
if (wxp && pTls != nullptr)
{
ptr_t pTeb = 0;
if (wxp)
pTeb = _process.remote().getWorker()->teb( static_cast<_TEB32*>(nullptr) );
else
pTeb = _process.remote().getWorker()->teb( static_cast<_TEB64*>(nullptr) );
pTeb = _process.remote().getWorker()->teb( static_cast<_TEB32*>(nullptr) );
auto mem = _process.memory().Allocate( 0x1000, PAGE_READWRITE, 0, false );
if (!mem)
@@ -168,22 +177,17 @@ NTSTATUS NtLdr::AddStaticTLSEntry( NtLdrEntry& mod, IMAGE_TLS_DIRECTORY *pTls )
tlsStore.Write( 0, tlsStore.ptr<uintptr_t>() + 0x800 );
tlsStore.Write( 0x800, size, buf.get() );
if (wxp)
_process.memory().Write( pTeb + FIELD_OFFSET( _TEB32, ThreadLocalStoragePointer ), tlsStore.ptr<DWORD32>() );
else
_process.memory().Write( pTeb + FIELD_OFFSET( _TEB64, ThreadLocalStoragePointer ), tlsStore.ptr<DWORD64>() );
return STATUS_SUCCESS;
return _process.memory().Write( pTeb + FIELD_OFFSET( _TEB32, ThreadLocalStoragePointer ), tlsStore.ptr<uint32_t>() );
}
// Use native method
if (_LdrpHandleTlsData)
if (LdrpHandleTlsData)
{
auto a = AsmFactory::GetAssembler( mod.type );
uint64_t result = 0;
a->GenPrologue();
a->GenCall( _LdrpHandleTlsData, { reinterpret_cast<uintptr_t>(pNode) }, IsWindows8Point1OrGreater() ? cc_thiscall : cc_stdcall );
a->GenCall( LdrpHandleTlsData, { pNode }, IsWindows8Point1OrGreater() ? cc_thiscall : cc_stdcall );
_process.remote().AddReturnWithEvent( *a );
a->GenEpilogue();
@@ -197,6 +201,7 @@ NTSTATUS NtLdr::AddStaticTLSEntry( NtLdrEntry& mod, IMAGE_TLS_DIRECTORY *pTls )
return STATUS_ORDINAL_NOT_FOUND;
}
/// <summary>
/// Create module record in LdrpInvertedFunctionTable
/// Used to create fake SAFESEH entries
@@ -205,84 +210,109 @@ NTSTATUS NtLdr::AddStaticTLSEntry( NtLdrEntry& mod, IMAGE_TLS_DIRECTORY *pTls )
/// <returns>true on success</returns>
bool NtLdr::InsertInvertedFunctionTable( NtLdrEntry& mod )
{
RTL_INVERTED_FUNCTION_TABLE7 table = { 0 };
PRTL_INVERTED_FUNCTION_TABLE_ENTRY Entries = nullptr;
uint64_t result = 0;
auto a = AsmFactory::GetAssembler( mod.type );
auto& memory = _process.memory();
// Invalid addresses. Probably pattern scan has failed
if (_RtlInsertInvertedFunctionTable == 0 || _LdrpInvertedFunctionTable == 0)
return false;
if (IsWindows8OrGreater())
Entries = reinterpret_cast<decltype(Entries)>(GET_FIELD_PTR( reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE8>(&table), Entries ));
else
Entries = reinterpret_cast<decltype(Entries)>(GET_FIELD_PTR( &table, Entries ));
//
// Try to find module address in table.
// If found - no additional work is required.
//
memory.Read( _LdrpInvertedFunctionTable, sizeof( table ), &table );
for (ULONG i = 0; i < table.Count; i++)
if (reinterpret_cast<ptr_t>(Entries[i].ImageBase) == mod.baseAddress)
return true;
a->GenPrologue();
if (IsWindows8Point1OrGreater())
a->GenCall( _RtlInsertInvertedFunctionTable, { mod.baseAddress, mod.size }, cc_fastcall );
else if (IsWindows8OrGreater())
a->GenCall( _RtlInsertInvertedFunctionTable, { mod.baseAddress, mod.size } );
else
a->GenCall( _RtlInsertInvertedFunctionTable, { _LdrpInvertedFunctionTable, mod.baseAddress, mod.size } );
_process.remote().AddReturnWithEvent( *a );
a->GenEpilogue();
_process.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result );
memory.Read( _LdrpInvertedFunctionTable, sizeof( table ), &table );
for(DWORD i = 0; i < table.Count; i++)
ptr_t RtlInsertInvertedFunctionTable = g_PatternLoader->data().RtlInsertInvertedFunctionTable64;
ptr_t LdrpInvertedFunctionTable = g_PatternLoader->data().LdrpInvertedFunctionTable64;
if (mod.type == mt_mod32)
{
if (reinterpret_cast<ptr_t>(Entries[i].ImageBase) != mod.baseAddress)
continue;
// If Image has SAFESEH, RtlInsertInvertedFunctionTable is enough
if (Entries[i].SizeOfTable != 0)
return mod.safeSEH = true;
//
// Create fake Exception directory
// Directory will be filled later, during exception handling
//
PIMAGE_RUNTIME_FUNCTION_ENTRY pImgEntry = nullptr;
// Allocate memory for 512 possible handlers
auto mem = memory.Allocate( sizeof( DWORD ) * 0x200, PAGE_READWRITE, 0, false );
if (!mem)
return false;
pImgEntry = mem->ptr<decltype(pImgEntry)>();
auto pEncoded = EncodeSystemPointer( pImgEntry );
// m_LdrpInvertedFunctionTable->Entries[i].ExceptionDirectory
uintptr_t field_ofst = reinterpret_cast<uintptr_t>(&Entries[i].ExceptionDirectory)
- reinterpret_cast<uintptr_t>(&table);
// In Win10 _LdrpInvertedFunctionTable is located in mrdata section
// mrdata is read-only by default
// LdrProtectMrdata is used to make it writable when needed
DWORD flOld = 0;
memory.Protect( _LdrpInvertedFunctionTable + field_ofst, sizeof( uintptr_t ), PAGE_EXECUTE_READWRITE, &flOld );
auto status = memory.Write( _LdrpInvertedFunctionTable + field_ofst, pEncoded );
memory.Protect( _LdrpInvertedFunctionTable + field_ofst, sizeof( uintptr_t ), flOld, &flOld );
return NT_SUCCESS( status );
RtlInsertInvertedFunctionTable = g_PatternLoader->data().RtlInsertInvertedFunctionTable32;
LdrpInvertedFunctionTable = g_PatternLoader->data().LdrpInvertedFunctionTable32;
}
return false;
// Invalid addresses. Probably pattern scan has failed
if (RtlInsertInvertedFunctionTable == 0 || LdrpInvertedFunctionTable == 0)
return false;
auto InsertP = [&]( auto&& table )
{
uint64_t result = 0;
auto a = AsmFactory::GetAssembler( mod.type );
auto& memory = _process.memory();
memory.Read( LdrpInvertedFunctionTable, sizeof( table ), &table );
for (ULONG i = 0; i < table.Count; i++)
if (table.Entries[i].ImageBase == mod.baseAddress)
return true;
a->GenPrologue();
if (IsWindows8Point1OrGreater())
a->GenCall( RtlInsertInvertedFunctionTable, { mod.baseAddress, mod.size }, cc_fastcall );
else if (IsWindows8OrGreater())
a->GenCall( RtlInsertInvertedFunctionTable, { mod.baseAddress, mod.size } );
else
a->GenCall( RtlInsertInvertedFunctionTable, { LdrpInvertedFunctionTable, mod.baseAddress, mod.size } );
_process.remote().AddReturnWithEvent( *a );
a->GenEpilogue();
_process.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result );
memory.Read( LdrpInvertedFunctionTable, sizeof( table ), &table );
for (DWORD i = 0; i < table.Count; i++)
{
if (table.Entries[i].ImageBase != mod.baseAddress)
continue;
// If Image has SAFESEH, RtlInsertInvertedFunctionTable is enough
if (table.Entries[i].SizeOfTable != 0)
return mod.safeSEH = true;
//
// Create fake Exception directory
// Directory will be filled later, during exception handling
//
// Allocate memory for 2048 possible handlers
auto mem = memory.Allocate( sizeof( DWORD ) * 0x800, PAGE_READWRITE, 0, false );
if (!mem)
return false;
uint32_t size = 0;
ptr_t pEncoded = 0;
auto cookie = *reinterpret_cast<uint32_t*>(0x7FFE0330);
if (mod.type == mt_mod64)
{
size = sizeof( uint64_t );
pEncoded = _rotr64( cookie ^ mem->ptr<uint64_t>(), cookie & 0x3F );
}
else
{
size = sizeof( uint32_t );
pEncoded = _rotr( cookie ^ mem->ptr<uint32_t>(), cookie & 0x1F );
}
// m_LdrpInvertedFunctionTable->Entries[i].ExceptionDirectory
uintptr_t field_ofst = reinterpret_cast<ptr_t>(&table.Entries[i].ExceptionDirectory)
- reinterpret_cast<ptr_t>(&table);
// In Win10 LdrpInvertedFunctionTable is located in mrdata section
// mrdata is read-only by default
// LdrProtectMrdata is used to make it writable when needed
DWORD flOld = 0;
memory.Protect( LdrpInvertedFunctionTable + field_ofst, sizeof( ptr_t ), PAGE_EXECUTE_READWRITE, &flOld );
auto status = memory.Write( LdrpInvertedFunctionTable + field_ofst, size, &pEncoded );
memory.Protect( LdrpInvertedFunctionTable + field_ofst, sizeof( ptr_t ), flOld, &flOld );
return NT_SUCCESS( status );
}
return false;
};
if (IsWindows8OrGreater())
{
if(mod.type == mt_mod64)
return InsertP( _RTL_INVERTED_FUNCTION_TABLE8<DWORD64>() );
else
return InsertP( _RTL_INVERTED_FUNCTION_TABLE8<DWORD>() );
}
else
{
if (mod.type == mt_mod64)
return InsertP( _RTL_INVERTED_FUNCTION_TABLE7<DWORD64>() );
else
return InsertP( _RTL_INVERTED_FUNCTION_TABLE7<DWORD>() );
}
}
/// <summary>
@@ -290,82 +320,71 @@ bool NtLdr::InsertInvertedFunctionTable( NtLdrEntry& mod )
/// </summary>
/// <param name="mod">Module data</param>
/// <returns>Pointer to created entry</returns>
_LDR_DATA_TABLE_ENTRY_W8* NtLdr::InitW8Node( NtLdrEntry& mod )
ptr_t NtLdr::InitW8Node( NtLdrEntry& mod )
{
UNICODE_STRING strLocal = { 0 };
typedef _LDR_DATA_TABLE_ENTRY_W8 EntryType;
ptr_t entry = AllocateInHeap( mod.type, sizeof( EntryType ) ).result( 0 );
ptr_t pDdagNode = AllocateInHeap( mod.type, sizeof( _LDR_DDAG_NODE ) ).result( 0 );
if (!entry || !pDdagNode)
return 0;
// Allocate space for Unicode string
UNICODE_STRING strLocal = { 0 };
auto mem = _process.memory().Allocate( 0x1000, PAGE_READWRITE, 0, false );
if (!mem)
return nullptr;
return 0;
auto StringBuf = std::move( mem.result() );
_LDR_DATA_TABLE_ENTRY_W8* pEntry = reinterpret_cast<decltype(pEntry)>(AllocateInHeap(
mod.type, sizeof( *pEntry )
).result( 0 ));
if(pEntry)
{
_LDR_DDAG_NODE* pDdagNode = reinterpret_cast<decltype(pDdagNode)>(AllocateInHeap(
mod.type, sizeof( *pDdagNode )
).result(0));
// pEntry->DllBase = ModuleBase;
_process.memory().Write( fieldPtr( entry, &EntryType::DllBase ), static_cast<uintptr_t>(mod.baseAddress) );
if(pDdagNode)
{
// pEntry->DllBase = ModuleBase;
_process.memory().Write( GET_FIELD_PTR( pEntry, DllBase ), static_cast<uintptr_t>(mod.baseAddress) );
// pEntry->SizeOfImage = ImageSize;
_process.memory().Write( fieldPtr( entry, &EntryType::SizeOfImage ), mod.size );
// pEntry->SizeOfImage = ImageSize;
_process.memory().Write( GET_FIELD_PTR( pEntry, SizeOfImage ), mod.size );
// pEntry->EntryPoint = entryPoint;
_process.memory().Write( fieldPtr( entry, &EntryType::EntryPoint ), static_cast<uintptr_t>(mod.entryPoint) );
// pEntry->EntryPoint = entryPoint;
_process.memory().Write( GET_FIELD_PTR( pEntry, EntryPoint ), static_cast<uintptr_t>(mod.entryPoint) );
// Dll name and name hash
SAFE_CALL( RtlInitUnicodeString, &strLocal, mod.name.c_str() );
mod.hash = HashString( mod.name );
// Dll name and name hash
SAFE_CALL( RtlInitUnicodeString, &strLocal, mod.name.c_str() );
mod.hash = HashString( mod.name );
// Write into buffer
strLocal.Buffer = StringBuf.ptr<PWSTR>();
StringBuf.Write( 0, mod.name.length() * sizeof( wchar_t ) + 2, mod.name.c_str() );
// Write into buffer
strLocal.Buffer = StringBuf.ptr<PWSTR>();
StringBuf.Write( 0, mod.name.length() * sizeof(wchar_t) + 2, mod.name.c_str() );
// pEntry->BaseDllName = strLocal;
_process.memory().Write( fieldPtr( entry, &EntryType::BaseDllName ), strLocal );
// pEntry->BaseDllName = strLocal;
_process.memory().Write( GET_FIELD_PTR( pEntry, BaseDllName ), strLocal );
// Dll full path
SAFE_CALL( RtlInitUnicodeString, &strLocal, mod.fullPath.c_str() );
strLocal.Buffer = reinterpret_cast<PWSTR>(StringBuf.ptr<uint8_t*>() + 0x800);
StringBuf.Write( 0x800, mod.fullPath.length() * sizeof( wchar_t ) + 2, mod.fullPath.c_str() );
// Dll full path
SAFE_CALL( RtlInitUnicodeString, &strLocal, mod.fullPath.c_str() );
strLocal.Buffer = reinterpret_cast<PWSTR>(StringBuf.ptr<uint8_t*>() + 0x800);
StringBuf.Write( 0x800, mod.fullPath.length() * sizeof(wchar_t) + 2, mod.fullPath.c_str() );
// pEntry->FullDllName = strLocal;
_process.memory().Write( GET_FIELD_PTR( pEntry, FullDllName ), strLocal );
// pEntry->FullDllName = strLocal;
_process.memory().Write( fieldPtr( entry, &EntryType::FullDllName ), strLocal );
// pEntry->BaseNameHashValue = hash;
_process.memory().Write( GET_FIELD_PTR( pEntry, BaseNameHashValue ), mod.hash );
// pEntry->BaseNameHashValue = hash;
_process.memory().Write( fieldPtr( entry, &EntryType::BaseNameHashValue ), mod.hash );
//
// Ddag node
//
//
// Ddag node
//
// pEntry->DdagNode = pDdagNode;
_process.memory().Write( GET_FIELD_PTR( pEntry, DdagNode ), pDdagNode );
// pEntry->DdagNode = pDdagNode;
_process.memory().Write( fieldPtr( entry, &EntryType::DdagNode ), pDdagNode );
// pDdagNode->State = LdrModulesReadyToRun;
_process.memory().Write( GET_FIELD_PTR( pDdagNode, State ), LdrModulesReadyToRun );
// pDdagNode->State = LdrModulesReadyToRun;
_process.memory().Write( fieldPtr( pDdagNode, &_LDR_DDAG_NODE::State ), LdrModulesReadyToRun );
// pDdagNode->ReferenceCount = 1;
_process.memory().Write( GET_FIELD_PTR( pDdagNode, ReferenceCount ), 1 );
// pDdagNode->ReferenceCount = 1;
_process.memory().Write( fieldPtr( pDdagNode, &_LDR_DDAG_NODE::ReferenceCount ), 1 );
// pDdagNode->LoadCount = -1;
_process.memory().Write( GET_FIELD_PTR( pDdagNode, LoadCount ), -1 );
// pDdagNode->LoadCount = -1;
_process.memory().Write( fieldPtr( pDdagNode, &_LDR_DDAG_NODE::LoadCount ), -1 );
return pEntry;
}
return nullptr;
}
return nullptr;
return entry;
}
/// <summary>
@@ -438,7 +457,7 @@ _LDR_DATA_TABLE_ENTRY_W7* NtLdr::InitW7Node( NtLdrEntry& mod )
/// </summary>
/// <param name="pNode">Node to insert</param>
/// <param name="mod">Module data</param>
void NtLdr::InsertTreeNode( _LDR_DATA_TABLE_ENTRY_W8* pNode, const NtLdrEntry& mod )
void NtLdr::InsertTreeNode( ptr_t pNode, const NtLdrEntry& mod )
{
//
// Win8 module tree
@@ -503,9 +522,9 @@ void NtLdr::InsertTreeNode( _LDR_DATA_TABLE_ENTRY_W8* pNode, const NtLdrEntry& m
a->GenCall( static_cast<uintptr_t>(RtlRbInsertNodeEx->procAddress),
{
_LdrpModuleIndexBase,
GET_FIELD_PTR( pLdrNode, BaseAddressIndexNode ),
fieldPtr( (ptr_t)pLdrNode, &_LDR_DATA_TABLE_ENTRY_W8::BaseAddressIndexNode ),
static_cast<uintptr_t>(bRight),
GET_FIELD_PTR( pNode, BaseAddressIndexNode )
fieldPtr( (ptr_t)pNode, &_LDR_DATA_TABLE_ENTRY_W8::BaseAddressIndexNode )
} );
_process.remote().AddReturnWithEvent( *a, mod.type );
@@ -519,27 +538,28 @@ void NtLdr::InsertTreeNode( _LDR_DATA_TABLE_ENTRY_W8* pNode, const NtLdrEntry& m
/// </summary>
/// <param name="pNodeMemoryOrderLink">InMemoryOrderModuleList link of entry to be inserted</param>
/// <param name="pNodeLoadOrderLink">InLoadOrderModuleList link of entry to be inserted</param>
void NtLdr::InsertMemModuleNode( uintptr_t pNodeMemoryOrderLink, uintptr_t pNodeLoadOrderLink, uintptr_t pNodeInitOrderLink )
template<typename T>
void NtLdr::InsertMemModuleNode( ptr_t pNodeMemoryOrderLink, ptr_t pNodeLoadOrderLink, ptr_t pNodeInitOrderLink )
{
PEB_T* pPeb = reinterpret_cast<PEB_T*>(_process.core().peb());
PEB_LDR_DATA_T* pLdr = nullptr;
ptr_t pPeb = _process.core().peb( (_PEB_T2<T>::type*)nullptr );
ptr_t pLdr = 0;
if (pPeb)
pLdr = _process.memory().Read<PEB_LDR_DATA_T*>( GET_FIELD_PTR( pPeb, Ldr ) ).result( nullptr );
pLdr = _process.memory().Read<T>( fieldPtr( pPeb, &PEB_T::Ldr ) ).result( 0 );
if (pLdr)
{
// pLdr->InMemoryOrderModuleList
if (pNodeMemoryOrderLink)
InsertTailList( GET_FIELD_PTR( pLdr, InMemoryOrderModuleList ), pNodeMemoryOrderLink );
InsertTailList<T>( fieldPtr( pLdr, &_PEB_LDR_DATA2<T>::InMemoryOrderModuleList ), pNodeMemoryOrderLink );
// pLdr->InLoadOrderModuleList
if (pNodeLoadOrderLink)
InsertTailList( GET_FIELD_PTR( pLdr, InLoadOrderModuleList ), pNodeLoadOrderLink );
InsertTailList<T>( fieldPtr( pLdr, &_PEB_LDR_DATA2<T>::InLoadOrderModuleList ), pNodeLoadOrderLink );
// pLdr->InInitializationOrderModuleList
if (pNodeInitOrderLink)
InsertTailList( GET_FIELD_PTR( pLdr, InInitializationOrderModuleList ), pNodeInitOrderLink );
InsertTailList<T>( fieldPtr( pLdr, &_PEB_LDR_DATA2<T>::InInitializationOrderModuleList ), pNodeInitOrderLink );
}
}
@@ -548,14 +568,14 @@ void NtLdr::InsertMemModuleNode( uintptr_t pNodeMemoryOrderLink, uintptr_t pNode
/// </summary>
/// <param name="pNodeLink">Link of entry to be inserted</param>
/// <param name="hash">Module hash</param>
void NtLdr::InsertHashNode( uintptr_t pNodeLink, ULONG hash )
void NtLdr::InsertHashNode( ptr_t pNodeLink, ULONG hash )
{
if(pNodeLink)
{
// LrpHashTable record
auto pHashList = _process.memory().Read<uintptr_t>( _LdrpHashTable + sizeof(LIST_ENTRY)*(hash & 0x1F) );
if(pHashList)
InsertTailList( pHashList.result(), pNodeLink );
InsertTailList<DWORD_PTR>( pHashList.result(), pNodeLink );
}
}
@@ -564,20 +584,21 @@ void NtLdr::InsertHashNode( uintptr_t pNodeLink, ULONG hash )
/// </summary>
/// <param name="ListHead">List head pointer</param>
/// <param name="Entry">Entry list link to be inserted</param>
void NtLdr::InsertTailList( uintptr_t ListHead, uintptr_t Entry )
template<typename T>
void NtLdr::InsertTailList( ptr_t ListHead, ptr_t Entry )
{
// PrevEntry = ListHead->Blink;
auto PrevEntry = _process.memory().Read<uintptr_t>( GET_FIELD_PTR( reinterpret_cast<PLIST_ENTRY>(ListHead), Blink ) ).result( 0 );
auto PrevEntry = _process.memory().Read<T>( fieldPtr( ListHead, &_LIST_ENTRY_T<T>::Blink ) ).result( 0 );
// Entry->Flink = ListHead;
// Entry->Blink = PrevEntry;
_process.memory().Write( GET_FIELD_PTR( reinterpret_cast<PLIST_ENTRY>(Entry), Flink ), ListHead );
_process.memory().Write( GET_FIELD_PTR( reinterpret_cast<PLIST_ENTRY>(Entry), Blink ), PrevEntry );
_process.memory().Write( fieldPtr( Entry, &_LIST_ENTRY_T<T>::Flink ), sizeof(T), &ListHead );
_process.memory().Write( fieldPtr( Entry, &_LIST_ENTRY_T<T>::Blink ), sizeof( T ), &PrevEntry );
// PrevEntry->Flink = Entry;
// ListHead->Blink = Entry;
_process.memory().Write( GET_FIELD_PTR( reinterpret_cast<PLIST_ENTRY>(PrevEntry), Flink ), Entry );
_process.memory().Write( GET_FIELD_PTR( reinterpret_cast<PLIST_ENTRY>(ListHead), Blink ), Entry );
_process.memory().Write( fieldPtr( PrevEntry, &_LIST_ENTRY_T<T>::Flink ), sizeof( T ), &Entry );
_process.memory().Write( fieldPtr( ListHead, &_LIST_ENTRY_T<T>::Blink ), sizeof( T ), &Entry );
}
/// <summary>
@@ -735,36 +756,6 @@ bool NtLdr::FindLdrpModuleIndexBase()
return false;
}
/// <summary>
/// Search for RtlInsertInvertedFunctionTable, LdrpInvertedFunctionTable, LdrpHandleTlsData.
/// </summary>
/// <returns>true on success</returns>
bool NtLdr::ScanPatterns( )
{
auto& data = g_PatternLoader->data();
_LdrKernel32PatchAddress = static_cast<uintptr_t>(data.LdrKernel32PatchAddress);
_APC64PatchAddress = static_cast<uintptr_t>(data.APC64PatchAddress);
_LdrProtectMrdata = static_cast<uintptr_t>(data.LdrProtectMrdata);
if (_process.core().isWow64())
{
_LdrpHandleTlsData = static_cast<uintptr_t>(data.LdrpHandleTlsData32);
_LdrpInvertedFunctionTable = static_cast<uintptr_t>(data.LdrpInvertedFunctionTable32);
_RtlInsertInvertedFunctionTable = static_cast<uintptr_t>(data.RtlInsertInvertedFunctionTable32);
}
else
{
_LdrpHandleTlsData = static_cast<uintptr_t>(data.LdrpHandleTlsData64);
_LdrpInvertedFunctionTable = static_cast<uintptr_t>(data.LdrpInvertedFunctionTable64);
_RtlInsertInvertedFunctionTable = static_cast<uintptr_t>(data.RtlInsertInvertedFunctionTable64);
}
return true;
}
/// <summary>
/// Find Loader heap base
/// </summary>
+15 -34
View File
@@ -70,16 +70,7 @@ public:
/// </summary>
/// <param name="mod">Module data</param>
/// <returns>true on success</returns>
BLACKBONE_API bool Unlink( const ModuleData& mod );
//
// Get some not exported values
//
BLACKBONE_API inline uintptr_t LdrpInvertedFunctionTable( ) const { return _LdrpInvertedFunctionTable; }
BLACKBONE_API inline uintptr_t LdrKernel32PatchAddress() const { return _LdrKernel32PatchAddress; }
BLACKBONE_API inline uintptr_t APC64PatchAddress() const { return _APC64PatchAddress; }
BLACKBONE_API inline uintptr_t LdrProtectMrdata() const { return _LdrProtectMrdata; }
BLACKBONE_API bool Unlink( const ModuleData& mod );
private:
/// <summary>
@@ -94,12 +85,6 @@ private:
/// <returns>true on success</returns>
bool FindLdrpModuleIndexBase();
/// <summary>
/// Search for RtlInsertInvertedFunctionTable, LdrpInvertedFunctionTable, LdrpHandleTlsDatas.
/// </summary>
/// <returns>true on success</returns>
bool ScanPatterns();
/// <summary>
/// Find Loader heap base
/// </summary>
@@ -111,7 +96,7 @@ private:
/// </summary>
/// <param name="mod">Module data</param>
/// <returns>Pointer to created entry</returns>
_LDR_DATA_TABLE_ENTRY_W8* InitW8Node( NtLdrEntry& mod );
ptr_t InitW8Node( NtLdrEntry& mod );
/// <summary>
/// Initialize OS-specific module entry
@@ -125,28 +110,30 @@ private:
/// </summary>
/// <param name="pNode">Node to insert</param>
/// <param name="mod">Module data</param>
void InsertTreeNode( _LDR_DATA_TABLE_ENTRY_W8* pNode, const NtLdrEntry& mod );
void InsertTreeNode( ptr_t pNode, const NtLdrEntry& mod );
/// <summary>
/// Insert entry into LdrpHashTable[]
/// </summary>
/// <param name="pNodeLink">Link of entry to be inserted</param>
/// <param name="hash">Module hash</param>
void InsertHashNode( uintptr_t pNodeLink, ULONG hash );
void InsertHashNode( ptr_t pNodeLink, ULONG hash );
/// <summary>
/// Insert entry into InLoadOrderModuleList and InMemoryOrderModuleList
/// </summary>
/// <param name="pNodeMemoryOrderLink">InMemoryOrderModuleList link of entry to be inserted</param>
/// <param name="pNodeLoadOrderLink">InLoadOrderModuleList link of entry to be inserted</param>
void InsertMemModuleNode( uintptr_t pNodeMemoryOrderLink, uintptr_t pNodeLoadOrderLink, uintptr_t pNodeInitOrderLink );
template<typename T>
void InsertMemModuleNode( ptr_t pNodeMemoryOrderLink, ptr_t pNodeLoadOrderLink, ptr_t pNodeInitOrderLink );
/// <summary>
/// Insert entry into standard double linked list
/// </summary>
/// <param name="ListHead">List head pointer</param>
/// <param name="Entry">Entry list link to be inserted</param>
void InsertTailList( uintptr_t ListHead, uintptr_t Entry );
template<typename T>
void InsertTailList( ptr_t ListHead, ptr_t Entry );
/// <summary>
/// Hash image name
@@ -169,8 +156,8 @@ private:
/// <param name="ptr">node pointer (if nullptr - new dummy node is allocated)</param>
/// <param name="pModule">Module base address</param>
/// <returns>Node address</returns>
template<typename T>
T* SetNode( T* ptr, void* pModule );
template<typename T, typename T2>
ptr_t SetNode( ptr_t ptr, T2 pModule );
/// <summary>
/// Unlink module from PEB_LDR_DATA
@@ -206,19 +193,13 @@ private:
NtLdr& operator =(const NtLdr&) = delete;
private:
class Process& _process; // Process memory routines
class Process& _process; // Process memory routines
uintptr_t _LdrpHashTable = 0; // LdrpHashTable address
uintptr_t _LdrpModuleIndexBase = 0; // LdrpModuleIndex address
uintptr_t _LdrHeapBase = 0; // Loader heap base address
uintptr_t _LdrKernel32PatchAddress = 0; // Address to patch to enable kernel32 loading under win7
uintptr_t _APC64PatchAddress = 0; // Address to patch for x64->WOW64 APC dispatching under win7
uintptr_t _LdrpHandleTlsData = 0; // LdrpHandleTlsData address
uintptr_t _LdrpInvertedFunctionTable = 0; // LdrpInvertedFunctionTable address
uintptr_t _RtlInsertInvertedFunctionTable = 0; // RtlInsertInvertedFunctionTable address
uintptr_t _LdrProtectMrdata = 0; // LdrProtectMrdata address
uintptr_t _LdrpHashTable = 0; // LdrpHashTable address
uintptr_t _LdrpModuleIndexBase = 0; // LdrpModuleIndex address
uintptr_t _LdrHeapBase = 0; // Loader heap base address
std::map<ptr_t, void*> _nodeMap; // Allocated native structures
std::map<ptr_t, ptr_t> _nodeMap; // Allocated native structures
};
}
+1 -1
View File
@@ -60,7 +60,7 @@ public:
/// <param name="...args">Function args</param>
/// <returns>Function result or 0 if import not found</returns>
template<typename T, typename... Args>
inline auto safeCall( const std::string& name, Args&&... args ) -> typename std::result_of<T(Args...)>::type
inline auto safeCall( const std::string& name, Args&&... args )
{
auto pfn = DynImport::get<T>( name );
return pfn ? pfn( std::forward<Args>( args )... ) : (std::result_of<T( Args... )>::type)(0);
+8 -2
View File
@@ -189,7 +189,10 @@ NTSTATUS NameResolve::ResolvePath(
dwSize = 255;
// In Win10 DllDirectory value got screwed, so less reliable method is used
GetSystemDirectoryW( sys_path, dwSize );
if (flags & Wow64)
GetSystemWow64DirectoryW( sys_path, dwSize );
else
GetSystemDirectoryW( sys_path, dwSize );
if (res == ERROR_SUCCESS)
{
@@ -232,7 +235,10 @@ NTSTATUS NameResolve::ResolvePath(
//
// 4. The system directory
//
GetSystemDirectoryW( tmpPath, ARRAYSIZE( tmpPath ) );
if (flags & Wow64)
GetSystemWow64DirectoryW( tmpPath, ARRAYSIZE( tmpPath ) );
else
GetSystemDirectoryW( tmpPath, ARRAYSIZE( tmpPath ) );
completePath = std::wstring( tmpPath ) + L"\\" + filename;
+1
View File
@@ -22,6 +22,7 @@ PEImage::PEImage( void )
PEImage::~PEImage( void )
{
Release();
}
/// <summary>
+3 -6
View File
@@ -4,6 +4,7 @@
#include "RPC/RemoteExec.h"
#include "../Misc/NameResolve.h"
#include "../Misc/Utils.h"
#include "../Misc/PattrernLoader.h"
#include "../Asm/AsmFactory.h"
#include <memory>
@@ -18,10 +19,6 @@
namespace blackbone
{
typedef std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&CloseHandle)> handlePtr;
ProcessModules::ProcessModules( class Process& proc )
: _proc( proc )
, _memory( _proc.memory() )
@@ -437,7 +434,7 @@ call_result_t<ModuleDataPtr> ProcessModules::Inject( const std::wstring& path )
if (switchMode == ForceSwitch && !_ldrPatched && IsWindows7OrGreater() && !IsWindows8OrGreater())
{
uint8_t patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
auto patchBase = _proc.nativeLdr().LdrKernel32PatchAddress();
auto patchBase = g_PatternLoader->data().LdrKernel32PatchAddress;
if (patchBase != 0)
{
@@ -870,7 +867,7 @@ bool ProcessModules::InjectPureIL(
// write JIT code to target
size_t codeSize = a->getCodeSize();
uintptr_t codeAddress = address.ptr<uintptr_t>() + offset;
ptr_t codeAddress = address.ptr() + offset;
std::vector<uint8_t> codeBuffer( codeSize );
+47 -37
View File
@@ -1,6 +1,7 @@
#include "RemoteExec.h"
#include "../Process.h"
#include "../../Misc/DynImport.h"
#include "../../Misc/PattrernLoader.h"
#include <VersionHelpers.h>
#include <sddl.h>
@@ -113,6 +114,9 @@ NTSTATUS RemoteExec::ExecInWorkerThread( PVOID pCode, size_t size, uint64_t& cal
{
NTSTATUS dwResult = STATUS_SUCCESS;
if (_proc.barrier().type == wow_64_32)
return ExecInAnyThread( pCode, size, callResult, _hWorkThd );
// Create thread if needed
CreateRPCEnvironment();
@@ -130,7 +134,7 @@ NTSTATUS RemoteExec::ExecInWorkerThread( PVOID pCode, size_t size, uint64_t& cal
{
if (_proc.barrier().type == wow_64_32)
{
auto patchBase = _proc.nativeLdr().APC64PatchAddress();
auto patchBase = g_PatternLoader->data().APC64PatchAddress;
if (patchBase != 0)
{
@@ -150,8 +154,8 @@ NTSTATUS RemoteExec::ExecInWorkerThread( PVOID pCode, size_t size, uint64_t& cal
// Execute code in thread context
// TODO: Find out why am I passing pRemoteCode as an argument???
auto pRemoteCode = _userCode.ptr<PVOID>();
if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueueApcThread, _hWorkThd->handle(), pRemoteCode, pRemoteCode, nullptr, nullptr ) ))
auto pRemoteCode = _userCode.ptr();
if (NT_SUCCESS( _proc.core().native()->NtQueueApcThreadT( _hWorkThd->handle(), pRemoteCode, pRemoteCode ) ))
{
dwResult = WaitForSingleObject( _hWaitEvent, 30 * 1000 /*wait 30s*/ );
callResult = _userData.Read<uint64_t>( RET_OFFSET, 0 );
@@ -275,7 +279,7 @@ NTSTATUS RemoteExec::ExecInAnyThread( PVOID pCode, size_t size, uint64_t& callRe
if (NT_SUCCESS( status ))
{
WaitForSingleObject( _hWaitEvent, INFINITE );
status = _userData.Read( INTRET_OFFSET, callResult );
status = _userData.Read( RET_OFFSET, callResult );
}
return status;
@@ -358,16 +362,7 @@ NTSTATUS RemoteExec::CreateRPCEnvironment( bool bThread /*= true*/, bool bEvent
// Create RPC sync event
if (bEvent)
{
if (_proc.barrier().type != wow_32_64)
{
status = CreateAPCEvent( thdID );
}
else
{
status = STATUS_NOT_SUPPORTED;
}
}
status = CreateAPCEvent( thdID );
return status;
}
@@ -386,8 +381,7 @@ call_result_t<DWORD> RemoteExec::CreateWorkerThread()
//
if(!_hWorkThd->valid())
{
eModType mt = mt_default;
if (_proc.barrier().type == wow_64_32)
/*if (_proc.barrier().type == wow_64_32)
{
a->SwitchTo64();
@@ -405,9 +399,9 @@ call_result_t<DWORD> RemoteExec::CreateWorkerThread()
(*a)->mov( (*a)->zdx, asmjit::host::dword_ptr_abs( 0x18 ).setSegment( asmjit::host::fs ) );
(*a)->mov( (*a)->intptr_ptr( (*a)->zdx, 0x2c8 ), (*a)->zax );
}
}
}*/
auto ntdll = _mods.GetModule( L"ntdll.dll", Sections, mt );
auto ntdll = _mods.GetModule( L"ntdll.dll", Sections );
auto proc = _mods.GetExport( ntdll, "NtDelayExecution" );
auto pExitThread = _mods.GetExport( ntdll, "NtTerminateThread" );
if (!proc || !pExitThread)
@@ -462,11 +456,6 @@ NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID )
OBJECT_ATTRIBUTES obAttr = { 0 };
UNICODE_STRING ustr = { 0 };
// Detect ntdll type
eModType mt = mt_default;
if (_proc.barrier().type == wow_64_32)
mt = mt_mod64;
// Event name
swprintf_s( pEventName, ARRAYSIZE( pEventName ), L"\\BaseNamedObjects\\_MMapEvent_0x%x_0x%x", threadID, GetTickCount() );
@@ -476,14 +465,14 @@ NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID )
// Prepare Arguments
ustr.Length = static_cast<USHORT>(wcslen( pEventName ) * sizeof(wchar_t));
ustr.MaximumLength = static_cast<USHORT>(sizeof(pEventName));
ustr.MaximumLength = static_cast<USHORT>(len);
ustr.Buffer = pEventName;
obAttr.ObjectName = &ustr;
obAttr.Length = sizeof(obAttr);
obAttr.SecurityDescriptor = pDescriptor;
auto pOpenEvent = _mods.GetNtdllExport( "NtOpenEvent", mt, Sections );
auto pOpenEvent = _mods.GetNtdllExport( "NtOpenEvent", mt_default, Sections );
if (!pOpenEvent)
return pOpenEvent.status;
@@ -494,9 +483,36 @@ NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID )
if (!NT_SUCCESS( status ))
return status;
ustr.Buffer = reinterpret_cast<PWSTR>(_userData.ptr<uintptr_t>() + ARGS_OFFSET + sizeof( obAttr ) + sizeof( ustr ));
obAttr.ObjectName = reinterpret_cast<PUNICODE_STRING>(_userData.ptr<uintptr_t>() + ARGS_OFFSET + sizeof(obAttr));
obAttr.SecurityDescriptor = nullptr;
auto fillAttributes = [this, len, pEventName]( auto& obAttr, auto& ustr )
{
ustr.Buffer = static_cast<decltype(ustr.Buffer)>(this->_userData.ptr() + ARGS_OFFSET + sizeof( obAttr ) + sizeof( ustr ));
ustr.Length = static_cast<USHORT>(wcslen( pEventName ) * sizeof( wchar_t ));
ustr.MaximumLength = static_cast<USHORT>(len);
obAttr.Length = sizeof( obAttr );
obAttr.ObjectName = static_cast<decltype(obAttr.ObjectName)>(this->_userData.ptr() + ARGS_OFFSET + sizeof( obAttr ));
NTSTATUS status = this->_userData.Write( ARGS_OFFSET, obAttr );
status |= this->_userData.Write( ARGS_OFFSET + sizeof( obAttr ), ustr );
status |= this->_userData.Write( ARGS_OFFSET + sizeof( obAttr ) + sizeof( ustr ), len, pEventName );
return status;
};
if (_proc.core().isWow64())
{
_OBJECT_ATTRIBUTES32 obAttr32 = { 0 };
_UNICODE_STRING32 ustr32 = { 0 };
status = fillAttributes( obAttr32, ustr32 );
}
else
{
_OBJECT_ATTRIBUTES64 obAttr64 = { 0 };
_UNICODE_STRING64 ustr64 = { 0 };
status = fillAttributes( obAttr64, ustr64 );
}
if (!NT_SUCCESS( status ))
return status;
a->GenCall( pOpenEvent->procAddress, {
_userData.ptr() + EVENT_OFFSET,
@@ -507,17 +523,11 @@ NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID )
// Save status
(*a)->mov( (*a)->zdx, _userData.ptr() + ERR_OFFSET );
(*a)->mov( asmjit::host::dword_ptr( (*a)->zdx ), asmjit::host::eax );
(*a)->ret();
status = _userData.Write( ARGS_OFFSET, obAttr );
status |= _userData.Write( ARGS_OFFSET + sizeof(obAttr), ustr );
status |= _userData.Write( ARGS_OFFSET + sizeof(obAttr) + sizeof(ustr), len, pEventName );
if (!NT_SUCCESS( status ))
return status;
ExecInNewThread( (*a)->make(), (*a)->getCodeSize(), dwResult );
status = _userData.Read<NTSTATUS>( ERR_OFFSET, -1 );
status = ExecInNewThread( (*a)->make(), (*a)->getCodeSize(), dwResult, NoSwitch );
if (NT_SUCCESS( status ))
status = _userData.Read<NTSTATUS>( ERR_OFFSET, -1 );
}
return status;
+1 -1
View File
@@ -118,7 +118,7 @@ public:
/// <param name="a">Target assembly helper</param>
BLACKBONE_API inline void SaveCallResult( IAsmHelper& a, uint32_t retOffset = RET_OFFSET )
{
a->mov( a->zdx, _userData.ptr<uintptr_t>() + retOffset );
a->mov( a->zdx, _userData.ptr() + retOffset );
a->mov( asmjit::host::dword_ptr( a->zdx ), a->zax );
}
@@ -303,6 +303,18 @@ NTSTATUS Native::SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx )
}
}
/// <summary>
/// NtQueueApcThread
/// </summary>
/// <param name="hThread">Thread handle.</param>
/// <param name="func">APC function</param>
/// <param name="arg">APC argument</param>
/// <returns>Status code</returns>
NTSTATUS Native::NtQueueApcThreadT( HANDLE hThread, ptr_t func, ptr_t arg )
{
return SAFE_NATIVE_CALL( NtQueueApcThread, hThread, reinterpret_cast<PVOID>(func), reinterpret_cast<PVOID>(arg), nullptr, nullptr );
}
/// <summary>
/// Get WOW64 PEB
/// </summary>
@@ -158,6 +158,15 @@ public:
/// <returns>Status code</returns>
virtual NTSTATUS SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx );
/// <summary>
/// NtQueueApcThread
/// </summary>
/// <param name="hThread">Thread handle.</param>
/// <param name="func">APC function</param>
/// <param name="arg">APC argument</param>
/// <returns>Status code</returns>
virtual NTSTATUS NtQueueApcThreadT( HANDLE hThread, ptr_t func, ptr_t arg );
/// <summary>
/// Get WOW64 PEB
/// </summary>
@@ -272,6 +272,25 @@ NTSTATUS NativeWow64::SetThreadContextT( HANDLE hThread, _CONTEXT64& ctx )
return static_cast<NTSTATUS>(X64Call( stc, 2, (DWORD64)hThread, (DWORD64)&ctx ));
}
/// <summary>
/// NtQueueApcThread
/// </summary>
/// <param name="hThread">Thread handle.</param>
/// <param name="func">APC function</param>
/// <param name="arg">APC argument</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::NtQueueApcThreadT( HANDLE hThread, ptr_t func, ptr_t arg )
{
if (_wowBarrier.targetWow64)
return Native::NtQueueApcThreadT( hThread, func, arg );
static ptr_t qat = GetProcAddress64( getNTDLL64(), "NtQueueApcThread" );
if (qat == 0)
return STATUS_ORDINAL_NOT_FOUND;
return static_cast<NTSTATUS>(X64Call( qat, 5, (DWORD64)hThread, func, arg, 0ull, 0ull ));
}
/// <summary>
/// Gets WOW64 PEB
/// </summary>
+9
View File
@@ -136,6 +136,15 @@ public:
/// <returns>Status code</returns>
virtual NTSTATUS SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx );
/// <summary>
/// NtQueueApcThread
/// </summary>
/// <param name="hThread">Thread handle.</param>
/// <param name="func">APC function</param>
/// <param name="arg">APC argument</param>
/// <returns>Status code</returns>
virtual NTSTATUS NtQueueApcThreadT( HANDLE hThread, ptr_t func, ptr_t arg );
/// <summary>
/// Get WOW64 PEB
/// </summary>