bugku-re-easy-100


OnCreate就是执行p函数,创建一个监听d类的onclick事件。而p函数就是读取url.png[144:160]的数据
1.png

mainactivity的代码

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
public class MainActivity extends q {
private String v;

static String a(MainActivity arg1) {
return arg1.v; // 返回字符串v。就是url.png[144:160]的数据
}

static boolean a(MainActivity arg1, String arg2, String arg3) {
return arg1.a(arg2, arg3); // 这个a函数调用了下面两个参数的a函数
}

private boolean a(String arg4, String arg5) { // arg4是v,arg5是输入的密码。调用c类的a函数和后面的做比较。如果相等就输出flag
return new c().a(arg4, arg5).equals("\u0015\uFFFD\uFFFD\uFFFDVu\uFFFD!2v\u0010\r\u0001\uFFFD\uFFFD\u0003\u0004g\uFFFDQ\u001ED6\uFFFD,\uFFFD]b\u0005;");
}

@Override // android.support.v7.a.q
protected void onCreate(Bundle arg3) {
super.onCreate(arg3);
this.setContentView(0x7F04001A); // layout:activity_main
ApplicationInfo v0 = this.getApplicationInfo();
v0.flags &= 2;
this.p(); // 执行p函数,并且创建监听d类的onclick事件
((Button)this.findViewById(0x7F0B0055)).setOnClickListener(new d(this)); // id:sureButton
}

private void p() { // 整个p就是读取url.png[144:160]的数据
try { // 以输入流读取assets下的url.png
InputStream v0_1 = this.getResources().getAssets().open("url.png"); // 以输入流读取assets下的url.png
int v1 = v0_1.available(); // 获取文件大小
byte[] v2 = new byte[v1]; // 定义缓冲数组的长度
v0_1.read(v2, 0, v1); // 从v0_1中每次读取v1个字节放在v2第0位开始的地方。在这里直接把v1读入v2
byte[] v0_2 = new byte[16]; // 定义一个16位的数组v0_2,用来存url.png[144:160]的数据
System.arraycopy(((Object)v2), 0x90, ((Object)v0_2), 0, 16); // v2的144位开始复制16位给v0_2(从第0位开始)
this.v = new String(v0_2, "utf-8"); // v就是url.png的[144:160]的数据
}
catch(Exception v0) {
v0.printStackTrace(); // 捕获异常,相当于py的except
}
}
}


再来看d类,判断是否正确,正确就输出flag。
if的第一个参数是this.a(句柄),第二个是调用只有一个参数的a类a函数,第三个则是v0(我们输入的字符串)

2.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class d implements View.OnClickListener {
final MainActivity a;

d(MainActivity arg1) {
this.a = arg1;
super();
}

@Override // android.view.View$OnClickListener
public void onClick(View arg5) {
String v0 = ((EditText)this.a.findViewById(0x7F0B0056)).getText().toString(); // id:passCode
if(MainActivity.a(this.a, MainActivity.a(this.a), v0)) { // 如果判断正确就返回flag。第一个参数是this.a(句柄),第二个是调用只有一个参数的a类a函数,第三个则是v0(我们输入的字符串)
TextView v0_1 = (TextView)this.a.findViewById(0x7F0B0054); // id:textView
Toast.makeText(this.a.getApplicationContext(), "Congratulations!", 1).show();
v0_1.setText(0x7F060022); // string:nice "Congratulations!"
return;
}

Toast.makeText(this.a.getApplicationContext(), "Oh no.", 1).show();
}
}

在看a类的三个3函数
第一个a函数只有一个参数,就是字符串v。就是图片[144:160]的数据
第二个a函数有三个参数,调用了有两个参数的a函数
第三个a函数有两个参数,arg4是v,arg5是输入的密码。调用c类的a函数和后面的做比较。如果相等就输出flag
3.png
9.png

1
2
3
4
5
6
7
8
9
10
11
static String a(MainActivity arg1) {
return arg1.v; // 返回字符串v。就是url.png[144:160]的数据
}

static boolean a(MainActivity arg1, String arg2, String arg3) {
return arg1.a(arg2, arg3); // 这个a函数调用了下面两个参数的a函数
}

private boolean a(String arg4, String arg5) { // arg4是v,arg5是输入的密码。调用c类的a函数和后面的做比较。如果相等就输出flag
return new c().a(arg4, arg5).equals("\u0015\uFFFD\uFFFD\uFFFDVu\uFFFD!2v\u0010\r\u0001\uFFFD\uFFFD\u0003\u0004g\uFFFDQ\u001ED6\uFFFD,\uFFFD]b\u0005;");
}

再来看c类,就是对之前从图片里提出来的字符串在进行加工。主要就是置换,两位为一个单位来置换。
4.png

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
public class c {
private String a(String arg4) {
try {
arg4.getBytes("utf-8");
StringBuilder v1 = new StringBuilder();
int v0_1; // v0_1是循环变量,for循环则是把arg4按照2位一组的形式,前后调换位置
for(v0_1 = 0; v0_1 < arg4.length(); v0_1 += 2) { // v0_1是循环变量,for循环则是把arg4按照2位一组的形式,前后调换位置
v1.append(arg4.charAt(v0_1 + 1));
v1.append(arg4.charAt(v0_1));
}

return v1.toString();
}
catch(UnsupportedEncodingException v0) {
v0.printStackTrace();
return null;
}
}

public String a(String arg5, String arg6) {
String v0 = this.a(arg5);
a v2 = new a();
v2.a(v0.getBytes());
try {
return new String(v2.b(arg6.getBytes()), "utf-8");
}
catch(Exception v0_1) {
v0_1.printStackTrace();
return "";
}
}

a类就是aes的加密
5.png

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
public class a {
private SecretKeySpec a;
private Cipher b;

protected void a(byte[] arg4) {
if(arg4 != null) {
goto label_15;
}

try {
byte[] v0_3 = "".getBytes("utf-8");
this.a = new SecretKeySpec(MessageDigest.getInstance("MD5").digest(v0_3), "AES");
this.b = Cipher.getInstance("AES/ECB/PKCS5Padding");
return;
label_15:
this.a = new SecretKeySpec(arg4, "AES"); // 根据arg4的字节数生成aes密钥
this.b = Cipher.getInstance("AES/ECB/PKCS5Padding"); // 根据指定aes算法生成密码器
}
catch(UnsupportedEncodingException v0_2) {
v0_2.printStackTrace();
}
catch(NoSuchAlgorithmException v0_1) {
v0_1.printStackTrace();
}
catch(NoSuchPaddingException v0) {
v0.printStackTrace();
}
}
}


6.png

1
2
3
4
protected byte[] b(byte[] arg4) {
this.b.init(1, this.a); // 初始化密码器,第一个参数作为加密或者解密操作,第二个参数是key
return this.b.doFinal(arg4); // 将数据加密
}

python解密脚本
7.png

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
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex

#equals比较的字节数组
byteArray =[21, -93, -68, -94, 86, 117, -19, -68, -92, 33,
50, 118, 16, 13, 1, -15, -13, 3, 4, 103, -18,
81, 30, 68, 54, -93, 44, -23, 93, 98, 5, 59]
#读取图片
with open('url.png','rb') as f:
p =f.read()
str1 =p[144:144+16]
# 字节数组转字符串
byte2str = str1.decode()
print("图片[144:144+16]字符串:"+ byte2str)
# 图片[144:144+16]字符串:this_is_the_key.

# 前后两个字符一组,互换位置,密钥字符串
str2 =""
for i in range(0,len(str1),2):
str2 += chr(str1[i+1])
str2 += chr(str1[i])
print("返回互换位置后的图片字符串:" + str2)

# 把密文字节数组转换为16进制字符串
str3 =""
for i in byteArray:
s=str(hex((i+256)%256)) # 负的变成正的,在转16进制
if len(s) <4:
s = s[0:2]+'0'+s[2:] #判断,不足4位就补零
str3+=s[2:] # 去掉前面的0x
print(str3)
#密文 15a3bca25675edbca4213276100d01f1f3030467ee511e4436a32ce95d62053b

# AES算法解密,ECB的工作模式,PKCS5Padding 的填充
# 去掉 PKCS5Padding 的填充
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
# 通过 密钥,工作模式ECB 进行初始化密码器
cipher = AES.new(str2.encode(), AES.MODE_ECB)
# a2b_hex()16进制转字符串,之后密码器解密字符串,再用unpad表达式去掉 PKCS5Padding 的填充,最后指定utf8的编码格式将bytes解码成字符串str
data_response = unpad(cipher.decrypt(a2b_hex(str3))).decode('utf8')
print("解密得到的明文密码flag:"+data_response)

也可以自己尝试提出url.png中的内容
8.png


自己可以用在线aes解密,python2写脚本。base64 encode加密完后丢解密网站,修改填充和加上密码。
10.png

1
2
3
4
5
6
7
8
9
10
import base64

str1 = [21, -93, -68, -94, 86, 117, -19, -68, -92, 33,50, 118, 16, 13, 1, -15, -13, 3, 4, 103, -18, 81, 30, 68, 54, -93, 44, -23, 93, 98, 5, 59]
ctext = ''
for i in str1:
ctext += chr((i+256)%256)

a = base64.b64encode(ctext)
# print(ctext)
print(a)

程序逻辑:

mainactivity->p()->d->a->c->脚本

脚本逻辑:

取图片里的字符串->字符串置换->密文转hex->脚本closed

参考:

https://blog.csdn.net/Onlyone_1314/article/details/108836559