注意大量的流程混淆会导致上架失败
准备工作
- 新建一个工程,并新建一个
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 */
-
运行,发现当前函数符号被混淆了
-
静态分析
字符常量混淆
//需要加密的字符串 @"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
的库路径
通过
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);
汇编 触发中断
- 汇编调用
syscall
和ptrace
// 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
指令,找到相同的汇编指令,实现破解