Skip to content

Commit

Permalink
Add x64 instrumentation callback hook
Browse files Browse the repository at this point in the history
  • Loading branch information
Mattiwatti committed Apr 5, 2019
1 parent d26e4dd commit 66ec9ad
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 2 deletions.
5 changes: 5 additions & 0 deletions HookLibrary/HookHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ FORCEINLINE ULONG NTAPI RtlNtMajorVersion()
return *(PULONG)(0x7FFE0000 + 0x26C);
}

FORCEINLINE ULONG NTAPI RtlNtMinorVersion()
{
return *(PULONG)(0x7FFE0000 + 0x270);
}

FORCEINLINE ULONG NTAPI RtlGetTickCount()
{
return (ULONG)(*(PULONG64)(0x7FFE0000 + 0x320) * *(PULONG)(0x7FFE0000 + 0x4) >> 24);
Expand Down
8 changes: 8 additions & 0 deletions HookLibrary/HookLibrary.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
Expand Down Expand Up @@ -169,7 +170,14 @@
<ClInclude Include="HookHelper.h" />
<ClInclude Include="HookMain.h" />
</ItemGroup>
<ItemGroup>
<MASM Include="InstrumentationCallbackX64.asm">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</MASM>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
5 changes: 5 additions & 0 deletions HookLibrary/HookLibrary.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="InstrumentationCallbackX64.asm">
<Filter>Source Files</Filter>
</MASM>
</ItemGroup>
</Project>
94 changes: 94 additions & 0 deletions HookLibrary/HookedFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,102 @@ static bool IsProcessHandleTracingEnabled = false;
#define STATUS_INVALID_PARAMETER ((DWORD )0xC000000DL)
#endif

#ifdef _WIN64

// Instrumentation callback

extern "C" void InstrumentationCallbackAsm();

static LONG volatile InstrumentationCallbackHookInstalled = 0;
static LONG volatile RecurseGuard = 0;

static
NTSTATUS
InstallInstrumentationCallbackHook(
_In_ HANDLE ProcessHandle,
_In_ BOOLEAN Remove
)
{
PVOID pInstrumentationCallbackAsm = (PVOID)InstrumentationCallbackAsm;
NTSTATUS Status = STATUS_NOT_SUPPORTED;

if (RtlNtMajorVersion() > 6)
{
// Windows 10
PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION InstrumentationCallbackInfo;
InstrumentationCallbackInfo.Version = 0; // Use 1 on x86 OS
InstrumentationCallbackInfo.Reserved = 0;
InstrumentationCallbackInfo.Callback = Remove ? nullptr : pInstrumentationCallbackAsm;

Status = HookDllData.dNtSetInformationProcess != nullptr
? HookDllData.dNtSetInformationProcess(ProcessHandle,
ProcessInstrumentationCallback,
&InstrumentationCallbackInfo,
sizeof(InstrumentationCallbackInfo))
: NtSetInformationProcess(ProcessHandle,
ProcessInstrumentationCallback,
&InstrumentationCallbackInfo,
sizeof(InstrumentationCallbackInfo));
}
else if (RtlNtMajorVersion() == 6 && RtlNtMinorVersion() >= 1)
{
// Windows 7-8.1 require SE_DEBUG for this to work, even on the current process
BOOLEAN SeDebugWasEnabled;
Status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &SeDebugWasEnabled);
if (!NT_SUCCESS(Status))
return Status;

Status = HookDllData.dNtSetInformationProcess != nullptr
? HookDllData.dNtSetInformationProcess(ProcessHandle,
ProcessInstrumentationCallback,
Remove ? nullptr : &pInstrumentationCallbackAsm,
sizeof(pInstrumentationCallbackAsm))
: NtSetInformationProcess(ProcessHandle,
ProcessInstrumentationCallback,
Remove ? nullptr : &pInstrumentationCallbackAsm,
sizeof(pInstrumentationCallbackAsm));

RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, SeDebugWasEnabled, FALSE, &SeDebugWasEnabled);
}

return Status;
}

extern "C"
ULONG64
InstrumentationCallback(
_In_ ULONG64 R10,
_Inout_ ULONG64 RAX
)
{
if (InterlockedOr(&RecurseGuard, 0x1) == 0x1)
return RAX;

const PVOID ImageBase = NtCurrentPeb()->ImageBaseAddress;
const PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(ImageBase);
if (NtHeaders != nullptr && R10 >= (ULONG64)ImageBase &&
R10 < (ULONG64)ImageBase + NtHeaders->OptionalHeader.SizeOfImage)
{
// Syscall return address within the exe file
RAX = STATUS_PORT_NOT_SET;
}

InterlockedAnd(&RecurseGuard, 0);

return RAX;
}

#endif // _WIN64

NTSTATUS NTAPI HookedNtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength)
{
#ifdef _WIN64
if (InterlockedOr(&InstrumentationCallbackHookInstalled, 0x1) == 0)
{
InstallInstrumentationCallbackHook(NtCurrentProcess, FALSE);
}
#endif

if ((ProcessInformationClass == ProcessDebugFlags ||
ProcessInformationClass == ProcessDebugObjectHandle ||
ProcessInformationClass == ProcessDebugPort ||
Expand Down
50 changes: 50 additions & 0 deletions HookLibrary/InstrumentationCallbackX64.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
include ksamd64.inc

extern InstrumentationCallback:near

.code
InstrumentationCallbackAsm proc

cmp eax, 0 ; STATUS_SUCCESS
jne ReturnToCaller

push rax ; return value
push rcx
push rbx
push rbp
push rdi
push rsi
push rsp
push r10
push r11
push r12
push r13
push r14
push r15

sub rsp, 20h
mov rcx, r10
mov rdx, rax
call InstrumentationCallback
add rsp, 20h

pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop rsp
pop rsi
pop rdi
pop rbp
pop rbx
pop rcx
add rsp, 8 ; preserve new rax

ReturnToCaller:
jmp r10

InstrumentationCallbackAsm endp

end
3 changes: 2 additions & 1 deletion InjectorCLI/CliMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ bool startInjection(DWORD targetPid, const WCHAR * dllPath)
{
bool result = false;

HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, 0, targetPid);
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION,
0, targetPid);
if (hProcess)
{
BYTE * dllMemory = ReadFileToMemory(dllPath);
Expand Down
3 changes: 2 additions & 1 deletion PluginGeneric/Injector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ void startInjectionProcess(HANDLE hProcess, HOOK_DLL_DATA *hdd, BYTE * dllMemory

void startInjection(DWORD targetPid, HOOK_DLL_DATA *hdd, const WCHAR * dllPath, bool newProcess)
{
HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, 0, targetPid);
HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION,
0, targetPid);
if (hProcess)
{
BYTE * dllMemory = ReadFileToMemory(dllPath);
Expand Down

0 comments on commit 66ec9ad

Please sign in to comment.