我来科锐学习了不少时间了,发点学习记录,虽然科锐没教iOS,但是学习思路是想通的,本人之前做了几年iOS开发,苦于工作加班严重和逆向难入门,所以来到科锐学习Windows逆向,以求曲线救国。这里感谢钱老师的教导。
iOS代码保护 :
在大多数iOS应用中,一些工具,比如Clutch,class-dump,cycript,lldb,theos.对应用程序的结构,代码逻辑,运行流程,可以做到很容易的分析。然后进行应用的破解,篡改,重签名。所以很有必要对代码做一些保护。
iOS代码保护思路:
可以从逆向分析的方式入手:
1.静态分析:针对这种情况可以把字符串加密 ,类名方法名混淆,代码混淆
2.调试 :反调试
3.注入 :反注入
4.中间人攻击 :https, 证书验证, 数据加密
下面依次介绍下实例:
字符串加密:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(@"Hello CR25");
} 比如这种字符串,我们看看其反汇编代码:
0000000100006794 sub sp , sp , # 0x30 ; Objective C Implementation defined at 0x1000080f8 (instance method), DATA XREF=0x1000080f8
0000000100006798 stp x29 , x30 , [sp , #0x20 ]
000000010000679c add x29 , sp , #0x20
00000001000067a0 mov x8 , sp
00000001000067a4 adrp x9 , # 0x100008000
00000001000067a8 add x9 , x9 , #0xc88 ; @selector(viewDidLoad)
00000001000067ac adrp x10 , # 0x100008000
00000001000067b0 add x10 , x10 , #0xca8 ; 0x100008ca8
00000001000067b4 stur x0 , [x29 , #-0x8 ]
00000001000067b8 str x1 , [sp , #0x10 ]
00000001000067bc ldur x0 , [x29 , #-0x8 ]
00000001000067c0 str x0 , sp
00000001000067c4 ldr x10 , x10
00000001000067c8 str x10 , [sp , #0x8 ]
00000001000067cc ldr x1 , x9
00000001000067d0 mov x0 , x8
00000001000067d4 bl imp___stubs__objc_msgSendSuper2
00000001000067d8 adrp x0 , #0x100008000 ; argument #1 for method imp___stubs__NSLog
00000001000067dc add x0 , x0 , #0x60 ; @"Hello CR25"
00000001000067e0 bl imp___stubs__NSLog
00000001000067e4 ldp x29 , x30 , [sp , #0x20 ]
00000001000067e8 add sp , sp , #0x30
00000001000067ec ret
CR25明文,如果我们这里是程序的敏感信息的话,分析者就会很容易找到我们的敏感信息。这里需要给字符串加密,然后运行时进行动态解密。
这里为了举例,我只做了简单的异或,具体算法你可以根据需求自己选择。
字符串加密后源码:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(DecodeOcString(&_7VA7EOJRUDOSFIS));
} 再看看反汇编:
-[ViewController viewDidLoad]:
0000000100006660 sub sp , sp , # 0x40 ; Objective C Implementation defined at 0x1000080e0 (instance method), DATA XREF=0x1000080e0
0000000100006664 stp x29 , x30 , [sp , #0x30 ]
0000000100006668 add x29 , sp , #0x30
000000010000666c add x8 , sp , #0x10
0000000100006670 adrp x9 , # 0x100008000
0000000100006674 add x9 , x9 , #0xc70 ; @selector(viewDidLoad)
0000000100006678 adrp x10 , # 0x100008000
000000010000667c add x10 , x10 , #0xca8 ; 0x100008ca8
0000000100006680 stur x0 , [x29 , #-0x8 ]
0000000100006684 stur x1 , [x29 , #-0x10 ]
0000000100006688 ldur x0 , [x29 , #-0x8 ]
000000010000668c str x0 , [sp , #0x10 ]
0000000100006690 ldr x10 , x10
0000000100006694 str x10 , [sp , #0x18 ]
0000000100006698 ldr x1 , x9
000000010000669c mov x0 , x8
00000001000066a0 bl imp___stubs__objc_msgSendSuper2
00000001000066a4 adrp x8 , # 0x100008000 ; argument #1 for method __B97DE2E4_175_F0C445_2D3_29549CFFE480
00000001000066a8 add x0 , x8 , #0xd58 ; __7VA7EOJRUDOSFIS
00000001000066ac bl __B97DE2E4_175_F0C445_2D3_29549CFFE480
00000001000066b0 mov x29 , x29
00000001000066b4 bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000066b8 mov x1 , x0
00000001000066bc str x0 , [sp , #0x8 ]
00000001000066c0 mov x0 , x1
00000001000066c4 bl imp___stubs__NSLog
00000001000066c8 ldr x0 , [sp , #0x8 ]
00000001000066cc bl imp___stubs__objc_release
00000001000066d0 ldp x29 , x30 , [sp , #0x30 ]
00000001000066d4 add sp , sp , #0x40
00000001000066d8 ret
这个时候你就看不到明文字符串了。一个项目中的字符串不计其数,如果是都要进行加密,需要遍历源文件然后进行加密。这里还有另外一种选择,就是用clang生成语法树,然后拿到节点,然后再进行加密。
Clang生成语法树 :
如下源码:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
static char* str1 = nil;
static char * str2 = "cr25HelloWorld";
static NSString *str3 = nil;
static NSString *str4 = @"cr23HelloWorld";
char* str5 = "cr24HelloWorld";
NSString *str6 = @"cr21HelloWorld\n";
NSString *str7 = [NSString stringWithFormat:@"I'm%@",@"cr25"];
} 终端输入命令:
xcrun -sdk iphoneos clang -arch arm64 -Xclang -ast-dump -fsyntax-only -F UIKit ViewController.m
然后输出语法树:(由于输出内容太多,这里只截取部分)
`- StringLiteral 0x7fb3e744b3c8 < col:26 > 'char [15]' lvalue "cr25HelloWorld"
| |- DeclStmt 0x7fb3e744b538 < line:24:5 , col:32 >
| | `- VarDecl 0x7fb3e744b448 < col:5 , /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/usr/include/sys/_types.h:52:33 > ViewController.m:24:22 str3 'NSString *' static cinit
| | `- ImplicitCastExpr 0x7fb3e744b520 < /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/usr/include/sys/_types.h:52:23 , col:33 > 'NSString *' < NullToPointer >
| | `- ParenExpr 0x7fb3e744b500 < col:23 , col:33 > 'void *'
| | `- CStyleCastExpr 0x7fb3e744b4d8 < col:24 , col:32 > 'void *' < NullToPointer >
| | `- IntegerLiteral 0x7fb3e744b4a8 < col:32 > 'int' 0
| |- DeclStmt 0x7fb3e744b620 < ViewController.m:26:5 , col:46 >
| | `- VarDecl 0x7fb3e744b568 < col:5 , col:30 > col:22 str4 'NSString *' static cinit
| | `- ObjCStringLiteral 0x7fb3e744b600 < col:29 , col:30 > 'NSString *'
| | `- StringLiteral 0x7fb3e744b5c8 < col:30 > 'char [15]' lvalue "cr23HelloWorld"
| |- DeclStmt 0x7fb3e744b6f8 < line:28:5 , col:34 >
| | `- VarDecl 0x7fb3e744b648 < col:5 , col:18 > col:11 str5 'char *' cinit
| | `- ImplicitCastExpr 0x7fb3e744b6e0 < col:18 > 'char *' < ArrayToPointerDecay >
| | `- StringLiteral 0x7fb3e744b6a8 < col:18 > 'char [15]' lvalue "cr24HelloWorld"
| |- DeclStmt 0x7fb3e744b7e0 < line:30:5 , col:41 >
| | `- VarDecl 0x7fb3e744b728 < col:5 , col:23 > col:15 str6 'NSString *' cinit
| | `- ObjCStringLiteral 0x7fb3e744b7c0 < col:22 , col:23 > 'NSString *'
| | `- StringLiteral 0x7fb3e744b788 < col:23 > 'char [16]' lvalue "cr21HelloWorld\n"
| `- DeclStmt 0x7fb3e744b998 < line:32:5 , col:66 >
| `- VarDecl 0x7fb3e744b810 < col:5 , col:65 > col:15 str7 'NSString *' cinit
| `- ObjCMessageExpr 0x7fb3e744b958 < col:22 , col:65 > 'NSString * _Nonnull':'NSString *' selector=stringWithFormat: class= 'NSString'
| |- ObjCStringLiteral 0x7fb3e744b8b0 < col:49 , col:50 > 'NSString *'
| | `- StringLiteral 0x7fb3e744b880 < col:50 > 'char [6]' lvalue "I'm%@"
| `- ObjCStringLiteral 0x7fb3e744b938 < col:58 , col:59 > 'NSString *'
| `- StringLiteral 0x7fb3e744b908 < col:59 > 'char [5]' lvalue "cr25"
这样子就生成了语法树,每个节点信息都表示得很清晰。
比如:
`- VarDecl 0x7fb3e744b568 < col:5 , col:30 > col:22 str4(变量名) 'NSString *'(类型) static cinit(静态)
| | `- ObjCStringLiteral(OC字符串) 0x7fb3e744b600 < col:29 , col:30 > 'NSString *'
| | `- StringLiteral(C类型的字符串) 0x7fb3e744b5c8 < col:30 > 'char [15]' lvalue "cr23HelloWorld"
我们可以利用Clang的一些API进行分析与加密(例子源码见附件,感谢Monkey的开源源码 ):
1.首先需要dlopen一个动态库:libclang.dylib
2.初始化函数指针:initlibfunclist(void* handle);
3.在这个函数enum CXChildVisitResult printVisitor( CXCursor cursor, CXCursor parent, CXClientData client_data) 里遍历出文件名,变量名,类型,以及字符是OC字符串还是C字符串,最重要的是我们可以在这个函数里拿到字符串的开始和结束的位置,然后再进行字符串加密操作。这样子就可以把整个项目的字符串进行加密。
(今天先记录下字符串加密,其他加固方式下次再记录)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: