第一题:
拿到ipa习惯性的拖到IDA看一看,找到-[ViewController onClick]函数:
额。。。如果只是这样,是不是有点简单了?
先不管了,既然你是调用AESCrypt来解密的,hook解密函数直接拿到结果即可。
hook代码如下:
代码:
1 2 3 | %hook AESCrypt + (id)decrypt:(id)arg1 password:(id)arg2 { %log; id r = %orig; NSLog(@" = %@", r); return r; } %end |
然后打开题目,直接点击,看设备打印信息,得到如下信息:
代码:
1 2 3 4 5 6 7 8 9 10 | iPad level1[2149] <Warning>: +[<AESCrypt: 0xa90e4> decrypt:inIVWxfpVkvZKCE9QaaD6c0eHDJjPJoBuvO0pUyw4N3GgwM0zktzZRqtV7DkmUKytBdcZeArzCGet95RFJAQL8nzkt4yi7CDRgxRyPFLinPpD7dkilS+tfPcCc2vMdo0pQCM8hYccar2OJkSywQKQQ== password:ZGlhb2RhX2ppYW5rYW5nCg==] iPad level1[2149] <Warning>: = hDmx1/d5KNhr1BBYQlRNVsZSEaOdw4MtKTpT3082x/x9lZucw0qEm+UhMaOVuoSLyqD1x0elXGXqM4nFSP3W8khfyg1ynDEwLhLt12m68U8= iPad level1[2149] <Warning>: +[<AESCrypt: 0xa90e4> decrypt:eAju1/a5HKeo1YYVNiOKSpWPBxLat4JqHQmQ3082u/u9iWrzt0nBj+ReJxLSrlPIvnA1u0biUDUnJ4kCPM3T8hecvd1vkABtIeIq12j68R8= password:ZGlhb2RhX2ppYW5rYW5nCg==] iPad level1[2149] <Warning>: = e1s6fwEoaC3l/4VLi1DA4KKPJdGcGWK3elMxPqOuG7MNa9fcfWu6gpui+m3q1akL iPad level1[2149] <Warning>: +[<AESCrypt: 0xa90e4> decrypt:c1q6duCmyA3j/4TJg1BY4IINHbEaEUI3cjKvNoMsE7KLy9dadUs6ensg+k3o1yiJ password:ZGlhb2RhX2ppYW5rYW5nCg==] iPad level1[2149] <Warning>: = 4p2eb81lORtnnduYgcAc3pxfqGh8Fybny9NFnTzYJ6B= iPad level1[2149] <Warning>: +[<AESCrypt: 0xa90e4> decrypt:4o2da81kNQsmmctXfbZb3owepFg8Examx9MEmSyXI6A= password:ZGlhb2RhX2ppYW5rYW5nCg==] iPad level1[2149] <Warning>: = QNEcNAUUYKq5mMZJTh3J5w== iPad level1[2149] <Warning>: +[<AESCrypt: 0xa90e4> decrypt:QNEcNAUUYKq5mMZJTh3J5w== password:ZGlhb2RhX2ppYW5rYW5nCg==] iPad level1[2149] <Warning>: = Sp4rkDr0idKit |
可以看到5次解密之后的结果是:Sp4rkDr0idKit
好了,打开网站提交答案,成功!
第二题:
首先看到题目之后,好像和ios关系不大啊,还有这些cdevsw结构体没接触过啊。
没关系,先来搜索下这个结构体是啥,和设备/dev/random 又有什么关系。
搜索到cdevsw结构体如下:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | struct cdevsw { int (*d_open) __P((dev_t dev, int oflags, int devtype, struct proc *p)); int (*d_close) __P((dev_t dev, int fflag, int devtype, struct proc *)); int (*d_read) __P((dev_t dev, struct uio *uio, int ioflag)); int (*d_write) __P((dev_t dev, struct uio *uio, int ioflag)); int (*d_ioctl) __P((dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p)); int (*d_stop) __P((struct tty *tp, int rw)); int (*d_reset) __P((int uban)); /* XXX */ struct tty *d_ttys; int (*d_select) __P((dev_t dev, int which, struct proc *p)); int (*d_mmap) __P(()); int (*d_strategy) __P((struct buf *bp)); }; |
然后继续了解到,这个结构是通过cdevsw_add函数添加到设备,来定义设备的一些行为的,和Windows下的驱动自定义设备读写,以及控制应该是一样的。
那么有思路了,找到cdevsw_add函数,从而找到它被调用的地方:
找到了5个调用的地方,先来看第一个:
这不就是/dev/random cdevsw_add函数吗,所以第二个参数就是cdevsw结构,点进去:
d_read,d_write,d_ioctl对应的就是框住的地址!
继续在第三个调用的地方找到/dev/pf 的cdevsw结构。
然后第4.5个好像都和/dev/ptmx 有关。
没关系不要忽略我们的搜索能力,看源码吧!
/dev/random:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /* * Called to initialize our device, * and to register ourselves with devfs */ void random_init(void) { int ret; if (gRandomInstalled) return; /* install us in the file system */ gRandomInstalled = 1; /* setup yarrow and the mutex */ PreliminarySetup(); ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw); if (ret < 0) { printf("random_init: failed to allocate a major number!\n"); gRandomInstalled = 0; return; } devfs_make_node(makedev (ret, 0), 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, 1), DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666, "urandom", 0); } |
/dev/pf:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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 }; ...... if (kernel_thread_start(pf_purge_thread_fn, NULL, &pf_purge_thread) != 0) { printf("%s: unable to start purge thread!", __func__); return; } 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, 0), DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0600, "pf", 0); ...... |
/dev/ptmx:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 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); return (0); } |
从上面可以看出,第一个cdevsw_add就是我们要找的/dev/ptmx的咯,第二个是ptsd的咯,自然不是咯。
所以得到地址:
好了把这几个地址组合得到:
0x800C0EA0#0x800C0E38#0x800C0E04#0x802873AC#0x802873AC#0x80149D18#0x80292250#0x80292660#0x8029298C
赶紧提交,wrong answer,,,这不是给我泼冷水吗?
后来注意到官方给出的例子,地址最后一位都是奇数,额,,我知道地址加1是为了从ARM 指令状态跳到Thumb 指令状态。那就加1吧,最后都转成小写,提交,通过!
所以answer is:
0x800c0ea1#0x800c0e39#0x800c0e05#0x802873ad#0x802873ad#0x80149d19#0x80292251#0x80292661#0x8029298d
Permalink
博主,我是个菜鸟,为什么第一题的ipa放到IDA中什么都没有,一行汇编代码都逆不出来。放到Hopper Disassembler中也出现类似的问题,但是class-dump完全可以查看,,也没有加密。。这是怎么回事
Permalink
不会啊,可以直接拖到IDA的
Permalink
敢问博主用的是ida是什么版本?
Permalink
windows 6.8