Hooked Function Parameter is Truncated

May 1, 2010 at 3:56 PM
Edited May 1, 2010 at 11:52 PM
FYI, development system:
WinXP 32-bit SP3, Visual Studio Pro 2008, C#
(Problem is the same under Win7 64-bit)

Hi All,

I'm trying to hook RegQueryValueExW from Advapi32.dll and although the hook seems to work ok (as in my code gets executed instead), the parameters don't seem to have been passed correctly: I only get the first character of a string. For example, if I hook the function with a parameter of "AppData", only "A" is passed to my function.

Code snippet:

        delegate int DMyRegQueryValueEx(
            UIntPtr hKey,
            string lpValueName,
            int lpReserved,
            out uint lpType,
            StringBuilder lpData,
            ref uint lpcbData);

        int MyRegQueryValueEx(
            UIntPtr hKey,
            string lpValueName,
            int lpReserved,
            out uint lpType,
            StringBuilder lpData,
            ref uint lpcbData)
        {
            MessageBox.Show(string.Format("Hooked: {0}", lpValueName));
            lpType = 1; // I know this line and the one below aren't right, but it's just for testing.
            return 0;
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            RegistryKey rk = Registry.CurrentUser;
            rk = rk.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");

            LocalHook localHook = LocalHook.Create(
                LocalHook.GetProcAddress("Advapi32.dll", "RegQueryValueExW"),
                new DMyRegQueryValueEx(MyRegQueryValueEx),
                this);

            localHook.ThreadACL.SetInclusiveACL(new int[] { 0 });            

            rk.GetValue("AppData");            
        }

I appreciate I've probably messed something up, but I've read through the Tutorial/Introduction and looked at some examples but I can't see it!

Any pointers would be greatly appreciated!

May 1, 2010 at 11:50 PM
Edited May 1, 2010 at 11:54 PM
Well, I've made some progress. I hadn't appreciated that I needed to declare the delegate function as Unmanaged code. Delegate definition now reads:
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        delegate int DMyRegQueryValueExW(
            UIntPtr hKey,
            string lpValueName,
            int lpReserved,
            out uint lpType,
            StringBuilder lpData,
            ref uint lpcbData);

So now my problem is that the StringBuilder (lpData) which holds the returned data seems to have a Capacity of 0 which means an exception occurs when the function tries sticking data into it. If I overwrite the StringBuilder with a new StringBuilder with a better capacity (e.g. 1024) the hooked function returns with an empty string - presumably because my new StringBuilder is not in the same memory location as the unmanaged code expects.

Oh, and if I try changing the capacity, I get an exception too as the MaximumCapacity is also 0 (which is a read-only attribute).

May 2, 2010 at 9:42 AM

Argh, this is killing me! Hooking function is:

int MyRegQueryValueExW(
            UIntPtr hKey,
            string lpValueName,
            int lpReserved,
            out uint lpType,
            StringBuilder lpData,
            ref uint lpcbData)
        {
            return RegQueryValueExW(hKey, lpValueName, lpReserved, out lpType, lpData, ref lpcbData);
        }
The function seems to get called twice. The first time it appears to just find the length of the string to be read from the Registry and the second time it does the actual reading. On the second time through however is when the annoying Exception mentioned in the previous post occurs. Anybody got any ideas? I'm guessing the type of lpData is probably wrong but I can't get it to work.
May 20, 2010 at 5:53 AM

I'm trying to use this one too except it doesnt appear to like my RegOpenKeyExW in Advapi32.dll???

May 20, 2010 at 9:56 AM
Edited May 20, 2010 at 9:57 AM

I did manage to get it working in the end - it's all about the correct data types. Mine should've been:

int MyRegQueryValueExW(
	UIntPtr hKey,
	string lpValueName,
        int lpReserved,
        out uint lpType,
        IntPtr lpData,
        ref uint lpcbData)
       	{
	...
        }

This code should work for RegOpenKeyExW though...

