stevemk14ebr / PolyHook

x86/x64 C++ Hooking Library
MIT License
886 stars 172 forks source link

IAT Hooking doesn't work #8

Closed TheAifam5 closed 8 years ago

TheAifam5 commented 8 years ago
iat_hook_createmutex->SetupHook("kernel32.dll", "CreateMutexA", (BYTE*)&HkCreateMutex, "Game.exe");
if (!iat_hook_createmutex->Hook())
{
    auto error = iat_hook_createmutex->GetLastError();
    iat_hook_createmutex->PostError(error);
}

Console output:

Import By Name: [Ordinal:34156] [Name:gluOrtho2D]
Posted Error [SEVERITY:2]:
PolyHook IATHook:Failed to find import
Posted Error [SEVERITY:2]:
PolyHook IATHook: Failed to find import
Posted Error [SEVERITY:2]:
PolyHook IATHook: Failed to find import
Import By Name: [Ordinal:34156] [Name:gluOrtho2D]
Posted Error [SEVERITY:2]:
PolyHook IATHook:Failed to find import
stevemk14ebr commented 8 years ago

There's a couple issues here: 1) You used the error interface wrong, i'll take some of the blame here, i shouldn't have exposted post error to the public interface. I've moved PostError to protected, and i've exposed a PrintError method that you can call. Please check my latest commit to master

2)I don't think you are telling it to look for the import where you think you are. Try this: Make sure to grab my latest commit from master first!

PLH::IATHook* IATMutexHk= new PLH::IATHook();
IATMutexHk->SetupHook("kernel32.dll", "CreateMutexA", (BYTE*)&hkCreateMutex); 
if (!IATMutexHk->Hook())
{
    PLH::RuntimeError err = IATMutexHk->GetLastError();
    IATMutexHk->PrintError(err);
}

that last param where you have "Game.exe" is meant for submodules. For example if Game.exe loaded a module called "Submodule.dll" you would pass in "Submodule.dll" and it would then scan the imports inside of that module, instead of the game.

Also try CreateMutexW instead of CreateMutexA

TheAifam5 commented 8 years ago

I'm using now "development" branch.

Game calling "CreateMutexA" from kernel32: http://prntscr.com/9ugxqq

Still the same:

Import By Name: [Ordinal:34156] [Name:gluOrtho2D]
Posted Error [SEVERITY:2]:
PolyHook IATHook:Failed to find import
Posted Error [SEVERITY:2]:
PolyHook IATHook: Failed to find import
Error PolyHook IATHook: Failed to find import

Debugging line by line: http://prntscr.com/9ugzra

This is executed only one time for (; pOriginalThunk->u1.Function != NULL; pOriginalThunk++, pThunk++).. then jumping back to begin for (int i = 0; pImports[i].Characteristics != 0; i++) and searching in other libraries...

On Windows 10, with VS2015. Game: Tibia :)

stevemk14ebr commented 8 years ago

Are you using the updated code i posted? I'm not sure why it's failing I would have to be able to see the import table of the game myself, you can always just detour using GetProcAddress.

TheAifam5 commented 8 years ago

Yes i used your code.

Gonna hook with GetProcAddress ^^

S0PEX commented 8 years ago

Hey,

i had a look at the FindIATFunc. The Problem is that he only Graps the first dll.

    for (int i = 0; pImports[i].Characteristics != 0; i++)
    {
        char* _ModuleName = (char*)ResolveRVA(hInst, pImports[i].Name);
        if (_stricmp(_ModuleName, LibraryName) != 0)
            continue;

        //Original holds the API Names
        PIMAGE_THUNK_DATA pOriginalThunk = (PIMAGE_THUNK_DATA)
            ResolveRVA(hInst, pImports->OriginalFirstThunk);

        //FirstThunk is overwritten by loader with API addresses, we change this
        PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)
            ResolveRVA(hInst, pImports->FirstThunk);

As you can see he checks if the Dll is in the Inports with pImports[i].Name, but then he uses ResolveRVA(hInst, pImports->OriginalFirstThunk); which will take then the wrong module. If you change it to ResolveRVA(hInst, pImports[i].OriginalFirstThunk); and PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) ResolveRVA(hInst, pImports[i].FirstThunk);

Then it finds the Imports, but the hooks fails it doesnt change the func address, i dont know but it looks like *pFuncThunkOut = pThunk; . fails it and returns shit, althought the func is found i checkt it and it findes the export

stevemk14ebr commented 8 years ago

Good catch S0pex! I've commited the change to master, 026642c48e77d13bb20a5dd4172d7b5ae2a79b81. From what i tested the fix still successfully hooks the function, can you confirm if im correct?

S0PEX commented 8 years ago

For me its still not hooking right. Seems it doest override the Func or smt. I am hooking BitBlt :

std::shared_ptr<PLH::IATHook> IATHook_Ex(new PLH::IATHook);
        IATHook_Ex->SetupHook("Gdi32.dll", "BitBlt", (BYTE*)&hookBitBlt);
        IATHook_Ex->Hook();
        g_fnOriginalBitBlt = IATHook_Ex->GetOriginal<BitBlt_t>();
        auto error = IATHook_Ex->GetLastError();
        printf("%s", error.GetString().c_str());

