闲着没事看看iOS逆向工程这书做个笔记以备查询

工具 class-dump 用来提取已经砸过壳的 app 的头文件

下载地址 http://stevenygard.com/projects/class-dump

下载完将 dmg 里面的 class-dump 复制到 osx 的 /usr/bin/ 目录下,然后打开 Terminal 执行命令 sudo chmod -R 777  /usr/bin/class-dump 赋予其执行权限

工具 theos  

安装 theos 必须先安装 Xcode 与 Command Line Tools,一般安装 Xcode 会附带Command Line Tools . 如果安装多个 Xcode 需要指定一个 Xcode 给 Theos 默认使用.命令: sudo Xcode-select  -s /Applications/Xcode.app/Contents/Developer

 下载 Theos

在 Terminal 输入命令 export THEOS=/opt/theos  然后输入 sudo  git clone git://github.com/DHowett/theos.git $THEOS

 上面这个是原版下载地址,不过作者已经很久没有更新了.下面这个是别开发者更新的新版sudo git clone --recursive https://github.com/theos/theos.git /opt/theos

配置 ldid 用来签名的工具

下载地址http://joedj.net/ldid 下载后把他放到/opt/theos/bin/ 目录下,然后执行命令 sudo chmod -R 777 /opt/theos/bin/ldid 赋予权限

配置 CydiaSubstrate 

执行命令sudo /opt/theos/bin/bootstrap.sh substrate 

然后手机上的 Cydia 搜索 CydiaSubstrate 然后安装,然后找到/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate 拷贝到 osx 中将其重新命名为 libsubstrate.dylib  后放到 /opt/theos/lib/libsubstrate.dylib 中 替换掉里面的文件

配置 dpkg-deb

https://github.com/theos/dm.pl 下载重命名dpkg-deb 后放到/opt/theos/bin/目录下,执行sudo chmod -R 777  /usr/bin/dpkg-deb 赋予权限.

配置 Theos NIC temolates内置了5种 theos 工程模板,还可以从https://giahub.com/DHowett/theos-nic-templates/archive/master.zip 下载后解压,复制5个 tar 文件到/opt/theos/templates/iphone/ 目录下

theos 创建工程在Terminal执行/opt/theos/bin/nic.pl

然后选择需要创建的工程类型输入一系列工程信息后,打开工程目录里面的 Makefile 输入配置信息

THEOS_DEVICE_IP = 192.168.31.230 手机的 ip

ARCHS = armv7 arm64

TARGET = iPhone:latest:8.0 或 TARGET = iPhone:8.1:8.0 

iPhone:8.1:8.0采用8.1SDK发布对象支持版iOS8.0及以上系统 

iPhone:latest:8.0采用 Xcode 附带的最新版本 sdk 编译

include $(THEOS)/makefiles/common.mk 固定格式不要修改

TWEAK_NAME = 工程名称 不要修改

工程名称_FILES = Tweak.xm 包含的源文件(不包括头文件),多个以空格分隔

工程名称_FRAMEWORKS = UIKit 需要导入的框架名称多个与空格分隔

工程名称_PRIVATE_FRAMEWORKS = private 框架名称 导入私有框架,需要注意:PRIVATE_FRAMEWORKS是 AppStore 开发所不允许使用的它的内容每个 ios 版本之间会有差异,导入之前一定要确定导入的PRIVATE FRAMEWORKS 确实存在

include $(THEOS_MAKE_PATH)/tweak.mk 

after-install::

install.exec “killall -9 SpringBoard” 安装后需要结束的后台程序或重启手机

工程名称_LDFLAGS = -lx 连接 Mach-O 对象 -lx代表连接 libx.a 或 lib.dylib, 既给 x 加上 lib 的前缀,以及 .a 或 .dylib 的后缀.如果 x 是 y.o 的形式,则直接连接 y.o 不加任何前缀或后缀,例如要连接

libsqlite3.0.dylib libz.dylib 和 dylib.o 那么就可以写成这样  工程名称_LDFLAGS = -lz -lsqlite3.0 -dylib1.o

