iOS -- 逆向 代码混淆

注意大量的流程混淆会导致上架失败

准备工作

  • 新建一个工程,并新建一个UserInfo
@interface UserInfoClass : NSObject

+ (BOOL)isVipWithAccount:(NSString *)account;

@end

#import "UserInfo.h"

@implementation UserInfoClass

+ (BOOL)isVipWithAccount:(NSString *)account{
    if ([account isEqualToString:@"hank"]) {
        return YES;
    }
    return NO;
}

@end

  • ViewController中调用

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    if ([UserInfoClass isVipWithAccount:@"hank123"]) {
        NSLog(@"是VIP");
    }else{
        NSLog(@"不是VIP");
    }
}

类名,方法名混淆

只能处理自定义的

  • 新建一个PrefixHeader.pch文件

  • PrefixHeader.pch中定义

#ifndef PrefixHeader_pch
#define PrefixHeader_pch
 
#define UserInfo CJKD2534
#define isVipWithAccount  KKLDIU34235

#endif /* PrefixHeader_pch */
  • 运行,发现当前函数符号被混淆了


    image.png
  • 静态分析


    image.png

字符常量混淆

//需要加密的字符串  @"IU**YD#$%()*"

#define KEY 0xAC
static NSString * AES_KEYINFO(){
    //这种方式能够让这些字符串不进入常量区。
    unsigned char key[] = {
        (KEY ^ 'I'),
        (KEY ^ 'U'),
        (KEY ^ '&'),
        (KEY ^ '*'),
        (KEY ^ '('),
        (KEY ^ '$'),
        (KEY ^ '%'),
        (KEY ^ ')'),
        (KEY ^ '\0')
    };
    unsigned char * p = key;
    while (((*p) ^= KEY) != '\0') p++;
    
    return [NSString stringWithUTF8String:(const char *)key];
}

dlopen 防护fishhook

  • 通过断点ptrace函数,image list打印库列表,拿到ptrace的库路径

    image.png

  • 通过dlopen可以将ptrace移出间接符号表,防止fishhook

#import 


    //通过dlopen拿到句柄(动态库)
    void * handle = dlopen("/usr/lib/system/libsystem_kernel.dylib",RTLD_LAZY);
    //定义函数指针
    int (*ptrace_p)(int _request, pid_t _pid, caddr_t _addr, int _data);
    ptrace_p = dlsym(handle,"ptrace");
    if (ptrace_p) {
        ptrace_p(PT_DENY_ATTACH,0,0,0);
    }

  • 混淆ptrace
void antyDebug(){

    unsigned char ptraceStr[] = {
        (KEY ^ 'p'),
        (KEY ^ 't'),
        (KEY ^ 'r'),
        (KEY ^ 'a'),
        (KEY ^ 'c'),
        (KEY ^ 'e'),
        (KEY ^ '\0')
    };
    unsigned char * p = ptraceStr;
    while (((*p) ^= KEY) != '\0') p++;

    //通过dlopen拿到句柄(动态库)
    void * handle = dlopen("/usr/lib/system/libsystem_kernel.dylib",RTLD_LAZY);
    //定义函数指针
    int (*ptrace_p)(int _request, pid_t _pid, caddr_t _addr, int _data);
    ptrace_p = dlsym(handle,(const char *)ptraceStr);

    if (ptrace_p) {
        ptrace_p(PT_DENY_ATTACH,0,0,0);
    }
}

  • 但是还是可以通过函数调用栈来找到ptrace的地址,通过静态修改破解

syscall 间接调用ptrace

通过syscall间接调用系统函数ptrace

  • 但是syscall会保存在间接符号表中,还是可以被fishhook
#import 


    //syscall
    /**
     1、编号,你要调用哪个系统函数
     2、后面都是参数!
     */
   syscall(26,31,0,0,0);
image.png

汇编 触发中断

  • 汇编调用syscallptrace

//    syscall
    /**
     1、编号,你要调用哪个系统函数
     2、后面都是参数!
     */
    syscall(26,31,0,0,0);
    
    
//    相当于是调用syscall
    asm volatile(
                 "mov x0,#26\n"
                 "mov x1,#31\n"
                 "mov x2,#0\n"
                 "mov x3,#0\n"
                 "mov x4,#0\n"
                 "mov x16,#0\n"//这里就是syscall的编号
                 "svc #0x80\n"//这条指令就是触发中断(系统级别的跳转!)
                 );
    
//    下面就是直接调用ptrace
    asm volatile(
                 "mov x0,#31\n"
                 "mov x1,#0\n"
                 "mov x2,#0\n"
                 "mov x3,#0\n"
                 "mov x16,#26\n"//这里就是syscall的编号
                 "svc #0x80\n"//这条指令就是触发中断(系统级别的跳转!)
                 );

  • 防护检测,触发软中断,退出程序
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    #ifdef  __arm64__
        asm(
            "mov x0,#0\n"
            "mov x16,#1\n"
            "svc #0x80\n"
            );
    #endif
    #ifdef __arm__
        asm(
            "mov r0,#0\n"
            "mov r16,#1\n"
            "svc #80\n"
            );
    #endif
    
}
  • 我们依然可以通过静态分析,检索svc指令,找到相同的汇编指令,实现破解

你可能感兴趣的:(iOS -- 逆向 代码混淆)