某瓣去广告实战与签名对抗
# 某瓣去广告实战与签名对抗## 写在前面
这应该是我第一次成功修改app,以前主要是调用app的接口实现数据采集(网络爬虫),这次尝试给app去广告,最后成功了很开心,主要是跟正己大佬学的,在此特别感谢!
郑重申明,本文仅用于学习交流,禁止用于非法途径,另外也**不提供成品软件**。
## 使用的工具
| 名称 | 描述 |
| ---------------------------------------------------------- | ---------------------------------------------- |
| 某瓣apk | 版本7.18.1 更高版本可能有壳 |
| 雷电模拟器或安卓真机 | 需要root |
| jadx | 反编译工具 |
| np管理器或mT管理器 | 反编译工具 ,smali代码修改 |
| frida | hook工具,验证想法 |
| 其他工具可参考正己大佬安卓逆向课程前四课的工具,如开发助手 | https://www.52pojie.cn/thread-1695141-1-1.html |
## 去除开屏广告
使用mt管理器的activity记录功能定位到开屏广告所在类
定位到开屏广告的包在`com.douban.frodo.activity.SplashActivity`,直接去这个类找了好久也没有找到关键的方法,用frida hook了一下发现好多方法在开屏阶段没有调用,表现为方法hook住了但没有输出。
没有找到从SplashActivity跳转到其他Activity的关键方法,我卡住了,我通过阅读了大量源码定位到以下这个方法`requestSplashShow`这个方法,这个方法位于`douban.ad.api`,用frida 先hook了一下发现这个方法确实有被调用,我注意到这个方法进行了异常捕获,直接return也是没有关系的。
先用frida hook这个方法,直接返回null试一下,发现真的就没有广告了,这个方法成功被我嚯嚯掉了【狗头】以下是frida hook的代码。
```javascript
let AdApi = Java.use("com.douban.ad.api.AdApi");
AdApi["requestSplashShow"].implementation = function (str, z, z2, str2) {
console.log(`AdApi.requestSplashShow is called: str=${str}, z=${z}, z2=${z2}, str2=${str2}`);
// let result = this["requestSplashShow"](str, z, z2, str2);
// console.log(`AdApi.requestSplashShow result=${result}`);
// return result;
return null;
};
```
使用np管理器修改对应的smali代码
虽然这样修改后这个方法似乎没有编译通过(np不能转成java代码),有大佬知道的话可以指点一下,我smali学的有点差,不过最起码我把这个请求广告的函数搞坏了。
修改保存后用np管理器重新签名,**发现确实没有开屏广告了**,但是请求非法104,这个app算是废了。
但是我之前研究过某瓣的网络请求签名“_sig”,它的签名方式是**hmachash**,而hmachash的密钥(secretkey)是根据app的签名信息动态生成的,我们对app进行了签名,生成的密钥(secretkey)不对了最后发生请求的“_sig”自然也不对了。
## 签名对抗
因为知道是请求"_sig"的有问题,可以按以下方式进行定位。
搜索关键字"_sig"
发现_sig 是a3
在`com.douban.frodo.network.ApiSignatureHelper`发现了以下代码,其中str4就是hmachash 密钥,如果为了构造请求的签名直接hook str4的值即可,但我们还可以继续跟。
我们的目的是弄清楚`str4`具体的生成方法
```java
String str4 = FrodoApi.a().e.b;
```
上面代码的意思是它是FrodoApi这个类调用了a方法后e属性的b属性,可能有点绕,我们可以在jadx中双击e
发现e是一个`ZenoConfig`类,再双击`ZenoConfig`
发现ZenoConfig的b是这个方法的第三个参数,也就是我们要的e.b是这个方法的第三个参数,我们可以查找用例
最终定位到这个方法
```java
@SuppressLint({"PackageManagerGetSignatures"})
public static void a(boolean z) {
if (TextUtils.isEmpty(b)) {
b = "74CwfJd4+7LYgFhXi1cx0IQC35UQqYVFycCE+EVyw1E=";
}
if (TextUtils.isEmpty(c)) {
c = "bHUvfbiVZUmm2sQRKwiAcw==";
}
if (z) {
try {
String encodeToString = Base64.encodeToString(AppContext.a().getPackageManager().getPackageInfo(AppContext.a().getPackageName(), 64).signatures.toByteArray(), 0);
b = AES.a(b, encodeToString);
c = AES.a(c, encodeToString); # hmachash的密钥(secretkey)即c
} catch (PackageManager.NameNotFoundException e2) {
e2.printStackTrace();
}
}
}
```
以上代码说明,hmachash的密钥(secretkey)通过aes加密了apk的签名信息生成,这就解释了重新签名后网络请求非法。
我想到破解的思路就是直接将正确的`AES.a(c, encodeToString)`加密结果写死;比较通用的方法还有io重定向,签名验证的时候还是让app还是读原包,运行的时候运行修改后的包,这个方法比较高端我还没学会,所以就用前者。
关于正确值怎么来?可以安装未修改的app然后用frida hook `AES.a`这个函数,以下是`hook代码`(可以直接用jadx生成的)
```javascript
let AES = Java.use("com.douban.frodo.utils.crypto.AES");
AES["a"].overload('java.lang.String', 'java.lang.String').implementation = function (str, str2) {
console.log(`AES.a is called: str=${str}, str2=${str2}`);
let result = this["a"](str, str2);
console.log(`AES.a result=${result}`);
return result;
};
```
hook结果
``` starting script
AES.a is called: str=74CwfJd4+7LYgFhXi1cx0IQC35UQqYVFycCE+EVyw1E=, str2=MIICUjCCAbsCBEty1MMwDQYJKoZIhvcNAQEEBQAwcDELMAkGA1UEBhMCemgxEDAOBgNVBAgTB0Jl
aWppbmcxEDAOBgNVBAcTB0JlaWppbmcxEzARBgNVBAoTCkRvdWJhbiBJbmMxFDASBgNVBAsTC0Rv
dWJhbiBJbmMuMRIwEAYDVQQDEwlCZWFyIFR1bmcwHhcNMTAwMjEwMTU0NjExWhcNMzcwNjI3MTU0
NjExWjBwMQswCQYDVQQGEwJ6aDEQMA4GA1UECBMHQmVpamluZzEQMA4GA1UEBxMHQmVpamluZzET
MBEGA1UEChMKRG91YmFuIEluYzEUMBIGA1UECxMLRG91YmFuIEluYy4xEjAQBgNVBAMTCUJlYXIg
VHVuZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAg622fxLuwQtC8KLYp5gHk0OmfrFiIisz
kzPLBhKPZDHjYS1URhQpzf00T8qg2oEwJPPELjN2Q7YOoax8UINXLhMgFQkyAvMfjdEOSfoKH93p
v2d4n/IjQc/TaDKu6yb53DOq76HTUYLcfLKOXaGwGjAp3QqTqP9LnjJjGZCdSvMCAwEAATANBgkq
hkiG9w0BAQQFAAOBgQA3MovcB3Hv4bai7OYHU+gZcGQ/8sOLAXGD/roWPX3gm9tyERpGztveH35p
aI3BrUWg2Vir0DRjbR48b2HxQidQTVIH/HOJHV0jgYNDviD18/cBwKuLiBvdzc2Fte+zT0nnHXMy
E6tVeW3UdHC1UvzyB7Qcxiu4sBiEO1koToQTWw==
AES.a result=0dad551ec0f84ed02907ff5c42e8ec70
AES.a is called: str=bHUvfbiVZUmm2sQRKwiAcw==, str2=MIICUjCCAbsCBEty1MMwDQYJKoZIhvcNAQEEBQAwcDELMAkGA1UEBhMCemgxEDAOBgNVBAgTB0Jl
aWppbmcxEDAOBgNVBAcTB0JlaWppbmcxEzARBgNVBAoTCkRvdWJhbiBJbmMxFDASBgNVBAsTC0Rv
dWJhbiBJbmMuMRIwEAYDVQQDEwlCZWFyIFR1bmcwHhcNMTAwMjEwMTU0NjExWhcNMzcwNjI3MTU0
NjExWjBwMQswCQYDVQQGEwJ6aDEQMA4GA1UECBMHQmVpamluZzEQMA4GA1UEBxMHQmVpamluZzET
MBEGA1UEChMKRG91YmFuIEluYzEUMBIGA1UECxMLRG91YmFuIEluYy4xEjAQBgNVBAMTCUJlYXIg
VHVuZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAg622fxLuwQtC8KLYp5gHk0OmfrFiIisz
kzPLBhKPZDHjYS1URhQpzf00T8qg2oEwJPPELjN2Q7YOoax8UINXLhMgFQkyAvMfjdEOSfoKH93p
v2d4n/IjQc/TaDKu6yb53DOq76HTUYLcfLKOXaGwGjAp3QqTqP9LnjJjGZCdSvMCAwEAATANBgkq
hkiG9w0BAQQFAAOBgQA3MovcB3Hv4bai7OYHU+gZcGQ/8sOLAXGD/roWPX3gm9tyERpGztveH35p
aI3BrUWg2Vir0DRjbR48b2HxQidQTVIH/HOJHV0jgYNDviD18/cBwKuLiBvdzc2Fte+zT0nnHXMy
E6tVeW3UdHC1UvzyB7Qcxiu4sBiEO1koToQTWw==
AES.a result=bf7dddc7c9cfe6f7
```
因此只要对代码进行如下修改就行
```java
//修改前
b = AES.a(b, encodeToString);
c = AES.a(c, encodeToString);
//修改后
b = "0dad551ec0f84ed02907ff5c42e8ec70"
c = "bf7dddc7c9cfe6f7"
```
但是java代码是不能直接改的,需要改smali代码
保存后重新安装app,发现正常请求到数据,并且也没有开屏广告。
## 去除推荐页的广告
最终定位到`onADLoaded`,先用frida hook验证一下
```javascript
let GdtFetcher = Java.use("com.douban.frodo.baseproject.ad.GdtFetcher");
GdtFetcher["onADLoaded"].implementation = function (list) {
console.log(`GdtFetcher.onADLoaded is called: list=${list}`);
this["onADLoaded"](null);// 发现传入null后就没有推荐页的广告了,此处应该直接什么都不做也可以
};
```
同样的用np管理器搞坏这个方法就好了,我的话是直接在方法最前面return了,似乎这个方法也没有编译通过,不过应该这个获取广告的函数坏了,所以也就没有广告了。 在非static函数中,p0代指“this",p1表示函数的第一个参数
在你这个方法里的第一个参数是个字符串类型,你给他赋值个0,那编译器肯定要坏掉
感谢支持,对你们有所帮助便是对本教程最大的回馈{:301_997:} const-string p1,"" 天空宫阙 发表于 2023-10-16 09:35
所以底下有大佬提示的const-string p1,"",然后返回就好了是吧。感谢大佬回复,我smali还得学习。
也不对,你这样返回值就变字符串类型,他是自定义的一个类型
应该是
const v0,0x0
return v0 没看懂但是照做可以用,哈哈 最重要的就是定位签名信息生成_sig,这个过了就随便改了
用软件签名生成请求数据的参数,又学到了一点 去开屏广告那个只要用MT管理器清空你找的方法就行了,具体是点击指南针,找到对应的方法长按,从菜单中点清空方法,它就会变成直接return null了,很好用。
去签名从你的操作上看似乎用MT的普通版去签就能搞定,早期版本的原理是hook,现在改成了通过反射修改字符串,效率更高了 侃遍天下无二人 发表于 2023-10-14 15:51
去开屏广告那个只要用MT管理器清空你找的方法就行了,具体是点击指南针,找到对应的方法长按,从菜单中点清 ...
学到了,高级的工具让逆向变简单了 BonnieRan 发表于 2023-10-14 15:42
用软件签名生成请求数据的参数,又学到了一点
是的,这也算是一种防护 学习一下,恨不得把手机上的app挨个搞一遍。启动广告太烦人