My Hook :

    BOOL WINAPI hookBitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop)
    {
        MessageBoxA(NULL, "Hallo", "JJAA", NULL);

        //BOOL bRet = g_fnOriginalBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, dwRop);

        return false;
    }

This should denie BitBlt so i get a black Screen. But the hook doesnt give me any errors anymore, but the BitBlt Func isnt hooked. It performs normal and the Msg Box isnt shown. I used http://www.unknowncheats.me/forum/c-and-c-/173907-iat-hooking-class.html all is working fine. I will try to find the error.

stevemk14ebr commented 8 years ago

I cannot duplicate your issue, it's hooking correctly from my tests. I added a BitBlt test to tests.cpp, 232d4f195c51f25594d9636c953de8df5069039c, can you run this and tell me if it works correctly for you? What application are you installing a hook on?

S0PEX commented 8 years ago

So in your Project everything is working fine. I am trying to hook it in D3D9 Test Enviroment, if i detour it and using gerprocadress all is fine. Weird. If I get new infos i will keep you updatet

stevemk14ebr commented 8 years ago

post a link to the test environment you are using so i can investigate please.

S0PEX commented 8 years ago
#include <d3d9.h>
#pragma comment(lib,"d3d9.lib")

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D9             g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold Vertices

                                      // A structure for our custom vertex type
struct CUSTOMVERTEX
{
    FLOAT x, y, z, rhw; // The transformed position for the vertex
    DWORD color;        // The vertex color
};

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_SPECULAR)

//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D(HWND hWnd)
{
    // Create the D3D object.
    if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
        return E_FAIL;

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

    // Create the D3DDevice
    if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dpp, &g_pd3dDevice)))
    {
        return E_FAIL;
    }

    // Device state would normally be set here

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: InitVB()
// Desc: Creates a vertex buffer and fills it with our Vertices. The vertex
//       buffer is basically just a chuck of memory that holds Vertices. After
//       creating it, we must Lock()/Unlock() it to fill it. For indices, D3D
//       also uses index buffers. The special thing about vertex and index
//       buffers is that they can be created in device memory, allowing some
//       cards to process them in hardware, resulting in a dramatic
//       performance gain.
//-----------------------------------------------------------------------------
HRESULT InitVB()
{
    // Initialize three Vertices for rendering a triangle
    CUSTOMVERTEX Vertices[] =
    {
        { 150.0f,  50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color
        { 450.0f, 450.0f, 0.5f, 11.0f, 0xff00ff00, },
        { 50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
    };

    // Create the vertex buffer. Here we are allocating enough memory
    // (from the default pool) to hold all our 3 custom Vertices. We also
    // specify the FVF, so the vertex buffer knows what data it contains.
    if (FAILED(g_pd3dDevice->CreateVertexBuffer(3 * sizeof(CUSTOMVERTEX),
        0, D3DFVF_CUSTOMVERTEX,
        D3DPOOL_DEFAULT, &g_pVB, NULL)))
    {
        return E_FAIL;
    }

    // Now we fill the vertex buffer. To do this, we need to Lock() the VB to
    // gain access to the Vertices. This mechanism is required becuase vertex
    // buffers may be in device memory.
    VOID* pVertices;
    if (FAILED(g_pVB->Lock(0, sizeof(Vertices), (void**)&pVertices, 0)))
        return E_FAIL;
    memcpy(pVertices, Vertices, sizeof(Vertices));
    g_pVB->Unlock();

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
    if (g_pVB != NULL)
        g_pVB->Release();

    if (g_pd3dDevice != NULL)
        g_pd3dDevice->Release();

    if (g_pD3D != NULL)
        g_pD3D->Release();
}
#include <Olectl.h> //BitBlt

HDC hdcClean = NULL;

bool saveBitmap(LPCSTR filename, HBITMAP bmp, HPALETTE pal)
{
    bool result = false;
    PICTDESC pd;

    pd.cbSizeofstruct = sizeof(PICTDESC);
    pd.picType = PICTYPE_BITMAP;
    pd.bmp.hbitmap = bmp;
    pd.bmp.hpal = pal;

    LPPICTURE picture;
    HRESULT res = OleCreatePictureIndirect(&pd, IID_IPicture, false,
        reinterpret_cast<void**>(&picture));

    if (!SUCCEEDED(res))
        return false;

    LPSTREAM stream;
    res = CreateStreamOnHGlobal(0, true, &stream);

    if (!SUCCEEDED(res))
    {
        picture->Release();
        return false;
    }

    LONG bytes_streamed;
    res = picture->SaveAsFile(stream, true, &bytes_streamed);

    HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, 0,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

    if (!SUCCEEDED(res) || !file)
    {
        stream->Release();
        picture->Release();
        return false;
    }

    HGLOBAL mem = 0;
    GetHGlobalFromStream(stream, &mem);
    LPVOID data = GlobalLock(mem);

    DWORD bytes_written;

    result = !!WriteFile(file, data, bytes_streamed, &bytes_written, 0);
    result &= (bytes_written == static_cast<DWORD>(bytes_streamed));

    GlobalUnlock(mem);
    CloseHandle(file);

    stream->Release();
    picture->Release();

    return result;
}

bool screenCapturePart(int x, int y, int w, int h, LPCSTR fname)
{
    HDC hdcSource = GetDC(NULL);
    HDC hdcMemory = CreateCompatibleDC(hdcSource);

    int capX = GetDeviceCaps(hdcSource, HORZRES);
    int capY = GetDeviceCaps(hdcSource, VERTRES);

    HBITMAP hBitmap = CreateCompatibleBitmap(hdcSource, w, h);
    HBITMAP hBitmapOld = (HBITMAP)SelectObject(hdcMemory, hBitmap);

    BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, y, SRCCOPY);

    hdcClean = hdcMemory;

    hBitmap = (HBITMAP)SelectObject(hdcMemory, hBitmapOld);

    DeleteDC(hdcSource);
    DeleteDC(hdcMemory);

    HPALETTE hpal = NULL;

    if (saveBitmap(fname, hBitmap, hpal)) return true;

    return FALSE;
}

//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
    static int frameID = 0;
    // Clear the backbuffer to a blue color
    g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 80, 255), 1.0f, 0);

    // Begin the scene
    if (SUCCEEDED(g_pd3dDevice->BeginScene()))
    {
        // Draw the triangles in the vertex buffer. This is broken into a few
        // steps. We are passing the Vertices down a "stream", so first we need
        // to specify the source of that stream, which is our vertex buffer. Then
        // we need to let D3D know what vertex shader to use. Full, custom vertex
        // shaders are an advanced topic, but in most cases the vertex shader is
        // just the FVF, so that D3D knows what type of Vertices we are dealing
        // with. Finally, we call DrawPrimitive() which does the actual rendering
        // of our geometry (in this case, just one triangle).
        g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
        g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
        g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 1);

        // End the scene
        g_pd3dDevice->EndScene();
    }
    frameID++;

    if (frameID > 40)
    {
        screenCapturePart(0, 0, 1920, 1080, "hallo.bmp");
        frameID = 0;
    }

    // Present the backbuffer contents to the display
    g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}

