阅读视图
iOS小技能:给debugserver添加task_for_pid权限,以便调试从AppStore中获取的App。
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情
前言
在做iOS开发时,在Mac上输入LLDB的命令就可以控制iOS端的App,是因为在iOS客户端中有一个debugserver服务器。
debugserver专门用来连接Mac端的LLDB客户端,接收LLDB所提供的命令,并且进行相应的执行。
如果你的iOS设备进行过真机调试的话,设备中就会被安装上debugserver, 不过该debugserver只能用来调试你自己的相关应用。
如果想要调试从AppStore中获取的App的话那么我们需要对iOS设备上的debugserver进行处理,那就是
给debugserver添加task_for_pid权限
本文的重点是给debugserver添加task_for_pid权限
,以便调试从AppStore中获取的App
I 、获取debugserver
iPhone:/Developer/usr/bin root# ls
DTDeviceArbitration ScreenShotr XcodeDeviceMonitor debugserver iprofiler xctest
位于/Developer/usr/bin目录下的debugserver。此debugserver只支持调试我们自己的App, 如果需要调试其他人的App的话,需要对此debugserver进行处理
II、对debugserver进行瘦身
进入到到Mac中debugserver所在的目录下执行上述命令即可,-thin后方填写你的测试机相应的ARM架构即可,因为我的测试机是iPhone 6 Plus, 是arm64的架构,所以此处填的参数是arm64, 如果你的是iPhone5的设备,那么就是armv7s了。
devzkndeMacBook-Pro:Downloads devzkn$ scp iphone:/Developer/usr/bin/debugserver ./debugserver
lipo -thin arm64 debugserver -output debugserver
devzkndeMacBook-Pro:Downloads devzkn$ ls -l debugserver
-rwxr-xr-x 1 devzkn staff 13801968 Oct 17 17:19 debugserver
devzkndeMacBook-Pro:Downloads devzkn$ lipo -thin armv7s debugserver -output debugserver
devzkndeMacBook-Pro:Downloads devzkn$ ls -l debugserver
-rwxr-xr-x 1 devzkn staff 4582800 Oct 17 17:19 debugserver
III、给debugserver添加task_for_pid权限
给debugserver添加task_for_pid权限后,我们就可以使用LLDB调试其他App了。 此部分我们需要一个存储配置信息的xml文件,该文件的内容如下。你可以将下下方的文本进行拷贝,然后存储成ent.xml即可。
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.springboard.debugapplications</key>
<true/>
<key>get-task-allow</key>
<true/>
<key>task_for_pid-allow</key>
<true/>
<key>run-unsigned-code</key>
<true/>
</dict>
</plist>
在给debugserver符权限时,我们需要使用到ldid命令,如果你的Mac上没有安装ldid命令,那么请用brew进行install 执行下方的命令行就可以给我们的debugserver赋上task_for_pid权限。需要注意的是-S与ent.xml文件名中是没有空格的。
ldid -Sent.xml debugserver
IV、将debugserver拷贝到iOS设备中
最后一步就是将处理好的debugserver拷贝到我们的越狱设备中,并且给debugserver赋上可执行的权限。
chmod +x debugserver
因为/Developer/usr/bin目录下的debugserver是只读的,所以你不能将处理好的debugserver拷贝到上述文件,
你要将处理好的debugserver拷贝到/usr/bin/目录下
devzkndeMacBook-Pro:Downloads devzkn$ scp ./debugserver iphone:/usr/bin/debugserver
Phone:/usr/bin root# ls -l debugserver
-rwxr-xr-x 1 root wheel 4582512 Oct 17 17:31 debugserver
iPhone:/usr/bin root# debugserver
debugserver-@(#)PROGRAM:debugserver PROJECT:debugserver-320.2.89
for armv7.
Usage:
debugserver host:port [program-name program-arg1 program-arg2 ...]
debugserver /path/file [program-name program-arg1 program-arg2 ...]
debugserver host:port --attach=<pid>
debugserver /path/file --attach=<pid>
debugserver host:port --attach=<process_name>
debugserver /path/file --attach=<process_name>
see also
How can you catch a process that is about to be launched, if you don’t know the PID yet?
———————————————— 版权声明:本文为CSDN博主「#公号:iOS逆向」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 更多内容请关注
公号:iOS逆向
原文链接:blog.csdn.net/z929118967/…
iOS小技能:__attribute__的应用
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
引言
LLVM和其他 GCC 特性一样,Clang 支持了 attribute, 还加入了一小部分扩展特性。
__attribute__
语法格式为:__attribute__ ((attribute-list))
constructor(priority), destructor(priority)
分别可以在main() 先后执⾏,可⽤于全局资源初始化和回收。
destructor让系统在main()函数退出或者调用了exit()之后,调用我们的函数。
Function-Attributes: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
I __attribute__的应用案例
1.1 代码注入
- ARM (通过汇编调用svc实现用户态到内核态的转换)
// 使用inline方式将函数在调用处强制展开,防止被hook和追踪符号
static __attribute__((always_inline)) void anti_debug()
#ifdef __arm__
asm volatile(
"mov r0,#31\n"
"mov r1,#0\n"
"mov r2,#0\n"
"mov r12,#26\n"
"svc #80\n"
);
#endif
#ifdef __arm64__
asm volatile(
"mov x0,#26\n"
"mov x1,#31\n"
"mov x2,#0\n"
"mov x3,#0\n"
"mov x16,#0\n"
"svc #128\n"
);
#endif
}
- 代码注入: facebook/fishhook符号表替换
/*
* A structure representing a particular intended rebinding from a symbol
* name to its replacement
*/
struct rebinding {//rebinding结构体
const char *name; //符号名称,C字符串,用来表明我们要hook哪个函数。
void *replacement; //新函数的地址
void **replaced; //原始函数地址的指针!
};
//重新绑定符号
FISHHOOK_VISIBILITY
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
//rebindings[] 是一个 rebinding类型数组,用来存储需要hook的函数
//rebindings_nel 表示数组的长度
/*
* Rebinds as above, but only in the specified image. The header should point
* to the mach-o header, the slide should be the slide offset. Others as above.
*/
FISHHOOK_VISIBILITY
int rebind_symbols_image(void *header,
intptr_t slide,
struct rebinding rebindings[],
size_t rebindings_nel);
//指定镜像的header, slide 表示偏移量
hook ptrace
函数,进行反反调试。
PT_DENY_ATTACH is an Apple-specific constant that can prevent debuggers (gdb, DTrace, etc.) from debugging your binary in kernel-level.
ptrace(PT_DENY_ATTACH, 0, 0, 0);
#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif
Rebinding customRebind = {"ptrace", my_ptrace, (void*)&orig_ptrace};
//第一个参数为需要替换的符号
//第二个参数为自己实现的函数名称
//第三个参数为原函数地址,因为fishhook是基于地址进行替换的+ `__attribute__((constructor))`实现注入
rebind_symbols((struct rebinding[1]){customRebind},1);
int my_ptrace(int _request, pid_t _pid, caddr_t _addr, int _data){
if(_request != PT_DENY_ATTACH){
return orig_ptrace(_request,_pid,_addr,_data);
}
return 0;
}
- 自定义打印方法:用真正的方法替换去拦截 NSLog 的功能(
iOS 11 之后这种方法失效了
),使用__attribute__((constructor));
进行实现,extern进行申明公共方法。
#ifdef DEBUG
// iOS 11 之前用真正的方法替换去实现拦截 NSLog 的功能,iOS 11 之后这种方法失效了,所以只能用宏定义的方式覆盖 NSLog。这也就意味着在 iOS 11 下一些如果某些代码编译时机比 QMUI 早,则这些代码里的 NSLog 是无法被替换为 KNLog 的
extern void _NSSetLogCStringFunction(void (*)(const char *string, unsigned length, BOOL withSyslogBanner));
static void PrintNSLogMessage(const char *string, unsigned length, BOOL withSyslogBanner) {
QMUILog(@"NSLog", @"%s", string);
}
static void HackNSLog(void) __attribute__((constructor));
static void HackNSLog(void) {
_NSSetLogCStringFunction(PrintNSLogMessage);
}
#define NSLog(...) KNLog(@"NSLog", __VA_ARGS__)// iOS 11 以后真正生效的是这一句
#endif
1.2 对格式化字符串进行类型检查
extern int
my_printf (void *my_object, const char *my_format, ...)
__attribute__((format(printf, 2, 3)));
//format 属性用于指定一个函数接收类似 printf, scanf, strftime 和 strfmon 风格的参数,应该按照参数对格式化字符串进行类型检查。
1.3 控制符号的可见性
#define STD_EXPORTS __attribute__ ((visibility("default")))
The -fvisibility=vis compiler option
lets you set the visibility for symbols in the current compilation. When set to hidden, symbols not explicitly marked as visible are hidden.
__attribute__((visibility("default"))) void MyFunction1() {}
__attribute__((visibility("hidden"))) void MyFunction2() {}
1.4 表明一些函数参数应该是非空的指针
extern void *
my_memcpy (void *dest, const void *src, size_t len)
__attribute__((nonnull (1, 2)));
1.5 确保线程在应用整个生命周期内都能一直运行
AFNetworking 在网络请求线程的入口使用 noreturn 属性,用于网络请求的 NSThread。
+ (void) __attribute__((noreturn)) networkRequestThreadEntryPoint:(id)__unused object {//确保这个线程在应用整个生命周期内都能一直运行
do {
@autoreleasepool {
[[NSRunLoop currentRunLoop] run];
}
} while (YES);
}
+ (NSThread *)networkRequestThread {//专门用于网络请求的 NSThread
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
1.6 检查能否使用特定的属性
可以用 __has_attribute
这个指令
#ifndef AX_REQUIRES_SUPER
#if __has_attribute(objc_requires_super)
#define AX_REQUIRES_SUPER __attribute__((objc_requires_super))
#else
#define AX_REQUIRES_SUPER
__attribute((objc_requires_super)) was first introduced as work in progress into CLANG in September 2012 and was documented in October 2013. On both OS X and iOS there is now a NS_REQUIRES_SUPER macro that conditionally wraps the objc_requires_super attribute depending on compiler support. Once a method declaration is appended with this macro, the compiler will produce a warning if super is not called by a subclass overriding the method.
II 导出和隐藏符号
2.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
2.2 __attribute__控制符号是否导出
The
-fvisibility=vis compiler option
lets you set the visibility for symbols in the current compilation. When set to hidden, symbols not explicitly marked as visible are hidden.
#define EXPORT __attribute__((visibility("default")))
隐藏未明确标记为可见的符号:
-
在编译参数中加入
-exported_symbols_list export_list
-
在编译参数中指定-fvisibility=hidden,对指定符号增加visibility(“default”)来导出符号
__attribute__((visibility("default"))) void MyFunction1() {}
__attribute__((visibility("hidden"))) void MyFunction2() {}
static 参数修饰,不会导出符号信息
static char _person_name[30] = {'\0'};
2.3 Pragmas控制符号是否导出
void f() { }
#pragma GCC visibility push(default)
void g() { }
void h() { }
#pragma GCC visibility pop
III ptrace系统调用
为了方便应用软件的开发和调试,unix的早期版本提供了一种对运行中的进程进行跟踪和控制手段:系统调用ptrace;通过ptrace,可以对另一个进程实现调试跟踪,同时ptrace提供了一个PT_DENY_ATTACH = 31参数用于告诉系统阻止调试器的依附
。
//ptrace系统调用 用于实现断点调试和对进程进行跟踪和控制
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
//enum __ptrace_request request:指示了ptrace要执行的命令。
//pid_t pid: 指示ptrace要跟踪的进程。
//void *addr: 指示要监控的内存地址。
//void *data: 存放读取出的或者要写入的数据。
//PT_DENY_ATTACH is an Apple-specific constant that can prevent debuggers (gdb, DTrace, etc.) from debugging your binary in kernel-level.
//ptrace(PT_DENY_ATTACH, 0, 0, 0);
gdb利用ptrace系统调用,在被调试程序和gdb之间建立跟踪关系。然后所有发送给被调试程序的信号(除SIGKILL)都会被gdb截获,gdb根据截获的信号,查看被调试程序相应的内存地址,并控制被调试的程序继续运行。
3.1 syscall
syscall是通过软中断来实现从用户态到内核态,syscall (26,31,0,0)
来调用系统函数ptrace(PT_DENY_ATTACH, 0, 0, 0);
。
ptrace的系统调用函数号是26,31是PT_DENY_ATTACH(用于告诉系统阻止调试器的依附)。
int syscall(int, ...);
#defineSYS_ptrace 26
3.2 反调试
-
运行时期,断点ptrace,直接返回
-
分析如何调用的ptrace,hook ptrace
-
通过tweak,替换disable_gdb函数
-
修改 PT_DENY_ATTACH:在二进制文件中 ,修改 PT_DENY_ATTACH的31,改成 任意一个值,如PT_ATTACH 0。 blog.csdn.net/z929118967/… AlipayWalletTweakF.xm
-
ARM (通过汇编调用svc实现用户态到内核态的转换)
// 使用inline方式将函数在调用处强制展开,防止被hook和追踪符号
static __attribute__((always_inline)) void anti_debug()
#ifdef __arm__
asm volatile(
"mov r0,#31\n"
"mov r1,#0\n"
"mov r2,#0\n"
"mov r12,#26\n"
"svc #80\n"
);
#endif
#ifdef __arm64__
asm volatile(
"mov x0,#26\n"
"mov x1,#31\n"
"mov x2,#0\n"
"mov x3,#0\n"
"mov x16,#0\n"
"svc #128\n"
);
#endif
}
see also
小程序:iOS逆向
iOS小技能:消息发送的步骤(利用类型编码加快消息分发)
iOS小技能:动态地给类添加新的方法、实例变量、属性。
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情
前言
添加新的实例变量的原理:利用category结合runtime的API实现
动态创建属性的应用场景:利用属性进行传值的时候,我们就可以利用本文的方法进行动态创建属性。尤其在逆向其他app的时候,往已经存在class新增一个属性,用于数据传递,尤其是异步操作的时候。
I 添加新的实例变量
1.1 原理
利用 runtime APIobjc_setAssociatedObject
和objc_getAssociatedObject
objc_setAssociatedObject
/**
* Sets an associated value for a given object using a given key and association policy.
*
* @param object The source object for the association.
* @param key The key for the association.
* @param value The value to associate with the key key for object. Pass nil to clear an existing association.
* @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
*
* @see objc_setAssociatedObject
* @see objc_removeAssociatedObjects
*/
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
/**
* Returns the value associated with a given object for a given key.
*
* @param object The source object for the association.
* @param key The key for the association.
*
* @return The value associated with the key \e key for \e object.
*
* @see objc_setAssociatedObject
*/
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
1.2 例子
类别(Category)
通过增加新的类和实例方法来扩展现有类的行为。作为惯例,类别被定义在它们自己的.{h,m}
文件里。
//
// Teacher+Profession.m
//
#import "Teacher+Profession.h"
#import <objc/runtime.h>
const char *ProfessionType = "NSString *"; //就是属性的key
@implementation Teacher (Profession)
-(void)setProf:(NSString*)prof
{
objc_setAssociatedObject(self, ProfessionType, prof, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)prof
{
NSString *pro = objc_getAssociatedObject(self, ProfessionType);
return pro;
}
@end
II 动态创建属性
使用分类、@dynamic
、objc_setAssociatedObject、objc_getAssociatedObject 实现。
2.1 应用场景
利用属性进行传值的时候,我们就可以利用本文的方法进行动态创建属性。尤其在逆向其他app的时候,往已经存在class新增一个属性,用于数据传递,尤其是异步操作的时候。
//结合@dynamic的 associatedObject例子
@implementation NSObject (AssociatedObject)
@dynamic associatedObject;
- (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self,
@selector(associatedObject), object,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self,
@selector(associatedObject));
}
2.2 例子:为VC新增一个属性
WCNewCommitViewController+KNWCNewCommitViewControllerAssociatedObject.h
#import "WCNewCommitViewController.h"
@interface NSObject (KNWCNewCommitViewControllerAssociatedObject)
// isa (Class): NSKVONotifying_WCNewCommitViewController (isa, 0x5a10db2abf7)
@property (nonatomic, strong) id associatedObject;
@end
WCNewCommitViewController+KNWCNewCommitViewControllerAssociatedObject.m
#import "WCNewCommitViewController+KNWCNewCommitViewControllerAssociatedObject.h"
@implementation NSObject (KNWCNewCommitViewControllerAssociatedObject)
@dynamic associatedObject;
- (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self,
@selector(associatedObject), object,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self,
@selector(associatedObject));
}
@end
2.3 效果
- usage:
#import "WCNewCommitViewController+KNWCNewCommitViewControllerAssociatedObject.h"
[WCNewCommit setAssociatedObject:@"sssss"];
- ret
NSLog(@"associatedObject:%@",[self valueForKey:@"associatedObject"]);//2018-09-06 12:06:06.977711 WeChat[717:226743] associatedObject:sssss
See Also
- iOS运行时的应用:
1、实现路由(接口控制app跳任意界面 )
2、获取修改对象的成员属性
3、动态添加/交换方法的实现
4、属性关联
iOS动态库的注入原理
「这是我参与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逆向公号号主
🍅 简历模板、技术互助。关注我,都给你。
iOS逆向小技能:Cydia Substrate的组成部分、编写Tweak的步骤
「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
前言
Cydia Substrate(以前叫做MobileSubstrate)是一个框架,允许第三方的开发者在系统的方法里打一些运行时补丁,扩展一些方法。
Cydia Substrate由3部分组成:
- MobileHooker
- MobileLoader
- safe mode
I Cydia Substrate]
1.1 MobileHooker
MobileHooker用来替换系统函数,这个过程也叫Hooking。有如下的API可以使用:
IMP MSHookMessage(Class class, SEL selector, IMP replacement, const char* prefix); // prefix should be NULL.
void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP *result);
void MSHookFunction(void* function, void* replacement, void** p_original);
MSHookMessageEx用来替换Objective-C的函数,MSHookFunction用来替换C/C++函数
1.2 MobileLoader
MobileLoader loads 3rd-party patching code into the running application. MobileLoader will first load itself into the run application using DYLD_INSERT_LIBRARIES environment variable. Then it looks for all dynamic libraries in the directory /Library/MobileSubstrate/DynamicLibraries/, and dlopen them.
控制是否加载到目标程序,是通过一个plist文件来控制的。如果需要被加载的动态库的名称叫做foo.dylib,那么这个plist文件就叫做foo.plist,这个里面有一个字段叫做filter,里面写明需要hook进的目标程序的bundle id。 比如,如果只想要foo.dylib加载进入SpringBoard,那么对应的plist文件中的filter就应该这样写:
Filter = {
Bundles = (com.apple.springboard);
};
1.3 Safe mode
When a extension crashed the SpringBoard, MobileLoader will catch that and put the device into safe mode. In safe mode all 3rd-party extensions will be disabled.
The following signals will invoke safe mode:
SIGABRT
SIGILL
SIGBUS
SIGSEGV
SIGSYS
II 编写Tweak的步骤
-
确定目标:在这个App上编写Tweak实现的特定功能,比如拦截某个具体的应用的特定API调用,获得关键信息。
-
导出头文件:确定目标之后,就可以利用Clutch先破解App,然后利用class-dump-z导出头文件,找到你感兴趣的类,对它进行分析。
-
获得类的方法:有时候,头文件没有所有方法调用的信息,这个时候你可以利用cycript,使用之前介绍的trick,打印出所需的方法信息。
-
编写Tweak:这一步你应该拿到需要Hook的类以及对应的方法,编写并安装与测试。
III SpringBoard 相关的API
- powerDown
+ (void) powerDown {
id SpringBoard = [UIApplication sharedApplication];//#"<SpringBoard: 0x173d8800>"
[SpringBoard powerDown];
}
- relaunchSpringBoard
@interface SpringBoard : UIApplication
\t_uiController (SBUIController*): <SBUIController: 0x1809c510>
- (void)relaunchSpringBoard; [#0x1617ca00 relaunchSpringBoard]
- (void)_relaunchSpringBoardNow;
- (void)powerDown;
- (void)_powerDownNow;
- (void)reboot;
- (void)_rebootNow;
@end
- 自动锁屏
[UIApplication sharedApplication].idleTimerDisabled=YES;//不自动锁屏,放在-(void)viewWillAppear:(BOOL)animated里面的时候,防止失效
[UIApplication sharedApplication].idleTimerDisabled=NO;//自动锁屏
see also
更多内容请关注 #小程序:iOS逆向,只为你呈现有价值的信息,专注于移动端技术研究领域;更多服务和咨询请关注#公众号:iOS逆向。
iOS设备日志查看工具:syslog、socat
「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。
前言
本文介绍iOS设备日志查看工具syslog、deviceconsole和socat
,如果上述工具都不满意,你也可以使用Mac系统自带的console控制台进行查看。
>
I syslog
1.1 安装syslog
在cydia搜索syslogd to /var/log/syslog安装即可
1.2 syslog用法
syslog是把系统日志写入到/var/log/syslog文件里,用法很简单,执行tail -f /var/log/syslog就能看到了
如果需要过滤某一应用的日志,只需加上grep即可,比如过滤微信
tail -f /var/log/syslog |grep WeChat
II socat
2.1 安装
- 在iOS设备安装
使用 APT 0.6 Transitional 安装socat 几乎所有流行的黑客工具都可以在 BigBoss Recommendation tools这个包中找到 ( APT 0.6 Transitional, Git, GNU Debugger, less, make, unzip, wget 和 SQLite 3.x)
apt-get install socat
如果找不到安装包的时候,运行一下 apt-get update, 获得最新的包列表.
2.2 连接到系统日志的sock文件
socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
- 进入到命令行交互界面,这时可以输入help查看帮助
iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
========================
ASL is here to serve you
>
2.3 日志的查看
输入watch查看,输入stop停止
2.4 清除日志文件数据
cat /dev/null >/var/log/syslog
III deviceconsole
自从iOS8之后,我就习惯使用Mac系统自带的console ,后来发现有些同事的Mac中console 版本低,没有device 选项;于是乎,就推荐他们使用deviceconsole
- deviceconsole --help
➜ bin git:(master) ✗ deviceconsole --help Usage: deviceconsole [options] Options: -d Include connect/disconnect messages in standard out -u <udid> Show only logs from a specific device -p <process name> Show only logs from a specific process Control-C to disconnect Mail bug reports and suggestions to <ryan.petrich@medialets.com>
knlog -help
Usage: knlog [options] Options: -i | --case-insensitive Make filters case-insensitive -f | --filter <string> Filter include by single word occurrences (case-sensitive) -x | --exclude <string> Filter exclude by single word occurrences (case-sensitive) -p | --process <string> Filter by process name (case-sensitive) -u | --udid <udid> Show only logs from a specific device -s | --simulator <version> Show logs from iOS Simulator --debug Include connect/disconnect messages in standard out --use-separators Skip a line between each line --force-color Force colored text --message-only Display only level and message Control-C to disconnect
- 编译之后的可执行文件 knlog
see also
更多内容请关注 #小程序:iOS逆向,只为你呈现有价值的信息,专注于移动端技术研究领域;更多服务和咨询请关注#公众号:iOS逆向。
iOS逆向小技能:Theos的安装
「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。
前言
Theos是越狱开发工具包。logos语法简单。,它给我们准备好了一些代码模板、预置一些基本的Makefile脚本,这样我们开发一个tweak就会变得方便的多,
(整合在Xcode的iOSopendev )由于逆向工程很多东西无法自动化,因此推荐Theos
I 安装Thoes
1.1 安装Xcode
安装Xcode,以及command line tools
1.2 下载Thoes
下载Thoes:https://github.com/theos/theos
查看环境变量: 终端中输入命令env
建立环境变量:
export THEOS=/opt/theos
#在当前终端中起作用了,关闭终端后又得重新设置。
为了避免每次都建立这个环境变量,建立一个永久的环境变量 : 编辑~/.profile文件,在其中添加export THEOS=/opt/theos/,这个环境变量就是永久的了.
记得source
source .profile
或者使用.bash_profile
open -e ~/.bash_profile
export THEOS=/opt/theos
source .bash_profile
devzkndeMacBook-Pro:opt devzkn$ git clone --recursive https://github.com/theos/theos.git $THEOS
fatal: could not create work tree dir '/opt/theos': Permission denied
devzkndeMacBook-Pro:opt devzkn$ sudo git clone --recursive https://github.com/theos/theos.git $THEOS
Password:
Cloning into '/opt/theos'...
新版的theos 已经自带CydiaSubstrate.framework(基本上,tweak都依赖于一个名叫cydia Substrate (以前名字也叫mobile Substrate)的动态库,Mobile Substrate是Cydia的作者Jay Freeman (@saurik)的作品,也叫Cydia Substrate,它的主要功能是hook某个App,修改代码比如替换其中方法的实现,Cydia上的tweak都是基于Mobile Substrate实现的.)
devzkndeMacBook-Pro:lib devzkn$ pwd
/opt/theos/vendor/lib
devzkndeMacBook-Pro:lib devzkn$ ls -lrt
total 72
drwxr-xr-x 3 root wheel 102 Aug 10 15:19 libswift
lrwxr-xr-x 1 root wheel 43 Aug 10 15:19 libsubstrate.tbd -> CydiaSubstrate.framework/CydiaSubstrate.tbd
-rw-r--r-- 1 root wheel 635 Aug 10 15:19 librocketbootstrap.tbd
-rw-r--r-- 1 root wheel 392 Aug 10 15:19 libprefs.tbd
-rw-r--r-- 1 root wheel 588 Aug 10 15:19 libflipswitch.tbd
-rw-r--r-- 1 root wheel 1111 Aug 10 15:19 libapplist.tbd
-rw-r--r-- 1 root wheel 5646 Aug 10 15:19 libactivator.tbd
drwxr-xr-x 4 root wheel 136 Aug 10 15:19 TechSupport.framework
-rw-r--r-- 1 root wheel 432 Aug 10 15:19 README.md
drwxr-xr-x 5 root wheel 170 Aug 10 15:19 Opener.framework
-rw-r--r-- 1 root wheel 3342 Aug 10 15:19 LICENSE.md
drwxr-xr-x 5 root wheel 170 Aug 10 15:19 CydiaSubstrate.framework
drwxr-xr-x 4 root wheel 136 Aug 10 15:19 Cycript.framework
drwxr-xr-x 5 root wheel 170 Aug 10 15:19 CepheiPrefs.framework
drwxr-xr-x 4 root wheel 136 Aug 10 15:19 Cephei.framework
1.3 配置ldid
用来专门签名iOS可执行文件的工具,用以在越狱iOS中取代Xcode自带的codesign. 安装这个ldid,推荐的方式是采用brew来安装--
brew install ldid
1.4 dpkg-deb
deb是越狱开发包的标准格式,dpkg-deb是个用于操作deb文件的工具,有了这个工具,Theos才能正确的把工程打包成deb文件.
brew install dpkg
see also
更多内容请关注 #小程序:iOS逆向,只为你呈现有价值的信息,专注于移动端技术研究领域;更多服务和咨询请关注#公众号:iOS逆向。