一般情况如下:

THEOS_DEVICE_IP = 192.168.31.230

ARCHS = armv7 arm64

TARGET = iPhone:latest:8.0

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = 工程名称

工程名称_FILES = Tweak.xm

工程名称_FRAMEWORKS = UIKit

include $(THEOS_MAKE_PATH)/tweak.mk

after-install::

install.exec “killall -9 SpringBoard”

默认源文件Tweak.xm "xm"中 x 代表支持 logos 语法 如果后缀单独一个 x 说明源文件支持 logos 和 c 语法,如果是 xm 说明源文件支持 logos 和 c/c++ 语法 

最基本的 logos 语法

%hook %log %orig 这3个预处理指令作用 %hook 指定要 hook 的 class 必须与 %end 结尾

%hook 类名 

- (void)_menuButtonDown:(id)down

{

NSLog(@"button");

%orig;

}

%end

这段代码的意思是 钩住 (hook) SpringBoard 类里的_menuButtonDown函数,先将依据话写入 syslog 在执行函数的原始操作.

%log 该指令在% hook 内部使用,将函数的类名,参数等信息写入 syslog 例如%log([(<type>)<expr>,..])的格式追加其他打印信息,如下:

%hook SpringBoard

- (void)_menuButtonDown:(id)down

{

%log((NSString *)@"iOSRE", (NSString *)@"Debug");

%orig;

}

%end

%orig 该指令在 %hook 内部使用,执行被钩住的 hook 的函数的原始代码,如下:

%hook SpringBoard

- (void)_menuButtonDown:(id)down

{

NSLog(@"button");

%orig;

}

%end

如果去掉%orig,那么原始函数不会得到执行

还可以利用%orig更改原始函数的参数,例如

%hook SBLockScreenDateViewController

- (void)setCustomSubtitleText:(id)arg1 withColor:(id)arg2 

{

%orig(@"IOS 8 App reverse Engineering", arg2");

}

%end

这行代码是把锁屏日期显示时间的地方修改成 这句话"IOS 8 App reverse Engineering"

除了 %hook %log %orig  以外, Logos 常用的预处理指令还有 %group %ctor %new %c

%group该指令是将 %hook 分组,便于代码管理及按条件初始化分组 必须以 %end 结束,一个%group的 %hook 会被隐式归类到%group_ungrouped 中.%group的用法如下:

%group iOS7Hook

%hook iOS7Class

- (id)iOS7Method

{

id result = %orig;

NSLog(@"This class & method only exist in iOS7.");

return result;

}

%end

%end

%group iOS8Hook

%hook iOS8Class

- (id)iOS8Method

{

id result = %orig;

NSLog(@"This class & method only exist in iOS8.");

return result;

}

%end

%end

%hook SpringBoard

- (void)powerDown

{

%orig;

}

%end

这段代码的意思是在%group iOS7Hook中钩住 iOS7Class 的 iOS7Method函数, 在%group iOS8Hook中钩住 iOS8Class 的 iOS8Method函数,然后在%group_ungrouped  中钩住SpringBoard类的powerDown函数,需要注意的是,%group必须配合%init使用才能生效

%init  该指令用于初始化某个%group,必须在%hook或%ctor内调用,如果带参数,则初始化制定的group,如果不带参数,则初始化 ungrouped, 如下

#ifndef kCFCoreFoundationVersionNumber_iOS_8_0

#define kCFCoreFoundationVersionNumber_iOS_8_0 1140.10

#endif

%hook SpringBoard

- (void)applicationDidFinishLaunching:(id)application

{

%orig;

%init;

if (kCFCoreFoundationVersionNumber >=

kCFCoreFoundationVersionNumber_iOS_7_0 && kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_8_0) %init(iOS7Hook);

if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0) %init(iOSHook);

}

%end

只有调用了%init  对应的%group才起作用,切记!

%ctor 该指令是 tweak 的 constructor, 完成初始化工作,如果不显式定义, Theos 会自动生成一个%ctor,并在其中调用%init(_ungrouped). 因此

%hook SpringBoard

- (void)reboot

{

NSLog(@"If rebooting doesn't work then I'm screwed.");

%orig;

}

%end

可以生效,因为 Theos 隐式定义了如下内容

%ctor

{

%init(_ungrouped);

}

%hook SpringBoard

- (void)reboot

{

NSLog(@"If rebooting doesn't work then I'm screwed.");

%orig;

}

%end

%ctor

{

}

这个%hook代码无法生效,因为这里显式定义了%ctor 却没有显式调用%init,%group(_ungrouped)不起作用.%ctor 一般可以用来初始化%group, 以及进行 MSHookFunction 等操作,如下:

#ifndef kCFCoreFoundationVersionNumber_iOS_8_0

#define kCFCoreFoundationVersionNumber_iOS_8_0 1140.10

#endif

%ctor

{

%init;

if (kCFCoreFoundationVersionNumber >=

kCFCoreFoundationVersionNumber_iOS_7_0 && kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_8_0) %init(iOS7Hook);

if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0) %init(iOSHook);

MSHookFunction((void *)&AudioServicesPlaySystemSound,(void *)&replaced_AudioServicesPlaySysTemSound,(void **)&original_AudioServicesPlaySystemSound);

}

注意,%ctor 不需要以%end结尾

%new 在 %hook 内部使用,给一个现有的 class 添加新函数,功能与 class_addMethod 相同.它的用法如下:

%hook SpringBoard

%new

- (void)namespaceNewMerhod

{

NSLog(@"We've added a new menthod to SpringBoard.");

}

%end

Objective-C 和 category 语法也可以给现有的 class 添加新函数,为什么要用%new呢?

因为 category 与 class_addMethod 的区别,前者是静态的后者是动态的.那么在这种情况下,静态和动态,尤其是当 class 来之某个可执行文件的时候.举个例子,上面的代码给 SpringBoard 类添加一个新方法,如果使用 cateGory, 代码应该是下面这样:

@interface SpringBoard (iOSRE)

- (void)namespaceNewMerhod;

@end

@implementation SpringBoard (iOSRE)

- (void)namespaceNewMerhod

{

NSLog(@"We've added a new menthod to SpringBoard.");

}

@end

如果尝试编译上面的代码,会得到"error:cannot find initerface declaration for'SpringBoard'"的报错信息,编译器找不到SpringBoard雷的定义.可以构造一个SpringBoard的定义,骗过编译器,如下:

@interface SpringBoard : NSObject

@end

@interface SpringBoard (iOSRE)

- (void)namespaceNewMerhod;

@end

@implementation SpringBoard (iOSRE)

- (void)namespaceNewMerhod

{

NSLog(@"We've added a new menthod to SpringBoard.");

}

@end

重新编译,仍然会报错,如下:

Undefined symbols for architecture armv7:"_OBJC_CLASS_S_SpringBoard",referenced from:l_OBJC_$_CATEGORY_SpringBoard_$_iOSRE in Tweak.xm.b1748661.o

ld: symbol(s) not found for architecture armv7

clang: error : linker command failed with exit code 1 (use -v to see invocation)

ld找不到"SpringBoard"的定义.一般来说, iOS 程序员在碰到这个错误时的第一反应是:"是不是忘记导入那个 "framework",但是转念一想,SpringBoard 类是SpringBoard这个 App里面的一个类,而不是一个framework,要怎么导入?现在你是不是觉得%new 非常可爱了呢?

%c  该指令的作用等同于 objc_getClass 或 NSClassFromString,既动态获取一个类的定义,在% hook 或% ctor 内使用

logos指令还有很多 需要的可以直接google 或百度

control 文件记录 deb 包的管理信息会打包到 deb 包里面.

工程文件中的. plist 文件

打开文件最外面是 dictionary  只有一个名为 Filter 的建 Filter 下是一系列的 Array ,可以分为三类 Bundles 指定若干个 bundle 为 tweak 的作用对象 ,Classes 指定若干个 class 为 tweak 的作用对象. Executables 指定若干个可执行文件为 tweak 的作用对象,这三类 Array 可以混合使用

