CNSS_2023_Recruit_Reverse_EASY_WriteUp

🍵[EASY]茶杯头大冒险

考点

加解密:

  • 位运算和异或操作
  • 迭代加密

说的是简单的Tea加密。。这个名字我还以为是。。。

Tea

“TEA” 的全称为**”Tiny Encryption Algorithm”** 是1994年由英国剑桥大学的David j.wheeler发明的.。就是微型加密算法。

TAG:分组加密;64位明文分组和128位密钥;存在缺陷,设计者提出XTEA,组织密钥表攻击,速度更慢;

加密函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Encrypt(long* EntryData, long* Key)
{
//分别加密数组中的前四个字节与后4个字节,4个字节为一组每次加密两组
unsigned long x = EntryData[0];
unsigned long y = EntryData[1];

unsigned long sum = 0;
unsigned long delta = 0x9E3779B9;
//总共加密32轮
for (int i = 0; i < 32; i++)
{
sum += delta;
x += ((y << 4) + Key[0]) ^ (y + sum) ^ ((y >> 5) + Key[1]);
y += ((x << 4) + Key[2]) ^ (x + sum) ^ ((x >> 5) + Key[3]);
}
//最后加密的结果重新写入到数组中
EntryData[0] = x;
EntryData[1] = y;
}

解密思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
x +=xxx

y+=xxx 这两个公式总共是执行了32轮,可以记做为

(x+=xxx)32

(y+=xxx)32
那么解密的时候肯定也是执行32轮,每次递减,且顺序变换过来
(y-=xxx)
(x-=xxx)
其中这里的xxx就是异或的公式,根据其特性我们不需要改公式中的内容.我们可以看做是 a ^ b ^ c 反过来
c ^ b ^ a 是一样的.
既然倒过来了.我们的变量(黄金分割)32轮的和也要依次递减来进行解密
所以解密算法如下
  • 其中用了异或的一个重要特性:c=a^b,那么我们一直c求a一样的 a=c^b。反正逆向直接抄

算法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void Decrypt(long* EntryData, long* Key)
{
//分别加密数组中的前四个字节与后4个字节,4个字节为一组每次加密两组
unsigned long x = EntryData[0];
unsigned long y = EntryData[1];

unsigned long sum = 0;
unsigned long delta = 0x9E3779B9;
sum = delta << 5; //注意这里,sum = 32轮之后的黄金分割值. 因为我们要反序解密. delta左移五位就是×32
//总共加密32轮 那么反序也解密32轮
for (int i = 0; i < 32; i++)
{

// 先将y解开 然后参与运算在解x
y -= ((x << 4) + Key[2]) ^ (x + sum) ^ ((x >> 5) + Key[3]);
x -= ((y << 4) + Key[0]) ^ (y + sum) ^ ((y >> 5) + Key[1]);
sum -= delta;
}
//最后加密的结果重新写入到数组中
EntryData[0] = x;
EntryData[1] = y;
}

