- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
.global main
main:
call func
.string "/bin/sh"
func:
push %rsp
pop %rsi
pop %rdi
mov $0x00, %edx
mov $0x3b, %eax
syscall
我像上面那样为 execute/bin/sh 编写了程序集 lagunage我编译了它,但是当我尝试执行程序时,/bin/sh: 0: Can't open ????
发生了这个错误。它不执行/bin/sh。我想知道为什么我不能执行/bin/sh
I'm using Ubuntu 16.04 and x64 Architectures
最佳答案
由于以一种奇怪的方式使用 push/pop,您的代码不必要地难以理解,但是在 strace -f ./a.out
下运行您的程序以跟踪系统调用显示:
... dynamic linker and libc init stuff before main() is called ...
execve("/bin/sh", ["/bin/sh", "\211\307\350\t\222\1", "\367", "\367", 0x100000000, "\350\10"], [/* 0 vars */]) = -1 EFAULT (Bad address)
exit_group(0) = ?
+++ exited with 0 +++
所以在我的系统上,execve
返回错误,但程序成功退出。 IDK 你是如何获得 /bin/sh: 0: Can't open ????
.您的问题没有包含足够的信息来重现您的结果。但也许当你尝试时,堆栈恰好包含不同的垃圾。我用 gcc -g foo.S
构建了它。
在 main
返回失败后,执行落入 main
之后的任何 CRT 函数,它以 RET 指令结束。它还必须将 eax 归零,因为它将在 SYSCALL 之后为 -EFAULT
。
无论如何,你的 asm 相当于这个无用的代码:
int main(void) {
const char *p = "/bin/sh";
execve(p, &p, NULL);
}
注意 push %rsp; pop %rsi
等同于 mov %rsp, %rsi
。所以 RSI 持有一个指向 CALL 写入“返回地址”的堆栈内存的指针。
之后的另一个 POP 取消引用堆栈指针并将指向字符串的指针加载到 RDI。
使用 CALL 来推送字符串的地址真的很讨厌。 IDK你为什么要那样做。像正常人一样使用 MOV 即可。
如何正确执行此操作
# build with gcc -no-pie -g shell.S
#include <asm/unistd.h> // for __NR_execve
// #include <sys/syscall.h> // or include this glibc header for SYS_execve
main: # main(argc, argv, envp)
mov $shell, %edi # filename = shell
# argv = main's argv, already in rsi (not on the stack like in _start)
# leave RDX = envp
# xor %edx, %edx # envp = NULL
mov $__NR_execve, %eax # execve
syscall # execve(shell, argv, envp)
ret # in case the syscall fails
.section .rodata
shell:
.string "/bin/sh"
这有效,并且不会做任何奇怪的事情。
或者,以一种与位置无关的平面二进制文件的方式工作,并且不使用 main() 的 argv,因为您添加了该请求:
#include <asm/unistd.h> // for __NR_execve
// #include <sys/syscall.h> // or include this glibc header for SYS_execve
.globl main
main:
lea shell(%rip), %rdi # filename = shell
xor %edx, %edx # envp = NULL
push %rdx # or push $0
push %rdi
mov %rsp, %rsi # argv = { $shell, NULL } that we just pushed
mov $__NR_execve, %eax # execve(
syscall
ret # in case the syscall fails
shell: # still part of the .text section, and we don't use the absolute address of the label, only for a RIP-relative LEA.
.string "/bin/sh"
你的 RSI=RSP 想法不错,但是你忘了在 argv[]
数组的末尾添加一个终止 NULL 指针。
在获取 envp[]
作为 arg 的 main
之外,我们没有可在任何地方访问的已构建的 envp[]
方便,所以只需传递 NULL。在 Linux 上,这相当于将一个有效指针传递给一个以 NULL 结尾的空数组,即指向内存中 8 字节 0
的指针。
关于linux - shell 的 Ubuntu 16.04 汇编代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39848264/
我试图在图形模式下打印一个字符。通常当我打印我正在做的一个字符时: mov ah,14 ; ah=14 mov al,'x' int 10h ; print the character 这
我试图通过更改其中的一个字节来修改存储在内存中的字符串。我为此使用了 movb,但由于某种原因,给定内存位置的字节没有改变。 在 gdb 调试器上: 14 movb %al, (%r10) # nex
我一直在阅读一些汇编代码,并且开始发现调用指令实际上是与程序计数器相关的。 但是,每当我使用 Visual Studio 或 Windbg 进行调试时,它总是显示 call 0xFFFFFF ...这
我最近一直在使用 Visual C++ 中的内联汇编,我想知道是否可以直接向堆栈上的局部变量添加值,例如: push 5 add [esp], 7 这样做可以吗?我问这个问题是因为我在执行此操作时随机
我有下一个代码: mov al, -5 add al, 132 add al, 1 据我检查,溢出标志和进位标志将在第一个操作中设置,而在第二个操作中,仅设置溢出。 但我不明白为什么: 在无符号数中,
在 64 位 x86 汇编 nasm 中,如何将单个字节从寄存器移动到 .data 节中定义的内存位置? 我知道这有效 global _main section .data quotient db 0
我的汇编代码有问题。我想打印存储在寄存器 cx 中的数字,但是当我尝试打印它时,它打印的是 ascii 字符而不是 ascii 数字,所以我决定编写一个程序将 ascii char 转换为 ascii
为什么第 1B 行的跳转指令(例如)变成了 EBBD? 我知道“jmp”= EB但是BD是怎么计算的呢? 最佳答案 短跳转使用一个带符号的偏移量添加到 JMP 之后的指令地址。 例如,第一个 JMP
以下两者有什么区别: mov eax, [eax+4] 和 add eax, 4 mov eax, [eax] 如果不是,那么汇编器是否会选择哪个来进行某种优化? 最佳答案 这
看《The Shellcoder's Handbook》中的一些汇编和反汇编代码,发现一条指令的序列操作数是不一样的。 例如,在 assembly 上: mov ebx,0 并且,在反汇编时: mov
我有这个非常简单的汇编代码: start: add ax, 100 ; if ax overflow add to bx 1 jmp start 但我不知道如何检测 ax 寄存器溢出,有人可以帮
在 64 位 x86 汇编 nasm 中,如何将单个字节从寄存器移动到 .data 节中定义的内存位置? 我知道这有效 global _main section .data quotient db 0
我的汇编代码有问题。我想打印存储在寄存器 cx 中的数字,但是当我尝试打印它时,它打印的是 ascii 字符而不是 ascii 数字,所以我决定编写一个程序将 ascii char 转换为 ascii
我正在学习一些关于操作系统开发的教程,我发现了一篇关于多重引导 header 。这些是您必须定义的一些“神奇”值才能使用GRUB2。这些是命令: # Declare constants used f
为什么第 1B 行的跳转指令(例如)变成了 EBBD? 我知道“jmp”= EB但是BD是怎么计算的呢? 最佳答案 短跳转使用一个带符号的偏移量添加到 JMP 之后的指令地址。 例如,第一个 JMP
我正在尝试从内存中复制一些单词并使用汇编将其保存到另一个内存地址。我正在尝试为其编写代码,但我不确定其中的某些部分。我将简要描述我想要做什么。 源地址、目标地址和要复制的字数是函数的输入参数。 最佳答
当我们想要像这样创建一个初始化变量时: name db 'zara ali' 我们创建了一个字节大小变量,但我们在其中存储了一个字符串 这怎么可能?? 当我们使用这条指令时: MOV ecx, nam
我还是汇编的新手,我还不知道汇编中的许多命令代码。我想在 16 位寄存器中进行除法。我想打印它的内容。我知道我需要将寄存器的内容转换为 ASCII 进行打印,但同样,我的问题是除法。请帮我。 比如cx
使用有什么区别: c.eq.s $1, $2 bc1t L2 并使用: beq $1, $2, L2 如果他们做同样的事情,为什么有两种分支方式?如果它们不同,那么它们各自的好处是什么
源代码: int main() { int i; for(i=0, i : push rbp 2. 0x000055555555463b :
我是一名优秀的程序员,十分优秀!