【发布时间】:2019-05-11 17:32:28
【问题描述】:
我尝试制作一个程序,您可以在其中放入一些十六进制的组装程序并运行它。
使用像int3 这样的简单指令它可以工作,但是当我尝试使用系统调用退出程序时它不起作用。
我用rasm2组装它
mov eax, 1
mov ebx, 12
int 0x80
然后把它作为参数./Programm b801000000bb0c000000cd80 1
但我遇到了段错误。
这是我的代码:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
char *base16dec(char *b16str) {
size_t stingrlength = strlen(b16str);
char *decodedstr = malloc(stingrlength / 2);
for (size_t i = 0; i < stingrlength; i += 2) {
u_int8_t num = 0;
char stringIn[3];
stringIn[0] = b16str[i];
stringIn[1] = b16str[i+1];
stringIn[2] = 0;
sscanf(stringIn, "%hhx", &num);
decodedstr[i/2] = (char) num;
}
return decodedstr;
}
这会解码十六进制字符串
int main(int argc, char *argv[]) {
char *dirstr = "XXXXXX";
char dir[7];
strcpy(dir, dirstr);
int fd = mkstemp(dir);
if (fd == -1) {
dirstr = "/tmp/XXXXXX";
char dir[12];
strcpy(dir, dirstr);
fd = mkstemp(dir);
}
unlink(dir);
这将创建存储程序集的 tmp 文件
char *stringIn;
if (argc == 2) {
stringIn = malloc(strlen(argv[1]));
strcpy(stringIn, argv[1]);
} else if (argc == 3) {
u_int8_t num = 0;
sscanf(argv[2], "%hhu", &num);
if (num == 1) {
char *done = base16dec(argv[1]);
stringIn = malloc(strlen(done));
strcpy(stringIn, done);
} else {
stringIn = malloc(strlen(argv[1]));
strcpy(stringIn, argv[1]);
}
} else {
stringIn = malloc(1024);
scanf("%s", stringIn);
char *done = base16dec(stringIn);
stringIn = malloc(strlen(done));
strcpy(stringIn, done);
}
这会解析输入并将其复制到stringIn
ftruncate(fd, strlen(stringIn));
u_int8_t *code = mmap(NULL, strlen(stringIn), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE , fd, 0);
这会扩展 tmp 文件并使其可执行并创建一个指向它的指针,名为 code
for (int i = 0; i < 1024; i++) {
code[i] = (u_int8_t) stringIn[i];
}
这会将汇编字节复制到code
#if __x86_64__
__asm__(
"mov %0, %%rbx\n"
"jmp *%%rbx"
:
: "g" (code)
: "memory"
);
#elif __i386__
__asm__(
"mov %0, %%ebx\n"
"jmp *%%ebx"
:
: "r" (code)
);
#else
#endif
这会跳转到程序集
return 0;
}
编辑:
我无法使用 gdb 调试 shellcode
我使用 64 位 Linux Mint
我尝试使用strcpy复制0
【问题讨论】:
-
您的代码段错误在哪条指令上?您所有的系统调用是否都返回成功?您是否使用
strace来确保所有系统调用都成功? edit 使其成为minimal reproducible example。 (顺便说一句,一个 tmp 文件似乎有点矫枉过正。只是mmap(MAP_ANONYMOUS)一个可执行 + 可写页面。此外,如果您在 Windows 上的 WSL 上使用 x86-64,32 位int 0x80系统调用不起作用,只有 64 位syscallABI。 -
“我无法使用 gdb 调试 shellcode” - 为什么不呢?无论如何使用
"g" (code)是一个非常糟糕的主意。不知道编译器将在那里使用什么。为什么不直接使用函数指针? -
@MaxSilvester: 转换为
(void*),因为在 C 中您可以将其分配给任何东西,或者使用(void (*)(void))code转换为指向函数的指针。当然char*不能隐式转换为函数指针,编译器可以保护您免受这种情况的影响,就像将float *分配给int*变量而不进行强制转换一样。如果您希望编译器不碍事,请使用void*。 -
您仍然必须使用
MAP_PRIVATE和MAP_ANONYMOUS,即MAP_PRIVATE|MAP_ANONYMOUS。当您传递 justMAP_ANONYMOUS时,mmap返回-1并带有 errno=EINVAL 或类似的东西。 使用strace查看 glibc malloc 和/或 CRT 启动代码的作用,并查看您自己的系统调用失败时出现的错误。在像这样的玩具实验中,strace是编写检查错误的代码的快速而肮脏的替代品。做一个或另一个是必要的,以排除这种愚蠢的错误。 -
使用
x/10i 0xwhatever之类的东西来反汇编。