app就不透露了(之前看各种大佬的分析也是怕侵权),什么方面的都有(也不知道是什么时候的app了),大家看看思路就好啦哈哈
找到登录界面,我输入的手机号是13905376666,密码是:666666666
先抓包:
这个是请求包:
第一步,也是最重要的一步,得先定位到关键代码的位置:
(这里插一句,分析协议字段的时候一般都是最后分析sign
字段,这个sign字段经过我这几天的学习总结出来的一般是这样生成的:
先将其他字段加密之后,然后有的还可能带一些盐,最后将各个字段排序之后,然后加密,MD5一般是)
回到分析过程中,这里发现,只有sign字段看着像加密的,其他的基本都是明文,然后找到两个方法,分别下断点,然后看看他走哪个就完事了
这里我打算搜索post请求中的v2/member,和"system_name"
最终定位到这个两个方法中比较像:
然后动态调试的时候我怕段不下来,就遇见sign都下了断点(这也是一种方法吧哈哈,但是他会在一些奇奇怪怪的方法中段下来,但是只要不是你想要的断点处,直接让程序继续运行就好了),然后发现我的判断没有错:(当点击登录按钮的时候程序从这里断了下来)
这个协议分析我也是刚刚开始自己动手,然后就打算把步骤写的详细一点:
首先看这个函数的两个参数:
第一个参数表示一个集合,在这个集合中保存发往服务器的数据包中的各个参数,然后第二个参数的翻译是上下文,所以这个参数应该就是连接上下函数的一个变量
然后看这个device_id就是表示手机的串号:
是这样声名的:
就是返回手机的型号,没有什么好说的
然后解释完第一个,其他的就不用过多解释啦:
这个clientid就是定值1:ClientID(客户端标识号)用于标识连接到API服务的客户端
然后下一个就是本机IP地址,还有时间timestamp,siteid站点标识符定值10001,系统名称system_name,型号type是Android的
然后重点就是这个sign了,这个是个签名校验,这个校验对于我们来说就是我们自己分析算出来的sign值和发往服务器的sign值一样,就说明分析正确了,一般的校验都是看这个发往服务器的sign值和服务器那边计算出来的sign值是否一样:
所以接下来就是要分析这个函数了 m8098a(params.getURLHashMap(), timestamp + ""));
:他是这样声名的:
然后就要分析这个关键函数了:
这样的话第一个app的协议字段到此就分析完了
我输入的用户名是kanxue,密码是kanxue123
......大无语事件来了,data值明文传输
根据上一个app的分析,这回需要重点分析的应该是codeSign,nonce,access_token(这个介绍一下吧):
然后剩下的字段看着直接random就好了
然后就该定位了,还是把看着像的地方都下上断点,然后看看从哪里段下来就好了:(这个挺好的哈哈就三处断点,上一个app我下了9个,就是说,不要嫌麻烦,静下心来就好啦):
然后发现程序断在了这里:
这里我插一句,之前我说过JEB谁用谁说好...今天出bug了哈哈,这个JEB他有的时候不显示寄存器的值:
,然后用readvar v0 string还报错,这就无语了啊,这就得上Android stdio啦
定位到这个关键函数:
直接上代码分析过程了:
接下来这个函数new C5445g.C5461f()就是键值对的拼接了:
然后就要一个个看看各个字段对应的值是怎么生成的了:
nonce:先生成一个随机数,然后进行字符的替换
然后这几个就是明文,没有加密过程:
其他的几个也是直接明文传输,就不一一展示了
然后来看看这个加密的字段access_token:
然后就要分析这个东西了 C5414a.f16229h 跳过去看看:
接着跟进去分析,终于找到了定义他的地方了:
这个字段f16227f是获取versionname:
后面的几个是deviceid,还有网络信息:
最后再看看这个函数C6448r.m23455a()干了什么:
就是个md5加密就完了
最后重点看这个codesign字段:
第一个参数relaceall是随机生成的数字,然后进行了字符串的替换
第二个参数a是之前传入的
jsonobject中的data中的数据,就是明文的用户名和密码
第三个参数是当前的时间
然后就要跟进分析这个函数了:
这个函数的三个参数都分析完了,只有这个参数我们还不知道是什么 m23483a():
然后就要看这个函数了C6420af.m23337b()
这个是获取资源文件的函数
所以要想得到这个字段的值就要从资源文件中看看了:
这样所有字段的值都得到了,最后直接看看这个函数就好了 C6448r.m23455a()还是刚刚那个md5加密的函数:
这样这款app就分析完了
分析完上面两款app大家也可以发现,这些工具没有谁最好,只是都得使用,各有个的好处,上次说那个JEB yyds就打脸了哈哈,这个jadx也挺好的,一些代码直接翻译成人能看懂的了
这款app我用的真机,模拟器出了点问题,先登录:
然后抓包:
登录包中只有这两个数据:
这里如果只在key上面下断点是段不下来程序的(分析到后面就知道了,这个传输的字段叫key_id),所以这里我打算从post字段上下手
这里我搜索的是login_jsonp_active这个字段,然后定位到这里:
然后看那个API_LOGIN的交叉引用定位到了这里:
然后向下找找看看有没有突破点:
这个函数中有解密字段,还有用户名和结果,看着比较像:
然后继续看交叉引用,这里有解密的标志,所以这里看着比较像:
最终定位到了这里,发现了是key_id字段,不是key字段.....难怪下这么多断点都找不到他:
然后还发现了这个:发现他是des加密:
然后就要分析这个函数是怎么加密key_id字段了:
这个传入的参数中的map数据,在fiddler中得数据包中可以发现
,然后通过搜索sign字段也可以定位到在app中的位置:
分析完参数是啥,就要看看函数的具体操作了:
先声名一个stringbuffer变量
在将map中的数据转化为string类型
然后就是对key字段进行的加密了:那个 KEYS.get("1")在这个可以找到了值:应该是密钥
然后就要分析这个函数了:DESedeCoder.encode(json, KEYS.get("1"))
第一个参数是map中的数据,第二个参数是密钥
先将传入的字符串转化为byte类型,然后传入encrypt函数:继续跟进分析:
好了这款app的加密字段也分析完了
这个协议分析和找flag基本上是一样的,就是定位到关键字段和函数,然后分析加密过程,这次就先分享三个java层的吧,下次在分析so的,最近几天也是比较迷茫,一直在找课,再往深了学能白嫖的视频越来越少了,这几天找资料也浪费了不少时间,好在找到了一个适合自己的,又是一个新的提升阶段哈哈,看了看一共100多h的视频,之后一定做好记录分享给大家,其实看视频是一方面,更重要的是要实践,才能发现其中的问题于奥秘
http:
/
/
m.xxxx.com.cn
/
v2
/
member?modules
=
cloudlogin
%
3A1
&password
=
666666666
&siteid
=
10001
&sign
=
d01f5e4445af0a30d148d4dc451b41cf&clientid
=
1
&system_name
=
android
&
type
=
android
&time
=
1659366738640
&ip
=
10.0
.
2.15
&device_id
=
2a
%
3Aa5
%
3A33
%
3A2d
%
3Ade
%
3Ac9
&account
=
13905376666
HTTP
/
1.1
http:
/
/
m.xxxx.com.cn
/
v2
/
member?modules
=
cloudlogin
%
3A1
&password
=
666666666
&siteid
=
10001
&sign
=
d01f5e4445af0a30d148d4dc451b41cf&clientid
=
1
&system_name
=
android
&
type
=
android
&time
=
1659366738640
&ip
=
10.0
.
2.15
&device_id
=
2a
%
3Aa5
%
3A33
%
3A2d
%
3Ade
%
3Ac9
&account
=
13905376666
HTTP
/
1.1
public static String m8098a(HashMap<String, String> paramsMap, String time) {
/
/
传入两个参数,一个是
map
集合,一个是刚刚获取的time
LinkedHashMap<String, String> sortParams
=
new LinkedHashMap<>();
/
/
声名一个新的集合
Object
[] key_arr
=
paramsMap.keySet().toArray();
/
/
将
map
中的属性取出来,存放在key_arr数组里面
Arrays.sort(key_arr);
/
/
进行排序
for
(
Object
key : key_arr) {
try
{
sortParams.put(key.toString(), URLEncoder.encode(paramsMap.get(key).toString(),
"UTF-8"
));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/
/
将刚刚key_arr数组里面的值转化成string类型,然后将
map
中的数据进行url编码,然后将这两个数组组合成一个键值对放在新声名的sortParams中
StringBuilder result
=
new StringBuilder();
for
(
Map
.Entry<String, String> entry : sortParams.entrySet()) {
/
/
把刚刚处理完的sortParams中的值利用迭代器取出来放在entry变量中
if
(result.length() >
0
) {
result.append(
"&"
);
}
/
/
在每一个键值对后面用 & 连接
result.append(entry.getKey());
result.append(
"="
);
result.append(entry.getValue());
/
/
将键和值之间用
=
连接
}
/
/
这样就像发往服务器的包的结构了
String replace
=
result.toString().replace(
"*"
,
"%2A"
).replace(
"%7E"
,
"~"
).replace(
"+"
,
"%20"
);
/
/
将处理完的结果result在to string之后进行字符替换为replace
String resultMD5
=
MD5.md5(replace);
/
/
将replace进行md5加密之后为resultMD5
String
str
=
resultMD5
+
"1fa50ba25ed527f3fd1eb9467686f2bb"
+
time;
/
/
进行字符串拼接之后(加盐)转换为
str
String md5Result
=
MD5.md5(
str
);
/
/
将
str
在进行md5加密之后作为函数的返回值md5Result
return
md5Result;
/
/
返回的md5Result即为sign值
}
public static String m8098a(HashMap<String, String> paramsMap, String time) {
/
/
传入两个参数,一个是
map
集合,一个是刚刚获取的time
LinkedHashMap<String, String> sortParams
=
new LinkedHashMap<>();
/
/
声名一个新的集合
Object
[] key_arr
=
paramsMap.keySet().toArray();
/
/
将
map
中的属性取出来,存放在key_arr数组里面
Arrays.sort(key_arr);
/
/
进行排序
for
(
Object
key : key_arr) {
try
{
sortParams.put(key.toString(), URLEncoder.encode(paramsMap.get(key).toString(),
"UTF-8"
));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/
/
将刚刚key_arr数组里面的值转化成string类型,然后将
map
中的数据进行url编码,然后将这两个数组组合成一个键值对放在新声名的sortParams中
StringBuilder result
=
new StringBuilder();
for
(
Map
.Entry<String, String> entry : sortParams.entrySet()) {
/
/
把刚刚处理完的sortParams中的值利用迭代器取出来放在entry变量中
if
(result.length() >
0
) {
result.append(
"&"
);
}
/
/
在每一个键值对后面用 & 连接
result.append(entry.getKey());
result.append(
"="
);
result.append(entry.getValue());
/
/
将键和值之间用
=
连接
}
/
/
这样就像发往服务器的包的结构了
String replace
=
result.toString().replace(
"*"
,
"%2A"
).replace(
"%7E"
,
"~"
).replace(
"+"
,
"%20"
);
/
/
将处理完的结果result在to string之后进行字符替换为replace
String resultMD5
=
MD5.md5(replace);
/
/
将replace进行md5加密之后为resultMD5
String
str
=
resultMD5
+
"1fa50ba25ed527f3fd1eb9467686f2bb"
+
time;
/
/
进行字符串拼接之后(加盐)转换为
str
String md5Result
=
MD5.md5(
str
);
/
/
将
str
在进行md5加密之后作为函数的返回值md5Result
return
md5Result;
/
/
返回的md5Result即为sign值
}
POST http:
/
/
xxxx.xx8xx88xx.com
/
v2_2
/
user
/
login HTTP
/
1.1
nonce
=
b104cc74ade1441a9c61759fe330883c
&codeSign
=
2086B76A137CBA8B84DD1CBCAC3F7B45
×tamp
=
1659843481869
&data
=
%
7B
%
22params
%
22
%
3A
%
7B
%
22username
%
22
%
3A
%
22kanxue
%
22
%
2C
%
22password
%
22
%
3A
%
22kanxue123
%
22
%
7D
%
7D
&version
=
2.2
.
1
&product_version
=
220
&platform
=
HD1910
&network
=
1
&device
=
864282012982996
&access_token
=
62cb31ab6f2ffdaef382236aba9b98f4
&screen_width
=
1280
&screen_height
=
720
&bbsnopic
=
0
&system
=
2
&system_version
=
19
&theme
=
4
POST http:
/
/
xxxx.xx8xx88xx.com
/
v2_2
/
user
/
login HTTP
/
1.1
nonce
=
b104cc74ade1441a9c61759fe330883c
&codeSign
=
2086B76A137CBA8B84DD1CBCAC3F7B45
×tamp
=
1659843481869
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-8-8 21:12
被以和爲貴编辑
,原因: