Reverse

easy_js

js代码有obfuscator混淆
obfuscator解码
解码出来的代码修一修能跑

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
function _0x4a2285(_0x2b5a00) {

var _0x289ba9 = -92 * -67 + -6972 + 808;
while (true) {
var _0x3e831f = new Array(6);
_0x3e831f = ['0','2','3','4','5','1'];
switch (_0x3e831f[_0x289ba9++]) {
case '0':
var array = new Array(-1 * 3007 + -9073 + -24 * -514);
continue;
case '1':
return array_1;
case '2':
var _0x563e78_2;
var _0x1be492;
var _0x563e78_2_1;
continue;
case '3':
var array_1 = new Array(-517 * 11 + 927 + -1 * -5016);
continue;
case '4':
for (_0x563e78_2 = -2 * -2767 + 3191 + -349 * 25; _0x563e78_2 < 697 + -207 + -234; _0x563e78_2++) {
array_1[_0x563e78_2] = _0x563e78_2;
array[_0x563e78_2] = _0x2b5a00.charCodeAt(_0x563e78_2 % _0x2b5a00.length);
}
continue;
case '5':
for (_0x563e78_2 = _0x1be492 = -1 * 7016 + 19 * 508 + -2636; _0x563e78_2 < -8 * 887 + 11 * 741 + -799; _0x563e78_2++) {
_0x1be492 = (_0x1be492 + array_1[_0x563e78_2] + array[_0x563e78_2]) % (-3514 + -8 * -464 + 58);
_0x563e78_2_1 = array_1[_0x563e78_2];
array_1[_0x563e78_2] = array_1[_0x1be492];
array_1[_0x1be492] = _0x563e78_2_1;
}
continue;
}
break;
}
}
function _0x569454(_0x1f637f, _0x46bf6a) {
return String.fromCharCode(_0x1f637f.charCodeAt(1565 * -6 + -2452 * -4 + -11 * 38) + (-3292 * -1 + -587 * -3 + -5040)) + String.fromCharCode(_0x46bf6a.charCodeAt(-8452 + -2476 * 1 + -2732 * -4) - (-6933 + -3630 + 10564)) + 'wstar' + '_' + String.fromCharCode(_0x46bf6a.charCodeAt(1543 * -3 + -5469 + -10099 * -1) + (-1 * -2873 + 1654 + -73 * 62)) + String.fromCharCode(_0x1f637f.charCodeAt(471 * 3 + -2823 + 3 * 471) + (54 * -109 + -9295 + 15182)) + 's';
}
function _0x221c90(_0x2acf55, _0x549db3) {
var fromCharCode = '';
var array = new Array(-8 * 478 + 8657 * 1 + -1 * 4577);
array = _0x4a2285(_0x2acf55);
var _0x37dfd2_1;
var _0x3c262d;
var _0x37dfd2_1;
_0x37dfd2_1 = _0x3c262d = -1 * -613 + 8323 + -8936;
for (var _0x4ff9a6 = -6009 + -1 * 9956 + -3193 * -5; _0x4ff9a6 < _0x549db3.length; _0x4ff9a6++) {
_0x37dfd2_1 = (_0x37dfd2_1 + (-74 * 52 + 440 + 3409) + (-317 * -15 + 8530 + -13284)) % (-5528 + 5019 + 765);
_0x3c262d = (_0x3c262d + array[_0x37dfd2_1]) % (-2077 * -3 + -3001 * 1 + 1 * -2974);
_0x37dfd2_1 = array[_0x37dfd2_1];
array[_0x37dfd2_1] = array[_0x3c262d];
array[_0x3c262d] = _0x37dfd2_1;
fromCharCode += String.fromCharCode(_0x549db3.charCodeAt(_0x4ff9a6) ^ array[(array[_0x37dfd2_1] + array[_0x3c262d]) % (1631 * 5 + -1774 * 2 + -4351)] ^ 6545 + 1177 + -83 * 93);
}
return fromCharCode;
}
window._0x54cd23 = _0x54cd23_1;
var _0x24eb58 = window._0x54cd23;
function _0x54cd23_1(_0x3cc7e4) {
return btoa(_0x3cc7e4) === 'Cn8RHIJEVdvlrRESjETCscwQZdlhRfsRkWoHCTa0HcfLPg==';
}
function _0x499d16() {
var _0x3b2b6e = -5913 + 5062 + 851;
while (true) {
var _0x27b01d = new Array(5);
_0x27b01d = ['0','1','2','3','4'];
switch (_0x27b01d[_0x3b2b6e++]) {
case '0':
var value = document.getElementById('username').value;
continue;
case '1':
alert('来试试吧');
continue;
case '2':
var value_1 = document.getElementById('password').value;
continue;
case '3':
var value_2 = document.getElementById('flagtext').value;
continue;
case '4':
if (value === 'admin' && value_1 === '123456') {
var _0x4e60d2 = -23 * 121 + 251 * 37 + 1084 * -6;
while (true) {
var _0x32853b = new Array(5);
_0x32853b = ['4','0','2','3','1'];
switch (_0x32853b[_0x4e60d2++]) {
case '0':
alert('账号密码正确\uFF01再接再厉');
continue;
case '1':
if (_0x24eb58(_0x221c90_1)) {
alert('flag正确\uFF01');
} else {
alert('不行不行!');
};
continue;
case '2':
alert('正在验证flag------');
continue;
case '3':
var _0x221c90_1 = _0x221c90(_0x569454(value, value_1), value_2);
continue;
case '4':
alert('正在验证账号密码------');
continue;
}
break;
}
} else {
alert('不行不行');
}
continue;
}
break;
}
}

通过调试,整理代码,可以阅读出来,整体式一个rc4加密
_0x569454()为S盒生成函数, _0x221c90为rc4加密结果异或3
加密过程就是由_0x569454(‘admin’,‘123456’)生成S盒
然后rc4加密并异或3,最后base64得到’Cn8RHIJEVdvlrRESjETCscwQZdlhRfsRkWoHCTa0HcfLPg==’
由于rc4为对称加密,考虑直接调用_0x569454解密
直接用原来的js代码,在控制台里输入
document.write(_0x221c90(_0x569454('admin', '123456'), atob('Cn8RHIJEVdvlrRESjETCscwQZdlhRfsRkWoHCTa0HcfLPg==')));
img

flag

flag{h0w_you_know_h0w_t0_S1lve_js}

VM题,先把opcode dump出来

1
2
3
4
5
addr = 0x61FC5C
arr = []
for i in range(0,0x1AB,4):
arr.append(Dword(addr + i))
print(arr)

然后模拟一下VM过程

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
def F1(a1,a2,a3):
if (a3):
if (a3 == 1):
print(f'reg[{a1}] = reg[{a2}]')
elif (a3 == 2):
print(f'reg[{a1}] = flag[{a2}]')
else:
print(f'reg[{a1}] = {a2}')
def F2(a1,a2,a3):
if (a3):
if (a3 == 1):
print(f'reg[{a1}] += reg[{a2}]')
elif (a3 == 2):
print(f'reg[{a1}] += flag[{a2}]')
else:
print(f'reg[{a1}] += {a2}')
def F3(a1,a2):
print(f'reg[{a1}] <<= {a2}')
def F4(a1,a2):
print(f'reg[{a1}] ^= reg[{a2}]')
def F5(a1,a2):
print(f'reg[{a1}] >>= {a2}')
enc = [
0x1A, 0x62, 0xB9, 0x76, 0xDE, 0xAD, 0xE4, 0xCC, 0xC8, 0xBF, 0xC8, 0x25, 0x72, 0xD4, 0xC2, 0x16, 0x3A, 0xD5, 0x17, 0xF3, 0xA1, 0x11, 0xA1, 0xF2, 0xE6, 0xF0, 0x89, 0xDF, 0x23, 0xA6, 0xCD, 0xDC, 0x09, 0xF4, 0xC2, 0x21, 0x63, 0x8D, 0xD8, 0xDB]
opcode = [
240, 241, 0, 0, 2, 241, 1, 1, 2, 241, 3, 0, 0, 241, 2, 0, 0, 242, 3, 2654435769, 0, 241, 4, 1, 1, 245, 4, 5, 242, 4, 1, 2, 241, 5, 1, 1, 243, 5, 5, 242, 5, 0, 2, 244, 4, 5, 241, 5, 1, 1, 242, 5, 3, 1, 244, 4, 5, 242, 0, 4, 1, 241, 4, 0, 1, 245, 4, 5, 242, 4, 3, 2, 241, 5, 0, 1, 243, 5, 5, 242, 5, 2, 2, 244, 4, 5, 241, 5, 0, 1, 242, 5, 3, 1, 244, 4, 5, 242, 1, 4, 1, 242, 2, 1, 0, 255]
k = [2,0,2,3]
reg = [0]*5
flag = ''
i = 0
while(opcode[i] != 255):
if opcode[i] == 0xF0:
i += 1
elif opcode[i] == 0xF1:
F1(opcode[i+1], opcode[i+2], opcode[i+3])
i += 4
elif opcode[i] == 0xF2:
F2(opcode[i+1], opcode[i+2], opcode[i+3])
i += 4
elif opcode[i] == 0xF3:
F3(opcode[i+1], opcode[i+2])
i += 3
elif opcode[i] == 0xF4:
F4(opcode[i+1], opcode[i+2])
i += 3
elif opcode[i] == 0xF5:
F5(opcode[i+1], opcode[i+2])
i += 3
"""
reg[0] = flag[0]
reg[1] = flag[1]
reg[3] = 0
reg[2] = 0
reg[3] += 2654435769
reg[4] = reg[1]
reg[4] >>= 5
reg[4] += flag[1]
reg[5] = reg[1]
reg[5] <<= 5
reg[5] += flag[0]
reg[4] ^= reg[5]
reg[5] = reg[1]
reg[5] += reg[3]
reg[4] ^= reg[5]
reg[0] += reg[4]
reg[4] = reg[0]
reg[4] >>= 5
reg[4] += flag[3]
reg[5] = reg[0]
reg[5] <<= 5
reg[5] += flag[2]
reg[4] ^= reg[5]
reg[5] = reg[0]
reg[5] += reg[3]
reg[4] ^= reg[5]
reg[1] += reg[4]
reg[2] += 1
"""

阅读一下可以得到F0-F6含义如下

1
2
3
4
5
6
7
0xF0 init
0xF1 mov
0xF2 add
0xF3 shl
0xF4 xor
0xF5 shr
0xF6 judge

结合栈空间的操作大致可以猜出来是tea,轮次40轮,两个位移都改成了5
看不出来也没关系 signsrch 也可以识别出来有个tea的常数delta
img

exp

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
#include <stdio.h>
#include <stdint.h>

void encrypt (uint32_t* v, uint32_t* k) {
uint32_t sum = 0;
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i=0; i<32; i++) {
sum += delta;
v0 += ((v1<<5) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<5) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
}

v[0]=v0;
v[1]=v1;
}

void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t sum = delta * 40;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i=0; i<40; i++) {
v1 -= ((v0<<5) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<5) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
}

v[0]=v0;
v[1]=v1;
}

int main(){
uint32_t v[] = {0x76B9621A, 0xCCE4ADDE, 0x25C8BFC8, 0x16C2D472, 0xF317D53A, 0xF2A111A1, 0xDF89F0E6, 0xDCCDA623,
0x21C2F409, 0xDBD88D63};
uint32_t k[4]= {2,0,2,3};
for(int i=0; i<5; i++) decrypt(v + i*2, k);
printf("%s", (char *)v);
return 0;
}
/*
flag{WOWOW!Y0uG0tTh3F0urthPZGALAXY1eve1}
*/

flag

flag{WOWOW!Y0uG0tTh3F0urthPZGALAXY1eve1}

iwannarest

先用jadx 看看MainActivity
img
encode 函数在native层
进入\iwannarest\lib\x86_64 看看so文件
so文件里面没有encode但是函数较少,可以猜到zzz应该就是encode(后面看了官方wp才知道是采用了动态注册的方式去注册native层函数)
zzz应该是个xxtea,并且findcrypt插件也识别出来了
img
直接解应该解不出来,再观察发现init函数内修改了key,值是[1,1,4,5]
img
写脚本梭

exp

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
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define DELTA 0x9E3779B9
#define MX (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[(p & 3) ^ e] ^ z)

void xxtea_encrypt(uint32_t *v, uint32_t len, uint32_t *k) {
uint32_t n = len - 1;
uint32_t y, z, sum = 0, e, p, q;
q = 6 + 52 / len;
while (q-- > 0) {
sum += DELTA;
e = sum >> 2 & 3;
for (p = 0; p < n; p++) {
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n] += MX;
}
}

void xxtea_decrypt(uint32_t *v, uint32_t len, uint32_t *k) {
uint32_t n = len - 1;
uint32_t y, z, sum, e, p, q;
q = 6 + 52 / len;
sum = q * DELTA;
y = v[0];
while (sum != 0) {
e = sum >> 2 & 3;
for (p = n; p > 0; p--) {
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n];
y = v[0] -= MX;
sum -= DELTA;
}
}

