首页
社区
课程
招聘
[原创]2015 MSC(第二届)iOS 1,2,3解题思路
发表于: 2015-10-21 00:03 13712

[原创]2015 MSC(第二届)iOS 1,2,3解题思路

2015-10-21 00:03
13712
第一题 -------------------->
   第一题出的可能有点坑人,倒不是技术的难题。我首先拿道题后,用IDA打开后,扫了扫,这个题挺简单啊,只需要写个tweak,就把密码爆出来,不是很复杂啊。但是在我的iPad min 2 3G版本运行崩溃,我刚开始还怀疑我下的包是不是正确,下了第二遍还是崩溃啊,不知道是本来设计就是这样还是因为我的设备问题。看看注意事项:“iOS赛题的运行需要iOS v8.4及以上版本,需iphone4s及以上机型“,没有说可以用iPad,难不成主办方还非限制不能使用iPad解题,最后无奈将LP的iPhone 5s(为了安全期间,手机是不一般不越狱的)越狱,安装AppSync后,运行又崩溃。不是吧,还以为是AppSync出什么问题,折腾了很久,最终放弃直接硬编码来破解了。哎,不知道是出题就是这么设计的,还是其他原因,这个题有点太。。。

   好了,下面进入主题。
   方法一:如果这个题能够能够正确运行,写个tweak如下,程序中的循环解密调用AESCrypt类decrypt最后的结果,就暴漏出答案了。
        %hook AESCrypt

        + (NSString *)decrypt:(NSString *)message password:(NSString *)password
        {
           NSLog(@"message=%@", message) ;
           NSLog(@"password=%@", password) ;

           NSString* answer = %orig;

           NSLog(@"answer=%@", answer) ;

          return answer ;
        }

        %end

  方法二:编码破解,其中用到的类NSData+Base64、NSData+CommonCrypto和Ceasar_CipherModel这个在github上很容易就搜索到了
    NSString *message =
    @"mrMZAbjtZozDOGI9UeeH6g0iLHNnTNsFyzS0tYca4R3KkaQ0doxdDVuxZ7HoqYOcxFhgDiEvdGKix95VJNEUP8rdox4cm7GHVkbVcTJPmrTtH7hompW+xjTgGg2zQhs0tUGQ8lCggev2SNoWcaUOUU==" ;
    int count = 5 ;
    NSString* result = @"" ;
    do {
        Ceasar_CipherModel * ceasar = [[Ceasar_CipherModel alloc] initWithCipherKey:--count] ;
        [ceasar setCodedMessage:message] ;
        [ceasar decrypt] ;

        message = [AESCrypt decrypt:[ceasar originalMessage] password:@"ZGlhb2RhX2ppYW5rYW5nCg=="] ;
    } while (count > 0) ;
    NSLog(@"%s", [message UTF8String]) ;

        @implementation AESCrypt
        + (NSString *)decrypt:(NSString *)message password:(NSString *)password
        {
            NSData* data = [NSData base64DataFromString:message] ;
            NSData* hash = [[password dataUsingEncoding:NSUTF8StringEncoding] SHA256Hash] ;

            return [[NSString alloc] initWithData:[data decryptedAES256DataUsingKey:hash error:nil] encoding:NSUTF8StringEncoding] ;
        }
        @end

