zoukankan      html  css  js  c++  java
  • 使用Hook屏蔽NSLog 及 pirntf 的打印

    1、场景说明

    • 为何需要hook日志:
      • 控制台输出的日志太多太杂了,导致看不见关键信息.
      • 或者有些输出的日志search不到源码,但是需要知道从哪儿调用的?(比如想知道哪个第三方库调用的)

    2、解决办法

    • 2.1 控制台右下角文本过滤

    • 2.2 设置xcode环境变量

      • OS_ACTIVITY_MODE 为 Disable,将会所有log不可见,不论系统log还是自行输出log

      • 效果说明:屏蔽的只是对NSLog及NSLog的封装打印对象。而系统中好多的自动打印是使用了NSLog,使用该方法可以屏蔽系统打印。
      • 代码中操作不规范造成的系统自动打印
    • 2.3 自定义宏代替NSLog宏

    // DEBUG  模式下打印日志, 当前行
    #ifdef DEBUG
    	// 02 输出格式:第868行: 要打印的信息
    	#define CHLog(...) fprintf(stderr,"第%d行:%s
    ",/* 行号 */__LINE__, /* 动态参数 */[[NSString stringWithFormat:__VA_ARGS__] UTF8String]);
    // 发布状态
    #else
    	#define  CHLog(...)
    #endif
    
    • 2.4 第三方的库里面的打印

      • 还有一些Log可能是在第三方的库里面打印的,所以我们无法采用第三种方式。我们可以采用method_swizzle来进行方法替换,但是NSLog和printf是函数,这时候就需要用到fishhook来进行函数实现替换。
      • ① 原理:
        • 简单说就是修改系统函数地址(自定义函数不可hook),达到函数实现交换的目的
      • ② 替换对象
        • ⓐ 替换NSLog
        // 函数指针,用来保存原始的函数地址 (C 语言语法,函数指针类型变量)
        static void (*sys_nslog)(NSString *format, ...);
        // 定义一个新的函数
        void my_nslog(NSString *format, ...) {
            va_list vl;
            va_start(vl, format);
            NSString *str = [[NSString alloc] initWithFormat:format arguments:vl];
            va_end(vl);
        
            // 调用原始的:此处类似method_swizzle
            //sys_nslog([NSString stringWithFormat:@"hook => %@", str]);
        }
        
        • ⓑ 替换NSLogv,有些极少的情况,可能还需要hook NSLogv()
        // 函数指针,用来保存原始的函数地址 (C 语言语法,函数指针类型变量)
        static void (*orig_nslogv)(NSString *format,va_list args);
        // 定义一个新的函数
        void my_nslogv(NSString *format,va_list args) {
            //orig_nslogv(format,args);
        }
        
        • ⓒ 替换printf
        // C语言原有printf
        static void (*orig_printf)(const char *path, ...);
        // 定义一个新的函数
        void my_printf(const char *format,...) {
            // 什么都不写就是屏蔽打印
            //orig_printf(format);
        }
        
      • ③ 具体用法:
        • 给自己的工具类开个分类,添加以下代码
        • CHTool+Log.m
        #import "CHTool+Log.h"
        
        #include "fishhook.h"
        
        @implementation CHTool (Log)
        
        // 函数指针,用来保存原始的函数地址 (C 语言语法,函数指针类型变量)
        static void (*sys_nslog)(NSString *format, ...);
        // 定义一个新的函数
        void my_nslog(NSString *format, ...) {
            va_list vl;
            va_start(vl, format);
            NSString *str = [[NSString alloc] initWithFormat:format arguments:vl];
            va_end(vl);
        
            // 调用原始的:此处类似method_swizzle
            //sys_nslog([NSString stringWithFormat:@"hook => %@", str]);
        }
        
        // 函数指针,用来保存原始的函数地址 (C 语言语法,函数指针类型变量)
        static void (*orig_nslogv)(NSString *format,va_list args);
        // 定义一个新的函数
        void my_nslogv(NSString *format,va_list args) {
            //orig_nslogv(format,args);
        }
        
        // C语言原有printf
        static void (*orig_printf)(const char *path, ...);
        // 定义一个新的函数
        void my_printf(const char *format,...) {
            // 什么都不写就是屏蔽打印
            //orig_printf(format);
        }
        
        // 关闭以下对象控制的日志打印
        + (void)stop_AllLog {
            // 启动后执行下面这句话即可实现NSLog() hook
            struct rebinding nslog_rebinding = {"NSLog", my_nslog, (void*)&sys_nslog};
            // 1代表后面有一个函数实现需要重新绑定
            rebind_symbols((struct rebinding[1]){nslog_rebinding}, 1);
            
            // 启动后执行下面这句话即可实现NSLogv() hook
            struct rebinding nslogv_rebinding = {"NSLogv",my_nslogv,(void*)&orig_nslogv};
            // 1代表后面有一个函数实现需要重新绑定
            rebind_symbols((struct rebinding[1]){nslogv_rebinding}, 1);
            
            // 启动后执行下面这句话即可实现printf() hook
            struct rebinding printf_rebinding = {"printf", my_printf, (void*)&orig_printf};
            // 1代表后面有一个函数实现需要重新绑定
            rebind_symbols((struct rebinding[1]){printf_rebinding}, 1);
        }
        
        @end
        
        • CHTool+Log.h
        #import "CHTool.h"
        
        NS_ASSUME_NONNULL_BEGIN
        
        @interface CHTool (Log)
        
        // DEBUG  模式下打印日志, 当前行
        #ifdef DEBUG
        	// 02 输出格式:第868行: 要打印的信息
        	#define CHLog(...) fprintf(stderr,"第%d行:%s
        ",/* 行号 */__LINE__, /* 动态参数 */[[NSString stringWithFormat:__VA_ARGS__] UTF8String]);
        // 发布状态
        #else
        	#define  CHLog(...)
        #endif
        // 关闭所有的日志打印
        + (void)stop_AllLog;
        
        @end
        
        • 据我自己的观察,fprintf 方法第三方用的比较少,所以保留成我自己的打印方法。
      • ④ 应用启动入口调用该方法就可以了
      #import <UIKit/UIKit.h>
      
      #import "AppDelegate.h"
      
      int main(int argc, char * argv[]) {
          @autoreleasepool {
              
              // 关闭所有的日志打印
              [CHTool stop_AllLog];
              
              return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
          }
      }
      
      • 效果:
  • 相关阅读:
    POJ 2251 Dungeon Master
    HDU 3085 Nightmare Ⅱ
    CodeForces 1060 B Maximum Sum of Digits
    HDU 1166 敌兵布阵(树状数组)
    HDOJ 2050 折线分割平面
    HDU 5879 Cure
    HDU 1878 欧拉回路
    HDU 6225 Little Boxes
    ZOJ 2971 Give Me the Number
    HDU 2680 Choose the best route
  • 原文地址:https://www.cnblogs.com/CH520/p/14007974.html
Copyright © 2011-2022 走看看