仅分享逆向分析过程,关键代码都有,还有截图,就不发APP了
APP中有个实名认证功能,需要上传身份证正反和身份证信息
提交POST时,有个keystr参数,是用来校验其它参数信息的,分析目标就是它了
Fiddler抓到的包文,keystr参数看起来像是一个MD5
post.jpg (46.95 KB, 下载次数: 0)
下载附件
2020-3-22 21:45 上传
用的ApkToolAid,对APP进行查壳,反编译
查到结果,未加壳,反编译正常,但是分析代码和文件,发现它是 ReactNative+NodeJS 开发的APP
此种类型的APP大都是把整个项目编译成一个 index.android.bundle 文件,放置于安卓目录结构的 assets路径下
把index.android.bundle文件,后缀名改为js, index.android.js 用相关JS编辑工具打开该文件,进行分析(我用的code)
chake.jpg (31.06 KB, 下载次数: 0)
下载附件
2020-3-22 20:53 上传
apk1.jpg (20.72 KB, 下载次数: 0)
下载附件
2020-3-22 20:53 上传
apk2.jpg (9.48 KB, 下载次数: 0)
下载附件
2020-3-22 20:53 上传
用Code格式化JS代码,方便查看,直接在JS文件中搜索关键字,POST参数里的几个参数名,定位到相关函数 uploadPersonalInfo (有几个类似的搜索结果,经过对比参数,确定函数位置)
从代码上看keystr是通过参数 t 传递进来的,搜索 uploadPersonalInfo函数名,找到调用位置,发现参数时来自全局对象的 c.NativeModules.HeHe.getKey
再次在JS文件中搜索getKey函数,未找到,那就只有1个可能,该函数在android代码里
我们先确认好,getKey传递的几个参数内容
参数内容,pid, fPhone手机号, IDCard身份证号, Name姓名
getKey(this.props.member.pId, this.props.member.fPhone, this.props.IDCard, this.props.Name)
up.jpg (56.96 KB, 下载次数: 1)
下载附件
2020-3-22 20:58 上传
up1.jpg (21.87 KB, 下载次数: 0)
下载附件
2020-3-22 21:01 上传
用ApkToolAid再次生成app的jar包,方便我们使用 jd-gui 工具,查看JAVA明文代码 (反编译的文件是dex类型,需要再次转为jar查看)
在jar包里搜索全局对象里的关键字 HeHe或getKey 定位到目标函数,对比参数数量和类型,确认无误
跟进c.a(paramInteger, paramString1, paramString2, paramString3) 函数体内
可以看到加密方式就在眼前了.(图片和代码在下面)
对代码进行分析时卡在函数内的第一行 new a().a(paramString3),
我们知道参数 paramString3是姓名,这 new a().a 对姓名做了什么处理,这里卡了我比较久
因为反编译的代码并非完全正确,对逆向分析和代码测试都带来了不少困扰
经过代码修复和测试,最后在百度搜索,修复代码生成的 private int[] c = new int[27] 数组内的内容时,无意中发现别人的JAVA生成姓名的首字母代码案例,内容比较一致,就大胆认为,它就是获取姓名首字母
(后经算法生成结果对比,确认了确实是姓名首字母)
此图就是JAVA获取姓名首字母的算法用到的数组
jar3.jpg (18.5 KB, 下载次数: 0)
下载附件
2020-3-22 21:24 上传
通过对加密函数的分析,发现大量的字符串拼接和MD5调用.
详细分析结果,已经注释到了代码中,转至下方代码查看
易语言加密算法函数
(如易语言引起不适,多多包涵)
e.jpg (64.61 KB, 下载次数: 1)
下载附件
2020-3-22 22:15 上传
下图为加密函数
jar1.jpg (48.92 KB, 下载次数: 0)
下载附件
2020-3-22 21:10 上传
jar2.jpg (160.16 KB, 下载次数: 0)
下载附件
2020-3-22 21:10 上传
关键代码,加入了分析结果和注释
[Java] 纯文本查看 复制代码package com.GeneApp.invokenative;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class c
{
private static final String[] a = { "A", "c", "9", "G", "H", "5", "P", "v", "7", "m", "d" };//密码本a
private static final String[] b = { "l", "I", "1", "O", "o", "w", "u", "#", "n", "q", "E" };//密码本b
private static final String c = "pjjsdsb";
public static String a(Integer paramInteger, String paramString1, String paramString2, String paramString3)
{
//获取姓名的首字母
paramString3 = new a().a(paramString3);
//获取首字母的第一位,姓的字母
String str = paramString3.substring(0, 1);
//获取手机号的第3 6 8位的内容转为整数型,从上方的 b 数组中获取对应 3 6 8的成员,拼接为字符串,赋值给 localObject1
Object localObject1 = new StringBuilder();
((StringBuilder)localObject1).append(b[Integer.parseInt(paramString1.substring(2, 3))]);
((StringBuilder)localObject1).append(b[Integer.parseInt(paramString1.substring(5, 6))]);
((StringBuilder)localObject1).append(b[Integer.parseInt(paramString1.substring(7, 8))]);
localObject1 = ((StringBuilder)localObject1).toString();
//拼接字符串 _和参数pid+6的结果 赋值给 localObject2
//如果pid为 384187 拼接结果为 _384193
Object localObject2 = new StringBuilder();
((StringBuilder)localObject2).append("_");
((StringBuilder)localObject2).append(paramInteger.intValue() + 6);
paramInteger = "";
((StringBuilder)localObject2).append("");
localObject2 = ((StringBuilder)localObject2).toString();
//获取手机号中的第4 5 7的内容转为整数型,从上方的 a 数组中获取对应 4 5 7的成员,拼接为字符串,赋值给 paramString1
Object localObject3 = new StringBuilder();
((StringBuilder)localObject3).append(a[Integer.parseInt(paramString1.substring(3, 4))]);
((StringBuilder)localObject3).append(a[Integer.parseInt(paramString1.substring(4, 5))]);
((StringBuilder)localObject3).append(a[Integer.parseInt(paramString1.substring(6, 7))]);
paramString1 = ((StringBuilder)localObject3).toString();
//身份证的拼接
localObject3 = new StringBuilder();
//获取身份证号的,第4位开始的3个字符的内容 拼接
((StringBuilder)localObject3).append(paramString2.substring(3, 6));
//获取身份证号的,第13位开始的4个字符的内容 拼接
((StringBuilder)localObject3).append(paramString2.substring(12, 16));
//拼接一个#
((StringBuilder)localObject3).append("#");
//获取身份证号的,第10位开始的5个字符的内容 拼接
((StringBuilder)localObject3).append(paramString2.substring(9, 14));
//拼接结果案例 7841174#01011
//拼接结果,赋值给 localObject3
localObject3 = ((StringBuilder)localObject3).toString();
/
/把以上所有拼接结果再次拼接
//拼接结果案例 Z#IO_3841937cH7841174#01011ZBJ
paramString2 = new StringBuilder();
//拼接姓首字母
paramString2.append(str);
//拼接第1个结果
paramString2.append((String)localObject1);
//拼接第2个结果
paramString2.append((String)localObject2);
//拼接第3个结果
paramString2.append(paramString1);
//拼接第4个结果
paramString2.append((String)localObject3);
//拼接姓名首字母
paramString2.append(paramString3);
//拼接结果,赋值给 paramString1
paramString1 = paramString2.toString();
try
{
//最终拼接
paramString2 = new java/lang/StringBuilder;
paramString2.();
//把上面的拼接结果,生成MD5 拼接
paramString2.append(a(paramString1));
//拼接 pjjsdsb
paramString2.append("pjjsdsb");
//拼接案例 ff69dd766a0be2705c5dff6ddf71d96fpjjsdsb
//把最终拼接的结果,生成MD5返回
paramString1 = a(paramString2.toString());
paramInteger = paramString1;
}
catch (Exception paramString1)
{
for (;;) {}
}
return paramInteger;
}
//生成MD5函数
public static String a(String paramString)
throws Exception
{
try
{
paramString = MessageDigest.getInstance("MD5").digest(paramString.getBytes("UTF-8"));
StringBuilder localStringBuilder = new StringBuilder(paramString.length * 2);
int i = paramString.length;
for (int j = 0; j
获取姓名首字母的类
[Java] 纯文本查看 复制代码package com.GeneApp.invokenative;
import java.io.PrintStream;
public class a
{
private char[] a = { 21834, -32083, 25830, 25645, -30978, 21457, 22134, 21704, 21704, 20987, 21888, 22403, 22920, 25343, 21734, 21866, 26399, 28982, 25746, 22604, 22604, 22604, 25366, 26132, 21387, 21277, 24231 };
private char[] b = { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90 };
private int[] c = new int[27];
public a()
{
for (int i = 0; i this.c) {
bool2 = false;
}
return bool2;
}
if (paramInt2 = 'a') && (paramChar = 'A') && (paramChar = 26) {
return '0';
}
return this.b[j];
}
public String a(String paramString)
{
int i = paramString.length();
int j = 0;
str1 = "";
str2 = "";
for (;;)
{
if (j