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



我有一个十六进制代码数组,可以转换为汇编指令,我想用 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

使用 x86 是可能的。

这是一个小样本。分配具有写入/执行权限的页面,并将操作码复制到该页面。

#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。

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

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

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

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

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

并尝试

f(); 

以运行十六进制代码。

因为数据页可能无法执行。在不关心函数内容的情况下定义函数的一种便捷方法是将.s文件添加到项目中。

用 GNU 作为编译它,并将其目标文件链接到你的最终程序。

例如:

主.c

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

X.S

代码的工作方式类似于 C 语句:printf("Hello ASMn"); 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

编译和运行

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

此外,如果您的十六进制代码数组位于二进制文件中,例如.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"

查看头文件 elf.h 。

您需要使用 OPCodes 填写这些结构中的字段。

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

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

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

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

最新更新