作者:海浪宝宝
链接:https://juejin.im/post/6886083253262876685

我们先创建一个目录:cd到该目录中,然后通过vi命令创建一个.c文件

vi test.c 

在test.c文件中输入下面内容:

#include<stdio.h>
int main(){
printf("123");
return 1;
}

然后通过clang命令进行编译、链接

clang -c test.h 

我们会发现在目录下多一个.o文件,这个.o文件是个目标文件,我们再通过file命令查看一下这个文件的属性

file test.o 

我们发现文件是下面属性:

test.o: Mach-O 64-bit object x86_64 

  • Mach-O:文件是Mach-O文件
  • 64-bit:文件是64位的
  • object:是个object文件
  • x86_64:是x86架构下的64位的文件

这个文件其实就是通过编译得到的目标文件

我们再通过clang对.o文件进行链接,链接之后得到的就是可执行文件

clang test.o 

我们发现目录下得到一个a.out文件,这个文件就是可执行文件,我们再通过file命令看一下这个文件是什么属性

file test.o 

得到下面提示

a.out: Mach-O 64-bit executable x86_64 

跟.o一样是个mach-O文件,不过文件类型是executable,而executable代表就是可执行文件

我们发现.o和.out都是Mach-O文件,说明Mach-O不只是指可执行文件,它只是一个文件格式

那么.o和.out文件有啥区别呢?

其实我们知道,我们一个项目有很多.h和.m文件, 我们再在目录下创建一个test1文件,里面定义一个test1函数

#include<stdio.h>
void test1(){
printf("test1");
return;
}

在test.c文件中定义一下test1函数,然后调用一下test1函数

#include<stdio.h>void test1();int main(){test1();printf("123");return 1;
}

然后再通过clang命令对两个文件都进行编译一下,得到两个.o文件

clang -c test.c test1.c 

再对两个.o文件进行链接得到demo可执行文件

clang -o demo test.o test1.o 

然后执行demo

./demo 

发现有打印

test1123 

相当于test1也执行了,这是因为链接时候会把两个文件链接在一起,所以就算没有头文件,test文件中也能执行test1函数

类似于其他.a、.dylib、.framework、dyld、dsym也都是Mach-O文件,我们可以通过find命令进行查找电脑中的这些文件,例如查找电脑中的.a文件

find /-name "*.a" 

可执行文件

我们主要对可执行文件进行分析,,在XCode项目的Build setting 里面的Mach-O,里面我们发现输出的是executable,可执行文件

当我们编译的时候选中的是我们的真机iPhone XS Max,那么编译的时候是什么架构的呢,编译一下,我们找到.app文件,然后找到里面的可执行文件,查看一下这个可执行文件的架构类型

file ZJJDEMO.app/WeChat 

我们发现是arm64架构的

ZJJAllModule_Example: Mach-O 64-bit executable arm64 

当我们把编译版本换成release版本时候,再次查看可执行版本,发现还是arm64版本,我们再把适配的系统类型转成iOS10.0,再次编译,查看

iOS11以上的的只适合ARM64位的

v7 v7s都是32位架构的

arm64 arm64e都是64位架构的

两个架构版本合成的可执行文件叫做通用二进制可执行文件

通用二进制文件

通用二进制文件是苹果公司提出的一种程序代码,能适用多种架构的二进制文件,我们可以将结合了多种架构的可执行文件

通过MachOView打开,打开后就是下面界面

其中问号那个是arm64e架构

我们可以通过lipo指令对可执行文件进行拆分,我们解释一下命令:

  • lipo -info MachO文件:查看machO文件有几种架构
  • lipo MachO文件 -thin 架构 -output 输出文件路径:拆分出某种架构
  • lipo -create MachO1 MachO2 -output 输出文件路径:合并多种架构

下面我们来操作一下,首先我们拿到多种架构的MachO文件,首先看一下这个MachO文件有哪几种架构:

lipo -info machO 

输出:

Architectures in the fat file: machO are: armv7 armv7s arm64 arm64e 

我们发现有4种架构。再拆分出armv7架构:

lipo machO -thin armv7 -output macho_armv7 

我们发现在当前文件夹中多了一个macho_armv7的可执行文件,并且原来可执行文件是336kb,而拆出来的文件大小是73kb

