学计算机的那个

不是我觉到、悟到,你给不了我,给了也拿不住;只有我觉到、悟到,才有可能做到,能做到的才是我的.

0%

iOS防逆向代码混淆

上一篇文章里可以看到,砸壳(Dumpdecrypted破壳)之后的ipa包使用class-dump分析之后,App跟裸奔一样,所以需要做代码混淆来添加逆向的难度。

砸壳

砸壳就是对安装包进行逆向操作,对已加密的软件进行解密,从而获得真实的软件代码。App Store下载的包全部都是经过苹果加密过的包(苹果不允许开发者自己加密ipa包),加密后的ipa包,无法对其进行反编译,也无法class-dump,需要对其进行解密才能反编译。

砸壳方式

  1. 静态砸壳
    使用已知的解密方法对软件进行解密叫静态砸壳,难度大,需要知道其软件的加密算法。
  2. 动态砸壳
    从进程的内存空间中获取软件镜像(image)进行转存处理叫动态砸壳。

动态砸壳工具

  1. clutch

2.dumpdecrypted
通过建立一个名为dumpdecrypted.dylib的动态库,插入目标应用实现脱壳

otool(object file displaying tool)工具

Mac OS X下二进制可执行文件的动态连结库是dylib文件(也就是bsd风格的动态库),等价于windows的dll和linux的so。Mac基于bsd,所以也使用的dylib

它是Xcode自带的常用工具

作用

  1. 依赖库查询 otool -L
  • eg:查看微信的是否加密等信息
    1
    otool -l WeChart | grep -B 2 crypt
    1
    2
    3
    4
    5
    6
    7
     cryptoff 16384
    cryptsize 6651904
    cryptid 0
    cryptoff 16384
    cryptsize 6553600
    cryptid 0123456
    //其中cryptid代表是否加壳,1代表加壳,0代表已脱壳。我们发现打印了两遍,其实代表着该可执行文件支持两种架构armv7和arm64.
  1. 查看 Mach-O头结构

    1
    2
    3
    4
    5
    6
    $ otool -h /Applications/Sublime\ Text.app/Contents/MacOS/Sublime\ Text 

    Mach header
    magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
    0xfeedfacf 16777223 3 0x80 2 27 4336 0x00218085

  2. 查看汇编码 otool -tV

class-dump

用来分析ipa文件的class信息的工具,它利用Objective-C语言的runtime的特性,将存储在mach-O文件中的@interface和@protocol信息提取出来,并生成对应的.h文件

使用

  1. class-dump -H [.app文件的路径] -o [输出文件夹路径]
    就可以得到所有的.h文件

导出文件特点

使用 class-dump 命令导出头文件有以下特点:

  1. 不管 .h 还是 .m 文件中的属性和方法都会被导出;
  2. 某个类的类别中的方法也会被导出,导出到源文件中,比如 ViewController (Navigation) 中的方法被导出到 ViewController 中;
  3. 实现的协议也会被导出,比如 ViewControllerDelegate 的方法被导出到 ViewController 中,如果 ViewController 不实现 ViewControllerDelegate 协议讲不会被导出;
  4. 协议中定义的方法不会被导出,只会导出到实现协议的类中;

代码混淆

我们希望在开发时一直保留清晰可读的程序代码,方便自己。
同时,希望编译出来的二进制包含乱七八糟的混淆后的程序代码,恶心他人

原理

方法名混淆其实就是字符串替换,有2个方法可以,一个是#define,一个是利用tops。
利用#define的方法有一个好处,就是可以把混淆结果合并在一个.h中,在工程Prefix.pch的最前面#import这个.h。不导入也可以编译、导入则实现混淆。

1
2
单段的selector,如func: ,可以通过#define func 来实现字符串替换。
多段的selector,如a:b:c: ,可以通过分别#define a 、b、c 来实现字符串替换。

混淆脚本

主要思路是把敏感方法名集中写在一个名叫func.list的文件中,逐一#define成随机字符,追加写入.h

  • confuse.sh
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
41
42
43
44
45
46
47
48
49
#! /usr/bin/env bash
TABLENAME=symbols
SYMBOL_DB_FILE="symbols"
STRING_SYMBOL_FILE="$PROJECT_DIR/$PROJECT_NAME/Source/CodeConfuse/func.list"
HEAD_FILE="$PROJECT_DIR/$PROJECT_NAME/Source/CodeConfuse/codeObfuscation.h"

export LC_CTYPE=C

createTable()
{
echo "create table $TABLENAME(src text, des text);" | sqlite3 $SYMBOL_DB_FILE
}

insertValue()
{
echo "insert into $TABLENAME values('$1' ,'$2');" | sqlite3 $SYMBOL_DB_FILE
}

query()
{
echo "select * from $TABLENAME where src='$1';" | sqlite3 $SYMBOL_DB_FILE
}

ramdomString()
{
openssl rand -base64 64 | tr -cd 'a-zA-Z' |head -c 16
}

rm -f $SYMBOL_DB_FILE
rm -f $HEAD_FILE
createTable

touch $HEAD_FILE
echo '#ifndef Demo_codeObfuscation_h' >> $HEAD_FILE
echo '#define Demo_codeObfuscation_h' >> $HEAD_FILE

echo "//confuse string at `date`" >> $HEAD_FILE
cat "$STRING_SYMBOL_FILE" | while read -ra line; do
if [[ ! -z "$line" ]]; then
ramdom=`ramdomString`
echo $line $ramdom
insertValue $line $ramdom
echo "#define $line $ramdom" >> $HEAD_FILE
fi
done
echo "#endif" >> $HEAD_FILE

sqlite3 $SYMBOL_DB_FILE .dump

  • func.list

    1
    2
    3
    4
    5
    6
    loginPass
    newPwd
    smsCode
    secret
    tradePwd

  • codeObfuscation.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #ifndef Demo_codeObfuscation_h
    #define Demo_codeObfuscation_h
    //confuse string at Wed Jan 16 17:30:22 CST 2019
    #define loginPass ITqIAxhareFWDEst
    #define newPwd SRgVmxvZsIWUEAWQ
    #define smsCode MyiekqqKlJxLiNAx
    #define secret hMcpMgCDFGgXwLPL
    #define tradePwd ARIKWIPQnJOBNgfS
    #endif

使用

  1. 将混淆脚本confuse.sh放到工程目录下
  2. 修改Prefix.pch
    打开Xcode,修改XXX-Prefix.ch ,添加混淆头文件:
    # import “codeObfuscation.h”
  3. 配置build pharse 加载confuse.sh脚本
  4. 创建函数名列表func.list,写入待混淆的函数名,如:
1
2
3
4
5
6
-(void)sample;
-(void)seg1:(NSString *)string seg2:(NSUInteger)num;
//就这样写:
sample
seg1
seg2
  1. 编译查看结果
    直接build,混淆脚本会在编译前运行,进行字符随机替换,并且每次build的随机字符不同,

class-dump测试

参考

  1. class-dump的安装和使用
  2. Objective-C代码混淆
  3. iOS逆向之《越狱砸壳/ipa脱壳》