前因:没有别的,就是群里有老哥发的文件,初学逆向,为自己记录顺带分享给和我一样刚开始起步学习的人,作为第一次在看雪上发帖子,有点小激动!
这里定位很简单,直接全局搜索关键词:"a" 就可以了,因为可以看到POST数据包中只有一个字段就是a,但是这里需要带上双引号,来到如下
可以看到最关键的加密代码就是:
initFromXML.getAppKey则正常返回一个定值
跟进m3385a函数可以发现,定义如下:
注意:这里发现JSONObject是处于org.json.JSONObject,系统自带的库中的类,这里也能作为一种hook的方法定位
对JSONObejct的hook效果如下,虽然是可以进行hook,但是我这里会发现程序会崩溃,可能代码有瑕疵,自己猜想就是因为第二个参数为java.lang.String类型的,但是你接收的时候如果要包含java.lang.String类型就必须指明java.lang.Object,然后再进行强转java.cast(),但是在接收的时候java.lang.Object不一定总是java.lang.String,可能是一个List或者Map等,这时候强转为java.lang.String就会造成程序结束
这里可以直接对m3385a这个函数进行观察,流程就是将传入的数据先进行一个url编码,然后拼接initFromXML.getAppKey作为参数,调用EncryptUtil.encryptString
继续跟到encryptString中去,代码如下,那么也就需要进libgavesec.so中的nativeEncrypt函数进行分析
这里遇到了一个问题,比如下面的两个函数和注入代码,一个函数会调用native中的函数,但是如果我hook encryptString这个函数,返回值写的是调用native层的nativeEncrypt函数,这样的写法就会导致程序结束,具体原因不知道
因为上面那样写就导致程序结束,所以这里就直接hook nativeEncrypt,发现这样子就不会导致程序结束了
这里可以对EncryptUtil.encryptString(encode + str),java层进行一次hook来获取对应的参数先
那么的initFromXML.getAppKey值就为:
然后接着继续跟native层进行分析,将libgavesec.so拖入到IDA中,并且找到对应的函数,该函数是静态注册的,所以特征很明显,如果是动态注册的话 可以通过jni_onload中一些偏移变量来进行寻找对应的静态注册的函数
主要进行了encrypt函数的调用
接着就是来到加密函数encrypt中进行分析
先是进行一次sha1加密
所以这里要hook两个地方
encrypt:Base + 0x1C8C ,获取第一个参数
SHA1::Result:Base + 0x2AA4,获取该函数调用完之后的第二个参数的结果
hook的结果如下显示:
接着打印了sha1加密过后的数据v12变量和最终的Sign值(这里也就是nativeEncrypt的返回值),但是你会发现结果是不一样的
接着继续往下面看,会发现存在循环的操作,所以sha1加密的结果应该被二次修改了,这里有两个大循环的操作
首先第一段循环:
你会发现hexDigits是data段的一段数据:
最后分析,其实就是将其原封不动的转换为16进制的字符,然后一起拼接起来,分析注释如下
然后就是第二段循环了,循环次数也可以看出来会对每个16进制字符进行处理,循环次数为40次
hook了char2hexInt处理过后的数据会发现,char2hexInt这个函数才是二次处理的函数
还需要char2hexInt的参数来观察,该地址为0x1B34,HOOK结果如下
其实就是两个返回值进行异或处理,比如0x2^0x2就为0,最后还会通过hexDigits数组转成对应的16进制在内存中保存为0x30,因为字符 '0' 对应的ASCII 十六进制就是 0x30 是相等的!
最终的sign值分析的注释:
sign这里也分析完了,还有个整体加密的分析,发现整体会进行一次Base64.encode,但是nativeAES可以跟进去观察
发现该函数依旧是native层的函数,所以这里继续去看分析
来到如下进行分析,看到名字就知道是AES算法加密了,这里的话用findcrypt插件通过特征码也可以进行识别
然后接着就是先对传入的数据进行字符串复制
然后就是AES对象和密钥的初始化,这里的AES需要hook,来确认v19的值,还有该函数最终的返回值dest_array_bytes的地址来进行打印
AES::AES:0x3274,Cipher:0x397C,然后hook到的数据如下,一个是AES密钥,最终要进行AES字符串加密的字符串
到这里就分析结束了
最终hook的代码:
简单的加密代码的实现:
结果对比:
hook:
python:
初学逆向,写的不好请见谅!
请求包:
POST
/
api
/
adult
/
check_guest HTTP
/
1.1
Content
-
Type
: application
/
x
-
www
-
form
-
urlencoded
User
-
Agent: Dalvik
/
2.1
.
0
(Linux; U; Android
8.1
.
0
; Pixel Build
/
OPM1.
171019.011
)
Host: service.kuyangsh.cn
Connection: Keep
-
Alive
Accept
-
Encoding: gzip
Content
-
Length:
1108
a
=
6ih0KN8TFL5
%
2FQT
%
2FN3JY63ZovsWQyeIxHjBLHp1GGwjUNYVaGJLC
%
2FYZenRFKbeqsgIoI4rD1atROr
%
0Ajkl1p7eobNMARMel19oiGkl5hRD72vOn9zyNbERMe8Cj3b24Ru4wc2mWbbnamKVKPepkaa2mqpJl
%
0Akp4
%
2Fa5udSz0UbDR6cTwLCRWeKb60H
%
2Fir4vzZv1OfwQF
%
2FXJQsuBmxH2F6wp9CJkk9WYchx4LQU
%
2FS3
%
0AjQfpQY2iZWwsmHAiyZGVsfZIgXTvhJygpT8vH268Py5JspYZoho0RRrx4BjUfs5boif6rEMpd5PC
%
0AiZTLhIPovbPpoZQJC7d
%
2BWPFtwjPT7Ljyzgz5QxtctnZqa4qMMkfFwAIeA7lj2wJZeZBD
%
2F
%
2BoU5R45
%
0AMEFK6OMrMXB1M
%
2BC4dBt7Rd384SYhe
%
2BAEp0gKNHGkrpxWImFcPAaalajyijs6V4Wl4res9CWuEE5W
%
0Ayj5ehtmPc6uZGuo5ns6THfDwnho8BiFOnH0QoqJEeyVdTsCzOiMwfBJJldB7qbsTfUlLbSnpq4tf
%
0AurPbVMVKQbk4ui1XgDH5v
%
2FptUHirNK0IHT
%
2BBms8wQ
%
2BSX3BcMLKFiWI0OBAjUydqcJpIi0sPSWpfh
%
0A2k1nmMlvPnljfc7P12iF8nFHoFWRYQPVie46K
%
2Bhd4
%
2FttkyrZ4Gy3WM6zWdmnED3h6CCgZ4rEe0DB
%
0AN5Dj8lJJbsOAE
%
2FxWcYDguyj8WkUET3yLB
%
2FBZQx
%
2BsOn9otWzjwROdhfi6V7OObXZ5XoGUIDffKaFu
%
0ADnvTinsAh
%
2FvjcSDVq
%
2BHyD
%
2FzUeRceMf6uQruBhHRzikSb2Oz0Zfxld7rqmWYZ8aIBe1DMRJuXecB
%
2F
%
0AAsBu4VVuVVfQf4hlCpVNmKnX6huuMkHtCptCLaD0pkmuY7X7OEfCsudtFIco
%
2F7gXaQ5aXgfCs7GJ
%
0AzAMxfpCRm4vnF0kc8nQ4OWlexOV5t65k
%
2B4eDt8wY91
%
2BIFHcq
%
2BIwZPR3e41oeKriHlbsPdocNOkeg
%
0AeyUw
%
2FXlAY97IpZA
%
3D
%
0A
返回包:
{
"ret"
:
0
,
"msg"
:
"没有错误"
,
"data"
: {
"needs_check"
:
"0"
,
"needs_bind"
:
"0"
,
"needs_guest_bind"
:
0
,
"user_is_guest"
:
-
1
}
}
请求包:
POST
/
api
/
adult
/
check_guest HTTP
/
1.1
Content
-
Type
: application
/
x
-
www
-
form
-
urlencoded
User
-
Agent: Dalvik
/
2.1
.
0
(Linux; U; Android
8.1
.
0
; Pixel Build
/
OPM1.
171019.011
)
Host: service.kuyangsh.cn
Connection: Keep
-
Alive
Accept
-
Encoding: gzip
Content
-
Length:
1108
a
=
6ih0KN8TFL5
%
2FQT
%
2FN3JY63ZovsWQyeIxHjBLHp1GGwjUNYVaGJLC
%
2FYZenRFKbeqsgIoI4rD1atROr
%
0Ajkl1p7eobNMARMel19oiGkl5hRD72vOn9zyNbERMe8Cj3b24Ru4wc2mWbbnamKVKPepkaa2mqpJl
%
0Akp4
%
2Fa5udSz0UbDR6cTwLCRWeKb60H
%
2Fir4vzZv1OfwQF
%
2FXJQsuBmxH2F6wp9CJkk9WYchx4LQU
%
2FS3
%
0AjQfpQY2iZWwsmHAiyZGVsfZIgXTvhJygpT8vH268Py5JspYZoho0RRrx4BjUfs5boif6rEMpd5PC
%
0AiZTLhIPovbPpoZQJC7d
%
2BWPFtwjPT7Ljyzgz5QxtctnZqa4qMMkfFwAIeA7lj2wJZeZBD
%
2F
%
2BoU5R45
%
0AMEFK6OMrMXB1M
%
2BC4dBt7Rd384SYhe
%
2BAEp0gKNHGkrpxWImFcPAaalajyijs6V4Wl4res9CWuEE5W
%
0Ayj5ehtmPc6uZGuo5ns6THfDwnho8BiFOnH0QoqJEeyVdTsCzOiMwfBJJldB7qbsTfUlLbSnpq4tf
%
0AurPbVMVKQbk4ui1XgDH5v
%
2FptUHirNK0IHT
%
2BBms8wQ
%
2BSX3BcMLKFiWI0OBAjUydqcJpIi0sPSWpfh
%
0A2k1nmMlvPnljfc7P12iF8nFHoFWRYQPVie46K
%
2Bhd4
%
2FttkyrZ4Gy3WM6zWdmnED3h6CCgZ4rEe0DB
%
0AN5Dj8lJJbsOAE
%
2FxWcYDguyj8WkUET3yLB
%
2FBZQx
%
2BsOn9otWzjwROdhfi6V7OObXZ5XoGUIDffKaFu
%
0ADnvTinsAh
%
2FvjcSDVq
%
2BHyD
%
2FzUeRceMf6uQruBhHRzikSb2Oz0Zfxld7rqmWYZ8aIBe1DMRJuXecB
%
2F
%
0AAsBu4VVuVVfQf4hlCpVNmKnX6huuMkHtCptCLaD0pkmuY7X7OEfCsudtFIco
%
2F7gXaQ5aXgfCs7GJ
%
0AzAMxfpCRm4vnF0kc8nQ4OWlexOV5t65k
%
2B4eDt8wY91
%
2BIFHcq
%
2BIwZPR3e41oeKriHlbsPdocNOkeg
%
0AeyUw
%
2FXlAY97IpZA
%
3D
%
0A
返回包:
{
"ret"
:
0
,
"msg"
:
"没有错误"
,
"data"
: {
"needs_check"
:
"0"
,
"needs_bind"
:
"0"
,
"needs_guest_bind"
:
0
,
"user_is_guest"
:
-
1
}
}
String a
=
m3385a((
Map
<String, String>) hashMap, initFromXML.getAppKey());
String a
=
m3385a((
Map
<String, String>) hashMap, initFromXML.getAppKey());
public static String m3385a(
Map
<String, String>
map
, String
str
) {
if
(C1074a.f2394c || TivicloudController.f2343a) {
map
.put(
"testing"
,
"1"
);
}
try
{
JSONObject jSONObject
=
new JSONObject(
map
);
Debug.m3346d(
"params : "
+
jSONObject.toString());
String encode
=
URLEncoder.encode(jSONObject.toString(),
"UTF-8"
);
String encryptString
=
EncryptUtil.encryptString(encode
+
str
);
JSONObject jSONObject2
=
new JSONObject();
try
{
jSONObject2.put(
"sign"
, encryptString);
jSONObject2.put(C0882di.C0883a.DATA, encode);
} catch (JSONException e) {
Debug.m3354w((Exception) e);
}
return
new String(Base64.encode(EncryptUtil.nativeAES(jSONObject2.toString()),
0
),
"UTF-8"
);
} catch (UnsupportedEncodingException e2) {
Debug.m3354w((Exception) e2);
return
null;
}
}
public static String m3385a(
Map
<String, String>
map
, String
str
) {
if
(C1074a.f2394c || TivicloudController.f2343a) {
map
.put(
"testing"
,
"1"
);
}
try
{
JSONObject jSONObject
=
new JSONObject(
map
);
Debug.m3346d(
"params : "
+
jSONObject.toString());
String encode
=
URLEncoder.encode(jSONObject.toString(),
"UTF-8"
);
String encryptString
=
EncryptUtil.encryptString(encode
+
str
);
JSONObject jSONObject2
=
new JSONObject();
try
{
jSONObject2.put(
"sign"
, encryptString);
jSONObject2.put(C0882di.C0883a.DATA, encode);
} catch (JSONException e) {
Debug.m3354w((Exception) e);
}
return
new String(Base64.encode(EncryptUtil.nativeAES(jSONObject2.toString()),
0
),
"UTF-8"
);
} catch (UnsupportedEncodingException e2) {
Debug.m3354w((Exception) e2);
return
null;
}
}
public static String encryptString(String
str
) {
return
nativeEncrypt(
str
);
}
private static native String nativeEncrypt(String
str
);
Java.perform(function () {
var EncryptUtil
=
Java.use(
"com.tivicloud.utils.EncryptUtil"
);
EncryptUtil.encryptString.implementation
=
function (a) {
send(
"EncryptUtil.encryptString args[0]: "
+
a);
var result
=
this.nativeEncrypt(a);
return
result;
}
});
public static String encryptString(String
str
) {
return
nativeEncrypt(
str
);
}
private static native String nativeEncrypt(String
str
);
Java.perform(function () {
var EncryptUtil
=
Java.use(
"com.tivicloud.utils.EncryptUtil"
);
EncryptUtil.encryptString.implementation
=
function (a) {
send(
"EncryptUtil.encryptString args[0]: "
+
a);
var result
=
this.nativeEncrypt(a);
return
result;
}
});
setImmediate(function(){
Java.perform(function () {
var EncryptUtil
=
Java.use(
"com.tivicloud.utils.EncryptUtil"
);
EncryptUtil.nativeEncrypt.implementation
=
function (a) {
send(
"EncryptUtil.nativeEncrypt args[0]: "
+
a);
var result
=
this.nativeEncrypt(a);
return
result;
}
});
});
setImmediate(function(){
Java.perform(function () {
var EncryptUtil
=
Java.use(
"com.tivicloud.utils.EncryptUtil"
);
EncryptUtil.nativeEncrypt.implementation
=
function (a) {
send(
"EncryptUtil.nativeEncrypt args[0]: "
+
a);
var result
=
this.nativeEncrypt(a);
return
result;
}
});
});
[
*
] EncryptUtil.encryptString args[
0
]: {
"mobile_operator"
:"
","
app_versioncode
":"
4
","
app_version
":"
2.1
.
0.22277
","
connection_type
":"
WIFI
","
os_version
":"
8.1
.
0
","
version_code
":"
4
","
version_name
":"
2.1
.
0.22277
","
os_lang
":"
zh
","
sdk_version
":"
3.1
.
4
","
package_name
":"
com.lm.lm
","
imei
":"
359906070277673
","
os_name
":"
Android
","
lang
":"
zh
","
udid
":"
10e1ef4509a2340eb0276bb99d186506
","
nudid
":"
155c2b70
-
fc97
-
4005
-
abc7
-
6d6c4329ed23
","
app_id
":"
10054
","
channel_id
":"
10006
","
tdid
":"
39fb282a761c17e80c069332fc6a2ffa9
"}fff18b83431fa3a83b9de80c1e413bde
[
*
] EncryptUtil.encryptString args[
0
]: {
"mobile_operator"
:"
","
app_versioncode
":"
4
","
app_version
":"
2.1
.
0.22277
","
connection_type
":"
WIFI
","
os_version
":"
8.1
.
0
","
version_code
":"
4
","
version_name
":"
2.1
.
0.22277
","
os_lang
":"
zh
","
sdk_version
":"
3.1
.
4
","
package_name
":"
com.lm.lm
","
imei
":"
359906070277673
","
os_name
":"
Android
","
lang
":"
zh
","
udid
":"
10e1ef4509a2340eb0276bb99d186506
","
nudid
":"
155c2b70
-
fc97
-
4005
-
abc7
-
6d6c4329ed23
","
app_id
":"
10054
","
channel_id
":"
10006
","
tdid
":"
39fb282a761c17e80c069332fc6a2ffa9
"}fff18b83431fa3a83b9de80c1e413bde
fff18b83431fa3a83b9de80c1e413bde
fff18b83431fa3a83b9de80c1e413bde
SHA1::Result((SHA1
*
)&v13, (unsigned
int
*
)v12);
/
/
sha1加密的结果
v4
=
0LL
;
/
/
long
long
v5
=
7
;
do
/
/
进行循环操作
{
v6
=
*
(_DWORD
*
)&v12[v4];
/
/
0X0C
v7
=
&dest_cstr_1[v5];
while
(
1
)
{
v8
=
v6 &
0xF
;
/
/
0X0C
v6 >>
=
4
;
/
/
0X00
*
v7
-
-
=
hexDigits[v8];
/
/
if
( !(v5 &
7
) )
break
;
-
-
v5;
}
*
(_DWORD
*
)&v12[v4]
=
v6;
/
/
赋值操作
v4
+
=
4LL
;
v5
+
=
15
;
}
while
( v4 !
=
20
);
SHA1::Result((SHA1
*
)&v13, (unsigned
int
*
)v12);
/
/
sha1加密的结果
v4
=
0LL
;
/
/
long
long
v5
=
7
;
do
/
/
进行循环操作
{
v6
=
*
(_DWORD
*
)&v12[v4];
/
/
0X0C
v7
=
&dest_cstr_1[v5];
while
(
1
)
{
v8
=
v6 &
0xF
;
/
/
0X0C
v6 >>
=
4
;
/
/
0X00
*
v7
-
-
=
hexDigits[v8];
/
/
if
( !(v5 &
7
) )
break
;
-
-
v5;
}
*
(_DWORD
*
)&v12[v4]
=
v6;
/
/
赋值操作
v4
+
=
4LL
;
v5
+
=
15
;
}
while
( v4 !
=
20
);
do
{
v10
=
char2hexInt(dest_cstr_1[v9]);
dest_cstr_1[v9]
=
hexDigits[(signed
int
)((unsigned __int64)char2hexInt(a211034f8af4e6b[v9]) ^ v10)];
/
/
异或的值为v10
+
+
v9;
}
do
{
v10
=
char2hexInt(dest_cstr_1[v9]);
dest_cstr_1[v9]
=
hexDigits[(signed
int
)((unsigned __int64)char2hexInt(a211034f8af4e6b[v9]) ^ v10)];
/
/
异或的值为v10
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-11-5 22:06
被初学逆向编辑
,原因: