Hooking application specific functions

Nov 21, 2008 at 10:14 PM
Edited Nov 21, 2008 at 10:15 PM
Can this be used to hook application specific functions? Like if I wrote a program with a function Add(int x, int y) { return x + y; } could it be hooked using EasyHook provided I disassembled and got the address of the function?

I'm asking because I would like to use this to hook functions in games and either rewrite the functions, or modify parameters and pass it back to original function.

This may be asking a little much, but could you write a more simplified example than the FileMon? Something really simple, like just popping up a messagebox when the about box is opened in minesweeper or something.

Thanks in advanced,
Kalagaraz
Nov 22, 2008 at 12:19 AM
You should read the tutorial first because it seems as if you have no clue what easyhook is doing...

But yes you can do this of course...

FileMon is the simplest example I can imagine. It simply makes no sense to hook your own process. You will find this for testing purposes in the Solution Test Project. The moment you are hooking other processes (which is the only useful thing I can imagine) FileMon is the simplest example..

regards
chris
Nov 22, 2008 at 1:48 AM
Edited Nov 22, 2008 at 1:54 AM
Right. I went through the FileMon example, and I understand what's going on, but not how to adapt this to my test I'm trying to do (Hook the StartAboutDialog function in minesweeper)

first off there is this:

LocalHook.GetProcAddress("kernel32.dll", "CreateFileW")
This obviously won't work when hooking minesweeper, so how do I identify the process address?
IDA Pro tells me this about the function:

.text:0101FED4 ; public: static void __stdcall UIDialogs::StartAboutDialog(void)

So will this work: IntPtr StartAboutDialogAddress = (IntPtr)0x0101FED4;  ?

