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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; } }
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; }
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; }
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; }
void CFGNormalizer::configure(const PropList& props) { CFGProcessor::configure(props); force = FORCE(props); verbose = VERBOSE(props); }
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; }
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; }
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, ¶ms, 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, ¶ms, &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; }
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; }
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; }
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); }
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; } }
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); }