基于sha1算法的登陆协议分析

1、整体分析

登陆抓包分析如下:
其中密码为:123456
这里写图片描述

这里写图片描述

可以看到对密码进行了加密,最后添加了封包签名加密

2、加密算法java层分析

定位到java关键代码如下:

public void loginCellFromRemote(final String paramString1, final String paramString2, String paramString3, final IUserManager.LogInCallback paramLogInCallback)
    throws WrongUserDataException
  {
    if (paramLogInCallback == null) {
      throw new NullPointerException("callback is null!");
    }
    Log.e("dss", "params = ");
    String str1 = this.deviceUserInfo.getDeviceId();
    String str2 = Md5Util.stringMd5(paramString2);
    RequestParams localRequestParams = new RequestParams();
    localRequestParams.add("code", paramString3);
    localRequestParams.add("device_id", str1);
    localRequestParams.add("mobile", paramString1);
    localRequestParams.add("pawd", str2);
    paramString3 = YoyoJieUtils.getTimeStamp();
    localRequestParams.add("timestamp", paramString3);
    ArrayList localArrayList = new ArrayList();
    localArrayList.add(new CmsTopUtils.UrlParameterBean("device_id", str1));
    localArrayList.add(new CmsTopUtils.UrlParameterBean("mobile", paramString1));
    localArrayList.add(new CmsTopUtils.UrlParameterBean("pawd", str2));
    localArrayList.add(new CmsTopUtils.UrlParameterBean("timestamp", paramString3));
    localRequestParams.add("sign", YoyoJieUtils.getSign(localArrayList, "oJf9prlOH3pmT5C87R2o82PLz#@uf^"));
    Log.e("dss", "params = " + localRequestParams);

..............

}

可以看到密码加密算法为:

Md5Util.stringMd5

sign签名加密算法为:

YoyoJieUtils.getSign(localArrayList, "oJf9prlOH3pmT5C87R2o82PLz#@uf^"));

其中,密码就是简单的MD5加密,如下:

public static String stringMd5(String paramString)
  {
    try
    {
      MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
      localMessageDigest.update(paramString.getBytes());
      paramString = HexUtil.byteToHexString(localMessageDigest.digest()).toLowerCase();
      return paramString;
    }
    catch (NoSuchAlgorithmException paramString)
    {
      paramString.printStackTrace();
    }
    return null;
  }

而sign签名算法为:

public static String getSign(List<CmsTopUtils.UrlParameterBean> paramList, String paramString)
  {
    Log.i("ASD", "加密了");
    return KeyGenerator.generateKeyByParams(getSignString(paramList));
  }
public static native String generateKeyByParams(String paramString)
    throws IllegalArgumentException;

下面分析native层的generateKeyByParams函数

3、加密算法native层分析

整理后的代码为:

int __fastcall generateKeyByParams(JNIEnv_ *a1, jclass clazz, jstring input)
{
  int v3; // r3@2
  _JNIEnv *env; // [sp+Ch] [bp-48h]@1
  char v6[4]; // [sp+14h] [bp-40h]@1
  int v7; // [sp+18h] [bp-3Ch]@1
  int v8; // [sp+1Ch] [bp-38h]@1
  int v9; // [sp+20h] [bp-34h]@1
  int v10; // [sp+24h] [bp-30h]@1
  int v11; // [sp+28h] [bp-2Ch]@1
  int v12; // [sp+2Ch] [bp-28h]@1
  int v13; // [sp+30h] [bp-24h]@1
  int v14; // [sp+34h] [bp-20h]@1
  int v15; // [sp+38h] [bp-1Ch]@1
  char v16; // [sp+3Ch] [bp-18h]@1
  jboolean isCopy; // [sp+3Fh] [bp-15h]@1
  int v18; // [sp+40h] [bp-14h]@3
  int v19; // [sp+44h] [bp-10h]@2
  unsigned __int8 v20; // [sp+4Bh] [bp-9h]@1
  int v21; // [sp+4Ch] [bp-8h]@1

  env = (_JNIEnv *)a1;
  isCopy = 0;
  v21 = _JNIEnv::GetStringUTFChars(&a1->functions, input, &isCopy);
  *(_DWORD *)v6 = 0;
  v7 = 0;
  v8 = 0;
  v9 = 0;
  v10 = 0;
  v11 = 0;
  v12 = 0;
  v13 = 0;
  v14 = 0;
  v15 = 0;
  v16 = 0;
  v20 = generate_key_by_value(v21, (int)v6);
  if ( v20 ^ 1 )
  {
    v19 = _JNIEnv::FindClass(env, "java/lang/IllegalArgumentException");
    _JNIEnv::ThrowNew(env, v19, "thrown from C code");
    v3 = 0;
  }
  else
  {
    v18 = _JNIEnv::NewStringUTF(env, v6);
    v3 = v18;
  }
  return v3;
}

该函数的流程为:
1、将输入的字符串转换成char*字符串。
2、generate_key_by_value函数对字符串加密。