{

Filter = {Mode = Any;Bundles = ("com.apple.springboard",);Classes = (123,);Executables = (aaaaa,);};}

Filter有不同的类的 array 是需要添加一个Mode : Any 键值对.Filter下只有一个类时,不需要添加Mode : Any 键值对.

编辑+打包+安装

make  命令编译工程 make package 命令编译打包 make package install 编译打包安装

设置 authorized_keys 钥匙 打开/Users/你的用户名/.ssh/known_hosts 删除对应的 iOSip 那一行

在 Terminal 中执行命令 ssh-keygen -t rsa  回车 回车 如果存在提示是否重写选择 y 重写 然后输入连接 iphone 的密码  然后cp /Users/jiangyihui/.ssh/id_rsa.pub ~/authorized_keys会在用户目录下生成authorized_keys 接下来配置 iOS ,在 Terminal 中执行连接到ssh root@你的iosip 在执行命令ssh-keygen 一路回车,然后执行scp ~/authorized_keys root@IOSIP:/var/root/.ssh

make clean 工程清除命令

Theos 开发示例

在 Terminal 中执行命令 iphone/tweak 按提示输入信息

然后编辑 Tweak.xm 文件

内容如下

%hook SpringBoard

- (void)applicationDidFinishLaunching:(id)application

{

%orig;

UIAlertView *[alert = [UIAlertView alloc] initWithTitle:@"你好!" message:"呵呵" delegate:self cancelButtonTitle:@"ok" otherButtonTitles:nil];

[alert show];

[alloc release];

}

%end

编辑 Makefile

THEOS_DEVICE_IP = 192.168.31.230

ARCHS = armv7 arm64

TARGET = iPhone:latest:8.0

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = 工程名称

工程名称_FILES = Tweak.xm

工程名称_FRAMEWORKS = UIKit

include $(THEOS_MAKE_PATH)/tweak.mk

after-install::

install.exec “killall -9 SpringBoard”

在 Terminal 中执行命令make package install

Reveal ui 调试工具 mac 上下载安装

iOS cydia 里面安装 Reveal loader

打开电脑上的Reveal 选中菜单Help下的 Show Reveal Library in Finder  然后复制 libReveal.dylib  到 iOS 的 /library/RHRevealLoader/ 文件夹中.没有这个文件夹自己创建一下

在ios 设置中找到Reveal 打开里面逆向想要调试的 app 然后电脑上打开Reveal ios 中打开相应的 app 界面就会显示在电脑中

ida (这里没有找到 mac 可以用的 ida demo) 就只能按照书上的先简单记录一下

打开 ida 选中对应的 ARM

左侧小部分 Functions 窗口 右边是 Main 窗口

Functions window 显示的是 函数或叫方法 ,双击一个函数 main window 会显示它的函数体.在选中 Functions window 时点击菜单栏身上的 Search  会弹出子菜单 选择Search 输入要查找的内容,可以在所有函数里查找指定的字符串,十分方便,当要查找的内容出现在搓个函数名里面时还可以点击Search again 来遍历这些函数名.

Functions window中的函数与 class-dump 导出的内容吻合, ida 还将所有 subroutine 罗列出来class-dump 是做不到的,class-dump导出的都是函数名.subroutine的名称只是一个代号,没有明显的含义,分析难度大, ios 的底层用c 和 c++实现的,编译之后哦生成大都是subroutine,只能使用 ida 这样的工具.想要深层次的挖掘 ios 必须掌握 ida 的用法.

Main window 有两种显示模式,分别是 Graph view 和 Text view 它们之间可以通过空格键切换.Graph view把程序用方块的形式表现出来.各个分支之间执行顺序用箭头表示,当执行到满足判断条件分支的线是绿色的.否则是红色的.当执行没有分支时线是蓝色的.当执行到某个方块会判断R0是否为0,如果 R0!=0 ,则满足条件就会执行 BEN (Branch if not Equal to zero) 走绿线接着执行下面的方块.否则走红线执行红线的方块.此处是 IDA 的难点之一.

