您的位置:首页 > 其它

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

2016-07-03 21:55 423 查看

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::
b667
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值,进行加密。其中在加密前后,附加盐
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息