闲鱼猪手定制与解密
如何定制
- fork 本仓库
- 下载 1.3.9_sub.apk
- 使用任意反编译工具打开,例如 MT管理器
- 编辑 classes.dex,全局搜索
REPLACE_ME_TO_YOUR_REPO
- 将
REPLACE_ME_TO_YOUR_REPO
部分替换为你的仓库地址jsDelivr 地址 - 回编译并签名
闲鱼猪手配置文件解密
因为太闲,突然想起这个上古大坑了
众所周知,有个很好用的 Xposed 模块叫闲鱼猪手,可惜不知道什么原因,作者已经跑路了,好在原作者是把配置文件放在 Gitee 上的,通过 Commit 记录抢救回了作者的最后一次更新。
作者的加密比较狠,不仅配置文件是加密的,连 APK 本身都经过混淆,加密的配置文件长这样
因为后缀是 Json,所以猜测 APP 内部获取完在线配置文件后会解密,然后按照 JSON 格式来解析。那么就开始反编译 APK 吧
Jadx 的反混淆是一如既往的弱鸡,啥也看不出来
但是之前替换配置文件 URL 的时候已经找到了定义 URL 的地方,这也是一个突破口,因为解密部分总在获取 URL 内容之后
这里继续用一个反混淆比较强的工具: Jeb 来继续反编译。虽然还是有很多鬼画符,但是 Jeb 至少可以反编译出人话了
鬼画符自然是看不懂的,也不需要看懂,我们只需要知道大致的逻辑就行了
在一个 IF 语句下面发现了 “解密失败” 的提示,那么解密部分肯定在这块 IF 之上咯,上面果然发现了处理解密的部分
把这块单独拎出来看看
label_235:
String v1_5 = s9.ۥ۠ۦ(v1_4); // GET 请求获取配置文件
if(TextUtils.isEmpty(v1_5)) {
goto label_369; // 跳获取配置失败
}
new String("content");
char[] v4_1 = v1_5.toCharArray();
dq.ۥۣ۟(v4_1, "this as java.lang.String).toCharArray()");
StringBuilder v5 = new StringBuilder();
// 解密部分
int v6 = v4_1.length;
int v7 = 0;
while(v7 < v6) {
char v12_1 = v4_1[v7];
++v7;
v5.append(((char)(v12_1 - 12))); // 12
}
解密部分还是很简单的,就是单纯把每个字符减了 12。用 Python 或者 Java 重写这部分,就是
# Python
encFile = open("C:\\Users\\Ayabe\\Downloads\\debug\\a7.8.50.json", "rb")
decFile = "C:\\Users\\Ayabe\\Downloads\\debug\\a7.8.50_decrypt.json"
data = encFile.read()
encFile.close()
str = data.decode(encoding='utf-8')
charArray = list(str)
v5 = ""
v6 = len(charArray)
v7 = 0
while v7 < v6:
v12_1 = charArray[v7]
v7 += 1
v5 += chr(ord(v12_1) - 12)
with open(decFile, 'w') as f:
f.write(v5)
// Java
public class main {
public static void main(String[] args) throws IOException {
File encFile = new File("C:\\Users\\Ayabe\\Downloads\\debug\\a7.8.50.json");
FileInputStream fileInputStream = new FileInputStream(encFile);
byte[] data = new byte[(int) encFile.length()];
fileInputStream.read(data);
fileInputStream.close();
String str = new String(data, StandardCharsets.UTF_8);
char[] charArray = str.toCharArray();
StringBuilder v5 = new StringBuilder();
int v6 = charArray.length;
int v7 = 0;
while(v7 < v6) {
char v12_1 = charArray[v7];
++v7;
v5.append(((char)(v12_1 - 12)));
}
System.out.println(v5);
}
}
这样我们就可以得到解密的 Json 配置文件了
{
"BottomPanelCls": "com.taobao.idlefish.fun.view.panel.BottomPanel",
"mBottomPanelClsInitList": "b",
"mBottomPanelClsClick": "a",
"BaseCellCls": "com.tmall.wireless.tangram3.structure.BaseCell",
"vBaseCellClsJsonObj": "n",
"VideoUGCFeedPlayPluginCls": "com.taobao.homeai.dovecontainer.VideoUGCFeedPlayPlugin",
"mVideoUGCFeedPlayPluginClsShowVideo": "a",
"FullVideoViewCls": "com.taobao.homeai.view.video.FullVideoView",
"ImmersiveComponentViewHolderCls": "com.taobao.homeai.dovecontainer.immersive.ImmersiveComponent$ViewHolder",
"SaveImageUtilsCls": "com.taobao.fleamarket.user.util.SaveImageUtils",
"mSaveImageUtilsClsSameBitmap": "a",
"DxHomeTitleBarCls": "com.taobao.fleamarket.home.dx.home.recommend.ui.HomeTitleBar",
"PowerHomeTitleBarCls": "com.taobao.idlefish.home.power.home.HomeTitleBar",
"mHomeTitleBarClsAddBarRight": "addBarRight",
"SplashAdRequestHelperCls1": "com.alimm.xadsdk.business.splashad.SplashAdRequestHelper$1",
"mSplashAdRequestHelperCls1OnSuccess": "onSuccess",
"TBSwipeRefreshLayoutCls": "com.taobao.idlefish.home.power.ui.TBSwipeRefreshLayout",
"MainActivityCls": "com.taobao.idlefish.maincontainer.activity.MainActivity",
"TBSoundPlayerCls": "com.taobao.tao.util.TBSoundPlayer",
"mTBSoundPlayerClsPlayScene": "a",
"MtopContextCls": "mtopsdk.framework.domain.MtopContext",
"mMtopContextClsMtopResponse": "c",
"FishFlutterBoostActivityCls": "com.idlefish.flutterbridge.flutterboost.boost.FishFlutterBoostActivity",
"vFlutterView": "c",
"vBottomPanelClsMenuItems": "a",
"CardSign": false,
"RP": false
}