颜色指示栏,当选中一个符号时,相同的符号都会用黄色高亮显示.方便跟踪查看.符号高亮,双击符号可以查看它的实现,在任意符号上点击鼠标右键,会弹出菜单.其中常用的功能有 jump to xref to operand... (快捷键 X) 点击后出现的窗口罗列了这个文件中显式引用这个符号的所有信息.选择菜单中的Xrefs graph to...  就会以图块和线显示引用.如果引用过多那就会像一团乱麻.看不清.还有 Xrefs graph from... 则会显示这个符号显示引用的多有符号.多数情况下,找到一个感兴趣的符号会进一步查找与这个符号相关的所有线索.一种笨方法是鼠标选中 Main window 时点击菜单栏上的 Search 此时菜单然后选择 text... 这时可以根据自己情况选择搜索是否对大小写敏感.搜索格式是不是正则表达式等.然后勾选Find all occurences 点击 OK  ida会将文件中所有满足搜索条件的符号列出来.供我们一一查看. Text view 一般配合 LLDB 进行动态调试. IDA 有个 Bug 会导致 Graph view 的末端显示不全.比如一个 subroutine  本来有100行指令 ,但是只显示了80行.当对某个Graph view块中的指令产生怀疑时,可以切换到 Text view 中看看Graph view是不是漏显示了某些代码.(由于书上的案例使用的是 ios8作为案例.我手上只有 ios9系统的 iphone 文件内部不一样,这里无法分析.等手上ios8的 iphone 到时候在补上)

KennyTM 开发的 dyld_decache  

下载地址https://github.com/downloads/kennytm/Miscellaneous/dyld_decache[v0.1c].bz2

下载解压后重新命名dyld_decache 然后赋予777权限 命令sudo chmod +x  dyld_decache

该工具可以dyld_shared_cache_armv7s或dyld_shared_cache_arm64其中的二进制文件提取出来,这样确保分析的文件来自本机,在使用 mac 工具分析同一目标时, osx 和 iOS 上分析得出的指令和地址是完全吻合的,避免出现驴唇对不上马嘴的低级错误.使用dyld_decache之前要将/System/Library/Caches/com.apple.dyld/dyld_shared_cache_文件拷贝到 osx 中 (不能用 SCP  命令拷贝) 

dyld_decache -o  /存放路径  /提取路径/dyld_shared_cache_arm64

iOS 配置

打开 cydia 搜索Cydia Substrate 安装

案例:用 Theos新建一个iphone/activator工程

代码如下:

#import "RootViewController.h"

class CPPClass

{

public:

void CPPFunction(const char *);

};

void CPPClass::CPPFunction(const char *arg0)

{

NSLog(@"iOSRE: CPPFuction: %s", arg0);

}

extern "C" void CFunction(const char *arg0)

{

NSLog(@"iOSRE: CFunction: %s", arg0);

}

extern "C" void ShortCFunction(const char *arg0)

{

CPPClass cppClass;

cppClass.CPPFunction(arg0);

}

@implementation RootViewController

- (void)loadView

{

NSLog(@"- loadView -");

self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];

self.view.backgroundColor = [UIColor redColor];

}

- (void)viewDidLoad

{

[super viewDidLoad];

NSLog(@"- viewDidLoad -");

CPPClass cppClass;

cppClass.CPPFunction("This is a C++ function!");

CFunction("This is a C function!");

ShortCFunction("This is a short c function!");

}

@end

然后 make package install 安装手机上

cycript 是一个方便的工具

 一些简单操作

在 Terminal 中执行命令 ps -e 查看当前进程找到你需要的进程 id 

cycript -p 进程 id

还有一些简单用法

UIApp.keyWindow.recursiveDescription().toString()

