将(const char *)分配给执行十六进制代码的函数指针

时间:2014-01-08 18:42:23

标签: c function pointers

我找到了一个如下所示的C代码:

#include <stdio.h>

char code[] =
"\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42"
"\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03"
"\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b"
"\x34\xaf\x01\xc6\x45\x81\x3e\x46\x61\x74\x61\x75\xf2\x81\x7e"
"\x08\x45\x78\x69\x74\x75\xe9\x8b\x7a\x24\x01\xc7\x66\x8b\x2c"
"\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf\xfc\x01\xc7\x68\x72\x6c"
"\x64\x01\x68\x6c\x6f\x57\x6f\x68\x20\x48\x65\x6c\x89\xe1\xfe"
"\x49\x0b\x31\xc0\x51\x50\xff\xd7";

int main(void)
{
    int (*func)();
    func = (int(*)()) code;
    (int)(*func)();
    return 0;
}

对于给定的HEX CODE,此程序运行良好并打印(“HelloWorld”)。我以为HEX CODE是一些机器指令,通过调用一个指向我们正在执行该代码的CODE的函数指针。

我的想法是对的吗?有什么可以改善的吗?

如何生成此HEX代码?

提前坦克。

3 个答案:

答案 0 :(得分:3)

你是正确的,通过强制像这样的函数指针,你调用写成十六进制字符串变量的机器指令。

我怀疑像这样的程序自2005年左右起就适用于任何CPU。

在大多数RISC CPU(如ARM)以及支持64位的所有Intel和AMD CPU上,内存页面都有一个No Execute位。或反向执行位。

在没有Execute位的内存页面上,CPU不会运行代码。编译器不会将变量放入可执行的内存页面。

为了运行注入的shell代码,攻击者现在必须使用&#34;返回libc&#34;或函数指针覆盖攻击,这些攻击设置为调用mprotect或VirtualProtect以在其shell代码上设置执行位。要么将其注入可执行空间,例如Java,.NET或Javascript JIT编译器,请使用。

安全加强的内核将拒绝调用mprotect的能力。一旦程序的地址空间由动态库加载器设置,它就会设置一个安全标志,并且不会创建新的可执行页面。

答案 1 :(得分:2)

为了使它始终有效,您可以使用malloc等分配一些executable_readwrite空间并将代码放在那里然后执行它。然后就不存在任何访问冲突错误。

void main(int argc, char** argv)
{
    void* PointerToNewMemoryRegion=0;
    void (*FunctionPointer) ();
    PointerToNewMemoryRegion=VirtualAlloc(RandomPointer,113,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
    if (PointerToNewMemoryRegion == NULL)
    {
        std::cout<<"Failed to Allocate Memory region Error code: "<<GetLastError();
        return;
    }
    memcpy(PointerToNewMemoryRegion, code,113);
    FunctionPointer = (void(*)()) PointerToNewMemoryRegion;
    (void)(*FunctionPointer) ();


    VirtualFree(PointerToNewMemoryRegion,113,MEM_DECOMMIT)

}

但代码永远不会返回到我的代码执行所以我的最后一行是没有意义的。所以我的代码有内存泄漏。

答案 2 :(得分:1)

从“一般C”的角度来问这个问题并不是那么有意义。

首先,您的代码存在许多重大问题:

  • 文字"\xFF\xFF\xFF"等于0xFFFFFF00,而不是0x00FFFFFF,可能是也可能不是。
  • 这个十六进制代码的含义是什么,如果它有意义,它依赖于字节序,也取决于给定CPU的地址总线宽度。
  • 正如其他人所提到的,C不支持或定义函数指针和常规指针之间的转换,C标准将其列为“公共扩展”。

话虽这么说,像这样的代码只有一个目的,那就是嵌入式系统中使用的各种形式的引导加载程序和自更新软件。

假设您有一个启动加载程序,该程序的任务是在执行所述程序本身的闪存的同一段中重新编程某些东西。由于内存硬件的工作方式,这是不可能的。因此,为了这样做,您必须从RAM执行实际的闪存编程例程。由于十六进制乱码数组存储在RAM中,程序可以使用函数指针技巧从那里执行,假设C编译器具有允许强制转换的非标准扩展。

至于如何生成代码,您可以在汇编程序中全部编写代码,然后手动将汇编程序指令转换为操作代码(非常繁琐)。或者更有可能的是,您在C中编写函数然后将其反汇编并从反汇编中复制/粘贴操作码。

后者更危险,因为获得这样的代码的关键部分是调用约定:你必须绝对确定函数在调用时完成堆栈/取消堆栈,并在完成时将其恢复,恢复所使用的任何CPU寄存器的内容等。这可能会强制您无论如何在汇编程序中编写部分函数。不用说,代码将完全不可移植。