恋恋加密算法解析
来源:互联网 发布:程序员考试时间 编辑:程序博客网 时间:2024/05/05 18:24
作者:无名侠
声明:只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
交流群:无名移动逆向小分队 471525564
恋恋登陆的数据包是被加密过,Fiddler抓包如下(篇幅有限,删去HTTP头的大部分数据):
POST http://mob.imlianai.com/call.do?cmd=mobileUser.login HTTP/1.1WbbJnSJh63FYTNGmBk5J+lGOOQ1PzYWveRIJF8F//3Wo576FuH0Kyhb9VG/UpFHkICtAQcQAReUcUYLjsJ4sozorNeprDwcahSJs7D3f2YJFWWNtlwJlqXmwIPHUz0mHPZiJqJJNSYmGr2EsfPHz6FtnagDzHP4eXQlsZMyRKOOrRgyigyTRYQ==
把APP拖入到Ak,然后搜索mobileUser.login
搜索结果有两项,第一个里面有很多url,应该不是。
第二个的类名是com.a.a.a.b.t;
在这个类中找到如下代码:
JSONObject localJSONObject = new JSONObject(); localJSONObject.put("uid", paramString1); localJSONObject.put("loginKey", paramString2); paramString1 = com.a.a.a.f.a.a(localJSONObject.toString()).getBytes(); this.b.a(paramString1); this.b.c(); return;
推测未加密的数据包应该采用的json格式。
com.a.a.a.f.a.a 应该是对数据的进一步处理,可能是加密部分,跟进去一看,八九不离十了。
package com.a.a.a.f;import com.jni.Jni;import java.security.Key;import javax.crypto.spec.IvParameterSpec;public class a{ private static final byte[] a = { 1, 2, 3, 4, 5, 6, 7, 8 }; private static final IvParameterSpec b = new IvParameterSpec(a); private static String c = "hqi/FjjcBxA="; private static Key d = null; public static String a(String paramString) { return Jni.getInstance().encryptString(paramString); }}
在这个类中调用了Jni的encryptString负责加密。继续反编译Jni类。
我已经给出大部分代码的注释。
package com.jni;public class Jni{ private static final int blockLength = 500; private static String hexString = "0123456789ABCDEF"; private static Jni myJni; static { System.loadLibrary("jni");// jni这个lib中导出getEncryptString函数 } private native String getEncryptString(String paramString, boolean paramBoolean); public static Jni getInstance() { if (myJni == null) { myJni = new Jni(); } return myJni; } public String encode(String paramString) // 这个函数的功能是把paramString转换成16进制的数据文本 { paramString = paramString.getBytes(); StringBuilder localStringBuilder = new StringBuilder(paramString.length * 2); int i = 0; for (;;) { if (i >= paramString.length) { return localStringBuilder.toString(); } localStringBuilder.append(hexString.charAt((paramString & 0xF0) >> 4)); localStringBuilder.append(hexString.charAt((paramString & 0xF) >> 0)); i += 1; } }public String encryptString(String arg9) { String v0_1; if(arg9 == null || arg9.length() == 0) { v0_1 = ""; } else { String v2 = this.encode(arg9);//把arg9转换为16进制文本 int v3 = v2.length(); StringBuffer v4 = new StringBuffer(); if(v3 < 500) { v4.append(this.getEncryptString(v2, true));//通过getEncryptString对字符串编码 } else { int v0; for(v0 = 1; v0 < v3 / 500 + 1; ++v0) { if(v3 % 500 == 0 && v0 == v3 / 500) {//通过getEncryptString对字符串编码 v4.append(this.getEncryptString(v2.substring((v0 - 1) * 500, v0 * 500), true)); break; } //通过getEncryptString对字符串编码 v4.append(this.getEncryptString(v2.substring((v0 - 1) * 500, v0 * 500), false)); } if(v3 % 500 == 0) { goto label_14; } //通过getEncryptString对字符串编码 v4.append(this.getEncryptString(v2.substring((v0 - 1) * 500, v3), true)); } label_14: //getEncryptString("a", true).substring(0,8)做密匙 v0_1 = DESencryption.getEncString(v4.toString(), this.getEncryptString("a", true).substring( 0, 8)); } return v0_1; }
getEncryptString是SO库中的东西,就用IDA来分析。
库的文件名是libjni.so
主函数代码比较清晰,直接F5
int __fastcall Java_com_jni_Jni_getEncryptString(int a1, int a2, int a3, int a4){ _JNIEnv *v4; // r5@1 int v5; // r4@1 int v6; // r2@1 const char *input; // r7@1 size_t sizeSInit; // r4@1 _JNIEnv *v9; // r0@2 char *v10; // r1@2 jstring (__cdecl *v11)(JNIEnv *, const char *); // r3@2 int result; // r0@6 char *s; // [sp+0h] [bp-828h]@1 int v14; // [sp+4h] [bp-824h]@1 char dest; // [sp+Ch] [bp-81Ch]@3 int v16; // [sp+80Ch] [bp-1Ch]@1 v4 = a1; v5 = a3; v14 = a4; v16 = _stack_chk_guard; g_env = a1; s = initAddStr(); // 获取一段内置的字符串,具体分析看后文 input = jstringTostring(v4, v5, v6); // 转换函数,把java字符串类转换为char * sizeSInit = strlen(s); if ( strlen(input) + sizeSInit <= 0x7FF ) // 分两种情况: // 1、输入字符串长度 + 内置字符串长度 小于等于0x7ff { memset(&dest, 0, 0x7FFu); strcat(&dest, input); if ( v14 ) // 根据Java传递过来的第二个参数(paramBoolean)选择处理方法 strcat(&dest, s); // 如果第二个参数为true,则追加内置字符串 v9 = v4; v10 = &dest; v11 = v4->functions->NewStringUTF; } else // 如果第二个参数为false,输入什么就返回什么 { v9 = v4; v10 = input; v11 = v4->functions->NewStringUTF; } result = (v11)(v9, v10); if ( v16 != _stack_chk_guard ) _stack_chk_fail(result); return result;}
再来说说initAddStr()函数。这个函数实际是一个固定的字符串,可以通过动态调试得出,但是还是分析一下它是如何获取的吧。因为它比较有意思,还返回到了Java来获取字符串。
int initAddStr(){ int v0; // r0@2 int v1; // r2@2 if ( !isInit ) { v0 = initInflect(jniStr); key = jstringTostring(g_env, v0, v1); isInit = 1; } return key;}[/mw_shl_code]initInflect 函数回调到Java层的com.Reflect.func函数。jniStr是一串字符串“/key=i im lianai”[mw_shl_code=cpp,true]int __fastcall initInflect(int a1){ _JNIEnv *v1; // r5@1 int v2; // r0@1 bool v3; // zf@1 int v4; // r7@1 JNINativeInterface *v5; // r0@1 jstring (__cdecl *v6)(JNIEnv *, const char *); // r3@3 const char *v7; // r1@3 int v8; // r0@2 JNINativeInterface *v9; // r3@4 int v10; // r4@4 int v12; // [sp+Ch] [bp-1Ch]@1 v12 = a1; v1 = g_env; v2 = ((*g_env)->FindClass)(g_env, "com/Reflect"); v4 = v2; v3 = v2 == 0; v5 = v1->functions; if ( v3 ) { v6 = v5->NewStringUTF; v7 = "jclass"; return (v6)(v1, v7); } v8 = (v5->GetStaticMethodID)(v1, v4, "func", "(ILjava/lang/String;)Ljava/lang/String;"); v9 = v1->functions; v10 = v8; if ( !v8 ) { v6 = v9->NewStringUTF; v7 = "method"; return (v6)(v1, v7); } (v9->NewStringUTF)(v1, v12); return _JNIEnv::CallStaticObjectMethod(v1, v4, v10, 10);}
再来看看Java的Reflect代码:
public class Reflect{ private static String hexString = "0123456789ABCDEF"; public static String tmp = " alien"; private static String encode(String paramString)//把数据编码为HEX文本 { paramString = paramString.getBytes(); StringBuilder localStringBuilder = new StringBuilder(paramString.length * 2); int i = 0; for (;;) { if (i >= paramString.length) { return localStringBuilder.toString(); } localStringBuilder.append(hexString.charAt((paramString & 0xF0) >> 4)); localStringBuilder.append(hexString.charAt((paramString & 0xF) >> 0)); i += 1; } } public static String func(int paramInt, String paramString) { return encode(paramString + tmp); }}
func实际作用就是把输入字符串拼接上“alien”,然后转换HEX数据文本。
实际上,initInflect返回的是“/key=i im lianai alien”的16进制数据文本2F6B65793D6920696D206C69616E616920616C69656E
最后面:
public static String getEncString(String paramString1, String paramString2){paramString1 = DESBase64.encode(getEncCode(paramString1.getBytes("UTF8"), paramString2)); return paramString1;}
所以最后的数据进行了DESBase64加密,得出了最后的结果。
0 0
- 恋恋加密算法解析
- 加密算法解析
- 解析常用加密算法
- "MD5"加密算法全解析
- 常用加密算法解析
- RC4加密算法 解析及代码
- RSA加密算法解析+数字签名验证
- Android中的SHA加密算法解析
- Android中的AES加密算法解析
- 谈谈心恋恋爱最新章节
- 谈谈心 恋恋爱
- RSA加密算法加密与解密过程解析
- MD5、RSA、DES加密算法原理解析
- RSA加密算法加密与解密过程解析
- RSA加密算法加密与解密过程解析
- Java中4大基本加密算法解析
- Java中4大基本加密算法解析
- Java中4大基本加密算法解析
- Css简介
- linux基础之 创建一个UDP socket
- unity5.3.3 no pc,mac&linux standalone
- cf273C. Primes on Interval【二分】
- Java 设计模式- 外观模式
- 恋恋加密算法解析
- TimesTen访问Oracle的口令存在哪里(ttCacheUidPwdSet还是OraclePWD)
- untiy 3d ShaderLab_第 2 章Unity中Shader(着色器)的形态_3_Shader的数据接口:属性和 uniform变量
- 在Java中如何高效判断数组中是否包含某个元素
- shiro多角色访问同一个url
- PAT-B 1006. 换个格式输出整数
- APP创意IDEA记录
- 文章标题
- 浅谈Solr和ElasticSearch建索引性能优化策略