#region RegOpenKeyExW Hook
        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        static extern int RegOpenKeyExW(
            UIntPtr hKey,
            string subKey,
            int ulOptions,
            int samDesired,
            out UIntPtr hkResult);

        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        delegate int DMyRegOpenKeyExW(
            UIntPtr hKey,
            string subKey,
            int ulOptions,
            int samDesired,
            out UIntPtr hkResult);

        int MyRegOpenKeyExW(
            UIntPtr hKey,
            string subKey,
            int ulOptions,
            int samDesired,
            out UIntPtr hkResult)
        {
            Console.WriteLine(string.Format("Accessing: {0}", subKey));
            return RegOpenKeyExW(hKey,subKey,ulOptions,samDesired,out hkResult);
        }
        #endregion

...and for the hook...

LocalHook localHook = LocalHook.Create(
                LocalHook.GetProcAddress("Advapi32.dll", "RegOpenKeyExW"),
                new DMyRegOpenKeyExW(MyRegOpenKeyExW),
                this);

            localHook.ThreadACL.SetExclusiveACL(new int[] { });
May 20, 2010 at 6:09 PM
Edited May 20, 2010 at 7:54 PM

I'm using your code but i get this error:

The target process has reported an error

System.MissingMethodException: The given method does not exist.

at EasyHook.LocalHook.GetProcAddress(String InModule, String InSymbolNname)

I don't get this as CreateFileW worked fine and gave me all file accesses? Im on same setup as you with VS2010

I've put my code below:

May 20, 2010 at 6:49 PM
Edited May 21, 2010 at 1:42 AM

 

   

