如何获取用户自定义函数的地址?
How to get address of user-defined function?
我正在尝试挂钩用户定义的函数。 (通过 DLL 注入和内联函数挂钩)
为此,我需要获取挂接进程内存的函数地址。
我试了各种方法求地址,最后得出下面的等式。
(offset) = (Address of function in EXE file) - (Image base of EXE file)
(Address of function in process memory) = (GetModuleHandle(NULL)) + (offset)
但是,我不确定这个等式是否总是成立。 (比如发生DLL Relocation时,我担心这个等式可能是错误的。)
总之,我想知道这个等式是否总是成立。如果没有,我想知道如何解决这个方程式。
(本文已由Google翻译。)
#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;
}
< testdll / pch.cpp >
#include "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 >
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
< DLL 注入器>
https://github.com/DarthTon/Xenos/releases/latest
将'testdll.dll'注入'testwinapi.exe'后,我希望能够监控'capture'函数调用。 (因为'capture'函数是逆向重构的,假设'testwinapi.exe'没有源码)
模块搬迁是整体发生的。各个部分永远不会相对于图像库移动。每个部分的偏移量 (RVA) 都硬编码在模块 header.
中
例如:
# 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 的隐式“header”部分,这就是第一部分从 0x1000 开始的原因。请注意,RVA 偏移量 != 文件偏移量。
所以是的,给定一些已知的图像基址和其中的地址,该地址与图像基址的偏移量将保持不变。
这允许 64 位代码使用 RIP-relative 寻址到 .data 部分,例如,它保存了一个修正。
我正在尝试挂钩用户定义的函数。 (通过 DLL 注入和内联函数挂钩)
为此,我需要获取挂接进程内存的函数地址。
我试了各种方法求地址,最后得出下面的等式。
(offset) = (Address of function in EXE file) - (Image base of EXE file)
(Address of function in process memory) = (GetModuleHandle(NULL)) + (offset)
但是,我不确定这个等式是否总是成立。 (比如发生DLL Relocation时,我担心这个等式可能是错误的。)
总之,我想知道这个等式是否总是成立。如果没有,我想知道如何解决这个方程式。
(本文已由Google翻译。)
#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;
}
< testdll / pch.cpp >
#include "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 >
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
< DLL 注入器>
https://github.com/DarthTon/Xenos/releases/latest
将'testdll.dll'注入'testwinapi.exe'后,我希望能够监控'capture'函数调用。 (因为'capture'函数是逆向重构的,假设'testwinapi.exe'没有源码)
模块搬迁是整体发生的。各个部分永远不会相对于图像库移动。每个部分的偏移量 (RVA) 都硬编码在模块 header.
中例如:
# 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 的隐式“header”部分,这就是第一部分从 0x1000 开始的原因。请注意,RVA 偏移量 != 文件偏移量。
所以是的,给定一些已知的图像基址和其中的地址,该地址与图像基址的偏移量将保持不变。
这允许 64 位代码使用 RIP-relative 寻址到 .data 部分,例如,它保存了一个修正。