上一篇利用xposed逆向某4k视频付费服务"")主要讲了一些破解的准备工作,这一篇将会进入重点,分为两个部分,一个是xposed的开发准备,一个是结合代码进行hook
<!--more---->
Xposed的开发
我们可以再这里下载到最新的xposed.jar 文件,网上有教程是下载jar包放到工程的lib文件夹下,我们不这么做,用gradle方式进行引用
开发环境
Mac
Android Studio 3.4.2
夜神模拟器Mac版 安卓版本4.4
xposed框架2.7版本(只有这个版本支持安卓4.4)
引入jar包
在app目录下的build.gradle 的dependencies中添加如下代码
compileOnly 'de.robv.android.xposed:api:82'
需要注意的是,由于2.7版本的xposed框架自带了xposed.jar,所以我们这里只需要compileOnly即可,否则会报错,官方文档是
compile 'de.robv.android.xposed:api:82'
这个要根据自己实际情况来酌情处理,关于 compileOnly 和compile 区别,可以查看
gradle 新的依赖方式 implementation、api、compileOnly
成为xposed模块
在mainfest文件的application标签下添加如下代码
<application
android:name=".base.BaseApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<meta-data
android:name="xposedmodule"
android:value="true"/>
<meta-data
android:name="xposeddescription"
android:value="模块描述文字"/>//会在模块里显示你的xposed具体描述
<meta-data
android:name="xposedminversion"
android:value="53"/>//由于2.7版本的xposed不支持82版本所以这里写53,支持的最低版本是53
</application>
这样,再gradle sync一下,我们的准备工作就完毕了。
进入其他应用的进程
在这里,将会进入我们的实际开发工作。上篇我们了解到,我们第一步需要hook掉用户的登录操作。
创建一个类FourK_Xposed,继承IXposedHookLoadPackage类,覆写handleLoadPackage方法,xposed的该方法在任何应用启动时都会被调用,故可以进入任何应用程序的进程,但是一般只针对某个特定的应用,例如,当前应用
public class FourK_Xposed implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("FourK_Xposed 模块生效");//进入这段代码说明我们的xposed模块生效了
//先判断是不是我们想要hook的应用,以包名判断,不是的话直接return
if (!TextUtils.equals(lpparam.packageName,"com.evo.watchbar.tv")){
return;
}
//hook 登录
XposedHelpers.findAndHookMethod(lpparam.classLoader.loadClass("com.evo.watchbar.tv.ui.activity.VRMovieDetailActivity"), "checkLogin", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
param.setResult(true);
}
});
在handleLoadPackage方法中,调用findAndHookMethod方法,并重写afterHookedMethod方法,由于检查登录的逻辑很简单,就在VRMovieDetailActivity中,所以我们只需要传入要hook的类以及方法名即可。
看一眼源码,
private boolean checkLogin()
{
boolean bool = true;
if (MyStorage.user == null)
{
errorAlert("请先登录", true);
new Handler().postDelayed(new Runnable()
{
public void run()
{
Intent localIntent = new Intent(VRMovieDetailActivity.this, PersonCenterActivity.class);
localIntent.putExtra("forResult", true);
localIntent.putExtra("type", 1);
VRMovieDetailActivity.this.startActivityForResult(localIntent, 100);
}
}, 500L);
}
for (;;)
{
return bool;
bool = false;
}
}
源码的逻辑看起来会很奇怪,不如直接smali看起来容易理解 因为有一段这样的代码
for (;;)
{
return bool;
bool = false;
}
这个不用管,通过smali代码可以猜到,如果是vip,那么这个返回值一定是false,(很奇怪是吧,逻辑就是这样的)
所以复写
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
param.setResult(false);
}
param.setResult(false);即可
通常情况下这样就可以了,打包模块,将模块推送到手机安装,这时候xposed模块会提示你重启,选择软重启即可。
然后进入日志选项,看看我们的应用生效没
可以看到xposed模块已经生效,但是hook生效了吗?进入应用验证,发现还是要登录,截图就不发了,
打开xposed日志我们发现这样的报错
没有找到com.evo.watchbar.tv.ui.activity.VRMovieDetailActivity这个类,事实上这个类是真实存在的,不是找不到,而是被腾讯加固给“隐藏”了
解决腾讯加固导致的classNotFound问题
通常情况下,如果代码没有进行加固,我们只需要按照上面的步骤解决即可,但是这个应用腾讯加固了,直接这么走就行不通了,原因在于apk经过加固,必须要用壳的ClassLoader来加载类,因为真正的代码是腾讯加固程序启动后它去加载真正的dex文件的。
所以第一步我们要hook TxAppEntry 的 attachBaseContext 方法
public static void hookClassLoader(final XC_LoadPackage.LoadPackageParam loadPackageParam){
if (classLoader == null){
try {
//腾讯加固,需要获取对应classloader
XposedHelpers.findAndHookMethod("com.tencent.StubShell.TxAppEntry", loadPackageParam.classLoader,
"attachBaseContext", Context.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
//获取到Context对象,通过这个对象来获取classloader
Context context = (Context) param.args[0];
//获取classloader,之后hook加固后的就使用这个classloader
context.getClassLoader();//这个classLoader才是真正需要的classLoader
}
});
}catch (Exception e){
}
}
}
并修改代码如下
public class FourK_Xposed implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("FourK_Xposed 模块生效");
//先判断是不是我们想要hook的应用,以包名判断
if (!TextUtils.equals(lpparam.packageName,"com.evo.watchbar.tv")){
return;
}
//腾讯加固,需要获取对应classloader
XposedHelpers.findAndHookMethod("com.tencent.StubShell.TxAppEntry", lpparam.classLoader,
"attachBaseContext", Context.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
//获取到Context对象,通过这个对象来获取classloader
Context context = (Context) param.args[0];
//获取classloader,之后hook加固后的就使用这个classloader
context.getClassLoader();
hookLogin(context.getClassLoader());
}
});
}
private static void hookLogin(ClassLoader classLoader){
//hook 登录
try {
XposedHelpers.findAndHookMethod(classLoader.loadClass("com.evo.watchbar.tv.ui.activity.VRMovieDetailActivity"), "checkLogin", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
param.setResult(true);
XposedBridge.log("hook成功");
}
});
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
打包验证
图就不上传了,太大了,超过1M限制
可以看到会员免费看一闪而过,至于为什么后面又出现让你登录的界面,是因为在播放界面他又验证有没有登录了,破解方法一致,这里就不再演示了,如果你想一劳永逸,可以从
MyStorage.user == null
这段代码入手,
hook方式就是常用的反射,代码如下:
cls = classLoader.loadClass("com.evo.watchbar.tv.storage.MyStorage");
Field field = cls.getField("user");
Class User = classLoader.loadClass("com.evo.m_base.bean.User");
field.set(cls.newInstance(),User.newInstance());
只要保证user!=null 即可
这样,就不会再提示登录了。
破解VIP
有了上文的铺垫,Vip的破解也就很容易了,在源码中我们多次看到这个方法
UserUtils.checkVIP()
所以从这段代码入手就行了,代码如下
private void hookVip(ClassLoader classLoader) {
try {
XposedHelpers.findAndHookMethod(classLoader.loadClass("com.evo.watchbar.tv.utils.UserUtils"), "checkVIP", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
param.setResult(true);
}
});
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
编写完毕后你就会神奇的发现,付费按钮消失了,只有一个播放按钮,点击播放按钮看一下效果
WTF,竟然显示会员才能享受服务,难道有服务端验证??
如果真的有服务端验证,那我们真的将前功尽弃。所以,我们现在必须得抓包看看
抓包破解vip
抓包的方法这里就不多说了,fiddler或者Charles都可以,我这里用的Charles
在抓包界面中我们看到
有一个sourceUrl字段,这个字段以.mp4结尾,很大概率是视频链接,把这个链接放到浏览器访问一下,发现居然播放了,所以,只要有了播放链接,那我们本地破解100%没问题,但是为什么还是提示 会员才能享受服务呢?
搜一下这段文案
在VRPlayerActivity和TwoDPlayerActivity中搜到了这段文案
binggo!!!,查看一下它的判断逻辑是 localData.getRetCode!=0 所以呢?我们的破解逻辑就有了
就是将getRectCode返回0不就行了
这段代码就不写啦,相信聪明的你已经领悟了,我就不放出来了,以防和谐,我还要偷偷摸摸用呢
最后,放一下实际效果吧
低调。。。。