C++ 劫持函数';通过链接另一个对象文件来实现

C++ 劫持函数';通过链接另一个对象文件来实现,c++,object,implementation,C++,Object,Implementation,我听说,通过将函数所在的对象文件与您编写的另一个文件链接,可以重写/劫持/破解函数的实现。我一直在玩,似乎我只能在一种情况下使用它。但是,我想知道,除了上述情况之外,是否有可能在其他情况下实现此结果(如下所示) 使用的编译器:TDM-GCC 4.9.2 操作系统:Windows 8 64位 以下描述了劫持“成功”的情况: 下面是一个名为sample.cpp #include <iostream> int returnOne(); int main() { std::cou

我听说,通过将函数所在的对象文件与您编写的另一个文件链接,可以重写/劫持/破解函数的实现。我一直在玩,似乎我只能在一种情况下使用它。但是,我想知道,除了上述情况之外,是否有可能在其他情况下实现此结果(如下所示)

使用的编译器:TDM-GCC 4.9.2

操作系统:Windows 8 64位

以下描述了劫持“成功”的情况:

下面是一个名为
sample.cpp

#include <iostream>

int returnOne();

int main()
{
    std::cout << "returnOne() returns " << returnOne();

    return 0;
}
使用
nm.exe
检查对象文件后,我的函数的损坏名称是:
\uuuuuz9returnonev

因此,进入另一个源代码
hack.cpp

extern "C" int _Z9returnOnev()
{
    return 5;  //rather than return 1
}
汇编:

g++ -c sample.cpp -o sample.o
g++ -c hack.cpp -o hack.o
现在,我使用
hack.o
文件“重新创建”可执行文件:

g++ -Wl,--allow-multiple-definition hack.o sample.o -o sample.exe
运行时,
sample.exe
生成:

returnOne() returns 5
所以劫机成功了

现在,如果我在任何时候在原始源代码中提供了
returnOne()
的实现,那么这种技术就不再有效了。例如:

#include <iostream>

int returnOne();

int main()
{
    std::cout << "returnOne() returns " << returnOne();

    return 0;
}

int returnOne()
{
    return 1;
}
但是,问题依然存在。

编辑2(7/15/15):
好的,我清理了,然后编译并链接了所有东西,带有-O0开关:

g++ -O0 -c sample.cpp -o sample.o

g++ -O0 -c hack.cpp -o hack.o

g++ -Wl,--allow-multiple-definition,-O0 hack.o sample.o -o sample.exe

它仍然返回1。

否,在这种情况下不可能重写函数实现

编译器编译源文件时通常会创建一个包含函数签名(标识符+参数类型)和函数地址的表。 当代码中有函数调用时,编译器将尝试使用此签名调用函数。 这就是为什么您需要一个链接器——实际上,#include语句在编译之前会将所有声明复制到您的代码中,以便您拥有正确的签名。然后链接器添加可调用函数的地址。
如果main.cpp中有函数定义,则编译器/链接器无需在其他任何地方查找定义

该函数很可能是由编译器内联的。尝试禁用所有优化。我尝试了链接器选项-O0,因此我的新调用是:
g++-Wl,--allow multiple definition,-O0 hack.o sample.o-o sample.exe
,但它产生了相同的效果。@PaulRich编译sample.cpp:
g++-O0-c sample.cpp-o sample.o
。相关
g++ -O0 -c sample.cpp -o sample.o

g++ -O0 -c hack.cpp -o hack.o

g++ -Wl,--allow-multiple-definition,-O0 hack.o sample.o -o sample.exe