Giter VIP home page Giter VIP logo

easyhook's Introduction

Welcome to EasyHook - The reinvention of Windows API Hooking

Join the chat at https://gitter.im/EasyHook/EasyHook

Master branch: Master branch build status

Develop branch: Develop branch build status

You can support the EasyHook project over at Bountysource or raise a bounty for an issue to be fixed: Current bounties

This project supports extending (hooking) unmanaged code (APIs) with pure managed ones, from within a fully managed environment on 32- or 64-bit Windows Vista x64, Windows Server 2008 x64, Windows 7, Windows 8.1, and Windows 10.

EasyHook currently supports injecting assemblies built for .NET Framework 3.5 and 4.0 and can also inject native DLLs.

EasyHook homepage

For more information head to the EasyHook site at https://easyhook.github.io

NuGet

https://www.nuget.org/packages/EasyHook

For native C++ apps there is also a native NuGet package available: https://www.nuget.org/packages/EasyHookNativePackage

Bug reports or questions

Reporting bugs is the only way to get them fixed and help other users of the library! If an issue isn't getting addressed, try raising a bounty for it.

Report issues at: https://github.com/EasyHook/EasyHook/issues

License

Copyright (c) 2009 Christoph Husse & Copyright (c) 2012 Justin Stenning

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

External libraries

EasyHook includes the UDIS86 library Copyright (c) 2002-2012, Vivek Thampi [email protected]. See .\DriverShared\Disassembler\udis86-LICENSE.txt for license details. Minor modifications have been made for it to compile with EasyHook.

More information about UDIS86 can be found at https://github.com/vmt/udis86

easyhook's People

Contributors

apetukhov avatar firedragonweb avatar gitter-badger avatar greatfirewall avatar justinstenning avatar pzankov avatar qlikterror avatar robertoaraujom avatar starius avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

easyhook's Issues

GetOpenFileName, EasyHook and Windows XP

Moved from CodePlex
Originally submitted by MTops

The Windows API function GetOpenFileName(...) spawns a window that will allow the user to select a file.

When the process that calls this function has a thread injected through EasyHook32, the GetOpenFileName functions stops working. Even without any hooks installed.

This only occurs on Windows XP. Windows Vista and 7 do not have this problem.

I managed to circumvent the problem by using the experimental STEALTH hooking method which doesn't inject a thread, but injects a bit of code into the main thread instead.

CreateAndInject Fails on x64 unmanaged target exe

Hi,
Problem:
I have downloaded the latest version 2 days ago. The filemon sample fails with the following message even with elevated privileges:
There was an error while connecting to target: System.ApplicationException: Unknown error code (-1073741816): Unable to retriev e function address (Code: 299) at EasyHook.RemoteHooking.CreateAndInject(String InEXEPath, String InCommandL ine, Int32 InProcessCreationFlags, InjectionOptions InOptions, String InLibraryP ath_x86, String InLibraryPath_x64, Int32& OutProcessId, Object[] InPassThruArgs) in h:\devroot\Other projects\EasyHook-2.7.5558.0\EasyHook\RemoteHook.cs:line 95 6 at FileMon.Program.Main(String[] args) in h:\devroot\Other projects\EasyHook- 2.7.5558.0\Examples\FileMon\Program.cs:line 88

I started to write my own sample in pure unmanaged c++, and got the same error. The reason is that the CreateToolhelp32Snapshot function fails with 299 partial copy, when the injector tries to obtain the loaded module handles. If I have to guess it is caused by the fact that when a process is created with CREATE_SUSPENDED flag, none of the libraries are loaded just yet.
MSDN remarks section:
...... if the loader data table in the target process is corrupted or not initialized, or if the module list changes during the function call as a result of DLLs being loaded or unloaded, the function might fail with ERROR_BAD_LENGTH or other error code. Ensure that the target process was not started in a suspended state, and try calling the function again.

Environment:
Windows 7 Pro x64, VS2013, EasyHook-2.7.5558.0

Target executable:
A hello world program, which does a messagebeep and then sleeps.

Does anyone have an idea? Am I missing something?
Thanks!

LGPL is not compatible with many app stores

LGPL is not compatible with online app stores,
but, EasyHook is the only choice in .net hooking...

So, I have no choice but ask the original author of EASYHOOK.

I am linking easyhook with dynamic dlls(compiled from a modified copy of easyhook sources)

How to resolve these conficts between LGPL and app stores?
Or could you grant me a license compatiple with app stores?

Thanks.

ProcessMoniter.exe not allowing to SaveAs word files in new name

I have run the sample ProcessMonitor.exe in the EasyHook-Binaries(2.7.5558.0) in the windows 7 machine. It has listed the running processes in the top section.

I have opened the word and selected the WINWORD.exe checkbox in the ProcessMonitor to monitor the word files.
capture1
And I’m trying to saveas the word file with new name, but it’s not allowing to save the file with new name and showing the error message “The file name is not valid”

error

Note:
If I change the compatibility mode from ‘Windows 7’ to ‘Windows XP service pack 2/3 or Windows Vista’ . its working good

word-prop

Right click Microsoft word -> Properties -> Compatibility tab

CreateAndInject doesn't work for managed targets

Moved from CodePlex
Originally submitted by taowen

*Environment: *
Windows Server 2003 R2 x64, Latest Service Pack

Projects:

  1. Host, managed console, who create target and inject guest
  2. Guest, managed dll, being inject to target
  3. Target, managed console, who just sleep three seconds and quit

Expected Behavior:
guest is loaded, and execute before target.

Actual Behavior:
guest is not loaded, and create and inject can not return until the target is finished.

Source Code attached. The log will appear in \helium-.txt
file attachments

bug.zip [x]
bug-bin.zip [x]

Comments

taowen wrote Sep 3, 2008 at 10:58 AM

binaries attached as well. Just execute host.exe, and you can see the logs similar to:

56:44: going to create target.exe and inject guest.dll to it
56:47: host experienced a error: System.ArgumentException: Process with an Id of 3212 is not running. at System.Diagnostics.Process.GetProcessById(Int32 processId, String machineName) at EasyHook.RemoteHooking.CreateAndInject(String InEXEPath, String InCommandLine, String InLibraryPath_x86, String InLibraryPath_x64, Int32& OutProcessId, Object[] InPassThruArgs) at host.Program.Main(String[] args) in C:\bug\host\Program.cs:line 21

The time difference is 3 seconds, it is because the create and inject wait the target sleep 3 seconds. and after create and inject, the target is exited, so that we can not get process by id.
wrote Sep 3, 2008 at 10:58 AM

taowen wrote Sep 3, 2008 at 11:10 AM

I just tested it again. Inject into unmanaged process, like: mspaint.exe, iexplorer.exe, no problem.
but inject to any managed process, no matter is console or GUI, it will always wait until the target finished, and guest not loaded.
so I doubt if the clr hosting api caused the issue. Or is it because the single threaded apartment?
maybe the only way would be inject unmanaged dll. but there is no example on how to use it yet. maybe I can work it out and post it back you.
taowen wrote Sep 3, 2008 at 11:14 AM

Also, if not use CreateAndInject, but create(not suspended), then inject. it works like a charm. So, another solution would be using a managed loader process, let it wait for the hooks being installed, and load the target assembly on the fly, and use reflection to invoke its entry point (main function).

taowen wrote Sep 4, 2008 at 8:19 AM

just verified, injecting to unmanaged console is ok. So, the problem is just for injecting to any managed process.

taowen wrote Sep 8, 2008 at 10:27 AM

Just added some logs. It shows, the target process will not be executed until we create the remote thread. So to me, it seems like CreateRemoteThread triggered the target process execution. The exit code of the remote thread is 0, so the error code says: c++ routine completion routine succeed but didn't raise the event... in the log, we can not see the completion routine being executed at all. but the process explorer shows the EasyHook library is loaded into target process successfully...

ChristophHusse wrote Sep 8, 2008 at 3:58 PM
Your solution folders may be one issue. Do you have all the files "easyhook.dll" "easyhook32/64.dll" and "easyhook32/64Svc.exe" AND the host binary as well as the guest library in one folder???
So to me, it seems like CreateRemoteThread triggered the target process execution.
Puuh... I think I never tried CreateAndInject on managed processes BTW. But make sure that you are not using the stealth injection for CreateAndInject. I think also in the DOCs there is stated somewhere that this won't work. CreateStealthRemoteThread() requires an ACTIVE thread and there is none if you call CreateAndInject...
The exit code of the remote thread is 0, so the error code says: c++ routine completion routine succeed but didn't raise the event... in the log, we can not see the completion routine being executed at all.
The C++ completion routine has no logging by default?! Did you add one? After all your custom completion routine will never be executed from assembler code... But it is still weird that Null is returned. Null should never be returned...

Maybe in case of managed processes you should only use unmanaged injection AND an unmanaged library in case of CreateAndInject. The problem I see here is that the NET Framework probably interfers with the process creation so much, that some assumptions I made about it are just wrong...

Please check whether unmanaged injection AND unmanaged library will work for CreateAndInject for managed processes.

regards
chris

ChristophHusse wrote Sep 8, 2008 at 4:00 PM
Sorry, currently I have no windows installed... Could you give me the logs of your machine???
taowen wrote Sep 9, 2008 at 1:17 AM

I have all the things in one folder (all copied to a folder called "work"), including EasyHook32.dll EasyHook64.dll...
yes, I added the logs, it is using fopen fwrite to write to a txt file.
So, according to the log file, the HookCompleteInjection (entry.cpp) is not being called if I am creating and injecting to a managed process. I tried with Unmanaged hook, it is the same. As HookCompleteInjection not being called, no matter is managed or unmanaged. I thought it was the clr hosting api as well, it turned out not.
The interesting behavior is, If I do not CreateRemoteThread, the target managed process will not be executed as we created it as suspended state. But after CreateRemoteThread, the asm being executed (as I can see the EasyHook dll being loaded), and the target process (suspended primary thread) being executed as well. I don't know what happened at that time (I can not add log to asm code...). I would suspect the load library triggered the dll main caused some problem. BTW, injecting to running process is working properly, but that is not I want, I need the api being hook from the very beginning.
BTW, have you considered using SetThreadContext or NTQueueAPCThread to complement CreateRemoteThread (NtCreateThreadEx), or they two have very obvious limitation force us to use CreateRemoteThread? I would like to know which one is the best. Or, could we make them as strategy, and let the end-user choose which way to use?
BTW again, the db 3eh instruction is for what? why it is before jne in the trampoline asm code? I suspect it is for nothing, just to make the instruction two bytes long?

ChristophHusse wrote Sep 18, 2008 at 5:48 AM
Sorry for late response...

If it only doesn't work from the beginning, then it depends on the target... I can't see any problem with EasyHook because it works in other scenarios, for example when injecting a library into FireFox from the very beginning...

The 0x3e instruction is for something ;-). It will tell the processor that the jump is not taken or taken in general (I am not sure which) and this will speed up the whole thing, because the code prefetcher will prefetch the correct code section most of the time...

regards
chris
wrote Jan 31, 2009 at 8:50 PM

ChristophHusse wrote Jan 31, 2009 at 8:50 PM
I will try to fix this in the final version
wrote Feb 13, 2009 at 1:05 PM

ChristophHusse wrote Mar 7, 2009 at 1:48 AM
The problem is that NET seems to "adapt" the first running thread in a process. So if we start a suspended process, all things go as usual. But the moment when the remote thread is created, instead of executing the target invokation stub, NET seems to hijack this thread for its own purposes. Very funning thing ;-). I will now try to compensate this with another thread.
ChristophHusse wrote Mar 8, 2009 at 4:36 AM

REASON:

It wasn't that easy but after some debugging I found out that NET is hijacking
the first active thread in a process. And since CreateAndInject() is meant to
execute EasyHook in first place, NET hijacks the thread intended to run EasyHook.
So EasyHook is never executed and the host waits until the target terminates.
Then I tried to start another thread but the same problem occurred. It does not
matter how many suspended threads you create and which one you start, the first
active thread will always run the process instead of EasyHook!

WORKAROUND:

Fortunately, NET is a good child ;-). Just setup a wrapper process, install all your
hook either locally or remotely in that process. Remotely means to "inject" a dll
into the wrapper process which has the advantage that EasyHook simplifies the work
required to setup a proper IPC-Connection.
After all your hooks are installed into the wrapper, all you have to do is to load
the target process by calling "System.Reflection.Assembly.Load()", extract the
main() method and execute it via dynamic invoke. To all guys new to this invokation
stuff, just read some articles about NET reflection and dynamic invokation ;-).

Infinite loop in LhInstallHook if no memory can be found.

Moved from CodePlex
Originally submitted by jgg99

I had an issue where a call to LhInstallHook in my application would never return, and after investigation, it was looping infinitely in LhAllocateMemory here:

    // we are trying to get memory as near as possible to relocate most RIP-relative addressings
    for(Base = (LONGLONG)InEntryPoint, Index = 0; ; Index += PAGE_SIZE)
    {
        if(Base + Index < iEnd)
        {
            if((Res = (UCHAR*)VirtualAlloc((void*)(Base + Index), PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)) != NULL)
                break;
        }

        if(Base - Index > iStart)
        {
            if((Res = (BYTE*)VirtualAlloc((void*)(Base - Index), PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)) != NULL)
                break;
        }
    }

If VirtualAlloc never returns a valid address, it will never exit this loop. A simple fix would be to break the loop if neither of the "if" branches is entered:

    // we are trying to get memory as near as possible to relocate most RIP-relative addressings
    for(Base = (LONGLONG)InEntryPoint, Index = 0; ; Index += PAGE_SIZE)
    {
        BOOLEAN end = TRUE;
        if(Base + Index < iEnd)
        {
            if((Res = (UCHAR*)VirtualAlloc((void*)(Base + Index), PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)) != NULL)
                break;
            end = FALSE;
        }

        if(Base - Index > iStart)
        {
            if((Res = (BYTE*)VirtualAlloc((void*)(Base - Index), PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)) != NULL)
                break;
            end = FALSE;
        }

        if (end)
            break;
    }

As a suggestion for improvement, this loop could also be optimized by using VirtualQuery to walk through contiguous regions of memory pages, e.g. to avoid examining each page of a large allocation.

Thanks!

Target process DLL missing error catching

Moved from CodePlex
Originally submitted by MTops

When using the EasyHook RhInjectLibrary function on a process that will not load because it is missing an implicitly loaded DLL, the resulting error message will be "Unknown error in injected assembler code."

The error handling switch statement needs to check for Code 0xC0000135 to catch this specific error.

Throw actual exception instead of swallowing them in FindEntryPoint and throwing System.IO.FileNotFoundException

Moved from CodePlex

Instead of {System.IO.FileNotFoundException: The given user library could not be found.}, have the binaries in build folder, and was still not sure why it fails to load. Finally decided to modify private static Type FindEntryPoint(string userAssemblyStrongName, string userAssemblyFileName) by throwing the actual exceptions instead of swallowing them. I found that my binaries were of incorrect type.
The actual exceptions were clear enough for me to fix!

{"Could not load file or assembly '<my dll>, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=c7d65e07d9025c78' or one of its dependencies. An attempt was made to load a
program with an incorrect format."}

Could not load file or assembly '' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Use SetWindowsHookEx with EasyHook?

I'm not sure if this is currently possible but if it's not this should be made possible with EasyHook because we don't just need to hook function, we also need to hook Win32 message. SetWindowsHookEx makes it possible to hook messages sent to some app (with hook id of WH_CALLWNDPROC or WH_GETMESSAGE and some other ids).

Using SetWindowsHookEx against the current process is just easy but when it comes to other process, we need some separate dll (containing the hook proc) to be injected into the target process. I think EasyHook does this part well. So the next part should be simple but maybe I still don't understand something important about how EasyHook works internally and cannot make it work.

My idea is declare SetWindowsHookEx (and some other related apis) right in the injected dll class. In the Run method, instead of creating LocalHook, I tried calling SetWindowsHookEx there. I think the executing context there should be inside the target process, so SetWindowsHookEx now is used just as if it was used to hook the local process. It returns a non-zero hook handle meaning it seems successful but the hook proc is not called (the logging code in there does not print any message). Here is what I tried, all inside the injected class (implementing IEntryPoint):

[DllImport("user32", SetLastError=true)]
static extern int SetWindowsHookEx(int iHook, HookProc proc, IntPtr hMod, int threadId);
[DllImport("user32")]
static extern int CallNextHookEx(int hHook, int idHook, IntPtr wParam, IntPtr lParam);
[DllImport("user32")]
static extern int UnhookWindowsHookEx(int iHook);
delegate int HookProc(int idHook, IntPtr wParam, IntPtr lParam);
struct CWPSTRUCT {
        public IntPtr wParam;
        public IntPtr lParam;
        public int msg;
        public IntPtr hwnd;
}

public void Run(RemoteHooking.IContext context, string channel) {
       hp = hookProc;
       //WH_CALLWNDPROC = 4
       //I've tried even using the native GetCurrentThreadId api but it has the same result.
       hHook = SetWindowsHookEx(4, hp, IntPtr.Zero, RemoteHooking.GetCurrentThreadId());
       RemoteHooking.WakeUpProcess();
       while(true){
             System.Threading.Thread.Sleep(500);
       }
}
int hHook;
HookProc hp;
int hookProc(int hookId, IntPtr wParam, IntPtr lParam) {
        client.Log("Some msg caught.");
        if (hookId >= 0) {                
            var msg = (CWPSTRUCT) Marshal.PtrToStructure(lParam, typeof(CWPSTRUCT));
            client.Log(msg.msg.ToString());
        }
        return CallNextHookEx(hHook, hookId, wParam, lParam);        
}

I doubt that the problem is a wrong thread id passed in. As I understand the thread id here should be the main thread id running the message loop of the target window.

BTW, if this is possible we should also know when the target app exits to call UnhookWindowsHookEx. I've tried handling AppDomain.CurrentDomain.ProcessExit and Process.GetCurrentProcess().Exited (with EnableRaisingEvents set to true) events but both are not even fired.

As I said this is a very interesting feature, if it is currently not possible, please make it possible. Thank you very much.

Injecting assembly into application using EasyHook internally (eg Unreal Engine 3) description

Moved from CodePlex
Originally submitted by capenl

Hi,
I'm having a strange issue injecting an assembly into applications using Unreal Engine 3. It works if I use a C++/CLI injection library, but if I write a C# library, my application crashes upon trying to inject. I get a "STATUS_INTERNAL_ERROR: Unknown error in injected C++ completion routine. (Code: 14)"

In both cases, I'm calling EasyHook from a C# assembly, but there is some difference in the method I use in EasyHook. For the C++/CLI library I use NativeAPI.RhInjectLibrary(), like this:
NativeAPI.RhInjectLibrary(ProcessInfo.ProcessId, 0, 0, dllName, dllName, intPtr.AddrOfPinnedObject(), (int)ms.Length);
Where ms is a MemoryStream to which I serialize the data I want to pass over, and intPtr is the pointer to the corresponding buffer (GCHandle.Alloc(ms.GetBuffer(), GCHandleType.Pinned);)

In the C# assembly I use RemoteHooking.Inject, like this:
RemoteHooking.Inject(ProcessInfo.ProcessId, dllName, dllName, injectionData);
Here injectionData is the data as an object, not serialized.

So, to reiterate, for most processes, both approaches work, but for Unreal Engine 3-games, only the C++/CLI version works. Any idea why? Am I doing something wrong? I'm using EasyHook version 2.7.5159, and my .NET projects target CLR 4.5.

Best regards,
Carl

Comments

Temaran wrote Apr 2 at 10:29 PM

Hello Spazzarama!

I am working with this now instead of capenl, and it seems like we are still experiencing similar errors here.

I've been running my tests with this workflow:

  1. Get the latest 2.7 release branch snapshot
  2. Build the netfx4.0-release configuration for both Win32, x64 and AnyCPU to get all binaries.
  3. Run the samples and try to inject into different targets

Some things seem to be working, some don't.

When running the AnyCPU ProcessMonitor for example it almost always throws the "STATUS_INTERNAL_ERROR: Unknown error in injected C++ completion routine. (Code: 15)" error, no matter the process.
Sometimes it also throws because of STATUS_INTERNAL_ERROR: Unable to find EasyHook library in target process context. (Code: 5). If I try to inject into chrome.exe for example I get this.

Now, if I instead build the netfx3.5 release, it works for almost all processes, except for a few. One is the SCNotification.exe process (not sure what this is, but it seems related to showing adverts) and also another process that is inhouse. Both of these processes are running .net 4.0, and throw "STATUS_INTERNAL_ERROR: Unknown error in injected C++ completion routine. (Code: 15)"

I don't think this matters much for us though, since we aren't really interested in injecting into any of these, but it might be interesting to find out why these processes cannot be injected into.

Best regards,
Temaran

CreateAndInject leads to crash

Moved from CodePlex
Originally submitted by werker

I tried the CreateAndInject function and the FileMon tool with the full path to the exe file.
In both cases the target exe crashed right after the start.

FileMon shows the following: "System.ApplicationException: STATUS_INTERNAL_ERROR: Unknown error in injected assembler code. (Code: 5)"

The target exe files were the Windows notepad.exe and calc.exe (and some others).
The operating system is Windows 7 64 bit (also tested 32 bit in VM).
I tested the .NET 4.0 and 3.5 version.
I used the latest EasyHook 2.7 download on this website and a self compiled binary from the latest source code.

Comments

Sebmaster wrote Jan 13 at 11:06 AM

I've found a possible cause for this, I'm not sure if it applies to your case though.

It occurs when EasyHook tries to inject a library into a suspended process. I spent the whole day debugging and managed to RhInjectLibrary.

In the 2.7 release branch you'll find the following lines:

Info->LoadLibraryW   = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "LoadLibraryW");
Info->FreeLibrary    = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "FreeLibrary");
Info->GetProcAddress = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "GetProcAddress");
Info->VirtualFree    = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "VirtualFree");
Info->VirtualProtect = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "VirtualProtect");
Info->ExitThread     = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "ExitThread");
Info->GetLastError   = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "GetLastError");

