iOS安全代码混淆研究

于春友

iOS相对于Android来说是比较安全的,而且能做的安全防护比Android要少很多,市面上大部分的应用都是在裸奔。虽然现在网上传播了一些防止GDB依附的手段,但都有相对的破解方法。so 为了给裸奔的应用添件衣服,笔者研究了代码混淆等方法(ps:以参考网络大神研究为主,为了某天也能成为大神 ~(^_^)~)

字符串混淆

对于字符串来说,IDA的明文字符串给攻击者进行静态分析提供了很大的帮助,例如(随便选取)

0000000102a9406c add x8, x8, #0x578 ; @"revokemsg%@"

这样的文字信息有惊喜,也许这就是发现下一步要执行的函数方法的爆破口。。。

通常这些方法是这样调用的

[NSString stringWithFormat:@"revokemsg%@", xyz];

HelloWorld源代码:

#import <Foundation/Foundation.h>

#ifndef STRING_OBFUSCATE

#define NSSTRING(string) @string
#define CSTRING(string) string

#endif

int main()  
{
    NSLog(@"%@", NSSTRING("Hello, world!"));
    printf("%s\n", CSTRING("Hello, world!"));
}

执行命令生成二进制文件

clang main.m -framework Foundation

IDA反编译

                                  _main:
0000000100000f20         push       rbp  
0000000100000f21         mov        rbp, rsp  
0000000100000f24         sub        rsp, 0x10  
0000000100000f28         lea        rax, qword [cfstring___]                    ; @"%@"  
0000000100000f2f         lea        rcx, qword [cfstring_Hello__world_]         ; @"Hello, world!"  
0000000100000f36         mov        rdi, rax                                    ; argument "format" for method imp___stubs__NSLog  
0000000100000f39         mov        rsi, rcx  
0000000100000f3c         mov        al, 0x0  
0000000100000f3e         call       imp___stubs__NSLog  
0000000100000f43         lea        rdi, qword [0x100000f9b]                    ; "%s\\n", argument "format" for method imp___stubs__printf  
0000000100000f4a         lea        rsi, qword [0x100000f9f]                    ; "Hello, world!"  
0000000100000f51         mov        al, 0x0  
0000000100000f53         call       imp___stubs__printf  
0000000100000f58         xor        edx, edx  
0000000100000f5a         mov        dword [rbp+var_4], eax  
0000000100000f5d         mov        eax, edx  
0000000100000f5f         add        rsp, 0x10  
0000000100000f63         pop        rbp  
0000000100000f64         ret  
                        ; endp

明文展示了“Hello, world!”

使用脚本混淆后,反编译截取部分加密代码:

_main:  
0000000100000dd0         push       rbp  
0000000100000dd1         mov        rbp, rsp  
0000000100000dd4         sub        rsp, 0x60  
0000000100000dd8         lea        rax, qword [rbp+var_16]  
0000000100000ddc         mov        rcx, qword [___stack_chk_guard_100001000]  
0000000100000de3         mov        rcx, qword [rcx]  
0000000100000de6         mov        qword [rbp+var_8], rcx  
0000000100000dea         mov        rcx, qword [objc_cls_ref_NSString]  
0000000100000df1         mov        byte [rbp+var_16], 0xe2  
0000000100000df5         mov        byte [rbp+var_15], 0xcf  
0000000100000df9         mov        byte [rbp+var_14], 0xc6  
0000000100000dfd         mov        byte [rbp+var_13], 0xc6  
0000000100000e01         mov        byte [rbp+var_12], 0xc5  
0000000100000e05         mov        byte [rbp+var_11], 0x86  
0000000100000e09         mov        byte [rbp+var_10], 0x8a  
0000000100000e0d         mov        byte [rbp+var_F], 0xdd  
0000000100000e11         mov        byte [rbp+var_E], 0xc5  
0000000100000e15         mov        byte [rbp+var_D], 0xd8  
0000000100000e19         mov        byte [rbp+var_C], 0xc6  
0000000100000e1d         mov        byte [rbp+var_B], 0xce  
0000000100000e21         mov        byte [rbp+var_A], 0x8b  
0000000100000e25         mov        byte [rbp+var_9], 0x0  
0000000100000e29         mov        qword [rbp+var_40], rax  
0000000100000e2d         mov        rax, qword [rbp+var_40]  
0000000100000e31         mov        qword [rbp+var_48], rax  
0000000100000e35         mov        qword [rbp+var_50], rcx

这样就看不到原始的字符串了~

参考链接: http://xelz.info/blog/2016/11/20/ios-code-obfuscation/

自定义方法混淆

使用class-dump导出应用的头文件(随便截取的)

- (void)UpdateAppRecvMsgState:(id)arg1 isRecvMsg:(_Bool)arg2;
- (_Bool)UpdateAppSettingItem:(id)arg1;
- (_Bool)UpdateAuthAppList:(int)arg1;
- (_Bool)UpdateBatchAppSettingItem:(id)arg1;
- (_Bool)addAppByUser:(id)arg1;
- (void)addAppByUserMoveToAppSetting;
- (void)addGetAppInfoListQueue:(id)arg1;
- (void)addInstalledAppInfoByAppID:(id)arg1 appName:(id)arg2 appIconUrl:(id)arg3;

IDA

0000000102a94064 ldr x25, [x8, #0xf70] ; "logWithLevel:module:errorCode:file:line:func:format:",@selector(logWithLevel:module:errorCode:file:line:func:format:)

编写Tweak,hook这些方法触发应用,很容易就可以发现应用方法的调用流程 ~

  1. (http://www.jianshu.com/p/0d42e5c6361c
  2. http://www.javashuo.com/content/p-6598464.html

因为与上述字符串加密操作流程类似,并且链接中已经详述,就不在详述流程,参考链接中的思路设计算进行加密混淆- (void)LoadSetting方法在导出的头文件中就变成了这样- (void)HxzTJlnQXYWkZpt,这就变成了听说你想hook。。。

其他代码安全方法
使用 block

IDAblock代码块是不能正常解析的,所以一些调用网络或是一些较为核心的代码放在block中实 现,像这样

block = ^(){  
    [self getOrderDetail];
}

这部分代码这在IDA中是独立的代码块,而且不能生成直观的伪代码。如果在block方法中使用block,那对逆向来说应该相当酸爽。。。

自定义方法

在自定义方法中尽量不要使用这样

-(void)getOrderDetailWithOrderId:(NSString *)orderId

因为这样即使不知道发起网络请求需要的参数,只要在应用中获取orderId就能走通应用的流程,获得想要的数据~

iOS系统做安全有很大的局限性,上述方法可以用在一些核心代码中,但这些这些混淆的方法并不能阻止应用被分析破解,只是增加了逆向分析的难度,just 增加了难度 ~