//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        Cleanup();
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int x = (GetSystemMetrics(0) / 2);
int y = (GetSystemMetrics(1) / 2);
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
{
    // Register the window class
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
        GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
        "winA", NULL };
    RegisterClassEx(&wc);

    // Create the application's window
    HWND hWnd = CreateWindow("winA", "D3D9 Test Envroiment",
        WS_SYSMENU | WS_MINIMIZEBOX, x - 300, y - 300, 600, 600,
        GetDesktopWindow(), NULL, wc.hInstance, NULL);

    // Initialize Direct3D
    if (SUCCEEDED(InitD3D(hWnd)))
    {
        // Create the vertex buffer
        if (SUCCEEDED(InitVB()))
        {
            // Show the window
            ShowWindow(hWnd, SW_SHOWDEFAULT);
            UpdateWindow(hWnd);

            // Enter the message loop
            MSG msg;
            ZeroMemory(&msg, sizeof(msg));
            while (msg.message != WM_QUIT)
            {
                if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
                else
                    Render();
            }
        }
    }

    UnregisterClass("winA", wc.hInstance);
    return 0;
}

There you go

stevemk14ebr commented 8 years ago

ConsoleApplication1.zip I tested the hook using you d3d9 test environment, it worked as expected. I don't know what you're doing wrong, i've appended a zip file of the project i used to test with. Run my code and tell me if it fails for you, inject dll.dll into your test environment, it should give a black image like you want. Make sure you build my code in x86 release mode, i didn't set the include paths for the other build settings.

S0PEX commented 8 years ago

Ohh my good. I found my mistake, like i fixed the thing with the adress of the func and stuff right. Then But then I had a look at my code :

namespace Hooks
{
    //---------------------------------------------------
    // Hook vars
    //---------------------------------------------------
    BitBlt_t                        g_fnOriginalBitBlt = nullptr;

    //static auto IsReady = reinterpret_cast<void(__cdecl*)()>(Utils::FindSignature(XorStr("client.dll"), XorStr("55 8B EC 51 56 8B 35 ? ? ? ? 80 7E 58 00")));
    //---------------------------------------------------
    // Hook functions
    //---------------------------------------------------
    void InitializeHooks()
    {
            std::shared_ptr<PLH::IATHook>      IATHook_Ex(new PLH::IATHook);
        IATHook_Ex->SetupHook("Gdi32.dll", "BitBlt", (BYTE*)&hookBitBlt);
        IATHook_Ex->Hook();
        g_fnOriginalBitBlt = IATHook_Ex->GetOriginal<BitBlt_t>();
    }

    void RestoreHooks()
    {
        IATHook_Ex->UnHook();
    }
}

So what happen is the Function Ini get called hooks it then the function returns right, so the instance deconstructor gets called and unhooks again :dango: sorry for taking your time, this type of errors shouldnt happen to me any more :D