本篇文章由团队大佬 pyth0n 总结编写
public static WebResourceResponse b(String str) {
WebResourceResponse webResourceResponse;
if (!ACEDes.isEncryptcj() || !str.startsWith("contents:///android_asset/")) { //如果不是加密过的文件或者是不是以contents:///android_asset/ 开头的文件就退出
return null;
}
try {
String substring = str.substring(26);
if (substring.contains("?")) {
substring = substring.substring(0, substring.lastIndexOf("?"));
}
InputStream open = ACEDes.getContext().getAssets().open(substring);
if (str.endsWith(".css") || str.endsWith(".js")) { //判断是不是js和css文件
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(DESUtility.a(DESUtility.a(open, open.available()), DESUtility.a(str)).getBytes()); //返回真正的资源文件
webResourceResponse = str.endsWith(".css") ? new WebResourceResponse("text/css", "UTF-8", byteArrayInputStream) : str.endsWith(".js") ? new WebResourceResponse("text/js", "UTF-8", byteArrayInputStream) : null;
} else {
webResourceResponse = new WebResourceResponse((String) null, "UTF-8", open);
}
return webResourceResponse;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public static WebResourceResponse b(String str) {
WebResourceResponse webResourceResponse;
if (!ACEDes.isEncryptcj() || !str.startsWith("contents:///android_asset/")) { //如果不是加密过的文件或者是不是以contents:///android_asset/ 开头的文件就退出
return null;
}
try {
String substring = str.substring(26);
if (substring.contains("?")) {
substring = substring.substring(0, substring.lastIndexOf("?"));
}
InputStream open = ACEDes.getContext().getAssets().open(substring);
if (str.endsWith(".css") || str.endsWith(".js")) { //判断是不是js和css文件
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(DESUtility.a(DESUtility.a(open, open.available()), DESUtility.a(str)).getBytes()); //返回真正的资源文件
webResourceResponse = str.endsWith(".css") ? new WebResourceResponse("text/css", "UTF-8", byteArrayInputStream) : str.endsWith(".js") ? new WebResourceResponse("text/js", "UTF-8", byteArrayInputStream) : null;
} else {
webResourceResponse = new WebResourceResponse((String) null, "UTF-8", open);
}
return webResourceResponse;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
if ("app包名".equals(lpparam.packageName)) {
Log.d("appcan", "load app " + lpparam.packageName);
XposedHelpers.findAndHookMethod("android.net.Uri$HierarchicalUri",lpparam.classLoader,"getPath",new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Log.d("Appcan--contentProvider", param.getResult().toString()); //获取 /android_asset/widget/js/swiper-3.4.1.min.js 文件路径
filename=param.getResult().toString(); //将文件路径 保存到filename里
}
});
Class clazz = lpparam.classLoader.loadClass("org.zywx.wbpalmstar.acedes.DESUtility");
XposedHelpers.findAndHookMethod(clazz, "a", byte[].class, String.class, new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
//Log.d("Appcan--result--xposed", String.valueOf(param.getResult()));
saveFile(param.getResult().toString(),filename); // hook org.zywx.wbpalmstar.acedes.DESUtility.a方法 返回值 为解密后的源码
}
});
}
}
public static void saveFile(String content, String fileName) { //保存文件的函数
String basePath = Environment.getExternalStorageDirectory().getPath() + "/appcan_dump";
String filePath = basePath + fileName;
Log.i("appcan-dump", "appcan.saveFile -> " + filePath);
try {
File file = new File(filePath);
File parentFile = file.getParentFile();
if (parentFile.isFile()) {
parentFile.delete();
}
parentFile.mkdirs();
file.createNewFile();
IOUtils.write(content,(OutputStream) new FileOutputStream(file),"utf-8");
} catch (IOException e) {
e.printStackTrace();
}
}
扫二维码
关注我们
本文始发于微信公众号(WhITECat安全团队):移动安全-APP渗透进阶之AppCan本地文件解密
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论