public class Main : EasyHook.IEntryPoint
    {
        FileMon.FileMonInterface Interface;
        LocalHook localHook;
        Stack<String> Queue = new Stack<String>();

        public Main(RemoteHooking.IContext InContext,String InChannelName)
        {
            // connect to host...
            Interface = RemoteHooking.IpcConnectClient<FileMon.FileMonInterface>(InChannelName);
            Interface.Ping();
        }

        public void Run(RemoteHooking.IContext InContext,String InChannelName)
        {
            // install hook...
            try
            {
                localHook = LocalHook.Create(LocalHook.GetProcAddress("Advapi32.dll", "RegOpenKeyExW"),new DMyRegOpenKeyExW(MyRegOpenKeyExW),this);

                localHook.ThreadACL.SetExclusiveACL(new int[] { });
            }
            catch (Exception ExtInfo)
            {
                Interface.ReportException(ExtInfo);
                return;
            }
            Interface.IsInstalled(RemoteHooking.GetCurrentProcessId());
            RemoteHooking.WakeUpProcess();
            // wait for host process termination...
            try
            {
                while (true)
                {
                    Thread.Sleep(500);
                    // transmit newly monitored file accesses...
                    if (Queue.Count > 0)
                    {
                        String[] Package = null;
                        lock (Queue)
                        {
                            Package = Queue.ToArray();
                            Queue.Clear();
                        }
                        Interface.OnCreateFile(RemoteHooking.GetCurrentProcessId(), Package);
                    }
                    else
                        Interface.Ping();
                }
            }
            catch
            {
                // Ping() will raise an exception if host is unreachable
            }
        }

        [DllImport("Advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        static extern int RegOpenKeyExW(UIntPtr hKey,string subKey,int ulOptions,int samDesired,out UIntPtr hkResult);

        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        delegate int DMyRegOpenKeyExW(UIntPtr hKey,string subKey,int ulOptions,int samDesired,out UIntPtr hkResult);

        int MyRegOpenKeyExW(UIntPtr hKey,string subKey,int ulOptions,int samDesired,out UIntPtr hkResult)
        {
            try
            {
                Main This = (Main)HookRuntimeInfo.Callback;
                lock (This.Queue)
                {
                    This.Queue.Push("[" + RemoteHooking.GetCurrentProcessId() + ":" + RemoteHooking.GetCurrentThreadId() +  "]: \"" + hKey + "\"");
                   
                }
            }
            catch
            {
            }
	return RegOpenKeyExW(hKey, subKey, ulOptions, samDesired, out hkResult);
        }

    }

 

May 21, 2010 at 8:53 AM

Hmm, I have to say that I can't see what's wrong with your code.

Below is all the code from a Form1.cs - it demonstrates hooking RegOpenKeyExW...

I started a new project in Visual Studio 2008, added the reference to EasyHook (EasyHook.dll and EasyHook32.dll in the 'debug' folder), and added a toolstrip with two buttons to the form.

The error you've got seems to suggest it can't find the function "RegOpenKeyExW" in 'Advapi32.dll'... which is weird.

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using EasyHook;
using System.Runtime.InteropServices;
using Microsoft.Win32;

namespace EasyHookExample
{
    public partial class Form1 : Form
    {
        #region RegOpenKeyExW Hook
        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        static extern int RegOpenKeyExW(
            UIntPtr hKey,
            string subKey,
            int ulOptions,
            int samDesired,
            out UIntPtr hkResult);

        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        delegate int DMyRegOpenKeyExW(
            UIntPtr hKey,
            string subKey,
            int ulOptions,
            int samDesired,
            out UIntPtr hkResult);

        int MyRegOpenKeyExW(
            UIntPtr hKey,
            string subKey,
            int ulOptions,
            int samDesired,
            out UIntPtr hkResult)
        {
            richTextBox1.AppendText(string.Format("Accessing: {0}{1}", subKey, Environment.NewLine));
            return RegOpenKeyExW(hKey, subKey, ulOptions, samDesired, out hkResult);
        }
        #endregion

        public Form1()
        {
            InitializeComponent();
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            LocalHook localHook = LocalHook.Create(
                LocalHook.GetProcAddress("Advapi32.dll", "RegOpenKeyExW"),
                new DMyRegOpenKeyExW(MyRegOpenKeyExW),
                this);

            localHook.ThreadACL.SetExclusiveACL(new int[] { });
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            RegistryKey rk = Registry.LocalMachine;
            rk = rk.OpenSubKey(@"SOFTWARE\Microsoft\MediaPlayer\PlayerUpgrade");
            richTextBox1.AppendText(string.Format("MediaPlayer Version: {0}{1}", rk.GetValue("PlayerVersion"), Environment.NewLine));

            rk = Registry.LocalMachine;
            rk = rk.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            richTextBox1.AppendText(string.Format("Windows Product: {0}{1}", rk.GetValue("ProductName"), Environment.NewLine));
        }
    }
}

May 21, 2010 at 10:12 AM

Sorry to sound a complete arse, can you run me through how to test the above? Is that for the class library and i should keep the filemon example to test it?

Or is that code above a complete example? I popped it in a Windows Form Application project, tried building and it needed a .exe

Sorry about this, i REALLY appreciate you helping me as i really need to get this done :)

May 21, 2010 at 10:28 AM
Edited May 22, 2010 at 9:37 AM

No probs... let's give it a whirl...

  1. Fire up Visual Studio 2008.
  2. Create a new 'Windows Forms Application' called 'EasyHookExample'.
  3. Add a 'Toolstrip' control to the form.
  4. Add 2 'Button' controls to the Toolstrip control you've just added.
  5. Add a RichTextBox to the form.
  6. Hit F7 to go into code view.
  7. Delete all the existing code.
  8. Paste in its place the code from the above post.
  9. In the 'Events' for toolStripButton1, associate the 'Click' event with toolStripButton1_Click.
  10. In the 'Events' for toolStripButton2, associate the 'Click' event with toolStripButton2_Click.
  11. Hit F5 to run.
  12. Use the button to read data from the Registry. With the hook enabled, you should see the message when the registry keys are accessed.

Good luck!

May 21, 2010 at 3:33 PM
Edited May 21, 2010 at 11:00 PM

<deleted>

May 21, 2010 at 5:36 PM
Edited May 21, 2010 at 11:02 PM

Bridgey! I found out what the problem on my original code was! Ive got 2x Administrator accounts, it HAS to be the first adminstrator account and not AN administrator account!

Im faily certain this is starting to screw up my OS, not permanently, but if i do a check for registry keys either i wanna loop through all processes and it cant do all of them, or if i select explorer.exe a few seconds later my OS crashes.....

Are you using just the one reg function? Which processes are you passing through?

 

Is there a way you dont have to explicity pass a process ID?

May 22, 2010 at 9:33 AM
Edited May 22, 2010 at 9:42 AM

Right, it sounds like weird sh*t is happening. The project I generated for you I also tested on WinXP, 32-bit, SP3, logged in as AN administrator account but NOT the FIRST administrator account.
I can't think of any good reason why you'd need to be logged in as the first administrator account.

In your PM to me you said that after restarting your laptop the same code didn't work - also weird - and no, I haven't experienced anything like that. The 'EasyHookExample' project above - did you get it working?
I've added a couple more steps to the post above to make it a bit clearer

That really is a simply example. I really would try and get that working and understand how it works before progressing to anything much more complicated. That same code works for me on: Visual Studio 2008 on XP/SP3/32-bit and Visual Studio 2010 on Win7/64-bit*.

Am I right in saying you're developing in Visual Studio 2008, on WinXP 32-bit SP3?
Just so when I prepare stuff for you I get it right.

If you PM me your email address I'll try send over some projects/exes that you can test.
I'd like to keep the discussion going on this thread rather than PMs so that they're available later and for other people.

* Actually, that's not strictly true... only some registry queries are hooked on Win7/64-bit, some seem to be missed - fine in XP/Vista though. Any ideas anybody?

May 22, 2010 at 4:32 PM

Ive got 2x setups. One is XP32 SP3 VS2010 and the other is XP64 VS2010. I do have VS2008 on the XP32 and I can also put it on the XP64 if you wish?

Here is a summary of events:

-The filemoninject .dll file appears not to update with successive builds.  I posted on stackoverflow and it turns out sometimes .dll files can play up like this as windows loads the old version :s

-The code compiles on XP32 and XP64 fine

-On XP64 the code works, but i ALWAYS have to ignore a 'EasyHook32svc has encountered a problem and needs to close.....' message. If someone could help me get rid of this then ive got no issues on XP64 except for the .dll updating.

-On XP64 i managed to get RegOpen and RegQuery working

-On XP64 it seems more consistent, if i restart the laptop i still get the same functionality from the code.

-On XP32 things seem even more random. At one point it was alternatively flipping between working and saying something about GAC  and create? When i say alternative i mean if i pressed f5 it would show the errort message, then on the next f5 it would run fine, then the next f5 it would show the same error message etc.

-On XP32 earlier in the evening i got RegOpen, RegDelete compiling i would run them and get output. Then I wrote a function to take the RemoteHooking.getProcessID integer and return the actual process name. I put this in the hook function at the bottom and suddenly i wasn't getting output (but wear in mind I was having delayed .dll issues).

I'm just writing this on the XP64, ive turned on the XP32. Last night i left it working, but it was not outputting from the hooks (and this was weird because that only happened suddenly, earlier on in the evening it was outputting.

I also have a feeling VS2010 could be screwing up here. At one point last night on the XP32 i had both FileMon and FileMonInject open. I did NOT copy and paste any code across. When i closed them and later re-opened them the code from FileMonInject was in the FileMon program.cs !!!!

To conclude, on the XP32 its getting to the point where when it works perfectly i have little faith that if i restart the OS, i will get the same results as present.

Shall we concentrate on eliminating problems using VS2008? I'll pm you my email address, you can zip me up projects which you know work and i can inform you of my results.

Also, if someone could tell me how to get rid of the XP64 EasyHooksvc32 error message that would give me a short-term solution at the moment :)

May 22, 2010 at 9:05 PM

Update:

The .dll editing taking ages appears to be due to VS2010. I'm using VS2008 and the changes are happening straight away if i have closed the process. Jeremy on these boards told me about the hook only changing once you've closed the process. This didn't fit in with my experience because i restarted my computing whilst using VS2010 and still had problems so perhaps its a combination.

Im just about to progress and modify my VS2008 project to the same as i had with VS2010 and see if it runs better.

May 23, 2010 at 2:38 AM

Update:

The reason it wasnt working on XP32 was (strangely) because i edited what was added to the Queue in the hook function. I took away the "[" etc and put it in my own format. I think the exact problem was that i passed RemoteHooking.getProcessID into a function which returned the name of the process. I cant understand why this isnt allowed, but anyway- ive now implemented this in the function which receives the items in FileMon.

Can anyone give me some advice how to get this working on XP64, that would really be fab :)

May 23, 2010 at 11:17 AM
Awesome that you solved it! Can't help with the 64bit version I'm afraid.