这次分享一个iOS端*车之家的登录接口的参数分析(仅供学习,严禁干坏事=。=)。本文为新手项,大佬请跳过。
抓包使用 charles,请自行安装并配置证书
抓取登陆接口,点击账号登陆。使用假账密测试抓包 123456 / 123456,能够抓包成功
登录页面需要输入3个信息,分别是账号 / 密码 / 验证码,对应字段 logincode / userpwd / validcode
logincode为一个字符串,是输入账号加一个 %3 做前缀。
userpwd是一个加密字符串,需要待分析
validcode是验证码原文
经过多次抓包分析,其他字段为一些设备信息,可以保持不变。_timestamp是一个10位的时间戳,_sign参数每次均改变,需要待分析
分析前将包含 Mach-O文件的,后缀名为 .app的文件夹从爱思助手导出
检查Mach-O文件是否需要脱壳
找到Mach-O文件
|
1
2
3
|
file
Payload
/
Autohome.app
/
*
| grep Mach
-
O
Payload
/
Autohome.app
/
Autohome: Mach
-
O
64
-
bit executable arm64
|
使用otool查看是否脱壳。1: 未脱壳;0: 脱壳;
|
1
2
3
4
5
|
%
otool
-
l Payload
/
Autohome.app
/
Autohome | grep crypt
cryptoff
16384
cryptsize
28295168
cryptid
1
|
使用 砸壳。
需要app完全启动才能砸,如果砸壳中遇到阻塞请重试。
砸完会生成一个 ipa,直接解压即可
再次使用otool检测会发现 cryptid 1 变为 cryptid 0,即砸壳完成。
开始分析userpwd参数。用ida将Mach-O文件 Autohome 打开,搜索字符串 userpwd
点击第一个进入,tab键转换伪代码.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
void __cdecl
-
[LOGThirdBindService bindThirdLogincode:userpwd:platformid:token:tokensecret:orginalname:openid:unionId:position:](LOGThirdBindService
*
self
, SEL a2,
id
a3,
id
a4,
int
a5,
id
a6,
id
a7,
id
a8,
id
a9,
id
a10,
int
a11)
{
id
v11;
/
/
x23
id
v12;
/
/
x22
id
v13;
/
/
x21
int
v14;
/
/
w27
id
v15;
/
/
x20
LOGThirdBindService
*
v16;
/
/
x25
__int64 v17;
/
/
x1
void
*
v18;
/
/
x20
__int64 v19;
/
/
x1
__int64 v20;
/
/
x21
__int64 v21;
/
/
x1
__int64 v22;
/
/
x1
__int64 v23;
/
/
x1
__int64 v24;
/
/
x1
void
*
v25;
/
/
x0
int
v26;
/
/
w19
NSMutableDictionary
*
v27;
/
/
x19
void
*
v28;
/
/
x0
__int64 v29;
/
/
x0
NSMutableDictionary
*
v30;
/
/
x19
void
*
v31;
/
/
x0
void
*
v32;
/
/
x0
NSMutableDictionary
*
v33;
/
/
x28
void
*
v34;
/
/
x0
NSMutableDictionary
*
v35;
/
/
x19
void
*
v36;
/
/
x0
NSMutableDictionary
*
v37;
/
/
x19
void
*
v38;
/
/
x0
NSMutableDictionary
*
v39;
/
/
x19
__int64 v40;
/
/
x0
__int64 v41;
/
/
x0
__int64 v42;
/
/
x27
void
*
v43;
/
/
[xsp
+
20h
] [xbp
-
90h
]
__int64 v44;
/
/
[xsp
+
50h
] [xbp
-
60h
]
char v45;
/
/
[xsp
+
58h
] [xbp
-
58h
]
v11
=
a8;
v12
=
a7;
v13
=
a6;
v14
=
a5;
v15
=
a4;
v16
=
self
;
v43
=
(void
*
)objc_retain(a3, a2);
v18
=
(void
*
)objc_retain(v15, v17);
v20
=
objc_retain(v13, v19);
objc_retain(v12, v21);
objc_retain(v11, v22);
objc_retain(a9, v23);
objc_retain(a10, v24);
sub_1016C6940((void
*
)v16
-
>postDataDic);
v25
=
sub_1016769C0(&OBJC_CLASS___AHUserSettings);
objc_retainAutoreleasedReturnValue(v25);
v26
=
sub_1016978E0();
objc_release();
if
( v26 )
{
v27
=
v16
-
>postDataDic;
v28
=
sub_1016769C0(&OBJC_CLASS___AHUserSettings);
objc_retainAutoreleasedReturnValue(v28);
v29
=
sub_10167D700();
objc_retainAutoreleasedReturnValue(v29);
sub_1017025E0((void
*
)v27);
objc_release();
objc_release();
}
v30
=
v16
-
>postDataDic;
v31
=
sub_101728CE0(v43);
objc_retainAutoreleasedReturnValue(v31);
sub_1017025E0((void
*
)v30);
objc_release();
v32
=
-
[LPNode count]_0(v18);
v33
=
v16
-
>postDataDic;
if
( v32 )
{
v34
=
sub_10162E040(&OBJC_CLASS___AHMD5);
objc_retainAutoreleasedReturnValue(v34);
sub_1017025E0((void
*
)v33);
objc_release();
}
else
{
sub_1017025E0((void
*
)v16
-
>postDataDic);
}
v35
=
v16
-
>postDataDic;
v36
=
sub_1016AAC00(&OBJC_CLASS___NSNumber);
objc_retainAutoreleasedReturnValue(v36);
sub_1017025E0((void
*
)v35);
objc_release();
if
( !v20 )
objc_release();
sub_1017025E0((void
*
)v16
-
>postDataDic);
sub_1017025E0((void
*
)v16
-
>postDataDic);
sub_1017025E0((void
*
)v16
-
>postDataDic);
sub_1017025E0((void
*
)v16
-
>postDataDic);
if
( v14
=
=
26
)
sub_1017025E0((void
*
)v16
-
>postDataDic);
v37
=
v16
-
>postDataDic;
v38
=
sub_1016AAC00(&OBJC_CLASS___NSNumber);
objc_retainAutoreleasedReturnValue(v38);
sub_1017025E0((void
*
)v37);
objc_release();
sub_1017025E0((void
*
)v16
-
>postDataDic);
v39
=
v16
-
>postDataDic;
v40
=
sub_1016CB900(&OBJC_CLASS___AHAppSettings);
objc_retainAutoreleasedReturnValue(v40);
sub_1017025E0((void
*
)v39);
objc_release();
objc_initWeak(&v45, v16);
v41
=
sub_10172F720(v16);
v42
=
objc_retainAutoreleasedReturnValue(v41);
objc_copyWeak(&v44, &v45);
sub_10167B600(v42);
objc_release();
objc_destroyWeak(&v44);
objc_destroyWeak(&v45);
objc_release();
objc_release();
objc_release();
objc_release();
objc_release();
objc_release();
objc_release();
}
|
分析发现有MD5字样,疑似为大写md5,用测试一下,果然是原滋原味的md5大写,未做任何魔改。那_sign字符串与userpwd的“样子”相似,可能也是md5。ios的md5使用的是 CC_MD5,那咱就直接用frida对CC_MD5进行hook了
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/
/
hook CC_MD5
let cc_md5
=
Module.findExportByName(null,
"CC_MD5"
);
console.log(`CC_MD5 addr>> ${cc_md5}`)
Interceptor.attach(cc_md5, {
onEnter: function(args){
/
/
获取传入 CC_MD5 函数的参数
const data
=
args[
0
];
const
len
=
args[
1
];
const output
=
args[
2
];
console.log(`md5>> ${data.readCString()} | ${parseInt(
len
,
16
)} | ${output}`)
console.log(
"\nBacktrace:\n\t"
+
Thread.backtrace(this.context, Backtracer.ACCURATE).
map
(DebugSymbol.fromAddress).join(
'\n\t'
)
+
'\n'
);
}
})
|
hook CC_MD5后,分析打印日志, 在userpwd md5日志下发现一个可以日志。是一个312位字符串,放到在线网站中测试一下,加密后果然是_sign的值。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
md5>> @
7U
$aPOE@$Version1_appidapp.iphone_timestamp1686474400autohomeuaiPhone
12.5
.
5
autohome
11.33
.
5
iPhonefPosition10004isCheckModeratorsRemote1isapp1logincode
%
3123456platform3reffersPosition1000405sessionid744ec98679b59e66a1fdc2deb77e7ee610812039showmob1userpwdE10ADC3949BA59ABBE56E057F20F883Evalidcodezbzt
@
7U
$aPOE@$ |
312
|
0x16f6cd528
Backtrace:
0x1069566cc
AHLoginServicesFramework!
+
[AHLoginServicesMD5 MD5WithString:]
0x1069515e4
AHLoginServicesFramework!__128
-
[AHLoginAccountLoginService accountLoginWidthUserName:PassWord:deviceToken:verifyCode:infoexpand:infoclub:sPosition:fPosition:]_block_invoke
0x1061ee424
AHBusinessFramework!
-
[AHServerTimeStampManager getServerTimeStampWithBlock:]
0x1069514a8
AHLoginServicesFramework!
-
[AHLoginAccountLoginService accountLoginWidthUserName:PassWord:deviceToken:verifyCode:infoexpand:infoclub:sPosition:fPosition:]
0x1069537b4
AHLoginServicesFramework!
-
[AHLoginAccountLoginManager loginWidthUserName:PassWord:deviceToken:verifyCode:infoexpand:infoclub:sPosition:fPosition:success:fail:]
0x100b13e9c
Autohome!
0x3e3e9c
0x1aebe9300
UIKitCore!
-
[UIApplication sendAction:to:
from
:forEvent:]
0x1ae692424
UIKitCore!
-
[UIControl sendAction:to:forEvent:]
0x101584aa4
Autohome!
0xe54aa4
0x1ae692744
UIKitCore!
-
[UIControl _sendActionsForEvents:withEvent:]
0x1ae6917b0
UIKitCore!
-
[UIControl touchesEnded:withEvent:]
0x1aec205c4
UIKitCore!
-
[UIWindow _sendTouchesForEvent:]
0x1aec217ec
UIKitCore!
-
[UIWindow sendEvent:]
0x1aec0185c
UIKitCore!
-
[UIApplication sendEvent:]
0x1aecc79d4
UIKitCore!__dispatchPreprocessedEventFromEventQueue
0x1aecca100
UIKitCore!__handleEventQueueInternal
|
再分析生成_sign的字符串,发现是由抓包中的各参数拼接成的,拼接代码如下。至此_sign参数分析结束。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
import
time
import
hashlib
"""
@7U$aPOE@$Version1_appidapp.iphone_timestamp1686473693autohomeuaiPhone 12.5.5 autohome 11.33.5 iPhoneisCheckModeratorsRemote1isapp1logincode%3123456reffersessionid744ec98679b59e66a1fdc2deb77e7ee610812039showmob1userpwdE10ADC3949BA59ABBE56E057F20F883Evalidcodeiaeh@7U$aPOE@$
A40B768AA55F204329C7769C98BB1C69
"""
usn
=
"123456"
pwd
=
"123456"
en_md5
=
lambda
x: hashlib.md5(x.encode()).hexdigest()
def
gen_sign(params):
s
=
f
"@7U$aPOE@$Version{params['Version']}_appid{params['_appid']}_timestamp{params['_timestamp']}autohomeua{params['autohomeua']}isCheckModeratorsRemote{params['isCheckModeratorsRemote']}isapp{params['isapp']}logincode{params['logincode']}reffer{params['reffer']}sessionid{params['sessionid']}showmob{params['showmob']}userpwd{params['userpwd']}validcode{params['validcode']}@7U$aPOE@$"
return
en_md5(s).upper()
if
__name__
=
=
"__main__"
:
params
=
{
"Version"
:
1
,
"_appid"
:
"app.iphone"
,
# "_timestamp": int(time.time()),
"_timestamp"
:
"1686473693"
,
"autohomeua"
:
"iPhone 12.5.5 autohome 11.33.5 iPhone"
,
"isCheckModeratorsRemote"
:
1
,
"isapp"
:
1
,
"logincode"
: f
"%3{usn}"
,
"reffer"
: "",
"sessionid"
:
"744ec98679b59e66a1fdc2deb77e7ee610812039"
,
"showmob"
:
1
,
"userpwd"
: en_md5(pwd).upper(),
"validcode"
:
"iaeh"
}
_sign
=
gen_sign(params)
print
(f
"{params=}\n{_sign=}"
)
|
登录接口的 userpwd 和 _sign 已经分析完了。比较简单,就一个大写md5,还没有任何魔改,熟悉算法的佬应该很快就反应过来的。可惜俺不是
更多【iOS某车之家登录参数_sign&userpwd分析】相关视频教程:www.yxfzedu.com