all of them will return a NULL pointer in a suspended process (although I haven't looked much into why that is). I have no idea why those function pointers are determined so weirdly, there may be a reason, but for my use-case I just patched those with the ones which are still in trunk:

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");

werker wrote Jan 14 at 7:52 AM

I think you are absolutely right.

A while ago I read that you can't enumerate the modules of a remote process when it is created and in a suspended state. So GetRemoteFuncAddress can't get the address of kernel32.dll to look further for the function addresses.

For now I don't know a solution that can still use GetRemoteFuncAddress.

werker wrote Jan 15 at 8:12 PM

I think I found the solution in another injection library for c++. It's called hadesmem by RaptorFactor.
He creates a remote thread that returns immediately, which seems to make it possible to enumerate the modules afterwards.

I created a function for this in the RemoteHook/thread.c mentioned above.

EASYHOOK_NT_INTERNAL NtForceLdrInitializeThunk(HANDLE hProc)
{
    HANDLE                  hRemoteThread = NULL;
    UCHAR*                  RemoteInjectCode = NULL;
    BYTE                    InjectCode[3];
    ULONG                   CodeSize;
    SIZE_T                  BytesWritten;
    NTSTATUS                NtStatus;

#ifdef _M_X64
    InjectCode[0] = 0xC3;
    CodeSize = 1;
#else
    InjectCode[0] = 0xC2;
    InjectCode[1] = 0x04;
    InjectCode[2] = 0x00;
    CodeSize = 3;
#endif

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

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

    if((hRemoteThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)RemoteInjectCode, NULL, 0, NULL)) == NULL)
        THROW(STATUS_ACCESS_DENIED, L"Unable to create remote thread.");

    WaitForSingleObject(hRemoteThread, INFINITE);

    RETURN;

THROW_OUTRO:
FINALLY_OUTRO:
    return NtStatus;
}

Then I call the function right before getting the remote function addresses, so it looks like this:

    FORCE(NtForceLdrInitializeThunk(hProc));

    // Determine function addresses within remote process
    Info->LoadLibraryW   = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "LoadLibraryW");
    Info->FreeLibrary    = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "FreeLibrary");
    Info->GetProcAddress = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "GetProcAddress");
    Info->VirtualFree    = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "VirtualFree");
    Info->VirtualProtect = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "VirtualProtect");
    Info->ExitThread     = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "ExitThread");
    Info->GetLastError   = (PVOID)GetRemoteFuncAddress(InTargetPID, hProc, "kernel32.dll", "GetLastError");

spazzarama wrote Jan 18 at 12:59 PM

The reason for the change to GetRemoteFuncAddress is that there are situations under which using your current process to determine the addresses within the remote process will not give you the same offset as within the target resulting in crashes also.

I like the idea of using the temporary remote thread solution that werker has posted, will need to test this out.

koczkatamas wrote Feb 25 at 10:24 PM

I had the same problem and werker's workaround solved it. Thanks werker!
wrote Feb 25 at 10:40 PM

tqtam1993 wrote May 14 at 1:53 PM

Thank you werker!

This solution helps me so much.

EasyHookSys.sln/TestDriver is not compiling

Moved from CodePlex
Originally submitted by howie_lius

libudis86 is introduced in release-2.7, but is not compiling in EasyHookSys.sln

Is it a problem?

Comments

spazzarama wrote Mar 9, 2014 at 6:37 PM

The EasyHookSys C++ project file needs updating.


Moved from CodePlex
Originally submitted by azizulhakim

EasyHook 2.6 Example TestDriver Build Error

I've been trying to learn kernel mode hooking in EasyHook. I've been trying to build the EasyHook version 2.6 which comes with some example codes also. I'm using Visual Studio 2010 and WDK 7.0.1 on Windows 7. So far I've been able to build all the projects included in EasyHook.sln except the driver project named TestDriver. Whenever I try to build this one it says a header file "winternl.h" is missing.

The exact error message is-
error C1083: Cannot open include file: "winternl.h": No such file or directory
I searched a little bit and most plausible solution was to install Windows SDK. I've done that with no success. I also couldn't found the header file in my directory structure and also don't have any idea about this header file. A guideline on how to build the TestDriver project in EasyHook solution is highly appreciable.

Potential LhFreeMemory call on random pointer

Hi,

in LhAllocateHook() the variable Hook isn't initialized with NULL and the first assignment is only done after three potential THROW calls.
So we might end in the THROW_OUTRO happily passing the null pointer check and calling LhFreeMemory() on a random pointer.

Updated Documentation

Moved from CodePlex
Originally submitted by blmille1

Can we please update the documentation to be in sync with the binaries--or perhaps vice versa.

Just as long as the tutorial works with the library.

Thanks!

No proper Run() method found

Whenever I try to inject my dll into a process using the RemoteHooking.Inject() method I get this error message:

The given user library does not export a proper Run(EasyHook.InjectionLoader+REMOTE_ENTRY_INFO) method in the 'EasyHook.IEntryPoint' interface.

I do have a Run method though, this is how the class looks like:

public class Main : IEntryPoint
{
    public Main(RemoteHooking.IContext InContext, String InChannelName)
    {

    }

    public void Run(RemoteHooking.IContext InContext, String InChannelName)
    {

    }
}

So I don't understand why it's saying there is no run method.

Address compiler warnings

Time to clean up some of the compiler warnings from adding the udis86 library and other long standing ones.

How to build EasyHook32Svc.exe and EasyHook64Svc.exe from the source code?

The only project seems to be used to build those exe files is EasyHookSvc.proj
But when building it the output is just the EasyHookSvc.exe

Are those exe files are pre-built from some other source code? If I can build them with the source code downloaded from here, how could I do that? Thank you very much.

Hook GetVolumeInformation in 32bit app failed to modify StringBuilder?

I made a simple 32bit app in which the function GetVolumeInformationA is called, here is the declaration:

[DllImport("kernel32")]
static extern int GetVolumeInformation(string root, StringBuilder volumeName, int volNameSize, ref int serial, ref int maxComponentLength, int flags, StringBuilder fileSystemName, int fileSystemNameSize);

And here is the code calling GetVolumeInformation, it succeeds getting the information:

int serial = 0;
int maxCLen = 0;
var volName = new StringBuilder(260);
var sysName = new StringBuilder(260);                        
GetVolumeInformation("d:\\", volName, volName.Capacity, ref serial, ref maxCLen, 0, sysName, sysName.Capacity);

Then I tried creating another app using EasyHook to hook GetVolumeInformationA, the hook in fact succeeds. But when I tried to modify the passed-in argument volumeName (a StringBuilder) by simply appending some suffix to the actual volume name like this:

volumeName.Append("_tail");

Then it failed with an exception:

System.ArgumentOutOfRangeException: capacity was less than the current size.

I inspected the passed-in argument volumeName and knew that its MaxCapacity is just 0. With the same code calling GetVolumeInformation but if built as x64 then the hook succeeds to modify the returned volumeName (with a suffix of "_tail" appended). So looks like it's not an easy problem to me. I also wonder if this may be an issue of EasyHook? And if it is possible to achieve what I want (hooking against 32bit app and modify the volumeName)? I've tried building my app including my test app, the injected dll,... (used to hook GetVolumeInformation) as both x86 and x64 but they both failed to give the desired result.

