iOS软件调试初探
写在前面:
最近热衷于一款背单词软件,但是有学习限制,于是就想尝试着破解。同时也顺便学习iOS安全方面的知识。本文以某某背单词软件为例子,一步一步介绍如何调试、破解,高手请无视,有纰漏之处欢迎指正。
免责声明:
文本涉及到的内容仅供学习,切勿用于商业用途。
准备工作:
动手前在论坛学习了一下,http://www.kanxue.com/bbs/showthread.php?t=167398和http://www.kanxue.com/bbs/showthread.php?t=138472两个帖子,按照文中介绍的步骤来,但是遇到了很多其他的问题,期间问题解决的过程也很坎坷。首先介绍gdb调试的方法:在一台越狱的设备上,cydia改为开发者模式,安装
>OpenSSH,作为SSH服务端;
>GNU Debugger(gdb调试工具):在这个源中cydia.radare.org,版本为1708,低版本不支持ios4.3+。
>adv-cmds:ps命令可以查看进程信息;
>darwin cc tools:otools可以查看可执行文件的详细信息;
>Link Identity Editor:ldid签名;
>PC上安装SSH Secure Shell Client
分析程序、反汇编代码:
在本例中要做的是破解软件学单词的数量限制,在文件管理器中查看软件目录,发现Learn.db应该存储了程序的参数信息,用sqlite browser之类的软件打开数据库,看到如下:
打开这个表,看到这一项:
应该是单词学习上限,只要修改这个值就可以轻松解除限制了,但是还看到了另一个东西:
应该是做校验的,看来直接修改还不行,要调试代码知道如何计算这个码才可以。这里我们先直接修改nStudyLimit为50000(毫不吝啬),另外备份一下这个db,保存复制回手机中。如果此时执行程序,会提示异常数据:
这是自然,因为擅自修改了文件,程序校验失败。用ida6.4打开软件中的执行文件,左侧可以看到程序中的函数名,根据名字猜测,看到在checkLearnNum这个函数中:
有关键信息,应该是在这个函数里做的校验。好我们记住这个函数附近的一个地址:0007610A,一会调试代码下断点要用到。
连接SSH:
要保证pc和手机连入同一个局域网中,ssh客户端中host即为手机ip地址,端口22,第一次接入账号为root,alpine,最好修改默认密码为你自己常用的。
如果没有无线设备可供使用,可以用数据线将手机连入pc,下载itools,打开其中的SSH隧道功能:
这时的host主机名为127.0.0.1。如图就算连接成功了:
熟悉gdb调试:
记住以下常用命令就足够了:
ps -ax:查看当前所有进程
Gdb -p pid:附加到目标进程
Info sh:这个可以查看程序代码在内存中的偏移地址
Break:下断点
display /i $pc | $cpsr.t:显示要执行的下一句指令
continue(或c):继续执行;
Nexti(或ni):单步执行一条汇编指令
Po $rN(N为数字,打印寄存器存储的对象,寄存器实际存储的是对象的地址)
Print $rN(打印寄存器中的值)
Set $rN=xxxx(给寄存器赋值)
先在手机上启动你要调试的程序,执行ps -ax查看目标进程的pid:
588 ?? 0:04.17 /var/mobile/Applications/77FFC04E-1B91-46CE-909C-CE886
然后附加到进程:
Gdb -p 588
过一会会显示........done.执行info -sh查看代码的偏移地址:
Num Basename Type Address Reason | | Source
| | | | | | | |
1 LearnEnglish - 0x8b000 exec Y Y /private/var/mobile/Applications/77FFC04E-1B91-46CE-909C-CE886A9060ED/LearnEnglish.app/LearnEnglish at 0x8b000 (offset 0x8a000)
最后的offset 0x8a000即为偏移地址,记下。此处有个窍门,info -sh后可能会输出很多信息,导致前面的都滚屏了,此时可在执行此命令后立即按pause键暂停,找到偏移地址后按方向键下,继续执行:)
此时需要先下断点,用之前我们找到的那个函数地址,执行break *(0x8a000+0x0007610A)下断点,输出以下说明成功:
Breakpoint 1 at 0x10010a
接着要再执行:
display /i $pc | $cpsr.t
这样之后我们每次单步执行都能输出下一句的代码来提示我们执行到了哪里。
此时执行c,让程序跑起来,在手机上操作程序,点击学习单词,看到gdb输出:
Breakpoint 1, 0x0010010a in -[WordsUIViewController checkLearnNum] ()
1: x/i $pc | $cpsr.t 0x10010a: 6f f0 34 ee blx 0x16fd74
说明断点下对了,我们找对了地方。
执行ni,向下走一步,此时要对比着ida中的代码一步步走,以防我们跟丢了:
我们单单只看这几句:
MOVW R2, #(:lower16:(cfstr_Nstudylimit - 0x7611C)) ; "nStudyLimit"
MOV R1, R4
MOVT.W R2, #(:upper16:(cfstr_Nstudylimit - 0x7611C)) ; "nStudyLimit"
ADD R2, PC ; "nStudyLimit"
//这里猜测应该是加载函数地址
BLX _objc_msgSend
//然后这句是执行
MOV R11, R0
//R0寄存器存储的应该是函数返回的值,也就是获取nStudyLimit的值。
我们ni执行到MOV R11,R0这句,执行po $r0:
(gdb) po $r0
50000
可以看到输出的是50000,就是我们之前修改的值。而且这里应该是NSString类型的字符串。
LDR R1, [R0] ; "currentDevice"
LDR R0, [R2] ; _OBJC_CLASS_$_UIDevice
BLX _objc_msgSend
MOV R1, #(selRef_uniqueGlobalDeviceIdentifier - 0x76164) ; selRef_uniqueGlobalDeviceIdentifier
ADD R1, PC ; selRef_uniqueGlobalDeviceIdentifier
LDR R1, [R1] ; "uniqueGlobalDeviceIdentifier"
//获取设备标识
BLX _objc_msgSend
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: