[英]What does void(*)() mean in code
我今天在一些 fb 个人资料中看到了这段代码,但无法理解它是什么以及它是如何工作的:-
(*(void(*)()) shellcode)()
有人可以解释一下,上面的代码是什么意思?
完整代码片段如下:-
#include <stdio.h>
#include <string.h>
char *shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
"\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(void)
{
fprintf(stdout,"Length: %d\n",strlen(shellcode));
(*(void(*)()) shellcode)();
return 0;
}
它是对函数指针的强制转换(没有返回结果,也没有参数)。 我更喜欢使用typedef
来定义此类函数的签名:
typedef void plainsig_t(void);
然后简单地编码
(*(plainsig_t*)shellcode) ();
对于函数指针,您无需取消引用它们,因此仅需编写代码即可:
((plainsig_t*) shellcode) ();
它基本上会调用其机器代码位于shellcode
存储区中的函数。
顺便说一句,这不是严格可移植的C。原则上,不能保证可以将数据指针转换为函数指针。 (在某些奇怪的处理器上,例如嵌入式微控制器,DSP,1970年代的计算机上,代码和数据位于不同的地址空间中,或具有不同的指针大小,等等。) 但是大多数常见的处理器和ABI(x86-64 / Linux,ARM / Android等)具有用于代码和数据的相同地址空间,并接受将函数指针转换为数据指针,反之亦然。
这是C和C ++不同的地方。
在C语言中,它表示指向函数的指针,该函数返回void并接受未指定类型的未指定数量的参数。
在C ++中,它表示指向返回空值且不带参数的函数的指针。
整个表达式都使用shellcode
的地址,将其转换为指向函数类型的指针,然后调用该函数-即,执行该字符串中的操作码。
void(*)()
意思是“指向不带参数的void函数的指针。” 线
(*(void(*)()) shellcode)();
是将shellcode
强制转换为此类函数指针,然后取消对该指针的引用(实际上不是必需的),然后调用该函数。
这是一个函数指针。 类型说明符匹配声明; 因此,函数void f()
类型为void()
; 并且指向函数void (*pf)()
的指针的类型为void(*)()
。
注意,与函数声明一样,它在C和C ++中的含义稍有不同。 在C中,空括号表示它具有未指定数量的参数,而在C ++中,表示没有参数。 但是,这不会影响代码的含义。
此代码将数组重新解释为函数,然后尝试调用它。 据推测,该数组包含用于打印消息,格式化硬盘或其他内容的机器代码。 在大多数现代平台上,这将导致保护错误,因为默认情况下(希望)静态数据不可执行。
在 C 中,变量声明为int foo;
, 声明一个 function 我们使用int foo( );
这意味着 function 的返回类型是 int。 我们使用*foo
来声明一个指针。
在表达式(*(void(*)())0)()
中我们可以看到
假设变量fp
是一个 function 指针,我们可以使用(*fp)( );
调用function,因为fp
是一个function指针,而*fp
是指针指向的function,所以(*fp)( );
可拨打function。
假设fp
是一个非返回值类型的指针,那么调用它的方式就是void (*fp)( )
,那么fp
变量的类型就是void (*)( )
。
如果我们要将此类型转换为常量shellcode
,那么我们使用( void (*)() ) shellcode
。
现在 shellcode 已转换为类型,为了调用我们使用的 shellcode
( ( void (*)() ) shellcode )();
注意:我们可以用typedef来代替上面表达式的类型名
例如: typedef void (*ff)( );
因此,调用function的方式可以写成:
(*(ff) shellcode ) ( );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.