Esempio n. 1
0
EASYHOOK_NT_EXPORT LhBarrierGetCallingModule(MODULE_INFORMATION* OutModule)
{
/*
Description:

    The given storage will receive the calling unmanaged module.

Returns:

    STATUS_NOT_FOUND
            
        No matching module could be found.

*/
    NTSTATUS        NtStatus;
    UCHAR*          ReturnAddress;

    FORCE(LhBarrierGetReturnAddress((PVOID*)&ReturnAddress));

    FORCE(LhBarrierPointerToModule(ReturnAddress, OutModule));

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
	return NtStatus;
}
Esempio n. 2
0
bool FKRuijie()
{
	NTSTATUS NtStatus;
	ULONG ACLEntries[1] = {0};
	TRACED_HOOK_HANDLE hHook = new HOOK_TRACE_INFO();

	hProcSetTimer = (FUNC)GetProcAddress(LoadLibraryA("user32.dll"), "SetTimer");


	FORCE(LhInstallHook(
		hProcSetTimer,
		SetTimerHook,
		(PVOID)0x12345678,
		hHook));

	FORCE(LhSetInclusiveACL(ACLEntries, 1, hHook));

	return TRUE;

ERROR_ABORT:

	if(hHook != NULL)
		delete hHook;

	if(RtlGetLastError() != 0)
		MessageBoxA(NULL, "ERROR", "FKAdvapi", 0);

	return NtStatus;
}
Esempio n. 3
0
NTSTATUS RunTestSuite()
{
	HOOK_TRACE_INFO			hHook = { NULL };
    NTSTATUS                NtStatus;
    ULONG                   ACLEntries[1] = {0};
	UNICODE_STRING			SymbolName;
	KTIMER					Timer;
	BOOLEAN					HasInterface = FALSE;
	PFILE_OBJECT			hEasyHookDrv;

	FORCE(EasyHookQueryInterface(EASYHOOK_INTERFACE_v_1, &Interface, &hEasyHookDrv));

	HasInterface = TRUE;

	RtlInitUnicodeString(&SymbolName, L"KeCancelTimer");

    /*
        The following shows how to install and remove local hooks...
    */
    FORCE(Interface.LhInstallHook(
            MmGetSystemRoutineAddress(&SymbolName),
            KeCancelTimer_Hook,
            (PVOID)0x12345678,
            &hHook));

    // won't invoke the hook handle because hooks are inactive after installation
	KeInitializeTimer(&Timer);

    KeCancelTimer(&Timer);

    // activate the hook for the current thread
    FORCE(Interface.LhSetInclusiveACL(ACLEntries, 1, &hHook));

    // will be redirected into the handler...
    KeCancelTimer(&Timer);

    // this will NOT unhook the entry point. But the associated handler is never called again...
    Interface.LhUninstallHook(&hHook);

    // this will restore ALL entry points of currently rending removals issued by LhUninstallHook()
    Interface.LhWaitForPendingRemovals();

	ObDereferenceObject(hEasyHookDrv);

	return STATUS_SUCCESS;

ERROR_ABORT:

	if(HasInterface)
	{
		ObDereferenceObject(hEasyHookDrv);

		KdPrint(("\n[Error]: \"%S\" (code: %d)\n", Interface.RtlGetLastErrorString(), Interface.RtlGetLastError()));
	}
	else
		KdPrint(("\n[Error]: \"Unable to obtain EasyHook interface.\" (code: %d)\n", NtStatus));

    return NtStatus;
}
Esempio n. 4
0
EASYHOOK_NT_EXPORT LhBarrierEndStackTrace(PVOID InBackup)
{
/*
Description:

    Is expected to be called inside a hook handler. Otherwise it
    will fail with STATUS_NOT_SUPPORTED. 

    You have to pass the backup pointer obtained with
    LhBarrierBeginStackTrace().
*/
    NTSTATUS            NtStatus;
    PVOID*              AddrOfRetAddr;

    if(!IsValidPointer(InBackup, 1))
        THROW(STATUS_INVALID_PARAMETER, L"The given stack backup pointer is invalid.");

    FORCE(LhBarrierGetAddressOfReturnAddress(&AddrOfRetAddr));

    *AddrOfRetAddr = InBackup;

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Esempio n. 5
0
EASYHOOK_NT_EXPORT DbgGetThreadIdByHandle(
                HANDLE InThreadHandle,
                ULONG* OutThreadId)
{
/*
Description:

    Translates the given thread handle back to its thread ID if possible.

Parameters:

    - InThreadHandle

        A thread handle with THREAD_QUERY_INFORMATION access.

    - OutThreadId

        Receives the thread ID.
*/
    THREAD_BASIC_INFORMATION        ThreadInfo;
    NTSTATUS                        NtStatus;

    if(!IsValidPointer(OutThreadId, sizeof(ULONG)))
        THROW(STATUS_INVALID_PARAMETER_2, L"Invalid TID storage specified."); 

    if(ZwQueryInformationThread != NULL)
    {
	    // use deprecated API
	    FORCE(ZwQueryInformationThread(
            InThreadHandle, 
            0 /* ThreadBasicInformation */, 
            &ThreadInfo, 
            sizeof(ThreadInfo), 
            NULL));

        *OutThreadId = ThreadInfo.ClientId.UniqueThread;
    }
    else
    {
	    ASSERT(ZwGetThreadId != NULL);

	    // use new support API
	    if((*OutThreadId = ZwGetThreadId(InThreadHandle)) == 0)
		    THROW(STATUS_INVALID_PARAMETER_1, L"Invalid thread handler or improper privileges.");
    }

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Esempio n. 6
0
EASYHOOK_NT_EXPORT DbgGetProcessIdByHandle(
                HANDLE InProcessHandle,
                ULONG* OutProcessId)
{
/*
Description:

    Translates the given process handle back to its process ID if possible.

Parameters:

    - InProcessHandle

        A process handle with PROCESS_QUERY_INFORMATION access.

    - OutProcessId

        Receives the process ID.
*/
    PROCESS_BASIC_INFORMATION       ProcInfo;
    NTSTATUS                        NtStatus;

    if(!IsValidPointer(OutProcessId, sizeof(ULONG)))
        THROW(STATUS_INVALID_PARAMETER_2, L"The given process ID storage is invalid.");

    if(ZwQueryInformationProcess != NULL)
    {
	    // use deprecated API
	    FORCE(ZwQueryInformationProcess(
            InProcessHandle, 
            0 /* ProcessBasicInformation */, 
            &ProcInfo, 
            sizeof(ProcInfo), 
            NULL));

	    *OutProcessId = (ULONG)ProcInfo.UniqueProcessId;
    }
    else
    {
	    ASSERT(ZwGetProcessId != NULL);

	    // use new support API
	    if((*OutProcessId = ZwGetProcessId(InProcessHandle)) == 0)
		    THROW(STATUS_INVALID_PARAMETER_1, L"Invalid process handle or improper privileges.");
    }

RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Esempio n. 7
0
static LONG hook_init()
{
	ULONG ACLEntries[1] = {0};
	NTSTATUS NtStatus;

#include "hooklist.h"
#undef HOOK_DEFINE

	FORCE(LhSetGlobalExclusiveACL(ACLEntries, 0));
	return NOERROR;

ERROR_ABORT:
	TRACE(_T("hook_init error: %#x\n"), NtStatus);
	return 1;
}
Esempio n. 8
0
static int draw_remove(struct render_command * __rcmd,
			rcmd_remove_reason_t reason, int flags)
{
	struct rcmd_draw * rcmd =
		container_of(__rcmd, struct rcmd_draw, base);
	FORCE(SYSTEM, "Draw remove\n");
	glDeleteProgram(rcmd->program);
	glDeleteShader(rcmd->vertex_shader);
	glDeleteShader(rcmd->fragment_shader);
	glDeleteBuffers(1, &rcmd->buffer);

	if (rcmd->tex)
		TEXGL_RELEASE(rcmd->tex);
	if (rcmd->tex2)
		TEXGL_RELEASE(rcmd->tex2);
	return 0;
}
Esempio n. 9
0
EASYHOOK_NT_INTERNAL LhRoundToNextInstruction(
			void* InCodePtr,
			ULONG InCodeSize)
{
/*
Description:

    Will round the given code size up so that the return
    value spans at least over "InCodeSize" bytes and always
    ends on instruction boundaries.

Parameters:

    - InCodePtr

        A code portion the given size should be aligned to.

    - InCodeSize

        The minimum return value.

Returns:

    STATUS_INVALID_PARAMETER

        The given pointer references invalid machine code.
*/
	UCHAR*				Ptr = (UCHAR*)InCodePtr;
	UCHAR*				BasePtr = Ptr;
    NTSTATUS            NtStatus;

	while(BasePtr + InCodeSize > Ptr)
	{
		FORCE(NtStatus = LhGetInstructionLength(Ptr));

		Ptr += NtStatus;
	}

	return (ULONG)(Ptr - BasePtr);

THROW_OUTRO:
    return NtStatus;
}
Esempio n. 10
0
EASYHOOK_NT_EXPORT RhInjectLibrary(
		ULONG InTargetPID,
		ULONG InWakeUpTID,
		ULONG InInjectionOptions,
		WCHAR* InLibraryPath_x86,
		WCHAR* InLibraryPath_x64,
		PVOID InPassThruBuffer,
        ULONG InPassThruSize)
{
/*
Description:

    Injects a library into the target process. This is a very stable operation.
    The problem so far is, that only the NET layer will support injection
    through WOW64 boundaries and into other terminal sessions. It is quite
    complex to realize with unmanaged code and that's why it is not supported!

    If you really need this feature I highly recommend to at least look at C++.NET
    because using the managed injection can speed up your development progress
    about orders of magnitudes. I know by experience that writing the required
    multi-process injection code in any unmanaged language is a rather daunting task!

Parameters:

    - InTargetPID

        The process in which the library should be injected.
    
    - InWakeUpTID

        If the target process was created suspended (RhCreateAndInject), then
        this parameter should be set to the main thread ID of the target.
        You may later resume the process from within the injected library
        by calling RhWakeUpProcess(). If the process is already running, you
        should specify zero.

    - InInjectionOptions

        All flags can be combined.

        EASYHOOK_INJECT_DEFAULT: 
            
            No special behavior. The given libraries are expected to be unmanaged DLLs.
            Further they should export an entry point named 
            "NativeInjectionEntryPoint" (in case of 64-bit) and
            "_NativeInjectionEntryPoint@4" (in case of 32-bit). The expected entry point 
            signature is REMOTE_ENTRY_POINT.

        EASYHOOK_INJECT_MANAGED: 
        
            The given user library is a NET assembly. Further they should export a class
            named "EasyHook.InjectionLoader" with a static method named "Main". The
            signature of this method is expected to be "int (String)". Please refer
            to the managed injection loader of EasyHook for more information about
            writing such managed entry points.

        EASYHOOK_INJECT_STEALTH:

            Uses the experimental stealth thread creation. If it fails
            you may try it with default settings. 

		EASYHOOK_INJECT_HEART_BEAT:
			
			Is only used internally to workaround the managed process creation bug.
			For curiosity, NET seems to hijack our remote thread if a managed process
			is created suspended. It doesn't do anything with the suspended main thread,


    - InLibraryPath_x86

        A relative or absolute path to the 32-bit version of the user library being injected.
        If you don't want to inject into 32-Bit processes, you may set this parameter to NULL.

    - InLibraryPath_x64

        A relative or absolute path to the 64-bit version of the user library being injected.
        If you don't want to inject into 64-Bit processes, you may set this parameter to NULL.

    - InPassThruBuffer

        An optional buffer containg data to be passed to the injection entry point. Such data
        is available in both, the managed and unmanaged user library entry points.
        Set to NULL if no used.

    - InPassThruSize

        Specifies the size in bytes of the pass thru data. If "InPassThruBuffer" is NULL, this
        parameter shall also be zero.

Returns:

    

*/
	HANDLE					hProc = NULL;
	HANDLE					hRemoteThread = NULL;
	HANDLE					hSignal = NULL;
	UCHAR*					RemoteInjectCode = NULL;
	LPREMOTE_INFO			Info = NULL;
    LPREMOTE_INFO           RemoteInfo = NULL;
	ULONG					RemoteInfoSize = 0;
	BYTE*					Offset = 0;
    ULONG                   CodeSize;
    BOOL                    Is64BitTarget;
    NTSTATUS				NtStatus;
    LONGLONG                Diff;
    HANDLE                  Handles[2];

    ULONG                   UserLibrarySize;
    ULONG                   PATHSize;
    ULONG                   EasyHookPathSize;
    ULONG                   EasyHookEntrySize;
    ULONG                   Code;

    SIZE_T                  BytesWritten;
    WCHAR                   UserLibrary[MAX_PATH+1];
    WCHAR					PATH[MAX_PATH + 1];
    WCHAR					EasyHookPath[MAX_PATH + 1];
#ifdef _M_X64
	CHAR*					EasyHookEntry = "HookCompleteInjection";
#else
	CHAR*					EasyHookEntry = "_HookCompleteInjection@4";
#endif

    // validate parameters
    if(InPassThruSize > MAX_PASSTHRU_SIZE)
        THROW(STATUS_INVALID_PARAMETER_7, L"The given pass thru buffer is too large.");

    if(InPassThruBuffer != NULL)
    {
        if(!IsValidPointer(InPassThruBuffer, InPassThruSize))
            THROW(STATUS_INVALID_PARAMETER_6, L"The given pass thru buffer is invalid.");
    }
    else if(InPassThruSize != 0)
        THROW(STATUS_INVALID_PARAMETER_7, L"If no pass thru buffer is specified, the pass thru length also has to be zero.");

	if(InTargetPID == GetCurrentProcessId())
		THROW(STATUS_NOT_SUPPORTED, L"For stability reasons it is not supported to inject into the calling process.");

	// open target process
	if((hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, InTargetPID)) == NULL)
	{
		if(GetLastError() == ERROR_ACCESS_DENIED)
		    THROW(STATUS_ACCESS_DENIED, L"Unable to open target process. Consider using a system service.")
		else
			THROW(STATUS_NOT_FOUND, L"The given target process does not exist!");
	}

	/*
		Check bitness...

		After this we can assume hooking a target that is running in the same
		WOW64 level.
	*/
#ifdef _M_X64
	FORCE(RhIsX64Process(InTargetPID, &Is64BitTarget));
      
    if(!Is64BitTarget)
        THROW(STATUS_WOW_ASSERTION, L"It is not supported to directly hook through the WOW64 barrier.");

    if(!GetFullPathNameW(InLibraryPath_x64, MAX_PATH, UserLibrary, NULL))
        THROW(STATUS_INVALID_PARAMETER_5, L"Unable to get full path to the given 64-bit library.");
#else
	FORCE(RhIsX64Process(InTargetPID, &Is64BitTarget));
      
    if(Is64BitTarget)
        THROW(STATUS_WOW_ASSERTION, L"It is not supported to directly hook through the WOW64 barrier.");

	if(!GetFullPathNameW(InLibraryPath_x86, MAX_PATH, UserLibrary, NULL))
        THROW(STATUS_INVALID_PARAMETER_4, L"Unable to get full path to the given 32-bit library.");
#endif

	/*
		Validate library path...
	*/
	if(!RtlFileExists(UserLibrary))
    {
    #ifdef _M_X64
        THROW(STATUS_INVALID_PARAMETER_5, L"The given 64-Bit library does not exist!");
    #else
        THROW(STATUS_INVALID_PARAMETER_4, L"The given 32-Bit library does not exist!");
    #endif
    }

	// import strings...
    RtlGetWorkingDirectory(PATH, MAX_PATH - 1);
    RtlGetCurrentModulePath(EasyHookPath, MAX_PATH);

	// allocate remote information block
    EasyHookPathSize = (RtlUnicodeLength(EasyHookPath) + 1) * 2;
    EasyHookEntrySize = (RtlAnsiLength(EasyHookEntry) + 1);
    PATHSize = (RtlUnicodeLength(PATH) + 1 + 1) * 2;
    UserLibrarySize = (RtlUnicodeLength(UserLibrary) + 1 + 1) * 2;

    PATH[PATHSize / 2 - 2] = ';';
    PATH[PATHSize / 2 - 1] = 0;

	RemoteInfoSize = EasyHookPathSize + EasyHookEntrySize + PATHSize + InPassThruSize + UserLibrarySize;

	RemoteInfoSize += sizeof(REMOTE_INFO);

	if((Info = (LPREMOTE_INFO)RtlAllocateMemory(TRUE, RemoteInfoSize)) == NULL)
		THROW(STATUS_NO_MEMORY, L"Unable to allocate memory in current process.");

	Info->LoadLibraryW = (PVOID)GetProcAddress(hKernel32, "LoadLibraryW");
	Info->FreeLibrary = (PVOID)GetProcAddress(hKernel32, "FreeLibrary");
	Info->GetProcAddress = (PVOID)GetProcAddress(hKernel32, "GetProcAddress");
	Info->VirtualFree = (PVOID)GetProcAddress(hKernel32, "VirtualFree");
	Info->VirtualProtect = (PVOID)GetProcAddress(hKernel32, "VirtualProtect");
	Info->ExitThread = (PVOID)GetProcAddress(hKernel32, "ExitThread");
	Info->GetLastError = (PVOID)GetProcAddress(hKernel32, "GetLastError");

    Info->WakeUpThreadID = InWakeUpTID;
    Info->IsManaged = InInjectionOptions & EASYHOOK_INJECT_MANAGED;

	// allocate memory in target process
	CodeSize = GetInjectionSize();

	if((RemoteInjectCode = (BYTE*)VirtualAllocEx(hProc, NULL, CodeSize + RemoteInfoSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == NULL)
        THROW(STATUS_NO_MEMORY, L"Unable to allocate memory in target process.");

	// save strings
	Offset = (BYTE*)(Info + 1);

	Info->EasyHookEntry = (char*)Offset;
	Info->EasyHookPath = (wchar_t*)(Offset += EasyHookEntrySize);
	Info->PATH = (wchar_t*)(Offset += EasyHookPathSize);
	Info->UserData = (BYTE*)(Offset += PATHSize);
    Info->UserLibrary = (WCHAR*)(Offset += InPassThruSize);

	Info->Size = RemoteInfoSize;
	Info->HostProcess = GetCurrentProcessId();
	Info->UserDataSize = 0;

	Offset += UserLibrarySize;

	if((ULONG)(Offset - ((BYTE*)Info)) > Info->Size)
        THROW(STATUS_BUFFER_OVERFLOW, L"A buffer overflow in internal memory was detected.");

	RtlCopyMemory(Info->EasyHookPath, EasyHookPath, EasyHookPathSize);
	RtlCopyMemory(Info->PATH, PATH, PATHSize);
	RtlCopyMemory(Info->EasyHookEntry, EasyHookEntry, EasyHookEntrySize);
    RtlCopyMemory(Info->UserLibrary, UserLibrary, UserLibrarySize);


	if(InPassThruBuffer != NULL)
	{
		RtlCopyMemory(Info->UserData, InPassThruBuffer, InPassThruSize);

		Info->UserDataSize = InPassThruSize;
	}

	// copy code into target process
	if(!WriteProcessMemory(hProc, RemoteInjectCode, GetInjectionPtr(), CodeSize, &BytesWritten) || (BytesWritten != CodeSize))
		THROW(STATUS_INTERNAL_ERROR, L"Unable to write into target process memory.");

	// create and export signal event>
	if((hSignal = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
        THROW(STATUS_INSUFFICIENT_RESOURCES, L"Unable to create event.");

	// Possible resource leck: the remote handles cannt be closed here if an error occurs
	if(!DuplicateHandle(GetCurrentProcess(), hSignal, hProc, &Info->hRemoteSignal, EVENT_ALL_ACCESS, FALSE, 0))
		THROW(STATUS_INTERNAL_ERROR, L"Failed to duplicate remote event.");

	// relocate remote information
	RemoteInfo = (LPREMOTE_INFO)(RemoteInjectCode + CodeSize);
	Diff = ((BYTE*)RemoteInfo - (BYTE*)Info);

	Info->EasyHookEntry = (char*)(((BYTE*)Info->EasyHookEntry) + Diff);
	Info->EasyHookPath = (wchar_t*)(((BYTE*)Info->EasyHookPath) + Diff);
	Info->PATH = (wchar_t*)(((BYTE*)Info->PATH) + Diff);
    Info->UserLibrary = (wchar_t*)(((BYTE*)Info->UserLibrary) + Diff);

	if(Info->UserData != NULL)
		Info->UserData = (BYTE*)(((BYTE*)Info->UserData) + Diff);

	Info->RemoteEntryPoint = RemoteInjectCode;

	if(!WriteProcessMemory(hProc, RemoteInfo, Info, RemoteInfoSize, &BytesWritten) || (BytesWritten != RemoteInfoSize))
		THROW(STATUS_INTERNAL_ERROR, L"Unable to write into target process memory.");

	if((InInjectionOptions & EASYHOOK_INJECT_STEALTH) != 0)
	{
		FORCE(RhCreateStealthRemoteThread(InTargetPID, (LPTHREAD_START_ROUTINE)RemoteInjectCode, RemoteInfo, &hRemoteThread));
	}
	else
	{
		if(!RTL_SUCCESS(NtCreateThreadEx(hProc, (LPTHREAD_START_ROUTINE)RemoteInjectCode, RemoteInfo, FALSE, &hRemoteThread)))
		{
			// create remote thread and wait for injection completion
			if((hRemoteThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)RemoteInjectCode, RemoteInfo, 0, NULL)) == NULL)
				THROW(STATUS_ACCESS_DENIED, L"Unable to create remote thread.");
		}
	}

	/*
	 * The assembler codes are designed to let us derive extensive error information...
	*/
    Handles[1] = hSignal;
	Handles[0] = hRemoteThread;

	Code = WaitForMultipleObjects(2, Handles, FALSE, INFINITE);

	if(Code == WAIT_OBJECT_0)
	{
		// parse error code
		GetExitCodeThread(hRemoteThread, &Code);

		SetLastError(Code & 0x0FFFFFFF);

		switch(Code & 0xF0000000)
		{
		case 0x10000000: THROW(STATUS_INTERNAL_ERROR, L"Unable to find internal entry point.");
		case 0x20000000: THROW(STATUS_INTERNAL_ERROR, L"Unable to make stack executable.");
		case 0x30000000: THROW(STATUS_INTERNAL_ERROR, L"Unable to release injected library.");
		case 0x40000000: THROW(STATUS_INTERNAL_ERROR, L"Unable to find EasyHook library in target process context.");
		case 0xF0000000: // error in C++ injection completion
			{
				switch(Code & 0xFF)
				{
#ifdef _M_X64
                case 20: THROW(STATUS_INVALID_PARAMETER_5, L"Unable to load the given 64-bit library into target process.");
                case 21: THROW(STATUS_INVALID_PARAMETER_5, L"Unable to find the required native entry point in the given 64-bit library.");
                case 12: THROW(STATUS_INVALID_PARAMETER_5, L"Unable to find the required managed entry point in the given 64-bit library.");
#else
                case 20: THROW(STATUS_INVALID_PARAMETER_4, L"Unable to load the given 32-bit library into target process.");
                case 21: THROW(STATUS_INVALID_PARAMETER_4, L"Unable to find the required native entry point in the given 32-bit library.");
                case 12: THROW(STATUS_INVALID_PARAMETER_4, L"Unable to find the required managed entry point in the given 32-bit library.");
#endif
                
                case 13: THROW(STATUS_DLL_INIT_FAILED, L"The user defined managed entry point failed in the target process. Make sure that EasyHook is registered in the GAC. Refer to event logs for more information.");
				case 1: THROW(STATUS_INTERNAL_ERROR, L"Unable to allocate memory in target process.");
				case 2: THROW(STATUS_INTERNAL_ERROR, L"Unable to adjust target's PATH variable.");
                case 10: THROW(STATUS_INTERNAL_ERROR, L"Unable to load 'mscoree.dll' into target process.");
				case 11: THROW(STATUS_INTERNAL_ERROR, L"Unable to bind NET Runtime to target process.");
				case 22: THROW(STATUS_INTERNAL_ERROR, L"Unable to signal remote event.");
				default: THROW(STATUS_INTERNAL_ERROR, L"Unknown error in injected C++ completion routine.");
				}
			}break;
		case 0:
			THROW(STATUS_INTERNAL_ERROR, L"C++ completion routine has returned success but didn't raise the remote event.");
		default:
			THROW(STATUS_INTERNAL_ERROR, L"Unknown error in injected assembler code.");
		}
	}
	else if(Code != WAIT_OBJECT_0 + 1)
		THROW(STATUS_INTERNAL_ERROR, L"Unable to wait for injection completion due to timeout. ");

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    {
		// release resources
		if(hProc != NULL)
			CloseHandle(hProc);

		if(Info != NULL)
			RtlFreeMemory(Info);

		if(hRemoteThread != NULL)
			CloseHandle(hRemoteThread);

		if(hSignal != NULL)
			CloseHandle(hSignal);

        return NtStatus;
	}
}
Esempio n. 11
0
EASYHOOK_NT_EXPORT LhBarrierPointerToModule(
              PVOID InPointer,
              MODULE_INFORMATION* OutModule)
{
/*
Description:

    Translates the given pointer (likely a method) to its
    owning module if possible.

Parameters:

    - InPointer

        A method pointer to be translated.

    - OutModule

        Receives the owner of a given method.
        
Returns:

    STATUS_NOT_FOUND
            
        No matching module could be found.
*/
    UCHAR*					Pointer = (UCHAR*)InPointer;
    NTSTATUS				NtStatus;
    BOOL					CanTryAgain = TRUE;
	MODULE_INFORMATION*		List;

	if(!IsValidPointer(OutModule, sizeof(MODULE_INFORMATION)))
		THROW(STATUS_INVALID_PARAMETER_2, L"The given module storage is invalid.");

LABEL_TRY_AGAIN:

	RtlAcquireLock(&GlobalHookLock);
	{
		List = LhModuleArray;

		// walk through process modules
		while(List != NULL)
		{
			if((Pointer >= List->BaseAddress) && (Pointer <= List->BaseAddress + List->ImageSize))
			{
				*OutModule = *List;

				RtlReleaseLock(&GlobalHookLock);

				RETURN;
			}

			List = List->Next;
		}
	}
	RtlReleaseLock(&GlobalHookLock);

    if((InPointer == NULL) || (InPointer == (PVOID)~0))
    {
        // this pointer does not belong to any module...
    }
    else
    {
        // unable to find calling module...
        FORCE(LhUpdateModuleInformation());

        if(CanTryAgain)
        {
            CanTryAgain = FALSE;

            goto LABEL_TRY_AGAIN;
        }
    }

    THROW(STATUS_NOT_FOUND, L"Unable to determine module.");

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Esempio n. 12
0
EASYHOOK_NT_INTERNAL NtCreateThreadEx(
	HANDLE InProcess,
	LPTHREAD_START_ROUTINE InRemoteThreadStart,
	void* InRemoteCallback,
	BOOLEAN InCreateSuspended,
    HANDLE* OutThread)
{
/*
Description:

	Only intended for Vista and later... Will return NULL for all others which
	should use CreateRemoteThread() and services instead!

	In contrast to RtlCreateUserThread() this one will fortunately setup a proper activation
	context stack, which is required to load the NET framework and many other
	common APIs. This is why RtlCreateUserThread() can't be used for Windows XP
	,for example, even if it would replace the windows service approach which is required
	in order to get CreateRemoteThread() working.

	Injection through WOW64 boundaries is still not directly supported and requires
	a WOW64 bypass helper process.

Parameters:

    - InProcess

        A target process opened with PROCESS_ALL_ACCESS.

    - InRemoteThreadStart

        The method executed by the remote thread. Must be valid in the
        context of the given process.

    - InRemoteCallback

        An uninterpreted callback passed to the remote start routine. 
        Must be valid in the context of the given process.

    - OutThread

        Receives a handle to the remote thread. This handle is valid
        in the calling process.

Returns:

    STATUS_NOT_SUPPORTED

        Only Windows Vista and later supports NtCreateThreadEx, all other
        platforms will return this error code.
*/
    HANDLE			        hRemoteThread;
	NTSTATUS            NtStatus;
    NtCreateThreadEx_PROC*  VistaCreateThread;

    if(!IsValidPointer(OutThread, sizeof(HANDLE)))
        THROW(STATUS_INVALID_PARAMETER_4, L"The given handle storage is invalid.");

	// this will only work for vista and later...
	if((VistaCreateThread = (NtCreateThreadEx_PROC*)GetProcAddress(hNtDll, "NtCreateThreadEx")) == NULL)
		THROW(STATUS_NOT_SUPPORTED, L"NtCreateThreadEx() is not supported.");

	FORCE(VistaCreateThread(
			&hRemoteThread,
			0x1FFFFF, // all access
			NULL,
			InProcess,
			(LPTHREAD_START_ROUTINE)InRemoteThreadStart,
			InRemoteCallback,
			InCreateSuspended,
			0,
			NULL,
			NULL,
			NULL
			));

    *OutThread = hRemoteThread;

	RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Esempio n. 13
0
EASYHOOK_NT_EXPORT RhCreateAndInject(
		WCHAR* InEXEPath,
        WCHAR* InCommandLine,
		ULONG InProcessCreationFlags,
		ULONG InInjectionOptions,
		WCHAR* InLibraryPath_x86,
		WCHAR* InLibraryPath_x64,
		PVOID InPassThruBuffer,
        ULONG InPassThruSize,
        ULONG* OutProcessId)
{
/*
Description:

    Creates a suspended process and immediately injects the user library.
    This is done BEFORE any of the usual process initialization is called.
    When the injection is made, NO thread has actually executed any instruction 
    so far... It is just like your library entry point is the first thing
    executed in such a process and you can allow the original execution to
    take place by calling RhWakeUpProcess() in the injected library. But even
    that is no requirement for the process to work...

Parameters:

    - InEXEPath

        A relative or absolute path to the EXE file of the process being created.

    - InCommandLine

        Optional command line parameters passed to the newly created process.

	- InProcessCreationFlags

		Custom process creation flags.

    - InInjectionOptions

        All flags can be combined.

        EASYHOOK_INJECT_DEFAULT: 
            
            No special behavior. The given libraries are expected to be unmanaged DLLs.
            Further they should export an entry point named 
            "NativeInjectionEntryPoint" (in case of 64-bit) and
            "_NativeInjectionEntryPoint@4" (in case of 32-bit). The expected entry point 
            signature is REMOTE_ENTRY_POINT.

        EASYHOOK_INJECT_MANAGED: 
        
            The given user library is a NET assembly. Further they should export a class
            named "EasyHook.InjectionLoader" with a static method named "Main". The
            signature of this method is expected to be "int (String)". Please refer
            to the managed injection loader of EasyHook for more information about
            writing such managed entry points.

        EASYHOOK_INJECT_STEALTH:

            Uses the experimental stealth thread creation. If it fails
            you may try it with default settings. 

    - InLibraryPath_x86

        A relative or absolute path to the 32-bit version of the user library being injected.
        If you don't want to inject into 32-Bit processes, you may set this parameter to NULL.

    - InLibraryPath_x64

        A relative or absolute path to the 64-bit version of the user library being injected.
        If you don't want to inject into 64-Bit processes, you may set this parameter to NULL.

    - InPassThruBuffer

        An optional buffer containg data to be passed to the injection entry point. Such data
        is available in both, the managed and unmanaged user library entry points.
        Set to NULL if no used.

    - InPassThruSize

        Specifies the size in bytes of the pass thru data. If "InPassThruBuffer" is NULL, this
        parameter shall also be zero.

    - OutProcessId

        Receives the PID of the newly created process.

*/
    ULONG       ProcessId = 0;
    ULONG       ThreadId = 0;
    HANDLE      hProcess = NULL;
    NTSTATUS    NtStatus;

    if(!IsValidPointer(OutProcessId, sizeof(ULONG)))
        THROW(STATUS_INVALID_PARAMETER_8, L"The given process ID storage is invalid.");

    // all other parameters are validate by called APIs...
	FORCE(RtlCreateSuspendedProcess(InEXEPath, InCommandLine, InProcessCreationFlags, &ProcessId, &ThreadId));


    // inject library
    FORCE(RhInjectLibrary(
		    ProcessId,
		    ThreadId,
		    InInjectionOptions,
		    InLibraryPath_x86,
		    InLibraryPath_x64,
		    InPassThruBuffer,
            InPassThruSize));

    *OutProcessId = ProcessId;

    RETURN;

THROW_OUTRO:
    {
        if(ProcessId != 0)
        {
            hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
            
            TerminateProcess(hProcess, 0);

            CloseHandle(hProcess);
        }
    }
FINALLY_OUTRO:
    return NtStatus;
}
Esempio n. 14
0
void CFGNormalizer::configure(const PropList& props) {
	CFGProcessor::configure(props);
	force = FORCE(props);
	verbose = VERBOSE(props);
}
Esempio n. 15
0
EASYHOOK_NT_EXPORT DbgHandleToObjectName(
                HANDLE InNamedHandle,
                PUNICODE_STRING OutNameBuffer,
                ULONG InBufferSize,
                ULONG* OutRequiredSize)
{
/*
Description:

    Queries the kernel space name of a named object. This is
    only possible if the handle refers to a named object of course.

Parameters:

    - InNamedHandle

        A valid file, event, section, etc.

    - OutNameBuffer

        A buffer large enough to hold the kernel space object name.
        To query the required size in bytes, set this parameter to
        NULL.

    - InBufferSize

        The maximum size in bytes the given buffer can hold.

    - OutRequiredSize

        Receives the required size in bytes. This parameter can be NULL.
*/
    ULONG           RequiredSize;
    NTSTATUS        NtStatus;


    if((InNamedHandle == NULL) || (InNamedHandle == INVALID_HANDLE_VALUE))
        THROW(STATUS_INVALID_PARAMETER_1, L"The given handle is invalid.");

    if(!IsValidPointer(OutNameBuffer, InBufferSize))
    {
        // determine required length
        if(InBufferSize != 0)
            THROW(STATUS_INVALID_PARAMETER_3, L"If no buffer is specified, the buffer size is expected to be zero.");

        if(OutRequiredSize == NULL)
            THROW(STATUS_INVALID_PARAMETER_4, L"If no buffer is specified, you are expected to query the required size.");
    }

    if((NtStatus = ZwQueryObject(InNamedHandle, ObjectNameInformation, NULL, 0, &RequiredSize)) 
            != STATUS_INFO_LENGTH_MISMATCH)
        FORCE(NtStatus);

    if(IsValidPointer(OutNameBuffer, InBufferSize))
    {
        // query string
        if(InBufferSize < RequiredSize)
            THROW(STATUS_BUFFER_TOO_SMALL, L"The given buffer is not long enough to hold all the data.");

        FORCE(ZwQueryObject(InNamedHandle, ObjectNameInformation, OutNameBuffer, InBufferSize, &RequiredSize));
    }

    if(IsValidPointer(OutRequiredSize, sizeof(ULONG)))
        *OutRequiredSize = RequiredSize;

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Esempio n. 16
0
extern "C" int main(int argc, wchar_t* argv[])
{
    TRACED_HOOK_HANDLE      hHook = new HOOK_TRACE_INFO();
    NTSTATUS                NtStatus;
    ULONG                   ACLEntries[1] = {0};
    UNICODE_STRING*         NameBuffer = NULL;

    ORIG_CreateFontIndirectW = CreateFontIndirectW;

    FORCE(LhInstallHook(
            ORIG_CreateFontIndirectW,
            IMPL_CreateFontIndirectW,
            (PVOID)0,
            hHook));
    FORCE(LhSetInclusiveACL(ACLEntries, 1, hHook));

    CreateFontIndirectW(0);
    CreateFontW(10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"system");
    LOGFONTA lf = {};
    CreateFontIndirectA(&lf);
    CreateFontA(12, 0, 0, 0, 400, 0, 0, 0, 2, 0, 0, 0, 0, "MARLETT");

#if 0
    ORIG_GetTextExtentPoint32A = GetTextExtentPoint32A;
    FORCE(LhInstallHook(
            ORIG_GetTextExtentPoint32A,
            IMPL_GetTextExtentPoint32A,
            (PVOID)0,
            hHook));
    HDC hdc = GetDC(NULL);
    SIZE size;
    FORCE(LhSetInclusiveACL(ACLEntries, 1, hHook));
    GetTextExtentPoint32W(hdc, L"abc", 3, &size);
    GetTextExtentPointW(hdc, L"abc", 3, &size);
    GetTextExtentPoint32A(hdc, "abc", 3, &size);
    GetTextExtentPointA(hdc, "abc", 3, &size);
#endif

#if 0
    ORIG_MessageBeepHook = MessageBeep;
    /*
        The following shows how to install and remove local hooks...
    */
    FORCE(LhInstallHook(
            ORIG_MessageBeepHook,
            MessageBeepHook,
            (PVOID)0,
            hHook));

    printf(".\n");
    // won't invoke the hook handler because hooks are inactive after installation
    MessageBeep(123);
    getch();

    BOOL flags = 1;
    FORCE(LhIsThreadIntercepted(hHook, 0, &flags));
    printf("Intercepted %d\n", flags);
    // activate the hook for the current thread
    FORCE(LhSetInclusiveACL(ACLEntries, 1, hHook));
    FORCE(LhIsThreadIntercepted(hHook, 0, &flags));
    printf("Intercepted %d\n", flags);

    printf(".\n");
    // will be redirected into the handler...
    MessageBeep(123);
    getch();

    FORCE(LhSetGlobalExclusiveACL(ACLEntries, 1));
    printf(".\n");
    // will be redirected into the handler...
    MessageBeep(123);
    getch();

    FORCE(LhSetGlobalInclusiveACL(ACLEntries, 1));
    printf(".\n");
    // will be redirected into the handler...
    MessageBeep(123);
    getch();

    printf(".\n");
    // won't invoke the hook handler because hooks are inactive after installation
    ORIG_MessageBeepHook(123);
    getch();
#endif
    // this will also invalidate "hHook", because it is a traced handle...
    LhUninstallAllHooks();
    // this will do nothing because the hook is already removed...
    LhUninstallHook(hHook);

    printf(".\n");
    // will be redirected into the handler...
    MessageBeep(123);
    getch();

    // now we can safely release the traced handle
    delete hHook;

    hHook = NULL;

    // even if the hook is removed, we need to wait for memory release
    LhWaitForPendingRemovals();

    return 0;

ERROR_ABORT:

    if(hHook != NULL)
        delete hHook;

    if(NameBuffer != NULL)
        free(NameBuffer );

    printf("\n[Error(0x%p)]: \"%S\" (code: %d {0x%p})\n", (PVOID)NtStatus, RtlGetLastErrorString(), RtlGetLastError(), (PVOID)RtlGetLastError());

    _getch();

    return NtStatus;
}
Esempio n. 17
0
static int
draw_init(struct render_command * __rcmd)
{
	struct rcmd_draw * rcmd =
		container_of(__rcmd, struct rcmd_draw, base);
	FORCE(SYSTEM, "Draw init\n");

	rcmd->vertex_shader = compile_shader(GL_VERTEX_SHADER,
			sizeof(vertex_shader) / sizeof(char*), vertex_shader);
	rcmd->fragment_shader = compile_shader(GL_FRAGMENT_SHADER,
			sizeof(fragment_shader) / sizeof(char*), fragment_shader);
	rcmd->program = init_program(
			rcmd->vertex_shader,
			rcmd->fragment_shader);

	GL_POP_ERROR();
	rcmd->idx_mv = glGetUniformLocation(rcmd->program, "iModelView");
	GL_POP_ERROR();
	rcmd->idx_tex = glGetUniformLocation(rcmd->program, "inTex");
	GL_POP_ERROR();
	rcmd->idx_position = glGetAttribLocation(rcmd->program, "iPosition");
	GL_POP_ERROR();
	rcmd->idx_texcoord = glGetAttribLocation(rcmd->program, "texCoord");
	GL_POP_ERROR();

//	rcmd->idx_color = glGetAttribLocation(rcmd->program, "iColor");
//	GL_POP_ERROR();
//	glVertexAttrib3f(rcmd->idx_color, 1.0f, 0.0f, 0.1f);
//	GL_POP_ERROR();

	load_identity(&rcmd->modelview);


	glGenBuffers(1, &rcmd->buffer);
	glBindBuffer(GL_ARRAY_BUFFER, rcmd->buffer);

	const GLfloat varray[] = {
		0.0, 0.0, 0.0, 0.0, 0.0,
		0.0, 1.0, 0.0, 0.0, 1.0,
		1.0, 1.0, 0.0, 1.0, 1.0,
		1.0, 0.0, 0.0, 1.0, 0.0,

		0.0, 0.0, 0.0, 0.0, 0.0,
		0.0, 1.0, 0.0, 0.0, 1.0,
		1.0, 1.0, 1.0, 1.0, 1.0,
		1.0, 0.0, 1.0, 1.0, 0.0,
	};

	glBufferData(GL_ARRAY_BUFFER, sizeof(varray), varray, GL_STATIC_DRAW);

	GL_POP_ERROR();

	res_id_t texres;
	char * fn = "common/rgb.png";
	texres = (uint64_t)(uint32_t)fn;
	struct rectangle rect = {
		0, 0, 64, 64
	};

	struct texture_params params = TEXTURE_PARAM_INIT;
	params.pin = TRUE;

	rcmd->tex = texgl_create(texres, rect, &params, NULL);
	GL_POP_ERROR();

	WARNING(SYSTEM, "tex->bitmap=%p\n", rcmd->tex->base.bitmap);
	if (rcmd->tex->base.bitmap != NULL)
		WARNING(SYSTEM, "tex->bitmap.refcount=%d\n", rcmd->tex->base.bitmap->base.ref_count);


	res_id_t texres2;
	char * fn2 = "common/rgb.png";
	texres2 = (uint64_t)(uint32_t)fn2;
	struct rectangle rect2 = {
		0, 0, 64, 64
	};
	struct texture_params params2 = TEXTURE_PARAM_INIT;
	struct texture_gl_params gl_params = TEXTURE_GL_PARAM_INIT;
	gl_params.mag_filter = GL_NEAREST;
	gl_params.min_filter = GL_NEAREST;
	rcmd->tex2 = texgl_create(texres, rect2, &params, &gl_params);
	GL_POP_ERROR();
	WARNING(SYSTEM, "tex2->bitmap=%p\n", rcmd->tex2->base.bitmap);
	if (rcmd->tex2->base.bitmap != NULL)
		WARNING(SYSTEM, "tex2->bitmap.refcount=%d\n", rcmd->tex2->base.bitmap->base.ref_count);
	return 0;
}
Esempio n. 18
0
extern "C" int main(int argc, wchar_t* argv[])
{
    HMODULE                 hUser32 = LoadLibraryA("user32.dll");
    TRACED_HOOK_HANDLE      hHook = new HOOK_TRACE_INFO();
    NTSTATUS                NtStatus;
    ULONG                   ACLEntries[1] = {0};
    UNICODE_STRING*         NameBuffer = NULL;
	HANDLE					hRemoteThread;

	// test driver...
	printf("Installing support driver...\n");

	FORCE(RhInstallSupportDriver());

	printf("Installing test driver...\n");

	if(RhIsX64System())
		FORCE(RhInstallDriver(L"TestDriver64.sys", L"TestDriver64.sys"))
	else
		FORCE(RhInstallDriver(L"TestDriver32.sys", L"TestDriver32.sys"));

	// test stealth thread creation...
	printf("Testing stealth thread creation...\n");

	hRemoteThread = CreateThread(NULL, 0, TestThread, NULL, 0, NULL);

	FORCE(RhCreateStealthRemoteThread(GetCurrentProcessId(), HijackEntry, (PVOID)0x12345678, &hRemoteThread));

	Sleep(500);

    /*
        The following shows how to install and remove local hooks...
    */
    FORCE(LhInstallHook(
            GetProcAddress(hUser32, "MessageBeep"),
            MessageBeepHook,
            (PVOID)0x12345678,
            hHook));

    // won't invoke the hook handler because hooks are inactive after installation
    MessageBeep(123);

    // activate the hook for the current thread
    FORCE(LhSetInclusiveACL(ACLEntries, 1, hHook));

    // will be redirected into the handler...
    MessageBeep(123);

    // this will also invalidate "hHook", because it is a traced handle...
    LhUninstallAllHooks();

    // this will do nothing because the hook is already removed...
    LhUninstallHook(hHook);

    // now we can safely release the traced handle
    delete hHook;

    hHook = NULL;

    // even if the hook is removed, we need to wait for memory release
    LhWaitForPendingRemovals();

    /*
        In many situations you will need the handler utilities.
    */
    HANDLE          Handle = CreateEventA(NULL, TRUE, FALSE, "MyEvent");
    ULONG           RequiredSize;
    ULONG           RealThreadId;
    ULONG           ThreadId;

    // handle to name
    if(!SUCCEEDED(NtStatus = DbgHandleToObjectName(Handle, NULL, 0, &RequiredSize)))
        goto ERROR_ABORT;

    NameBuffer = (UNICODE_STRING*)malloc(RequiredSize);

    FORCE(DbgHandleToObjectName(Handle, NameBuffer, RequiredSize, &RequiredSize));

    printf("\n[Info]: Event name is \"%S\".\n", NameBuffer->Buffer);

    // handle to thread ID
    Handle = CreateThread(NULL, 0, NULL, NULL, CREATE_SUSPENDED, &RealThreadId);

    FORCE(DbgGetThreadIdByHandle(Handle, &ThreadId));

    if(ThreadId != RealThreadId)
        return EXIT_FAILURE;

	_getch();

	return 0;

ERROR_ABORT:

    if(hHook != NULL)
        delete hHook;

    if(NameBuffer != NULL)
        free(NameBuffer );

	printf("\n[Error(0x%p)]: \"%S\" (code: %d {0x%p})\n", (PVOID)NtStatus, RtlGetLastErrorString(), RtlGetLastError(), (PVOID)RtlGetLastError());

    _getch();

    return NtStatus;
}
Esempio n. 19
0
EASYHOOK_NT_INTERNAL LhRelocateEntryPoint(
				UCHAR* InEntryPoint,
				ULONG InEPSize,
				UCHAR* Buffer,
				ULONG* OutRelocSize)
{
/*
Description:

    Relocates the given entry point into the buffer and finally
    stores the relocated size in OutRelocSize.

Parameters:

    - InEntryPoint

        The entry point to relocate.

    - InEPSize

        Size of the given entry point in bytes.

    - Buffer

        A buffer receiving the relocated entry point.
        To ensure that there is always enough space, you should
        reserve around 100 bytes. After completion this method will
        store the real size in bytes in "OutRelocSize".
		Important: all instructions using RIP relative addresses will 
		be relative to the buffer location in memory.

    - OutRelocSize

        Receives the size of the relocated entry point in bytes.

Returns:

*/
#ifdef _M_X64
    #define POINTER_TYPE    LONGLONG
#else
    #define POINTER_TYPE    LONG
#endif
	UCHAR*				pRes = Buffer;
	UCHAR*				pOld = InEntryPoint;
    UCHAR			    b1;
	UCHAR			    b2;
	ULONG			    OpcodeLen;
	POINTER_TYPE   	    AbsAddr;
	BOOL			    a16 = FALSE;
	BOOL			    IsRIPRelative;
    ULONG               InstrLen;
    NTSTATUS            NtStatus;

	ASSERT(InEPSize < 20,L"reloc.c - InEPSize < 20");

	while(pOld < InEntryPoint + InEPSize)
	{
		b1 = *(pOld);
		b2 = *(pOld + 1);
		OpcodeLen = 0;
		AbsAddr = 0;
		IsRIPRelative = FALSE;

		// check for prefixes
		switch(b1)
		{
            case 0x67: // address-size override prefix
    			// TODO: this implementation does not take into consideration all scenarios
                //       e.g. http://wiki.osdev.org/X86-64_Instruction_Encoding#Operand-size_and_address-size_override_prefix
                a16 = TRUE; 
                // We increment pOld to skip this prefix, pOld is then decremented 
                // if the instruction is to be copied unchanged.
				pOld++;
				continue;
            /*
                Don't need to do anything with 0x66 (operand/data-size prefix), we only need to know when an address-size override prefix is present.
                Instructions with 0x66 generally end up unchanged (except 64-bit rip relative addresses where we only adjust the address anyway)
            */
		}

		/////////////////////////////////////////////////////////
		// get relative address value
		switch(b1)
		{
			case 0xE9: // jmp imm16/imm32
			{
				/* only allowed as first instruction and only if the trampoline can be planted 
				   within a 32-bit boundary around the original entrypoint. So the jumper will 
				   be only 5 bytes and whereever the underlying code returns it will always
				   be in a solid state. But this can only be guaranteed if the jump is the first
				   instruction... */
				if(pOld != InEntryPoint)
					THROW(STATUS_NOT_SUPPORTED, L"Hooking far jumps is only supported if they are the first instruction.");
				
				// ATTENTION: will continue in "case 0xE8"
			}
			case 0xE8: // call imm16/imm32
			{
				if(a16)
				{
					AbsAddr = *((__int16*)(pOld + 1));
					OpcodeLen = 3;
				}
				else
				{
					AbsAddr = *((__int32*)(pOld + 1));
					OpcodeLen = 5;
				}
			}break;

        	case 0xEB: // jmp imm8
            {
                AbsAddr = *((__int8*)(pOld + 1));
                OpcodeLen = 2;
            }break;
        /*
			The problem with (conditional) jumps is that there will be no return into the relocated entry point.
			So the execution will be proceeded in the original method and this will cause the whole
			application to remain in an unstable state. Only near jumps with 32-bit offset are allowed as
			first instruction (see above)...
		*/
			case 0xE3: // jcxz imm8
			{
				THROW(STATUS_NOT_SUPPORTED, L"Hooking near (conditional) jumps is not supported.");
			}break;
			case 0x0F:
			{
				if((b2 & 0xF0) == 0x80) // jcc imm16/imm32
					THROW(STATUS_NOT_SUPPORTED,  L"Hooking far conditional jumps is not supported.");
			}break;
		}

		if((b1 & 0xF0) == 0x70) // jcc imm8
			THROW(STATUS_NOT_SUPPORTED,  L"Hooking near conditional jumps is not supported.");

		/////////////////////////////////////////////////////////
		// convert to: mov eax, AbsAddr

		if(OpcodeLen > 0)
		{
			AbsAddr += (POINTER_TYPE)(pOld + OpcodeLen);

#ifdef _M_X64
			*(pRes++) = 0x48; // REX.W-Prefix
#endif
			*(pRes++) = 0xB8;               // mov eax,
			*((LONGLONG*)pRes) = AbsAddr;   //          address

			pRes += sizeof(void*);

			// points into entry point?
			if((AbsAddr >= (LONGLONG)InEntryPoint) && (AbsAddr < (LONGLONG)InEntryPoint + InEPSize))
				/* is not really unhookable but not worth the effort... */
				THROW(STATUS_NOT_SUPPORTED, L"Hooking jumps into the hooked entry point is not supported.");

			/////////////////////////////////////////////////////////
			// insert alternate code
			switch(b1)
			{
			case 0xE8: // call eax
				{
					*(pRes++) = 0xFF;
					*(pRes++) = 0xD0;
				}break;
			case 0xE9: // jmp eax
            case 0xEB: // jmp imm8
				{
					*(pRes++) = 0xFF;
					*(pRes++) = 0xE0;
				}break;
			}

			/* such conversions shouldnt be necessary in general...
			   maybe the method was already hooked or uses some hook protection or is just
			   bad programmed. EasyHook is capable of hooking the same method
			   many times simultanously. Even if other (unknown) hook libraries are hooking methods that
			   are already hooked by EasyHook. Only if EasyHook hooks methods that are already
			   hooked with other libraries there can be problems if the other libraries are not
			   capable of such a "bad" circumstance.
			*/

			*OutRelocSize = (ULONG)(pRes - Buffer);
		}
		else
		{
            // Check for RIP relative instructions and relocate
            FORCE(LhRelocateRIPRelativeInstruction((ULONGLONG)pOld, (ULONGLONG)pRes, &IsRIPRelative));
		}

		// If 16-bit address-prefix override, move pointer back to start of instruction
		if (a16) pOld--;

		// find next instruction
		FORCE(InstrLen = LhGetInstructionLength(pOld));

		if(OpcodeLen == 0)
		{
			// just copy the instruction
			if(!IsRIPRelative)
				RtlCopyMemory(pRes, pOld, InstrLen);

			pRes += InstrLen;
		}

		pOld += InstrLen;
		IsRIPRelative = FALSE;
		a16 = FALSE;
	}

	*OutRelocSize = (ULONG)(pRes - Buffer);

	RETURN(STATUS_SUCCESS);

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Esempio n. 20
0
void force() {
    FORCE(softspace);
    FORCE(my_assert);

    FORCE(boxInt);
    FORCE(unboxInt);
    FORCE(boxFloat);
    FORCE(unboxFloat);
    FORCE(boxCLFunction);
    FORCE(unboxCLFunction);
    FORCE(boxInstanceMethod);
    FORCE(boxBool);
    FORCE(boxBoolNegated);
    FORCE(unboxBool);
    FORCE(createTuple);
    FORCE(createDict);
    FORCE(createList);
    FORCE(createSlice);
    FORCE(createUserClass);
    FORCE(createClosure);
    FORCE(createGenerator);
    FORCE(createLong);
    FORCE(createPureImaginary);
    FORCE(createSet);
    FORCE(decodeUTF8StringPtr);

    FORCE(getattr);
    FORCE(getattr_capi);
    FORCE(setattr);
    FORCE(delattr);
    FORCE(nonzero);
    FORCE(binop);
    FORCE(compare);
    FORCE(augbinop);
    FORCE(unboxedLen);
    FORCE(getitem);
    FORCE(getitem_capi);
    FORCE(getclsattr);
    FORCE(getGlobal);
    FORCE(delGlobal);
    FORCE(setGlobal);
    FORCE(setitem);
    FORCE(delitem);
    FORCE(unaryop);
    FORCE(import);
    FORCE(importFrom);
    FORCE(importStar);
    FORCE(repr);
    FORCE(str);
    FORCE(exceptionMatches);
    FORCE(yield);
    FORCE(getiterHelper);
    FORCE(hasnext);

    FORCE(unpackIntoArray);
    FORCE(raiseAttributeError);
    FORCE(raiseAttributeErrorStr);
    FORCE(raiseAttributeErrorCapi);
    FORCE(raiseAttributeErrorStrCapi);
    FORCE(raiseIndexErrorStr);
    FORCE(raiseIndexErrorStrCapi);
    FORCE(raiseNotIterableError);
    FORCE(assertNameDefined);
    FORCE(assertFailDerefNameDefined);
    FORCE(assertFail);
    FORCE(printExprHelper);
    FORCE(printHelper);

    FORCE(strOrUnicode);
    FORCE(printFloat);
    FORCE(listAppendInternal);
    FORCE(getSysStdout);

    FORCE(runtimeCall);
    FORCE(runtimeCallCapi);
    FORCE(callattr);
    FORCE(callattrCapi);

    FORCE(raise0);
    FORCE(raise0_capi);
    FORCE(raise3);
    FORCE(raise3_capi);
    FORCE(PyErr_Fetch);
    FORCE(PyErr_NormalizeException);
    FORCE(PyErr_Restore);
    FORCE(caughtCapiException);
    FORCE(reraiseCapiExcAsCxx);
    FORCE(deopt);

    FORCE(div_i64_i64);
    FORCE(mod_i64_i64);
    FORCE(pow_i64_i64);

    FORCE(div_float_float);
    FORCE(floordiv_float_float);
    FORCE(mod_float_float);
    FORCE(pow_float_float);

    FORCE(exec);

    FORCE(dump);

    FORCE(boxFloat);

    FORCE(createModule);

    FORCE(gc::sizes);

    FORCE(boxedLocalsSet);
    FORCE(boxedLocalsGet);
    FORCE(boxedLocalsDel);

    FORCE(threading::allowGLReadPreemption);

    // FORCE(listIter);
}
Esempio n. 21
0
EASYHOOK_NT_EXPORT LhBarrierCallStackTrace(
            PVOID* OutMethodArray, 
            ULONG InMaxMethodCount,
            ULONG* OutMethodCount)
{
/*
Description:

    Creates a call stack trace and translates all method entries
    back into their owning modules.

Parameters:

    - OutMethodArray

        An array receiving the methods on the call stack.

    - InMaxMethodCount

        The length of the method array. 

    - OutMethodCount

        The actual count of methods on the call stack. This will never
        be greater than 64.

Returns:

    STATUS_NOT_IMPLEMENTED

        Only supported since Windows XP.
*/
    NTSTATUS				NtStatus;
    PVOID					Backup = NULL;

	if(InMaxMethodCount > 64)
		THROW(STATUS_INVALID_PARAMETER_2, L"At maximum 64 modules are supported.");

	if(!IsValidPointer(OutMethodArray, InMaxMethodCount * sizeof(PVOID)))
		THROW(STATUS_INVALID_PARAMETER_1, L"The given module buffer is invalid.");

	if(!IsValidPointer(OutMethodCount, sizeof(ULONG)))
		THROW(STATUS_INVALID_PARAMETER_3, L"Invalid module count storage.");

    FORCE(LhBarrierBeginStackTrace(&Backup));

#ifndef DRIVER
    if(RtlCaptureStackBackTrace == NULL)
        RtlCaptureStackBackTrace = (PROC_RtlCaptureStackBackTrace*)GetProcAddress(hKernel32, "RtlCaptureStackBackTrace");

    if(RtlCaptureStackBackTrace == NULL)
        THROW(STATUS_NOT_IMPLEMENTED, L"This method requires Windows XP or later.");
#endif

    *OutMethodCount = RtlCaptureStackBackTrace(1, 32, OutMethodArray, NULL);

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
     {
        if(Backup != NULL)
            LhBarrierEndStackTrace(Backup);

        return NtStatus;
    }
}
Esempio n. 22
0
void force() {
    FORCE(my_assert);

    FORCE(boxInt);
    FORCE(unboxInt);
    FORCE(boxFloat);
    FORCE(unboxFloat);
    FORCE(boxStringPtr);
    FORCE(boxCLFunction);
    FORCE(unboxCLFunction);
    FORCE(boxInstanceMethod);
    FORCE(boxBool);
    FORCE(unboxBool);
    FORCE(createTuple);
    FORCE(createDict);
    FORCE(createList);
    FORCE(createSlice);
    FORCE(createClass);

    FORCE(getattr);
    FORCE(setattr);
    FORCE(print);
    FORCE(nonzero);
    FORCE(binop);
    FORCE(compare);
    FORCE(augassign);
    FORCE(unboxedLen);
    FORCE(getitem);
    FORCE(getclsattr);
    FORCE(getGlobal);
    FORCE(setitem);
    FORCE(unaryop);
    FORCE(import);

    FORCE(checkUnpackingLength);
    FORCE(raiseAttributeError);
    FORCE(raiseAttributeErrorStr);
    FORCE(raiseNotIterableError);
    FORCE(assertNameDefined);

    FORCE(printFloat);
    FORCE(listAppendInternal);

    FORCE(dump);

    FORCE(runtimeCall);
    FORCE(callattr);

    FORCE(div_i64_i64);
    FORCE(mod_i64_i64);
    FORCE(pow_i64_i64);

    FORCE(div_float_float);
    FORCE(mod_float_float);
    FORCE(pow_float_float);

    FORCE(boxFloat);

    FORCE(createModule);

    FORCE(gc::sizes);

    //FORCE(listIter);
}