【问题标题】:Loading raw code from C program从 C 程序加载原始代码
【发布时间】:2011-07-02 23:16:11
【问题描述】:

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

加载代码的程序:

#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

【问题讨论】:

  • 当你说没有显示任何文本时,你的意思是它不打印“test”还是它甚至不打印“[EXEC]”行?
  • +1 个有趣的问题,不过我希望这不会被用于任何恶意行为。
  • -S 添加到对objcopy 的调用中是否有帮助?
  • -S 应该没有帮助 - 代码有缺陷......
  • >当你说没有显示文本时,你的意思是它不打印“test”还是它甚至不打印“[EXEC]”行? “[EXEC]”之间必须有“测试”

标签: c linux assembly system-calls shellcode


【解决方案1】:

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

更多信息请参见The Technique of Writing Portable Shell Code

【讨论】:

  • 是的,当您通常链接和加载代码时(例如,使用 dlopen),加载器所做的一件事就是修复代码中的地址引用以匹配那些实际加载到内存中的位置。手动加载和执行代码,您将不得不手动进行这些修复,或者坚持不使用绝对地址。
  • @Alexey:您可以使用 call 将指令指针压入堆栈并以这种方式获取您的 shellcode 的地址(参见链接文档中的清单 11.1)
  • 链接下来先生:(
【解决方案2】:

您没有指定 CPU 的详细信息,但您可能与 NX bit 发生冲突。我希望您的代码能够 SEGFAULT,而不是运行完成。

这正是在英特尔至强 E5410 上运行的我的机器(Linux 2.6.32-28-generic #55-Ubuntu SMP Mon Jan Jan 10 23:42:43 UTC 2011 x86_64 GNU/Linux)上发生的事情。

【讨论】:

  • 我在内核中禁用了 NX 位。代码总是成功执行,我运行了大约 30 次(我也在 gdb 中检查过)
【解决方案3】:

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

阅读此处了解如何将代码编译为 .so、在程序中动态加载它以及从中执行导出的函数。

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

【讨论】:

  • 我想学习如何手动加载代码,只是为了好玩(也许是为了将来的shellcode测试)
【解决方案4】:

一件事:你应该以二进制形式打开文件。

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

【讨论】:

  • 在 POSIX 系统上无关紧要:“字符 'b' 无效,但允许符合 ISO C 标准。”
猜你喜欢
  • 2012-03-29
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 2013-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-30
相关资源
最近更新 更多