第一:反調(diào)試,修改main.m
#import <dlfcn.h>
#import <sys/types.h>
//定義一個函數(shù)指針用來接收動態(tài)加載出來的函數(shù)ptrace
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif
// 阻止調(diào)試器attach
void disable_gdb() {
//第一個參數(shù)path為0時, 它會自動查找 $LD_LIBRARY_PATH,$DYLD_LIBRARY_PATH, $DYLD_FALLBACK_LIBRARY_PATH 和 當前工作目錄中的動態(tài)鏈接庫.
void * handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
//動態(tài)加載ptrace函數(shù),ptrace函數(shù)的參數(shù)個數(shù)和類型,及返回類型跟ptrace_ptr_t函數(shù)指針定義的是一樣的
ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace");
//執(zhí)行ptrace_ptr相當于執(zhí)行ptrace函數(shù)
ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
//關閉動態(tài)庫,并且卸載
dlclose(handle);
}
int main(int argc, char * argv[]) {
@autoreleasepool {
#ifndef DEBUG
disable_gdb();
#endif
signal(SIGPIPE, SIG_IGN);
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
第二:反注入,定時查看(不能在開始只檢查一次)。原理為lib庫白名單檢查
//代碼防注入
bool HKCheckWhitelist(){
int count = _dyld_image_count();
NSArray * arr = @[@"libstdc++.tbd",...,@"libViewDebuggerSupport.dylib"];
for (int i = 0; i < count; i++) {
//遍歷拿到庫名稱!
const char * imageName = _dyld_get_image_name(i);
//系統(tǒng)的lib Debug庫 除外
if (strstr(imageName, "/System/Library/Frameworks/") || strstr(imageName, "/Developer/") ) {
continue;
}
if (strstr(imageName, "libAppProxy") || strstr(imageName, "PacketTunnel")) {
continue;
}
NSString *str= [NSString stringWithCString:imageName encoding:[NSString defaultCStringEncoding]];
str = [str lastPathComponent];
//應用本身除外
if ([str isEqualToString:@"workspace"] ) {
continue;
}
BOOL isMyLib = NO;
for (NSString * libName in arr) {
if ([libName containsString:str]) {
isMyLib = YES;
}
}
if (isMyLib == NO) {
printf("lib已被修改==?。?s",imageName);
TLogD(@"lib已被修改==??!%s",imageName);
exit(0);
return NO;
}else{
return YES;
}
}
return YES;
}
第三:防止重簽打包的簡單驗證,原理為讀出打包的證書ID,然后和預埋的比較
+ (void)prepareEnv {
NSString *embeddedPath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"];
if ([[NSFileManager defaultManager] fileExistsAtPath:embeddedPath]) {
NSString *embeddedProvisioning = [NSString stringWithContentsOfFile:embeddedPath encoding:NSASCIIStringEncoding error:nil];
NSArray *embeddedProvisioningLines = [embeddedProvisioning componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for (int i = 0; i < [embeddedProvisioningLines count]; i++) {
if ([[embeddedProvisioningLines objectAtIndex:i] rangeOfString:@"application-identifier"].location != NSNotFound) {
NSInteger fromPosition = [[embeddedProvisioningLines objectAtIndex:i+1] rangeOfString:@"<string>"].location+8;
NSInteger toPosition = [[embeddedProvisioningLines objectAtIndex:i+1] rangeOfString:@"</string>"].location;
NSRange range;
range.location = fromPosition;
range.length = toPosition - fromPosition;
NSString *fullIdentifier = [[embeddedProvisioningLines objectAtIndex:i+1] substringWithRange:range];
NSArray *identifierComponents = [fullIdentifier componentsSeparatedByString:@"."];
NSString *appIdentifier = [identifierComponents firstObject];
// 對比簽名ID
if ([appIdentifier caseInsensitiveCompare:@“*******”] != NSOrderedSame) {
exit(0);
}
break;
}
}
}
}
第四:日志敏感信息。原理,利用fishhook,hook系統(tǒng)方法“NSLog”,進行過濾處理
#import "UIApplication+NSLog.h"
#import "fishhook.h"
@implementation UIApplication (NSLog)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//定義rebinding結構體
/*
struct rebinding {
const char *name;//需要HOOK的函數(shù)名稱,字符串
void *replacement;//替換到那個新的函數(shù)上(函數(shù)指針,也就是函數(shù)的名稱)
void **replaced;//保存原始函數(shù)指針變量的指針(它是一個二級指針!)
};
*/
rebind_symbols((struct rebinding[1]){{"NSLog", new_NSLog, (void *)&orig_NSLog}}, 1);
});
}
// orig_NSLog是原有方法被替換后 把原來的實現(xiàn)方法放到另一個地址中
// new_NSLog就是替換后的方法了
static void (*orig_NSLog)(NSString *format, ...);
void(new_NSLog)(NSString *format, ...) {
va_list args;
if(format) {
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
DDLogInfo(@"Hook:%@", message); //使用DDLog保存日志到本地
#ifndef DEBUG
orig_NSLog(@"===%@", message);//debug狀態(tài)下打印日志方便查看
#endif
va_end(args);
}
}
@end