如何使用 C++ 挂钩 Delphi 函数
How to hook Delphi function using C++
我正在尝试挂钩使用 C++ 和 Detours 库编写的 Delphi 程序的用户定义函数。 (DLL 注入)
但是,我无法挂钩它,因为 Delphi 和 C++ 的函数调用约定不匹配。
Delphi使用fastcall函数调用约定,C++也提供了fastcall函数调用约定
然而,Delphi 的 fastcall 将其参数顺序存储在 EAX、EDX、ECX 和堆栈中,而 C++ 的 fastcall 将其参数顺序存储在 ECX、EDX 和堆栈中。 (这是因为fastcall没有标准。)
由于这些差异,我无法获取存储在 EAX 中的参数。
我该如何解决这个问题?
(本文已由Google翻译。)
#include "pch.h"
typedef void(__fastcall* ORGFP)(char); //Prototype of function to hook (reverse engineering)
ORGFP originFunc1 = (ORGFP)((DWORD)GetModuleHandle(NULL) + 0x2B2F20); //Image base of target process + offset of function to hook
ORGFP originFunc2 = (ORGFP)((DWORD)GetModuleHandle(NULL) + 0x2B2A20);
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 __fastcall DetourFunc1(char on) {
WriteLog(TEXT("Function called : BlockInternet(%d)\n"), on);
return originFunc1(on);
}
void __fastcall DetourFunc2(char on) {
WriteLog(TEXT("Function called : BlockInputDevices(%d)\n"), on);
return originFunc2(on);
}
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&)originFunc1, DetourFunc1);
DetourAttach(&(PVOID&)originFunc2, DetourFunc2);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
FreeConsole();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)originFunc1, DetourFunc1);
DetourDetach(&(PVOID&)originFunc2, DetourFunc2);
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>
#endif
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
根据维基百科:
Borland register
Evaluating arguments from left to right, it passes three arguments via EAX, EDX, ECX. Remaining arguments are pushed onto the stack, also left to right.[12] It is the default calling convention of the 32-bit compiler of Delphi, where it is known as register. This calling convention is also used by Embarcadero's C++Builder, where it is called __fastcall.[13] In this compiler, Microsoft's fastcall can be used as __msfastcall.[14]
GCC and Clang can be made to use a similar calling convention by using __stdcall with the regparm function attribute or the -mregparm=3 switch. (The stack order is inverted.) It is also possible to produce a caller clean-up variant using cdecl or extend this to also use SSE registers.[15] A cdecl-based version is used by the Linux kernel on i386 since version 2.6.20 (released February 2007).
https://en.wikipedia.org/wiki/X86_calling_conventions#Borland_register
我使用 __declspec(naked)
解决了这个问题!感谢所有帮助过我的人!
#include <iostream>
#include <Windows.h>
#include <detours.h>
using namespace std;
__declspec(naked) void __fastcall originFunction(char arg) {
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
__asm {
mov byte ptr [arg], al
}
cout << (int)arg << endl;
__asm {
mov esp, ebp
pop ebp
ret
}
}
typedef void(__fastcall* FP)(char);
FP originFunctionPointer = originFunction;
__declspec(naked) void __fastcall detourFunction(char arg) {
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
__asm {
mov byte ptr [arg], al
}
cout << (int)arg << endl;
arg = 0;
__asm {
mov al, byte ptr [arg]
call dword ptr [originFunctionPointer]
}
__asm {
mov esp, ebp
pop ebp
ret
}
}
int main() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)originFunctionPointer, detourFunction);
DetourTransactionCommit();
__asm {
mov al, 1h
call dword ptr [originFunction]
}
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)originFunctionPointer, detourFunction);
DetourTransactionCommit();
return 0;
}
我正在尝试挂钩使用 C++ 和 Detours 库编写的 Delphi 程序的用户定义函数。 (DLL 注入)
但是,我无法挂钩它,因为 Delphi 和 C++ 的函数调用约定不匹配。
Delphi使用fastcall函数调用约定,C++也提供了fastcall函数调用约定
然而,Delphi 的 fastcall 将其参数顺序存储在 EAX、EDX、ECX 和堆栈中,而 C++ 的 fastcall 将其参数顺序存储在 ECX、EDX 和堆栈中。 (这是因为fastcall没有标准。)
由于这些差异,我无法获取存储在 EAX 中的参数。
我该如何解决这个问题?
(本文已由Google翻译。)
#include "pch.h"
typedef void(__fastcall* ORGFP)(char); //Prototype of function to hook (reverse engineering)
ORGFP originFunc1 = (ORGFP)((DWORD)GetModuleHandle(NULL) + 0x2B2F20); //Image base of target process + offset of function to hook
ORGFP originFunc2 = (ORGFP)((DWORD)GetModuleHandle(NULL) + 0x2B2A20);
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 __fastcall DetourFunc1(char on) {
WriteLog(TEXT("Function called : BlockInternet(%d)\n"), on);
return originFunc1(on);
}
void __fastcall DetourFunc2(char on) {
WriteLog(TEXT("Function called : BlockInputDevices(%d)\n"), on);
return originFunc2(on);
}
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&)originFunc1, DetourFunc1);
DetourAttach(&(PVOID&)originFunc2, DetourFunc2);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
FreeConsole();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)originFunc1, DetourFunc1);
DetourDetach(&(PVOID&)originFunc2, DetourFunc2);
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>
#endif
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
根据维基百科:
Borland register Evaluating arguments from left to right, it passes three arguments via EAX, EDX, ECX. Remaining arguments are pushed onto the stack, also left to right.[12] It is the default calling convention of the 32-bit compiler of Delphi, where it is known as register. This calling convention is also used by Embarcadero's C++Builder, where it is called __fastcall.[13] In this compiler, Microsoft's fastcall can be used as __msfastcall.[14]
GCC and Clang can be made to use a similar calling convention by using __stdcall with the regparm function attribute or the -mregparm=3 switch. (The stack order is inverted.) It is also possible to produce a caller clean-up variant using cdecl or extend this to also use SSE registers.[15] A cdecl-based version is used by the Linux kernel on i386 since version 2.6.20 (released February 2007).
https://en.wikipedia.org/wiki/X86_calling_conventions#Borland_register
我使用 __declspec(naked)
解决了这个问题!感谢所有帮助过我的人!
#include <iostream>
#include <Windows.h>
#include <detours.h>
using namespace std;
__declspec(naked) void __fastcall originFunction(char arg) {
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
__asm {
mov byte ptr [arg], al
}
cout << (int)arg << endl;
__asm {
mov esp, ebp
pop ebp
ret
}
}
typedef void(__fastcall* FP)(char);
FP originFunctionPointer = originFunction;
__declspec(naked) void __fastcall detourFunction(char arg) {
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
__asm {
mov byte ptr [arg], al
}
cout << (int)arg << endl;
arg = 0;
__asm {
mov al, byte ptr [arg]
call dword ptr [originFunctionPointer]
}
__asm {
mov esp, ebp
pop ebp
ret
}
}
int main() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)originFunctionPointer, detourFunction);
DetourTransactionCommit();
__asm {
mov al, 1h
call dword ptr [originFunction]
}
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)originFunctionPointer, detourFunction);
DetourTransactionCommit();
return 0;
}