我们再查看一下这个文件的架构,发现只有armv7架构了

通过这种方式,我们可以把相应架构的可执行文件都分离出来,我们先拆出arm64和armv7的可执行文件

我们在将这两个可执行文件合成一个:

lipo -create macho_arm64 macho_armv7 -output mach_arm64_v7 

查看一下mach_arm64_v7的属性:

lipo -info mach_arm64_v7 

输出:

Architectures in the fat file: mach_arm64_v7 are: armv7 arm64 

说明合并成功了,当然不仅仅是两个,可以多个macho文件合成一个,我们可以通过这种方式来分析可执行文件的单一架构。

合并之后的可执行文件,代码部分是不共用的,每个架构都有自己的独立的代码,但是资源是共用的,但是合并的话会增加一些合并架构的东西,所以合并后的可执行文件可能会比合并的可执行文件的大小和大一点

MachO文件结构

首先我们看一下苹果官方的图片

分三部分:

  • header:包含该二进制文件的一般信息,最开始读取的部分,例如字节顺序、架构类型、加载指令的数量等。类似于一本书的标题。使得可以快速确认一些信息,比如当前文件用于32位还是64位,对应的处理器是什么,文件类型是什么
  • load commands:一张包含很多内容的表,对Data的一种描述,类似目录。内容包括区域的位置、符号表、动态符号表等
  • Data:具体数据区,文件最大的部分

例如我们把单一架构的可执行文件通过MachOView打开

里面有这三类,而对于多个架构合成的maco文件我,我们也打开看看:

我们发现会有多种架构并列,而每个架构都有自己但多的head、Load Commands、Data

Header

我们在仔细分析一下head里面数据

  • Magic Number:确定是多少位的,MH_MAGIC:代表32位,MH_MAGIC_64:64位
  • CPU Type:代表arm型号。 0000000C对应值是CPU_TYPE_ARM,是32位的;0100000C对应的值是CPU_TYPE_ARM64,代表是64位的
  • CPU SubType:指出具体架构类型,例如00000009,代表arm_v7;00000000代表arm64;0000000B代表arm_v7s
  • File Type:00000002代表MH_EXECUTE,可执行文件。假如我们打开的是.a文件,这个值就是MH_OBJECT
  • Number of load Commands:代表有多少条加载指令,也就是Load Commands里面有多少条
  • Size of Load Commands:加载文件的大小
  • Flags:标志位,给CPU做标记用,主要标识二进制文件支持的功能,主要是和系统加载、链接有关

其实Header是一个结构体,具体结构如下:

这个我们可以在系统库mach-o里的loader.h文件中看到

关于File Type字段的一些值也可以在这个文件中看到

系统在加载MachO文件的时候,会首先加载Header,这样就知道该MachO文件架构模式。CPU类型。已经加载大小、方式等

Load Commands

我们再看一下Load Commands:

Load Commands的最尾部的地址是

而DATA的最开始的地址是:

说明 在Load Commands和DATA之间有一大块内存地址,这是为什么呢,因为苹果有一个原则就是二进制对齐原则,这样会导致一些内存空间是空余出来的,而且还有扩容原则、读取数据原则,预留的空间是为了使数据的读取更高效,用空间换时间,同时这些地方也可以提供给我们添加动态库。

而Header和Load Commands直接是没有空余的空间

我们再看一下具体结构: [图片上传中...(image-c9e978-1604301382758-5)]

前4个部分,告诉系统文件分为四大块,每块内容

  • Command:Load Command类型
  • Command Size:Load Command大小
  • Segment Name:代表什么段,__TEXT:说明是文字段
  • VM Address:虚拟地址,映射到内存中的地址
  • VM Size:虚拟文件大小
  • File Offset:文件偏移大小
  • File Size:文件大小

当文件读进内存之后我要从文件的offset位置加上文件的大小,

  • LC_SEGMENT_64(_PAGEZERO):虚拟的,内存中其实是不存在的
  • LC_SEGMENT_64(_TEXT):
  • LC_SEGMENT_64(_DATA):
  • LC_SEGMENT_64(_LINKEDIT):
  • LC_DYLD_INFO_ONLY:动态链接相关的信息!因为iOS系统存在共享缓存,例如系统库Foundation框架在iOS系统中所有APP都共用这个库,而且内存中只有这一份,而dyld加载app的时候会将foundation框架中的函数生成一个符号,然后通过这个符号和相应的函数实现进行绑定
  • LC_SYMTAB:符号表
  • LC_DYSYMTAB:动态符号表
  • LC_LOAD_DYLINKER:dyld路径,也是使用谁加载我,iOS中是dyld
  • LC_UUID:文件的唯一标示
  • LC_VERSION_MIN_IPHONEOS:支持的最低操作系统版本
  • LC_SOURCE_VERSION:源代码版本
  • LC_MAIN:主程序入口地址和栈大小
  • LC_ENCRPTION_INFO_64:
  • LC_LOAD_DYLIB(Foundation):依赖库的路径,包括三方库

...

  • LC_RPATH:
  • LC_FUNCTION_STARTS:函数起始位置表地址
  • LC_DATA_IN_CODE:
  • LC_CODE_SIGNATURE:代码签名

我们看一下TEXT段和DATA段

我们发现__DATA的偏移量就是__TEXT的文件大小

DATA

我们再到DATA部分可以看到DATA部分分为_TEXT和__DATA,而Load Commands部分就是描述DATA部分的数据

TEXT部分 --代码段

  • Section64 (_TEXT,_text):程序代码,hoper重点分析它
  • Section64 (_TEXT,_stubs):动态链接
  • Section64 (_TEXT,_stubs_helper):
  • Section64 (_TEXT,_objc_methname):方法名称
  • Section64 (_TEXT,_objc_classname):类名称
  • Section64 (_TEXT,_objc_methtype):方法类型
  • Section64 (_TEXT,_cstring):静态字符串,也就是字符串常量,刚运行时候字符串就加载进去了
  • Section64 (_TEXT,_unwind_info):

DATA部分 --数据段

  • Section64 (_DATA,_got):非懒加载的符号表
  • Section64 (_DATA,_la_symbol_ptr):懒加载的符号表,只有当调用的时候生成一个符号,然后和函数绑定
  • Section64 (_DATA,_objc_classlist):类列表
  • Section64 (_DATA,_objc_protolist):协议列表
  • Section64 (_DATA,_objc_imageinfo):
  • Section64 (_DATA,_objc_const):常量区
  • Section64 (_DATA,_objc_selrefs):方法
  • Section64 (_DATA,_objc_classrefs):类
  • Section64 (_DATA,_objc_superrefs):
  • Section64 (_DATA,_objc_ivar):
  • Section64 (_DATA,_objc_data):
  • Section64 (_DATA,_data):
  • Dynamic Loader Info
  • Function Starts
  • Symbol Table
  • Data in Code Entries
  • Dynamic Symbol Table
  • String Tabel
  • Code Signature

总结

MachO文件的结构分为Header、Load Commond、DATA三部分,如果将MachO文件当做一本书的话,那么Header就是书的封面,Load Commond就是书的目录,DATA就是书的内容。

因为MachO只是一种文件类型,所以,系统在加载应用程序的时候会加载很多个MachO文件,如果一个MachO文件依赖其他MachO文件,那么就会将依赖的MachO文件加载到自己的Load Commands里面,而程序调用方法也是先找到方法所在的MachO文件在哪个,找到对应的Header,然后在文件的Load Commands里面找方法在的位置,如果方法不再自己文件中就会找该MachO文件所依赖的库,而MachO文件的Load Commands会指引依赖库的位置,直到找到方法的所在。有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:891488181 不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!

ncl 多个单一时间文件合并成一个nc文件_iOS逆向--MachoO文件相关推荐

  1. 将两个HEX文件合并成一个HEX文件

    将两个HEX文件合并成一个HEX文件 文章目录 将两个HEX文件合并成一个HEX文件 系统环境 1. 生成BootLoader和app的HEX文件 2. 将两个HEX文件合并成一个HEX 3. 利用J ...

  2. 怎么把多个pdf文件合并成一个?一分钟解决

    当我们有多个PDF文件时,将它们合并成一个文件可以帮助您更轻松地管理和浏览文件.不必打开多个文件,只需打开一个文件就能查看所有内容.将PDF文件合并成一个文件可以帮助您更好地组织文档,以便于共享和备份 ...

  3. python处理多个excel文件-python多个excel文件合并成一个sheet

    运营人员需要历年的订单数据,这就需要把多个文件夹下面的excel文件合并到一个sheet中,之前的解决的办法是用VBA把多个excel文件合并成一个表的多个sheet,再把多个sheet合并成一个sh ...

  4. 用python将指定目录下的所有json文件合并成一个csv文件

    #!/usr/bin/env python # -*- encoding: utf-8 -*-import sys import json import os import pandas as pd ...

  5. 如何将多个excel表格合并成一个_怎么将多个pdf文件合并成一个?

    现实生活中,不知道大家有没有遇上这样的时刻,自己不会做pdf文件,于是就去网上找了一些素材,但是网上的素材都是零零散散的,但是我们又不知道应该如何才能将她们拼凑到一起.如果你也在为这样的问题而烦恼的话 ...

  6. 怎么将几张pdf合并成一张_怎么把多个PDF文件合并成一个

    怎么把多个PDF文件合成为一个PDF文件?我相信这个问题是许多小伙伴在工作当中都会遇到的一个问题,其实想要将多个PDF文件合成为一个PDF文件还是非常简单的,只需要利用到迅捷PDF转换器,就可以轻松的 ...

  7. 怎么把几个PDF文件合并成一个PDF

    有时一份pdf文档资料会被分成多个部分,在整理的时候可能需要将这些文件合并到一起,那么怎样可以将这多个pdf文件合并成一个呢?下面就教你怎样用PDF编辑器对pdf文件进行合并. ​ 方法/步骤 < ...

  8. PDF合并:如何将两个PDF文件合并成一个PDF文件

    PDF文件是我们在工作中经常能够用到的文件,尤其是在办公中会遇到很多PDF文件在传输的过程中为了传输更快被拆分成了几个PDF文件,但是要找一个完整的PDF文件就需要把两个被拆分的PDF文件合并成一个P ...

  9. 怎么将几张pdf合并成一张_如何将多个pdf文件合并成一个pdf文件?

    原标题:如何将多个pdf文件合并成一个pdf文件? 我很喜欢使用PDF文件格式,为什么呢?因为PDF具有许多其他电子文档格式无法相比的优点.PDF文件格式可以将文字.字型.格式.颜色及独立于设备和分辨 ...

最新文章

  1. 【转】IOS的各种后台情况的实现
  2. laravel的composer require报错:Installation failed, reverting ./composer.json to its original content.
  3. com.xxl.rpc.util.XxlRpcException: java.lang.IllegalStateException: failed to create a child event lo
  4. jquery插件最佳实践之progressbar
  5. 1594: TomCat的操作系统课(思维)
  6. Git Bash的一些命令和配置
  7. TCP三次握手建立连接
  8. javascript 文件的同步加载与异步加载
  9. 职教云自签系统部署教程及源码
  10. 视频跟踪——CMT算法
  11. android异步加载视频缩略图,swift-如何将视频URL的缩略图异步加载到tableview列表中...
  12. jni java c 变量对应_GitHub - jkangzhang/JNIDemo: JNI中Java和C的数据传递
  13. IOS学习笔记06---C语言函数
  14. 单位与单位的换算(二)
  15. RTKLIB之RTCM解析
  16. socket.io实现简单多人聊天室
  17. 轻松让Ubunt虚拟机访问windows宿主机(本地硬盘)
  18. 开源视频云转码 m3u8_8种开源视频游戏
  19. 计算机随机储存器是什么,随机存储器是什么
  20. 何为真正的大规模定制

热门文章

  1. Linux 给我的七个宝贵教训
  2. 这是一本零基础学习 Python 的好书
  3. 助力开发者的魔法式“绝招儿”,你了解几个?
  4. 你相信逛 B 站也能学编程吗?
  5. 果断 Mark!27 个免费、低成本 Python 学习资源入手!
  6. 深入浅出 Proguard
  7. mail linux 客户端,Nylas Mail: 一个 Linux 的免费邮件客户端
  8. 经验总结:java自学视频免费
  9. 第 19 章 迭代器模式
  10. 2014年3月计算机四级网络工程师考试试题及答案,某年3月计算机等级考试四级网络工程师笔试试题...