【原创】2015第2届移动安全挑战赛iOS第二题分析
2015-10-21 本文已影响505人
crean
creantan/P.Y.G 转载请注明出处
第二题题目如下
环境:iPhone5C(A1529) iOS 8.4 kernelcache ,解密后的kernelcache见附件
求得下列地址(减去kaslr):
(1)设备/dev/random,对应结构体cdevsw中d_read, d_write, d_ioctl在题目给出kernelcache中的地址。
(2)设备/dev/pf,对应结构体cdevsw中d_read, d_write, d_ioctl在题目给出kernelcache中的地址。
(3)设备/dev/ptmx,对应结构体cdevsw中d_read, d_write, d_ioctl在题目给出kernelcache中的地址。
假设上述地址的结果是:
/dev/random
d_read:0x80001231
d_write:0x80001253
d_ioctl:0x80001275
/dev/pf
d_read:0x80201297
d_write:0x802012b9
d_ioctl:0x801012db
/dev/ptmx
d_read:0x802012ed
d_write:0x802012ff
d_ioctl:0x80201211
那么答案的格式应该是:(用#号分隔)
0x80001231#0x80001253#0x80001275#0x80201297#0x802012b9#0x801012db#0x802012ed#0x802012ff#0x80201211
我们知道iOS内核是基于XNU内核改的,XNU for mac的代码可以从苹果官方下载到:
xnu-2782.40.9/bsd/dev/random/randomdev.c
static struct cdevsw random_cdevsw =
{
random_open, /* open */
random_close, /* close */
random_read, /* read */
random_write, /* write */
random_ioctl, /* ioctl */
(stop_fcn_t *)nulldev, /* stop */
(reset_fcn_t *)nulldev, /* reset */
NULL, /* tty's */
eno_select, /* select */
eno_mmap, /* mmap */
eno_strat, /* strategy */
eno_getc, /* getc */
eno_putc, /* putc */
0 /* type */
};
/*
* Called to initialize our device,
* and to register ourselves with devfs
*/
void
random_init(void)
{
int ret;
ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw);
if (ret < 0) {
panic("random_init: failed to allocate a major number!");
}
devfs_make_node(makedev (ret, RANDOM_MINOR), DEVFS_CHAR,
UID_ROOT, GID_WHEEL, 0666, "random", 0);
/*
* also make urandom
* (which is exactly the same thing in our context)
*/
devfs_make_node(makedev (ret, URANDOM_MINOR), DEVFS_CHAR,
UID_ROOT, GID_WHEEL, 0666, "urandom", 0);
}
将kernercache拖到IDA或者hopper中分析,找到该代码段:
================ B E G I N N I N G O F P R O C E D U R E ================
sub_800c0d88:
800c0d88 push {r4, r5, r6, r7, lr}
800c0d8a add r7, sp, #0xc
800c0d8c sub sp, #0xc
800c0d8e movw r0, #0xc5c6
800c0d92 movt r0, #0x2f
800c0d96 add r0, pc ; 0x803bd360 (_PE_poll_input + 0xaf4c)
800c0d98 addw r1, r0, #0xb14
800c0d9c mov.w r0, #0xffffffff
800c0da0 bl _cdevsw_add
800c0da4 mov r4, r0
800c0da6 cmp.w r4, #0xffffffff
800c0daa bgt 0x800c0dba
800c0dac movw r0, #0x655f
800c0db0 movt r0, #0x2b
800c0db4 add r0, pc ; "\\\\\\\\\\\\\\\\\\\\\\\\"random_init: failed to allocate a major number!\\\\\\\\\\\\\\\\\\\\\\\\"", argument #1 for method _panic
800c0db6 bl _panic
800c0dba movw r0, #0x657b ; XREF=sub_800c0d88+34
800c0dbe mov.w r6, #0x1b6
800c0dc2 movt r0, #0x2b
800c0dc6 movs r5, #0x0
800c0dc8 str r6, [sp] ; argument #5 for method _devfs_make_node
800c0dca add r0, pc ; "random"
800c0dcc movs r1, #0x0 ; argument #2 for method _devfs_make_node
800c0dce str r0, [sp, #0x4] ; argument #6 for method _devfs_make_node
800c0dd0 lsl.w r0, r4, #0x18 ; argument #1 for method _devfs_make_node
800c0dd4 movs r2, #0x0 ; argument #3 for method _devfs_make_node
800c0dd6 movs r3, #0x0 ; argument #4 for method _devfs_make_node
800c0dd8 str r5, [sp, #0x8]
800c0dda bl _devfs_make_node
800c0dde movw r0, #0x6560
800c0de2 movs r1, #0x0 ; argument #2 for method _devfs_make_node
800c0de4 movt r0, #0x2b
800c0de8 str r6, [sp] ; argument #5 for method _devfs_make_node
800c0dea movs r2, #0x0 ; argument #3 for method _devfs_make_node
800c0dec add r0, pc ; "urandom"
800c0dee movs r3, #0x0 ; argument #4 for method _devfs_make_node
800c0df0 str r0, [sp, #0x4] ; argument #6 for method _devfs_make_node
800c0df2 movs r0, #0x1
800c0df4 orr.w r0, r0, r4, lsl #24 ; argument #1 for method _devfs_make_node
800c0df8 str r5, [sp, #0x8]
800c0dfa bl _devfs_make_node
800c0dfe add sp, #0xc
800c0e00 pop {r4, r5, r6, r7, pc}
; endp
800c0e02 nop
从源码中可以看出 cdevsw_add 函数第二个参数为cdevsw结构体地址
从汇编中算出random_cdevsw结构体地址为0x803bd360+0xb14 = 0x803BDE74
go到0x803BDE74 random_cdevsw:
803bde74 db 0x19 ; '.'
803bde75 db 0x0e ; '.'
803bde76 db 0x0c ; '.'
803bde77 db 0x80 ; '.'
803bde78 db 0x35 ; '5'
803bde79 db 0x0e ; '.'
803bde7a db 0x0c ; '.'
803bde7b db 0x80 ; '.'
803bde7c db 0xa1 ; '.'
803bde7d db 0x0e ; '.'
803bde7e db 0x0c ; '.'
803bde7f db 0x80 ; '.' ---->random_read 0x800c0ea1
803bde80 db 0x39 ; '9'
803bde81 db 0x0e ; '.'
803bde82 db 0x0c ; '.'
803bde83 db 0x80 ; '.' ---->random_write 0x800c0e39
803bde84 db 0x05 ; '.'
803bde85 db 0x0e ; '.'
803bde86 db 0x0c ; '.'
803bde87 db 0x80 ; '.' ---->random_ioctl 0x800c0e05
803bde88 db 0xc9 ; '.'
803bde89 db 0x73 ; 's'
803bde8a db 0x28 ; '('
803bde8b db 0x80 ; '.'
803bde8c db 0xc9 ; '.'
803bde8d db 0x73 ; 's'
803bde8e db 0x28 ; '('
803bde8f db 0x80 ; '.'
803bde90 db 0x00 ; '.'
803bde91 db 0x00 ; '.'
803bde92 db 0x00 ; '.'
803bde93 db 0x00 ; '.'
803bde94 db 0xad ; '.'
803bde95 db 0x73 ; 's'
803bde96 db 0x28 ; '('
803bde97 db 0x80 ; '.'
803bde98 db 0xad ; '.'
803bde99 db 0x73 ; 's'
803bde9a db 0x28 ; '('
803bde9b db 0x80 ; '.'
803bde9c db 0xb1 ; '.'
803bde9d db 0x73 ; 's'
803bde9e db 0x28 ; '('
803bde9f db 0x80 ; '.'
803bdea0 db 0xad ; '.'
803bdea1 db 0x73 ; 's'
803bdea2 db 0x28 ; '('
803bdea3 db 0x80 ; '.'
803bdea4 db 0xad ; '.'
803bdea5 db 0x73 ; 's'
803bdea6 db 0x28 ; '('
803bdea7 db 0x80 ; '.'
803bdea8 db 0x00 ; '.'
803bdea9 db 0x00 ; '.'
803bdeaa db 0x00 ; '.'
803bdeab db 0x00 ; '.'
得到 /dev/random 结果: 0x800c0ea1#0x800c0e39#0x800c0e05
(2)设备/dev/pf,对应结构体cdevsw中d_read, d_write, d_ioctl在题目给出kernelcache中的地址。
xnu-2782.40.9/bsd/net/pf_ioctl.c:
static struct cdevsw pf_cdevsw = {
/* open */ pfopen,
/* close */ pfclose,
/* read */ eno_rdwrt,
/* write */ eno_rdwrt,
/* ioctl */ pfioctl,
/* stop */ eno_stop,
/* reset */ eno_reset,
/* tty */ NULL,
/* select */ eno_select,
/* mmap */ eno_mmap,
/* strategy */ eno_strat,
/* getc */ eno_getc,
/* putc */ eno_putc,
/* type */ 0
};
void
pfinit(void)
{......
maj = cdevsw_add(PF_CDEV_MAJOR, &pf_cdevsw);
if (maj == -1) {
printf("%s: failed to allocate major number!\\\\\\\\n", __func__);
return;
}
(void) devfs_make_node(makedev(maj, PFDEV_PF), DEVFS_CHAR,
UID_ROOT, GID_WHEEL, 0600, "pf", 0);
(void) devfs_make_node(makedev(maj, PFDEV_PFM), DEVFS_CHAR,
UID_ROOT, GID_WHEEL, 0600, "pfm", 0);
......
}
对应kernelcache汇编代码(节选):
8024b51a movw r0, #0x1e3a
8024b51e movt r0, #0x17
8024b522 add r0, pc ; 0x803bd360 (_PE_poll_input + 0xaf4c)
8024b524 addw r1, r0, #0xbbc
8024b528 mov.w r0, #0xffffffff
8024b52c bl _cdevsw_add
8024b530 mov r5, r0
8024b532 cmp.w r5, #0xffffffff
8024b536 beq 0x8024b5ba
8024b538 movw r0, #0x4532
8024b53c mov.w r4, #0x180
8024b540 movt r0, #0x13
8024b544 mov.w r11, #0x0
8024b548 str r4, [sp]
8024b54a add r0, pc ; "pf"
8024b54c movs r1, #0x0
8024b54e str r0, [sp, #0x4]
8024b550 lsl.w r0, r5, #0x18
8024b554 movs r2, #0x0
8024b556 movs r3, #0x0
8024b558 str.w r11, [sp, #0x8]
8024b55c bl _devfs_make_node
8024b560 movw r0, #0x4555
8024b564 movs r1, #0x0
8024b566 movt r0, #0x13
8024b56a str r4, [sp]
8024b56c movs r2, #0x0
8024b56e add r0, pc ; "pfm"
8024b570 movs r3, #0x0
8024b572 str r0, [sp, #0x4]
8024b574 movs r0, #0x1
8024b576 orr.w r0, r0, r5, lsl #24
8024b57a str.w r11, [sp, #0x8]
8024b57e bl _devfs_make_node
算出pf_cdevsw结构体地址为0x803bd360+0xbbc = 0x803BDF1C
go到0x803BDF1C pf_cdevsw:
803bdf1c db 0x65 ; 'e'
803bdf1d db 0x2c ; ','
803bdf1e db 0x15 ; '.'
803bdf1f db 0x80 ; '.'
803bdf20 db 0xf5 ; '.'
803bdf21 db 0x2b ; '+'
803bdf22 db 0x15 ; '.'
803bdf23 db 0x80 ; '.'
803bdf24 db 0xad ; '.'
803bdf25 db 0x73 ; 's'
803bdf26 db 0x28 ; '('
803bdf27 db 0x80 ; '.' ---->eno_rdwrt 0x802873ad
803bdf28 db 0xad ; '.'
803bdf29 db 0x73 ; 's'
803bdf2a db 0x28 ; '('
803bdf2b db 0x80 ; '.' ---->eno_rdwrt 0x802873ad
803bdf2c db 0x19 ; '.'
803bdf2d db 0x9d ; '.'
803bdf2e db 0x14 ; '.'
803bdf2f db 0x80 ; '.' ---->pfioctl 0x80149d19
803bdf30 db 0xad ; '.'
803bdf31 db 0x73 ; 's'
803bdf32 db 0x28 ; '('
803bdf33 db 0x80 ; '.'
803bdf34 db 0xad ; '.'
803bdf35 db 0x73 ; 's'
803bdf36 db 0x28 ; '('
803bdf37 db 0x80 ; '.'
803bdf38 db 0x00 ; '.'
803bdf39 db 0x00 ; '.'
803bdf3a db 0x00 ; '.'
803bdf3b db 0x00 ; '.'
803bdf3c db 0xad ; '.'
803bdf3d db 0x73 ; 's'
803bdf3e db 0x28 ; '('
803bdf3f db 0x80 ; '.'
803bdf40 db 0xad ; '.'
803bdf41 db 0x73 ; 's'
803bdf42 db 0x28 ; '('
803bdf43 db 0x80 ; '.'
803bdf44 db 0xb1 ; '.'
803bdf45 db 0x73 ; 's'
803bdf46 db 0x28 ; '('
803bdf47 db 0x80 ; '.'
803bdf48 db 0xad ; '.'
803bdf49 db 0x73 ; 's'
803bdf4a db 0x28 ; '('
803bdf4b db 0x80 ; '.'
803bdf4c db 0xad ; '.'
803bdf4d db 0x73 ; 's'
803bdf4e db 0x28 ; '('
803bdf4f db 0x80 ; '.'
803bdf50 db 0x00 ; '.'
803bdf51 db 0x00 ; '.'
803bdf52 db 0x00 ; '.'
803bdf53 db 0x00 ; '.'
得到 /dev/pf 的结果: 0x802873ad#0x802873ad#0x80149d19
(3)设备/dev/ptmx,对应结构体cdevsw中d_read, d_write, d_ioctl在题目给出kernelcache中的地址。
/xnu-2782.40.9/bsd/kern/tty_ptmx.c:
static struct cdevsw ptmx_cdev = {
ptcopen, ptcclose, ptcread, ptcwrite,
ptyioctl, ptcstop, ptcreset, 0,
ptcselect, eno_mmap, eno_strat, eno_getc,
eno_putc, D_TTY
};
int
ptmx_init( __unused int config_count)
{
/*
* We start looking at slot 10, since there are inits that will
* stomp explicit slots (e.g. vndevice stomps 1) below that.
*/
/* Get a major number for /dev/ptmx */
if((ptmx_major = cdevsw_add(-15, &ptmx_cdev)) == -1) {
printf("ptmx_init: failed to obtain /dev/ptmx major number\\\\\\\\n");
return (ENOENT);
}
if (cdevsw_setkqueueok(ptmx_major, &ptmx_cdev, 0) == -1) {
panic("Failed to set flags on ptmx cdevsw entry.");
}
/* Get a major number for /dev/pts/nnn */
if ((ptsd_major = cdevsw_add(-15, &ptsd_cdev)) == -1) {
(void)cdevsw_remove(ptmx_major, &ptmx_cdev);
printf("ptmx_init: failed to obtain /dev/ptmx major number\\\\\\\\n");
return (ENOENT);
}
if (cdevsw_setkqueueok(ptsd_major, &ptsd_cdev, 0) == -1) {
panic("Failed to set flags on ptmx cdevsw entry.");
}
/*
* Locks to guard against races between revoke and kevents
*/
ptsd_kevent_lock_init();
/* Create the /dev/ptmx device {<major>,0} */
(void)devfs_make_node_clone(makedev(ptmx_major, 0),
DEVFS_CHAR, UID_ROOT, GID_TTY, 0666,
ptmx_clone, PTMX_TEMPLATE);
_ptmx_driver.master = ptmx_major;
_ptmx_driver.slave = ptsd_major;
_ptmx_driver.fix_7828447 = 1;
_ptmx_driver.fix_7070978 = 1;
#if CONFIG_MACF
_ptmx_driver.mac_notify = 1;
#endif
_ptmx_driver.open = &ptmx_get_ioctl;
_ptmx_driver.free = &ptmx_free_ioctl;
_ptmx_driver.name = &ptmx_get_name;
_ptmx_driver.revoke = &ptsd_revoke_knotes;
tty_dev_register(&_ptmx_driver);
return (0);
}
对应kernelcache汇编代码(节选):
80293330 push {r4, r5, r6, r7, lr}
80293332 add r7, sp, #0xc
80293334 push.w {r8, r10, r11}
80293338 sub sp, #0xc
8029333a movw r4, #0xa016
8029333e mvn r0, #0xe
80293342 movt r4, #0x12
80293346 add r4, pc ; 0x803bd360 (_PE_poll_input + 0xaf4c)
80293348 addw r1, r4, #0xc2c
8029334c bl _cdevsw_add
80293350 movw r8, #0x6b90
80293354 cmp.w r0, #0xffffffff
80293358 movt r8, #0x16
8029335c add r8, pc ; 0x803f9ef0
8029335e str.w r0, [r8, #0xc58] ; 0x803fab48
80293362 beq 0x80293412
80293364 cmp r0, #0x2a
80293366 bhi 0x802933a8
80293368 movw r1, #0xe0d0
8029336c rsb r2, r0, r0, lsl #3
80293370 movt r1, #0x11
80293374 add r1, pc ; _cdevsw
80293376 add.w r1, r1, r2, lsl #3
8029337a movs r2, #0x0
8029337c adds r6, r4, r2 ; XREF=sub_80293330+92
8029337e ldrb r3, [r1, r2]
80293380 ldrb.w r6, [r6, #0xc2c]
80293384 cmp r3, r6
80293386 bne 0x802933a8
80293388 adds r2, #0x1
8029338a cmp r2, #0x38
8029338c bne 0x8029337c
8029338e movw r1, #0x583c
80293392 movs r2, #0x1
80293394 movt r1, #0x16
80293398 add r1, pc ; 0x803f8bd8
8029339a str.w r2, [r1, r0, lsl #3]
8029339e add.w r0, r1, r0, lsl #3
802933a2 movs r1, #0x0
802933a4 str r1, [r0, #0x4]
802933a6 b 0x802933b6
802933a8 movw r0, #0xeb91 ; XREF=sub_80293330+54, sub_80293330+86
802933ac movt r0, #0xc
802933b0 add r0, pc ; "\\\\\\\\\\\\\\\\\\\\\\\\"Failed to set flags on ptmx cdevsw entry.\\\\\\\\\\\\\\\\\\\\\\\\"", argument #1 for method _panic
802933b2 bl _panic
802933b6 addw r1, r4, #0xc64 ; XREF=sub_80293330+118
802933ba mvn r0, #0xe
802933be bl _cdevsw_add
算出ptmx_cdev结构体地址为0x803bd360+0xc2c = 0x803BDF8C
go到0x803BDF8C ptmx_cdev:
803bdf8c db 0x9d ; '.'
803bdf8d db 0x1f ; '.'
803bdf8e db 0x29 ; ')'
803bdf8f db 0x80 ; '.'
803bdf90 db 0xd5 ; '.'
803bdf91 db 0x20 ; ' '
803bdf92 db 0x29 ; ')'
803bdf93 db 0x80 ; '.'
803bdf94 db 0x51 ; 'Q'
803bdf95 db 0x22 ; '"'
803bdf96 db 0x29 ; ')'
803bdf97 db 0x80 ; '.' ---->ptcread 0x80292251
803bdf98 db 0x61 ; 'a'
803bdf99 db 0x26 ; '&'
803bdf9a db 0x29 ; ')'
803bdf9b db 0x80 ; '.' ---->ptcwrite 0x80292661
803bdf9c db 0x8d ; '.'
803bdf9d db 0x29 ; ')'
803bdf9e db 0x29 ; ')'
803bdf9f db 0x80 ; '.' ---->ptyioctl 0x8029298d
803bdfa0 db 0x59 ; 'Y'
803bdfa1 db 0x26 ; '&'
803bdfa2 db 0x29 ; ')'
803bdfa3 db 0x80 ; '.'
803bdfa4 db 0x5d ; ']'
803bdfa5 db 0x26 ; '&'
803bdfa6 db 0x29 ; ')'
803bdfa7 db 0x80 ; '.'
803bdfa8 db 0x00 ; '.'
803bdfa9 db 0x00 ; '.'
803bdfaa db 0x00 ; '.'
803bdfab db 0x00 ; '.'
803bdfac db 0x0d ; '.'
803bdfad db 0x25 ; '%'
803bdfae db 0x29 ; ')'
803bdfaf db 0x80 ; '.'
803bdfb0 db 0xad ; '.'
803bdfb1 db 0x73 ; 's'
803bdfb2 db 0x28 ; '('
803bdfb3 db 0x80 ; '.'
803bdfb4 db 0xb1 ; '.'
803bdfb5 db 0x73 ; 's'
803bdfb6 db 0x28 ; '('
803bdfb7 db 0x80 ; '.'
803bdfb8 db 0xad ; '.'
803bdfb9 db 0x73 ; 's'
803bdfba db 0x28 ; '('
803bdfbb db 0x80 ; '.'
803bdfbc db 0xad ; '.'
803bdfbd db 0x73 ; 's'
803bdfbe db 0x28 ; '('
803bdfbf db 0x80 ; '.'
803bdfc0 db 0x03 ; '.'
803bdfc1 db 0x00 ; '.'
803bdfc2 db 0x00 ; '.'
803bdfc3 db 0x00 ; '.'
得到 /dev/ptmx 的结果: 0x80292251#0x80292661#0x8029298d
所以最终结果为:
0x800c0ea1#0x800c0e39#0x800c0e05#0x802873ad#0x802873ad#0x80149d19#0x80292251#0x80292661#0x8029298d