一、起因:
最近在考驾照,钱是去年年初的时候交的。科目一到前段时间才开始,又碰上疫情。所以耐着性子看了三四遍驾考宝典。1350个题目用两个不同的驾考app各刷了一遍。总担心考不过科目一。尤其是刷了第一遍题目后总感觉还有些内容总结不够。看这个app会员功能有总结,当时还发了个朋友圈要买个会员,问别人有没有会员可以借来使使的(当然,经过大家一致的吐糟,最后迎着苦涩又刷了一遍题目)。所以,过程有点曲折,但是起因就是对这个app的vip功能情有独钟。
二、契机:
最近在看Xposed的事情,如果你看过之前的文章,你会知道我为啥看这个框架。总之是折腾之后有点失落。最后决定对这个享誉盛名的app表达一下尊重。我们严肃的表示,我们在探索技术。
三、准备工作:
从他的官网下载了app。保存在桌面。安装了MuMu模拟器。用模拟器安装这个app。
备注:为什么用MuMu模拟器原因有两个:
1、模拟器开发者模式和root都已经做了。Xposed框架基础条件都有
2、在调试功能的时候要经常重启。如果用真机我担心对我的“三老婆”有损。(二老婆是车(暂时没有)三老婆是手机(宝贝着咧))
按照上一个文章所示,搭建好android studio 环境,过程请看:
Android Studio 在MuMu模拟器上实现 xposed简单劫持
工程结构如图:
MainActivity.java代码如下:
package com.cf.exposedpractice;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn=(Button)findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showCenterContent();
}
});
}
public void showCenterContent()
{
TextView centerText=(TextView)findViewById(R.id.centerTextView);
centerText.setText(GetContent());
}
public String GetContent()
{
return "Xposed test";
}
}
XposedTools.java代码如下:
package com.cf.exposedpractice;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class XposedTools implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("Loaded app: " + lpparam.packageName);
if(lpparam.packageName.equals("com.cf.exposedpractice"))
{
XposedHelpers.findAndHookMethod("com.cf.exposedpractice.MainActivity", lpparam.classLoader, "GetContent", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("GetContent afterHookedMethod");
param.setResult("hooked the function of GetContent");
}
});
}
if(lpparam.packageName.equals("com.handsgo.jiakao.android"))
{
XposedHelpers.findAndHookMethod("cn.mucang.android.comment.api.data.UserSimpleJsonData", lpparam.classLoader, "isJiakaoVip", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("afterHookedMethod");
Object result=param.getResult();
boolean v=(boolean)result;
XposedBridge.log("afterHookedMethod isJiakaoVip ori v:"+v);
param.setResult(true);
//打印堆栈查看调用关系
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆栈:" + wodelogs[i].toString());
}
//获取类
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的类:" + clazz.getName());
}
});
XposedHelpers.findAndHookMethod("cn.mucang.android.comment.api.data.UserSimpleJsonData", lpparam.classLoader, "isAdmin", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object result=param.getResult();
boolean v=(boolean)result;
XposedBridge.log("afterHookedMethod isAdmin ori v:"+v);
param.setResult(true);
}
});
XposedHelpers.findAndHookMethod("cn.mucang.android.account.data.AuthUser", lpparam.classLoader, "getExpiredTime", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object result=param.getResult();
Long v=(Long)result;
v+=999999999;
XposedBridge.log("afterHookedMethod isAdmin ori v:"+v);
param.setResult(v);
//打印堆栈查看调用关系
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆栈:" + wodelogs[i].toString());
}
//获取类
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的类:" + clazz.getName());
}
});
XposedHelpers.findAndHookMethod("cn.mucang.android.account.data.AuthUser", lpparam.classLoader, "getNickname", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object result=param.getResult();
String v=(String)result;
XposedBridge.log("afterHookedMethod isAdmin ori v:"+v);
param.setResult("Xposed "+v);
//打印堆栈查看调用关系
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆栈:" + wodelogs[i].toString());
}
//获取类
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的类:" + clazz.getName());
}
});
XposedHelpers.findAndHookMethod("com.handsgo.jiakao.android.main.manager", lpparam.classLoader, "getPracticeVideoCount", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object result=param.getResult();
int v=(int)result;
XposedBridge.log("afterHookedMethod getPracticeVideoCount ori v:"+v);
param.setResult(v+888);
//打印堆栈查看调用关系
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆栈:" + wodelogs[i].toString());
}
//获取类
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的类:" + clazz.getName());
}
});
XposedHelpers.findAndHookMethod("com.handsgo.jiakao.android.main.manager", lpparam.classLoader, "LMa", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object result=param.getResult();
int v=(int)result;
XposedBridge.log("afterHookedMethod LMa ori v:"+v);
param.setResult(v+9999);
//打印堆栈查看调用关系
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆栈:" + wodelogs[i].toString());
}
//获取类
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的类:" + clazz.getName());
}
});
}
}
}
看过上面的文章你一定能发现,我这里做了个简单的按钮,点击按钮显示想要的内容。这里这一步是为了测试整个框架有没有生效。因为就我的发现是,在某些不确定的情况下,框架有可能不成功。所以需要价格按钮来确定如果框架成功了,点击按钮显示的就是:hooked the function of GetContent
否则显示的应该是Xposed test。如图:
另外,因为我使用的输出日志的方法是:XposedBridge.log,所以在Xposed Installler中能看到对应的日志。
四、关于app:
像这种app不可能不代码混淆。所以这个是一个蛋疼的点。我尝试用jadx这个工具反编译这个app。如图:
反编译的方法很简单,就是直接用工具打开桌面上apk就行。不过我感觉这个东西耗内存。反编译过程内存按照G来算的。
反编译等他执行完了之后执行如图所示反代码混淆:
事实上只稍微好那么一丢丢。但是比起CSDN或者百度搜索反编译反混淆都是千篇一律的那种要好一些吧。至少看到了不一样的声音。
工具我已经整体打包上传CSDN了,有需要的下载
五、想做什么?
我想看看他的vip功能是怎么做的!
所以,我在jadx上搜索vip。搜索结果显示如下:
我发现,在包名为:package cn.mucang.android.comment.api.data,类名是:UserSimpleJsonData的java类中,定义了一个名为:jiakaoVip的变量,如图:
打开这个类,能看到有一些get/set方法。
进一步,我搜索这个方法有哪些地方赋值了,在jadx中直接右键点击方法名,选择查找用例,如图:
只有一个地方用到了,如图:
额。。。。。感觉跟设想的不一样。用户信息中的vip属性不应该是很多地方都用的吗,看这个类的名称:CommentTitleModel,这丫丫的不是啥标题啥的?
我感觉我的思路除了点问题。
回顾一波:
首先是我想通过Xposed框架修改vip属性。所以我通过jadx搜索vip字段。但时并没有如我预想的那样。
然后我在Android Studio 的Xposedtools中对代码进行修改,发现并没有什么用。代码如图:
if(lpparam.packageName.equals("com.handsgo.jiakao.android"))
{
XposedHelpers.findAndHookMethod("cn.mucang.android.comment.api.data.UserSimpleJsonData", lpparam.classLoader, "isJiakaoVip", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("afterHookedMethod");
Object result=param.getResult();
boolean v=(boolean)result;
XposedBridge.log("afterHookedMethod isJiakaoVip ori v:"+v);
param.setResult(true);
//打印堆栈查看调用关系
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆栈:" + wodelogs[i].toString());
}
//获取类
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的类:" + clazz.getName());
}
});
}
这个地方我对包名做了限制,只有是包名为:com.handsgo.jiakao.android的应用才起作用。包名是通过jadx中的AndroidManifest.xml看到的,如图:
顺便贴一下他的签名信息:
额…矫情了。
言归正传。
既然找不到vip相关的信息,我试着找userinfo信息等关键字。如图:
上面红框里面那些android.support我就不看了,我看到下面有个包名下面有个AccountManager的类。我感觉这个应该就是用户信息了。
如图:
这个地方不是一个账号管理Manager嘛,为毛还有Activity,这是哪个程序员写的?拖出去枪毙。
管理功能里面怎么能放Activity咧。你不得通过通知之类的方法去使用啊。搞不懂。因为是反编译还带混淆功能。一时半会看不懂他的逻辑。但是我找到了一个AuthUser的类。点开看看:
额,看样子这就是个人信息了。但是奇怪的是,这个类中依旧没有vip相关的信息。我得思考。我有点彷徨,我有点犹豫,我有点像撞墙,我有点想去拉大便。。。。。。。
暂停十分钟。。。。。
好了,舒畅。。。。
不管他,先试试这个nickname。代码如下:
XposedHelpers.findAndHookMethod("cn.mucang.android.account.data.AuthUser", lpparam.classLoader, "getNickname", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object result=param.getResult();
String v=(String)result;
XposedBridge.log("afterHookedMethod isAdmin ori v:"+v);
param.setResult("Xposed "+v);
//打印堆栈查看调用关系
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆栈:" + wodelogs[i].toString());
}
//获取类
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的类:" + clazz.getName());
}
});
这个代码也就是说,如果有地方需要用名称的时候强项在前面加个Xposed 。试试。编译到MuMu模拟器,将ExposedPractice 添加到Xposed Installler模块中,重启模拟器。运行这个app.如图:
呵呵,这个功能算是成功了。
但我并不能满足于此,vip还是没有搞定。于是,我继续通过jadx查。
我看视频如果是新用户只能播放3个,我是不是可以修改这个数量,也不知道他们是不是再前端限制的播放次数。反正试试呗。如图:
这里显示一段文字:可免费观看3个视频,那我搜索“可免费观看”如图:
点进去,看具体代码:
嗯,这个LMa的变量应该是用了混淆的结果吧。反正从这个代码中看,是这个变量显示的数量。其中有个类叫:PracticeVideoManager,貌似是个管理类。如图:
对应的方法在:
看这个方法,同时发现了另外一个class,如图:
这里大概就是所谓3次的由来了。试着用代码Hook
XposedHelpers.findAndHookMethod("com.handsgo.jiakao.android.main.manager.VideoCountModel", lpparam.classLoader, "getPracticeVideoCount", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object result=param.getResult();
int v=(int)result;
XposedBridge.log("afterHookedMethod getPracticeVideoCount ori v:"+v);
param.setResult(v+888);
//打印堆栈查看调用关系
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆栈:" + wodelogs[i].toString());
}
//获取类
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的类:" + clazz.getName());
}
});
XposedHelpers.findAndHookMethod("com.handsgo.jiakao.android.main.manager.PracticeVideoManager", lpparam.classLoader, "LMa", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object result=param.getResult();
int v=(int)result;
XposedBridge.log("afterHookedMethod LMa ori v:"+v);
param.setResult(v+9999);
//打印堆栈查看调用关系
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆栈:" + wodelogs[i].toString());
}
//获取类
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的类:" + clazz.getName());
}
});
重新编译,重启MuMu,运行查看。
…
报错了:
额。没有找到这个东东。
啥原因????
额。。。。。。。。。。。我得研究一下。。。。
由于篇幅问题,暂时就到这里吧。主要原因是我还得研究研究。我都是一边研究一边写文章的。所以过程很重要。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
另外:谁有更好的反混淆工具推荐的。请一定留言告知。不胜感激。
好了,再拉屎去…
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/34085.html