分析

  • F5
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
int __fastcall main(int argc, const char **argv, const char **envp)
{
_DWORD Str[8]; // [rsp+20h] [rbp-60h] BYREF
int v5[8]; // [rsp+40h] [rbp-40h]
unsigned int v6[6]; // [rsp+60h] [rbp-20h] BYREF
int j; // [rsp+78h] [rbp-8h]
int i; // [rsp+7Ch] [rbp-4h]

_main();
v6[0] = 429459223; 32位 -> v6 : 32*4=128位 -> 密钥
v6[1] = 537200643;
v6[2] = 537462290;
v6[3] = 537006083;
v5[0] = -999025570;
v5[1] = 970203505;
v5[2] = -181949973;
v5[3] = -483739382;
v5[4] = 1062983671;
v5[5] = -697079924;
printf("input the flag: \\n");
scanf("%s", Str);
if ( strlen((const char *)Str) == 24 ){
for ( i = 0; i <= 4; ++i ){
encrypt(&Str[i], v6);
for ( j = 0; j <= 5; ++j ){
if ( Str[j] != v5[j] ){
printf("it's not my teapot!");
return 0;
}
}
printf("Oh my god, you made it?!");
system("pause");
return 0;
}
else{
printf("the length is NSFW~~~");
return 0;
}
}
  • strlen((const char *)Str) == 24 说明flag是24位

关键应该是encrpt函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 __fastcall encrypt(unsigned int *a1, unsigned int *a2)  //encrypt(&Str[i], v6);
{
__int64 result; // rax
unsigned int i; // [rsp+10h] [rbp-10h]
unsigned int v4; // [rsp+14h] [rbp-Ch]
unsigned int v5; // [rsp+18h] [rbp-8h]
unsigned int v6; // [rsp+1Ch] [rbp-4h]

v6 = *a1; //v6=a1=&str[i]
v5 = a1[1]; //v5=str[i+1]
v4 = 0;
for ( i = 0; i <= 0x1F; ++i )
{
v6 += (((v5 >> 5) ^ (16 * v5)) + v5) ^ (a2[v4 & 3] + v4);
v4 += 289739793;
v5 += (((v6 >> 5) ^ (16 * v6)) + v6) ^ (a2[(v4 >> 11) & 3] + v4);
}
*a1 = v6;
result = v5;
a1[1] = v5;
return result;
}

查了一下(看出题人解释,发现就是Tea加密。

Untitled

先处理main()函数逆向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def main():	{
Str = [0] * 6 # 一组长度位4
key = [429459223, 537200643, 537462290, 537006083]
res = [0xC474145E, 0x39D42171, 0xF527A9EB, 0xE32AB90A, 0x3F5BD7F7, 0xD673678C]

for i in range(5):
decrypt(res[i:i+1], key)

print(res)

res_array = bytearray()
for hex_res in res:
res_array += hex_res.to_bytes(4, byteorder='big')
print(res_array )

再处理decrypt()函数逆向

1
2
3
4
5
6
7
8
9
10
11
12
def decrypt(res, key): 
x = res[0]
y = res[1]

delta = 0x114514
z = delta << 4
for i in range(32):
y -= (((x >> 5) ^ (x << 4)) + x) ^ (key[(z >> 11) & 3] + z) #注意先解y
z -= delda
x -= (((y >> 5) ^ (y << 4)) + y) ^ (key[z & 3] + z)
Flag[0] = x
Flag[1] = y

放弃python了。分组加密还是用数据类型强的语言吧,而且我也不熟练。就用cpp

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
#include <cstdio>
#include <cstdint>

void decrypt(int32_t* v, uint32_t* key)
{
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 289739793;
uint32_t sum = delta << 5;

for (int i = 0; i < 32; i++)
{
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}

v[0] = v0;
v[1] = v1;
//printf(" %d %d----",v[0],v[1]);
return ;
}

int main()
{
uint32_t key[4];
key[0] = 429459223;
key[1] = 537200643;
key[2] = 537462290;
key[3] = 537006083;

int32_t enc[12];
enc[0] = -999025570;
enc[1] = 970203505;
enc[2] = -181949973;
enc[3] = -483739382;
enc[4] = 1062983671;
enc[5] = -697079924;

for (int i = 4; i >= 0; i--)
decrypt(&enc[i], key);

for (int i = 0; i <= 5; i++)
{
printf("%c", enc[i] & 0xFF);
printf("%c", (enc[i] & 0xFF00) >> 8);
printf("%c", (enc[i] & 0xFF0000) >> 16);
printf("%c", (enc[i] & 0xFF000000) >> 24);
}
putchar('\\n');
return 0;
}
  • 终于python调试出来,python函数也需要return,其次& 0XFFFFFFFF 注意使用规范
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
def decrypt(res, key):
x, y = res[0] & 0xFFFFFFFF, res[1] & 0xFFFFFFFF
delta = 289739793
z = delta * 32

for i in range(32):
y -= (((x << 4) ^ (x >> 5)) + x) ^ (key[(z >> 11) & 3] + z)
y = y & 0xFFFFFFFF #这里很重要!
z -= delta
z = z & 0xFFFFFFFF
x -= (((y << 4) ^ (y >> 5)) + y) ^ (key[z & 3] + z)
x = x & 0xFFFFFFFF

res[0], res[1] = x, y
#print(res[0], ' ', res[1])
return res[0],res[1] # 一次性return两个出去

def main():
key = [0x19990717, 0x20050803, 0x20090612, 0x20021003]
res = [0xC474145E, 0x39D42171, 0xF527A9EB, 0xE32AB90A, 0x3F5BD7F7, 0xD673678C]

for i in range(4, -1, -1):
res[i],res[i+1] = decrypt(res[i:], key)

decrypted_string = ''.join([chr((res[i] >> j) & 0xFF) for i in range(6) for j in range(0, 32, 8)])
print(decrypted_string)

if __name__ == "__main__":
main()

复盘

  • 自我感觉用python坑的地方在十六进制数据转换为字符串部分,还有分组运算的溢出问题
  • 用cpp写,转不转换成无符号整数都不影响,用不用十六进制表示数字也不影响,比较方便吧

✈️[EASY] 打飞机高手

考点

  • (动态调试)
  • patch
  • 机器码和汇编转换

分析

  • F5
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
int __fastcall main(int argc, const char **argv, const char **envp)
{
_main(argc, argv, envp);
Startup();
while ( IsOver )
{
UpdateInput();
UpdateNormal();
Show();
}
printf("\\t\\tYou Are so WEAK!\\n");
Sleep(0x9C4u);
system("pause");
return 0;
}

void Startup()
{
unsigned int v0; // eax
int j; // [rsp+28h] [rbp-8h]
int i; // [rsp+2Ch] [rbp-4h]

IsOver = 1;
score = 0i64;
for ( i = 0; i <= 26; ++i )
{
for ( j = 0; j <= 61; ++j )
{
if ( i && i != 26 && j && j != 61 )
canvas[62 * i + j] = 0;
else
canvas[62 * i + j] = -1;
}
}
pos_h = 12;
pos_w = 30;
canvas[774] = 1;
enemynum = 3;
v0 = time(0i64);
srand(v0);
interval = 4;
itv_move = 5;
itv_new = 40;
}
  • 发现里面的函数都非常复杂,而且看不懂。
  • 试着打开exe发现就是打飞机游戏,应该代码很多,不是简单的解密
  • 其中show函数中有getflag,看起来是patch了

关键逻辑在show()

1
2
3
4
5
6
7
8
result = score;
if ( score > 1145141918 )
{
printf("\\t\\tWell Done! You got the flag!\\n\\t\\t");
get_flag();
Sleep(0x9C4u);
return system("pause");
}

把里面的114514那段改成1的数字就是了。

  • 先打断点debug然后找到汇编地方
  • edit里面选择patch
image-20240227132325833

最后一步:apply patches to input file

然后debuger重新启动,getflag!

image-20240227132402713

复盘

  • 学会使用IDA进行patch
  • 注意patch的时候格式,最好还是就使用字节码替换吧
  • 记得``apply patches to input file`

💥[EASY]爆了爆了,和java爆了

考点

  • 安卓 apk 逆向
  • base64 加密

分析

  • 解压之后是apk,搜了一下Android逆向,可以使用apktool解压apk文件,获取源码
1
D:\app\\apktool>java -jar apktool.jar d ezAndroid.apk -o ./demo

解释:

  • original 目录:保存了原始的 AndroidManifest.xml 和签名信息
  • res 目录:应用程序的资源文件目录,包含了应用程序的布局文件、字符串资源、图片资源等。
  • smali 目录:应用程序的 Smali 代码目录,包含了应用程序的所有 Smali 代码文件(Smali 就是字节码)
  • assets 目录:应用程序的 assets 目录,包含了应用程序需要使用的各种资源文件,例如音频、视频、图片、配置文件等。
  • lib 目录:应用程序的库目录,包含了应用程序需要使用的库文件,例如 so 文件等。
  • AndroidManifest.xml:应用程序的清单文件,包含应用程序的名称、包名、版本号、权限等信息。
  • apktool.yml:是 APKTool 工具使用的配置文件,用于指定反编译和打包 APK 文件时的各种参数和选项。
  • 又用jadx反编译了一下

先查看AndroidManifest.xml 里面信息,发现可疑信息

1
2
3
<activity android:exported="false" android:name="com.cnss.myapplication.o0o0o000o"/>
<activity android:exported="false" android:name="com.cnss.myapplication.o0o0o0o0oo"/>
<activity android:exported="true" android:name="com.cnss.myapplication.MainActivity">

于是找到这三个文件。其中o0o0o000o 中包含很多可疑函数,这应该就是这道题的关键了

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
public class o0o0o000o extends AppCompatActivity {
private String Hint = "key is a meaningful string.";
private String i1 = "SJNPhthkmYBHow5Y75wRDa==";
private String i2 = "RoBAU/g/jlxuy+Ns1YtA86==";
···
private String i100 = "cIU9ZQpjiINPy/kOw31OEa==";
private char[] str = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};

/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_o0o0o000o);
Button btn = (Button) findViewById(R.id.flagBtn);
final EditText flagInput = (EditText) findViewById(R.id.flagEdt);
final TextView flagOut = (TextView) findViewById(R.id.flagOUt);
btn.setOnClickListener(new View.OnClickListener() { // from class: com.cnss.myapplication.o0o0o000o.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
String s = o0o0o000o.this.decode(String.valueOf(flagInput.getText()));
try {
flagOut.setText(o0o0o000o.this.qvq(s));
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e2) {
throw new RuntimeException(e2);
} catch (BadPaddingException e3) {
throw new RuntimeException(e3);
} catch (IllegalBlockSizeException e4) {
throw new RuntimeException(e4);
} catch (NoSuchPaddingException e5) {
throw new RuntimeException(e5);
}
}
});
}

public String decode(String code) {
int length = code.length();
if (length == 0 || length % 4 != 0) {
return null;
}
int endEqualNum = 0;
if (code.endsWith("==")) {
endEqualNum = 2;
} else if (code.endsWith("=")) {
endEqualNum = 1;
}
code.replace('=', '0');
StringBuilder sb = new StringBuilder(length);
int blockNum = length / 4;
for (int i = 0; i < blockNum; i++) {
String afterDecode = decodeDetail(code.substring(i * 4, (i * 4) + 4));
sb.append(afterDecode);
}
String result = sb.toString();
return result.substring(0, result.length() - endEqualNum);
}

private String decodeDetail(String str) {
int len = str.length();
if (len != 4) {
return null;
}
int a1 = getIndex(str.charAt(0));
qwq();
int a2 = getIndex(str.charAt(1));
qwq();
int a3 = getIndex(str.charAt(2));
qwq();
int a4 = getIndex(str.charAt(3));
qwq();
char[] b = {(char) ((a1 << 2) | ((a2 & 48) >> 4)), (char) (((a2 & 15) << 4) | ((a3 & 60) >> 2)), (char) (((a3 & 3) << 6) | a4)};
return String.copyValueOf(b);
}

private int getIndex(char c) {
int i = 0;
while (true) {
char[] cArr = this.str;
if (i < cArr.length) {
if (cArr[i] != c) {
i++;
} else {
return i;
}
} else {
return -1;
}
}
}

private void qwq() {
char[] tmp = new char[64];
int i = 0;
while (true) {
char[] cArr = this.str;
if (i < cArr.length) {
tmp[i] = cArr[(i + 2) % 64];
i++;
} else {
this.str = (char[]) tmp.clone();
return;
}
}
/* JADX INFO: Access modifiers changed from: private */
public String qvq(String keyStr) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] eBytes = Base64.decode("11VaDwVeOwKvL6eqb2hsA2rb0wTbTRwsb7WirGpBW8s=".getBytes(), 0);
SecretKeySpec mykey = new SecretKeySpec(keyStr.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(2, mykey);
return new String(cipher.doFinal(eBytes));
}
} //才看到还有这个
  • 用雷电模拟器打开apk看看怎么个事儿

    • 打开就让find the botton

      image-20240227132837822
    • 呃呃,右下角一个小绿块。真无语了

    image-20240227132901653
  • 想到 **class** o0o0o0o0oo 里的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    public void onClick(View view) {
    if (o0o0o0o0oo.this.packetInput.getText().toString().equals("com.cnss.myapplication")) {
    Toast.makeText(o0o0o0o0oo.this, "Go to the final page", 0).show();
    o0o0o0o0oo.this.startActivity(new Intent(o0o0o0o0oo.this, o0o0o000o.class));
    return;
    }
    Toast.makeText(o0o0o0o0oo.this, "Plz find the packet name", 0).show();
    }
  • 所以是:com.cnss.myapplication

    image-20240227132926272
  • 最后一步了,肯定就是o0o0o000o里面那串一眼base64加密

onclick逻辑:

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
String s = o0o0o000o.this.decode(String.valueOf(flagInput.getText()));
try {
flagOut.setText(o0o0o000o.this.qvq(s));
} catch
decode(flagInput.getText())
public String decode(String code) {
int length = code.length();
if (length == 0 || length % 4 != 0) { //flag为4的倍数
return null;
}
int endEqualNum = 0;
if (code.endsWith("==")) {
endEqualNum = 2;
} else if (code.endsWith("=")) {
endEqualNum = 1;
} //计算'='的数量
code.replace('=', '0');
StringBuilder sb = new StringBuilder(length);
int blockNum = length / 4;
for (int i = 0; i < blockNum; i++) {
String afterDecode = decodeDetail(code.substring(i * 4, (i * 4) + 4));
sb.append(afterDecode);
}
String result = sb.toString();
return result.substring(0, result.length() - endEqualNum);
}
  • decode 是 base64 的解码,decode_detail 逻辑就是四个字符,分别解密然后转成三个明文字符。但是每解密一次就执行 qwq()
  • qwq() 进行了 base64 字符表的右移,相当于每次解密字符表都不同。
  • 然后总逻辑是:对输入的值进行decode(base64变种),然后放进qvq 作为 key 进行aes 解密。
  • 提示 key is a meaningful str
  • 因此,思路就是把上面那些串都拿去解密。因为那些串:去掉末尾两个=,再将中间的=替换为0,就是标准的可以解密的 base64 密文。因此不管怎么样都要先把那100个解密了
  • 直接抄他的逻辑用 java 跑
  • 解密出来发现一个 meaningful str
  • 直接传进 app 中
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
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class Test {
private String Hint = "key is a meaningful string.";

private char[] str = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};

public static void main(String[] args) {
Test test = new Test();
String c = test.i3;
String a[] = {"SJNPhthkmYBHow5Y75wRDa==", ···,};
for(int i=0;i<100;i++){
String s = test.decode(a[i]);
System.out.println(a[i]);
System.out.println(s);
}
}

public String decode(String code) {
int length = code.length();
if (length == 0 || length % 4 != 0) {
return null;
}
int endEqualNum = 0;
if (code.endsWith("==")) {
endEqualNum = 2;
} else if (code.endsWith("=")) {
endEqualNum = 1;
}
code.replace('=', '0');
StringBuilder sb = new StringBuilder(length);
int blockNum = length / 4;
for (int i = 0; i < blockNum; i++) {
String afterDecode = decodeDetail(code.substring(i * 4, (i * 4) + 4));
sb.append(afterDecode);
}
String result = sb.toString();
return result.substring(0, result.length() - endEqualNum);
}

private String decodeDetail(String str) {
int len = str.length();
if (len != 4) {
return null;
}
int a1 = getIndex(str.charAt(0));
qwq();
int a2 = getIndex(str.charAt(1));
qwq();
int a3 = getIndex(str.charAt(2));
qwq();
int a4 = getIndex(str.charAt(3));
qwq();
char[] b = {(char) ((a1 << 2) | ((a2 & 48) >> 4)), (char) (((a2 & 15) << 4) | ((a3 & 60) >> 2)), (char) (((a3 & 3) << 6) | a4)};
return String.copyValueOf(b);
}

private int getIndex(char c) {
int i = 0;
while (true) {
char[] cArr = this.str;
if (i < cArr.length) {
if (cArr[i] != c) {
i++;
} else {
return i;
}
} else {
return -1;
}
}
}

private void qwq() {
char[] tmp = new char[64];
int i = 0;
while (true) {
char[] cArr = this.str;
if (i < cArr.length) {
tmp[i] = cArr[(i + 2) % 64];
i++;
} else {
this.str = (char[]) tmp.clone();
return;
}
}
}