这是2W班8月份的练习题第一题。题目要求是
参考文档:https://bbs.pediy.com/thread-260422.htm
本题加密流程已经由大佬给出,也就是在大佬的基础上进行取证。对Brida的使用花费了多一点的时间。
另外当时做这题的时候,自己对frida的操作还是停留在根据内存分布去处理数据,而10月课程学习后,其实有很多更简便兼容性也更强的方式。
这里的代码都是对应于7月份老版本的HOOK。新版本需要重新找hook点。
参考文档中已经给出了APP的加密流程和解密代码。这里就不再分析APP的加密,只是打印出解密后的数据。
直接定位图片解密函数,保存返回值。
可以保存但是速度极慢,因为不知道怎么取出result的地址,所以就新建buffer重写了一遍在保存。
这样下载图片速度不会影响app的正常运行了,只是批量下载需要滑动触发图片加载。
大量读取的话,还是用原作者写好的分页查询图片,然后依次下载脱离app运行方便很多,这里就下载一点测试。
由于解密的函数com.ilulutv.fulao2.other.g.b.a大多接口都会调用。这里我只想显示m3u8的数据,所以打印了堆栈,向上找了一些定位到了c.c.a.h.a.c.a。
这个函数应该是不同类型http请求解密后呈现数据的方法。筛选82018就是m3u8解密的数据。
这边就直接使用send打印出数据了。
这里app本身需要代理才能播放视频,但是ffmpeg下载确没有什么限制,可能是其他接口被干掉导致播放不了。
ffmpeg.exe -protocol_whitelist "file,http,crypto,tcp,https,tls" -i test.m3u8 -c copy test.mp4
根据作者给出的命令下载正常播放,确定解密的视频数据正确。
BurpSuite安装Brida从BApp Store直接安装比较方便,这里只有最新版,其他版本就是用jar包在Extensions中添加
配置碰到一些小坑,因为要求是最新版0.4版本,网上教程大多数是0.3版本的教程。所以直接看官方文档才能避免这些问题。
0.4版本主要更新是新增了Custonm Plugins选项卡,有4种类型的内部插件使用也比较方便。
还有一点就是RPC导出的函数没必要hex转来转去,直接使用字符串就可以了。如果是老版本代码去掉hexToString,stringToHex的调用即可。
Win10我配置后console.log获取不到打印,不知道什么原因,然后kali正常,后面测试也都是在kali上。
最开始写代码最好在Debug export中测试正常后再使用插件调用
1.首先使用Brida的IConetxtMenu添加右键菜单,在Repeater请求后右键选择添加的菜单解密。
2.接下来使用IHttpListener自动修改Repeater的返回值
3.都顺利后可以自动解密Proxy中所有带X-VTag的返回数据,配置和上一步差不多,只是不替换resphone,单纯打印
这样解密的日志可以直接在console中查看,这里是复制出来的数据,将其他类型的数据也一起打印出来了。
调用app解密函数代码就比较简单了
var class_decimg
=
Java.use(
"com.ilulutv.fulao2.other.g.b"
);
class_decimg.b.overload(
'[B'
,
'[B'
,
'java.lang.String'
).implementation
=
function(bArr, bArr2,
str
){
var result
=
this.b(bArr, bArr2,
str
);
imgResult
=
result;
console.log(
"imgResult.length->"
, imgResult.length);
var fileName
=
"/sdcard/fulao2/"
+
imgResult.length
+
".jpg"
;
try
{
var
buffer
=
Memory.alloc(imgResult.length);
for
(var i
=
0
;i<imgResult.length;i
+
+
){
var ival
=
imgResult[i];
if
(ival <
0
) {
ival
+
=
256
;
}
/
/
console.log(
"buffer:"
,
buffer
.add(i),ival);
buffer
.add(i).writeU8(ival);
/
/
imgResult[i]
}
console.log(
"buffer:"
, hexdump(
buffer
));
var fd
=
new
File
(fileName,
"ab+"
);
if
(fd && fd !
=
null) {
var dex_buffer
=
ptr(
buffer
).readByteArray(imgResult.length);
fd.write(dex_buffer);
fd.flush();
fd.close();
console.log(
"[dump img]:"
, fileName);
}
}
catch(error){
console.log(
"write_file_log error:"
,error);
}
return
result;
}
var class_decimg
=
Java.use(
"com.ilulutv.fulao2.other.g.b"
);
class_decimg.b.overload(
'[B'
,
'[B'
,
'java.lang.String'
).implementation
=
function(bArr, bArr2,
str
){
var result
=
this.b(bArr, bArr2,
str
);
imgResult
=
result;
console.log(
"imgResult.length->"
, imgResult.length);
var fileName
=
"/sdcard/fulao2/"
+
imgResult.length
+
".jpg"
;
try
{
var
buffer
=
Memory.alloc(imgResult.length);
for
(var i
=
0
;i<imgResult.length;i
+
+
){
var ival
=
imgResult[i];
if
(ival <
0
) {
ival
+
=
256
;
}
/
/
console.log(
"buffer:"
,
buffer
.add(i),ival);
buffer
.add(i).writeU8(ival);
/
/
imgResult[i]
}
console.log(
"buffer:"
, hexdump(
buffer
));
var fd
=
new
File
(fileName,
"ab+"
);
if
(fd && fd !
=
null) {
var dex_buffer
=
ptr(
buffer
).readByteArray(imgResult.length);
fd.write(dex_buffer);
fd.flush();
fd.close();
console.log(
"[dump img]:"
, fileName);
}
}
catch(error){
console.log(
"write_file_log error:"
,error);
}
return
result;
}
class_decimg.a
-
> [
object
Object
]
class_decimg.a
-
>
56439
buffer
:
0
1
2
3
4
5
6
7
8
9
A B C D E F
0123456789ABCDEF
95e7f148
ff d8 ff e0
00
10
4a
46
49
46
00
01
01
00
00
01
......JFIF......
95e7f158
00
01
00
00
ff fe
00
3b
43
52
45
41
54
4f
52
3a
.......;CREATOR:
95e7f168
20
67
64
2d
6a
70
65
67
20
76
31
2e
30
20
28
75
gd
-
jpeg v1.
0
(u
95e7f178
73
69
6e
67
20
49
4a
47
20
4a
50
45
47
20
76
36
sing IJG JPEG v6
95e7f188
32
29
2c
20
71
75
61
6c
69
74
79
20
3d
20
39
30
2
), quality
=
90
95e7f198
0a
ff db
00
43
00
03
02
02
03
02
02
03
03
03
03
....C...........
95e7f1a8
04
03
03
04
05
08
05
05
04
04
05
0a
07
07
06
08
................
95e7f1b8
0c
0a
0c
0c
0b
0a
0b
0b
0d
0e
12
10
0d
0e
11
0e
................
95e7f1c8
0b
0b
10
16
10
11
13
14
15
15
15
0c
0f
17
18
16
................
95e7f1d8
14
18
12
14
15
14
ff db
00
43
01
03
04
04
05
04
.........C......
95e7f1e8
05
09
05
05
09
14
0d
0b
0d
14
14
14
14
14
14
14
................
95e7f1f8
14
14
14
14
14
14
14
14
14
14
14
14
14
14
14
14
................
95e7f208
14
14
14
14
14
14
14
14
14
14
14
14
14
14
14
14
................
95e7f218
14
14
14
14
14
14
14
14
14
14
14
ff c0
00
11
08
................
95e7f228
01
ca
03
1b
03
01
22
00
02
11
01
03
11
01
ff c4 ......".........
95e7f238
00
1f
00
00
01
05
01
01
01
01
01
01
00
00
00
00
................
[dump img]:
/
sdcard
/
fulao2
/
56439.jpg
class_decimg.a
-
> [
object
Object
]
class_decimg.a
-
>
56439
buffer
:
0
1
2
3
4
5
6
7
8
9
A B C D E F
0123456789ABCDEF
95e7f148
ff d8 ff e0
00
10
4a
46
49
46
00
01
01
00
00
01
......JFIF......
95e7f158
00
01
00
00
ff fe
00
3b
43
52
45
41
54
4f
52
3a
.......;CREATOR:
95e7f168
20
67
64
2d
6a
70
65
67
20
76
31
2e
30
20
28
75
gd
-
jpeg v1.
0
(u
95e7f178
73
69
6e
67
20
49
4a
47
20
4a
50
45
47
20
76
36
sing IJG JPEG v6
95e7f188
32
29
2c
20
71
75
61
6c
69
74
79
20
3d
20
39
30
2
), quality
=
90
95e7f198
0a
ff db
00
43
00
03
02
02
03
02
02
03
03
03
03
....C...........
95e7f1a8
04
03
03
04
05
08
05
05
04
04
05
0a
07
07
06
08
................
95e7f1b8
0c
0a
0c
0c
0b
0a
0b
0b
0d
0e
12
10
0d
0e
11
0e
................
95e7f1c8
0b
0b
10
16
10
11
13
14
15
15
15
0c
0f
17
18
16
................
95e7f1d8
14
18
12
14
15
14
ff db
00
43
01
03
04
04
05
04
.........C......
95e7f1e8
05
09
05
05
09
14
0d
0b
0d
14
14
14
14
14
14
14
................
95e7f1f8
14
14
14
14
14
14
14
14
14
14
14
14
14
14
14
14
................
95e7f208
14
14
14
14
14
14
14
14
14
14
14
14
14
14
14
14
................
95e7f218
14
14
14
14
14
14
14
14
14
14
14
ff c0
00
11
08
................
95e7f228
01
ca
03
1b
03
01
22
00
02
11
01
03
11
01
ff c4 ......".........
95e7f238
00
1f
00
00
01
05
01
01
01
01
01
01
00
00
00
00
................
[dump img]:
/
sdcard
/
fulao2
/
56439.jpg
var class_decimg
=
Java.use(
"com.ilulutv.fulao2.other.g.b"
);
class_decimg.b.overload(
'[B'
,
'[B'
,
'java.lang.String'
).implementation
=
function(bArr, bArr2,
str
){
var result
=
this.b(bArr, bArr2,
str
);
imgBase64Arr[imginx
+
+
]
=
gson.$new().toJson(result);
return
result;
}
rpc.exports
=
{
getimgarr : function(i){
var result
=
'';
if
(i
in
imgBase64Arr){
try
{
result
=
imgBase64Arr[i];
console.log(
"imgBase64Arr[i] result->"
, result.length);
}
catch(error){
console.log(error);
}
}
else
{
console.log(
"i in imgBase64Arr false"
);
}
return
result;
},
getimginx : function(){
return
imginx;
},
clearimgarr: function(start,
len
){
for
(var i
=
0
; i<
len
;i
+
+
){
/
/
imgBase64Arr[start
+
i]
=
"clear"
;
delete imgBase64Arr[start
+
i];
}
}
}
var class_decimg
=
Java.use(
"com.ilulutv.fulao2.other.g.b"
);
class_decimg.b.overload(
'[B'
,
'[B'
,
'java.lang.String'
).implementation
=
function(bArr, bArr2,
str
){
var result
=
this.b(bArr, bArr2,
str
);
imgBase64Arr[imginx
+
+
]
=
gson.$new().toJson(result);
return
result;
}
rpc.exports
=
{
getimgarr : function(i){
var result
=
'';
if
(i
in
imgBase64Arr){
try
{
result
=
imgBase64Arr[i];
console.log(
"imgBase64Arr[i] result->"
, result.length);
}
catch(error){
console.log(error);
}
}
else
{
console.log(
"i in imgBase64Arr false"
);
}
return
result;
},
getimginx : function(){
return
imginx;
},
clearimgarr: function(start,
len
){
for
(var i
=
0
; i<
len
;i
+
+
){
/
/
imgBase64Arr[start
+
i]
=
"clear"
;
delete imgBase64Arr[start
+
i];
}
}
}
def
downImg(imgDataStr):
try
:
ms
=
re.findall(
"(-?\d+)"
, imgDataStr)
intArr
=
[]
for
m
in
ms:
ival
=
int
(m)
if
ival <
0
:
ival
+
=
256
intArr.append(ival)
bs
=
bytes(intArr)
m
=
hashlib.md5()
m.update(bs)
downname
=
m.hexdigest()
with
open
(
"download/"
+
downname
+
".jpg"
,
'ab'
) as f:
f.write(bs)
print
(
"download sucess->"
+
downname
+
".jpg"
)
except
Exception as e:
print
(
"downImg Error->"
)
imginx
=
0
while
True
:
try
:
imgArrValue
=
script.exports.getimginx()
while
imgArrValue > imginx:
imgobj
=
script.exports.getimgarr(imginx)
downImg(imgobj)
script.exports.clearimgarr(imginx,
1
)
imginx
+
=
1
print
(imgArrValue)
time.sleep(
3
)
except
Exception as ex:
print
(
"Error:"
, ex)
break
def
downImg(imgDataStr):
try
:
ms
=
re.findall(
"(-?\d+)"
, imgDataStr)
intArr
=
[]
for
m
in
ms:
ival
=
int
(m)
if
ival <
0
:
ival
+
=
256
intArr.append(ival)
bs
=
bytes(intArr)
m
=
hashlib.md5()
m.update(bs)
downname
=
m.hexdigest()
with
open
(
"download/"
+
downname
+
".jpg"
,
'ab'
) as f:
f.write(bs)
print
(
"download sucess->"
+
downname
+
".jpg"
)
except
Exception as e:
print
(
"downImg Error->"
)
imginx
=
0
while
True
:
try
:
imgArrValue
=
script.exports.getimginx()
while
imgArrValue > imginx:
imgobj
=
script.exports.getimgarr(imginx)
downImg(imgobj)
script.exports.clearimgarr(imginx,
1
)
imginx
+
=
1
print
(imgArrValue)
time.sleep(
3
)
except
Exception as ex:
print
(
"Error:"
, ex)
break
public void a(String
str
,
int
i2) {
switch (i2) {
case
82000
:
VideoInfoGson videoInfoGson
=
(VideoInfoGson) a(
str
, (Class<?>) VideoInfoGson.
class
);
a(videoInfoGson.getStatus().getCode(), videoInfoGson.getStatus().getMessage(), videoInfoGson, this);
return
;
case
82001
:
com.ilulutv.fulao2.other.b.t
=
str
;
g.m(
str
);
if
(
str
.isEmpty()) {
Crashlytics.logException(new Exception(
"BC"
+
str
));
}
MenuTitleGson menuTitleGson
=
(MenuTitleGson) a(
str
, (Class<?>) MenuTitleGson.
class
);
if
(g.v0()) {
g.e(menuTitleGson.getResponse().getMenus().getUncoverX().size());
}
else
{
g.e(
0
);
}
if
(g.u0()) {
g.d(menuTitleGson.getResponse().getMenus().getCoverX().size());
}
else
{
g.d(
0
);
}
a(menuTitleGson.getStatus().getCode(), menuTitleGson.getStatus().getMessage(), menuTitleGson, this);
return
;
case
82002
:
LikeGson likeGson
=
(LikeGson) a(
str
, (Class<?>) LikeGson.
class
);
a(likeGson.getStatus().getCode(), likeGson.getStatus().getMessage(), likeGson, this);
return
;
case
82003
:
ReportVideoGson reportVideoGson
=
(ReportVideoGson) a(
str
, (Class<?>) ReportVideoGson.
class
);
a(reportVideoGson.getStatus().getCode(), reportVideoGson.getStatus().getMessage(), reportVideoGson, this);
return
;
case
82004
:
VideoListGson videoListGson
=
(VideoListGson) a(
str
, (Class<?>) VideoListGson.
class
);
a(videoListGson.getStatus().getCode(), videoListGson.getStatus().getMessage(), videoListGson, this);
return
;
case
82005
:
c(
str
);
return
;
case
82006
:
AdGson2 adGson2
=
(AdGson2) a(
str
, (Class<?>) AdGson2.
class
);
a(adGson2.getStatus().getCode(), adGson2.getStatus().getMessage(), adGson2, this);
return
;
case
82007
:
ActorInfoGson actorInfoGson
=
(ActorInfoGson) a(
str
, (Class<?>) ActorInfoGson.
class
);
a(actorInfoGson.getStatus().getCode(), actorInfoGson.getStatus().getMessage(), actorInfoGson, this);
return
;
case
82008
:
a(
str
);
return
;
case
82009
:
VideoLikeListGson videoLikeListGson
=
(VideoLikeListGson) a(
str
, (Class<?>) VideoLikeListGson.
class
);
a(videoLikeListGson.getStatus().getCode(), videoLikeListGson.getStatus().getMessage(), videoLikeListGson, this);
return
;
case
82010
:
e(
str
);
return
;
case
82011
:
d(
str
);
return
;
case
82012
:
CurrentOrderGson currentOrderGson
=
(CurrentOrderGson) a(
str
, (Class<?>) CurrentOrderGson.
class
);
a(currentOrderGson.getStatus().getCode(), currentOrderGson.getStatus().getMessage(), currentOrderGson, this);
return
;
case
82013
:
HistoryOrdersGson historyOrdersGson
=
(HistoryOrdersGson) a(
str
, (Class<?>) HistoryOrdersGson.
class
);
a(historyOrdersGson.getStatus().getCode(), historyOrdersGson.getStatus().getMessage(), historyOrdersGson, this);
return
;
case
82014
:
g(
str
);
return
;
case
82015
:
f(
str
);
return
;
case
82016
:
UserInfoGson userInfoGson
=
(UserInfoGson) a(
str
, (Class<?>) UserInfoGson.
class
);
a(userInfoGson.getStatus().getCode(), userInfoGson.getStatus().getMessage(), userInfoGson, this);
return
;
case
82017
:
AddUserSourceGson addUserSourceGson
=
(AddUserSourceGson) a(
str
, (Class<?>) AddUserSourceGson.
class
);
a(addUserSourceGson.getStatus().getCode(), addUserSourceGson.getStatus().getMessage(), addUserSourceGson, this);
return
;
case
82018
:
a((
Object
)
str
);
return
;
case
82019
:
WatchHistoryListsGson watchHistoryListsGson
=
(WatchHistoryListsGson) a(
str
, (Class<?>) WatchHistoryListsGson.
class
);
a(watchHistoryListsGson.getStatus().getCode(), watchHistoryListsGson.getStatus().getMessage(), watchHistoryListsGson, this);
return
;
case
82020
:
b(
str
);
return
;
case
82021
:
NoticeListGson noticeListGson
=
(NoticeListGson) a(
str
, (Class<?>) NoticeListGson.
class
);
a(noticeListGson.getStatus().getCode(), noticeListGson.getStatus().getMessage(), noticeListGson, this);
return
;
case
82022
:
NoticeListGsonTwo noticeListGsonTwo
=
(NoticeListGsonTwo) a(
str
, (Class<?>) NoticeListGsonTwo.
class
);
a(noticeListGsonTwo.getStatus().getCode(), noticeListGsonTwo.getStatus().getMessage(), noticeListGsonTwo, this);
return
;
default:
return
;
}
}
public void a(String
str
,
int
i2) {
switch (i2) {
case
82000
:
VideoInfoGson videoInfoGson
=
(VideoInfoGson) a(
str
, (Class<?>) VideoInfoGson.
class
);
a(videoInfoGson.getStatus().getCode(), videoInfoGson.getStatus().getMessage(), videoInfoGson, this);
return
;
case
82001
:
com.ilulutv.fulao2.other.b.t
=
str
;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)