Beispiel #1
0
LONG LhSetACL(
            HOOK_ACL* InAcl,
            BOOL InIsExclusive,
            ULONG* InThreadIdList,
            ULONG InThreadCount)
{
/*
Description:

    This method is used internally to provide a generic interface to
    either the global or local hook ACLs.
    
Parameters:
    - InAcl
        NULL if you want to set the global ACL.
        Any LOCAL_HOOK_INFO::LocalACL to set the hook specific ACL.

    - InIsExclusive
        TRUE if all listed thread shall be excluded from interception,
        FALSE otherwise

    - InThreadIdList
        An array of thread IDs. If you specific zero for an entry in this array,
        it will be automatically replaced with the calling thread ID.

    - InThreadCount
        The count of entries listed in the thread ID list. This value must not exceed
        MAX_ACE_COUNT! 
*/

    ULONG           Index;

    ASSERT(IsValidPointer(InAcl, sizeof(HOOK_ACL)),L"acl.c - IsValidPointer(InAcl, sizeof(HOOK_ACL))");

    if(InThreadCount > MAX_ACE_COUNT)
        return STATUS_INVALID_PARAMETER_2;

    if(!IsValidPointer(InThreadIdList, InThreadCount * sizeof(ULONG)))
        return STATUS_INVALID_PARAMETER_1;

    for(Index = 0; Index < InThreadCount; Index++)
    {
        if(InThreadIdList[Index] == 0)
            InThreadIdList[Index] = GetCurrentThreadId();
    }

    // set ACL...
    InAcl->IsExclusive = InIsExclusive;
    InAcl->Count = InThreadCount;

    RtlCopyMemory(InAcl->Entries, InThreadIdList, InThreadCount * sizeof(ULONG));

    return STATUS_SUCCESS;
}
Beispiel #2
0
EASYHOOK_NT_EXPORT LhBarrierGetReturnAddress(PVOID* OutValue)
{
/*
Description:

    Is expected to be called inside a hook handler. Otherwise it
    will fail with STATUS_NOT_SUPPORTED. The method retrieves
    the return address of the hook handler. This is usually the
    instruction behind the "CALL" which invoked the hook.

    The calling module determination is based on this method.

*/
    NTSTATUS            NtStatus;
	LPTHREAD_RUNTIME_INFO       Runtime;

    if(!IsValidPointer(OutValue, sizeof(PVOID)))
        THROW(STATUS_INVALID_PARAMETER, L"Invalid result storage specified.");

	if(!TlsGetCurrentValue(&Unit.TLS, &Runtime))
        THROW(STATUS_NOT_SUPPORTED, L"The caller is not inside a hook handler.");

	if(Runtime->Current != NULL)
		*OutValue = Runtime->Current->RetAddress;
	else
		THROW(STATUS_NOT_SUPPORTED, L"The caller is not inside a hook handler.NULL");

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Beispiel #3
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;
}
Beispiel #4
0
EASYHOOK_NT_EXPORT LhBarrierGetCallback(PVOID* OutValue)
{
/*
Description:

    Is expected to be called inside a hook handler. Otherwise it
    will fail with STATUS_NOT_SUPPORTED. The method retrieves
    the callback initially passed to the related LhInstallHook()
    call.

*/
    NTSTATUS            NtStatus;
	LPTHREAD_RUNTIME_INFO       Runtime;

    if(!IsValidPointer(OutValue, sizeof(PVOID)))
        THROW(STATUS_INVALID_PARAMETER, L"Invalid result storage specified.");

	if(!TlsGetCurrentValue(&Unit.TLS, &Runtime))
        THROW(STATUS_NOT_SUPPORTED, L"The caller is not inside a hook handler.");

	if(Runtime->Current != NULL)
		*OutValue = Runtime->Callback;
	else
		THROW(STATUS_NOT_SUPPORTED, L"The caller is not inside a hook handler. NULL");

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
void MultiMBC1MemoryRule::PerformWrite(u16 address, u8 value)
{
    switch (address & 0xE000)
    {
        case 0x0000:
        {
            bool previous = m_bRamEnabled;
            m_bRamEnabled = ((value & 0x0F) == 0x0A);

            if (IsValidPointer(m_pRamChangedCallback) && previous && !m_bRamEnabled)
            {
                (*m_pRamChangedCallback)();
            }
            break;
        }
        case 0x2000:
        {
            if (m_iMode == 0)
            {
                m_iFinalROMBank = (m_iCurrentROMBank & 0x1F) ? m_iCurrentROMBank : (m_iCurrentROMBank | 1);
                m_iFinalROMBank &= (m_pCartridge->GetROMBankCount() - 1);
            }
            else
            {
                int rombank = ((m_iCurrentROMBank >> 1) & 0x30) | (m_iCurrentROMBank & 0xF);
                m_iFinalROMBank = (rombank & 0x1F) ? rombank : (rombank | 1);
            }
            break;
        }
        case 0x4000:
        {
            m_iCurrentROMBank = ((value << 5) & 0x60) | (m_iCurrentROMBank & 0x1F);
            SetRomBank();
            break;
        }
        case 0x6000:
        {
            m_iMode = value & 0x01;
            SetRomBank();
            break;
        }
        case 0xA000:
        {
            if (m_bRamEnabled)
            {
                m_pMemory->Load(address, value);
            }
            else
            {
                Log("--> ** Attempting to write on RAM when ram is disabled %X %X", address, value);
            }
            break;
        }
        default:
        {
            m_pMemory->Load(address, value);
            break;
        }
    }
}
Beispiel #6
0
void PhysicsManager::SetPhysicsCallback(PhysicsCallbackGeneric* pCallback)
{
    m_pPhysicsCallback = pCallback;

    if (IsValidPointer(m_pDynamicsWorld))
    {
        m_pDynamicsWorld->setInternalTickCallback(&PhysicsManager::__PhysicsCallback);
    }
}
Beispiel #7
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;
}
Beispiel #8
0
EASYHOOK_NT_EXPORT LhGetHookBypassAddress(TRACED_HOOK_HANDLE InHook, PVOID** OutAddress)
{
/*
Description:

	Retrieves the address to bypass the hook. Using the returned value to call the original
	function bypasses all thread safety measures and must be used with care.
	This function should be called each time the address is required to ensure the hook  and
	associated memory is still valid at the time of use.
	CAUTION:
	This must be used with extreme caution. If the hook is uninstalled and pending hooks 
	removed, the address returned by this function will no longer point to valid memory and 
	attempting to use the address will result in unexpected behaviour, most likely crashing 
	the process.

Parameters:

	- InHook

		The hook to retrieve the relocated entry point for.

	- OutAddress

		Upon successfully retrieving the hook details this will contain
		the address of the relocated function entry point. This address
		can be used to call the original function from outside of a hook
		while still bypassing the hook.
	
Returns:

	STATUS_SUCCESS             - OutAddress will contain the result
	STATUS_INVALID_PARAMETER_1 - the hook is invalid
	STATUS_INVALID_PARAMETER_3 - the target pointer is invalid

*/
	NTSTATUS			NtStatus;
	PLOCAL_HOOK_INFO    Handle;

	if (!LhIsValidHandle(InHook, &Handle))
		THROW(STATUS_INVALID_PARAMETER_1, L"The given hook handle is invalid or already disposed.");

	if (!IsValidPointer(OutAddress, sizeof(PVOID*)))
		THROW(STATUS_INVALID_PARAMETER_3, L"Invalid pointer for result storage.");

	*OutAddress = (PVOID*)Handle->OldProc;

	RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
	return NtStatus;
}
Beispiel #9
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;
}
Beispiel #10
0
EASYHOOK_NT_EXPORT RhGetProcessToken(
            ULONG InProcessId,
            HANDLE* OutToken)
{
/*
Description:

     This method is intended for the managed layer and has no special
     advantage in an unmanaged environment!

Parameters:

    - InProcessId

        The target process shall be accessible with PROCESS_QUERY_INFORMATION.

    - OutToken

        The identity token for the session the process was created in.
*/
    HANDLE			    hProc = NULL;
    NTSTATUS            NtStatus;

    if(!IsValidPointer(OutToken, sizeof(HANDLE)))
        THROW(STATUS_INVALID_PARAMETER_2, L"The given token storage is invalid.");

	if((hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, InProcessId)) == NULL)
	{
		if(GetLastError() == ERROR_ACCESS_DENIED)
			THROW(STATUS_ACCESS_DENIED, L"The given process is not accessible.")
		else
			THROW(STATUS_NOT_FOUND, L"The given process does not exist.");
	}

	if(!OpenProcessToken(hProc, TOKEN_READ, OutToken))
	    THROW(STATUS_INTERNAL_ERROR, L"Unable to query process token.");

	RETURN(STATUS_SUCCESS);

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

        return NtStatus;
	}
}
Beispiel #11
0
EASYHOOK_NT_EXPORT LhIsProcessIntercepted(
	TRACED_HOOK_HANDLE InHook,
	ULONG InProcessID,
    BOOL* OutResult)