There are many 32bit apps out there, if this is impossible then we cannot enjoy EasyHook in many cases. BTW the "serial" (a ref int) can be modified well, just StringBuilder arguments are not able to be modified (with the exception I mentioned).

LocalHook.Create throwing AccessViolationException

Hi EasyHookers,

Your product is working wonderfully for us in most situations. But we are experiencing an issue on Windows 2008 Terminal Services machine. The call to GetProcAddress is throwing this exception:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at EasyHook.LocalHook.Create(IntPtr InTargetProc, Delegate InNewProc, Object InCallback)

Your documentation clearly states that this exception will be thrown when "Access to target process denied or the current user is not an administrator", but we are running our application as an administrator (using the "Run as administrator" File Manager menu option), so it should have the necessary permissions.

Below is a summary of the code we are using. Are we doing anything wrong that might cause this error? ANY suggestions at all that you can provide would be most appreciated!

Andrew

public class Injector : EasyHook.IEntryPoint {

[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
delegate bool DExtTextOutW(IntPtr hdc, int X, int Y, uint fuOptions, IntPtr lprc, IntPtr lpString, uint cbCount, IntPtr lpDx);

public void InstallHook(NxKitInterface iface) {
LocalHook.Create(
LocalHook.GetProcAddress("Gdi32.dll", "ExtTextOutW"),
new DExtTextOutW(ExtTextOutW_Hooked),
this
);
}

static bool ExtTextOutW_Hooked(IntPtr hdc, int X, int Y, uint fuOptions, IntPtr lprc, IntPtr lpString, uint cbCount, IntPtr lpDx) {
}

}

Hooked Stacks are not walkable

Moved from CodePlex
Originally submitted by Alois

Easyhook is a great library which I have used for x86 programs with great success to hook into OS methods to find handle leaks and such things.
I did basically hook e.g. MapViewOfFile and write out an ETW Event with the method arguments. The same for UnmapViewOfFile. With Windows Event Tracing I get a nice ETL file which I can open with WPA and directly see where the leaks might be hiding.
This is a great way to find leaks of pretty much anything without slowing down the application like a debugger does with breakpoints and logging the call stacks.
Under x64 Win 8.1 the ETW stackwalker is not able to walk the stack so the call stack ends at my hooked method which is unfortunate. It looks like interceptions method Easyhook uses to hook methods is not exepcted by the stackwalker to further traverse the stack.
I wonder if there is a way to make Easyhooked method more ETW stackwalk friendly so I can get the best of both worlds.

Comments from CodePlex

Alois wrote May 8 at 3:31 PM

I have got word from MS that for hooked methods one needs to add Unwind information to the hooked methods.

The OS needs to have the 64 bit unwind information in order to unwind a stack frame. If you inject new methods, you need to also register the unwind information associated with it. There were already APIs for doing this, but it expected you to register a complete Function table (for an entire module) all at once. For JIT compilation we needed a way of specifying this information incrementally as methods are JIT compiled. We used these new Win8 functions to do it.

RtlAddGrowableFunctionTable
RtlGrowFunctionTable
RtlDeleteGrowableFunctionTable 

Since the CLR is open source now we could use this like the JIT compiler does it here:

https://github.com/dotnet/coreclr/blob/master/src/vm/codeman.cpp

Has anyone experience with such stuff?

spazzarama wrote May 8 at 11:02 PM
Looks interesting, it would be helpful to have a cut down simple test project to use to test with, any chance you can attach something here? Thanks

Alois wrote May 12 at 3:56 PM
Yes I will make a small sample to repro the issue. Currently I am quite busy. Give me a week to come up with a sample.

Alois wrote May 15 at 7:33 AM
I have edited FileMon.exe of your samples with an custom ETW Provider.

See https://drive.google.com/folderview?id=0BxlmobpeaahAMllKamt3LWxheXM&usp=sharing

Under Source\Build\netfx4-Debug\CreateFileLogs.etl is an ETL file which shows the issue. Additionally in the shared folder is a Screenshot of WPA.exe looking at the call stack which ends in the middle.

The current implementation of FileMon compiles only for x64. I hope this helps to reproduce the problem and if you can add the corresponding exception handler unwind information to EasyHook it would be really helpful.

Alois wrote May 27 at 5:12 AM
Dies the sample work for you? If you have problems to get it running drop me a note.

Yours,
Alois Kraus

Registering for all threads is not obvious

Moved from CodePlex
Originally submitted by joachim99

My idea was to use LhSetGlobalExclusiveACL(0,0).

Exclusive would mean to allow all threads not in the list. And since the list is empty, all threads are allowed.
But internally in LhSetACL there is a check for IsValidPointer which fails for 0, even though the size is also 0.
So currently I must specify a valid pointer to an array and size 0, even though the array is then not used.
The check should include the InThreadCount. e.g.:

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

And it would be very helpful to add a valid example for this in the documentation.
Joachim

Comments

joachim99 wrote Jun 1, 2010 at 6:10 AM

After trying again and debugging, I saw, that I also have to call LhSetExclusiveACL() for each hook too.
Perhaps you could provide a method to enable all hooks for all threads in one step?
Joachim

Support for injecting a dll only once

Moved from CodePlex
Originally submitted by chaos072

There's no need to inject the same dll to a target process many times. It only causes clumsy problems.

It'll be great if EasyHook support an injection method that prevents duplicate injections.

It can be implemented easily as follows:

In DLL's constructor,

private readonly Mutex hookedMutex;

public Main(RemoteHooking.IContext context, string ipcChannelName) {
  this.hookedMutex = new Mutex(true, String.Format("MyHookedMutex.{0}", RemoteHooking.GetCurrentProcessId()));
}

And in injecting host program:

private void Inject(int targetPID, string x86Library, string x64Library) {
  if (!this.IsAlreadyHooked(targetPID)) {
    RemoteHooking.Inject(targetPID, x86Library, x64Library, this.ipcChannelName);
  }
}

private bool IsAlreadyHooked(int targetPID) {
  try {
    Mutex mutex = Mutex.OpenExisting(String.Format("MyHookedMutex.{0}", targetPID));
    return true;
  }
  catch (WaitHandleCannotBeOpenedException) {
    return false;
  }
}

LhWaitForPendingRemovals never times out

UINT32 Timeout = 1000;
Later:
if (Timeout < 0)
{
// this hook was not released within timeout or cannot be released.
// We will leak the memory, but not hang forever.
NtStatus = STATUS_TIMEOUT;
break;
}

I guess the fix is to use signed int.
Thanks!

WinXP + GetWindowDC hook crash

Moved from CodePlex
Originally submitted by EaSy123

I have described problem and (probably) a solution to this. I hope it will be an easy fix. :)

http://easyhook.codeplex.com/Thread/View.aspx?ThreadId=73300

Thanks.

Comments

EaSy123 wrote Oct 20, 2010 at 4:51 AM

for example: "ResumeThread" will be no longer hookable on 32b using this solution ... workaround is to hook NtResumeThread

Paramike wrote Feb 8, 2011 at 7:24 PM

This error also occurs while hooking FindNextFileA on Windows Vista 32 bits. The same fix applies.

Suggested solution

EaSy123 Oct 8, 2010 at 6:27 AM Edited Oct 8, 2010 at 6:32 AM

Hello,

sorry for reopening old post.

I want add some info. There is a problem with RtlProtectMemory.

The solution to problem is:

#ifdef X64_DRIVER
    FORCE(EntrySize = LhRoundToNextInstruction(InEntryPoint, 16)); //originaly was 12
#else
    FORCE(EntrySize = LhRoundToNextInstruction(InEntryPoint, 8)); //originaly was 5
#endif

value is then used by:

//this code is used only in 32b, so in 64b 12 will probably work
FORCE(RtlProtectMemory(Hook->TargetProc, Hook->EntrySize, PAGE_EXECUTE_READWRITE));

and data are written:

#ifdef X64_DRIVER
...
    *((ULONGLONG*)(Hook->TargetProc + 0)) = AtomicCache_x64;
    *((ULONGLONG*)(Hook->TargetProc + 8)) = AtomicCache;               //reason why 16 (not 12)
#else
...
    *((ULONGLONG*)Hook->TargetProc) = AtomicCache;  //reason why 8 (not 5)
#endif

You may wonder, why it is problem.

It is not problem until LhRoundToNextInstruction is returning >= 8, and this is not happening on some wXP machines with GetWindowDC function --> crash or BSOD.

Finally I hope, this modification wont cause more trouble. :))

Look into supporting Action<T> and Func<T,TResult> as hook handlers

MessageBoxA for example might be hooked similar to:

var messageBoxHook = LocalHook.Create<Func<IntPtr, string, string, int, int>>(
  (hwnd, lpText, lpCaption, type) => {
    // do something else first, then call original method
    return MessageBoxA(hwnd, lpText, lpCaption, type);
  }, addressOfOriginalMessageBoxA
); 

There is a bug in ReleaseSelfProtection()

Moved from CodePlex
Originally submitted by howie_lius

void ReleaseSelfProtection()
{
/*
Description:
Exists the TDB self protection. Refer to AcquireSelfProtection() for more
information.

An assertion is raised if the caller has not owned the self protection.
*/
LPTHREAD_RUNTIME_INFO       Runtime = NULL;

ASSERT(TlsGetCurrentValue(&Unit.TLS, &Runtime) && Runtime->IsProtected);

Runtime->IsProtected = FALSE;
}

If the code is compile in release mode. The code looks like:

LPTHREAD_RUNTIME_INFO       Runtime = NULL;
Runtime->IsProtected = FALSE;

System will be crashed.

The same bug occurs in LhBarrierOutro()

NuGet for EasyHook

Moved from CodePlex
Originally submitted by Cel654321

Would it be possible to ease deployment by creating a NuGet - and this would potentially increase uptake manyfold, in general ..

Access violation when hooking registry inside Winword process (64bit, Windows 8) - reentrant

Moved from CodePlex
Originally submitted by helmy

Hi,
I have to hook all windows registry functions in a VSTO addin that runs inside Microsoft Word.
This worked fine for years now with your great easyhook ...until we ported to .NET 4.0.
Using latest version 2.7 of easyhook did not solve the problem.
32bit works fine, but running the hook in 64bit winword process crashes with an access violation.
The problem appears under Windows 8 (sometimes also under Windows 7). I am using the 64bit version of Office 2010 and 2013.

I did a lot of debugging but could not find the problem. RIP addresses are not used, I checked that during debugging.

I attached a VSTO addin sample where I only install a hook for RegOpenKeyW and RegOpenKeyA. There is a setup in the publish folder
to install the addin in Word 2010 or 2013 (64bit).

The addin adds a new HOOKING tab on the ribbon. Create RegHook installs hook for RegOpenKeyW and RegOpenKeyA of kernelbase.dll.

Clicking on "Create RegHook" will crash winword process.

Any help is appreciated!
thanks

Comments

helmy wrote Sep 4, 2014 at 5:45 PM
There seems to be a problem with reentrances just under 64bit (W7 & W8.1). We are using the latest release 2.7.5292.0.
In our registry handler for e.g. RegOpenKeyEx we are calling HookRuntimeInfo.Callback at the very beginning.
Before the Callback is returned, RegOpenKeyEx is

called from the system on the same thread and in LhBarrierIntro Runtime->Current is set to NULL. HookRuntimeInfo.Callback returns then STATUS_NOT_SUPPORTED. Although I am inside a hook handler. This is very strange because we never saw that exception before. It appeared when we switched to Framework 4.0, and only for 64bit.

There is a SelfProtection in LhBarrierIntro that cares about reentrance.
We solved the problem by putting the AquireSelfProtection() and ReleaseSelfProtection()
to the interface of easyhook to be able to call it before our hook handlers are called. Since we are using that our problems are solved.

Callstack of a thread looks as following:

EasyHook64.dll!LhBarrierGetCallback() // throws status not supported although I am inside a hook handler

[managed to native trainsition]
EasyHook64.dll!LhBarrierIntro() // at DONT_INTERCEPT: Info->Current = NULL
advapi32.dll!RegOpenKeyExWStub()// system calls RegOpenKey
EasyHook.dll!EasyHook.NativeAPI.LhBarrierGetCallback()
EasyHook.dll!EasyHook.HookRuntimeInfo.Handle.get()
EasyHook.dll!EasyHook.HookRuntimeInfo.Callback.get()
OurCustomWinApiHooks.dll!RegOpenKeyEx_Hooked() // this is my hook callback where I call HookRuntimeInfo.Callback 

Attached the modified sample (with 2.7.5292.0). where the exception is easily reproducible with word 64bit. attachment: https://www.dropbox.com/s/8hkzj10f19f7ezq/WordPlugin2.zip?dl=0

would be great if you could take a look at it and maybe consider putting SelfProtection on the interface for such cases?
thanks

Any file with name of EasyLoad32.dll in the same folder with target will cause exception!

I've found this very very little bug by chance. And I think you may even know this but assumed that it should never happen. To me this is not a serious bug but anyway it's a bug. We can hardly encounter this bug because the condition is if there is any file with name EasyLoad32.dll (no matter it is the actual binary file EasyLoad32.dll companied with the EasyHook package or not) in the same folder with the target application (which we hook), the hook then will fail with both Inject and CreateAndInject throwing this exception: STATUS_INTERNAL_ERROR: Unknown error in injected C++ completion routine. (Code: 15)

Here is the test project I've made: https://drive.google.com/file/d/0B9pRIB5Qqb08VjNxdXJwNjlTa2M/view?usp=sharing

This time I'm not very eager to wait for the bug to be fixed :)

Hook COM Interface BUG

I use COMClassInfo Navigate2 hook method (Microsoft.mshtml.dll WebBrowserClass, IWebBrowser2), I found that using new COMClassInfo (typeof (WebBrowserClass), typeof (IWebBrowser2), "Navigate2") correctly hooked Navigate2 method, but using new COMClassInfo (typeof (WebBrowserClass) .GUID, typeof (IWebBrowser2) .GUID, 52) can not be hooked. The reason is COMClassInfo the Query method has a BUG

 IntPtr interfaceIntPtr = IntPtr.Zero;
            if (InterfaceType! = null)
                interfaceIntPtr = Marshal.GetComInterfaceForObject (classInstance, InterfaceType);
            else
                interfaceIntPtr = Marshal.GetIUnknownForObject (classInstance);

Change the Code

IntPtr interfaceIntPtr = IntPtr.Zero;
if (InterfaceType! = null)
{
      interfaceIntPtr = Marshal.GetComInterfaceForObject (classInstance, InterfaceType);
 }
