mirror of
https://github.com/8damon/Blackbird-Platform
synced 2026-06-21 13:41:12 +00:00
363 lines
11 KiB
C++
363 lines
11 KiB
C++
#include "internal.h"
|
|
|
|
static BOOL ControllerInjectionReadImageMachine(_In_z_ PCWSTR ImagePath, _Out_ USHORT *MachineOut)
|
|
{
|
|
HANDLE fileHandle = INVALID_HANDLE_VALUE;
|
|
IMAGE_DOS_HEADER dosHeader;
|
|
DWORD signature = 0;
|
|
IMAGE_FILE_HEADER fileHeader;
|
|
LARGE_INTEGER ntHeaderOffset;
|
|
DWORD bytesRead = 0;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
if (ImagePath == NULL || ImagePath[0] == L'\0' || MachineOut == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
*MachineOut = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
ZeroMemory(&dosHeader, sizeof(dosHeader));
|
|
ZeroMemory(&fileHeader, sizeof(fileHeader));
|
|
|
|
fileHandle = CreateFileW(ImagePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (fileHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ReadFile(fileHandle, &dosHeader, sizeof(dosHeader), &bytesRead, NULL) || bytesRead != sizeof(dosHeader))
|
|
{
|
|
err = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE || dosHeader.e_lfanew <= 0)
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ntHeaderOffset.QuadPart = dosHeader.e_lfanew;
|
|
if (!SetFilePointerEx(fileHandle, ntHeaderOffset, NULL, FILE_BEGIN))
|
|
{
|
|
err = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!ReadFile(fileHandle, &signature, sizeof(signature), &bytesRead, NULL) || bytesRead != sizeof(signature))
|
|
{
|
|
err = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
if (signature != IMAGE_NT_SIGNATURE)
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!ReadFile(fileHandle, &fileHeader, sizeof(fileHeader), &bytesRead, NULL) || bytesRead != sizeof(fileHeader))
|
|
{
|
|
err = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
if (fileHeader.Machine == IMAGE_FILE_MACHINE_UNKNOWN)
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
*MachineOut = fileHeader.Machine;
|
|
CloseHandle(fileHandle);
|
|
return TRUE;
|
|
|
|
Cleanup:
|
|
CloseHandle(fileHandle);
|
|
SetLastError((err == ERROR_SUCCESS) ? ERROR_BAD_EXE_FORMAT : err);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL ControllerInjectionReadImageSubsystem(_In_z_ PCWSTR ImagePath, _Out_ USHORT *SubsystemOut)
|
|
{
|
|
HANDLE fileHandle = INVALID_HANDLE_VALUE;
|
|
IMAGE_DOS_HEADER dosHeader;
|
|
DWORD signature = 0;
|
|
IMAGE_FILE_HEADER fileHeader;
|
|
WORD optionalMagic = 0;
|
|
USHORT subsystem = 0;
|
|
LARGE_INTEGER offset;
|
|
DWORD bytesRead = 0;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
if (ImagePath == NULL || ImagePath[0] == L'\0' || SubsystemOut == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
*SubsystemOut = IMAGE_SUBSYSTEM_UNKNOWN;
|
|
fileHandle = CreateFileW(ImagePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (fileHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ReadFile(fileHandle, &dosHeader, sizeof(dosHeader), &bytesRead, NULL) || bytesRead != sizeof(dosHeader))
|
|
{
|
|
err = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE || dosHeader.e_lfanew <= 0)
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
offset.QuadPart = dosHeader.e_lfanew;
|
|
if (!SetFilePointerEx(fileHandle, offset, NULL, FILE_BEGIN) ||
|
|
!ReadFile(fileHandle, &signature, sizeof(signature), &bytesRead, NULL) || bytesRead != sizeof(signature) ||
|
|
signature != IMAGE_NT_SIGNATURE || !ReadFile(fileHandle, &fileHeader, sizeof(fileHeader), &bytesRead, NULL) ||
|
|
bytesRead != sizeof(fileHeader))
|
|
{
|
|
err = GetLastError();
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (fileHeader.SizeOfOptionalHeader < sizeof(WORD) ||
|
|
!ReadFile(fileHandle, &optionalMagic, sizeof(optionalMagic), &bytesRead, NULL) ||
|
|
bytesRead != sizeof(optionalMagic))
|
|
{
|
|
err = GetLastError();
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (optionalMagic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
|
{
|
|
if (fileHeader.SizeOfOptionalHeader < FIELD_OFFSET(IMAGE_OPTIONAL_HEADER32, Subsystem) + sizeof(subsystem))
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
goto Cleanup;
|
|
}
|
|
offset.QuadPart = dosHeader.e_lfanew + sizeof(signature) + sizeof(fileHeader) +
|
|
FIELD_OFFSET(IMAGE_OPTIONAL_HEADER32, Subsystem);
|
|
}
|
|
else if (optionalMagic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
|
|
{
|
|
if (fileHeader.SizeOfOptionalHeader < FIELD_OFFSET(IMAGE_OPTIONAL_HEADER64, Subsystem) + sizeof(subsystem))
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
goto Cleanup;
|
|
}
|
|
offset.QuadPart = dosHeader.e_lfanew + sizeof(signature) + sizeof(fileHeader) +
|
|
FIELD_OFFSET(IMAGE_OPTIONAL_HEADER64, Subsystem);
|
|
}
|
|
else
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!SetFilePointerEx(fileHandle, offset, NULL, FILE_BEGIN) ||
|
|
!ReadFile(fileHandle, &subsystem, sizeof(subsystem), &bytesRead, NULL) || bytesRead != sizeof(subsystem))
|
|
{
|
|
err = GetLastError();
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
err = ERROR_BAD_EXE_FORMAT;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
*SubsystemOut = subsystem;
|
|
CloseHandle(fileHandle);
|
|
return TRUE;
|
|
|
|
Cleanup:
|
|
CloseHandle(fileHandle);
|
|
SetLastError((err == ERROR_SUCCESS) ? ERROR_BAD_EXE_FORMAT : err);
|
|
return FALSE;
|
|
}
|
|
|
|
typedef BOOL(WINAPI *BK_IS_WOW64_PROCESS2_FN)(_In_ HANDLE ProcessHandle, _Out_ USHORT *ProcessMachine,
|
|
_Out_ USHORT *NativeMachine);
|
|
|
|
static BOOL ControllerInjectionQueryProcessMachine(_In_ HANDLE ProcessHandle, _Out_ USHORT *ProcessMachineOut,
|
|
_Out_opt_ USHORT *NativeMachineOut)
|
|
{
|
|
HMODULE kernel32Module = NULL;
|
|
BK_IS_WOW64_PROCESS2_FN isWow64Process2Fn = NULL;
|
|
USHORT processMachine = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
USHORT nativeMachine = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
BOOL wow64 = FALSE;
|
|
|
|
if (ProcessHandle == NULL || ProcessHandle == INVALID_HANDLE_VALUE || ProcessMachineOut == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
kernel32Module = GetModuleHandleW(L"kernel32.dll");
|
|
isWow64Process2Fn =
|
|
(kernel32Module != NULL) ? (BK_IS_WOW64_PROCESS2_FN)GetProcAddress(kernel32Module, "IsWow64Process2") : NULL;
|
|
if (isWow64Process2Fn != NULL)
|
|
{
|
|
if (!isWow64Process2Fn(ProcessHandle, &processMachine, &nativeMachine))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!IsWow64Process(ProcessHandle, &wow64))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#if defined(_WIN64)
|
|
processMachine = wow64 ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64;
|
|
nativeMachine = IMAGE_FILE_MACHINE_AMD64;
|
|
#elif defined(_M_IX86)
|
|
processMachine = IMAGE_FILE_MACHINE_I386;
|
|
nativeMachine = IMAGE_FILE_MACHINE_I386;
|
|
#elif defined(_M_ARM64)
|
|
processMachine = wow64 ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_ARM64;
|
|
nativeMachine = IMAGE_FILE_MACHINE_ARM64;
|
|
#else
|
|
processMachine = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
nativeMachine = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
#endif
|
|
}
|
|
|
|
*ProcessMachineOut = processMachine;
|
|
if (NativeMachineOut != NULL)
|
|
{
|
|
*NativeMachineOut = nativeMachine;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD ControllerInjectionValidateHookArchitecture(_In_ HANDLE ProcessHandle, _In_z_ PCWSTR HookDllPath)
|
|
{
|
|
USHORT hookMachine = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
USHORT processMachine = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
USHORT nativeMachine = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
USHORT effectiveProcessMachine = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
DWORD err;
|
|
|
|
if (ProcessHandle == NULL || ProcessHandle == INVALID_HANDLE_VALUE || HookDllPath == NULL ||
|
|
HookDllPath[0] == L'\0')
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!ControllerInjectionReadImageMachine(HookDllPath, &hookMachine))
|
|
{
|
|
err = GetLastError();
|
|
return (err == ERROR_SUCCESS) ? ERROR_BAD_EXE_FORMAT : err;
|
|
}
|
|
|
|
if (!ControllerInjectionQueryProcessMachine(ProcessHandle, &processMachine, &nativeMachine))
|
|
{
|
|
err = GetLastError();
|
|
return (err == ERROR_SUCCESS) ? ERROR_GEN_FAILURE : err;
|
|
}
|
|
|
|
effectiveProcessMachine = (processMachine != IMAGE_FILE_MACHINE_UNKNOWN) ? processMachine : nativeMachine;
|
|
#if defined(_WIN64)
|
|
if (effectiveProcessMachine == IMAGE_FILE_MACHINE_UNKNOWN)
|
|
{
|
|
effectiveProcessMachine = IMAGE_FILE_MACHINE_AMD64;
|
|
}
|
|
#endif
|
|
|
|
if (hookMachine != IMAGE_FILE_MACHINE_UNKNOWN && effectiveProcessMachine != IMAGE_FILE_MACHINE_UNKNOWN &&
|
|
hookMachine != effectiveProcessMachine)
|
|
{
|
|
return ERROR_BAD_EXE_FORMAT;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
BOOL ControllerInjectionPathPointsToFile(_In_z_ PCWSTR Path)
|
|
{
|
|
DWORD attrs;
|
|
|
|
if (Path == NULL || Path[0] == L'\0')
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
attrs = GetFileAttributesW(Path);
|
|
if (attrs == INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0);
|
|
}
|
|
|
|
BOOL ControllerInjectionResolveHookDllPath(_In_ const BKIPC_SET_USER_HOOK_TARGET_REQUEST *Request,
|
|
_Out_writes_z_(OutputChars) PWSTR Output, _In_ size_t OutputChars)
|
|
{
|
|
WCHAR modulePath[BK_MAX_IMAGE_PATH_CHARS];
|
|
PWSTR slash;
|
|
DWORD chars;
|
|
|
|
if (Request == NULL || Output == NULL || OutputChars == 0)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
Output[0] = L'\0';
|
|
if (Request->HookDllPath[0] != L'\0' && ControllerInjectionPathPointsToFile(Request->HookDllPath))
|
|
{
|
|
return SUCCEEDED(StringCchCopyW(Output, OutputChars, Request->HookDllPath));
|
|
}
|
|
|
|
ZeroMemory(modulePath, sizeof(modulePath));
|
|
chars = GetModuleFileNameW(NULL, modulePath, RTL_NUMBER_OF(modulePath));
|
|
if (chars == 0 || chars >= RTL_NUMBER_OF(modulePath))
|
|
{
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
|
|
slash = wcsrchr(modulePath, L'\\');
|
|
if (slash == NULL)
|
|
{
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
slash[1] = L'\0';
|
|
|
|
if (FAILED(StringCchCatW(modulePath, RTL_NUMBER_OF(modulePath), L"SR71.dll")))
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ControllerInjectionPathPointsToFile(modulePath))
|
|
{
|
|
SetLastError(ERROR_FILE_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
|
|
if (FAILED(StringCchCopyW(Output, OutputChars, modulePath)))
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|