第二题 -------------------->
        找出kernelcache中的/dev/random,/dev/pf和/dev/ptmx在kernelcache中的d_read, d_write, d_ioctl地址。
        这些都是字符型设备文件,如果对linux驱动了解的话,很容易联想到,cdev_init,cdev_add,cdev_del函数,这些*nix都是相通的。所以在函数表中找找cdev看看是否存在_cdevsw_add,可以通过这个函数找出所有设备文件定义。因为这儿bin是被strip掉的,需要定位这几个设备文件分别对应的是哪款代码,可以通过devfs_make_node函数的倒数第二个参数完全判断出来。找到字符设备添加的位置,只需要分析_cdevsw_add函数传入的第二个结构体,得到答案,至于那个d_read, d_write, d_ioctl的地址,也可以进入相应指针地址的函数内稍微瞅瞅就可以区分出来。当然也有偷懒的方式,毕竟XNU苹果是开源的,直接可以通过查找opensource.apple.com找到对应源码。

        互相并以学习的态度,我就啰嗦点多写点。下面是我找的地址,以供大家学习参考交流:

        #/dev/random
        http://www.opensource.apple.com/source/xnu/xnu-2422.1.72/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 */
        };

    #在IDA中的内容
        __DATA:__data:803BDE74 off_803BDE74    DCD sub_800C0E18+1      ; open
        __DATA:__data:803BDE78                 DCD sub_800C0E34+1      ; close
        __DATA:__data:803BDE7C                 DCD sub_800C0EA0+1      ; read
        __DATA:__data:803BDE80                 DCD sub_800C0E38+1      ; write
        __DATA:__data:803BDE84                 DCD sub_800C0E04+1      ; ioctl

        其他/dev/pf和/dev/ptmx就把啰嗦列举了。源码地址分别如下
        http://www.opensource.apple.com/source/xnu/xnu-2782.30.5/bsd/net/pf_ioctl.c
        http://www.opensource.apple.com/source/xnu/xnu-2782.30.5/bsd/kern/tty_ptmx.c

        至于相对kernelcache有更多了解的朋友,可以参见
        https://www.nowsecure.com/blog/2014/04/14/ios-kernel-reversing-step-by-step/

