描述
package: com.tlamb96.spetsnazmessenger
目标
找到Flag
APK下载
https://yhxx.lanzoue.com/iwnao22p7pda
题解
首先打开APP看一下,检测到只能运行在俄罗斯版的设备上,需要先过设备检测。
Jadx-GUI打开找到设备检测的位置,发现用System.getProperty("user.home")
来获取设备类型,同时发现还用到System.getenv("USER")
增加了用户白名单检测,白名单用户是R.string.User
。
想找用户字符串很简单,Android的字符串资源都存储在/res/values/strings.xml
中,可以使用apktool工具解压apk文件查看apktool d base.apk
。或者直接在Jadx-GUI的路径/资源文件/resources.arsc/res/values/strings.xml
中查看。
打开xml文件后可以看到名为User的字符串值:RkxBR3s1N0VSTDFOR180UkNIM1J9Cg==
即为白名单用户。
hook以上两个函数就可以过检测了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function passCheck() {
Java.perform(function () {
var System = Java.use('java.lang.System');
System.getProperty.overload('java.lang.String').implementation = function (name) {
if (name == 'user.home') return 'Russia';
return this.getProperty(name);
};
System.getenv.overload('java.lang.String').implementation = function (name) {
if (name == 'USER') return 'RkxBR3s1N0VSTDFOR180UkNIM1J9Cg==';
return this.getProperty(name);
};
});
}
function main() {
passCheck();
}
setImmediate(main);
|
打开APP没有提示了,显示需要输入用户名密码进入APP
用Jadx-GUI继续看APP,找到登陆页,发现用户名依旧是从资源里面取username
,拿到是codenameduchess
。密码是在j()
方法中对比。
打开j()
方法,发现是md5对比,md5字符串是从资源里面取password
,拿到是84e343a0486ff05530df6c705c8bb4
。这是一个非标准md5,需要进行补0,直接去百度搜md5原文,或者hook j()方法,搜索得到明文是guest
。
输入用户名codenameduchess
和密码guest
进入APP,显示是个聊天页,需要发送正确消息。
用Jadx-GUI继续看APP,找到发送消息页,发现是在i()
方法中获得flag,但是i()
方法需要用到this.q
和this.s
。
继续看可以找到this.q
和this.s
是在onSendMessage()
方法中生成的,而要生成this.s
和this.q
又需要用到a()
方法和b()
方法。
a()
方法比较简单,直接用本地进行还原。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
from z3 import *
from binascii import b2a_hex, a2b_hex
def question1():
char_array = list("V@]EAASB\u0012WZF\u0012e,a$7(&am2(3.\u0003")
length = len(char_array)
for i in range(length // 2):
c = char_array[length - i - 1]
char_array[length - i - 1] = chr(ord(char_array[i]) ^ ord('2'))
char_array[i] = chr(ord(c) ^ ord('A'))
print(''.join(char_array))
def main():
question1()
if __name__ == "__main__":
main()
# output: Boris, give me the password
|
b()
方法较a()
方法难度提升,同时有不可见字符,直接逆向推导函数会有不可见字符,使用Z3-Solver进行推导。
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
|
from z3 import *
from binascii import b2a_hex, a2b_hex
def question2():
r = "\u0000dslp}oQ\u0000 dks$|M\u0000h +AYQg\u0000P*!M$gQ\u0000"
r_result = bytearray(a2b_hex(''.join(f'{ord(c):02x}' for c in r)))
for i in range(int(len(r_result) / 2)):
c = r_result[i]
r_result[i] = r_result[len(r_result) - i - 1]
r_result[len(r_result) - i - 1] = c
s = Solver()
x = [BitVec("x%s" % i, 32) for i in range(len(r_result))]
for i in range(len(r_result)):
c = r_result[i]
s.add(((x[i] >> (i % 8)) ^ x[i]) == r_result[i]) #z3
s.add(x[i] >= 0, x[i] <= 255)
if (s.check() == sat):
model = (s.model())
flag = ""
for i in range(len(r_result)):
if (model[x[i]] != None):
value = model[x[i]].as_long().real
flag += " " if value == 0 else chr(value)
else:
flag += " "
print('"' + flag + '"')
def main():
question2()
if __name__ == "__main__":
main()
# output: " ay I *P EASE* h ve the assword "
|
将密码输入APP,密码正确,密码为ay I *P EASE* h ve the assword
。(由于加密的字符中有许多ascii为0的字符无法正确推导,所以也可以对output中的空格进行替换,得到:May I *PLEASE* hive the password?
)