APP网络请求参数校验,逆向分析分享

查看 98|回复 10
作者:wxyzyou   
分享一个APP post参数验签校验案例
仅分享逆向分析过程,关键代码都有,还有截图,就不发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

下载次数, 代码

wxyzyou
OP
  


非凡公子 发表于 2020-3-24 11:29
楼主可否分享一下你那个安卓查壳软件

52的爱盘里,安卓工具
看,六眼飞鱼   

这波操作太6了,学习到了
52Douyin   

厉害,分析的冷静而又准确。
sddson   

谢谢分享
bjxiaoyao   

学习了分析很专业
Parkourr   

这么强的吗?感谢分享
东方学痞   

来学习学习
liangdaofeng   

感谢分享
tvrcfdfe   

这个厉害了  666666感谢
您需要登录后才可以回帖 登录 | 立即注册