|
- 1. vi shellcode.c
- #include
- int main ( int argc, char * argv[] )
- {
- char * name[2];
- name[0] = "/bin/ksh";
- name[1] = NULL;
- execve( name[0], name, NULL );
- return 0;
- }
- 2. gcc -o shellcode -ggdb -static shellcode.c
- 3. gdb shellcode
- [scz@ /home/scz/src]> gdb shellcode
- GNU gdb 4.17.0.11 with Linux support
- This GDB was configured as "i386-redhat-linux"...
- (gdb) disassemble main <-- -- -- 输入
- Dump of assembler code for function main:
- 0x80481a0 : pushl %ebp
- 0x80481a1 : movl %esp,%ebp
- 0x80481a3 : subl $0x8,%esp
- 0x80481a6 : movl $0x806f308,0xfffffff8(%ebp)
- 0x80481ad : movl $0x0,0xfffffffc(%ebp)
- 0x80481b4 : pushl $0x0
- 0x80481b6 : leal 0xfffffff8(%ebp),%eax
- 0x80481b9 : pushl %eax
- 0x80481ba : movl 0xfffffff8(%ebp),%eax
- 0x80481bd : pushl %eax
- 0x80481be : call 0x804b9b0 <__execve>
- 0x80481c3 : addl $0xc,%esp
- 0x80481c6 : xorl %eax,%eax
- 0x80481c8 : jmp 0x80481d0
- 0x80481ca : leal 0x0(%esi),%esi
- 0x80481d0 : leave
- 0x80481d1 : ret
- End of assembler dump.
- (gdb) disas __execve <-- -- -- 输入
- Dump of assembler code for function __execve:
- 0x804b9b0 <__execve>: pushl %ebx
- 0x804b9b1 <__execve+1>: movl 0x10(%esp,1),%edx
- 0x804b9b5 <__execve+5>: movl 0xc(%esp,1),%ecx
- 0x804b9b9 <__execve+9>: movl 0x8(%esp,1),%ebx
- 0x804b9bd <__execve+13>: movl $0xb,%eax
- 0x804b9c2 <__execve+18>: int $0x80
- 0x804b9c4 <__execve+20>: popl %ebx
- 0x804b9c5 <__execve+21>: cmpl $0xfffff001,%eax
- 0x804b9ca <__execve+26>: jae 0x804bcb0 <__syscall_error>
- 0x804b9d0 <__execve+32>: ret
- End of assembler dump.
- 4. 研究 main() 函数的汇编代码
- 0x80481a0 : pushl %ebp # 保存原来的栈基指针
- # 栈基指针与堆栈指针不是一个概念
- # 栈基指针对应栈底,堆栈指针对应栈顶
- 0x80481a1 : movl %esp,%ebp # 修改得到新的栈基指针
- # 与我们以前在dos下汇编格式不一样
- # 这个语句是说把esp的值赋给ebp
- # 而在dos下,正好是反过来的,一定要注意
- 0x80481a3 : subl $0x8,%esp # 堆栈指针向栈顶移动八个字节
- # 用于分配局部变量的存储空间
- # 这里具体就是给 char * name[2] 预留空间
- # 因为每个字符指针占用4个字节,总共两个指针
- 0x80481a6 : movl $0x806f308,0xfffffff8(%ebp)
- # 将字符串"/bin/ksh"的地址拷贝到name[0]
- # name[0] = "/bin/ksh";
- # 0xfffffff8(%ebp) 就是 ebp - 8 的意思
- # 注意堆栈的增长方向以及局部变量的分配方向
- # 先分配name[0]后分配name[1]的空间
- 0x80481ad : movl $0x0,0xfffffffc(%ebp)
- # 将NULL拷贝到name[1]
- # name[1] = NULL;
- 0x80481b4 : pushl $0x0
- # 按从右到左的顺序将execve()的三个参数依次压栈
- # 首先压入 NULL (第三个参数)
- # 注意pushl将压入一个四字节长的0
- 0x80481b6 : leal 0xfffffff8(%ebp),%eax
- # 将 ebp - 8 本身放入eax寄存器中
- # leal的意思是取地址,而不是取值
- 0x80481b9 : pushl %eax # 其次压入 name
- 0x80481ba : movl 0xfffffff8(%ebp),%eax
- 0x80481bd : pushl %eax # 将 ebp - 8 本身放入eax寄存器中
- # 最后压入 name[0]
- # 即 "/bin/ksh" 字符串的地址
- 0x80481be : call 0x804b9b0 <__execve>
- # 开始调用 execve()
- # call指令首先会将返回地址压入堆栈
- 0x80481c3 : addl $0xc,%esp
- # esp + 12
- # 释放为了调用 execve() 而压入堆栈的内容
- 0x80481c6 : xorl %eax,%eax
- 0x80481c8 : jmp 0x80481d0
- 0x80481ca : leal 0x0(%esi),%esi
- 0x80481d0 : leave
- 0x80481d1 : ret
- 5. 研究 execve() 函数的执行过程
- Linux在寄存器里传递它的参数给系统调用,用软件中断跳到kernel模式(int $0x80)
- 0x804b9b0 <__execve>: pushl %ebx # ebx压栈
- 0x804b9b1 <__execve+1>: movl 0x10(%esp,1),%edx
- # 把 esp + 16 本身赋给edx
- # 为什么是16,因为栈顶现在是ebx
- # 下面依次是返回地址、name[0]、name、NULL
- # edx --> NULL
- 0x804b9b5 <__execve+5>: movl 0xc(%esp,1),%ecx
- # 把 esp + 12 本身赋给 ecx
- # ecx --> name
- # 命令的参数数组,包括命令自己
- 0x804b9b9 <__execve+9>: movl 0x8(%esp,1),%ebx
- # 把 esp + 8 本身赋给 ebx
- # ebx --> name[0]
- # 命令本身,"/bin/ksh"
- 0x804b9bd <__execve+13>: movl $0xb,%eax
- # 设置eax为0xb,这是syscall表中的索引
- # 0xb对应execve
- 0x804b9c2 <__execve+18>: int $0x80
- # 软件中断,转入kernel模式
- 0x804b9c4 <__execve+20>: popl %ebx
- # 恢复ebx
- 0x804b9c5 <__execve+21>: cmpl $0xfffff001,%eax
- 0x804b9ca <__execve+26>: jae 0x804bcb0 <__syscall_error>
- # 判断返回值,报告可能的系统调用错误
- 0x804b9d0 <__execve+32>: ret # execve() 调用返回
- # 该指令会用压在堆栈中的返回地址
- 从上面的分析可以看出,完成 execve() 系统调用,我们所要做的不过是这么几项而已:
- a) 在内存中有以NULL结尾的字符串"/bin/ksh"
- b) 在内存中有"/bin/ksh"的地址,其后是一个 unsigned long 型的NULL值
- c) 将0xb拷贝到寄存器EAX中
- d) 将"/bin/ksh"的地址拷贝到寄存器EBX中
- e) 将"/bin/ksh"地址的地址拷贝到寄存器ECX中
- f) 将 NULL 拷贝到寄存器EDX中
- g) 执行中断指令int $0x80
- 如果execve()调用失败的话,程序将继续从堆栈中获取指令并执行,而此时堆栈中的数据
- 是随机的,通常这个程序会core dump。我们希望如果execve调用失败的话,程序可以正
- 常退出,因此我们必须在execve调用后增加一个exit系统调用。
复制代码
这段东东偶看8大明白,请问斑竹要学习那方面的书?有推荐的满? |
|