c++ - 调用复制函数时访问冲突
问题描述
这是一个将函数复制到堆上,将其设置为可执行文件并调用它的程序。
#include <iostream>
#include <iomanip>
#include <csignal>
#include <Windows.h>
using std::cout;
#define RET 0xC3
void printBytes(void* start, uintptr_t numBytes) {
std::ios_base::fmtflags savedFlags(cout.flags());
cout << std::hex << std::uppercase << std::setfill('0');
bool lineComplete = false;
for (unsigned int byte = 0; byte < numBytes; byte++) {
lineComplete = byte % 4 == 3;
cout << std::setw(2)
<< (int)*((uint8_t*)start + byte)
<< (lineComplete ? '\n' : ' ');
}
cout << (lineComplete ? "\n" : "\n\n");
cout.flags(savedFlags);
}
uint8_t* findByte(void* start, uint8_t targetByte) {
uint8_t* pByte = (uint8_t*) start;
while (*pByte != targetByte) pByte++;
return pByte;
}
uintptr_t findByteOffset(void* base, uint8_t targetByte) {
uint8_t* byte = findByte(base, targetByte);
return (uintptr_t)byte - (uintptr_t)base;
}
int main() {
void(*function)() = [] { cout << "Hello world"; };
uintptr_t size = findByteOffset(function, RET) + 1;
cout << "function : " << function << "\n\n";
printBytes(function, size);
void(*functioncopy)() = static_cast<void(*)()>(malloc(size));
cout << "functioncopy : " << functioncopy << "\n\n";
if (functioncopy)
{
memcpy(functioncopy, function, size);
printBytes(functioncopy, size);
DWORD oldProtect;
VirtualProtect(functioncopy, size, PAGE_EXECUTE_READWRITE, &oldProtect);
cout << "functioncopy()\n";
functioncopy();
VirtualProtect(functioncopy, size, oldProtect, &oldProtect);
}
else cout << "malloc(" << size << ") failed.";
}
当我运行程序时(在 Release 或 Debug 配置中,有或没有优化),它在 functioncopy() 中给出了访问冲突。我不知道为什么。
解决方案
绝对没有理由期望这会奏效。无论是否有人能想到它不起作用的原因,根本没有理由期望它起作用。没有标准或参考说这应该起作用,并且期望它起作用,坦率地说,是疯狂的。
作为它可能失败的最明显的方式:如果一个0xc3
恰好作为其他东西的一部分出现在函数的代码中怎么办,也许是它调用的辅助函数的地址?如果它不使用RET
指令返回怎么办?如果函数的代码使用相对跳转到翻译单元中的另一个函数怎么办?如果函数跳转并且它的一些代码位于RET
内存之后怎么办?如果有一百万件其他事情出错了,我这一秒都想不出来怎么办?
这段代码很荒谬。它不是基于任何合理的工程推理。
推荐阅读
- python-3.x - 如何在一个回调中识别 QLineEdit 以进行多行编辑?
- c# - 定时器功能冻结应用程序窗口
- .net - 通过 PowerShell 5 从 GIF 图像中删除透明度
- c# - 如何删除 foreach 循环中的第一个数组元素?
- java - 如何正确使用 setLocaleScale 方法?我在确定我的 AR 模型的大小时遇到问题
- firebase - 达到 Flame 计划限制后,我可以重新打开 Firebase
- ruby-on-rails - 两个表单输入值不能相同 Ruby on Rails
- sql-server - 收缩 Microsoft Dynamics CRM 的数据库日志文件
- excel - 如何将所有工作表名称复制到同一工作簿中的特定工作表?
- file - 如何从 C# 中 Directory.GetFiles 中基于正则表达式的文件夹中读取图像?