逆向工程汇编代码到C
有人请给我提供帮助,分解下面的shell代码(在注释部分),并向我解释最后一行代码的作用?逆向工程汇编代码到C
# include <stdlib .h>
# include <stdio .h>
# include <string .h>
const char code [] =
"\x31\xc0" /* Line 1: xorl %eax, %eax */
"\x50" /* Line 2: pushl %eax */
"\x68""// sh" /* Line 3: pushl $0x68732f2f */
"\x68""/bin" /* Line 4: pushl $0x6e69622f */
"\x89\xe3" /* Line 5: movl %esp, %ebx */
"\x50" /* Line 6: pushl %eax */
"\x53" /* Line 7: pushl %ebx */
"\x89\xe1" /* Line 8: movl %esp, %ecx */
"\x99" /* Line 9: cdq */
"\xb0\x0b" /* Line 10: movb $0x0b, %al */
"\xcd\x80" /* Line 11: int $0x80 */;
int main (int argc , char ** argv) {
char buf [ sizeof (code)];
strcpy (buf , code);
((void (*)()) buf)(); /*I don't understand what this line is for*/
}
我读了一点关于gdb,但我不知道如何在这种情况下使用它。
P.S:我在一台x86-32 Ubuntu Linux机器上。
C可以做到这一点,但根据我的理解,没有反向编译器可以解决这个问题。
此代码进行系统调用。这就是int $0x80
。 它表示它是系统调用11之前的行。 其余指令为其设置参数。
xorl %eax, %eax ; clear the 32-bit A register to 0
pushl %eax ; push 32-bit 0 on the stack
pushl $0x68732f2f ; push two 32-bit constants on the stack
pushl $0x6e69622f
movl %esp, %ebx ; copy the stack pointer into the 32-bit B register
pushl %eax ; push another 0
pushl %ebx ; push the stack pointer
movl %esp, %ecx ; copy the stack pointer into the 32-bit C register
cdq ; A already has 0. This also sets D to zero, 32-bit
movb $0x0b, %al ; move a constant 11 into the lower 8 bits of the A register
int $0x80 ; and do the system call
如果这段代码是为了某种邪恶的目的而设计的,这并不会让我感到意外。 这是一种将一些未知代码引入程序并让计算机执行的方法。
谢谢你的队友,你的详细解释:) – sasuke
您已经拥有内嵌代码的反汇编代码,它在注释中。所以这部分有点混乱。
最终陈述将buf
转换为函数指针并调用代码。这是漏洞的实际使用。它也是(据我所知)未定义的行为,并且不能在防止执行随机区域内存的环境中工作。
这可能是第一个问题实际上是在标题。如果我的理解是正确的,OP要反编译的机器代码为C. – 2015-11-19 17:51:20
@unwind是:)不过我很想了解如何将在意见汇编代码看起来像在C语言或者至少是对的? – sasuke
程序集所做的是构建一个参数列表,以传递给操作系统调用来执行二进制文件(/bin/sh
)。
这两行将/bin/sh
推到堆栈上。
pushl $0x68732f2f
pushl $0x6e69622f
这些行根据calling convention放置指针/bin/sh
在参数寄存器。
movl %esp, %ebx
pushl %eax
pushl %ebx
movl %esp, %ecx
cdq
该行将系统调用号码11置于寄存器中作为中断的参数。
movb $0x0b, %al
最后一行调用操作系统。
int $0x80
C代码中的这行只是将缓冲区转换为函数指针,然后调用该函数。
((void (*)()) buf)();
注意,这里曾经是利用软件,然而类似的方法可以用来JIT编译代码的常用方法。
非常感谢你 – sasuke
我首先想到的第3行和第4行是设置/ bin/sh,但是第二个想法可能是sh/bin/X对于某些X我不太明白。实际上// sh部分看起来几乎就像一个评论?
我的预感是系统调用第11行是exec系统调用,并且前面的行为exec调用设置了参数。
要为V小心运行此代码,我会大胆地猜测;)
您可能要调查六角射线反汇编器,它可以(的排序)转换成机器代码/汇编(二是等价的)转换成C.
该代码是最有可能在进行呼叫到sys_execve()
内核函数
const char code [] =
"\x31\xc0" /* Line 1: xorl %eax, %eax */
"\x50" /* Line 2: pushl %eax */
"\x68""// sh" /* Line 3: pushl $0x68732f2f */
"\x68""/bin" /* Line 4: pushl $0x6e69622f */
"\x89\xe3" /* Line 5: movl %esp, %ebx */
"\x50" /* Line 6: pushl %eax */
"\x53" /* Line 7: pushl %ebx */
"\x89\xe1" /* Line 8: movl %esp, %ecx */
"\x99" /* Line 9: cdq */
"\xb0\x0b" /* Line 10: movb $0x0b, %al */
"\xcd\x80" /* Line 11: int $0x80 */;
- 线1被设定EAX寄存器为零,将使用d为 空字符串终止
- 线2,3和4所使用的堆栈作为临时缓冲器来存储空终止ASCII字符串“/ bin/sh的”;由于堆栈按递减顺序增长,所以字符相反,这就是为什么首先推送终结符的原因。
- 第5行被加载 到EBX堆栈指针,它在这一刻指向我们形成在前面的步骤的字符串的第一个字符的地址的当前值。 Ebx是
sys_execve()
期望字符串与要运行的文件的寄存器。 - 线6,和7被再次使用堆栈作为 临时缓冲器来保存一个空空终止ASCII字符串
- 管道8加载到ECX这个空字符串的其中
sys_execve()
期望命令行中的地址参数 - 9号线,没有它的目的
- 10号线的想法,负载十进制值11 AL注册,指定的
sys_execve()
功能是我们要调用 - 11个线触发interrput 0x80的一个 - 它的处理器是会采取行动的代码ually执行sys_execve()调用为我们
最后一行是在'BUF []'一个函数调用的代码。如果堆栈内存段的NX位被设置为安全性,它可能不起作用。 –
最后一行是函数调用:http://cdecl.org/?q=%28+void+%28%2a%29%28+%29%29+buf+。 – kay
@伊恩是对的。 '(void(*)())'是指向一个没有参数的函数指针的'buf'类型。你可以使用'gdb'。只需使用'ni'和'si'命令即可进入指令级别。 –