8

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

5 回答 5

8

使用 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。

于 2012-06-28T22:09:11.537 回答
4

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

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

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

于 2012-06-28T20:56:15.527 回答
4

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

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

并尝试

f(); 

运行十六进制代码。

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

用 GNU as 编译它,并将它的目标文件链接到您的最终程序。

例如:

主程序

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

xs

代码像 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

编译运行

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

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

那么你的xs可能是:

.global helloasm
helloasm:
.incbin "a.bin"
于 2012-06-29T07:02:47.523 回答
1

查看头文件 elf.h 。

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

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

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

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

于 2012-06-28T21:12:53.440 回答
-1

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

于 2012-06-28T20:56:23.897 回答