else
{
                
    interfaceIntPtr = Marshal.GetIUnknownForObject (classInstance);
    Marshal.QueryInterface (interfaceIntPtr, ref interfaceGuid, out interfaceIntPtr);
  }

Command line arguments missing

Moved from CodePlex
Originally submitted by lustuyck

We are using the RemoteHooking.CreateAndInject, and pass arguments which contain double quotes, like:

@"/RT:Live /W:""\server\test""";

The application receives this argument, but all quotes were stripped for some reason; and therefore it fails.

Do you have any idea why double quotes are stripped?

Comments

lustuyck wrote Feb 11, 2014 at 5:35 PM

Correction: it seems arguments are not passed at all? My code is:

RemoteHooking.CreateAndInject(_applicationPath,
                                            _commandLineArgs,
                                            (int)creationFlags,
                                            "AHRUValuationControllerAFMToolboxInject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=95DCCA448AADD932",
                                            "AHRUValuationControllerAFMToolboxInject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=95DCCA448AADD932",
                                            out processId,
                                            ChannelName,
                                            regKeyOverride.Key,
                                            regKeyOverride.ValueName,
                                            regKeyOverride.OverridenValue
                                            );                

And _commandLineArgs contains a string. But the executed application doesn't receive it.

Error while hooking CreateThread

Moved from CodePlex
Originally submitted by Alois

I have tried to hook CreateThread which fails on Win7 x86/x64 with an access violation.
The original code before hooking is

KERNEL32!CreateThreadStub:
00000000`77346580 4883ec48        sub     rsp,48h
00000000`77346584 488b442478      mov     rax,qword ptr [rsp+78h]
00000000`77346589 4889442438      mov     qword ptr [rsp+38h],rax
00000000`7734658e 8b442470        mov     eax,dword ptr [rsp+70h]
00000000`77346592 48c744243000000000 mov   qword ptr [rsp+30h],0
00000000`7734659b 89442428        mov     dword ptr [rsp+28h],eax
00000000`7734659f 4c894c2420      mov     qword ptr [rsp+20h],r9
00000000`773465a4 4d8bc8          mov     r9,r8
00000000`773465a7 4c8bc2          mov     r8,rdx
00000000`773465aa 488bd1          mov     rdx,rcx
00000000`773465ad 4883c9ff        or      rcx,0FFFFFFFFFFFFFFFFh
00000000`773465b1 e80e000000      call    KERNEL32!CreateRemoteThreadEx (00000000`773465c4)
00000000`773465b6 4883c448        add     rsp,48h
00000000`773465ba c3              ret

After hooking:

> KERNEL32!CreateThreadStub:
00000000`77346580 48139df4ff8b44  adc     rbx,qword ptr [rbp+448BFFF4h]
00000000`77346587 2478            and     al,78h
00000000`77346589 4889442438      mov     qword ptr [rsp+38h],rax
00000000`7734658e 8b442470        mov     eax,dword ptr [rsp+70h]
00000000`77346592 48c744243000000000 mov   qword ptr [rsp+30h],0
00000000`7734659b 89442428        mov     dword ptr [rsp+28h],eax
00000000`7734659f 4c894c2420      mov     qword ptr [rsp+20h],r9
00000000`773465a4 4d8bc8          mov     r9,r8
00000000`773465a7 4c8bc2          mov     r8,rdx
00000000`773465aa 488bd1          mov     rdx,rcx
00000000`773465ad 4883c9ff        or      rcx,0FFFFFFFFFFFFFFFFh
00000000`773465b1 e80e000000      call    KERNEL32!CreateRemoteThreadEx (00000000`773465c4)

Easyhook seems to generate incorrect assembly instructions when hooking CreateThread.

0000000077346580 48139df4ff8b44 adc rbx,qword ptr [rbp+448BFFF4h]
0000000077346587 2478 and al,78h

The backpatched assembly target looks not ok after the managed hook was called.

Managed hook:

    static IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId)
    {
        var handle = NativeMethods.CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
        return handle;
    }

Native declaration:

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, 
        uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, 
        uint dwCreationFlags, IntPtr lpThreadId);

Remove TRemoteObject : System.MarshalByRefObject constraint from RemoteHooking::IpcConnectClient<TRemoteObject>(string InChannelName)

Moved from CodePlex
Originally submitted by yimeltem

Background: I have a project where the client side and server side code is physically separated and neither of the projects have a reference to the other. There is, however, a 3rd assembly, which contains the interfaces that are implemented on both sides as MarshalByRefObj's, and some serializable dto's, and referenced by the client and the server assemblies. (see the attachment)

Therefore, I need to create the proxy objects using the interfaces, and MarshalByRefObj constraint on RemoteHooking::IpcConnectClient(string InChannelName) makes it unusable in this case.

However, the code below works fine.

this.serverInterface =
            (IServerInterface)
            Activator.GetObject(typeof(IServerInterface), "ipc://" + channelName + "/" + channelName);

model

Trying to make EasyHook even easier but having issue with target being unhooked after the main app (server) exits?

I don't touch any source code of EasyHook. I just create a base class implementing IEntryPoint, it has an internal List to maintain all APIs to be hooked. The Run method then will loop through that List and create each LocalHook foreach one.

Next time, I don't have to implement IEntryPoint, just inherit the base class I created, add custom APIs to the List and done. It works nearly perfectly but I've found that if the main app (IPC server but I call it client because it gets info from the target :) exits, the target then seems to be unhooked. Although there is not any specific code to unhook I could find.

If implementing IEntryPoint directly (as before), the target remains hooked after the main app exits. That behavior is commonly useful so I need your help to find out what could be wrong causing this quite strange issue.

Here is the test project I've made: https://drive.google.com/file/d/0B9pRIB5Qqb08a3QyMlhYaldnSWs/view?usp=sharing

After running the testApp, you can try closing the target (TryExitingMe.exe), it shows that it's hooked OK. But now try exiting the main app, after that try closing the target again, it then shows that it seems to be unhooked and behaves normally (allowing to exit normally).

I hope you could help me solving this, I myself tried finding out what's wrong for a whole day but finally I had to accept that it's out of my knowledge. Thank you very much!

PS: I believe my approach would surely make it easier when working with EasyHook, so it should be supported.

Problem with LhBarrierBeginStackTrace AFTER the original function is called from a hook handler

Hi, I'm trying to log functions together with a callstack trace.
My hook handler:

LPVOID WINAPI HeapAllocHook(
    _In_ HANDLE hHeap,
    _In_ DWORD  dwFlags,
    _In_ SIZE_T dwBytes
    )
{
    LPVOID result = HeapAlloc(hHeap, dwFlags, dwBytes);
    PVOID pCallStackBackup = NULL;
    LhBarrierBeginStackTrace(&pCallStackBackup);

// Here I call my own logger function which captures stack trace and logs the 'result' and the dwBytes
        Log(result,dwBytes);

    if (pCallStackBackup)
        LhBarrierEndStackTrace(pCallStackBackup);
    return result;
}

The problem is that I get the "The caller is not inside a hook handler." error when calling the LhBarrierBeginStackTrace function in the example above. It looks like that after calling the original HeapAlloc function the LhBarrierBeginStackTrace can't obtain the 'Runtime->Current' pointer as the LhBarrierIntro's DONT_INTERCEPT part will set it to NULL. So when it returns, these functions think that they are outside the hook handler, however it is not the case.
This makes it really awkward for me to capture call stack as I would need to first Save it early to somewhere, then call the original function, then pass the saved callstack to my logger function separately. There could be other scenarios too which can be problematic I guess.

