简体   繁体   English

如何获取自定义函数的地址?

[英]How to get address of user-defined function?

I am trying to hook a user-defined function.我正在尝试挂钩用户定义的函数。 (via DLL injection and inline function hooking) (通过 DLL 注入和内联函数挂钩)
To do that, I need to get the address of the function to hook in process memory.为此,我需要获取函数的地址以挂接到进程内存中。

I tried various methods to find the address, and finally came up with the equation below.我尝试了各种方法来找到地址,最后得出了下面的等式。

(offset) = (Address of function in EXE file) - (Image base of EXE file) (偏移量)=(EXE 文件中函数的地址)-(EXE 文件的图像库)

(Address of function in process memory) = (GetModuleHandle(NULL)) + (offset) (进程内存中的函数地址) = (GetModuleHandle(NULL)) + (offset)

However, I am not sure if this equation always holds.但是,我不确定这个等式是否始终成立。 (For example, when DLL Relocation occurs, I am worried that this equation may be wrong.) (例如,当发生DLL Relocation时,我担心这个等式可能是错误的。)

In conclusion, I want to know whether this equation always holds.总之,我想知道这个等式是否总是成立。 And if not, I'd like to know how to fix this equation.如果没有,我想知道如何解决这个等式。

(This article has been translated by Google Translate.) (本文由谷歌翻译翻译。)


< testwinapi / main.cpp > < testwinapi / main.cpp >

#include <stdio.h>
#include <Windows.h>

void capture(HBITMAP* canvas);

int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) {
    while(1) {
        HBITMAP canvas;
        capture(&canvas);
        Sleep(2000);
    }

    return 0;
}

void capture(HBITMAP* canvas) {
    RECT srcRect;
    HWND hSrcWnd;
    HDC hSrcDC, hDestDC;

    hSrcWnd = GetDesktopWindow();
    hSrcDC = GetDC(hSrcWnd);

    GetWindowRect(hSrcWnd, &srcRect);
    int SrceenWidth = srcRect.right - srcRect.left;
    int SrceenHeight = srcRect.bottom - srcRect.top;

    hDestDC = CreateCompatibleDC(hSrcDC);
    *canvas = CreateCompatibleBitmap(hSrcDC, SrceenWidth, SrceenHeight);
    SelectObject(hDestDC, *canvas);

    for (int y = 0; y < SrceenHeight; y += 50) {
        BitBlt(hDestDC, 0, y, SrceenWidth, 50, hSrcDC, 0, y, SRCCOPY);
        Sleep(2);
    }

    ReleaseDC(hSrcWnd, hSrcDC);
    DeleteDC(hDestDC);
}

< testdll / dllmain.cpp > <testdll/dllmain.cpp>

#include "pch.h"

DWORD WriteLog(LPCTSTR format, ...);
void MyCapture(HBITMAP* canvas);

void(*originFunc)(HBITMAP*) = reinterpret_cast<void(*)(HBITMAP*)>(0x941880); //Address of function in process memory

DWORD WriteLog(LPCTSTR lpszFormat, ...) {
    TCHAR szLog[512];
    DWORD dwCharsWritten;

    va_list args;
    va_start(args, lpszFormat);
    _vstprintf_s(szLog, 512, lpszFormat, args);
    va_end(args);

    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), szLog, _tcslen(szLog), &dwCharsWritten, NULL);

    return dwCharsWritten;
}

void MyCapture(HBITMAP* canvas) {
    WriteLog(TEXT("Function called : capture(0x%X)\n"), (DWORD)canvas);
    return originFunc(canvas);
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    if (DetourIsHelperProcess())
        return TRUE;

    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
        AllocConsole();
        DetourRestoreAfterWith();
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)originFunc, MyCapture);
        DetourTransactionCommit();
        break;
    case DLL_PROCESS_DETACH:
        FreeConsole();
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourDetach(&(PVOID&)originFunc, MyCapture);
        DetourTransactionCommit();
        break;
    }

    return TRUE;
}

< testdll / pch.cpp > <testdll/pch.cpp>

#include "pch.h"

< testdll / pch.h > <testdll/pch.h>

#ifndef PCH_H
#define PCH_H

#include "framework.h"
#include <stdio.h>
#include <stdarg.h>
#include <tchar.h>
#include <detours.h> 
//MS Detours library 
//Can be downloaded from NuGet Package Manager

#endif

< testdll / framework.h > <testdll/framework.h>

#pragma once

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

< DLL Injector > < DLL 注入器 >
https://github.com/DarthTon/Xenos/releases/latest https://github.com/DarthTon/Xenos/releases/latest


After injecting 'testdll.dll' into 'testwinapi.exe', I want to be able to monitor the 'capture' function call.将“testdll.dll”注入“testwinapi.exe”后,我希望能够监视“捕获”函数调用。 (Because the 'capture' function is reconstructed by reverse engineering, it is assumed that there is no source code for 'testwinapi.exe') (因为'capture'函数是逆向重构的,所以假设没有'testwinapi.exe'的源码)


EXE文件的图像库

EXE文件中函数的地址


获取模块句柄(NULL)

进程内存中的函数地址

Module relocation occurs as a whole.模块重定位作为一个整体发生。 Individual sections are never moved with respect to the image base.各个部分永远不会相对于图像库移动。 The offsets (RVA) of each section are hardcoded in the module header.每个部分的偏移量 (RVA) 都硬编码在模块头中。

For example:例如:

#  Name   VirtSize RVA      PhysSize Offset
1 .text   000C44C1 00001000 000C4600 00000800
2 .data   00000FEC 000C6000 00000E00 000C4E00
3 .rsrc   00000520 000C7000 00000600 000C5C00
4 .reloc  0000B098 000C8000 0000B200 000C6200

These sections are loaded at specified RVA offsets, regardless of image base address.无论映像基址如何,这些部分都以指定的 RVA 偏移量加载。 There's also the implicit "header" section with RVA 0 and size 0x1000, which is why the first section starts at 0x1000.还有隐含的“标题”部分,其中 RVA 为 0,大小为 0x1000,这就是第一部分从 0x1000 开始的原因。 Note that RVA offset != file offset.请注意,RVA 偏移量 != 文件偏移量。

So yes, given some known image base and an address inside of it, the offset of that address from the image base will remain constant.所以是的,给定一些已知的图像基址和其中的地址,该地址与图像基址的偏移量将保持不变。

This allows 64-bit code to employ RIP-relative addressing into the .data section, for example, which saves a fixup.例如,这允许 64 位代码在 .data 部分中使用 RIP 相对寻址,从而节省了修正。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM