mirror of
https://github.com/DarthTon/Blackbone.git
synced 2026-10-28 19:36:34 +08:00
remote local hook WIP
This commit is contained in:
@@ -408,6 +408,7 @@
|
||||
<ClCompile Include="Process\ProcessModules.cpp" />
|
||||
<ClCompile Include="Process\RPC\RemoteExec.cpp" />
|
||||
<ClCompile Include="Process\RPC\RemoteHook.cpp" />
|
||||
<ClCompile Include="Process\RPC\RemoteLocalHook.cpp" />
|
||||
<ClCompile Include="Process\RPC\RemoteMemory.cpp" />
|
||||
<ClCompile Include="Process\Threads\Thread.cpp" />
|
||||
<ClCompile Include="Process\Threads\Threads.cpp" />
|
||||
@@ -499,6 +500,7 @@
|
||||
<ClInclude Include="Process\RPC\RemoteExec.h" />
|
||||
<ClInclude Include="Process\RPC\RemoteFunction.hpp" />
|
||||
<ClInclude Include="Process\RPC\RemoteHook.h" />
|
||||
<ClInclude Include="Process\RPC\RemoteLocalHook.h" />
|
||||
<ClInclude Include="Process\RPC\RemoteMemory.h" />
|
||||
<ClInclude Include="Process\Threads\Thread.h" />
|
||||
<ClInclude Include="Process\Threads\Threads.h" />
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
<Filter Include="ManualMap\Native">
|
||||
<UniqueIdentifier>{ed49eaa5-5d59-4422-9da7-4e68f2e82774}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Process\RPC">
|
||||
<UniqueIdentifier>{f688ae04-991b-40b2-9243-89e38275be42}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="AsmJit">
|
||||
<UniqueIdentifier>{400c27bd-fb7a-4125-abf2-90a4bdb04f09}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -46,6 +43,9 @@
|
||||
<Filter Include="AsmJit\Core">
|
||||
<UniqueIdentifier>{84644925-22dd-4022-be68-30ddf267b977}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Process\Remote">
|
||||
<UniqueIdentifier>{f688ae04-991b-40b2-9243-89e38275be42}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Subsystem\NativeSubsystem.cpp">
|
||||
@@ -82,10 +82,10 @@
|
||||
<Filter>Process\Threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Process\RPC\RemoteExec.cpp">
|
||||
<Filter>Process\RPC</Filter>
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Process\RPC\RemoteHook.cpp">
|
||||
<Filter>Process\RPC</Filter>
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PE\ImageNET.cpp">
|
||||
<Filter>PE</Filter>
|
||||
@@ -121,7 +121,7 @@
|
||||
<Filter>DriverControl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Process\RPC\RemoteMemory.cpp">
|
||||
<Filter>Process\RPC</Filter>
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Asm\AsmHelper32.cpp">
|
||||
<Filter>AsmJit\Helpers</Filter>
|
||||
@@ -189,6 +189,9 @@
|
||||
<ClCompile Include="..\..\contrib\AsmJit\base\zone.cpp">
|
||||
<Filter>AsmJit\Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Process\RPC\RemoteLocalHook.cpp">
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Config.h" />
|
||||
@@ -226,16 +229,16 @@
|
||||
<Filter>Process\Threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Process\RPC\RemoteContext.hpp">
|
||||
<Filter>Process\RPC</Filter>
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Process\RPC\RemoteExec.h">
|
||||
<Filter>Process\RPC</Filter>
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Process\RPC\RemoteFunction.hpp">
|
||||
<Filter>Process\RPC</Filter>
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Process\RPC\RemoteHook.h">
|
||||
<Filter>Process\RPC</Filter>
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PE\ImageNET.h">
|
||||
<Filter>PE</Filter>
|
||||
@@ -316,7 +319,7 @@
|
||||
<Filter>DriverControl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Process\RPC\RemoteMemory.h">
|
||||
<Filter>Process\RPC</Filter>
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Asm\AsmHelper64.h">
|
||||
<Filter>AsmJit\Helpers</Filter>
|
||||
@@ -426,5 +429,8 @@
|
||||
<ClInclude Include="..\..\contrib\AsmJit\base\zone.h">
|
||||
<Filter>AsmJit\Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Process\RPC\RemoteLocalHook.h">
|
||||
<Filter>Process\Remote</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -2,209 +2,209 @@
|
||||
|
||||
namespace blackbone
|
||||
{
|
||||
std::unordered_map<void*, DetourBase*> DetourBase::_breakpoints;
|
||||
void* DetourBase::_vecHandler = nullptr;
|
||||
std::unordered_map<void*, DetourBase*> DetourBase::_breakpoints;
|
||||
void* DetourBase::_vecHandler = nullptr;
|
||||
|
||||
DetourBase::DetourBase()
|
||||
DetourBase::DetourBase()
|
||||
{
|
||||
_buf = (uint8_t*)VirtualAlloc( nullptr, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
_origCode = _buf + 0x100;
|
||||
_newCode = _buf + 0x200;
|
||||
}
|
||||
|
||||
DetourBase::~DetourBase()
|
||||
{
|
||||
VirtualFree( _buf, 0, MEM_RELEASE );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Temporarily disable hook
|
||||
/// </summary>
|
||||
/// <returns>true on success</returns>
|
||||
bool DetourBase::DisableHook()
|
||||
{
|
||||
if (_type == HookType::InternalInline || _type == HookType::Int3)
|
||||
WriteProcessMemory( GetCurrentProcess(), _original, _origCode, _origSize, NULL );
|
||||
else if (_type == HookType::HWBP)
|
||||
ToggleHBP( _hwbpIdx[GetCurrentThreadId()], false );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable disabled hook
|
||||
/// </summary>
|
||||
/// <returns>true on success</returns>
|
||||
bool DetourBase::EnableHook()
|
||||
{
|
||||
if (_type == HookType::InternalInline || _type == HookType::Int3)
|
||||
WriteProcessMemory( GetCurrentProcess(), _original, _newCode, _origSize, NULL );
|
||||
else if (_type == HookType::HWBP)
|
||||
ToggleHBP( _hwbpIdx[GetCurrentThreadId()], true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle hardware breakpoint for current thread
|
||||
/// </summary>
|
||||
/// <param name="index">Breakpoint index ( 0-4 )</param>
|
||||
/// <param name="enable">true to enable, false to disable</param>
|
||||
/// <returns>true on success</returns>
|
||||
bool DetourBase::ToggleHBP( int index, bool enable )
|
||||
{
|
||||
CONTEXT context = { 0 };
|
||||
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
||||
|
||||
if (GetThreadContext( GetCurrentThread(), &context ) != TRUE)
|
||||
return FALSE;
|
||||
|
||||
if (enable)
|
||||
BitTestAndSetT( (LONG_PTR*)&context.Dr7, 2 * index );
|
||||
else
|
||||
BitTestAndResetT( (LONG_PTR*)&context.Dr7, 2 * index );
|
||||
|
||||
return (SetThreadContext( GetCurrentThread(), &context ) != FALSE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy original function bytes
|
||||
/// </summary>
|
||||
/// <param name="Ptr">Origianl function address</param>
|
||||
void DetourBase::CopyOldCode( uint8_t* ptr )
|
||||
{
|
||||
// Store original bytes
|
||||
uint8_t* src = ptr;
|
||||
uint8_t* old = (uint8_t*)_origCode;
|
||||
uint32_t all_len = 0;
|
||||
ldasm_data ld = { 0 };
|
||||
|
||||
do
|
||||
{
|
||||
_buf = (uint8_t*)VirtualAlloc( nullptr, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
_origCode = _buf + 0x100;
|
||||
_newCode = _buf + 0x200;
|
||||
}
|
||||
uint32_t len = ldasm( src, &ld, is_x64 );
|
||||
|
||||
DetourBase::~DetourBase()
|
||||
{
|
||||
VirtualFree( _buf, 0, MEM_RELEASE );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Temporarily disable hook
|
||||
/// </summary>
|
||||
/// <returns>true on success</returns>
|
||||
bool DetourBase::DisableHook()
|
||||
{
|
||||
if (_type == HookType::InternalInline || _type == HookType::Int3)
|
||||
WriteProcessMemory( GetCurrentProcess(), _original, _origCode, _origSize, NULL );
|
||||
else if (_type == HookType::HWBP)
|
||||
ToggleHBP( _hwbpIdx[GetCurrentThreadId()], false );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable disabled hook
|
||||
/// </summary>
|
||||
/// <returns>true on success</returns>
|
||||
bool DetourBase::EnableHook()
|
||||
{
|
||||
if (_type == HookType::InternalInline || _type == HookType::Int3)
|
||||
WriteProcessMemory( GetCurrentProcess(), _original, _newCode, _origSize, NULL );
|
||||
else if (_type == HookType::HWBP)
|
||||
ToggleHBP( _hwbpIdx[GetCurrentThreadId()], true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle hardware breakpoint for current thread
|
||||
/// </summary>
|
||||
/// <param name="index">Breakpoint index ( 0-4 )</param>
|
||||
/// <param name="enable">true to enable, false to disable</param>
|
||||
/// <returns>true on success</returns>
|
||||
bool DetourBase::ToggleHBP( int index, bool enable )
|
||||
{
|
||||
CONTEXT context = { 0 };
|
||||
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
||||
|
||||
if (GetThreadContext( GetCurrentThread(), &context ) != TRUE)
|
||||
return FALSE;
|
||||
|
||||
if (enable)
|
||||
BitTestAndSetT( (LONG_PTR*)&context.Dr7, 2 * index );
|
||||
else
|
||||
BitTestAndResetT( (LONG_PTR*)&context.Dr7, 2 * index );
|
||||
|
||||
return (SetThreadContext( GetCurrentThread(), &context ) != FALSE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy original function bytes
|
||||
/// </summary>
|
||||
/// <param name="Ptr">Origianl function address</param>
|
||||
void DetourBase::CopyOldCode( uint8_t* ptr )
|
||||
{
|
||||
// Store original bytes
|
||||
uint8_t* src = ptr;
|
||||
uint8_t* old = (uint8_t*)_origCode;
|
||||
uint32_t all_len = 0;
|
||||
ldasm_data ld = { 0 };
|
||||
|
||||
do
|
||||
// Determine code end
|
||||
if (ld.flags & F_INVALID
|
||||
|| (len == 1 && (src[ld.opcd_offset] == 0xCC || src[ld.opcd_offset] == 0xC3))
|
||||
|| (len == 3 && src[ld.opcd_offset] == 0xC2)
|
||||
|| len + all_len > 128)
|
||||
{
|
||||
uint32_t len = ldasm( src, &ld, is_x64 );
|
||||
break;
|
||||
}
|
||||
|
||||
// Determine code end
|
||||
if (ld.flags & F_INVALID
|
||||
|| (len == 1 && (src[ld.opcd_offset] == 0xCC || src[ld.opcd_offset] == 0xC3))
|
||||
|| (len == 3 && src[ld.opcd_offset] == 0xC2)
|
||||
|| len + all_len > 128)
|
||||
{
|
||||
// move instruction
|
||||
memcpy( old, src, len );
|
||||
|
||||
// if instruction has relative offset, calculate new offset
|
||||
if (ld.flags & F_RELATIVE)
|
||||
{
|
||||
#ifdef USE64
|
||||
// exit if jump is greater then 2GB
|
||||
if (_abs64( (uintptr_t)(src + *((int*)(old + ld.opcd_size))) - (uintptr_t)old ) > INT_MAX)
|
||||
break;
|
||||
}
|
||||
|
||||
// move instruction
|
||||
memcpy( old, src, len );
|
||||
|
||||
// if instruction has relative offset, calculate new offset
|
||||
if (ld.flags & F_RELATIVE)
|
||||
{
|
||||
#ifdef USE64
|
||||
// exit if jump is greater then 2GB
|
||||
if (_abs64( (uintptr_t)(src + *((int*)(old + ld.opcd_size))) - (uintptr_t)old ) > INT_MAX)
|
||||
break;
|
||||
else
|
||||
*(uint32_t*)(old + ld.opcd_size) += (uint32_t)(src - old);
|
||||
#else
|
||||
*(uintptr_t*)(old + ld.opcd_size) += src - old;
|
||||
#endif
|
||||
}
|
||||
|
||||
src += len;
|
||||
old += len;
|
||||
all_len += len;
|
||||
|
||||
} while (all_len < _origSize);
|
||||
|
||||
// Failed to copy old code, use backup plan
|
||||
if (all_len < _origSize)
|
||||
{
|
||||
_type = HookType::InternalInline;
|
||||
memcpy( _origCode, ptr, _origSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_JUMP( old, src );
|
||||
_callOriginal = _origCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Exception handler
|
||||
/// </summary>
|
||||
/// <param name="excpt">Exception information</param>
|
||||
/// <returns>Exception disposition</returns>
|
||||
LONG NTAPI DetourBase::VectoredHandler( PEXCEPTION_POINTERS excpt )
|
||||
{
|
||||
switch (excpt->ExceptionRecord->ExceptionCode)
|
||||
{
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
return Int3Handler( excpt );
|
||||
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
return AVHandler( excpt );
|
||||
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
return StepHandler( excpt );
|
||||
|
||||
default:
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Int3 exception handler
|
||||
/// </summary>
|
||||
/// <param name="excpt">Exception information</param>
|
||||
/// <returns>Exception disposition</returns>
|
||||
LONG NTAPI DetourBase::Int3Handler( PEXCEPTION_POINTERS excpt )
|
||||
{
|
||||
if (_breakpoints.count( excpt->ExceptionRecord->ExceptionAddress ))
|
||||
{
|
||||
DetourBase* pInst = _breakpoints[excpt->ExceptionRecord->ExceptionAddress];
|
||||
|
||||
((_NT_TIB*)NtCurrentTeb())->ArbitraryUserPointer = (void*)pInst;
|
||||
excpt->ContextRecord->NIP = (uintptr_t)pInst->_internalHandler;
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
else
|
||||
*(uint32_t*)(old + ld.opcd_size) += (uint32_t)(src - old);
|
||||
#else
|
||||
*(uintptr_t*)(old + ld.opcd_size) += src - old;
|
||||
#endif
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
src += len;
|
||||
old += len;
|
||||
all_len += len;
|
||||
|
||||
/// <summary>
|
||||
/// Access violation handler
|
||||
/// </summary>
|
||||
/// <param name="excpt">Exception information</param>
|
||||
/// <returns>Exception disposition</returns>
|
||||
LONG NTAPI DetourBase::AVHandler( PEXCEPTION_POINTERS /*excpt*/ )
|
||||
} while (all_len < _origSize);
|
||||
|
||||
// Failed to copy old code, use backup plan
|
||||
if (all_len < _origSize)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Single step exception handler
|
||||
/// </summary>
|
||||
/// <param name="excpt">Exception information</param>
|
||||
/// <returns>Exception disposition</returns>
|
||||
LONG NTAPI DetourBase::StepHandler( PEXCEPTION_POINTERS excpt )
|
||||
_type = HookType::InternalInline;
|
||||
memcpy( _origCode, ptr, _origSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD index = 0;
|
||||
int found = _BitScanForward( &index, static_cast<DWORD>(excpt->ContextRecord->Dr6) );
|
||||
SET_JUMP( old, src );
|
||||
_callOriginal = _origCode;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != 0 && index < 4 && _breakpoints.count( excpt->ExceptionRecord->ExceptionAddress ))
|
||||
{
|
||||
DetourBase* pInst = _breakpoints[excpt->ExceptionRecord->ExceptionAddress];
|
||||
|
||||
// Disable breakpoint at current index
|
||||
BitTestAndResetT( (LONG_PTR*)&excpt->ContextRecord->Dr7, 2 * index );
|
||||
/// <summary>
|
||||
/// Exception handler
|
||||
/// </summary>
|
||||
/// <param name="excpt">Exception information</param>
|
||||
/// <returns>Exception disposition</returns>
|
||||
LONG NTAPI DetourBase::VectoredHandler( PEXCEPTION_POINTERS excpt )
|
||||
{
|
||||
switch (excpt->ExceptionRecord->ExceptionCode)
|
||||
{
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
return Int3Handler( excpt );
|
||||
|
||||
((_NT_TIB*)NtCurrentTeb())->ArbitraryUserPointer = (void*)pInst;
|
||||
excpt->ContextRecord->NIP = (uintptr_t)pInst->_internalHandler;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
return AVHandler( excpt );
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
return StepHandler( excpt );
|
||||
|
||||
default:
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Int3 exception handler
|
||||
/// </summary>
|
||||
/// <param name="excpt">Exception information</param>
|
||||
/// <returns>Exception disposition</returns>
|
||||
LONG NTAPI DetourBase::Int3Handler( PEXCEPTION_POINTERS excpt )
|
||||
{
|
||||
if (_breakpoints.count( excpt->ExceptionRecord->ExceptionAddress ))
|
||||
{
|
||||
DetourBase* pInst = _breakpoints[excpt->ExceptionRecord->ExceptionAddress];
|
||||
|
||||
((_NT_TIB*)NtCurrentTeb())->ArbitraryUserPointer = (void*)pInst;
|
||||
excpt->ContextRecord->NIP = (uintptr_t)pInst->_internalHandler;
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Access violation handler
|
||||
/// </summary>
|
||||
/// <param name="excpt">Exception information</param>
|
||||
/// <returns>Exception disposition</returns>
|
||||
LONG NTAPI DetourBase::AVHandler( PEXCEPTION_POINTERS /*excpt*/ )
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Single step exception handler
|
||||
/// </summary>
|
||||
/// <param name="excpt">Exception information</param>
|
||||
/// <returns>Exception disposition</returns>
|
||||
LONG NTAPI DetourBase::StepHandler( PEXCEPTION_POINTERS excpt )
|
||||
{
|
||||
DWORD index = 0;
|
||||
int found = _BitScanForward( &index, static_cast<DWORD>(excpt->ContextRecord->Dr6) );
|
||||
|
||||
if (found != 0 && index < 4 && _breakpoints.count( excpt->ExceptionRecord->ExceptionAddress ))
|
||||
{
|
||||
DetourBase* pInst = _breakpoints[excpt->ExceptionRecord->ExceptionAddress];
|
||||
|
||||
// Disable breakpoint at current index
|
||||
BitTestAndResetT( (LONG_PTR*)&excpt->ContextRecord->Dr7, 2 * index );
|
||||
|
||||
((_NT_TIB*)NtCurrentTeb())->ArbitraryUserPointer = (void*)pInst;
|
||||
excpt->ContextRecord->NIP = (uintptr_t)pInst->_internalHandler;
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,9 +16,9 @@ namespace CallOrder
|
||||
{
|
||||
enum e
|
||||
{
|
||||
HookFirst,
|
||||
HookLast,
|
||||
NoOriginal,
|
||||
HookFirst, // Hook called before original function
|
||||
HookLast, // Hook called after original function
|
||||
NoOriginal, // Original function doesn't get called
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ namespace ReturnMethod
|
||||
{
|
||||
enum e
|
||||
{
|
||||
UseNew,
|
||||
UseOriginal
|
||||
UseNew, // Return value returned by hook
|
||||
UseOriginal // Return original function value
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ Process::Process()
|
||||
, _memory( this )
|
||||
, _threads( _core )
|
||||
, _hooks( _memory )
|
||||
, _localHooks( *this )
|
||||
, _remote( *this )
|
||||
, _mmap( *this )
|
||||
, _nativeLdr( *this )
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Threads/Threads.h"
|
||||
#include "RPC/RemoteExec.h"
|
||||
#include "RPC/RemoteHook.h"
|
||||
#include "RPC/RemoteLocalHook.h"
|
||||
#include "../ManualMap/Native/NtLoader.h"
|
||||
#include "../ManualMap/MMap.h"
|
||||
|
||||
@@ -141,14 +142,15 @@ public:
|
||||
//
|
||||
// Subroutines
|
||||
//
|
||||
BLACKBONE_API inline ProcessCore& core() { return _core; } // Core routines and native
|
||||
BLACKBONE_API inline ProcessMemory& memory() { return _memory; } // Memory manipulations
|
||||
BLACKBONE_API inline ProcessModules& modules() { return _modules; } // Module management
|
||||
BLACKBONE_API inline ProcessThreads& threads() { return _threads; } // Threads
|
||||
BLACKBONE_API inline RemoteHook& hooks() { return _hooks; } // Hooking code remotely
|
||||
BLACKBONE_API inline RemoteExec& remote() { return _remote; } // Remote code execution
|
||||
BLACKBONE_API inline MMap& mmap() { return _mmap; } // Manual module mapping
|
||||
BLACKBONE_API inline NtLdr& nativeLdr() { return _nativeLdr; } // Native loader routines
|
||||
BLACKBONE_API inline ProcessCore& core() { return _core; } // Core routines and native
|
||||
BLACKBONE_API inline ProcessMemory& memory() { return _memory; } // Memory manipulations
|
||||
BLACKBONE_API inline ProcessModules& modules() { return _modules; } // Module management
|
||||
BLACKBONE_API inline ProcessThreads& threads() { return _threads; } // Threads
|
||||
BLACKBONE_API inline RemoteHook& hooks() { return _hooks; } // Hooking code remotely
|
||||
BLACKBONE_API inline RemoteLocalHook& localHooks() { return _localHooks; } // Hooking code remotely
|
||||
BLACKBONE_API inline RemoteExec& remote() { return _remote; } // Remote code execution
|
||||
BLACKBONE_API inline MMap& mmap() { return _mmap; } // Manual module mapping
|
||||
BLACKBONE_API inline NtLdr& nativeLdr() { return _nativeLdr; } // Native loader routines
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
@@ -160,15 +162,17 @@ private:
|
||||
|
||||
Process(const Process&) = delete;
|
||||
Process& operator =(const Process&) = delete;
|
||||
|
||||
private:
|
||||
ProcessCore _core; // Core routines and native subsystem
|
||||
ProcessModules _modules; // Module management
|
||||
ProcessMemory _memory; // Memory manipulations
|
||||
ProcessThreads _threads; // Threads
|
||||
RemoteHook _hooks; // Hooking code remotely
|
||||
RemoteExec _remote; // Remote code execution
|
||||
MMap _mmap; // Manual module mapping
|
||||
NtLdr _nativeLdr; // Native loader routines
|
||||
ProcessCore _core; // Core routines and native subsystem
|
||||
ProcessModules _modules; // Module management
|
||||
ProcessMemory _memory; // Memory manipulations
|
||||
ProcessThreads _threads; // Threads
|
||||
RemoteHook _hooks; // Hooking code remotely
|
||||
RemoteLocalHook _localHooks; // In-process remote hooks
|
||||
RemoteExec _remote; // Remote code execution
|
||||
MMap _mmap; // Manual module mapping
|
||||
NtLdr _nativeLdr; // Native loader routines
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Include/Winheaders.h"
|
||||
#include "../Include/NativeStructures.h"
|
||||
#include "../Subsystem/Wow64Subsystem.h"
|
||||
#include "../Subsystem/x86Subsystem.h"
|
||||
|
||||
@@ -343,9 +343,11 @@ exportData ProcessModules::GetExport( const ModuleData* hMod, const char* name_o
|
||||
/// Inject image into target process
|
||||
/// </summary>
|
||||
/// <param name="path">Full-qualified image path</param>
|
||||
/// <param name="pStatus">Injection status code</param>
|
||||
/// <returns>Module info. nullptr if failed</returns>
|
||||
const ModuleData* ProcessModules::Inject( const std::wstring& path )
|
||||
const ModuleData* ProcessModules::Inject( const std::wstring& path, NTSTATUS* pStatus /*= nullptr*/ )
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
const ModuleData* mod = nullptr;
|
||||
ptr_t res = 0;
|
||||
auto& barrier = _core.native()->GetWow64Barrier();
|
||||
@@ -358,7 +360,12 @@ const ModuleData* ProcessModules::Inject( const std::wstring& path )
|
||||
|
||||
// Already loaded
|
||||
if ((mod = GetModule( path, LdrList, img.mType() )) != nullptr)
|
||||
{
|
||||
if (pStatus)
|
||||
*pStatus = STATUS_IMAGE_ALREADY_LOADED;
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
// Image path
|
||||
UNICODE_STRING ustr = { 0 };
|
||||
@@ -378,7 +385,7 @@ const ModuleData* ProcessModules::Inject( const std::wstring& path )
|
||||
// Try to use LoadLibrary if possible
|
||||
if (pLoadLibrary != 0 && sameArch)
|
||||
{
|
||||
_proc.remote().ExecDirect( pLoadLibrary, modName.ptr<ptr_t>() + sizeof(ustr) );
|
||||
_proc.remote().ExecDirect( pLoadLibrary, modName.ptr() + sizeof( ustr ) );
|
||||
}
|
||||
// Can't generate code through WOW64 barrier
|
||||
else if ((barrier.type != wow_32_64 && img.mType() == mt_mod64) ||
|
||||
@@ -386,7 +393,12 @@ const ModuleData* ProcessModules::Inject( const std::wstring& path )
|
||||
{
|
||||
auto pLdrLoadDll = GetExport( GetModule( L"ntdll.dll", Sections, img.mType() ), "LdrLoadDll" ).procAddress;
|
||||
if (pLdrLoadDll == 0)
|
||||
{
|
||||
if (pStatus)
|
||||
*pStatus = STATUS_NOT_FOUND;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Patch LdrFindOrMapDll to enable kernel32.dll loading
|
||||
#ifdef USE64
|
||||
@@ -410,9 +422,14 @@ const ModuleData* ProcessModules::Inject( const std::wstring& path )
|
||||
a.GenCall( (size_t)pLdrLoadDll, { 0, 0, modName.ptr<size_t>(), modName.ptr<size_t>() + 0x800 } );
|
||||
a->ret();
|
||||
|
||||
_proc.remote().ExecInNewThread( a->make(), a->getCodeSize(), res );
|
||||
status = _proc.remote().ExecInNewThread( a->make(), a->getCodeSize(), res );
|
||||
if (NT_SUCCESS( status ))
|
||||
status = static_cast<NTSTATUS>(res);
|
||||
}
|
||||
|
||||
if (pStatus)
|
||||
*pStatus = status;
|
||||
|
||||
if (res == STATUS_SUCCESS)
|
||||
return GetModule( path, LdrList, img.mType() );
|
||||
else
|
||||
|
||||
@@ -120,8 +120,9 @@ public:
|
||||
/// Inject image into target process
|
||||
/// </summary>
|
||||
/// <param name="path">Full-qualified image path</param>
|
||||
/// <param name="pStatus">Injection status code</param>
|
||||
/// <returns>Module info. nullptr if failed</returns>
|
||||
BLACKBONE_API const ModuleData* Inject( const std::wstring& path );
|
||||
BLACKBONE_API const ModuleData* Inject( const std::wstring& path, NTSTATUS* pStatus = nullptr );
|
||||
|
||||
#ifdef COMPILER_MSVC
|
||||
/// <summary>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Include/Winheaders.h"
|
||||
#include "../ProcessMemory.h"
|
||||
#include "../ProcessCore.h"
|
||||
#include "../ProcessMemory.h"
|
||||
#include "../Threads/Thread.h"
|
||||
#include "../../Include/Macro.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "RemoteLocalHook.h"
|
||||
|
||||
#include "../Process.h"
|
||||
|
||||
#ifdef USE64
|
||||
#define HOOK_CTX_T(v, ctx) HookCtx64& v = ctx.hook64
|
||||
#else
|
||||
#define HOOK_CTX_T(v, ctx) HookCtx32& v = ctx.hook32
|
||||
#endif
|
||||
|
||||
namespace blackbone
|
||||
{
|
||||
|
||||
RemoteLocalHook::RemoteLocalHook( class Process& process )
|
||||
: _process( process )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RemoteLocalHook::~RemoteLocalHook()
|
||||
{
|
||||
}
|
||||
|
||||
NTSTATUS RemoteLocalHook::SetHook( ptr_t address, asmjit::Assembler& /*hook*/ )
|
||||
{
|
||||
HookCtx ctx = { 0 };
|
||||
HOOK_CTX_T( ctx_t, ctx );
|
||||
UNREFERENCED_PARAMETER( ctx_t );
|
||||
|
||||
// Already hooked
|
||||
if (_hooks.count( address ) != 0)
|
||||
return STATUS_ADDRESS_ALREADY_EXISTS;
|
||||
|
||||
_hooks.emplace( std::make_pair( address, ctx ) );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS RemoteLocalHook::Restore( ptr_t address )
|
||||
{
|
||||
// No such hook
|
||||
if (_hooks.count( address ) == 0)
|
||||
return STATUS_NOT_FOUND;
|
||||
|
||||
HOOK_CTX_T( ctx_t, _hooks[address] );
|
||||
|
||||
_hooks.erase( address );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Config.h"
|
||||
#include "../../Asm/AsmHelper.h"
|
||||
#include "../../Include/Types.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace blackbone
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Hook data, sizeof = 0x50 bytes
|
||||
/// </summary>
|
||||
struct HookCtx32
|
||||
{
|
||||
uint32_t codeSize; // Size of saved code
|
||||
uint8_t original_code[34]; // Original function code
|
||||
};
|
||||
|
||||
struct HookCtx64
|
||||
{
|
||||
uint64_t dst_ptr; // Target address
|
||||
uint32_t codeSize; // Size of saved code
|
||||
uint8_t original_code[32]; // Original function code
|
||||
uint8_t far_jmp[6]; // Far jump code
|
||||
};
|
||||
|
||||
union HookCtx
|
||||
{
|
||||
HookCtx32 hook32;
|
||||
HookCtx64 hook64;
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// In-process remote hook
|
||||
/// </summary>
|
||||
class RemoteLocalHook
|
||||
{
|
||||
typedef std::unordered_map<ptr_t, HookCtx> mapCtx;
|
||||
|
||||
public:
|
||||
RemoteLocalHook( class Process& process );
|
||||
~RemoteLocalHook();
|
||||
|
||||
NTSTATUS SetHook( ptr_t address, asmjit::Assembler& hook );
|
||||
|
||||
NTSTATUS Restore( ptr_t address );
|
||||
|
||||
private:
|
||||
RemoteLocalHook( const RemoteLocalHook& ) = delete;
|
||||
RemoteLocalHook& operator = (const RemoteLocalHook&) = delete;
|
||||
|
||||
private:
|
||||
class Process& _process;
|
||||
mapCtx _hooks;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -357,7 +357,10 @@ ptr_t NativeWow64::getTEB( HANDLE hThread, _TEB64* pteb )
|
||||
static ptr_t ntQit = _local.GetProcAddress64( _local.getNTDLL64(), "NtQueryInformationThread" );
|
||||
|
||||
if (ntQit == 0)
|
||||
{
|
||||
LastNtStatus( STATUS_ORDINAL_NOT_FOUND );
|
||||
return 0;
|
||||
}
|
||||
|
||||
_local.X64Call( ntQit, hThread, 0, &info, sizeof(info), &bytes );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user