一、日志输出
关闭XCODE打包时日志打印
项目Edit Scheme -所有命令的 Build Configration 设置为Release
二、后台快照
应用进入后台时仍会展示当且的页面,模糊视图即可
修改前后:
-
2D477E38-36B5-4919-8535-2CE1C3066DB1.png
-
23ECCA4E-6542-49AD-9175-A961E693E942.png
代码:
.h
/**
后台模糊工具
*/
@interface SafeBackstageTool : NSObject
/**
单例对象
@return 单例
*/
+ (instancetype)shared;
/**
模糊后台视图
*/
- (void)blurBackstageView;
/**
移除后台模糊视图
*/
- (void)clearBackstageView;
/**
获取当前展示视图
@return 当前展示视图
*/
- (UIViewController *)setupCurrentViewController;
@end
.m
#import "AppDelegate.h"
#import "SafeBackstageTool.h"
//屏幕宽度
#define ScreenWidth [UIScreen mainScreen].bounds.size.width
//屏幕高度
#define ScreenHeight [UIScreen mainScreen].bounds.size.height
@interface SafeBackstageTool ()
/**
当前视窗
*/
@property (nonatomic, strong) UIWindow *window;
@end
// 单例对象
static SafeBackstageTool *singletonVC;
// dispatch_once_t
static dispatch_once_t onceToken;
// 偏移量
static NSUInteger const kOffset = 0X33;
@implementation SafeBackstageTool
/**
单例对象
@return 单例
*/
+ (instancetype)shared {
dispatch_once(&onceToken, ^{
singletonVC = [[SafeBackstageTool alloc] init];
});
return singletonVC;
}
/**
模糊后台视图
*/
- (void)blurBackstageView {
[self setupKeyWindow];
UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
view.tag = kOffset;
// 获取当前视图控制器
UIViewController *controller = [self setupCurrentViewController];
UIImage *image = [self snapshot:controller.view];
imageView.image = [self setupCoreBlurImage:image];
imageView.contentMode = UIViewContentModeScaleAspectFill;
[view addSubview:imageView];
[self.window addSubview:view];
}
- (void)setupKeyWindow {
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.window = app.window;
}
// 获取当前屏幕显示的viewcontroller
- (UIViewController *)setupCurrentViewController {
if (!self.window) {
[self setupKeyWindow];
}
UIViewController *result = nil;
UIView *frontView = [[self.window subviews] firstObject];
id nextResponder = [frontView nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
result = nextResponder;
} else {
result = self.window.rootViewController;
}
return result;
}
// 截取当前视图为图片
- (UIImage *)snapshot:(UIView *)view {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, 0);
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
// 对图片进行模糊处理
- (UIImage *)setupCoreBlurImage:(UIImage *)image {
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *inputImage= [CIImage imageWithCGImage:image.CGImage];
// 设置filter
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[filter setValue:inputImage forKey:kCIInputImageKey];
// 模糊图片
CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGRect rect = CGRectMake(0, 0, ScreenWidth * 2, ScreenHeight * 2);
CGImageRef outImage = [context createCGImage:result fromRect:rect];
UIImage *blurImage = [UIImage imageWithCGImage:outImage];
CGImageRelease(outImage);
return blurImage;
}
/**
移除后台模糊视图
*/
- (void)clearBackstageView {
UIView *view = [self.window viewWithTag: kOffset];
if (view) {
[UIView animateWithDuration:0.5 animations:^{
[view removeFromSuperview];
}];
}
}
@end
AppDelegate.m
- (void)applicationWillResignActive:(UIApplication *)application {
// 后台模糊
[[SafeBackstageTool shared] blurBackstageView];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// 移除后台模糊
[[SafeBackstageTool shared] clearBackstageView];
}
三、越狱检测
设备越狱提示或退出程序
.h
/**
检查设备是否越狱
*/
@interface JailBreakCheckTool : NSObject
+ (BOOL)isJailbroken;
/**
越狱设备提示
*/
+ (void)setupJailBreakAlertWithController:(UIViewController *)controller;
@end
.m
#import "JailBreakCheckTool.h"
#include <sys/stat.h>
#include <dlfcn.h>
#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
const char* jailbreak_paths[] = {
"/Applications/Cydia.app",
"/Library/MobileSubstrate/MobileSubstrate.dylib",
"/var/lib/cydia/",
"/var/cache/apt"
};
@implementation JailBreakCheckTool
+ (BOOL)isJailbroken {
// 以下检测的过程是越往下,越狱越高级
BOOL jailbroken = NO;
if ([self judgeFilePath]) {
jailbroken = YES;
}
if ([self judgeFilePathWithStat]) {
jailbroken = YES;
}
// 可能存在stat也被hook了,可以看stat是不是出自系统库,有没有被攻击者换掉
// 在真机的情况下,这里要判断是否是模拟器,模拟器系统库不是这个
#if !(TARGET_IPHONE_SIMULATOR)
// 如果不是系统库,判断已越狱 0
int ret;
Dl_info dylib_info;
int (*func_stat)(const char *,struct stat *) = stat;
if ((ret = dladdr(func_stat, &dylib_info))) {
if (strcmp(dylib_info.dli_fname, "/usr/lib/system/libsystem_kernel.dylib")) {
jailbroken = YES;
}
}
#else
NSLog(@"The device is IPHONE_SIMULATOR!");
#endif
// 如果攻击者给MobileSubstrate改名,但是原理都是通过DYLD_INSERT_LIBRARIES注入动态库
// 那么可以,检测当前程序运行的环境变量
char *env = getenv("DYLD_INSERT_LIBRARIES");
if (env != NULL) {
jailbroken = YES;
}
return jailbroken;
}
// 判断是否存在文件
+ (BOOL)judgeFilePath {
for (int index = 0; index < ARRAY_SIZE(jailbreak_paths); index++) {
if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithUTF8String:jailbreak_paths[index]]]) {
NSLog(@"The device is jail broken!");
return YES;
}
}
return NO;
}
// 可能存在hook了NSFileManager方法,此处用底层C stat去检测 越狱文件
+ (BOOL)judgeFilePathWithStat {
struct stat stat_info;
for (int index = 0; index < ARRAY_SIZE(jailbreak_paths); index++) {
if (0 == stat(jailbreak_paths[index], &stat_info)) {
NSLog(@"The device is jail broken!");
return YES;
}
}
return NO;
}
/**
越狱设备提示
*/
+ (void)setupJailBreakAlertWithController:(UIViewController *)controller {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:L(@"tip")
message:@"当前设备已越狱,是否继续?"
preferredStyle:UIAlertControllerStyleAlert];
WS(weakSelf);
UIAlertAction *action = [UIAlertAction actionWithTitle:@"继续" style:UIAlertActionStyleDefault handler:nil];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
[weakSelf exitApplication];
}];
[alertController addAction:cancel];
[alertController addAction:action];
UIViewController *controller = [[SafeBackstageTool shared] setupCurrentViewController];
[controller presentViewController:alertController animated:YES completion:nil];
}
/**
退出程序
*/
+ (void)exitApplication {
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UIWindow *window = app.window;
[UIView animateWithDuration:1.0f animations:^{
window.alpha = 0;
window.frame = CGRectMake(0, window.bounds.size.width, 0, 0);
} completion:^(BOOL finished) {
exit(0);
}];
}
@end
使用
// 越狱检测
if ([JailBreakCheckTool isJailbroken]) {
[JailBreakCheckTool setupJailBreakAlertWithController:self];
}
四、输入类组件禁止复制粘贴
复制粘贴可能导致信息泄露
写个类继承 UITextField 、UITextView,实现以下方法即可
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
UIMenuController *menuController = [UIMenuController sharedMenuController];
if(menuController) {
[UIMenuController sharedMenuController].menuVisible=NO;
}
return NO;
}
网友评论