【发布时间】:2016-11-11 18:13:19
【问题描述】:
我知道 C 编译器能够获取独立代码,并为它们所针对的特定系统生成独立的 shellcode。
例如,在anon.c 中给出以下内容:
int give3() {
return 3;
}
我可以跑
gcc anon.c -o anon.obj -c objdump -D anon.obj
这给了我(在 MinGW 上):
anon1.obj: file format pe-i386
Disassembly of section .text:
00000000 <_give3>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: b8 03 00 00 00 mov $0x3,%eax
8: 5d pop %ebp
9: c3 ret
a: 90 nop
b: 90 nop
所以我可以像这样制作 main:
main.c
#include <stdio.h>
#include <stdint.h>
int main(int argc, char **argv)
{
uint8_t shellcode[] = {
0x55,
0x89, 0xe5,
0xb8, 0x03, 0x00, 0x00, 0x00,
0x5d, 0xc3,
0x90,
0x90
};
int (*p_give3)() = (int (*)())shellcode;
printf("%d.\n", (*p_give3)());
}
我的问题是,自动化转换自包含匿名函数的过程是否可行,该函数不引用不在其范围或参数中的任何内容?
例如:
#include <stdio.h>
#include <stdint.h>
int main(int argc, char **argv)
{
uint8_t shellcode[] = [@[
int anonymous() {
return 3;
}
]];
int (*p_give3)() = (int (*)())shellcode;
printf("%d.\n", (*p_give3)());
}
哪个会将文本编译成shellcode,并将其放入缓冲区?
我问的原因是因为我真的很喜欢写C,但是做pthreads,callbacks是非常痛苦的;并且一旦你比 C 更上一层以获得“lambdas”的概念,你就会失去你的语言的 ABI(例如,C++ 有 lambda,但是你在 C++ 中所做的一切都突然依赖于实现)和“Lisplike”脚本插件(例如插入 Lisp、Perl、JavaScript/V8,任何其他已经知道如何泛化回调的运行时)使回调非常容易,但也比折腾 shellcode 更昂贵。
如果这是可行的,那么可以将只调用一次的函数放入调用它的函数体中,从而减少全局范围污染。这也意味着您不需要为您所针对的每个系统手动生成 shellcode,因为每个系统的 C 编译器已经知道如何将自包含的 C 转换为汇编,那么您为什么要这样做,并破坏您的可读性拥有一堆二进制 blob 的代码。
所以问题是:这是否实用(对于完全自包含的函数,例如,即使他们想调用 puts,puts 也必须作为参数给出或在参数的哈希表/结构中给出)?还是有什么问题阻碍了它的实用性?
【问题讨论】:
-
我看不出引入未定义的行为比简单地编写命名函数更可取。
-
因为在代码中只调用一次的函数不应该污染全局范围。想象一个回调繁重的程序;有了这个,您可以轻松创建 5 个回调 pthread,而不会产生任何全局污染。是什么导致了未定义的行为?
-
GCC 有一个nested functions 扩展,但我不知道它们是否适用于 (p) 线程,尽管我对此表示怀疑。
-
您知道您可以将函数声明为
static,所以它不会污染全局范围? -
您在这里严重误用了“shellcode”一词。 Shellcode 是用于利用漏洞的特制机器代码。您所说的只是机器代码。正如 EOF 指出的那样,您尝试做的事情毫无意义,您可以只使用静态函数。与您提出的替代方案会造成的可怕的不可维护的混乱相比,这会“污染”文件范围名称空间这一事实是一个微不足道的问题。
标签: c assembly lambda functional-programming shellcode