Compilation 如何编写C/C++;有额外代码的程序?

Compilation 如何编写C/C++;有额外代码的程序?,compilation,Compilation,我想用代码洞做一些测试。给定C或C++程序,我如何使编译器(GCC,CLAN等)在二进制?中插入额外的代码洞穴? (我不想直接在代码中添加后门,而是在编译后插入代码。)这归结为在要放置任何有效负载的阶段有一块虚拟内存,它是a)可读+可执行的,b)可写的。第二个约束规定了根据需要在何处以及如何创建此类空间 堆栈分配 如果您只想在某个位置转储一点外壳代码,以便在进程运行时运行,您可以简单地堆栈分配一个数组: void my_vulnerable_function() { char foo[3

我想用代码洞做一些测试。给定C或C++程序,我如何使编译器(GCC,CLAN等)在二进制?

中插入额外的代码洞穴?
(我不想直接在代码中添加后门,而是在编译后插入代码。)

这归结为在要放置任何有效负载的阶段有一块虚拟内存,它是a)可读+可执行的,b)可写的。第二个约束规定了根据需要在何处以及如何创建此类空间

堆栈分配 如果您只想在某个位置转储一点外壳代码,以便在进程运行时运行,您可以简单地堆栈分配一个数组:

void my_vulnerable_function() {
    char foo[32];
    gets(foo);
}
要使此操作可行,请确保使用传递给GCC的
-fno stack protector
-z execstack
标志进行编译。您可能还希望关闭ASLR,以便堆栈位于可预测的位置。老实说,我从来没有试图使用clang故意使程序不安全,所以我不知道在这种情况下会使用什么标志

内存映射区 如果您想让某些东西更长寿,但在内存中,您可以
mmap
rwx访问的区域:

mmap(0, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
现在只需在其中编写一些代码,并在准备好后跳转到其中

可执行文件占位符 如果您希望在可执行文件中有一个占位符,该占位符是可执行的,并且可以使用十六进制编辑器进行编辑,只需确保编译器发出对字符串文字的引用,该引用:

int main() { 
    char* copyright = "Copyright 2019 John Zhau. All rights reserved.";
    puts(copyright);
}
然后可以在ELF文件本身中修补该字符串的内容。您的程序将需要跳转到字符串中的地址(关于ASLR/ELF加载执行的任何重新定位)。下面是一个简单的方法:

int main() { 
    char* copyright = "Copyright 2019 John Zhau. All rights reserved.";
    void (*foo)(void ) = ((void (*)(void)) copyright);
    foo();
    // or, more succinctly,
    (*(void(*)()) copyright)(); 
}

这会将指向字符串第一个字符的指针转换为指向函数的指针。通过该指针调用该“函数”将导致执行跳转到您的缓冲区——希望届时它将具有有效的外壳代码

这归结为在您想要放置任何有效负载的阶段有一个a)可读+可执行和b)可写的虚拟内存块。第二个约束规定了根据需要在何处以及如何创建此类空间

堆栈分配 如果您只想在某个位置转储一点外壳代码,以便在进程运行时运行,您可以简单地堆栈分配一个数组:

void my_vulnerable_function() {
    char foo[32];
    gets(foo);
}
要使此操作可行,请确保使用传递给GCC的
-fno stack protector
-z execstack
标志进行编译。您可能还希望关闭ASLR,以便堆栈位于可预测的位置。老实说,我从来没有试图使用clang故意使程序不安全,所以我不知道在这种情况下会使用什么标志

内存映射区 如果您想让某些东西更长寿,但在内存中,您可以
mmap
rwx访问的区域:

mmap(0, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
现在只需在其中编写一些代码,并在准备好后跳转到其中

可执行文件占位符 如果您希望在可执行文件中有一个占位符,该占位符是可执行的,并且可以使用十六进制编辑器进行编辑,只需确保编译器发出对字符串文字的引用,该引用:

int main() { 
    char* copyright = "Copyright 2019 John Zhau. All rights reserved.";
    puts(copyright);
}
然后可以在ELF文件本身中修补该字符串的内容。您的程序将需要跳转到字符串中的地址(关于ASLR/ELF加载执行的任何重新定位)。下面是一个简单的方法:

int main() { 
    char* copyright = "Copyright 2019 John Zhau. All rights reserved.";
    void (*foo)(void ) = ((void (*)(void)) copyright);
    foo();
    // or, more succinctly,
    (*(void(*)()) copyright)(); 
}

这会将指向字符串第一个字符的指针转换为指向函数的指针。通过该指针调用该“函数”将导致执行跳转到您的缓冲区——希望届时它将具有有效的外壳代码

似乎最快、最简单的方法是分配一个
null
数组。只需执行
char-cave[1000]=NULL
以及
chmod
chown
(而不是
mmap
)允许我执行注入的外壳代码?@JohnZhau您不能
chmod
一段虚拟内存。我的直觉是,
char-cave[1000]=NULL
将以.bss结束,它可能在您的系统上不可执行。通过使用字符串文字,您更有可能导致在已知可执行的.text区域中发出符号和内存。在这种情况下,您也不需要
mmap
mmap
严格适用于您希望在运行时动态创建这样一个洞穴的情况。@JohnZhau此外,我介绍的字符串方法实际上并不明显慢。我尝试了我自己的例子,它编译速度非常快,手工修补速度相当快,而且以后执行起来也很可靠。似乎最快、最简单的方法就是分配一个
null
数组。只需执行
char-cave[1000]=NULL
以及
chmod
chown
(而不是
mmap
)允许我执行注入的外壳代码?@JohnZhau您不能
chmod
一段虚拟内存。我的直觉是,
char-cave[1000]=NULL
将以.bss结束,它可能在您的系统上不可执行。通过使用字符串文字,您更有可能导致在已知可执行的.text区域中发出符号和内存。在这种情况下,您也不需要
mmap
mmap
严格适用于您希望在运行时动态创建这样一个洞穴的情况。@JohnZhau此外,我介绍的字符串方法实际上并不明显慢。我尝试了我自己的例子,编译速度非常快,手工修补速度相当快,之后执行起来也很可靠。