iOS加固

1. 需求背景

App越狱机存在反编译的情景。存在刷金币,等类似外挂的行为。App加固。使越狱者不能hookApp的方法。

2. 旧方案问题

玩吧App越狱可逆向。

3. iOS上线版本

v10.5

4. 影响范围/ 风险预警

需要测试详细测试。改动全局。 需要越狱测试机,我这边做加固完模拟攻防。

开发周期 3-5天,测试周期:3-5天。

5. 测试注意点

测开需要也做下模拟逆向攻防。并且做全局测试回归。

建议逐步改进。

6.技术方案

6.1.使用NSFileManager判断设备是否安装了如下越狱常用工具:

eg:

/Applications/Cydia.app
/Library/MobileSubstrate/MobileSubstrate.dylib
/bin/bash
/usr/sbin/sshd
/etc/apt

if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"]){

return YES;

}

6.1.1 尝试打开cydia应用注册的URL scheme:

if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://package/com.example.package"]]){
NSLog(@"Device is jailbroken");
}

6.1.2 尝试读取下应用列表,看看有无权限获取:
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/User/Applications/"]){
NSLog(@"Device is jailbroken");
NSArray *applist = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/User/Applications/"
error:nil];
NSLog(@"applist = %@",applist);
}

攻击者可能会hook NSFileManager 的方法,让你的想法不能如愿。可以回避 NSFileManager,

6.1.3 尝试打开cydia应用注册的URL scheme:使用stat系列函数检测Cydia等工具:

import <sys/stat.h>

void checkCydia(void)
{
struct stat stat_info;
if (0 == stat("/Applications/Cydia.app", &stat_info)) {
NSLog(@"Device is jailbroken");
}
}

6.1.4 如果攻击者可能会利用 Fishhook原理 hook了stat。

import <dlfcn.h>

void checkInject(void)
{
int ret ;
Dl_info dylib_info;
int (*func_stat)(const char *, struct stat *) = stat;
if ((ret = dladdr(func_stat, &dylib_info))) {
NSLog(@"lib :%s", dylib_info.dli_fname);
}
}

如果结果不是 /usr/lib/system/libsystem_kernel.dylib 的话,那就100%被攻击了。

6.1.5 还可以检索一下自己的应用程序是否被链接了异常动态库。

列出所有已链接的动态库:

import <mach-o/dyld.h>

void checkDylibs(void)
{
uint32_t count = _dyld_image_count();
for (uint32_t i = 0 ; i < count; ++i) {
NSString *name = [[NSString alloc]initWithUTF8String:_dyld_get_image_name(i)];
NSLog(@"--%@", name);
}
}

通常情况下,会包含越狱机的输出结果会包含字符串: Library/MobileSubstrate/MobileSubstrate.dylib 。

攻击者可能会给MobileSubstrate改名,但是原理都是通过DYLD_INSERT_LIBRARIES注入动态库。

通过检测当前程序运行的环境变量:
void printEnv(void)

{

char *env = getenv("DYLD_INSERT_LIBRARIES");

NSLog(@"%s", env);

}

未越狱设备返回结果是null,越狱设备就各有各的精彩了,尤其是老一点的iOS版本越狱环境。

6.2 为了不让攻击者理清自己程序的敏感业务逻辑,于是我们想方设法提高逆向门槛。利用static关键字裁掉函数符号。

如果函数属性为 static ,那么编译时该函数符号就会被解析为local符号。
在发布release程序时(用Xcode打包编译二进制)默认会strip裁掉这些函数符号,无疑给逆向者加大了工作难度。

eg:

static id static_createBtn()
{
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectZero];
[btn setFrame:CGRectMake(50, 100, 100, 100)];
[btn setBackgroundColor:[UIColor blueColor]];
btn.layer.cornerRadius = 7.0f;
btn.layer.masksToBounds = YES;
return btn;

}

怎么让别的文件也能调到本文件的static方法呢?
在本文件建造一个结构体,结构体里包含函数指针。把static函数的函数指针都赋在这个结构体里,再把这个结构体抛出去。
这样做的好处是,既隐藏了函数代码也丰富了调用方式。

6.2.1 为了不让攻击者理清自己程序的敏感业务逻辑,于是我们想方设法提高逆向门槛。利用static关键字裁掉函数符号。为了安全,将敏感的方法改写为C函数。

改写方法如下:

@interface XXUtil : NSObject
    • (BOOL)isVerified;
    • (BOOL)isNeedSomething;
    • (void)resetPassword:(NSString *)password;
  1. @end

    改写为:

    //XXUtil.h

    import <Foundation/Foundation.h>

    typedef struct _util {
    BOOL (isVerified)(void);
    BOOL (
    isNeedSomething)(void);
    void (*resetPassword)(NSString *password);
    }XXUtil_t ;

    define XXUtil ([_XXUtil sharedUtil])

    @interface _XXUtil : NSObject

    • (XXUtil_t *)sharedUtil;
      @end

    import "XXUtil.h"

    static BOOL _isVerified(void)
    {
    //bala bala ...
    return YES;
    }

    static BOOL _isNeedSomething(void)
    {
    //bala bala ...
    return YES;
    }

    static void _resetPassword(NSString *password)
    {
    //bala bala ...
    }

    static XXUtil_t * util = NULL;
    @implementation _XXUtil

    +(XXUtil_t *)sharedUtil
    {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    util = malloc(sizeof(XXUtil_t));
    util->isVerified = _isVerified;
    util->isNeedSomething = _isNeedSomething;
    util->resetPassword = _resetPassword;
    });
    return util;
    }

    • (void)destroy
      {
      util ? free(util): 0;
      util = NULL;
      }
      @end

    调用 XXUtil->isVerified();

6.3 Objective-C代码混淆,阻止 class-dump出可读的信息有效方法是易读字符替换。

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

以下脚本。放进Xcode 的Build Phrase 中设定在编译之前进行方法名的字符串替换。 结合外部plist要替换的方法使用。

!/usr/bin/env bash

TABLENAME=symbols
SYMBOL_DB_FILE="symbols"
STRING_SYMBOL_FILE="func.list"
HEAD_FILE="PROJECT_DIR/PROJECT_NAME/codeObfuscation.h"
export LC_CTYPE=C

维护数据库方便日后作排重

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

insertValue()
{
echo "insert into TABLENAME values('1' ,'2');" | sqlite3SYMBOL_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 -fHEAD_FILE
createTable

touch $HEAD_FILE
echo '#ifndef Demo_codeObfuscation_h

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` echoline ramdom insertValueline ramdom echo "#defineline ramdom" >>HEAD_FILE
fi
done
echo "#endif" >> $HEAD_FILE

使用:

  1. //添加混淆作用的头文件(这个文件名是脚本confuse.sh中定义的)

  2. import "codeObfuscation.h"

效果:

[图片上传失败...(image-7b2a62-1591782762772)]

网上也有一些工具。混淆方法比较多。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容