need help creating a remote hook

Jul 24, 2012 at 6:00 PM

Hi.  I am new to Easyhook and hooking in general.  I am trying to create an unmanaged hook and I can not seem to get past this error "C++ completion routine has returned success but didn't raise the remote event.".  I have searched all over and I found a few references but nothing that has helped.  I have tried using RhInjectLibrary as well as RhCreateAndInject; both with the same results.

I am on a windows 7 x64 machine however my injection dll and the program I am trying to inject into are both 32 bit.

My native entry point is extremely basic right now:

extern "C" __declspec(dllexport) void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO * remoteInfo)
{
    RhWakeUpProcess();
}

And the code to create and inject the process:

    std::string libPath = "...valid path to my injection dll";
    std::string exePath = "...valid path to my exe";
    std::string cmdLine = "";

    std::wstring e(exePath.begin(), exePath.end());
    std::wstring c(cmdLine.begin(), cmdLine.end());

    ULONG pid;

    std::wstring wlibPath = std::wstring(libPath.begin(), libPath.end());
    NTSTATUS result = RhCreateAndInject((WCHAR*)e.c_str(), (WCHAR*)c.c_str(), 0, EASYHOOK_INJECT_DEFAULT, (WCHAR*)wlibPath.c_str(), NULL, NULL, 0, &pid);
    if( result!=0)
    {
        std::wstring error = RtlGetLastErrorString();
        _error = std::string(error.begin(), error.end());
        return false;
    }

Not sure what I might be missing, I appreciate any help.  Thanks!

Jul 24, 2012 at 10:16 PM

For a test I decided to create the process manually and then using the task manager I get the PID and then use RhInjectLibrary to connect to the PID directly.  I managed to get a little further, or at least the failure is different.  My reasoning was maybe the process did not have enough time to get up and running before the injection is attempted.  When I do this, I now get the error "Unknown error in injected assembler code."

I have searched for reasons behind this and everything I found seems to suggest that I need admin privileges when running the app; I then tried first to just run my app as an admin, that didn't work.  I then added a manifest with requireAdministrator as the requestedExecutionLevel to my executable, this also made no difference I still get the same error.

I have tried my injection on several different programs just to see if one of them would work but no luck.  Still scratching my head....

My injection Dll happens to be the same Dll that creates the hook, this should not matter should it?  As you can see my NativeInjectionEntryPoint does not do a whole lot.

Thanks.

Coordinator
Jul 30, 2012 at 4:06 AM

There is a task for creating a C++ example, possibly with changes to the project to provide static linking.

I don't know if any work has commenced yet - I will ask about.

Jul 30, 2012 at 5:36 PM

Well, this may be a little off topic for you since you appear to be having problems "injecting" your .dll.  Unfortunately I've never tried to "inject" a .dll from another native process.

However, as a stop gap measure to get you over this hurdle (so you can test your other code) until you can get the "injection" process you want functional, you might be able to use Window's built in mechanism for injecting .dlls via AppInit_Dlls. You can find more information about this here and here.  Its easy enough to write a batch script to modify the registry entries needed, launch your app, then restore the changed registry entries.

If you go this route there are a few things gotchas you should know about.

  • On Windows 64 bit OS's, these registry entries are for 64 bit applications
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion \Windows\AppInit_Dlls
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion \Windows\LoadAppInit_Dlls
  • On Windows 64 bit OS's, these registry entries are for 32 bit applications
    HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion \Windows\AppInit_Dlls
    HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion \Windows\LoadAppInit_Dlls
  • Be very careful what you put in DllMain(), it is very restrictive what can be done in this routine because it occurs during early loading.  I've found that you can create a thread (even though its not recommend) and threads will NOT start until after early loading so you can code in relative safety within that thread.  Microsoft Best Proactices for Creating DLLs
  • Be sure to remove your registry entries unless you intend to hook every process on the machine because that's what will happen :D

This is really a temporary alternate solution for you i suppose, so sorry if this is not helpful to you.

Jul 30, 2012 at 5:58 PM

Hi Ultratrunks,