int main() {
uint32_t v[8] = {
3962803346,3145558623,1541010058,1093420299,
3315082129,861271549,352576336,60051825, };
uint32_t key[4] = { 1,1,4,5 };
uint32_t i;
uint32_t temp[2];
for (i = 0; i < 8; i += 2){
temp[0] = v[i];
temp[1] = v[i + 1];
xxtea_decrypt(temp, 2, key);
v[i] = temp[0];
v[i + 1] = temp[1];
}
printf("%s", (char *)v);
return 0;
}
//flag{GDu7Il0v3uP1zl3tm3Gr@duate}?

flag

flag{GDu7Il0v3uP1zl3tm3Gr@duate}

简单的跨栏

先看MainActivity
这部分应该是个反调试
img
这部分生成S盒,交换,异或,一眼RC4
img
这部分先用key="runrunrun"RC4加密输入然后调用了native层的encode
img
去so中找找逻辑
在xxx中发现了密文
img
然后b64中明显的变表base64
img
写脚本梭,对密文先解base64,然后用key='runrunrun'解rc4但是结果一直是错的
因为在java字符串传递到jni接口时,采用了GetStringUtfChars,这个函数会自动采用utf-8的解码格式。
我们需要将base64解密后的utf-8编码的数据转化为对应的Unicode编码

UTF-8编码,是Unicode的一种可变长度字符编码,是Unicode的一种实现方式,又称万国码;UTF8使用1~4字节为每个字符编码,相对于Unicode 固定的四字节长度,更节省存储空间。UTF-8字节长度与Unicode 码点对应关系如下:
一字节(0x00-0x7F)-> U+00~U+7F
二字节(0xC280-0xDFBF)-> U+80~U+7FF
三字节(0xE0A080-0xEFBFBF)-> U+800~U+FFFF
四字节(0xF0908080-0xF48FBFBF)-> U+10000~U+10FFFF
字符U+0000到U+007F(ASCII)被编码为字节0×00到0x7F(ASCIⅡ兼容)。这意味着只包含7位ASCIl字符的文件在ASCIⅡ和UTF-8两种编码方式下是一样的。
所有大于0x007F的字符被编码为一个有多个字节的串,每个字节都有标记位集,常用汉字基本上都被编码成三字节。

exp

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
from Crypto.Cipher import ARC4
import base64
def custom_base64_decode(data):
custom_chars = '0123456789ABCMtuvwxNOPQRabcdefghijklSTUVWXDEFGHIJKLYZmnopqrsyz+/'
# 创建标准Base64字符集和自定义字符集的映射表
base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
char_map = str.maketrans( custom_chars, base64_chars)
# 替换为自定义字符
data = data.translate(char_map)
# 使用标准Base64解码
decoded_data = list(base64.b64decode(data.encode()))
return decoded_data
enc = 'Jr0VJ81KJD1PJpY2WytxgeAnJWu2H1qutyA0xFtyJrZHJrZeJrM8ATCWJWft9FtgJsV2SCtR4yASJrE2Uv=='
data = custom_base64_decode(enc)
result = []

i = 0
while i < len(data):
byte = data[i]
if byte == 0xc0 and i+1 < len(data) and data[i+1] == 0x80:
result.append(0x00)
i += 2
elif 0x00 <= byte <= 0x7F:
result.append(byte)
i += 1
elif 0xC0 <= byte <= 0xDF and i+1 < len(data):
char = bytes([data[i], data[i+1]])
decoded = char.decode('utf-8', errors='ignore')
if decoded:
result.append(ord(decoded))
else:
result.append(byte)
i += 2
elif 0xE0 <= byte <= 0xEF and i+2 < len(data):
char = bytes([data[i], data[i+1], data[i+2]])
decoded = char.decode('utf-8', errors='ignore')
if decoded:
result.append(ord(decoded))
else:
result.append(byte)
i += 3
else:
result.append(byte)
i += 1
# print(result)
a = [
0xe0,0x27,0x00,0x71,0xa0,0x55,0xcc,0xa3,0xd2,0x79,
0xb6,0x83,0xb8,0x1e,0x4f,0x3b,0x80,0x4a,0xfc,0xed,
0x2e,0xed,0x1c,0xe3,0x48,0x2a,0x53,0x28,0x87,0x4e,
0x26,0xde,0xf9,0x90,0xd7,0x13,0xa4,0xea,0x99]
key = b'runrunrun'

enc = b''.join([bytes([i]) for i in result])
rc4 = ARC4.new(key)
decrypted_data = rc4.decrypt(enc)
print(decrypted_data.decode('utf-8'))
# flag{DED3D3DED3DE03DEBUG1sfunnyr1gh7??}

flag

flag{DED3D3DED3DE03DEBUG1sfunnyr1gh7??}