如何制作一个可以运行x86十六进制代码的C程序

时间:2012-06-28 20:52:56

标签: c x86 inline-assembly

我有一组十六进制代码转换为汇编指令,我想在C中创建可以执行这些代码的程序。

unsigned char rawData[5356] = {
    0x4C, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0C, 0x00, 0x00,
    0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x2E, 0x74, 0x65, 0x78,
    0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xB4, 0x05, 0x00, 0x00, 0xA4, 0x01, 0x00, 0x00, 0x68, 0x08, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x60,
    0x2E, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x40, 0x00, 0x30, 0xC0, 0x2E, 0x62, 0x73, 0x73, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x30, 0xC0, 0x2F, 0x34, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x14, 0x00, 0x00, 0x00, 0x58, 0x07, 0x00, 0x00, 0x32, 0x0C, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x10, 0x30, 0x60,
    0x2F, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x6C, 0x07, 0x00, 0x00,...and so on

5 个答案:

答案 0 :(得分:8)

使用x86是可能的。

这是一个小样本。使用write / exec权限分配页面并在那里复制您的操作码。

#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#endif


int main(){
    char opcodes[] = { ..... }; 

    #ifdef _WIN32

    HANDLE mem_handle = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0,  length, NULL);

    void* mem_map = MapViewOfFile( mem_handle, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0x0, 0x0, length);

    #else // posix
    void* mem_map = mmap(NULL, sizeof(opcodes), PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
    #endif

    memcpy(mem_map, opcodes, sizeof(opcodes));

    (( void(*)() )mem_map)();

    return 0;
}

对于POSIX系统,请使用mmap()调用。

还阅读有关蹦床的内容。请参阅链接:http://pages.cs.wisc.edu/~weinrich/papers/method_dispatch.pdf

你没有说明这是一个完整的程序还是一个单一的功能。相对/绝对地址可能存在问题。

小注:此代码也适用于启用了MMU的PowerPC和ARM。

答案 1 :(得分:4)

声明一个函数指针然后调用该函数。

void (*f)(void) = (void (*)(void)) rawData;
f();

当然这是未定义的行为,并不能保证有效。

答案 2 :(得分:4)

在某些平台上,您不能只声明:

void (*f)(void) = (void (*)(void)) rawData;

并尝试

f(); 

运行已修改的代码。

由于数据页面可能无法执行。定义函数而不关心其内容的便捷方法是向项目中添加.s文件。

将其编译为GNU as,并将其目标文件链接到最终程序。

例如:

<强>的main.c

int main()
{
    helloasm();
    return 0;
}

<强> x.s

代码就像C语句一样:printf("Hello ASM\n"); exit(11);

.global helloasm
helloasm:
.byte 0x48, 0xc7, 0xc7, 0x01, 0x00, 0x00, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6c, 0x6c
.byte 0x6f, 0x20, 0x41, 0x53, 0x4d, 0x21, 0x0a, 0x5e, 0x48, 0xc7, 0xc2, 0x0b, 0x00, 0x00, 0x00, 0xb8
.byte 0x01, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xbf, 0x0b, 0x00, 0x00, 0x00, 0xb8, 0x3c, 0x00, 0x00, 0x00
.byte 0x0f, 0x05

编译&amp;运行

as x.s -o x.o
gcc main.c x.o -o main
./main
Hello ASM!

此外,如果您的hexed代码数组位于二进制文件中,例如 a.bin

hexdump -C a.bin
00000000  48 c7 c7 01 00 00 00 e8  0b 00 00 00 48 65 6c 6c  |H...........Hell|
00000010  6f 20 41 53 4d 21 0a 5e  48 c7 c2 0b 00 00 00 b8  |o ASM!.^H.......|
00000020  01 00 00 00 0f 05 bf 0b  00 00 00 b8 3c 00 00 00  |............<...|
00000030  0f 05                                             |..|
00000032

然后您的 x.s 可能是:

.global helloasm
helloasm:
.incbin "a.bin"

答案 3 :(得分:1)

查看头文件elf.h。

您需要使用OPCodes完成这些结构中的字段。

在x86中有一个加载可执行文件的协议,但是在链接器将控件传递给加载的代码之后,它会崩溃。

在这里查看如何创建有效的可执行文件:

http://bellard.org/otcc/otccelfn.c

答案 4 :(得分:-1)

你难道不能将它们输出到文件然后使用system()电话吗?这样您就不必担心该数组是否遵循C调用约定。