# 【APK】滴答qd # 【APK】滴答qd ## 解锁会员 打开软件,使用一个会员功能跳出这个界面,为什么会跳转到这里?肯定是在点了使用后判断当前是否是会员,如果是会员正常使用,不是会员则跳转到这。所以逆向的关键是找到这个判断的地方 ![image-20240406221822688](http://cdn.wutongliran.top/img/image-20240406221822688.png) 打开 jadx ,把安装包丢进去反编译,jadx 可以将反编译后的 smali 代码转成 java 代码,方便分析。尝试搜索字符串“升级到高级会员”来定位关键代码: ![image-20240406222207620](http://cdn.wutongliran.top/img/image-20240406222207620.png) 搜出来的资源,只有圈起来这三个比较符合这个界面上的字符串 尝试搜索其中的第一个字符串的值: ![image-20240406222746135](http://cdn.wutongliran.top/img/image-20240406222746135.png) 在搜索结果中没发现什么有关逻辑性的代码 再试第二个: ![image-20240406222909136](http://cdn.wutongliran.top/img/image-20240406222909136.png) 在搜索结果中发现一个可疑三目运算代码: ```java getString(user.isPro() ? R.string.alreay_pro_account : R.string.upgrade_to_premium) ``` 代码的意思是:调用 user 类下的 `isPro()` 方法,如果返回的值为 true (真),则获取 `R.string.alreay_pro_account` 对应的字符串,反之获取 `R.string.upgrade_to_premium` 对应的字符串。我们已经知道 `upgrade_to_premium` 对应的字符串是“升级到高级会员” 看看`alreay_pro_account`对应的字符串是啥: ![image-20240406223323059](http://cdn.wutongliran.top/img/image-20240406223323059.png) ![a70e957a4558687d777a088174c789ea](http://cdn.wutongliran.top/img/a70e957a4558687d777a088174c789ea.jpg) 事到如今已经很明显了,也就是当`user.isPro()`返回的布尔类型为 true (真),就会显示“您以是高级会员”,反之显示“升级到高级会员” 静态分析眼见为虚,为了验证前面的判断,掏出Frida hook一波,如果没问题再去改 smali 代码 hook 代码: ```javascript Java.perform(function () { let User = Java.use("com.ticktick.task.data.User");//找到User类 User["isPro"].implementation = function () {//hook User.isPro() console.log(`User.isPro is called`);//如果打印,表示 User.isPro 被调用 let result = this["isPro"](); //接收 isPro 运行的结果 console.log(`User.isPro result=${result}`);//打印 User.isPro() 运行结果 return result;//返回结果保证后续正常运行 }; }); ``` 运行 hook 代码,当使用会员功能时跳转到充值界面,同时控制台输出`User.isPro is called`和`User.isPro result=false` ![image-20240406224556817](http://cdn.wutongliran.top/img/image-20240406224556817.png) 这说明当使用会员功能时调用了`User.isPro()`并且返回的结果是`false`,也就是判断我们当前不是会员 如果想让他判断我们是会员,就应该想办法使`isPro()`返回的结果为 true (真)。现在更新 hook 代码,在返回结果前把 result 赋值为 `true` ```javascript Java.perform(function () { let User = Java.use("com.ticktick.task.data.User");//找到User类 User["isPro"].implementation = function () {//hook User.isPro() console.log(`User.isPro is called`);//打印 User.isPro 被调用 let result = this["isPro"](); //接收 isPro 运行的结果 console.log(`User.isPro result=${result}`);//打印 User.isPro() 运行结果 result = true;//结果返回前赋值为 true console.log(`User.isPro last result=${result}`);//打印修改后的返回值 return result;//返回结果保证后续正常运行 }; }); ``` 再次使用会员功能,这次成功使用上,证明了之前的判断是正确的 ![image-20240406225422943](http://cdn.wutongliran.top/img/image-20240406225422943.png) 最后去修改 smali 代码: 打开 AndroidKiller (电脑端的反编译/回编译工具,手机端可以用MT管理器来反编译/回编译),把安装包丢进去反编译,搜索:`isPro`,找到 `com\ticktick\task\data\User` 类 (smali中类的路径用"\\"隔开) ![image-20240406230726337](http://cdn.wutongliran.top/img/image-20240406230726337.png) 在返回前强行赋值 ![image-20240406230857991](http://cdn.wutongliran.top/img/image-20240406230857991.png) 保存、回编译,逆向成功