【问题标题】:How can I call an array as a function? [duplicate]如何将数组称为函数? [复制]
【发布时间】:2020-02-13 12:03:59
【问题描述】:

我有一个十六进制值表示汇编指令的数组。
我想将 HelloWorld 数组作为 printf 的参数推送。

(int)&HelloWorld 是获取我的数组地址的正确方法还是有更好的解决方案?
以及如何将 Code[] 作为函数调用?

我尝试使用函数指针,但程序跳转到内存中的其他位置并最终在无效指令处崩溃。

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <errno.h>

int main()
{
    int HelloWorld[15] =
    {
        // Hello World
        0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00
    };

    int Code[50] =
    {
        // PUSH [DWORD PTR] DS:<address of array HelloWorld>
        0xFF, 0x35, (int)&HelloWorld,
        // CALL <address of function printf>
        0xE8, (int)&printf,
        // ADD esp, 4
        0x83, 0xC4, 0x04,
        // RET
        0xC3
    };

    long unsigned int ProtectionCode = 0;

    // Change protection to read, write, execute
    int ChangeProtect = VirtualProtect(Code, 50, PAGE_EXECUTE_READWRITE,
                                       &ProtectionCode);

    if(ChangeProtect == 0)
    {
        printf("Error: %s\n", strerror(errno));
        return 1;
    }

    void (*CodePtr)() = &Code;
    (*CodePtr)();

    return 0;
}

感谢您的帮助。

【问题讨论】:

  • “我有一个十六进制值表示汇编指令的数组。” -- 汇编指令不应该是一堆整数。它们应该以包含指令的字符串形式出现,例如"mov eax, 3"。然后通过使用asm 关键字运行。您尝试的任何类似函数指针转换的行为都是未定义的行为,并且只有在您的编译器文档说明您可以这样做时才能可靠地工作。
  • 假设您使用 x86_32 或 x86_64:问题是,确实在内存中“0xff,0x35”存储为“ff 00 00 00 35 00 00 00 ...”,而您想要有“ff 35 ...”。当您尝试使用机器代码创建缓冲区时,您必须更加小心。您还可以尝试将缓冲区写入文件并使用 objdump 对其进行反汇编以验证其格式是否正确。否则,函数调用看起来没问题。
  • 这个问题重复了 Stack Overflow 上的其他问题;不时询问如何执行包含机器指令的数据。首先,答案取决于平台,因此您必须指定您使用的操作系统。其次,你必须得到正确的机器码。 int 的数组,或者最好是 unsigned int,可以用于具有固定指令大小的机器,但是对于 Intel,unsigned char 的数组是更好的方法。第三,您需要调用操作系统例程来更改页面映射并刷新指令缓存。
  • 这个问题确实比那些原版有更多的问题,所以可以重新打开它来解决这些问题。但它们是基本错误,可能应该单独讨论。使用(uintptr_t)&amp;HelloWorld 是获取地址以供动态准备的指令使用的一种方法,但可能还有其他方法。但是,对于 x86 架构,必须将指令流写入为字节序列,而不是 int,并且必须将地址(或偏移量或使用的任何内容)作为字节而不是整体复制到该序列中intuintptr_t.

标签: c arrays


【解决方案1】:

这个版本在我的 Windows 上运行良好:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <errno.h>


char HelloWorld[15] =
{
    // Hello World
    0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00
};


void  __attribute__((used)) foo(void)
{
    int (*p)(const char *, ...) = printf;
    p(HelloWorld);
}


int main()
{

    unsigned char Code[] ={

        0x55,
        0x89, 0xe5,
        0x83, 0xec, 0x28,
        0xc7, 0x45,  0xf4,  0x78,  0x8c,  0x40, 0x00,
        0xc7, 0x04, 0x24, 0x04, 0xa0, 0x40, 0x00,
        0x8b, 0x45, 0xf4,
        0xff, 0xd0,
        0x90,
        0xc9,
        0xc3,
    };

    long unsigned int ProtectionCode = 0;

    // Change protection to read, write, execute
    int ChangeProtect = VirtualProtect(Code, 50, PAGE_EXECUTE_READWRITE,
                                       &ProtectionCode);

    if(ChangeProtect == 0)
    {
        printf("Error: %s\n", strerror(errno));
        return 1;
    }

    void (*CodePtr)() = &Code;
    (*CodePtr)();

    return 0;
}

foo 只是从 :) 中获取代码

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-05
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多