Thanks for the reply.  As of right now I do not have any other code to test, I figure I would start writing that once I was able to get the hook working and since your suggesting the method above is a temporary solution I would probably rather avoid it, sounds dangerous as well if my process crashes and the registry entries do not get reverted properly. :)

Now I am thinking to get around this is to do the hook with C# and have that call into my native libraries and just use C# as glue code but I was hoping to avoid the performance hit with this route.

Maybe it is time to get the full source and step through and compare my c hook with the c# hook example.

Thanks again, if you can think of anything else let me know.

Aug 1, 2012 at 4:49 PM

I have been following the C# code and comparing to my C++ code.  As a test I tried to modify the ProcessMonitor to inject my dll instead of ProcMonInject.dll and I came across something that is unclear to me.  In Form1.cs there is this call when you check the process you want to be monitored:

 

RemoteHooking.Inject(
    PID,
    (_noGAC ? InjectionOptions.DoNotRequireStrongName : InjectionOptions.Default), // if not using GAC allow assembly without strong name
    System.IO.Path.Combine(System.IO.Path.GetDirectoryName(typeof(DemoInterface).Assembly.Location), "ProcMonInject.dll"), // 32-bit version (the same because AnyCPU)
    System.IO.Path.Combine(System.IO.Path.GetDirectoryName(typeof(DemoInterface).Assembly.Location), "ProcMonInject.dll"), //"ProcMonInject.dll", // 64-bit version (the same because AnyCPU)
    // the optional parameter list...
    ChannelName);

 

And within RemoteHooking.Inject it calls InjectEx which will then call NativeAPI.RhInjectLibraryEx like so:

 

NtStatus = NativeAPI.RhInjectLibraryEx(
    InTargetPID,
    InWakeUpTID,
    NativeAPI.EASYHOOK_INJECT_MANAGED | InNativeOptions,
    typeof(Config).Assembly.Location,
    typeof(Config).Assembly.Location,
    hPassThru.AddrOfPinnedObject(),
    (int)PassThru.Length))

 

Here I was expecting to see ProcMonInject.dll as the file being passed for the user library at typeof(Config).Assembly.Location, but instead this actually points to EasyHook.dll.  Should I be using the EasyHook.dll in my native code to pass into RhInjectLibrary ? If so, where do I inject my native library?  

Thanks!

Coordinator
Aug 5, 2012 at 1:38 AM

The managed injection uses a helper wrapper to facilitate the loading of a managed assembly and passing parameters, along with IPC context. This is why you see the EasyHook.dll being passed in.

For unmanaged you will not want to do this, instead you will want to pass NativeAPI.EASYHOOK_INJECT_DEFAULT without the MANAGED flag, and the native DLL you would like to inject.

Your injected native DLL must have a REMOTE_ENTRY_POINT exported as "NativeInjectionEntryPoint". Take a look at easyhook.h for the signature of that export.

Aug 9, 2012 at 4:58 PM

Ok, I have managed to create a hook finally.. or at least I can now load my DLL where the NativeInjectionEntryPoint gets called now.  I had everything set up correctly however EasyHook does not seem to like it if my NativeInjectionEntryPoint is in the same dll that is calling RhInjectLibrary.  I am not sure if this is the actual cause or if it is something else about that dll it does not like.  I ended up creating a new DLL for the injection with then NativeInjectionEntryPoint and little else, within this function I open a file and write some text out just to verify everything is working, and it is!

Any ideas as to why I am unable to use the same DLL to call RhInjectLibrary using itself as the injection library?

Either way I am happy to be making some progress!

Thanks!

Aug 12, 2012 at 8:39 PM

It seems when I try to load another DLL of mine within the NativeInjectionEntryPoint then my hook fails, if I do not load it then everything is OK.  Are there any rules or guidelines about using other DLL's within your injected library?

Aug 13, 2012 at 3:33 AM

Finally, everything is working.  What a journey.  Turns out you can load other DLL's just fine, for some reason one of the DLL's my DLL was using was not loading properly - once I fixed this my DLL loaded within the injection point no problem! Easyhook is a slick library, thanks!!