signed int __fastcall generate_key_by_value(char *input, int a2)
{
  char *inputStr; // ST04_4@1
  signed int v3; // r4@3
  unsigned int v4; // r0@5
  std::string *v5; // r0@7
  int v6; // r4@7
  std::string *v7; // r0@7
  int v8; // r0@7
  int v9; // r0@7
  int v10; // r4@7
  int v11; // r0@7
  int v12; // r0@7
  int v14; // [sp+0h] [bp-F4h]@1
  char v15; // [sp+8h] [bp-ECh]@6
  int j; // [sp+64h] [bp-90h]@6
  char v17; // [sp+68h] [bp-8Ch]@9
  char *v18; // [sp+7Ch] [bp-78h]@1
  char v19; // [sp+88h] [bp-6Ch]@1
  char v20; // [sp+8Ch] [bp-68h]@1
  char v21; // [sp+A4h] [bp-50h]@1
  char v22; // [sp+A8h] [bp-4Ch]@1
  char v23; // [sp+ACh] [bp-48h]@1
  char v24; // [sp+B0h] [bp-44h]@1
  char v25; // [sp+B4h] [bp-40h]@4
  char v26; // [sp+BCh] [bp-38h]@4
  char v27; // [sp+C4h] [bp-30h]@4
  char v28; // [sp+CCh] [bp-28h]@4
  char v29; // [sp+D0h] [bp-24h]@4
  int v30; // [sp+D4h] [bp-20h]@8
  int v31; // [sp+D8h] [bp-1Ch]@2
  std::string *v32; // [sp+DCh] [bp-18h]@2
  int k; // [sp+E0h] [bp-14h]@9
  unsigned int i; // [sp+E4h] [bp-10h]@1
  char v35[12]; // [sp+E8h] [bp-Ch]@10

  inputStr = input;
  v14 = a2;
  std::map<std::string,std::string,order_by_inc,std::allocator<std::pair<std::string const,std::string>>>::map(&v20);
  std::allocator<char>::allocator(&v21);
  // 输入字符串
  std::string::string(&v19, inputStr, (int)&v21);
  std::allocator<char>::~allocator(&v21);
  std::string::string((std::string *)&v22, (const std::string *)&v19);
  std::allocator<char>::allocator(&v24);
  std::string::string(&v23, (const char *)&unk_68F84, (int)&v24);// 分隔符&
  split((int)&v18, (std::string *)&v22, (std::string *)&v23);// 利用分割符&,对输入的字符串进行分割
  std::string::~string((std::string *)&v23);
  std::allocator<char>::~allocator(&v24);
  std::string::~string((std::string *)&v22);
  for ( i = 0; ; ++i )
  {
    v4 = std::vector<std::string,std::allocator<std::string>>::size(&v18);// 分割后数组的长度
    if ( v4 <= i )                              // 判断是否超过了数组长度
      break;
    v32 = (std::string *)std::vector<std::string,std::allocator<std::string>>::operator[](&v18, i);// 获取每一项
    v31 = std::string::find(v32, (const char *)&unk_68F88, 0);// 查找 =
    if ( v31 == -1 )
    {
      v3 = 0;
      goto LABEL_13;
    }
    std::string::substr(&v28, v32, 0, v31);     // =前面的字符串
    std::string::substr(&v29, v32, v31 + 1, -1);// =后面的字符串
    std::make_pair<std::string,std::string>(&v27, &v28, &v29);// 键值对
    std::pair<std::string const,std::string>::pair<std::string,std::string>(&v26, &v27);
    std::map<std::string,std::string,order_by_inc,std::allocator<std::pair<std::string const,std::string>>>::insert(
      &v25,
      &v20,
      &v26);                                    // 插入map
    std::pair<std::string const,std::string>::~pair(&v26);
    std::pair<std::string,std::string>::~pair(&v27);
    std::string::~string((std::string *)&v29);
    std::string::~string((std::string *)&v28);
  }
  SHA1Init(&v15);
  SHA1Update(&v15, "bi2ipxazqodmw9hoety0h1wwgjvkttng", 32);// 对输入的字符串加密前,先进行一次自定义的字符串加密
  for ( j = std::map<std::string,std::string,order_by_inc,std::allocator<std::pair<std::string const,std::string>>>::begin(&v20);
        ;
        std::_Rb_tree_iterator<std::pair<std::string const,std::string>>::operator++(&j) )// 遍历上面的获取的map中的每一项
  {
    v30 = std::map<std::string,std::string,order_by_inc,std::allocator<std::pair<std::string const,std::string>>>::end(&v20);
    if ( !std::_Rb_tree_iterator<std::pair<std::string const,std::string>>::operator!=(&j, &v30) )
      break;
    v5 = (std::string *)std::_Rb_tree_iterator<std::pair<std::string const,std::string>>::operator->(&j);
    v6 = std::string::c_str(v5);                // 获取的值
    v7 = (std::string *)std::_Rb_tree_iterator<std::pair<std::string const,std::string>>::operator->(&j);
    v8 = std::string::size(v7);                 // 值的长度
    SHA1Update(&v15, v6, v8);
    v9 = std::_Rb_tree_iterator<std::pair<std::string const,std::string>>::operator->(&j);
    v10 = std::string::c_str((std::string *)(v9 + 4));// 将值往后移动4位
    v11 = std::_Rb_tree_iterator<std::pair<std::string const,std::string>>::operator->(&j);
    v12 = std::string::size((std::string *)(v11 + 4));// 将值往后移动4位的长度
    SHA1Update(&v15, v10, v12);
  }
  SHA1Update(&v15, "bi2ipxazqodmw9hoety0h1wwgjvkttng", 32);// 结尾再加密自定义字符串
                                                // 
  SHA1Final(&v17, &v15);
  for ( k = 0; k <= 19; ++k )
    sprintf((char *)(v14 + 2 * k), "%02x", (unsigned __int8)v35[k - 128]);
  v3 = 1;
LABEL_13:
  std::vector<std::string,std::allocator<std::string>>::~vector(&v18);
  std::string::~string((std::string *)&v19);
  std::map<std::string,std::string,order_by_inc,std::allocator<std::pair<std::string const,std::string>>>::~map(&v20);
  return v3;
}

里面我已经添加了详细的注释,应该比较简单,原理为:对输入的字符串,利用&分割,然后再分解=左右的字符串,存入map,最后遍历每个map值,进行加密。其中在加密前后,附加盐

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值