Second part I'm confused at:

        // just use a P-Invoke implementation to get native API access from C# (this step is not necessary for C++.NET)
        [DllImport("kernel32.dll",
            CharSet = CharSet.Unicode,
            SetLastError = true,
            CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr CreateFile(
            String InFileName,
            UInt32 InDesiredAccess,
            UInt32 InShareMode,
            IntPtr InSecurityAttributes,
            UInt32 InCreationDisposition,
            UInt32 InFlagsAndAttributes,
            IntPtr InTemplateFile);

Now I'm trying to hook MineSweeper.exe, so how do I convert the above to the StartAboutDialog function?

Thanks for quick reply,
Kalagaraz



Nov 22, 2008 at 8:55 AM
Soryy, but try to find out yourself. I am not really sure how much experiences you have with windows programming but as far as I can see you are no very familiar with most of the concepts necessary for API hooking. It makes no sense to post you the answer, because if you can't answer this basic questions yourself you will immediately be stuck with new problems you can't solve. Hooking is advanced stuff even if you use libraries like EasyHook...

My advise is to learn more about the windows API and come back later...

regards
chris
Nov 22, 2008 at 11:59 AM
Right, so basically you expect me to study how to build a house so I can construct a shed in my backyard? I don't see the need to learn the entire underlying concepts of the windows API just so I can hook a function.

In detours this was just a simple CreateTrampoline() call...and I was hoping I could do something similar in C# since hate I programming in C++.
Nov 22, 2008 at 12:30 PM
No, but the problem you mentioned has nothing to do with EasyHook. You have to construct a delegate for the target method just like you need to declare the method you are hooking in detours. But this is all stated in the tutorial so I would only recitate... If you want to know how to convert the mentioned above thing to hook your desired method you should look for P-Invoke implementations in the net and try to understand how this NET mechanism is working in order to do it yourself...

Understanding how the API works is essential to hook it. It's like wanting to catch a fish without knowing what a fish actually is... It might work but you will run into serious problems if something doesn't go the way you expect... Even if someone is giving you the right fishing rod...
Nov 22, 2008 at 10:31 PM
Edited Nov 22, 2008 at 11:14 PM
alright well before I spend months of my life trying to figure out how to do this stuff on my own, let me make sure what I'm trying to do is possible using EasyHook and managed code.

I want to hook functions that have most likely NOT been exported (declared with extern or whatever) and generally do NOT have function names to which to provide to DLLImport. The only way to identify these functions is with their entry point address and parameters. They have no names. Example functions would be say the function/functions used to make your character jump in a video game or something.

In Detours, I would do DetourFunction((PBYTE)EntryPointAddress, (PBYTE)MyFunction) to hook those functions.

Are these types of functions hookable in EasyHook using managed code?
Nov 23, 2008 at 8:47 AM
If you get the entry point address yourself, they are of course hookable... Instead of using LocalHook.GetProcAddress() you would pass (IntPtr)0x12345678 to LocalHook.Create()...

regards
chris
Nov 23, 2008 at 7:40 PM
Edited Nov 23, 2008 at 7:45 PM
Right that's what I was doing. But I didn't know how to call the original function. But I think I figured that out now...

        IntPtr StartAboutProcAddress = (IntPtr)0x0101FED4;


        [UnmanagedFunctionPointer(CallingConvention.StdCall,
            CharSet = CharSet.Auto,
        SetLastError = true)]
        delegate void DStartAboutDialog();

        DStartAboutDialog OriginalFunction;

        public Main(RemoteHooking.IContext Context, string ChannelName)
        {
            OriginalFunction = (DStartAboutDialog)Marshal.GetDelegateForFunctionPointer(StartAboutProcAddress, typeof(DStartAboutDialog));
            Interface = RemoteHooking.IpcConnectClient<MinesweeperInterface>(ChannelName);
            
            Interface.Ping();
        }

        public void Run(RemoteHooking.IContext Context, string ChannelName)
        {
            try
            {
                 
                StartAboutHook = LocalHook.Create(StartAboutProcAddress,
                    new DStartAboutDialog(StartAboutDialog_Hooked), this);

                StartAboutHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
            }
            catch(Exception info)
            {
                Interface.ReportException(info);
            }

            Interface.IsInstalled(RemoteHooking.GetCurrentProcessId());

            RemoteHooking.WakeUpProcess();

            try
            {
                while (true)
                {
                    Thread.Sleep(500);
                    Interface.Ping();
                }
            }
            catch
            {
                // Ping() will raise an exception if host is unreachable
            }
        }

        static void StartAboutDialog_Hooked()
        {
            
            //Main This = (Main)HookRuntimeInfo.Callback;

            
            //This.OriginalFunction();

            //Crashes with or without the above lines.
        }
    }

That look about right? Creating the hook though always crashes Minesweeper with no error message even if my hook does nothing (or simply calls original function). So not sure whats going on. I know I have the right entry point for the start about dialog. StartAboutDialog has no parameters and returns void, so those are right too. It also crashes right when I inject it, so can never test the hook. If I comment out the lines to create the hook, it works find, will report that it's been installed.


Nov 23, 2008 at 8:34 PM
[UnmanagedFunctionPointer(CallingConvention.StdCall,
            CharSet = CharSet.Auto,
        SetLastError = true)]
        delegate void DStartAboutDialog();


Are you sure that's the right signature for StartAboutDialog?  If you don't have the signature exactly right, that would certainly cause a crash.


Nov 23, 2008 at 8:59 PM
This is the dissassembled code, void return, void arguments.

.text:0101FED4 ; public: static void __stdcall UIDialogs::StartAboutDialog(void)
.text:0101FED4 ?StartAboutDialog@UIDialogs@@SGXXZ proc near
.text:0101FED4                                         ; CODE XREF: sub_101A97D:loc_101A9E3p
.text:0101FED4                 push    18h
.text:0101FED6                 mov     eax, offset loc_106AFD9
.text:0101FEDB                 call    __EH_prolog3
.text:0101FEE0                 mov     ecx, ?g_pRenderManager@@3PAVRenderManager@@A ; RenderManager * g_pRenderManager
.text:0101FEE6                 push    1
.text:0101FEE8                 call    ?Render@RenderManager@@QAEX_N@Z ; RenderManager::Render(bool)
.text:0101FEED                 cmp     ?g_Flowerbed@@3_NA, 0 ; bool g_Flowerbed
.text:0101FEF4                 jz      short loc_101FEFA
.text:0101FEF6                 push    6Fh
.text:0101FEF8                 jmp     short loc_101FEFC
.text:0101FEFA ; ---------------------------------------------------------------------------
.text:0101FEFA
.text:0101FEFA loc_101FEFA:                            ; CODE XREF: UIDialogs::StartAboutDialog(void)+20j
.text:0101FEFA                 push    6Eh             ; lpIconName
.text:0101FEFC
.text:0101FEFC loc_101FEFC:                            ; CODE XREF: UIDialogs::StartAboutDialog(void)+24j
.text:0101FEFC                 push    ?g_hInstance@@3PAUHINSTANCE__@@A ; hInstance
.text:0101FF02                 call    ds:__imp__LoadIconW@8 ; LoadIconW(x,x)
.text:0101FF08                 mov     edi, eax
.text:0101FF0A                 call    ?StopAllSounds@GameAudio@@YGXXZ ; GameAudio::StopAllSounds(void)
.text:0101FF0F                 push    6Ch             ; uID
.text:0101FF11                 lea     ecx, [ebp-24h]  ; int
.text:0101FF14                 call    ??0Str@@QAE@I@Z ; Str::Str(uint)
.text:0101FF19                 mov     esi, eax
.text:0101FF1B                 and     dword ptr [ebp-4], 0
.text:0101FF1F                 push    66h             ; uID
.text:0101FF21                 lea     ecx, [ebp-18h]  ; int
.text:0101FF24                 call    ??0Str@@QAE@I@Z ; Str::Str(uint)
.text:0101FF29                 mov     esi, [esi+8]
.text:0101FF2C                 mov     eax, [eax+8]
.text:0101FF2F                 push    edi             ; hIcon
.text:0101FF30                 push    esi             ; szOtherStuff
.text:0101FF31                 push    eax             ; szApp
.text:0101FF32                 push    ?g_hWnd@@3PAUHWND__@@A ; hWnd
.text:0101FF38                 call    ds:__imp__ShellAboutW@16 ; Display a Shell About dialog box
.text:0101FF3E                 lea     ecx, [ebp-18h]
.text:0101FF41                 call    ??1Str@@QAE@XZ  ; Str::~Str(void)
.text:0101FF46                 or      dword ptr [ebp-4], 0FFFFFFFFh
.text:0101FF4A                 lea     ecx, [ebp-24h]
.text:0101FF4D                 call    ??1Str@@QAE@XZ  ; Str::~Str(void)
.text:0101FF52                 call    ?Engine_ResetTimer@@YGXXZ ; Engine_ResetTimer(void)
.text:0101FF57                 call    __EH_epilog3
.text:0101FF5C                 retn
.text:0101FF5C ?StartAboutDialog@UIDialogs@@SGXXZ endp ; sp = -4

Nov 23, 2008 at 11:16 PM
I'd like to apologize for the above posted problem. This was a problem with my crappy reverse engineering skills. I started to doubt the address given by IDA Pro so I decided to run it in debug mode in IDA and set a breakpoint at that address, when it hit that breakpoint, it was at at completely different address! (0x00CAFED4). I tried this new address and it worked. I'm not sure why the address changed, might be something to do with it being a function member of UIDialogs.
Nov 24, 2008 at 6:48 AM
whole program optimizations can cause internal (unexported) functions to make assumptions about the caller. a hook won't provide these assumptions in general. that is why you should only hook public APIs.

but okay... the next fact is that function are addresses are far away for being stable. each update can cause them to change and also random address mapping (a feature against various security leaks) can cause all static addresses to be remapped at every application start.