#include "Wow64Subsystem.h"
#include "../Misc/DynImport.h"
#include "../Include/Macro.h"
#include <3rd_party/rewolf-wow64ext/src/wow64ext.h>
namespace blackbone
{
NativeWow64::NativeWow64( HANDLE hProcess )
: Native( hProcess )
{
}
NativeWow64::~NativeWow64()
{
}
///
/// Allocate virtual memory
///
/// Allocation address
/// Region size
/// Allocation type
/// Memory protection
/// Status code
NTSTATUS NativeWow64::VirtualAllocExT( ptr_t& lpAddress, size_t dwSize, DWORD flAllocationType, DWORD flProtect )
{
DWORD64 size64 = dwSize;
static ptr_t ntavm = GetProcAddress64( getNTDLL64(), "NtAllocateVirtualMemory" );
if (ntavm == 0)
return STATUS_ORDINAL_NOT_FOUND;
return static_cast(X64Call( ntavm, 6, (DWORD64)_hProcess, (DWORD64)&lpAddress, 0ull, (DWORD64)&size64, (DWORD64)flAllocationType, (DWORD64)flProtect ));
}
///
/// Free virtual memory
///
/// Memory address
/// Region size
/// Memory release type.
/// Status code
NTSTATUS NativeWow64::VirtualFreeExT( ptr_t lpAddress, size_t dwSize, DWORD dwFreeType )
{
static ptr_t ntfvm = GetProcAddress64( getNTDLL64(), "NtFreeVirtualMemory" );
if (ntfvm == 0)
return STATUS_ORDINAL_NOT_FOUND;
DWORD64 tmpAddr = lpAddress;
DWORD64 tmpSize = dwSize;
return static_cast(X64Call( ntfvm, 4, (DWORD64)_hProcess, (DWORD64)&tmpAddr, (DWORD64)&tmpSize, (DWORD64)dwFreeType ));
}
///
/// Query virtual memory
///
/// Address to query
/// Retrieved memory info
/// Status code
NTSTATUS NativeWow64::VirtualQueryExT( ptr_t lpAddress, PMEMORY_BASIC_INFORMATION64 lpBuffer )
{
static ptr_t ntqvm = GetProcAddress64( getNTDLL64(), "NtQueryVirtualMemory" );
if (ntqvm == 0)
return STATUS_ORDINAL_NOT_FOUND;
return static_cast(X64Call( ntqvm, 6, (DWORD64)_hProcess, lpAddress, 0ull, (DWORD64)lpBuffer, (DWORD64)sizeof( MEMORY_BASIC_INFORMATION64 ), 0ull ));
}
///
/// Query virtual memory
///
/// Address to query
/// Retrieved memory info
/// Status code
NTSTATUS NativeWow64::VirtualQueryExT( ptr_t lpAddress, MEMORY_INFORMATION_CLASS infoClass, LPVOID lpBuffer, size_t bufSize )
{
static ptr_t ntqvm = GetProcAddress64( getNTDLL64(), "NtQueryVirtualMemory" );
if (ntqvm == 0)
return STATUS_ORDINAL_NOT_FOUND;
return static_cast(X64Call( ntqvm, 6, (DWORD64)_hProcess, lpAddress, (DWORD64)infoClass, (DWORD64)lpBuffer, (DWORD64)bufSize, 0ull ));
}
///
/// Change memory protection
///
/// Memory address.
/// Region size
/// New protection.
/// Old protection
/// Status code
NTSTATUS NativeWow64::VirtualProtectExT( ptr_t lpAddress, DWORD64 dwSize, DWORD flProtect, DWORD* flOld )
{
static ptr_t ntpvm = GetProcAddress64( getNTDLL64(), "NtProtectVirtualMemory" );
if (ntpvm == 0)
return STATUS_ORDINAL_NOT_FOUND;
return static_cast(X64Call( ntpvm, 5, (DWORD64)_hProcess, (DWORD64)&lpAddress, (DWORD64)&dwSize, (DWORD64)flProtect, (DWORD64)flOld ));
}
///
/// Read virtual memory
///
/// Memory address
/// Output buffer
/// Number of bytes to read
/// Mumber of bytes read
/// Status code
NTSTATUS NativeWow64::ReadProcessMemoryT( ptr_t lpBaseAddress, LPVOID lpBuffer, size_t nSize, DWORD64 *lpBytes /*= nullptr */ )
{
DWORD64 junk = 0;
if (lpBytes == nullptr)
lpBytes = &junk;
return SAFE_NATIVE_CALL( NtWow64ReadVirtualMemory64, _hProcess, lpBaseAddress, lpBuffer, nSize, lpBytes );
}
///
/// Write virtual memory
///
/// Memory address
/// Buffer to write
/// Number of bytes to read
/// Mumber of bytes read
/// Status code
NTSTATUS NativeWow64::WriteProcessMemoryT( ptr_t lpBaseAddress, LPCVOID lpBuffer, size_t nSize, DWORD64 *lpBytes /*= nullptr */ )
{
DWORD64 junk = 0;
if (lpBytes == nullptr)
lpBytes = &junk;
return SAFE_NATIVE_CALL( NtWow64WriteVirtualMemory64, _hProcess, lpBaseAddress, (LPVOID)lpBuffer, nSize, lpBytes );
}
///
/// Call NtQueryInformationProcess for underlying process
///
/// Information class
/// Output buffer
/// Buffer size
/// Status code
NTSTATUS NativeWow64::QueryProcessInfoT( PROCESSINFOCLASS infoClass, LPVOID lpBuffer, uint32_t bufSize )
{
ULONG length = 0;
return SAFE_NATIVE_CALL( NtWow64QueryInformationProcess64, _hProcess, infoClass, lpBuffer, bufSize, &length );
}
///
/// Call NtSetInformationProcess for underlying process
///
/// Information class
/// Input buffer
/// Buffer size
/// Status code
NTSTATUS NativeWow64::SetProcessInfoT( PROCESSINFOCLASS infoClass, LPVOID lpBuffer, uint32_t bufSize )
{
static ptr_t ntspi = GetProcAddress64( getNTDLL64(), "NtSetInformationProcess" );
if (ntspi == 0)
return STATUS_ORDINAL_NOT_FOUND;
return static_cast(X64Call( ntspi, 4, (DWORD64)_hProcess, (DWORD64)infoClass, (DWORD64)lpBuffer, (DWORD64)bufSize ));
}
///
/// Creates new thread in the remote process
///
/// Created thread handle
/// Thread entry point
/// Thread argument
/// Creation flags
/// Status code*/
NTSTATUS NativeWow64::CreateRemoteThreadT( HANDLE& hThread, ptr_t entry, ptr_t arg, CreateThreadFlags flags, DWORD access )
{
// Try to use default routine if possible
/*if(_wowBarrier.targetWow64 == true)
{
return Native::CreateRemoteThreadT( hThread, entry, arg, flags, access );
}
else*/
{
static DWORD64 NtCreateThreadEx = GetProcAddress64( getNTDLL64(), "NtCreateThreadEx" );
if (NtCreateThreadEx == 0)
return STATUS_ORDINAL_NOT_FOUND;
// hThread can't be used directly because x64Call will zero stack space near variable
DWORD64 hThd2 = NULL;
NTSTATUS status = static_cast(X64Call(
NtCreateThreadEx, 11, (DWORD64)&hThd2, (DWORD64)access, 0ull,
(DWORD64)_hProcess, (DWORD64)entry, (DWORD64)arg, (DWORD64)flags,
0ull, 0x1000ull, 0x100000ull, 0ull
));
hThread = reinterpret_cast(hThd2);
return status;
}
}
///
/// Get WOW64 thread context
///
/// Thread handle.
/// Thread context
/// Status code
NTSTATUS NativeWow64::GetThreadContextT( HANDLE hThread, _CONTEXT32& ctx )
{
// Target process is x64. 32bit CONTEXT is not available.
if (_wowBarrier.targetWow64 == false)
{
return STATUS_NOT_SUPPORTED;
}
else
{
SetLastNtStatus( STATUS_SUCCESS );
GetThreadContext( hThread, reinterpret_cast(&ctx) );
return LastNtStatus();
}
}
///
/// Get native thread context
///
/// Thread handle.
/// Thread context
/// Status code
NTSTATUS NativeWow64::GetThreadContextT( HANDLE hThread, _CONTEXT64& ctx )
{
static ptr_t gtc = GetProcAddress64( getNTDLL64(), "NtGetContextThread" );
if (gtc == 0)
return STATUS_ORDINAL_NOT_FOUND;
return static_cast(X64Call( gtc, 2, (DWORD64)hThread, (DWORD64)&ctx ));
}
///
/// Set WOW64 thread context
///
/// Thread handle.
/// Thread context
/// Status code
NTSTATUS NativeWow64::SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx )
{
// Target process is x64. 32bit CONTEXT is not available.
if (_wowBarrier.targetWow64 == false)
{
return STATUS_NOT_SUPPORTED;
}
else
{
SetLastNtStatus( STATUS_SUCCESS );
SetThreadContext( hThread, reinterpret_cast(&ctx) );
return LastNtStatus();
}
}
///
/// Set native thread context
///
/// Thread handle.
/// Thread context
/// Status code
NTSTATUS NativeWow64::SetThreadContextT( HANDLE hThread, _CONTEXT64& ctx )
{
static ptr_t stc = GetProcAddress64( getNTDLL64(), "NtSetContextThread" );
if (stc == 0)
return STATUS_ORDINAL_NOT_FOUND;
return static_cast(X64Call( stc, 2, (DWORD64)hThread, (DWORD64)&ctx ));
}
///
/// NtQueueApcThread
///
/// Thread handle.
/// APC function
/// APC argument
/// Status code
NTSTATUS NativeWow64::QueueApcT( HANDLE hThread, ptr_t func, ptr_t arg )
{
if (_wowBarrier.targetWow64)
return Native::QueueApcT( hThread, func, arg );
static ptr_t qat = GetProcAddress64( getNTDLL64(), "NtQueueApcThread" );
if (qat == 0)
return STATUS_ORDINAL_NOT_FOUND;
return static_cast(X64Call( qat, 5, (DWORD64)hThread, func, arg, 0ull, 0ull ));
}
///
/// Gets WOW64 PEB
///
/// Retrieved PEB
/// PEB pointer
ptr_t NativeWow64::getPEB( _PEB32* ppeb )
{
// Target process is x64. PEB32 is not available.
if (_wowBarrier.targetWow64 == false)
{
return 0;
}
else
{
PROCESS_BASIC_INFORMATION pbi = { 0 };
ULONG bytes = 0;
if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueryInformationProcess, _hProcess, ProcessBasicInformation, &pbi, (ULONG)sizeof( pbi ), &bytes ) ) && ppeb)
ReadProcessMemory( _hProcess, pbi.PebBaseAddress, ppeb, sizeof(_PEB32), NULL );
return reinterpret_cast(pbi.PebBaseAddress);
}
}
///
/// Get native PEB
///
/// Retrieved PEB
/// PEB pointer
ptr_t NativeWow64::getPEB( _PEB64* ppeb )
{
_PROCESS_BASIC_INFORMATION_T info = { 0 };
ULONG bytes = 0;
SAFE_NATIVE_CALL( NtWow64QueryInformationProcess64, _hProcess, ProcessBasicInformation, &info, (ULONG)sizeof( info ), &bytes );
if (bytes > 0 && NT_SUCCESS( SAFE_NATIVE_CALL( NtWow64ReadVirtualMemory64, _hProcess, info.PebBaseAddress, ppeb, (ULONG)sizeof( _PEB64 ), nullptr ) ))
return info.PebBaseAddress;
return 0;
}
///
/// Get WOW64 TEB
///
/// Retrieved TEB
/// TEB pointer
ptr_t NativeWow64::getTEB( HANDLE hThread, _TEB32* pteb )
{
// Target process is x64. TEB32 is not available.
if (_wowBarrier.targetWow64 == false)
{
return 0;
}
else
{
_THREAD_BASIC_INFORMATION_T tbi = { 0 };
ULONG bytes = 0;
if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueryInformationThread, hThread, (THREADINFOCLASS)0, &tbi, (ULONG)sizeof( tbi ), &bytes ) ) && pteb)
ReadProcessMemory( _hProcess, (LPCVOID)((uintptr_t)tbi.TebBaseAddress), pteb, sizeof( _TEB32 ), nullptr );
return static_cast(tbi.TebBaseAddress);
}
}
///
/// Get native TEB
///
/// Retrieved TEB
/// TEB pointer
ptr_t NativeWow64::getTEB( HANDLE hThread, _TEB64* pteb )
{
_THREAD_BASIC_INFORMATION_T info = { 0 };
ULONG bytes = 0;
static ptr_t ntQit = GetProcAddress64( getNTDLL64(), "NtQueryInformationThread" );
if (ntQit == 0)
{
SetLastNtStatus( STATUS_ORDINAL_NOT_FOUND );
return 0;
}
X64Call( ntQit, 5, (DWORD64)hThread, 0ull, (DWORD64)&info, (DWORD64)sizeof(info), (DWORD64)&bytes );
if (bytes > 0 && NT_SUCCESS( SAFE_NATIVE_CALL( NtWow64ReadVirtualMemory64, _hProcess, info.TebBaseAddress, pteb, sizeof( _TEB64 ), nullptr ) ))
return static_cast(info.TebBaseAddress);
return 0;
}
}