分享逆向一款vpn软件的过程和疑问!

看完第二版的“IOS应用逆向工程”,感觉比第一版更顺畅,很多细节都一一描述的非常清楚。在这感谢一下狗神。 :kissing_heart:
看完之后就像是自己手握一把屠龙刀了,有种见谁想砍谁的感觉,于是先拿陌陌试了一下手,发现代码太复杂,头文件就3800多个,所以就想找个简单的下手。柿子要找软的捏嘛 :grinning:

于是就想起最近安装的一款vpn软件(名字就不说了,毕竟■■人家也不好),这个软件免费只能用一两天,继续使用就要交费,试用期间感觉挺稳定的,关键是新上线的,代码应该相对简单。下面我就说说■■的过程。

目标:一款基于socket的vpn软件,mac版。
版本:1167
系统:Mac 10.11
工具: Hopper 3.7.8 Charles 3.8.3

先看看 app 里都有些什么东西,在“应用程序”里找到 app 图标,右键“显示包内容”,Contents 目录里有一些文件和文件夹,一般需要关注的有 Info.plist\MacOS\Resources 这三个东西。
Info.plist 文件是主配置文件,里面 CFBundleExecutable 字段说明了启动的主程序文件。
MacOS 一般存放主程序
Resources 一般存放一些图片,配置文件等。
Resources 里有个可疑的东西 engine,看名字猜测应该是提供 socket 代理的主要代码。

再看看应用的界面,可以看到有账号状态,有效期,流量等控制参数。

把主程序拷贝出来,使用 dump-class 导出头文件。

class-dump -S -s -H XXXX -o headers

大概看了一眼,知道选对下手目标了,因为一共只有30个头文件。

两个可疑的头文件映入眼帘, LaunchAtLoginController.h 和 MainWindow.h ,一个是主窗口一个是登录和运行控制器。

主窗口应该是刚刚看到界面,运行控制器应该是在后台访问网络,这两个地方都有可能是判断是否能继续使用的地方。
LaunchAtLoginController 里没有什么东西, MainWindow 里有一个可疑的方法 UpdateUserInfo ,定位到了方法。

就可以祭出神器 Hopper 。搜索 UpdateUserInfo 定位到方法里。点击 Pseudo Code 按钮,

转义成我这样的低手能看懂的形式,看到上来先是从 GetUserInfo 里取出 NSMutableDictionary。
然后从 NSMutableDictionary 里取出 user_valid_date 、 user_bandwidth_usage 、 user_stat 等数据。然后根据 user_stat 的返回值,由 swtich 到不同的分支。


通过对 user_stat 各种 swtich 不同的分析,它有以下几个情况。

0 = 第一次进入,访问网络读取信息
1 = ok
2 = DATA_OUT 流量不足
3 = SERVICE_EXP 服务过期
4 = SERVICE_UN 服务不可用
5 = UNKNOWN 未知错误

由此可见是否可用主要来自于访问网络的内容。

然后,打开 Charles ,选择 Mac OS Proxy 选项。退出应用重新登录,立即看到各种 http 访问信息。
全是明文 http json 内容,简直裸奔啊! :grin: 而且名字起的都清楚明了。 login 肯定是登录啦,bandwidth 应该是上传本地使用的流量,下载服务器的过期时间和剩余流量。

看到这基本有了■■的思路,建立一个网站,模拟 bandwidth 接口,完成 json 数据的返回。然后在/etc/hosts 把域名指向本地(127.0.0.1)。

简单写个php

<?php echo json_encode(array( 'user_bandwidth_usage' => "950.827", 'user_valid_date' => "2015-12-12 18:06:14", 'user_stat' => "1", 'version' => "1", )); ?>

然后成功■■,已经使用四五天了,没有出现任何问题。

最后,虽然通过逆向已经越过软件的付费功能,但我用的是偷懒的方法。
所以想问,像这种情况,并不是通过一个方法返回boolean值判断是否可用,所以不能简单粗暴的用hopper改汇编(mov eax , 0x1 ret)。而是在方法里,通过各种判断值决定是否过期。这种情况怎么实现 patch ?还是用 Hopper 编写汇编代码吗?还是 MacOS 系统也有类似 CydiaSubstrate 的框架写个程序实现 patch?而且 swtich 的汇编也是在看不太懂,下图是 swtich 相关的汇编代码,不知道改那个寄存器的值永久性的把值改成2!?各位帮忙看看!让我能实现一个完整的■■~

这个是服务器返回,VPN软件需要解析的JSON是吧?
你只要定位到解析这个JSON的地方,然后固定把它当作参数传给那个解析的地方/函数,就可以离线了。
注:user_valid_date可以改得更远一点,到2016年啥的

可以让他直接注入dylib修改返回的字典啊

是,这是服务器返回的,软件本身也是在内部解析了json。我也知道吧json的值固定下来就可以实现■■。

我是想问用什么方式吧json的值固定下来,也就是说用什么方式吧编译好的二进制修改了?是直接修改二进制文件?还是由hook类似的方法打个patch?

我是不是有点太较真了~ :joy:

ps,我没把日期改到2099年,是怕程序在我不知道的地方,吧这个日期传到服务器上,这样这软件作者肯定傻眼了, :joy: 他还没收到那么多会员费呢,就有人用到那时候了。
如果能固定下来,可以改到16年,一般一年后这软件也升级多少次了。

怎么注入到 mac app 的程序里?有没有什么参考的例子或者文章?

我的想法是,你先找到解析这个JSON的地方,看看它是怎么解析的;我估计会一个key一个key的分别解析,拿user_valid_date来说,会取出这个值,然后跟当前时间[NSDate date]比较,来判断app有没有失效。既然比较了,就有返回结果,要么0要么1,如果你能定位到这个返回的地方,把它静态patch掉,ret一个固定值,就可以达到目的了

按照我的经验好像一般是NSXMLParser吧

明白了,谢谢~
也就是说,不管他内部逻辑如何,总会有个0或1的判断,然后修改二进制把它固定下来。