#endif
{
/*
Description:

    This method will negotiate whether a given thread passes
    the ACLs and would invoke the related hook handler. Refer
    to the source code of Is[Thread/Process]Intercepted() for more information
    about the implementation.

*/
    NTSTATUS            NtStatus;
    PLOCAL_HOOK_INFO    Handle;

    if(!LhIsValidHandle(InHook, &Handle))
        THROW(STATUS_INVALID_PARAMETER_1, L"The given hook handle is invalid or already disposed.");

    if(!IsValidPointer(OutResult, sizeof(BOOL)))
        THROW(STATUS_INVALID_PARAMETER_3, L"Invalid pointer for result storage.");

#ifndef DRIVER
    *OutResult = IsThreadIntercepted(&Handle->LocalACL, InThreadID);
#else
	*OutResult = IsProcessIntercepted(&Handle->LocalACL, InProcessID);
#endif

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Beispiel #12
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;
}
Beispiel #13
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;
	}
}
Beispiel #14
0
void MBC5MemoryRule::PerformWrite(u16 address, u8 value)
{
    switch (address & 0xE000)
    {
        case 0x0000:
        {
            if (m_pCartridge->GetRAMSize() > 0)
            {
                bool previous = m_bRamEnabled;
                m_bRamEnabled = ((value & 0x0F) == 0x0A);

                if (IsValidPointer(m_pRamChangedCallback) && previous && !m_bRamEnabled)
                {
                    (*m_pRamChangedCallback)();
                }
            }
            break;
        }
        case 0x2000:
        {
            if (address < 0x3000)
            {
                m_iCurrentROMBank = value | (m_iCurrentROMBankHi << 8);
            }
            else
            {
                m_iCurrentROMBankHi = value & 0x01;
                m_iCurrentROMBank = (m_iCurrentROMBank & 0xFF) | (m_iCurrentROMBankHi << 8);
            }
            m_iCurrentROMBank &= (m_pCartridge->GetROMBankCount() - 1);
            m_CurrentROMAddress = m_iCurrentROMBank * 0x4000;
            break;
        }
        case 0x4000:
        {
            m_iCurrentRAMBank = value & 0x0F;
            m_iCurrentRAMBank &= (m_pCartridge->GetRAMBankCount() - 1);
            m_CurrentRAMAddress = m_iCurrentRAMBank * 0x2000;
            break;
        }
        case 0x6000:
        {
            Log("--> ** Attempting to write on invalid address %X %X", address, value);
            break;
        }
        case 0xA000:
        {
            if (m_bRamEnabled)
            {
                m_pRAMBanks[(address - 0xA000) + m_CurrentRAMAddress] = value;
            }
            else
            {
                Log("--> ** Attempting to write on RAM when ram is disabled %X %X", address, value);
            }
            break;
        }
        default:
        {
            m_pMemory->Load(address, value);
            break;
        }
    }
}
Beispiel #15
0
EASYHOOK_NT_EXPORT RtlCreateSuspendedProcess(
		WCHAR* InEXEPath,
        WCHAR* InCommandLine,
		ULONG InCustomFlags,
        ULONG* OutProcessId,
        ULONG* OutThreadId)
{
/*
Description:

    Creates a suspended process with the given parameters.
    This is only intended for the managed layer.

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.

	- InCustomFlags

		Additional process creation flags.

    - OutProcessId

        Receives the PID of the newly created process.

    - OutThreadId

        Receives the initial TID of the newly created process.
*/
    STARTUPINFO				StartInfo;
	PROCESS_INFORMATION		ProcessInfo;
	WCHAR					FullExePath[MAX_PATH + 1];
	WCHAR                   FullCommandLine[MAX_PATH + 1];
    WCHAR					CurrentDir[MAX_PATH + 1];
    WCHAR*					FilePart;
    NTSTATUS            NtStatus;

    // must be executed before any THROW or RETURN!
    RtlZeroMemory(&StartInfo, sizeof(StartInfo));
    RtlZeroMemory(&ProcessInfo, sizeof(ProcessInfo));

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

    if(!IsValidPointer(OutThreadId, sizeof(ULONG)))
        THROW(STATUS_INVALID_PARAMETER_4, L"The given thread ID storage is invalid.");

    // parse path
    if(!RtlFileExists(InEXEPath))
        THROW(STATUS_INVALID_PARAMETER_1, L"The given process file does not exist.");

    if(GetFullPathName(InEXEPath, MAX_PATH, CurrentDir, &FilePart) > MAX_PATH)
        THROW(STATUS_INVALID_PARAMETER_1, L"Full path information exceeds MAX_PATH characters.");

    // compute current directory...
    RtlCopyMemory(FullExePath, CurrentDir, sizeof(FullExePath));
    
    swprintf_s(FullCommandLine, MAX_PATH, L"\"%s\" \"%s\"", FullExePath, InCommandLine);

    *FilePart = 0;

    // create suspended process
    StartInfo.cb = sizeof(StartInfo);
	StartInfo.wShowWindow = TRUE;

    if(!CreateProcessW(
		    FullExePath, 
		    FullCommandLine, 
            NULL, NULL,  
            FALSE, 
		    InCustomFlags | CREATE_SUSPENDED,
		    NULL,
		    CurrentDir,
		    &StartInfo,
		    &ProcessInfo))
	    THROW(STATUS_INVALID_PARAMETER, L"Unable to start process; please check the given parameters.");

    *OutProcessId = ProcessInfo.dwProcessId;
    *OutThreadId = ProcessInfo.dwThreadId;

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    {
        if(ProcessInfo.hProcess != NULL)
		    CloseHandle(ProcessInfo.hProcess);

        if(ProcessInfo.hThread != NULL)
		    CloseHandle(ProcessInfo.hThread);

        return NtStatus;
	}
}
Beispiel #16
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;
}
Beispiel #17
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;
}
Beispiel #18
0
EASYHOOK_NT_EXPORT RhIsX64Process(
            ULONG InProcessId,
            BOOL* OutResult)
{
/*
Description:

    Detects the bitness of a given process.

Parameters:

    - InProcessId

        The calling process must have PROCESS_QUERY_INFORMATION access
        to the process represented by this ID.

    - OutResult

        Is set to TRUE if the given process is running under 64-Bit,
        FALSE otherwise.
*/
	BOOL			            IsTarget64Bit = FALSE;
	HANDLE			            hProc = NULL;
    IsWow64Process_PROC*        pIsWow64Process;
    NTSTATUS            NtStatus;

#ifndef _M_X64
    GetNativeSystemInfo_PROC*   pGetNativeSystemInfo;
    SYSTEM_INFO		            SysInfo;
#endif

    if(!IsValidPointer(OutResult, sizeof(BOOL)))
        THROW(STATUS_INVALID_PARAMETER_2, L"The given result storage is invalid.");

	// open target process
	if((hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, InProcessId)) == NULL)
	{
		if(GetLastError() == ERROR_ACCESS_DENIED)
			THROW(STATUS_ACCESS_DENIED, L"The given process is not accessible.")
		else
			THROW(STATUS_NOT_FOUND, L"The given process does not exist.");
	}

	// if WOW64 is not available then target must be 32-bit
	pIsWow64Process = (IsWow64Process_PROC*)GetProcAddress(hKernel32, "IsWow64Process");

#ifdef _M_X64
	// if the target is not WOW64, then it is 64-bit
	if(!pIsWow64Process(hProc, &IsTarget64Bit))
		THROW(STATUS_INTERNAL_ERROR, L"Unable to detect wether target process is 64-bit or not.");

	IsTarget64Bit = !IsTarget64Bit;

#else

	IsTarget64Bit = FALSE;

	if(pIsWow64Process != NULL)
	{
		// check if we are running on a 32-bit OS
		pGetNativeSystemInfo = (GetNativeSystemInfo_PROC*)GetProcAddress(hKernel32, "GetNativeSystemInfo");

		if(pGetNativeSystemInfo != NULL)
		{
			pGetNativeSystemInfo(&SysInfo);

			if(SysInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
			{
				// if not, then and only then a 32-bit process will be marked as WOW64 process!
				if(!pIsWow64Process(hProc, &IsTarget64Bit))
					THROW(STATUS_INTERNAL_ERROR, L"Unable to detect wether target process is 64-bit or not.");

				IsTarget64Bit = !IsTarget64Bit;
			}
		}
	}
#endif

	*OutResult = IsTarget64Bit;

    RETURN(STATUS_SUCCESS);

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

        return NtStatus;
	}
}
Beispiel #19
0
void MBC2MemoryRule::PerformWrite(u16 address, u8 value)
{
    switch (address & 0xE000)
    {
        case 0x0000:
        {
            if (!(address & 0x0100))
            {
                bool previous = m_bRamEnabled;
                m_bRamEnabled = ((value & 0x0F) == 0x0A);

                if (IsValidPointer(m_pRamChangedCallback) && previous && !m_bRamEnabled)
                {
                    (*m_pRamChangedCallback)();
                }
            }
            else
            {
                Log("--> ** Attempting to write on invalid register %X %X", address, value);
            }
            break;
        }
        case 0x2000:
        {
            if (address & 0x0100)
            {
                m_iCurrentROMBank = value & 0x0F;
                if (m_iCurrentROMBank == 0)
                    m_iCurrentROMBank = 1;
                m_iCurrentROMBank &= (m_pCartridge->GetROMBankCount() - 1);
                m_CurrentROMAddress = m_iCurrentROMBank * 0x4000;
            }
            else
            {
                Log("--> ** Attempting to write on invalid register %X %X", address, value);
            }
            break;
        }
        case 0x4000:
        case 0x6000:
        {
            Log("--> ** Attempting to write on invalid address %X %X", address, value);
            break;
        }
        case 0xA000:
        {
            if (address < 0xA200)
            {
                if (m_bRamEnabled)
                {
                    m_pMemory->Load(address, value & 0x0F);
                }
                else
                {
                    Log("--> ** Attempting to write on RAM when ram is disabled %X %X", address, value);
                }
            }
            else
            {
                Log("--> ** Attempting to write on invalid RAM %X %X", address, value);
            }
            break;
        }
        default:
        {
            m_pMemory->Load(address, value);
            break;
        }
    }
}
Beispiel #20
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;
}
Beispiel #21
0
void MBC1MemoryRule::PerformWrite(u16 address, u8 value)
{
    switch (address & 0xE000)
    {
        case 0x0000:
        {
            if (m_pCartridge->GetRAMSize() > 0)
            {
                bool previous = m_bRamEnabled;
                m_bRamEnabled = ((value & 0x0F) == 0x0A);

                if (IsValidPointer(m_pRamChangedCallback) && previous && !m_bRamEnabled)
                {
                    (*m_pRamChangedCallback)();
                }
            }
            break;
        }
        case 0x2000:
        {
            if (m_iMode == 0)
            {
                m_iCurrentROMBank = (value & 0x1F) | (m_HigherRomBankBits << 5);
            }
            else
            {
                m_iCurrentROMBank = value & 0x1F;
            }

            if (m_iCurrentROMBank == 0x00 || m_iCurrentROMBank == 0x20
                    || m_iCurrentROMBank == 0x40 || m_iCurrentROMBank == 0x60)
                m_iCurrentROMBank++;

            m_iCurrentROMBank &= (m_pCartridge->GetROMBankCount() - 1);
            m_CurrentROMAddress = m_iCurrentROMBank * 0x4000;
            break;
        }
        case 0x4000:
        {
            if (m_iMode == 1)
            {
                m_iCurrentRAMBank = value & 0x03;
                m_iCurrentRAMBank &= (m_pCartridge->GetRAMBankCount() - 1);
                m_CurrentRAMAddress = m_iCurrentRAMBank * 0x2000;
            }
            else
            {
                m_HigherRomBankBits = value & 0x03;
                m_iCurrentROMBank = (m_iCurrentROMBank & 0x1F) | (m_HigherRomBankBits << 5);

                if (m_iCurrentROMBank == 0x00 || m_iCurrentROMBank == 0x20
                        || m_iCurrentROMBank == 0x40 || m_iCurrentROMBank == 0x60)
                    m_iCurrentROMBank++;

                m_iCurrentROMBank &= (m_pCartridge->GetROMBankCount() - 1);
                m_CurrentROMAddress = m_iCurrentROMBank * 0x4000;
            }
            break;
        }
        case 0x6000:
        {
            if ((m_pCartridge->GetRAMSize() != 3) && (value & 0x01))
            {
                Log("--> ** Attempting to change MBC1 to mode 1 with incorrect RAM banks %X %X", address, value);
            }
            else
            {
                m_iMode = value & 0x01;
            }
            break;
        }
        case 0xA000:
        {
            if (m_bRamEnabled)
            {
                if (m_iMode == 0)
                {
                    if ((m_pCartridge->GetRAMSize() == 1) && (address >= 0xA800))
                    {
                        // only 2KB of ram
                        Log("--> ** Attempting to write on invalid RAM %X %X", address, value);
                    }

                    m_pRAMBanks[address - 0xA000] = value;
                }
                else
                    m_pRAMBanks[(address - 0xA000) + m_CurrentRAMAddress] = value;
            }
            else
            {
                Log("--> ** Attempting to write on RAM when ram is disabled %X %X", address, value);
            }
            break;
        }
        default:
        {
            m_pMemory->Load(address, value);
            break;
        }
    }
}
Beispiel #22
0
EASYHOOK_NT_EXPORT LhUninstallHook(TRACED_HOOK_HANDLE InHandle)
{
/*
Description:

    Removes the given hook. To also release associated resources,
    you will have to call LhWaitForPendingRemovals(). In any case
    your hook handler will never be executed again, after calling this
    method.

Parameters:

    - InHandle

        A traced hook handle. If the hook is already removed, this method
        will still return STATUS_SUCCESS.
*/
    LOCAL_HOOK_INFO*        Hook = NULL;
    LOCAL_HOOK_INFO*        List;
    LOCAL_HOOK_INFO*        Prev;
    NTSTATUS                NtStatus;
    BOOLEAN                 IsAllocated = FALSE;

     if(!IsValidPointer(InHandle, sizeof(HOOK_TRACE_INFO)))
        return FALSE;

    RtlAcquireLock(&GlobalHookLock);
    {
        if((InHandle->Link != NULL) && LhIsValidHandle(InHandle, &Hook))
        {
            InHandle->Link = NULL;

            if(Hook->HookProc != NULL)
            {
                Hook->HookProc = NULL;  

                IsAllocated = TRUE;
            }
        }

        if(!IsAllocated)
        {
            RtlReleaseLock(&GlobalHookLock);

            RETURN;
        }

        // remove from global list
        List = GlobalHookListHead.Next;
        Prev = &GlobalHookListHead;

        while(List != NULL)
        {
            if(List == Hook)
            {
                Prev->Next = Hook->Next;

                break;
            }

            List = List->Next;
        }

        // add to removal list
        Hook->Next = GlobalRemovalListHead.Next;
        GlobalRemovalListHead.Next = Hook;
    }
    RtlReleaseLock(&GlobalHookLock);

    RETURN(STATUS_SUCCESS);

//THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}
Beispiel #23
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;
    }
}
Beispiel #24
0
void MBC3MemoryRule::PerformWrite(u16 address, u8 value)
{
    switch (address & 0xE000)
    {
        case 0x0000:
        {
            if (m_pCartridge->GetRAMSize() > 0)
            {
                bool previous = m_bRamEnabled;
                m_bRamEnabled = ((value & 0x0F) == 0x0A);

                if (IsValidPointer(m_pRamChangedCallback) && previous && !m_bRamEnabled)
                {
                    (*m_pRamChangedCallback)();
                }
            }
            m_bRTCEnabled = ((value & 0x0F) == 0x0A);
            break;
        }
        case 0x2000:
        {
            m_iCurrentROMBank = value & 0x7F;
            if (m_iCurrentROMBank == 0)
                m_iCurrentROMBank = 1;
            m_iCurrentROMBank &= (m_pCartridge->GetROMBankCount() - 1);
            m_CurrentROMAddress = m_iCurrentROMBank * 0x4000;
            break;
        }
        case 0x4000:
        {
            if ((value >= 0x08) && (value <= 0x0C))
            {
                // RTC
                if (m_pCartridge->IsRTCPresent() && m_bRTCEnabled)
                {
                    m_RTCRegister = value;
                    m_iCurrentRAMBank = -1;
                }
                else
                {
                    Log("--> ** Attempting to select RTC register when RTC is disabled or not present %X %X", address, value);
                }
            }
            else if (value <= 0x03)
            {
                m_iCurrentRAMBank = value;
                m_iCurrentRAMBank &= (m_pCartridge->GetRAMBankCount() - 1);
                m_CurrentRAMAddress = m_iCurrentRAMBank * 0x2000;
            }
            else
            {
                Log("--> ** Attempting to select unkwon register %X %X", address, value);
            }
            break;
        }
        case 0x6000:
        {
            if (m_pCartridge->IsRTCPresent())
            {
                // RTC Latch
                if ((m_iRTCLatch == 0x00) && (value == 0x01))
                {
                    UpdateRTC();
                    m_iRTCLatchedSeconds = m_iRTCSeconds;
                    m_iRTCLatchedMinutes = m_iRTCMinutes;
                    m_iRTCLatchedHours = m_iRTCHours;
                    m_iRTCLatchedDays = m_iRTCDays;
                    m_iRTCLatchedControl = m_iRTCControl;
                }
                if ((value == 0x00) || (value == 0x01))
                {
                    m_iRTCLatch = value;
                }
            }
            break;
        }
        case 0xA000:
        {
            if (m_iCurrentRAMBank >= 0)
            {
                if (m_bRamEnabled)
                {
                    m_pRAMBanks[(address - 0xA000) + m_CurrentRAMAddress] = value;
                }
                else
                {
                    Log("--> ** Attempting to write on RAM when ram is disabled %X %X", address, value);
                }
            }
            else if (m_pCartridge->IsRTCPresent() && m_bRTCEnabled)
            {
                m_RTCLastTime = static_cast<s32>(m_pCartridge->GetCurrentRTC());
                switch (m_RTCRegister)
                {
                    case 0x08:
                        m_iRTCSeconds = value;
                        break;
                    case 0x09:
                        m_iRTCMinutes = value;
                        break;
                    case 0x0A:
                        m_iRTCHours = value;
                        break;
                    case 0x0B:
                        m_iRTCDays = value;
                        break;
                    case 0x0C:
                        if (m_iRTCControl & 0x80)
                            m_iRTCControl = 0x80 | value;
                        else
                            m_iRTCControl = value;
                        break;
                }
            }
            else
            {
                Log("--> ** Attempting to write on RTC when RTC is disabled or not present %X %X", address, value);
            }
            break;
        }
        default:
        {
            m_pMemory->Load(address, value);
            break;
        }
    }
}
Beispiel #25
0
EASYHOOK_NT_EXPORT LhEnumModules(
			HMODULE* OutModuleArray, 
            ULONG InMaxModuleCount,
            ULONG* OutModuleCount)
{
/*
Description:

	For performance reasons, only the module base addresses are returned.
	You may then loop through the array and use LhBarrierPointerToModule()
	to query each module information.

Parameters:
	
	- OutModuleArray

		An array receiveing module pointers. Set to NULL to only query "OutModuleCount".

	- InMaxModuleCount

		The maximum count of modules that the given buffer can hold.

	- OutModuleCount

		The actual count of modules loaded into the current process or into the kernel,
		depending on the caller's context. This pointer must be specified if no
		module buffer is passed; if one is passed, this parameter is optional.
*/
	ULONG					ModIndex = 0;
	NTSTATUS				NtStatus;
	MODULE_INFORMATION*		List;

	if(IsValidPointer(OutModuleArray, InMaxModuleCount * sizeof(PVOID)))
	{
		// loop through the module list...
		RtlAcquireLock(&GlobalHookLock);
		{
			if(IsValidPointer(OutModuleCount, sizeof(ULONG)))
				*OutModuleCount = LhModuleCount;

			List = LhModuleArray;

			// walk through process modules
			while(List != NULL)
			{
				if(ModIndex > InMaxModuleCount)
				{
					RtlReleaseLock(&GlobalHookLock);

					THROW(STATUS_BUFFER_TOO_SMALL, L"The given buffer was filled but could not hold all modules.");
				}

				OutModuleArray[ModIndex++] = (HMODULE)List->BaseAddress;

				List = List->Next;
			}	
		}	
		RtlReleaseLock(&GlobalHookLock);
	}
	else
	{
		// return module count...
		if(!IsValidPointer(OutModuleCount, sizeof(ULONG)))
			THROW(STATUS_INVALID_PARAMETER_3, L"If no buffer is specified you need to pass a module count storage.");

		*OutModuleCount = LhModuleCount;
	}

	RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}