【iOS】基于frida的砸壳工具优化方案(和砸壳本身关系不大)
小组里用的砸壳工具主要有两种:
一种是Clutch,使用比较简单的,但是总是会砸失败(原因大佬说过我忘了)
一种是frida,使用稍微复杂一点,不过效果好,当然也有问题,下面主要讨论frida。
使用frida砸壳需要这些东西:(大部分步骤是网上的资料,一些是自己实际使用的时候调整的)
iPhone端:
1. 添加源:https://build.frida.re
2. 按机子架构安装对应的砸壳工具
Mac端:
基于Python2.7,如果不是Python2.7的先切换至2.7(这一点没有留意,我自己的版本是2.7.1)
1. sudo easy_install pip
2. sudo pip install frida
如果遇到错误:Uninstalling a distutils installed project (six) has been deprecated and will be removed in a future version. This is due to the fact that uninstalling a distutils project will only partially uninstall the project.
试着运行以下命令:
sudo pip install frida --upgrade --ignore-installed six
3. 如果调用frida显示command not found,是因为新版本(12.2.26会出现这种问题)需要安装frida和frida-tools
sudo pip install frida-tools
以上可能还涉及到安装路径的问题,调整好路径就能解决。
准备工作做完之后,使用usbmuxd进行端口转发(原本写的是iproxy,但大佬们实际上使用的都是usbmuxd),然后直接在frida-ios-dump-master目录下运行命令行 ./dump.py +指令即可实现相关操作
相关代码:https://github.com/AloneMonkey/frida-ios-dump
一般来说这就算实现一键砸壳,但是针对实际应用还是进行了一点点优化。
优化之一
就是把端口转发也加进原来的dump.py里面,这主要是因为希望这个砸壳工具同样能提供给运营使用(目前还没有,因为可能需要做个配套的app?)
这个优化说起来简单,实际也不难,主要处理两个细节
1.端口转发会占用端口,因此在每次启动(或者是结束时)应该处理这个问题
2.端口转发需要时间,因此应该在转发完成的时候通信一下,接受完成的消息(庆幸usbmuxd的python-client如此易懂)
第一点的处理
[code] # 删除 ~/.ssh/known_hosts 文件 os.system('sudo chmod -R 777 ~/.ssh/') result = os.system("rm ~/.ssh/known_hosts") if result == 256: print('not remove ~/.ssh/known_hosts becasuse file not exist') elif result != 0: print('remove ~/.ssh/known_hosts failed') exit(0); # 检查 2222 端口占用 如果占用则kill try: find_port = 'ps -e | grep %s' %Port print('search port 2222 state') result = os.popen(find_port) text = result.read() text = text.split('\n') pid = [] for index in range(len(text)): if "tcprelay" in text[index]: pid = text[index].split()[0] break if pid != []: find_kill= 'kill %s' %pid print(find_kill) result = os.popen(find_kill) print ('kill port 2222 process') time.sleep(0.1) #等待进程kill except: print ('search port 2222 error') exit(1); print ('check port 2222 finish')
可以看到还是有瑕疵的,要等待进程kill该端口而让其sleep了一点时间,这显然不太好。
第二点的处理
在dump.py中加入代码作为服务器端(注意我用的是tcprelay2.py,因为保留了原文件没有动)
[code] # 建立socket连接是为了监听tcprelay.py成功的信号 try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = Host port = 9999 sock.bind((host, port)) sock.listen(5) except: print ('build listen socket failed,try run again') sock.close() exit(1); # 调用python-client工具转换端口 22:2222 os.system("python -t ./usbmuxd/python-client/tcprelay2.py 22:2222 &") # 接收端口信息来判断端口已经转发成功 (tcprelay.py作为客户端发送信息) while True: connection,address = sock.accept() data = connection.recv(1024) if data == "Forwarding Finish": connection.close() break; sock.close()
改一下usbmuxd/python-client/tcprelay.py(更名为tcprelay2.py)作为客户端,加在最后
[code]for rport, lport in ports: print "Forwarding local port %d to remote port %d"%(lport, rport) server = serverclass((HOST, lport), TCPRelay) server.rport = rport server.bufsize = options.bufsize servers.append(server) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = HOST port = 9999 sock.connect((host, port)) sock.send("Forwarding Finish") sock.close() alive = True while alive: try: rl, wl, xl = select.select(servers, [], []) for server in rl: server.handle_request() except: alive = False
只有中间那段是新添加的代码
优化之二
frida砸壳有一个问题,他只会砸执行时在内存里面的framework,而有一些应用在启动时(指在砸壳之前)并没有把framework加载进内存,于是就需要我们手动去把他们加载进内存(这个是大佬的思路,我只是负责实现)
采用的方法也很简单,直接遍历bundle下的framework,对他们执行dlopen
需要注意的一点是dlopen的配置选项应该选RTLD_LAZY。
我把这个写成了一个钩子(OC),然后在dump.py中把钩子dylib和plist放进了砸壳手机的对应目录。
当然如果这样处理的话在dump.py中打开应用后也是需要sleep的,保证砸壳在钩子执行之后,这显然也不是一个好方法。
补充优化二
在原来的砸壳代码中有一份dump.js,这一份是真正调用了frida的javascript API。
启动砸壳的代码如下:
[code]function handleMessage(message) { //start dump modules = getAllAppModules(); for (var i = 0; i < modules.length; i++) { console.log("start dump " + modules[i].path); result = dumpModule(modules[i].path); send({ dump: result, path: modules[i].path}); } send({app: ObjC.classes.NSBundle.mainBundle().bundlePath().toString()}); send({done: "ok"}); recv(handleMessage); }
可以看到我们只要在 getAllAppModules之前执行dlopen所有framework就能够保证砸壳前所有framwork都被加载进内存,而不再需要复制钩子进入对应目录,避免使用sleep这种不稳定手段。
具体代码之后更新,目前还未研究出js中调用OC(实际上dlopen是C++方法)的方法。
实际上对于优化二还是有优化空间,直接从dump.js下手,调用OC方法来dlopen所有framework。(需要看一下frida文档)
但现在要回去处理之前的功能整合需求,因此这个优化就暂时搁置了,毕竟已经算是基本实现一键砸壳了。
- 【iOS-Cocos2d游戏开发之九】讲解CCSpriteBatchNode与TP工具的".pvr.ccz",".plist"共用的终极精灵优化及注意事项!
- 轨迹系列——一种基于路网图层的GPS轨迹优化方案
- UITableview性能优化方案 iOS
- ios 查看UIView的层次继承关系工具
- 基于集合关系对求解闰年数的算法优化
- 基于关系数据库的查询优化
- android sdcard存储方案优化(基于wrapfs文件系统):之三
- iOS 客户端基于 WebP 图片格式的流量优化(上)
- 基于集合关系对求解闰年数的算法优化
- 帆软报表自动推送方案小结(基于ETL工具)
- iOS开发笔记之六十六——基于Json的页面动态化方案
- 【iOS-Cocos2d游戏开发之九】讲解CCSpriteBatchNode与TP工具的".pvr.ccz",".plist"共用的终极精灵优化及注意事项!
- iOS 仿斗鱼聊天:基于CoreText的面向对象图文排版工具AWRichText
- iOS 客户端基于 WebP 图片格式的流量优化(下)
- iOS 性能优化:Instruments 工具的救命三招
- 【iOS-Cocos2d游戏开发之九】讲解CCSpriteBatchNode与TP工具的".pvr.ccz",".plist"共用的终极精灵优化及注意事项!
- 价值100W的经验分享: 基于JSPatch的iOS应用线上Bug的即时修复方案,附源码.
- 【iOS-Cocos2d游戏开发之九】讲解CCSpriteBatchNode与TP工具的".pvr.ccz",".plist"共用的终极精灵优化及注意事项!
- 【iOS-Cocos2d游戏开发之九】讲解CCSpriteBatchNode与TP工具的".pvr.ccz",".plist"共用的终极精灵优化及注意事项!