警告:这是一个漏洞利用。不要执行此代码。
//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.
}
谁能给我一个更好的解释?
最佳答案
显然,这段代码试图改变堆栈,以便当 main
函数返回,程序执行不会定期返回运行时库(通常会终止程序),而是跳转到保存在 shellcode
中的代码中。大批。
1) int *ret;
在堆栈上定义一个变量,就在 main
的下面函数的参数。
2) ret = (int *)&ret + 2;
让 ret
变量指向 int *
即放置两个 int
s 以上 ret
在堆栈上。据说这就是返回地址所在的位置,当 main
时程序将继续返回。
2) (*ret) = (int)shellcode;
返回地址设置为shellcode
的地址数组的内容,所以 shellcode
的内容将在 main
时执行返回。shellcode
似乎包含可能执行系统调用以启动 /bin/sh
的机器指令.我可能是错的,因为我实际上并没有拆卸 shellcode
.
附注:此代码依赖于机器和编译器,可能无法在所有平台上运行。
回复您的第二个问题:
and what happens if I use ret=(int)&ret +2 and why did we add 2? why not 3 or 4??? and I think that int is 4 bytes so 2 will be 8bytes no?
ret
被声明为 int*
,因此分配一个 int
(例如 (int)&ret
)将是一个错误。至于为什么添加 2 而不是任何其他数字:显然是因为此代码假定返回地址将位于堆栈上的该位置。考虑以下:ret
)更高的内存地址。 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
——但这些在这里并不重要。)当函数执行时,堆栈指针指向 ret
.返回地址位于“上方”的 64 位 ret
,对应于 + 2
在ret = (int*)&ret + 2;
是
+ 2
因为 ret
是 int*
, 和 int
是 32 位,因此加 2 表示将其设置到 (int*)&ret
上方 2 × 32 位(=64 位)的内存位置...这将是返回地址的位置,如果上一段中的所有假设都是正确的。游览:让我用英特尔汇编语言演示如何调用 C 函数(如果我没记错的话——我不是这个主题的专家,所以我可能是错的):
// 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
在 main 中,可能会发生以下情况:
// create a new stack frame and make room for local variables:
push ebp
mov ebp, esp
sub esp, 4
// access return address:
mov edi, ss:[ebp+4]
// access argument 'argc'
mov eax, ss:[ebp+8]
// access argument 'argv'
mov ebx, ss:[ebp+12]
// access local variable 'ret'
mov edx, ss:[ebp-4]
...
// restore stack frame and return to caller (by popping the return address)
mov esp, ebp
pop ebp
retf
另见: procedure call sequence in C的说明对这个话题的另一种解释。
关于谁能给我解释一下这段代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2705854/