15_命令行工具的开发

命令行工具的本质:

  • 可执行文件
  • 和app可执行文件的区别只是在于没有资源文件,没有UI
zhanglingli@bogon Desktop % file Clutch 
Clutch: Mach-O universal binary with 3 architectures: [arm_v7:Mach-O executable arm_v7] [arm_v7s:Mach-O executable arm_v7s] [arm64:Mach-O 64-bit executable arm64]
Clutch (for architecture armv7):    Mach-O executable arm_v7
Clutch (for architecture armv7s):   Mach-O executable arm_v7s
Clutch (for architecture arm64):    Mach-O 64-bit executable arm64
zhanglingli@bogon Desktop % 

一、开发命令行工具

下面以分析桌面Clutch文件类型为例,开发一个命令行工具

01、创建项目
  • 如果命令行工具用在mac电脑上,那么可以直接创建命令行项目
  • 如果命令行工具用在iPhone上,那么可以创建iOS项目,然后删除除了main.minfo.plist之外的其他文件
02、编写代码,选择release模式编译
//main.m
#import 
#import 
#import 

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        //准备分析的文件路径
        NSString *path = @"/Users/zhanglingli/Desktop/Clutch";
        
        NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
        
        int length = sizeof(uint32_t);
        
        //读取magic,关于magic请参考mach-o那篇文章
        NSData *magicData = [handle readDataOfLength:length];
        uint32_t magicNumber;
        [magicData getBytes:&magicNumber length:length];
        
        if (magicNumber == FAT_MAGIC || magicNumber == FAT_CIGAM) {
            printf("FAT文件 ");
        }else if (magicNumber == MH_MAGIC || magicNumber == MH_CIGAM) {
            printf("非64bit架构文件 ");
        }else if (magicNumber == FAT_MAGIC_64 || magicNumber == FAT_CIGAM_64) {
            printf("64bit架构文件 ");
        }
        
        printf("magicNumber = 0x%x\n",magicNumber);
        
        [handle closeFile];
        
    }
    return 0;
}
03、导出mach-o文件
  • 放到bin目录
  • 赋予权限
    % chmod +x /usr/local/bin/LLZTools
04、执行命令行工具

% LLZTools FAT文件 magicNumber = 0xbebafeca

二、参数说明

/**
 * argc: 参数的个数
 * argv:存放参数的数组
 * argv[0]:当前可执行文件的路径
 */
int main(int argc, char * argv[]) {
}

例:以分析mach-o文件架构类型为例,由用户提供文件路径

int main(int argc, const char * argv[]) {
    @autoreleasepool {
          
        if (argc == 1 || argc > 2) {
            printf("格式错误");
            return 0;
        }
        
        //准备分析的文件路径
        NSString *path = [NSString stringWithUTF8String:argv[1]];
          
        NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
          
          int length = sizeof(uint32_t);
          
          NSData *magicData = [handle readDataOfLength:length];
          
          uint32_t magicNumber;
          [magicData getBytes:&magicNumber length:length];
          
          if (magicNumber == FAT_MAGIC || magicNumber == FAT_CIGAM) {
              printf("FAT文件 ");
          }else if (magicNumber == MH_MAGIC || magicNumber == MH_CIGAM) {
              printf("非64bit架构文件 ");
          }else if (magicNumber == FAT_MAGIC_64 || magicNumber == FAT_CIGAM_64) {
              printf("64bit架构文件 ");
          }else{
              printf("读取失败");
          }
          
          printf("magicNumber = 0x%x\n",magicNumber);
    }
    return 0;
}
zhanglingli@bogon ~ % chmod +x /usr/local/bin/LLZTools
zhanglingli@bogon ~ % LLZTools                        
格式错误%                                                                       zhanglingli@bogon ~ % LLZTools /Users/lingli/Desktop/Clutch 
FAT文件 magicNumber = 0xbebafeca

三、权限说明

有时候读取其他文件不成功,我们需要给可执行文件签上一定的权限,让他可以访问其他app的可执行文件。

  • 导出可执行文件的权限
% ldid   
usage: ldid -S[entitlements.xml] 
   ldid -e MobileSafari
   ldid -S cat
   ldid -Stfp.xml gdb
% ldid -e LZTools > LZTools.entitlements

LZTools.entitlements文件实质是一个xml文件,也就是plist文件,存放着可执行文件的权限信息


Snip20200813_9.png
  • 修改可执行文件的权限

    我们赋予它SpringBoard可执行文件的权限

    • 找出SpringBoard 可执行文件,并导出权限文件
      % ldid -e SpringBoard > SpringBoard.entitlements
    • 修改LZTools权限
      % ldid -SSpringBoard.entitlements LZTools

你可能感兴趣的:(15_命令行工具的开发)