我已经阅读并搜索了左右规则来解码函数指针。
例如:
int (*(*fun_one)(char *,double))[9][20];
是: fun_one是函数期望的指针(char *,double)和 返回指向int的数组(大小为20)的数组(大小为9)的指针。
那是什么
const char code[] = "\x31\xc0";
int main(){
((void(*)( ))code)();
}
" 代码是??返回指向函数的指针返回void ... ????那之后外面的()"
我对这一点感到困惑。
答案 0 :(得分:3)
const char code[] = "\x31\xc0";
int main(){
((void(*)( ))code)();
}
这是它的工作原理。 code
变量将衰减到第一个元素(\x31
)的地址。
然后,该地址将被转换为采用不确定参数的函数的地址,并且不返回任何内容。
它涵盖整个((void(*)( ))code)
位,并且到那里,你基本上构造了一个指向你的字符串的函数指针。
()
然后只需调用您指向的函数。
如果那是你要定位的英特尔CPU,31 c0
会反汇编到xor eax, eax
,但是当它从缓冲区的末端运行时,我并不期待很多快乐,它很可能会崩溃。标记字符串结尾的\x00
是add
指令的第一位,但至于之后的内容,则无法保证。
在字符串的末尾添加ret
指令可能使其更安全,但您可能必须检查生成的调用本身的汇编程序代码以找出哪个< / em> ret
应该被使用。
答案 1 :(得分:2)
这不是函数指针声明,它是一个函数指针 cast 和一个调用。
对演员表进行了一段时间的着色,我们((
某种类型)code)()
- 也就是说,将code
转换为某种类型(显然是函数指针),然后调用它。
那么演员阵容里面的类型是什么?它是void (*)()
。换句话说,指向函数的指针返回void
并且没有特别关注(它实际上可以接受参数,这要归功于C遗留,但在这种情况下它没有)。没什么,没什么。
在*
之后,如果这是一个声明,那么名称会去,但由于它是一个演员,所以这个类型是独立的,根本就没有名字。
答案 2 :(得分:2)
您感到困惑,因为它不是函数指针声明,而是函数调用后的强制转换。
(void (*)()) code
这会将code
转换为指向函数的指针,该函数使用未指定数量的参数返回任何内容。
((void (*)()) code)
这是括号括起来的上面的整个表达式;结果是一个函数指针。
(void (*)() code)();
这将调用由转换点“创建”的函数指针所在的函数。
这实际上是试图调用code
中构造的一些机器代码 - 这里你省略了其余部分,但31 c0是通常的xor eax,eax
。