我一直在使用c / c ++中的指针和函数指针。因为你可以获得函数的地址,你能改变函数调用的实际结束位置吗?
我尝试获取某个函数的内存地址,然后将第二个函数地址写入该位置,但它给了我一个访问冲突错误。
此致
答案 0 :(得分:2)
函数指针是变量,就像整数和双精度数一样。函数的地址是不同的。它是二进制文件.text
部分中函数开头的位置。您可以将函数的地址分配给相同类型的函数指针,但.text
部分是只读的,因此您无法对其进行修改。写入函数的地址会尝试覆盖函数开头的代码,因此不允许。
注意强>: 如果要在运行时更改函数调用结束的位置,可以创建一个称为vritual dispatch table或vtable的东西。这是一个包含函数指针的结构,用于多语言的c ++等语言。
e.g:
struct VTable {
int (*foo)(void);
int (*bar)(int);
} vTbl;
在运行时,您可以更改vTbl.foo
和vTbl.bar
的值以指向不同的功能,并且对vTbl.foo()
或.bar
的任何调用都将定向到新功能
答案 1 :(得分:1)
在某些环境中,可以“修补”函数的开头指令,使调用转到其他位置。这是一种不寻常的技术,不用于正常编程。如果您有现有的编译程序并且需要更改它与操作系统交互的方式,有时会使用它。
Microsoft Detours是具有此功能的库的示例。
答案 2 :(得分:1)
如果你试图打电话的功能是内联的,那么你几乎没有运气。但是,如果不内联,那么可能有一种方法:
在Unix系统上,动态链接器的一个共同特征是LD_PRELOAD
,它允许您使用自己的版本覆盖共享库中的函数。有关此问题的一些讨论,请参阅问题What is the LD_PRELOAD trick?。如果你试图劫持的函数没有从共享库中加载(即如果它是可执行文件的一部分,或者它是来自静态链接的库),那么你可能运气不好。
在Windows上,还有其他攻击媒介。如果某个DLL导出要挂钩的函数,则可以使用Import Address Table Patching来劫持它而不需要修改函数的代码。如果它不是由DLL 导出但是你可以获取它的地址(即通过获取函数的地址),你可以使用类似免费(强烈推荐)N-CodeHook项目的东西
答案 3 :(得分:0)
您可以更改函数指针指向的内容,但不能更改正常函数,也不能更改函数包含的内容。
答案 4 :(得分:0)
您通常无法找到功能结束的位置。语言中没有这样的标准功能,编译器可以通过这样的方式优化代码,使得函数的代码不是连续的,并且实际上没有单个结束点,并且为了找到代码结束的位置,需要使用一些代码。非标准工具或反汇编代码并理解它,这不是你可以轻松编写自动执行程序的东西。