「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」。
前言
动态库的注入原理:
- 一个是基于修改Mach-O 的Load Commands,即通过修改可执行文件的Load Commands来实现的. 在Load Commands中增加一个LC_LOAD_DYLIB , 写入dylib路径。
Usage: insert_dylib dylib_path binary_path [new_binary_path]
- 一个是利用环境变量DYLD_INSERT_LIBRARIES,例如使用它进行dumpdecrypted(补充:Clutch 通过
posix_spawnp
生成一个新的进程,然后暂停进程并dump内存) - 另一个是在挂载的进程上创建一个挂起的线程, 然后在这个线程里申请一片用于加载动态库的内存,然后恢复线程,动态库就被注入(通过 taskfor_pid函数获取目标进程句柄,然后通过在进程内创建新线程并执行自己的代码。) cycript 就是以这种方式执行脚本代码。
I、静态库和动态库的区别
1.1 动态库的特点
- 存在形式有 .dylib,.framework 和链接符号 .tdb;
- 它的好处是可以只保留一份文件和内存空间,从而能够被多个进程使用,例如系统动态库;
- 可减小可执行文件的体积,不需要链接到目标文件。
1.2 静态库的特点
- 以.a 或者.framework形式存在的一种共享程序代码的方式,从本质上来讲就是一种可执行文件的二进制形式;常常会将程序的部分功能编译成库,暴露出头文件的形式供开发者调用
- 静态库以一个或者多个object文件组成;可以将一个静态库拆解成多个object文件(ar -x)
- 静态库链接的时会直接链接到目标文件,并作为它的一部分存在。
II、动态库的编译和注入
2.1 编译
xcrun --sdk iphoneos clang++ dynamiclib -arch arm64 -framework Foundation Person.mm -o target.dylib -fvisibility=hidden
- Makefile
CC = xcrun --sdk iphoneos clang++
ARCH = arm64
FRAMEWORK = -framework Foundation
VERSION = -compatibility_version 1 -current_version 1
VISIBLE = -fvisibility=hidden
TARGET = target.dylib
SOURCE = Person.m
$(TARGET):$(SOURCE)
$(CC) -dynamiclib -arch $(ARCH) $(FRAMEWORK) $(SOURCE) -o $(TARGET) $(VERSION)
.PHONY:clean
clean:
rm $(TARGET)
2.2 动态库的注入方式
2.2.1 cycript注入动态库的方式
在挂载的进程上创建一个挂起的线程, 然后在这个线程里申请一片用于加载动态库的内存,然后恢复线程,动态库就被注入(通过 taskfor_pid函数获取目标进程句柄,然后通过在进程内创建新线程并执行自己的代码。)
2.2.2 通过环境变量DYLD_INSERT_LIBRARIES 注入
DYLD_INSERT_LIBRARIES=/PathFrom/dumpdecrypted.dylib /PathTo
#New Run Script Phase:
cd ${TARGET_BUILD_DIR}
export DYLD_INSERT_LIBRARIES=./libKNoke.dylib && /Applications/QKNQ.app/Contents/MacOS/QKNQ
2.2.3 通过增加load command 的LC_LOAD_DYLIB或者LC_LOAD_WEAK_DYLIB,指定动态库的路径来实现注入
修改App可执行文件的头部,给它添加这么一个load command,并指定load我们构造的dylib就好
- 二次打包动态库的注入:
避免每次从环境变量注入–偏静态:通过LC_LOAD_DYLIB实现dylib的加载
通过修改可执行文件的Load Commands来实现的. 在Load Commands中增加一个LC_LOAD_DYLIB , 写入dylib路径 Usage: insert_dylib dylib_path binary_path [new_binary_path]
1、现在iOS上的绝大多数以root权限运行的App,都是通过setuid + bash来实现的
2、App运行所需要的信息,一般都存放在其MachO头部43中,其中dylib的信息是由load commands指定的.
这些信息是以静态的方式存放在二进制文件里(不是由DYLD_INSERT_LIBRARIES动态指定),而又是由dyld动态加载的,所以我们给它起了个“偏静态”的名字--在此App得到执行时,dyld会查看其MachO头部中的load commands,并把里面LC_LOAD_DYLIB相关的dylib给加载到进程的内存空间
- 如果需要修改LC_ID_DYLIDB、、LC_LOAD_DYLIB,可以使用install_name_tool
install_name_toll -id xxx imputfile
install_name_toll -change old new imputfile
- 通过cydia substrate提高的注入:
配置plist文件,并将对应的plist、dylib文件放入指定目录 /Layout/Library/MobileSubstrate/DynamicLibraries/、/usr/lib/TweakInject
其实也是通过DYLD_INSERT_LIBRARIES将自己注入,然后遍历DynamicLibraries目录下的plist文件,再将符合规则的动态库通过dlopen打开
III、导出和隐藏符号
3.1 导出符号
- 查看导出符号信息
nm -gm tmp_64.dylib
(__DATA,__data) external
(undefined) external _CFDataCreate (from CoreFoundation)
(undefined) external _CFNotificationCenterGetDarwinNotifyCenter (from CoreFoundation)
(__TEXT,__text) external
(undefined) external _IOObjectRelease (from IOKit)
(undefined) external _IORegistryEntryCreateCFProperty (from IOKit)
000000010ffa3f97 (__DATA,__objc_data) external _OBJC_CLASS_$_BslyjNwZmPCJkVst
000000010ffa3f97 (__DATA,__objc_data) external _OBJC_CLASS_$_ChiDDQmRSQpwQJgm
3.2 隐藏符号
- static 参数修饰,不会导出符号信息
static char _person_name[30] = {'\0'};
- 在编译参数中加入-exported_symbols_list export_list
CC = xcrun --sdk iphoneos clang
ARCH = arm64
FRAMEWORK = -framework Foundation
VERSION = -compatibility_version 1 -current_version 1
EXPORT = -exported_symbols_list export_list
VISIBLE = -fvisibility=hidden
TARGET = target.dylib
SOURCE = Person.mm
target1:$(SOURCE1)
$(CC) -dynamiclib -arch $(ARCH) $(FRAMEWORK) $(SOURCE) -o $(TARGET) $(VERSION)
target2:$(SOURCE1)
$(CC) -dynamiclib -arch $(ARCH) $(FRAMEWORK) $(SOURCE) -o $(TARGET) $(VERSION) $(EXPORT)
target3:$(SOURCE1)
$(CC) -dynamiclib -arch $(ARCH) $(FRAMEWORK) $(SOURCE) -o $(TARGET) $(VERSION) $(VISIBLE)
clean:
rm $(TARGET)
- 在编译参数中指定-fvisibility=hidden,对指定符号增加visibility(“default”)来导出符号
//#define EXPORT __attribute__((visibility("default")))
CC = xcrun --sdk iphoneos clang++
ARCH = arm64
FRAMEWORK = -framework Foundation
VERSION = -compatibility_version 1 -current_version 1
VISIBLE = -fvisibility=hidden
TARGET = target.dylib
SOURCE = Person.m
$(TARGET):$(SOURCE)
$(CC) -dynamiclib -arch $(ARCH) $(FRAMEWORK) $(SOURCE) -o $(TARGET) $(VERSION)
.PHONY:clean
clean:
rm $(TARGET)
see also
由于篇幅原因,更多内容请关注 #小程序:iOS逆向,只为你呈现有价值的信息,专注于移动端技术研究领域;更多服务和咨询请关注#公众号:iOS逆向。
🍅 联系作者: iOS逆向(公号:iosrev)
🍅 作者简介:CSDN 博客专家认证🏆丨全站 Top 50、华为云云享专家认证🏆、iOS逆向公号号主
🍅 简历模板、技术互助。关注我,都给你。