Cydia源:http://zlxdike.github.io/repo/
需求
最新得Telegram已经开始全部使用Swift开发了。导致之前得tgunblock tweak失效。于是就想要自己试试hook swift。也当作一个学习过程吧。研究了一半后发现已经有现成插件了,叫nsfwgram,支持swift版的Telegram,不过既然都开始研究了,也顺便继续下去。自己在写一个吧。
分析
Github上其实有Swift版Telegram的源码,能减少很多功夫。项目叫TelegramSwift
git clone下来看了下。hookPeerUtils.swift中的public var restrictionText: String?{}方法就可以解决channel被屏蔽的问题
实施
虽然我们知道了要hook的相关内容了。但是我们知道swift编译后没法使用class-dump把类dump下来,这是因为swift所有的函数名都被mangled类似C++程序编译后的函数名。姑且叫它Swift Name Mangling。
举几个例子:
- hello.Rect.subscript.getter (hello.Direction) -> Swift.Int重整为- _TFV5hello4Rectg9subscriptFOS_9DirectionSi
- HookExampleApp.ViewController.viewDidLoad() -> ()重整为- _T014HookExampleApp14ViewControllerC11viewDidLoadyyF
- SwiftDemo.ViewController.CustomMethod(number: Swift.Int) -> Swift.Int重整为- _T09SwiftDemo14ViewControllerC12CustomMethodS2i6number_tF
xcode提供swift-demangle工具可以还原这些。1
2zlxdikedeMac:Desktop zlxdike$ xcrun swift-demangle _T09SwiftDemo14ViewControllerC12CustomMethodS2i6number_tF
_T09SwiftDemo14ViewControllerC12CustomMethodS2i6number_tF ---> SwiftDemo.ViewController.CustomMethod(number: Swift.Int) -> Swift.Int
接下来就是找到被重整后的symbol了
首先把TelegramCore扔到IDA Pro里面。结果坑爹了。形如_T函数几乎少的可怜。基本都是形如_$S
一开始我以为是因为上架了AppStroe。Apple对symbol做了修改防止被swift-demangle还原。还试图想要在自己机器(用的还是Swift3)上编译个TelegramCore。然后对比做还原。后来发现。应该是Swift版本编译的问题。从Swift4.2开始都开始用$S了
使用IDA Pro脚本先导出所有函数名
| 1 | from idautils import * | 
回到macOS使用用python脚本调用swift-demangle还原1
2
3
4
5
6
7
8
9
10
11
12
13
14import os
l = []
i = 0
with open("output.txt" ,"rb") as f:
	data=f.read()
	dataArr = data.split("\n")
	for x in dataArr:
		ret = os.popen('./swift-demangle %s' % x)
		i = i +1
		print i
		l.append(ret.read())
with open("result.txt","wb") as f:
	f.write("\n".join(l))
找到对应symbol$S7Postbox4PeerP12TelegramCoreE15restrictionTextSSSgvg ---> (extension in TelegramCore):Postbox.Peer.restrictionText.getter : Swift.String?
接下来用MSFindSymbol和MSHookFunction和MSGetImageByName搭配使用即可
踩过的坑
MobileSubstrate(Cydia Substrate),它是由Saurik开发的一个框架。应该是iOS11目前的越狱,不被Saurik所认可吧,所以导致这个框架一直没兼容iOS11。当然也可能是大神没空。目前iOS11上的Substrate很多都是越狱工具作者另外修改的可能基于comex的substitute项目做的修改
测试设备
iPhone 5S iOS10.0.2(yalu beta2越狱)
iPad Air2 iOS9.0.2(盘古越狱)
iPhone7 Plus iOS11.1.1(unc0ver RC9越狱)
这过程中遇到下面的问题,猜测可能是substrate的问题:
- MSGetImageByName在iOS9 iOS10上都返回NULL,iOS11正常
 - MSImageRef image = MSGetImageByName("@rpath/TelegramCore.framework/TelegramCore");
 即使用绝对路径也是一样情况
- MSFindSymbol在iOS9 iOS10上第一参数必为- NULL,才能正常获取到函数指针
 - MSFindSymbol(NULL,"_$S7Postbox4PeerP12TelegramCoreE15restrictionTextSSSgvg");
 在iOS11上虽然- MSGetImageByName能获取到值,但是- MSFindSymbol第一参数无论是不是- NULL,- MSFindSymbol都无法获取到函数指针。
 看了下comex的substitute的MSFindSymbol函数实现。发现都是并不是使用- dlsym去查找,他自己写了个- find_syms_raw,查找- MachO_machHeader,可能类似xcode带的- nm工具,- nm也无法导出这些- symbol,不然就不需要IDA Pro跑脚本获取所有的- Function Name了
- 使用dlsym与MSFindSymbol不同。MSFindSymbol以IDA Pro为准,即要带下划线_,而dlsym则不需要,这个估计与MSFindSymbol的实现有一定关系
代码实现
- iOS9 iOS10可工作 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 static int (*orig_function)(void) = NULL;
 static int new_function() {
 return 0;
 }
 %ctor {
 void *symbol = MSFindSymbol(NULL,"_$S7Postbox4PeerP12TelegramCoreE15restrictionTextSSSgvg");
 if (symbol) {
 MSHookFunction((void *)symbol,
 (void*)&new_function,
 (void**)&orig_function);
 }
 }
- 最原始有效,iOS9-iOS11通杀 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 static int (*orig_function)(void) = NULL;
 static int new_function() {
 return 0;
 }
 %ctor {
 void* handle=dlopen("@rpath/TelegramCore.framework/TelegramCore",RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
 if (handle){
 void* symbol = dlsym(handle,"$S7Postbox4PeerP12TelegramCoreE15restrictionTextSSSgvg");
 if (symbol){
 MSHookFunction((void *)symbol,(void*)&new_function,(void**)&orig_function);
 }
 }
 }
已经上传到Cydia源:http://zlxdike.github.io/repo,本文如有不足,请批评指正。