调用复制函数时访问冲突

问题描述

这是一个将函数复制到堆上,将其设置为可执行文件并调用它的程序。

#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,oldProtect,&oldProtect);
    }
    else cout << "malloc(" << size << ") failed.";
}

当我运行程序时(在Release或Debug配置中,有或没有进行优化),它在functioncopy()中给出了访问冲突。我不知道为什么。

解决方法

绝对没有理由期望它能起作用。不管是否有人想到它不起作用的原因,根本没有理由期望它起作用。没有任何标准或参考资料表明这应该起作用,并且期望它起作用是直率的,疯狂的。

它可能会失败,这是最明显的方式:如果0xc3恰好出现在该函数的代码中作为其他内容的一部分,可能是它调用的辅助函数的地址?如果它不使用RET指令返回怎么办?如果该函数的代码相对于转换单元中的另一个函数使用了相对跳转,该怎么办?如果函数跳转并且其某些代码位于内存中的RET之后怎么办?如果有一百万个其他问题出了错而我又想不出该怎么办?

这段代码是荒谬的。它不是基于任何理性的工程推理。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...