[#0x12fca3e00  nextResponder]

获得某各类的对象choose(SBScreenShotter)

获取APP所有window

cy# [UIApp windows]

获取View的superView和subView

cy# [#0x15e8d2c0 subviews]

cy# [#0x12345678 superview]

可以用#address的方式来调用对象。 利用着几个函数可以看所有view,可以用[#viewAddress setHidden:YES]函数,UI上消失的就是对应的view。

LLDB 和debugserver

debug server配置

通过命令复制到 osx 中scp root@192.168.31.230:/Developer/usr/bin/debugserver ~/debugserver

debugserver瘦身在 Terminal 中执行命令 lipo -thin arm64 ~/debugserver -output ~/debugserver 其中 arm64 对应你机器的型号

给debug server添加task_for_pid权限

下载http://iosre.com/ent.xml

在 Terminal 中执行命令 /opt/theos/bin/ldid -Sent.xml debugserver 

上面5秒内没有完成用下面的方法 

下载 http://iosre.com/ent.plist 

在 Terminal 中执行命令codesign -s - -- entitlements ent.plist -f debugserver

拷贝回 iso 目录中 scp ~/debugserver root@192.168.31.230:/usr/bin/debugserver

连接到 iOS 命令 ssh  root@192.168.31.230

授权 命令 chmod +x /usr/bin/debugserver

用debugserver启动或附加进程

命令开启进程等待连接 debugserver -x backboard *:1234 /Applications/MobileSMS.app/MobileSMS

命令 debugserver 192.168.31.230:1234 -a "MobileSMS" 会附加MobileSMS并开启进程等待192.168.31.230的 LLDB 接入

如果执行错误说明 ios 上的 Developer目录下缺少必要的调试数据.这种情况一般是因为没有在 Xcode 连接过给设备. 在 Xcode 重新连接一次该设备

当退出debug server时,当前调试的进程也会一并退出.debugserver的配置结束.接下来的操作都是 LLDB 上完成的.

LLDB使用说明

在了解 LLDB 用法之前,需要对 LLDB 的一个 bug 有所了解: Xcode6所附带的 LLDB 版本号320.x.xx 才 armv7和 armv7s 设备上有时候会混淆 arm 和 THUMB 指令,根本无法调试.

连接命令 process connect connect://192.168.31.230:1234 连接时间比较长需要3分钟以上

USB如何连接的:

1.点击下载usbmuxb,单独保存python-client目录下的tcprelay.py和usbmux.py两个文件,把它们放到同一个目录下;

2.本地端口转发到远程iOS端口

/Users/jiangyihui/code/tcprelay.py -t 22:2222

3.ssh到iOS设备

ssh root@localhost -p 2222

4.debugserver attach进程

debugserver *:1234 -a "SpringBoard"

5.将本地端口转发到debugserver端口

/Users/snakeninny/Code/USBSSH/tcprelay.py -t 1234(debugserver端口):1234(本地端口)

6.lldb调试

lldb

process connect connect://localhost:1234

image list 与 GDB 中的 info shared 类似,用于列举当前进程中的所有模块image 每次进程启动,同一进程的所有模块在虚拟内存中的起始地址都会产生随机偏移

举例:进程 A 中有一个模块 B , B 模块的大小是100字节,进程 A 第一次启动时,模块 B 可能会被加载到虚拟内存的0x00到0X64.第二次启动被加到0x10 到0X74.第三次启动被加到0X60到0Xc4也就是说它的大小虽然没有变,但是起始地址每次都在变,然而这个起始地址恰恰是接下来回频繁用到的一个关键数据.

使用命令 image list-o-f ,待 LLDB 链接 debugserver 后输入 image list-o-f 命令

image list -o -f

[  0] 0x01645000 /System/Library/CoreServices/SpringBoard.app/SpringBoard(0x0000000023c4000)

[第一列序号] (模块偏移地址简称 ASLR) 全路径(模块偏移后起始地址) 

计算方法 

偏移后基地址(0x023c4000) = (IDA)基地址 + ASLR偏移地址(0x01645000)

偏移后基地址(0x023c4000) - ASLR偏移地址(0x01645000) = 基地址(0X2260A000)


符号基地址 

符号在模块中的地址 - 模块第一条地址 = 符号模块在中的相对地址

符号在模块中的相对地址 + 模块偏移后起始地址 = 符号基地址

NSLog的基地址 = NSLog 在 Foundation 中的相对地址 + Foundation 的基地址

NSLog 函数在 Foundation 中的相对位置, NSLog 函数地址指令 "SUB SP,SP,#0xc"  左边的那个0X2261AB94 ,代表 NSLog 在 Foundation 中的位置

NSLog 在 Foundation 中的地址(0X2261AB94) - Foundation基地址(0X2260A000) = NSLog 函数在 Foundation 中的相对地址 0X10B94

NSLog 的基地址 = NSLog 函数在 Foundation 中的相对地址 0X10B94 + Foundation偏移后基地址(0x023c4000) = NSLog 在 Foundation 中的地址(0X2261AB94)

偏移后模块基地址 = 偏移前模块基地址 + ASLR 偏移地址

偏移后符号基地址NSLog 在 Foundation 中的地址(0X2261AB94) = 偏移前符号基地址 + 符号所在模块的 ASLR 偏移地址(Foundation ASLR)

偏移后指令基地址 = 偏移前指令基地址 + 指令所在模块的 ASLR 偏移

符号的基地址 = 符号对应函数第一条指令的地址 

偏移前地址从 IDA 里面查看. ASLR 偏移从 LLDB 里面查看, 两者相加就是偏移后基地址.

breakpoint  与 CGB 中的 break 类似,用于设置断点,在逆向中一般用到的 b function 或 br s -a address 以及 br s -a 'ASLROffset+address'

在函数的起始位置设置断点,命令 b NSLog

在地址处设置断点,命令br a -s 0xcccccc 或 br s -a '0x6+0x9'

注意在输出中 Breakpoint X  "x" 代表序号

因为在逆向中调试涉及多是汇编代码,所以大多情况下都是在某一条汇编指令上下断点,在函数上下断点的情况很少.要在汇编指令上下断点就要知道它的便宜后基地址,

还可以用"br dis", "br en", "br del" 来禁用,启用,删除断点

禁用某个断点命令 br dis 6

启用所有断点 br en 或启用某个断点 br en 6

删除所有断点 br del 删除某个断点 br del 6

指定在某个断点得到触发时执行预先设置的指令 

br com add 1

执行到这条指令后, LLDB 会要求我们设置一系列指令,以 DONE 结束.例如:

po [$r0 class]

p (char *)$r1

c

DONE

这里输入了3条指令,1号断点一旦触发,就会顺序执行.

br com add 一般用于自动观察某个断点被触发时其上下文的变化.找到进一步的线索

print 它可以打印某处的值

p 命令打印

用 po 命令打印 oc 对象

用 p(char *) 强制转换方式打印 C语言基本数据类型对象

但是 LLDB 解析有时候会出错,注释的符号不对.这种情况请以 IDA 静态分析的符号为准

用x 命令打印一个地址存放的值

用 p/x 以十六进制方式打印 SP, 它是一个指针

x/10 打印指针指向的联系10个字(word)的数据

nexti 与 stepi 的作用是执行下一条机器指令,它们最大的区别是前者不进入函数体.后者会进入函数体.它们分别以简写 ni 和 si ,是调试时使用最多的指令之一,

register write 命令用于给指定的寄存器赋值,从而对程序进行改动,观察程序的执行过程有什么变化.用于改变 r0值 查看它跳转到那个分支

LLDB 使用小提示

调试的二进制文件必须从 IOS 中提取.

IDA 分析的二进制文件必须与 LLDB 调试的二进制文件相同.这样偏移前基地址, ASLR 偏移,偏移后基地址才能对应得上.从其他渠道(如 SDK,模拟器等)提取的文件一般不能用作动态调试.

LLDB 中简化输入

如果想重复一条指令,直接按回车就可以了.如果想查看以前执行过的指令,按方向键的向上和向下就可以了.

dumodecrypted 用于砸壳

http://www.jianshu.com/p/039dfd040253

cycript调试常用命令

http://www.jianshu.com/p/2bbe4b0b3950

暂时写到这里等有时间的时候在继续














x

推荐阅读更多精彩内容