Is there a recommended workaround for this (so this behaviour is intentional), or is it a bug in easyhook?

Thanks in advance!

Error linking to easyhook32.lib

Moved from CodePlex
Originally submitted by DSridharC

Hi,

I am building an app using the EasyHook 2.7 (Beta). I get the following error when I try to build it for Win32 Platform.

fatal error LNK1107: invalid or corrupt file: cannot read at 0x2D8 <>

In my application, I am trying to link to easyhook32.lib.

Any suggestions why this happens ?

If I compile for x64 platform, it works fine.

Thanks

CodePlex comments

anroOfCode wrote May 16 at 4:20 AM
I'm seeing this too- I think the binary drop was published with the lib for static linkage.

STATUS_INTERNAL_ERROR: Unknown error in injected assembler code. (Code: 5)

I've just made a simple test with EasyHook 2.7 binaries but it did not work and threw the exception as in the question title. I tried the same with EasyHook 2.6 (of course the code is a little different because it requires registering dlls to GAC) and it worked OK.

Here is the test project I made https://drive.google.com/file/d/0B9pRIB5Qqb08STZpdXNBUkU5LWc/view?usp=sharing

I've tried both 3.5 and 4.0 binaries files and also changed the .NET Framework Target of all projects in my test variously but still not working (with the same exception).

In my test project, I try using RemoteHooking.CreateAndInject.
However when using RemoteHooking.Inject, there is not any exception but it does not seem to hook successfully. As in my test, when closing the target process, a message box should appear but it does not.

Other info: I'm using VS2012, Windows 7 Ultimate 64 bit and again the important thing is EasyHook2.6 works with almost the same code.

Could you see and let me know what's actually wrong here?

Hook CreateFile successful but hook TextOut fail

Moved from CodePlex
Originally submitted by waley_he

Hi,
When I try hook API via EasyHookDll in my C++ project, I can hook "Kernel32.dll"/CreateFileA and "Kernel32.dll"/CreateFileW successfully, but all others fail. Who can help have a look. Thanks

fail api:

"Gdi32.dll" TextOutA
"Gdi32.dll" TextOutW
"Gdi32.dll" ExtTextOutA
"Gdi32.dll" ExtTextOutW
"User32.dll" DrawTextA
"User32.dll" DrawTextW
"User32.dll" DrawTextExA
"User32.dll" DrawTextExW

code:

{ 
HMODULE hDllTextOutA = LoadLibrary("Gdi32.dll"); 
if (0 != hDllTextOutA) { 
NTSTATUS status = 0; 
hHookTextOutA = new HOOK_TRACE_INFO(); 
realTextOutA = (ptrTextOutA)GetProcAddress(hDllTextOutA, "TextOutA"); 
status = LhInstallHook(realTextOutA, MyTextOutA, 0, hHookTextOutA); 
status = LhSetExclusiveACL(HookTextOutA_ACLEntries, 1, hHookTextOutA); 
} 
};

Waley

CreateAndInject failed - Beta 2.7.5558.0

Moved from CodePlex
Originally submitted by etommVizubi

The same code that was working fine with the previous release, is crashing miserably with the last beta with the following error when starting with CreateAndInject

STATUS_INTERNAL_ERROR: Unknown error in injected assembler code.

I tryed both the source and the binary version.

Helper for hooking COM interfaces

Moved from CodePlex
Originally submitted by tleibnitz

Just FYI, a class that queries COM interfaces, so you can hook the function. Use it like this:

COMclassQuery.COMclassQuery.COMclassInfo cci = new COMclassQuery.COMclassQuery.COMclassInfo(typeof(AVRSimulatorMKIILib.SimulatorMKIIClass), typeof(AVRSimulatorMKIILib.IAvrTarget), "Run");
COMclassQuery.COMclassQuery.Query(cci);

hookSimMk2Run = EasyHook.LocalHook.Create(cci.FunctionPointer, new Delegate_SimulatorMKIIClass_IAvrTarget_Run(SimulatorMKIIClass_IAvrTarget_Run), null);
hookSimMk2Run.ThreadACL.SetExclusiveACL(new Int32[] { });

Sometimes rpcrt4.dll hijacks (puts proxies into) the vtable, so we need to go little deeper^^

See https://easyhook.codeplex.com/discussions/228910 for source

EasyHook64Drv.sys and TestDriver64.sys crash on windows 7 x64 (EasyHook 2.6)

Moved from CodePlex
Originally submitted by fishjam

  1. Download Easy Hook source code 2.6
  2. open EasyHookSys.sln with VS2008 and build for x64 Debug.
  3. copy EasyHook64Drv.sys and TestDriver64.sys to Windows 7 64Bit OS on VMWare.
  4. install EasyHook64Drv.sys with SRVINSTW.EXE and start the service.
  5. install TestDriver64.sys with SRVINSTW.EXE and start the service.
  6. then BSoD, reason is "An attempt was made to write to read-only memory". PS: I haven't changed any code.

When I check the call stack in WinDbg
a. the call stack is:

0: kd> kn
# Child-SP RetAddr Call Site
00 fffff88002ff4d98 fffff800029c36d2 nt!DbgBreakPointWithStatus
01 fffff88002ff4da0 fffff800029c4a98 nt!KiBugCheckDebugBreak+0x12
02 fffff88002ff4e00 fffff800028ce004 nt!KeBugCheck2+0xcf8
03 fffff88002ff54d0 fffff8000294cdb2 nt!KeBugCheckEx+0x104
04 fffff88002ff5510 fffff800028cbfee nt! ?? ::FNODOBFM::string'+0x4244e
05 fffff88002ff5670 fffff880039d094c nt!KiPageFault+0x16e
06 fffff88002ff5800 fffff880039d83d1 EasyHook64Drv!LhInstallHook+0x55c [f:\tools\program\driver\easyhooksourcecode26\drivershared\localhook\install.c @ 345]
07 fffff88002ff5890 fffff880039d8e3c TestDriver64!RunTestSuite+0x91 [f:\tools\program\driver\easyhooksourcecode26\examples\testdriver\testsuite.c @ 50]
08 fffff88002ff5940 fffff80002cb5477 TestDriver64!DriverEntry+0x9c [f:\tools\program\driver\easyhooksourcecode26\examples\testdriver\main.c @ 63]
09 fffff88002ff59a0 fffff80002cb5875 nt!IopLoadDriver+0xa07
0a fffff88002ff5c70 fffff800028db161 nt!IopLoadUnloadDriver+0x55
0b fffff88002ff5cb0 fffff80002b71166 nt!ExpWorkerThread+0x111
0c fffff88002ff5d40 fffff800028ac486 nt!PspSystemThreadStartup+0x5a
0d fffff88002ff5d80 00000000`00000000 nt!KxStartSystemThread+0x16

b. the error code is( instal.c, line345 ):
((ULONGLONG)(Hook->TargetProc + 0)) = AtomicCache_x64;

Please help me.
Thanks.

Comments

fishjam wrote Aug 14, 2013 at 10:41 AM

I know the reason that crash at line345.
Need enable code writable by call WPOFFx64().
The function of WPOFFx64 is:

KIRQL WPOFFx64()
{
KIRQL irql= KeRaiseIrqlToDpcLevel();
UINT64 cr0=__readcr0();
cr0 &= ~0x10000; 
__writecr0(cr0);
//_disable();
return irql;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.