2

I've downloaded and compiled the Microsoft detouring library. Inside my project I've included the header file and added the .lib file as a dependency. Everything compiles without errors. Now I've been trying to detour DrawText, but for some reason that detoured function doesn't get called at all. Similiarly I tried detouring the Sleep function and that worked as intended and the function I detoured to was called.

I'm not very well-versed in the business of API programming nor any other low level activities. I suspect it might have something to do with the fact that I'm trying to do this inside a console application instead of having the detouring done inside a DLL. I just find it strange that it would be able to detour Sleep in that case.

Is there something wrong with my approach or does the fault lie in the code?

#include <windows.h>
#include <stdio.h>
#include "detours.h"

int ( WINAPI *Real_DrawText )(HDC a0, LPCSTR a1, int a2, LPRECT a3, UINT a4) = DrawTextA;

int Mine_DrawText(HDC hdc, LPCSTR text,  int nCount, LPRECT lpRect, UINT uOptions)
{
   printf("TEST");
   return Real_DrawText(hdc, text, nCount, lpRect, uOptions);
}

int main(int argc, char **argv)
{
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)Real_DrawText, Mine_DrawText);
    DetourTransactionCommit();
    printf("Calling Sleep\n");
    Sleep(1000);
    printf("Second callout");
    Sleep(5000);

    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourDetach(&(PVOID&)Real_DrawText, Mine_DrawText);
    DetourTransactionCommit();
    return 0;
}
Kasper Holdum
  • 12,993
  • 6
  • 45
  • 74
  • In main you are calling Sleep instead of DrawTextA, is this just a copy/paste error or this is a real example you have used? – Cristian Adam Sep 09 '09 at 18:21
  • If I call DrawTextA myself instead of sleep then my routed function is called in place of the function. I'm interested in having this happen globally or in another window at least. I was hoping there was a another way than injecting my library into the application. – Kasper Holdum Sep 09 '09 at 18:36

3 Answers3

1

Based on your code-example, it seems you're only detouring your own process. Therefore detouring DrawText doesn't output anything. Perhaps, you need to inject your code to desired target's process memory and detour the API call from there. For example, you can create system wide CBT hook which works kind of a.. launch point to your detouring needs. Something like this, to point you out a direction:

LRESULT CALLBACK CBTProcedure(int nCode, WPARAM wParam, LPARAM lParam)
{
        if (nCode < 0)
                return CallNextHookEx(g_hHook, nCode, wParam, lParam);
        else if (!g_pClient)
                return 0;

        HWND hWnd = (HWND)wParam;

        if (!hWnd)
                return 0;

        switch (nCode) {
                case HCBT_ACTIVATE:
                        /** Here, you can check up against the handle to see,
                          * if the target window is the one you're looking for...
                          *
                          */
                        if (!g_pClient->IsRegisteredWindow(hWnd))
                                if (g_pClient->RegisterWindow(hWnd)) {
                                }

                break;

                case HCBT_DESTROYWND:
                        if (g_pClient->IsRegisteredWindow(hWnd))
                                g_pClient->UnregisterWindow(hWnd);

                break;
        }

        return 0;
}

bool __0XYOUROWN_API InstallHook()
{
        // Call this one from your main process; set's up the system-wide hook.

        g_hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC)CBTProcedure, g_hInstance, 0);

        /** #pragma data_seg("Shared")
          *         HHOOK g_hHook = NULL;
          * #pragma data_seg()
          */

        return g_hHook != NULL;
}

/** The actual DLL...
  *
  *
  */
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
        switch (ul_reason_for_call) {
                case DLL_PROCESS_ATTACH:
                        g_hInstance = (HINSTANCE)hModule;

                        if (::GetModuleHandle(_T("THEDESIREDMODULE.EXE")) != NULL) {
                                g_pClient = new Client();

                                if (g_pClient) {
                                        InitializeCriticalSection(&g_CriticalSection); // You can setup a critic. sec. for later synchronization...
                                        DetourTransactionBegin();
                                        DetourUpdateThread(GetCurrentThread());
                                        DetourAttach(&(PVOID&)Real_DrawTextW, Mine_DrawTextW);
                                        DetourTransactionCommit();
                                }
                        }

                break;

                case DLL_THREAD_ATTACH: break;

                case DLL_THREAD_DETACH: break;

                case DLL_PROCESS_DETACH:
                        if (::GetModuleHandle(_T("THEDESIREDMODULE.EXE")) != NULL) {
                                if (g_pClient) {
                                        DetourTransactionBegin(); 
                                        DetourUpdateThread(GetCurrentThread());
                                        DetourDetach(&(PVOID&)Real_DrawTextW, Mine_DrawTextW);
                                        DetourTransactionCommit();

                                        delete g_pClient;

                                        g_pClient = NULL;
                                }
                        }

                break;
        }
}
nhaa123
  • 9,570
  • 11
  • 42
  • 63
  • If that was the case, wouldnt my detoured function still be called to draw the text of the console window? The problem is that DllMain seemes to be declared both in my own project but also in 'detour.lib' which causes an error. – Kasper Holdum Sep 09 '09 at 18:20
  • Please look MSalters' answer. – nhaa123 Sep 18 '09 at 06:53
  • You're ultimatively correct. Detouring only happens within the program of injection which means I'll have to inject into virtually everything until I find the program of choice. You code looks pretty copy pasted by the way – Kasper Holdum Sep 19 '09 at 21:18
  • Oh yes, the sample is from one of my current projects. – nhaa123 Nov 03 '09 at 14:50
1

It seems you're assuming printf() will call DrawText(). It won't. DrawText() is a GDI function. printf() goes to WriteConsole(). These don't intermix. "Console Windows" are quite unlike all other windows. This distinction is a fundamental architectural one; they're even managed by separate kernel components.

MSalters
  • 173,980
  • 10
  • 155
  • 350
1

Only a side note: EasyHook - The reinvention of Windows API Hooking is an open source (LGPL) project developing a successor to Detours. It is quite mature already.

MaD70
  • 4,078
  • 1
  • 25
  • 20