第三题 -------------------->
        第三题虽然没有做出来,与大家分享一下我的分析过程,互相学习并望指点一下有没有更精妙的方法(感觉自己的方案有点太人肉计算机了)。
        第三题倒是在我的ipad上能够运行。拿到第三题后感觉确实就难度增加了,这个就不能简单的用静态分析来解决问题了,需要使用lldb来动态调试跟踪了。我对arm7汇编还是熟悉,在这种疯跳的代码面前,还是选自己熟悉的汇编格式来分析更省事,所以搞了个iPhone 5c来,越狱装AppSync有是一顿折腾。外加Xcode6的lldb对armv7调试与IDA不同显示相同,从苹果网站下个Xcode5.0.2那个慢,又是一顿折腾。。

        闲话少说,开始真题。这道题我是两个方案并行进行。一个是暴力破解方法,另外一个就是人工分析。
        方案一:暴力破解
                __text:0000B070 ; void __cdecl -[ViewController onClick](struct ViewController *self, SEL)
                __text:0000B0C2                 ADD             R0, PC ; selRef_UTF8String
                __text:0000B0C4                 LDR             R1, [R0] ; "UTF8String"
                __text:0000B0C6                 MOV             R0, R6         ; R0为输入文本
                __text:0000B0C8                 BLX             _objc_msgSend
                __text:0000B0CC                 BL              sub_1DCB8 ; checkPassword

        其中sub_1DCB8是关键函数,返回1表示成功(“呵呵!正式在下!”),返回0表示失败(“大人,冤枉啊!不是我!”)
        所以写个tweak,hook到sub_1DCB8,当然这个方案是下下策,也就是赌一下,毕竟人工分析与机器碰运气也是互相不耽误的。呵呵
        下面是tweak大体内容如下:

        int (*original_checkPassword)(const char*);
        int replaced_checkPassword(const char* password) {
                for (char* word in 暴力字典表) {
                        retValue = original_checkPassword(word);
                        if (retValue == 1) {
                                return retValue ;//爆破成功
                        }
                }
        }

        %ctor
        {
          @autoreleasepool
          {
             MSImageRef image = MSGetImageByName("/var/mobile/Containers/Bundle/Application/076C360A-AA7C-473B-AF88-C5A1171D91AB/iOS题3.app/iOS题3") ;

             //Look for our target method
             unsigned int *sym = (unsigned int*)0x1dcb9 ;//0x1dcb8 + 1

             MSHookFunction((void *)sym, (void *)replaced_checkPassword, (void **)&original_checkPassword);
          }
        }
        可惜最终也没有爆破出来。

        方案二:人工分析
        下面是我的分析过程,可能写的会比较啰嗦,大家不要介意,也是希望这个帖子公布出来后,有大牛能够给我指点一二或给大家提个思路,我能提高学习一下。lldb调试就不在累述了,需要帮助的朋友可以参见《iOS应用逆向工程(第2版)》
        首先,在
                __text:0000B0CC                 BL              sub_1DCB8 ; checkPassword
        下断点,
                (lldb) br s -a 0xb0cc
        运行起来随便输入点,比如"wang",此时R0保存的是输入字符串的地址0x003660e0(以下地址或者内存内容为我当时分析时数据,因时因输入而异,仅供以下分析参考)。因为输入毕竟要使用,所以可以在输入地址0x003660e0下个观察点的断点。看看代码是从哪里开始处理这个字符串,关键也是这个代码跳的厉害,一步一步追踪很难找到关键点。

        ----下个读断点
        (lldb) wa s e -w read -- 0x003660e0
        Watchpoint created: Watchpoint 1: addr = 0x003660e0 size = 4 state = enabled type = r
            new value: 1735287159

        然后运行起来后,在这里断到读观察点,
                __text:00020F76                 STR.W           R3, [R7,#-0x7C]
                __text:00020F7A                 BLX             _strlen ; check input words length
        在这里下断点,查看一下数据,这个就是刚才输入的“wang",在根据_strlen,这不是求长度吗? 差不多找到只能说一部分关键点了,下来就跟着往下追踪了。看看有什么可获取的。解决这个程序中有两个地方是决定跳转到下一条地址的代码,在这两个地方下个断点,并加个打印条件打出下一条执行的代码段地址,这样就不会跑飞了。
                片段1:
                        __text:00013ED8   LDR             R0, [SP,#arg_8]
                        __text:00013EDC   STR             LR, [SP,#arg_8] ; LR = return address
                        __text:00013EE0   MOV             LR, R0

                片段2:
                        __text:00013ED8   LDR             R0, [SP,#arg_8]
                        __text:00013EDC   STR             LR, [SP,#arg_8] ; LR = return address
                        __text:00013EE0   MOV             LR, R0

                (lldb) br s -a 0x13ee0
                        5: address = 0x00013ee0, ....
                (lldb) br com add 5   <- 这个5是上面断点编号
                  # p/x $lr
                  # DONE

                (lldb) br s -a 0x13f08
                        6: address = 0x00013f08, ....
                (lldb) br com add 6   <- 这个5是上面断点编号
                  # p/x $lr
                  # DONE

        知道关键函数开始点后,又能取到跳转下一条跳转地址后,那么下面就是开始单步。模式如下:
                __text:00020F88                 LDR.W           R1, [R7,#-0x6C]  <----我们关系的执行代码
                __text:00020F8C                 PUSH            {R0,R1,LR}       <----从这里开始就开始调用调用地址重算函数了,所以在这个地址执行c就可以了
                __text:00020F8E                 MOVW            R0, #0x21D
                __text:00020F92                 BL              LocationPCPosition

        如下是我分析的讲字符串"wang"加密成数字的片段:
                计算输入长度
                __text:00020F76                 STR.W           R3, [R7,#-0x7C]     r3=0xa3610b54   ro=输入地址
                __text:00020F7A                 BLX             _strlen ; check input words length

                判断输入长度是否为零
                __text:00020F96                 CMP             R0, #0  ; r0 为输入长度

                __text:00021072                 MOVW            R1, #0  ; 此时r1为0

                __text:00020FE4                 IT EQ
                __text:00020FE6                 MOVEQ           R1, #1  ; 如果输入长度为0,则R1赋值为1

                __text:00020FD4                 CMP             R1, #0       ;如果r1=0, 长度不为0,否则长度为0,失败
                __text:00020FD6                 LDR.W           R1, [R7,#-0x7C]     ;r1 = 0xa3610b54
                __text:00020FC6                 LDR.W           R2, [R7,#-0x78]     ;r2 = 0xf029035e

                __text:000211CA                 IT NE
                __text:000211CC                 MOVNE           R1, R2          ;r1=0xa3610b54  r2 = 0xf029035e

                ;保存初始密钥key
                __text:00020FB4                 STR.W           R1, [R7,#-0x40]  ;[R7,#-0x40]=0xa3610b54

                ;取第一个字符存[R7,#-0x41]
                __text:00020FB8                 LDRB.W          R1, [R7,#-0x32]  ;[R7,#-0x32]=0x00000077   r1=0x00000077   <-第一个字符'w'  取第一个字符
                __text:00020FA2                 STRB.W          R1, [R7,#-0x41]  ;[R7,#-0x41]=0x610b5477

                ;保存原始输入字符指针和长度到 [R7,#-0x48] 和 [R7,#-0x4C]
                __text:00020FA6                 LDR.W           R1, [R7,#-0x68]  ;r1 = 0x0030d5c0                <-输入字符串的地址 “wang”
                __text:0002112E                 STR.W           R1, [R7,#-0x48]  ;[R7,#-0x48]=0x0030d5c0         <-输入字符串的地址 “wang”
                __text:00021132                 STR.W           R0, [R7,#-0x4C]  ;[R7,#-0x4C]=0x00000004         <-输入字符串的地址 “wang” 的长度

                ;初始化一个相关的KEY,从[R7,#-0x74]转存到[R7,#-0x50]
                __text:00021204                 LDR.W           R0, [R7,#-0x74]  ;[R7,#-0x74] = 0xffffffff  设置R0为0xffffffff
                __text:00020F64                 STR.W           R0, [R7,#-0x50]  ;[R7,#-0x50] = 0xffffffff

                ;初始化一个相关的KEY,从[R7,#-0x70]转存到[R7,#-0x54]
                __text:00020F68                 LDR.W           R3, [R7,#-0x70]  ;设置R3为 0x00000000
                __text:0002119A                 STR.W           R3, [R7,#-0x54]  ;[R7,#-0x54] = 0x00000000

                ;找到初始化KEY是0xa3610b54的地方开始执行代码,并且将Key暂存在[R7,#-0x6C]
                __text:000200C6                 LDR.W           R0, [R7,#-0x40] ;[R7,#-0x40] = 0xa3610b54, R0取值0xa3610b54
                __text:000206A2                 MOVW            R1, #0xC15      ;
                __text:00020722                 MOVT.W          R1, #0xAC47     ; R1=0xac470c15
                __text:00020716                 CMP             R0, R1          ; R0=0xa3610b54   R1=0xac470c15
                __text:000206FC                 STR.W           R0, [R7,#-0x6C]  ;[R7,#-0x6C]=0xa3610b54
                __text:000206EE                 MOVW            R0, #0xB54
                __text:00020930                 MOVT.W          R0, #0xA361   ;R0 = 0xa3610b54
                __text:00020934                 LDR.W           R1, [R7,#-0x6C]  ;R1 = 0xa3610b54
                __text:000206B0                 CMP             R1, R0           :R0 = 0xa3610b54, R1 = 0xa3610b54

                __text:00021120                 MOVW            R0, #0x986
                __text:00020F24                 MOVT.W          R0, #0x7C4A     ; R0 = 0x7c4a0986
                __text:00020F28                 MOVW            R1, #0xDC4D
                __text:00020F56                 MOVT.W          R1, #0xAEFF      ; R1 = 0xaeffdc4d
                __text:00020F44                 MOV             R2, #0xFFFFFFFF   ; R2 = 0xffffffff

                __text:00020F48                 MOVW            R3, #0x98B0       ;
                __text:0002125C                 MOVT.W          R3, #0            ; R3 = 0x000098b0
                __text:00021260                 ADD             R3, PC            ; PC = 0x00021260, R3 = 0x000098b0    之后R3=0x0002ab14

                ;R9一个变动的KEY值,初始化的时候为0xffffffff
                __text:0002126C                 LDR.W           R9, [R7,#-0x50]      ; [R7,#-0x50] 为-1,R9也变成R9 = 0xffffffff
                ;R12为输入字符串的长度
                __text:00021270                 LDR.W           R12, [R7,#-0x4C]     ; [R7,#-0x4C] 为0x00000004,R12也变成0x00000004 <-输入字符串的地址 “wang” 的长度
                ;LR为输入字符串在内存中的地址
                __text:000212EC                 LDR.W           LR, [R7,#-0x48]      ; LR = 0x0030d5c0   <-输入字符串的地址 “wang”
                ;取的第一个字符
                __text:000212F0                 LDRB.W          R4, [R7,#-0x41]      ; R4 = 0x00000077

                ; 输入的字符串长度减一
                __text:000212AC                 MOV             R5, #0x3EE9B11C       ; R5 = 0x3ee9b11c
                __text:000212D0                 SUB.W           R12, R12, R5          ; R12 = 0x00000004, R5 = 0x3ee9b11c  R12 = R12 - R5 = 0xc1164ee8
                __text:000212DE                 ADD.W           R12, R12, #0xFFFFFFFF  ; 0xFFFFFFFF 也等于0  R12 = 0xc1164ee7
                __text:000212BE                 MOV             R5, #0x3EE9B11C        ; R5 = 0x3ee9b11c
                __text:0002133A                 ADD             R12, R5                ; R12 = 0xc1164ee7 R5 = 0x3ee9b11c     R12 = R12 + R5 = 0x00000003

                ;降减一后的字符长度,保存在[R7,#-0x30],并且下一个字符地址保存在[R7,#-0x2C]
                __text:00021318                 STR.W           R12, [R7,#-0x30]       ; [R7,#-0x30] = 0x00000003

                ;去第二个字符地址保存在[R7,#-0x2C]
                __text:0002131C                 ADD.W           R12, LR, #1            ; LR=0x0030d5c0  <-输入字符串的地址  R12 = LR + 1 = 0x0030d5c1  <- "ang"
                __text:0002130A                 STR.W           R12, [R7,#-0x2C]       ; R12 = 0x0030d5c1 <- 即"ang"的地址, [R7,#-0x2C]= 0x0030d5c1

                ;R4=第一个字符, LR=初始化KEY异或#0xFFFFFFFF,R2为0x20F44地方初始化的常量0xFFFFFFFF
                __text:0002129A                 AND.W           R12, R4, #0xFF        ; R4 = 0x00000077, R12 = R4 & 0xFF = 0x00000077
                __text:0002129E                 EOR.W           LR, R9, #0xFFFFFFFF   ; R9 = 0xffffffff  LR = R9 ^ 0xFFFFFFFF = 0x00000000
                __text:000213F4                 EOR.W           R4, R2, #0xFF          ; R2 = 0xffffffff,  R4 = R2 ^ 0xFF = 0xffffff00

                __text:000213F8                 MOVW            R5, #0x3A26
                __text:0002127E                 MOVT.W          R5, #0xA4D7            ; R5 = 0xa4d73a26
                __text:00021282                 EORS            R5, R2                  ; R5 = 0xa4d73a26, R2 = 0xffffffff  R5 = R5 ^ R2 = 0x5b28c5d9

                __text:000213B6                 ORR.W           LR, LR, R4              ; LR = 0x00000000, R4 = 0xffffff00, LR = LR | R4 = 0xffffff00

                __text:000213BA                 MOVW            R4, #0x3A26
                __text:000213D6                 MOVT.W          R4, #0xA4D7             ; R4 = 0xa4d73a26
                __text:000213DA                 ORRS            R4, R5                   ; R4 = 0xa4d73a26, R5 = 0x5b28c5d9, R4 = R4 | R5 = 0xffffffff

                __text:000213E6                 EOR.W           LR, LR, #0xFFFFFFFF      ; LR = 0xffffff00,  LR = LR ^ 0xFFFFFFFF = 0x000000ff
                __text:000213C8                 AND.W           LR, LR, R4               ; LR = 0x000000ff, LR = LR & R4 = 0x000000ff & 0xffffffff = 0x000000ff

                ;第一个字符R12
                __text:0002138E                 EOR.W           R4, R12, #0xFFFFFFFF     ; R4 = 0xffffff88    R4=‘w' ^ 0xFFFFFFFF
                __text:00021392                 AND.W           R4, R4, LR               ; R4 = 0x00000088

                ;根据第一个字符和R3,计算出地址,然后取出来放R3,看来R3有大用
                __text:00020F36                 EOR.W           LR, LR, #0xFFFFFFFF       ; LR = 0x000000ff ^ 0xFFFFFFFF = 0xffffff00
                __text:00020DDC                 AND.W           R12, R12, LR         ; R12 = 0x00000077 & 0xffffff00 = 0x00000000
                __text:00020DE0                 ORR.W           R12, R12, R4         ; R12 = 0x00000088
                __text:00020DCC                 MOV.W           R12, R12,LSL#2         ; R12 = 0x00000220
                __text:00020DD0                 ADD             R3, R12               ; R3 = 0x0002ab14,  R3 = R3 + R12 = 0x0002ad34
                __text:0002135E                 LDR             R3, [R3]            ; R3 = 0xe3630b12

                __text:00020DBE                 MOVW            R12, #8             ;
                __text:00020CAE                 MOVT.W          R12, #0             ; R12 = 0x00000008
                __text:00020CB2                 LSR.W           R9, R9, R12         ; R9 = 0xffffffff   R9 = R9 >> R12 = 0xffffffff >> 0x00000008 = 0x00ffffff

                ;R3为输入的字符进行相应操作,然后再取的一个值,对他进行0xFFFFFFFF EOR操作保存在R12
                __text:00020CC0                 EOR.W           R12, R3, #0xFFFFFFFF  ; R3 =0xe3630b12 , R12 = R3 ^ 0xFFFFFFFF = 0x1c9cf4ed

                ;然后与0x3802bd30进行 and 操作
                __text:00020CC4                 MOVW            LR, #0xBD30
                __text:00020D5C                 MOVT.W          LR, #0x3802     ;  LR = 0x3802bd30
                __text:00020D60                 AND.W           R12, R12, LR      ; R12 = R12 & LR = 0x0002112f

                ;R2为0x20F44地方初始化的常量0xFFFFFFFF
                __text:00020CD2                 MOVW            LR, #0xBD30
                __text:00020CF0                 MOVT.W          LR, #0x3802       ; LR = 0x3802bd30
                __text:00020CF4                 EOR.W           R2, R2, LR        ; R2 = 0xffffffff   R2 = R2 ^ LR = 0xc7fd42cf

                ;R3为上面那个根据第一个字母算出来,然后查表的R3
                __text:00020D6E                 ANDS            R3, R2            ; R3 = 0xe3630b12   R3 = R3 & R2 = 0xc3610202

                __text:00020D4A                 EOR.W           LR, R9, #0xFFFFFFFF   ; R9 = 0x00ffffff, LR = R9 ^ 0xFFFFFFFF = 0xff000000

                __text:00020D4E                 MOVW            R4, #0xBD30
                __text:00020D3C                 MOVT.W          R4, #0x3802          ; R4 = 0x3802bd30

                __text:00020D2A                 AND.W           LR, LR, R4           ; LR = 0x38000000
                __text:00020D2E                 AND.W           R2, R2, R9           ; R2 = 0x00fd42cf
                __text:00020D7A                 ORR.W           R3, R3, R12          ; R3 = 0xdb61b622S
                __text:00020D7E                 ORR.W           R2, R2, LR           ; R2 = 0x38fd42cf
                __text:00020D02                 EORS            R2, R3               ; R2 = 0xe39cf4ed

                ;上面进行一系列操作后,保存在[R7,#-0x28],这个地方以后估计要进行比较,下个读监听就知道在哪里判断了
                __text:00020D1C                 STR.W           R2, [R7,#-0x28]      ; [R7,#-0x28] 中保存 0xe39cf4ed

                .........
                一堆无用代码或跳转代码,到下面
                .........

                ; R0=剩余长度
                __text:0001FEB0                 LDR.W           R0, [R7,#-0x30]    ; R0 = 0x00000003
                ; R2=剩余字符串的字符串地址
                __text:0001FE90                 LDR.W           R2, [R7,#-0x2C]    ; R2 = 0x0030d5c1
                ; 第一个字符计算的结果
                __text:0001FE94                 LDR.W           R3, [R7,#-0x28]    ; R3 = 0xe39cf4ed

                ;;;;;;;;;
                ;;;;;;;;;第二个字符开始,后面的都是循环从这里开始处理的
                ;;;;;;;;;

                ; 保存第二个字符到[R7,#-0x41]
                __text:0001FE82                 STRB.W          R1, [R7,#-0x41]    ; R1 = 0x00000061  就是'a'  保存
                ; 保存第二个字符地址到[R7,#-0x48]
                __text:00020092                 STR.W           R2, [R7,#-0x48]    ; R2 = 0x0030d5c1
                ; 保存剩余长度到[R7,#-0x4C]
                __text:0001FBCE                 STR.W           R0, [R7,#-0x4C]    ; R0 = 0x00000003
                ; 保存一个字符进行加密计算的结果到[R7,#-0x50]
                __text:0001FBD2                 STR.W           R3, [R7,#-0x50]    ; R3 = 0xe39cf4ed

        以上是对输入字符进行加密的核心代码,循环调用上面的算法,进行运算。当找到关键代码前半部分执行开始和结束地址后,下面只需要在下两个端点,下次调试的时候,就可以跳过分析这段了,分别可以在如下两个地方下断点:
                ; R4为当前要处理的那个字符开始
                __text:0002129A                 AND.W           R12, R4, #0xFF        ; R4 = 0x00000077, R12 = R4 & 0xFF = 0x00000077

                ; R2为上面R4字符处理完成后,运算结果保存地址。
                __text:00020D1C                 STR.W           R2, [R7,#-0x28]      ; [R7,#-0x28] 中保存 0xe39cf4ed

        通过处理"wang"过程中,[R7,#-0x28]分别被变更为:
                w = 0xe39cf4ed
                a = 0xe4ed53ff
                n = 0x87ec4e81
                g = 0x49eeab03

        好在每次调试这几个字符,数值都不变化,也减少了调试的难度。
        下来执行就一顿乱跳了,不知道所云,好在秉着生成的数据总是要用的原则,处理完输入字符后,给[R7,#-0x28]的地址下读观察点断点,来定位哪里开始使用这个关键数据的。
        下个watchpoint,继续运行,会再一段代码断下来。由于所有程序在规定是时间内我没有分析完,而且在这个地方我也没有分析太多,所以就不在罗列了。

            不知不觉,啰嗦了这么多,也算是对自己的这几天参加比赛的总结。其中肯定有比我分析方法高明的地方,只是罗列一下自己的愚见,望大家指点,共同提高。
            也非常感谢看雪与主办方举行的第一和第二次比赛,对我帮助很大,尤其是对我这种对破解感兴趣的业余人员。提供了学习的目标和指引的方向。
            再次感谢看雪论坛,见谅我平时只看帖不回贴的行为,呵呵

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 222
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
第三题你逆向的这部分是在计算你输入的字符串的CRC值,只要把那几个关键的int值贴百度搜一下,就可以看到是CRC计算的过程。然后调用了13ffc,这里面又会raise一个SIGTRAP。
2015-10-21 19:59
0
游客
登录 | 注册 方可回帖
返回
//