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

Posted

技术标签:

【中文标题】如何获取用户定义函数的地址?【英文标题】:How to get address of user-defined function? 【发布时间】:2020-09-28 19:02:32 【问题描述】:

我正在尝试挂钩用户定义的函数。 (通过 DLL 注入和内联函数挂钩) 为此,我需要获取函数的地址以挂接到进程内存中。

我尝试了各种方法来找到地址,最后得出了下面的等式。

(offset) = (EXE 文件中的函数地址) - (EXE 文件的图片库)

(进程内存中的函数地址) = (GetModuleHandle(NULL)) + (offset)

但是,我不确定这个等式是否始终成立。 (例如,当发生 DLL Relocation 时,我担心这个公式可能是错误的。)

总之,我想知道这个等式是否始终成立。如果没有,我想知道如何解决这个等式。

(本文由谷歌翻译翻译。)


#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);

#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;

#include "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

#pragma once

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

https://github.com/DarthTon/Xenos/releases/latest


将“testdll.dll”注入“testwinapi.exe”后,我希望能够监控“捕获”函数调用。 (因为‘capture’函数是逆向重构的,所以假设‘testwinapi.exe’没有源码)



【问题讨论】:

我想你想破解另一个进程,而不是当前进程? ????????请在此处以纯文本形式发布代码、错误、示例数据或文本输出,而不是难以阅读、无法复制粘贴以帮助测试代码或在答案中使用的图像,并且对依赖的人构成障碍在屏幕阅读器上。您可以编辑问题以在问题正文中添加代码。为了便于格式化,请使用 按钮标记代码块,或使用四个空格缩进以获得相同的效果。 屏幕截图的内容无法搜索、作为代码运行或复制和编辑以创建解决方案。 GetProcAddress 有什么问题? @IInspectable // 不可能,因为试图获取地址的函数没有在dll中定义。 @tadman // 抱歉。我已经在文章中添加了源代码和一些解释。 【参考方案1】:

模块重定位作为一个整体发生。各个部分永远不会相对于图像库移动。每个部分的偏移量 (RVA) 都硬编码在模块头中。

例如:

#  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

这些部分在指定的 RVA 偏移处加载,而与图像基地址无关。还有 RVA 0 和大小 0x1000 的隐式“标题”部分,这就是第一部分从 0x1000 开始的原因。请注意,RVA 偏移量!= 文件偏移量。

所以是的,给定一些已知的图像库和其中的地址,该地址相对于图像库的偏移量将保持不变。

这允许 64 位代码在 .data 部分中使用 RIP 相对寻址,例如,这样可以保存修复。

【讨论】:

对于在 CLR 中运行的 JIT 编译代码也是如此吗? @IInspectable 此答案仅适用于本机代码。我只知道 GetProcAddress 给出的地址是恒定的,并且 JIT 编译的代码可以随时重新编译,因此我假设在固定地址处会有一些蹦床跳转到 JIT 代码。对 CLR 内部工作原理了解不足,无法明确回答。 我也不熟悉 CLR 的时间间隔,但我确实记得 - 与 Java 不同 - .NET 代码最多只能被 JIT 编译一次。

以上是关于如何获取用户定义函数的地址?的主要内容,如果未能解决你的问题,请参考以下文章

从单元格获取超链接地址的用户定义函数

如何使用用户定义的函数获取 cassandra 的 blob 列的大小?

在 C 中,如何从用户定义的函数中获取一个值,然后在另一个用户定义的函数中将其打印出来? [关闭]

如何在 SQL Server 中获取用户定义的表值函数的结果形状? [复制]

如何在 Symfony2 控制器中获取用户 IP 地址?

Java:如何获取错误信息?