问题 从C程序加载原始代码


我正在编写一个程序来加载和执行文件中的代码。 但是我遇到了一个问题:“写”系统调用不起作用。 代码成功加载并执行,但不会在屏幕上显示任何文本。

加载代码的程序:

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

int main(int argc,char* argv[])
{
    unsigned int f_size = 0;
    unsigned char* code_buf = NULL;
    void (*func_call)(void) = NULL;

    if(argc < 2) 
    {
        printf("Usage: %s <FILE>\n",argv[0]);
        return 1;
    }

    FILE* fp = fopen(argv[1],"rb");
    if(!fp)
    {
        printf("Error while opening this file: %s\n",argv[1]);
        return 1;
    }

    unsigned int fsize = 0;
    fseek(fp,0,SEEK_END);
    fsize = ftell(fp);
    fseek(fp,0,SEEK_SET);
    if(fsize < 4)
    {
        printf("Code size must be > 4 bytes\n");
        return 1;
    }

    code_buf = (unsigned char*) malloc(sizeof(unsigned char)*fsize);
    if(fread(code_buf,fsize,1,fp)<1)
    {
        printf("Error while reading file: %s\n",argv[1]);
        free(code_buf);
        return 1;
    }
    func_call = (void (*)(void)) code_buf;

    printf("[EXEC] Binary is loaded\n"
           "\tFirst 2 bytes: 0x%x 0x%x\n"
           "\tLast 2 bytes: 0x%x 0x%x\n",
           code_buf[0],code_buf[1],
           code_buf[fsize-2],code_buf[fsize-1]);
    printf("[EXEC] Starting code...\n");
    (*func_call)();
    printf("[EXEC] Code executed!\n");

    free(code_buf);

    return 0;
}

我尝试通过此程序执行的代码(test.s):

.text
    movl    $4, %eax
    movl    $1, %ebx
    movl    $str, %ecx
    movl    $5, %edx
    int     $0x80
    jmp end
    str:
        .string "test\n"
    end:
    ret

这是我如何编译它:

 gcc -c test.s
 objcopy -O binary test.o test.bin

解决了,感谢@Christoph

有工作代码:

.text
    call start
    str:
        .string "test\n"
    start:
    movl    $4, %eax
    movl    $1, %ebx
    pop     %ecx
    movl    $5, %edx
    int     $0x80
    ret

7310
2018-02-23 18:01


起源

当你说没有显示文字时,你是说它不打印“测试”或者它甚至不打印“[EXEC]”行? - AShelly
+1有趣的问题,虽然我希望这不是用于任何恶意的.. - BlueRaja - Danny Pflughoeft
它有助于添加 -S 致电 objcopy? - Christoph
-S 不应该帮忙 - 代码有缺陷...... - Christoph
>当你说没有显示文字时,你的意思是它不打印“测试”或它甚至不打印“[EXEC]”行? “[EXEC]”之间必须有“测试” - Alexey


答案:


您的方法无法工作:shellcode必须与位置无关,但您的代码指的是绝对地址 str。无条件跳转也可以是相对的或绝对的:确保获得相对的verison(x86上的操作码EB和E9)。

看到 编写便携式Shell代码的技巧 了解更多信息。


9
2018-02-23 18:48



是的,当您正常链接和加载代码时(例如,使用dlopen),加载程序执行的操作之一就是修复代码中的地址引用以匹配实际加载到内存中的位置。手动加载和执行代码,您必须手动执行这些修复,或坚持不使用绝对地址。 - bdk
看起来你是对的!谢谢。 - Alexey
@Alexey:你可以用 call 将指令指针推送到堆栈并以这种方式获取shellcode的地址(参见链接文档中的清单11.1) - Christoph


您没有指定CPU的详细信息,但可能与您的CPU有关 NX位。我希望您的代码可以使用SEGFAULT,而不是运行完成。

这正是我在Intel Xeon E5410上运行的盒子(Linux 2.6.32-28-generic#55-Ubuntu SMP Mon Jan 10 23:42:43 UTC 2011 x86_64 GNU / Linux)上发生的事情。


3
2018-02-23 18:14



我在内核中禁用了NX位。代码总是成功执行,我运行了大约30次(我也在gdb中检查过它) - Alexey


一件事:您应该将文件打开为二进制文件。

FILE* fp = fopen(argv[1],"rb"); 

2
2018-02-23 18:15



在POSIX系统上无关紧要:“字符'b'不起作用,但允许符合ISO C标准。” - Christoph


为什么不使用.so文件动态加载代码?您是在测试安全方案还是真的尝试动态加载和运行代码?

在这里阅读如何将代码编译为.so,在程序中动态加载它,并从中执行导出的函数。

http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html


1
2018-02-23 18:19



我想学习如何手动加载代码,只是为了好玩(以及将来的shellcode测试) - Alexey