在指向现有内存地址的 hpp 文件中声明成员函数的最佳方法
Best way to declare member functions in a hpp file that point to an existing memory address
由于 MVSC x86/x64 编译器的更改,我无法使用__asm(jmp addr)
通过项目中的内存地址执行直接函数。
对于非成员函数,此问答起到了作用:将内联程序集尾调用函数尾声替换为 x86/x64 msvc 的 Intrinsics
但是对于成员函数,我现在需要一个替代方案;必须指出的是,对于构造函数和解构函数,以及我的变体不起作用的同名函数,这也是必需的。当然,也欢迎提出改进建议,是的,我只有内存地址,所以没有其他方法可以调用它。
zstring.hpp:
#pragma once
#include <string>
#include "../asmjmp.h"
int __cdecl operator==(class zSTRING const &, char const * const);
int __cdecl operator==(class zSTRING const &, class zSTRING const &);
class zSTRING
{
public:
zSTRING() {
__asm( jmp 0x00402AF0);
}
zSTRING(zSTRING const &) {
__asm( jmp 0x00416500);
}
~zSTRING() {
__asm( jmp 0x00401160);
}
int Overwrite(unsigned int, class zSTRING const &) {
__asm( jmp 0x0046B6A0);
}
int Overwrite(string) {
__asm( jmp 0x0046B6FF);
}
int Insert(unsigned int, class zSTRING const &) {
__asm( jmp 0x0046B400);
}
/* My Variant: */
int (*Insert)(unsigned int, class zSTRING const &) = ((int(*)(unsigned int, class zSTRING const &))0x0046B400);
int Delete(class zSTRING const &, enum zTSTR_KIND) {
__asm( jmp 0x0046BCF0);
}
/* My Variant: */
int (*Delete)(class zSTRING const &, enum zTSTR_KIND) = ((int(*)(class zSTRING const &, enum zTSTR_KIND))0x0046BCF0);
char * ToChar() const
{
__asm( jmp 0x004639D0);
}
zSTRING Copied(unsigned int, unsigned long) const
{
__asm( jmp 0x0046C170);
}
zSTRING &operator+=(char const *) {
__asm( jmp 0x0067A7B0);
}
/* My Variant (without knowing if it would work): */
zSTRING (*&operator+=)(char const *) = ((zSTRING (*)(char const *))0x0067A7B0);
char & operator[](unsigned int) {
__asm( jmp 0x00445A20);
}
/* My Variant (without knowing if it would work): */
char & (operator[])(unsigned int) = ((char &(*)(unsigned int))0x00445A20);
};
如果你想要某个函数包含单个jmp
指令到某个地址 - 你需要用__declspec(dllimport)
声明它(这是Microsoft特定的,仅适用于CL编译器,但认为另一个编译器具有平等的语法(。 比如说
void __declspec(dllimport) TrimLeft(char);
如果你对类中的所有成员函数都使用了这个 - 用这个声明所有类:
class __declspec(dllimport) zSTRING
{
zSTRING();
// .. more declarations
};
这将对所有非虚拟成员函数和类的静态数据成员产生影响,就像它用__declspec(dllimport)
声明的那样
当函数声明时__declspec(dllimport)
编译器声明了 extern 指针变量:
extern void* __imp___FUNCDNAME__;
其中__FUNCDNAME__
是修饰的函数名称 +__imp_
前缀; 并且每次调用这样的函数编译器时都会生成call __imp___FUNCDNAME__
指令(在将函数参数传递给寄存器或堆栈之后(。 使用"编辑并继续"选项 编译器通常会生成不太优化的代码:
call func
func:
jmp __imp___FUNCDNAME__ ; exactly what you try - single jmp in function body
这实际上相当于单call __imp___FUNCDNAME__
现在很明显,对于每个导入的函数,void* __imp___FUNCDNAME__
必须在某个地方定义并包含实际函数地址。 否则你会得到众所周知的链接器错误LNK2001:未解析的外部符号
通常我们使用LIB文件,其中精确定义了__imp___FUNCDNAME__
符号 - 在这种情况下,链接器将所有这些__imp_*
变量放在 PEIAT
部分中,并在导入部分中对其进行描述。 作为结果加载器,加载图像时为每个__imp___FUNCDNAME__
分配正确的地址。
如果您尝试从某个 DLL 导入此函数并且此 DLL导出此函数 - 您必须为此提供 LIB 文件。 即使您没有LIB- 您也可以自己轻松创建 -创建单独的项目,其输出文件名与 DLL 名称完全匹配,您将从中调用代码并使用每个函数或类的__declspec(dllexport)
"实现"所有这些函数。 每个函数的实现 - 可以是空的或单个的return 0;
- 实际上当我们构建 lib 时 - 它不包含任何代码(因为结果实现可能是假的/空的(。它完全包含函数名称和DLL名称(因为项目的此输出文件名必须完全是DLL名称。通常 - 这必须如下所示:
void __declspec(dllexport) TrimLeft(char)
{
}
class __declspec(dllexport) zSTRING
{
public:
zSTRING()
{
}
int Overwrite(unsigned int, class zSTRING const &)
{
return 0;
}
//...
};
您可以轻松地构建此代码并获得所需的所有LIB文件(导入库(。
如果此功能未导出 - 不清楚您从哪里获得地址,但无论如何 - 这不能是硬编码的绝对地址。 在极端情况下,您可以使用来自DLL的硬编码RVA...无论如何,如果此功能未导出- 您需要自己定义所有__imp___FUNCDNAME__
。并且您自己在开始时为其分配正确的函数地址。
因为__FUNCDNAME__
通常包含非法的C/C++
符号 - 你需要在ASM中声明它,如下所示:
_BSS segment
__imp_?TrimLeft@@YAXD@Z DQ ?
__imp_??0zSTRING@@QEAA@XZ DQ ?
__imp_??1zSTRING@@QEAA@XZ DQ ?
__imp_??0zSTRING@@QEAA@AEBV0@@Z DQ ?
__imp_?Insert@zSTRING@@QEAAHIAEBV1@@Z DQ ?
public __imp_?TrimLeft@@YAXD@Z
public __imp_??0zSTRING@@QEAA@XZ
public __imp_??1zSTRING@@QEAA@XZ
public __imp_??0zSTRING@@QEAA@AEBV0@@Z
public __imp_?Insert@zSTRING@@QEAAHIAEBV1@@Z
_BSS ends
并实现自己解决导入的功能
resolveimport proc
lea rax,[rcx + rva_1]
mov __imp_?TrimLeft@@YAXD@Z,rax
lea rax,[rcx + rva_2]
mov __imp_??0zSTRING@@QEAA@XZ,rax
;...
ret
resolveimport endp
假设您从地址为 DLL 的C++代码调用resolveimport
-resolveimport(LoadLibraryW(L"my.dll"));
- 在指向现有内存地址的 hpp 文件中声明成员函数的最佳方法
- 如何使用模板声明成员函数?(不是模板类)
- 如何使用 Boost.Hana 声明成员变量
- 声明成员对象而不调用其默认构造函数
- 使用函数类型语法声明成员函数
- 尝试访问标头声明成员时出现隔离错误
- 根据二手构造函数声明成员
- C 模板明确声明成员函数值/避免了宏的问题
- 如何在基本模板类中声明成员,其中类型取决于派生类的类型
- 错误:类中没有声明成员函数
- 我可以使用相同的名称为周围作用域中的类型声明成员类型别名吗
- 从variadic模板参数声明成员变量
- 在类(C )中使用模板时未声明成员函数
- 错误:类中未声明 '' 成员函数
- 如何在指向常量地址时声明成员函数常量指针
- 何时以及为什么在堆C++上声明成员变量
- C++ 错误:未在范围内声明;成员函数
- 在不声明成员变量的情况下更改按钮颜色
- 错误 C2535:已定义或声明成员函数
- 当声明成员函数时,*New()是什么意思