任何人都可以清楚地解释这种反汇编吗?
Can anyone clearly explain this disassembly?
我是调试新手。我通过这段代码来说明它在执行时产生 shell 提示。
0: 31 c0 xor eax,eax
2: 50 push eax
3: 68 2f 2f 73 68 push 0x68732f2f
8: 68 2f 62 69 6e push 0x6e69622f
d: 89 e3 mov ebx,esp
f: 50 push eax
10: 53 push ebx
11: 89 e1 mov ecx,esp
13: b0 0b mov al,0xb
15: cd 80 int 0x80
请在这里解释清楚寄存器和内存中到底发生了什么。
一些硬编码值被压入堆栈,然后压入堆栈本身的指针。最后,EAX 寄存器保留最终加载的值,EBX、ECX 和 ESP 保留指向堆栈上的位置。
STACK (from highest address to lowest):
0
0x68732f2f
/-> /-> 0x6e69622f
| | 0 (arg[1])
| /-> \-- arg[0]
| |
EAX = 0xb | |
EBX(arg[0]) = ------/ |
ECX(&arg[0]) = --------/
ESP = Same as ECX
正如@PaulR 所建议的那样,那必须是一个 execve
并且在 C:
中它会接近于此
char *arg[2] = { "/bin//sh", 0 };
execve(arg[0], &arg[0], envp);
(envp
值在此代码片段中不可用。它可以是 EDX 中的任何值。如果这是整个程序,大概 EDX 在入口处为零 - 在 linux 上,空指针被解释为空环境列表。)
; Push 0 onto the stack
xor eax,eax ; a classic x86 optimization trick to clear/zero a register
push eax ; push that zeroed register onto the stack
; Push two constant values onto the stack
push 0x68732f2f ; 0x68732f2f == 1,752,379,183
push 0x6e69622f ; 0x6e69622f == 1,852,400,175
; Save the current value of the stack pointer (ESP) in the EBX register.
mov ebx,esp
; Push another 0 onto the stack (remember, EAX still contains 0).
push eax
; Push the value of the previous stack pointer onto the stack.
; (This is the same as pushing ESP+4, since the previous PUSH instruction
; implicitly decremented the stack pointer by 32 bits.)
push ebx
; Save the current value of the stack pointer (ESP) in the ECX register.
; (Presumably, it is either used again later in the function, or the interrupt
; that we're about to call requires some input value to be passed in ECX.)
mov ecx,esp
堆栈现在如下所示(在 x86 上,堆栈向下增长,因此最旧的值位于顶部):
╔═════════════════╗ direction of growth
║ 0 ║ |
╠═════════════════╣ |
║ 0x68732F2F ║ V
╠═════════════════╣
║ 0x6E69622F ║ <----
╠═════════════════╣ |
║ 0 ║ |
╠═════════════════╣ |
║ pointer to ... ║ ----
╚═════════════════╝ (lowest address)
; Place the value 0xB (11) in the AL register, which is the bottom 8 bits of EAX.
; The value in EAX specifies the sub-function to be executed when the interrupt is raised.
; (Note that setting only the bottom 8 bits is safe because we already zeroed EAX.)
mov al,0xb
; Raise an interrupt, passing control to interrupt vector 0x80.
; On Unix systems, this is how you make a system call.
; This is why we went through all the trouble of pushing those values onto
; the stack: this is how parameters are passed through to the system call.
int 0x80
不是 Unix 大师,我必须查找系统调用号(在本例中为 0xB)以了解它的作用。事实证明,0xB 映射到 sys_execve
,它执行指定的二进制文件。它需要一个指向要在 EBX
中执行的文件的指针,一个指向 ECX
中命令行参数的指针,以及一个指向 EDX
中环境块的指针。回想一下,在前面的代码中,这些寄存器都被初始化为包含指向堆栈上不同位置的指针。
我是调试新手。我通过这段代码来说明它在执行时产生 shell 提示。
0: 31 c0 xor eax,eax
2: 50 push eax
3: 68 2f 2f 73 68 push 0x68732f2f
8: 68 2f 62 69 6e push 0x6e69622f
d: 89 e3 mov ebx,esp
f: 50 push eax
10: 53 push ebx
11: 89 e1 mov ecx,esp
13: b0 0b mov al,0xb
15: cd 80 int 0x80
请在这里解释清楚寄存器和内存中到底发生了什么。
一些硬编码值被压入堆栈,然后压入堆栈本身的指针。最后,EAX 寄存器保留最终加载的值,EBX、ECX 和 ESP 保留指向堆栈上的位置。
STACK (from highest address to lowest):
0
0x68732f2f
/-> /-> 0x6e69622f
| | 0 (arg[1])
| /-> \-- arg[0]
| |
EAX = 0xb | |
EBX(arg[0]) = ------/ |
ECX(&arg[0]) = --------/
ESP = Same as ECX
正如@PaulR 所建议的那样,那必须是一个 execve
并且在 C:
char *arg[2] = { "/bin//sh", 0 };
execve(arg[0], &arg[0], envp);
(envp
值在此代码片段中不可用。它可以是 EDX 中的任何值。如果这是整个程序,大概 EDX 在入口处为零 - 在 linux 上,空指针被解释为空环境列表。)
; Push 0 onto the stack
xor eax,eax ; a classic x86 optimization trick to clear/zero a register
push eax ; push that zeroed register onto the stack
; Push two constant values onto the stack
push 0x68732f2f ; 0x68732f2f == 1,752,379,183
push 0x6e69622f ; 0x6e69622f == 1,852,400,175
; Save the current value of the stack pointer (ESP) in the EBX register.
mov ebx,esp
; Push another 0 onto the stack (remember, EAX still contains 0).
push eax
; Push the value of the previous stack pointer onto the stack.
; (This is the same as pushing ESP+4, since the previous PUSH instruction
; implicitly decremented the stack pointer by 32 bits.)
push ebx
; Save the current value of the stack pointer (ESP) in the ECX register.
; (Presumably, it is either used again later in the function, or the interrupt
; that we're about to call requires some input value to be passed in ECX.)
mov ecx,esp
堆栈现在如下所示(在 x86 上,堆栈向下增长,因此最旧的值位于顶部):
╔═════════════════╗ direction of growth
║ 0 ║ |
╠═════════════════╣ |
║ 0x68732F2F ║ V
╠═════════════════╣
║ 0x6E69622F ║ <----
╠═════════════════╣ |
║ 0 ║ |
╠═════════════════╣ |
║ pointer to ... ║ ----
╚═════════════════╝ (lowest address)
; Place the value 0xB (11) in the AL register, which is the bottom 8 bits of EAX.
; The value in EAX specifies the sub-function to be executed when the interrupt is raised.
; (Note that setting only the bottom 8 bits is safe because we already zeroed EAX.)
mov al,0xb
; Raise an interrupt, passing control to interrupt vector 0x80.
; On Unix systems, this is how you make a system call.
; This is why we went through all the trouble of pushing those values onto
; the stack: this is how parameters are passed through to the system call.
int 0x80
不是 Unix 大师,我必须查找系统调用号(在本例中为 0xB)以了解它的作用。事实证明,0xB 映射到 sys_execve
,它执行指定的二进制文件。它需要一个指向要在 EBX
中执行的文件的指针,一个指向 ECX
中命令行参数的指针,以及一个指向 EDX
中环境块的指针。回想一下,在前面的代码中,这些寄存器都被初始化为包含指向堆栈上不同位置的指针。