基於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值,進行加密。其中在加密前後,附加鹽

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章