java 混淆字符串_Java逆向基础之ZKM字符串混淆与还原

本文详细介绍了ZKM字符串混淆技术,包括早期的简单异或加密和后续的流加密方法。混淆后的代码通过复杂的异或和流密码方式加密字符串,反编译后代码长达1000行。通过分析,作者给出了静态代码块的异或解密方法和a方法的流密码解密方法,展示了如何解密混淆的字符串并输出`Hello`和`World`。

为了防止静态分析,ZMK在混淆时对输出的字符串使用对称加密方法进行加密

早期的ZKM只在静态代码块的时候进行简单的异或加密,后续版本使用了流加密技术进行二次加密

看一个简单的字符串输出例子package com.vvvtimes.main;

public class Main {

public static void main(String[] args) {

System.out.println("Hello");

System.out.println("World");

}

}

混淆反编译之后的代码//

// Source code recreated from a .class file by IntelliJ IDEA

// (powered by Fernflower decompiler)

//

package com.vvvtimes.main;

public class a {

public static int a;

public static int b;

private static String[] c;

private static String[] d;

public a() {

}

public static void main(String[] var0) {

int var10000 = b;

System.out.println(a(-7991, 8444));

int var1 = var10000;

System.out.println(a(-7992, -25829));

if (var1 != 0) {

int var2 = a;

++var2;

a = var2;

}

}

static {

String[] var5 = new String[2];

int var3 = 0;

String var2 = "\u0093íè[Í\u0005ükçÀú";

int var4 = var2.length();

char var1 = 5;

int var0 = -1;

boolean flag =true;

while(flag) {

char[] var10002;

label41: {

++var0;

char[] var10001 = var2.substring(var0, var0 + var1).toCharArray();

int var10003 = var10001.length;

int var6 = 0;

var10002 = var10001;

int var7 = var10003;

char[] var9;

int var10004;

if (var10003 <= 1) {

var9 = var10001;

var10004 = var6;

} else {

var10002 = var10001;

var7 = var10003;

if (var10003 <= var6) {

break label41;

}

var9 = var10001;

var10004 = var6;

}

while(true) {

char var10005 = var9[var10004];

byte var10006;

switch(var6 % 7) {

case 0:

var10006 = 116;

break;

case 1:

var10006 = 91;

break;

case 2:

var10006 = 57;

break;

case 3:

var10006 = 40;

break;

case 4:

var10006 = 121;

break;

case 5:

var10006 = 92;

break;

default:

var10006 = 118;

}

var9[var10004] = (char)(var10005 ^ var10006);

++var6;

if (var7 == 0) {

var10004 = var7;

var9 = var10002;

} else {

if (var7 <= var6) {

break;

}

var9 = var10002;

var10004 = var6;

}

}

}

String var11 = (new String(var10002)).intern();

var5[var3++] = var11;

if ((var0 += var1) >= var4) {

c = var5;

d = new String[2];

flag=false;

}else{

var1 = var2.charAt(var0);

}

}

}

private static String a(int var0, int var1) {

int var2 = (var0 ^ -7991) & '\uffff';

if (d[var2] == null) {

char[] var3 = c[var2].toCharArray();

short var10000;

switch(var3[0] & 255) {

case 0:

var10000 = 181;

break;

case 1:

var10000 = 149;

break;

case 2:

var10000 = 85;

break;

case 3:

var10000 = 171;

break;

case 4:

var10000 = 128;

break;

case 5:

var10000 = 103;

break;

case 6:

var10000 = 238;

break;

case 7:

var10000 = 159;

break;

case 8:

var10000 = 225;

break;

case 9:

var10000 = 234;

break;

case 10:

var10000 = 14;

break;

case 11:

var10000 = 200;

break;

case 12:

var10000 = 138;

break;

case 13:

var10000 = 205;

break;

case 14:

var10000 = 127;

break;

case 15:

var10000 = 50;

break;

case 16:

var10000 = 186;

break;

case 17:

var10000 = 169;

break;

case 18:

var10000 = 68;

break;

case 19:

var10000 = 61;

break;

case 20:

var10000 = 10;

break;

case 21:

var10000 = 46;

break;

case 22:

var10000 = 121;

break;

case 23:

var10000 = 230;

break;

case 24:

var10000 = 80;

break;

case 25:

var10000 = 89;

break;

case 26:

var10000 = 0;

break;

case 27:

var10000 = 24;

break;

case 28:

var10000 = 167;

break;

case 29:

var10000 = 5;

break;

case 30:

var10000 = 132;

break;

case 31:

var10000 = 53;

break;

case 32:

var10000 = 81;

break;

case 33:

var10000 = 231;

break;

case 34:

var10000 = 141;

break;

case 35:

var10000 = 251;

break;

case 36:

var10000 = 241;

break;

case 37:

var10000 = 219;

break;

case 38:

var10000 = 173;

break;

case 39:

var10000 = 20;

break;

case 40:

var10000 = 38;

break;

case 41:

var10000 = 182;

break;

case 42:

var10000 = 229;

break;

case 43:

var10000 = 67;

break;

case 44:

var10000 = 183;

break;

case 45:

var10000 = 188;

break;

case 46:

var10000 = 222;

break;

case 47:

var10000 = 107;

break;

case 48:

var10000 = 248;

break;

case 49:

var10000 = 244;

break;

case 50:

var10000 = 156;

break;

case 51:

var10000 = 88;

break;

case 52:

var10000 = 246;

break;

case 53:

var10000 = 240;

break;

case 54:

var10000 = 13;

break;

case 55:

var10000 = 211;

break;

case 56:

var10000 = 49;

break;

case 57:

var10000 = 144;

break;

case 58:

var10000 = 40;

break;

case 59:

var10000 = 21;

break;

case 60:

var10000 = 130;

break;

case 61:

var10000 = 179;

break;

case 62:

var10000 = 202;

break;

case 63:

var10000 = 194;

break;

case 64:

var10000 = 201;

break;

case 65:

var10000 = 174;

break;

case 66:

var10000 = 117;

break;

case 67:

var10000 = 99;

break;

case 68:

var10000 = 137;

break;

case 69:

var10000 = 6;

break;

case 70:

var10000 = 12;

break;

case 71:

var10000 = 153;

break;

case 72:

var10000 = 213;

break;

case 73:

var10000 = 206;

break;

case 74:

var10000 = 93;

break;

case 75:

var10000 = 249;

break;

case 76:

var10000 = 33;

break;

case 77:

var10000 = 28;

break;

case 78:

var10000 = 120;

break;

case 79:

var10000 = 95;

break;

case 80:

var10000 = 37;

break;

case 81:

var10000 = 4;

break;

case 82:

var10000 = 55;

break;

case 83:

var10000 = 237;

break;

case 84:

var10000 = 102;

break;

case 85:

var10000 = 196;

break;

case 86:

var10000 = 34;

break;

case 87:

var10000 = 216;

break;

case 88:

var10000 = 143;

break;

case 89:

var10000 = 98;

break;

case 90:

var10000 = 133;

break;

case 91:

var10000 = 94;

break;

case 92:

var10000 = 203;

break;

case 93:

var10000 = 254;

break;

case 94:

var10000 = 92;

break;

case 95:

var10000 = 2;

break;

case 96:

var10000 = 16;

break;

case 97:

var10000 = 124;

break;

case 98:

var10000 = 48;

break;

case 99:

var10000 = 11;

break;

case 100:

var10000 = 3;

break;

case 101:

var10000 = 163;

break;

case 102:

var10000 = 221;

break;

case 103:

var10000 = 195;

break;

case 104:

var10000 = 192;

break;

case 105:

var10000 = 59;

break;

case 106:

var10000 = 119;

break;

case 107:

var10000 = 161;

break;

case 108:

var10000 = 72;

break;

case 109:

var10000 = 29;

break;

case 110:

var10000 = 160;

break;

case 111:

var10000 = 224;

break;

case 112:

var10000 = 198;

break;

case 113:

var10000 = 41;

break;

case 114:

var10000 = 42;

break;

case 115:

var10000 = 65;

break;

case 116:

var10000 = 114;

break;

case 117:

var10000 = 136;

break;

case 118:

var10000 = 176;

break;

case 119:

var10000 = 22;

break;

case 120:

var10000 = 122;

break;

case 121:

var10000 = 209;

break;

case 122:

var10000 = 129;

break;

case 123:

var10000 = 100;

break;

case 124:

var10000 = 112;

break;

case 125:

var10000 = 82;

break;

case 126:

var10000 = 43;

break;

case 127:

var10000 = 35;

break;

case 128:

var10000 = 83;

break;

case 129:

var10000 = 189;

break;

case 130:

var10000 = 255;

break;

case 131:

var10000 = 78;

break;

case 132:

var10000 = 239;

break;

case 133:

var10000 = 52;

break;

case 134:

var10000 = 252;

break;

case 135:

var10000 = 116;

break;

case 136:

var10000 = 60;

break;

case 137:

var10000 = 193;

break;

case 138:

var10000 = 207;

break;

case 139:

var10000 = 101;

break;

case 140:

var10000 = 142;

break;

case 141:

var10000 = 51;

break;

case 142:

var10000 = 74;

break;

case 143:

var10000 = 76;

break;

case 144:

var10000 = 154;

break;

case 145:

var10000 = 145;

break;

case 146:

var10000 = 105;

break;

case 147:

var10000 = 30;

break;

case 148:

var10000 = 31;

break;

case 149:

var10000 = 27;

break;

case 150:

var10000 = 204;

break;

case 151:

var10000 = 54;

break;

case 152:

var10000 = 7;

break;

case 153:

var10000 = 110;

break;

case 154:

var10000 = 166;

break;

case 155:

var10000 = 123;

break;

case 156:

var10000 = 150;

break;

case 157:

var10000 = 208;

break;

case 158:

var10000 = 115;

break;

case 159:

var10000 = 75;

break;

case 160:

var10000 = 134;

break;

case 161:

var10000 = 36;

break;

case 162:

var10000 = 199;

break;

case 163:

var10000 = 125;

break;

case 164:

var10000 = 210;

break;

case 165:

var10000 = 109;

break;

case 166:

var10000 = 17;

break;

case 167:

var10000 = 71;

break;

case 168:

var10000 = 152;

break;

case 169:

var10000 = 104;

break;

case 170:

var10000 = 178;

break;

case 171:

var10000 = 44;

break;

case 172:

var10000 = 165;

break;

case 173:

var10000 = 87;

break;

case 174:

var10000 = 235;

break;

case 175:

var10000 = 1;

break;

case 176:

var10000 = 220;

break;

case 177:

var10000 = 108;

break;

case 178:

var10000 = 106;

break;

case 179:

var10000 = 148;

break;

case 180:

var10000 = 56;

break;

case 181:

var10000 = 15;

break;

case 182:

var10000 = 250;

break;

case 183:

var10000 = 62;

break;

case 184:

var10000 = 151;

break;

case 185:

var10000 = 26;

break;

case 186:

var10000 = 243;

break;

case 187:

var10000 = 57;

break;

case 188:

var10000 = 172;

break;

case 189:

var10000 = 66;

break;

case 190:

var10000 = 197;

break;

case 191:

var10000 = 223;

break;

case 192:

var10000 = 228;

break;

case 193:

var10000 = 63;

break;

case 194:

var10000 = 19;

break;

case 195:

var10000 = 70;

break;

case 196:

var10000 = 126;

break;

case 197:

var10000 = 164;

break;

case 198:

var10000 = 212;

break;

case 199:

var10000 = 158;

break;

case 200:

var10000 = 227;

break;

case 201:

var10000 = 139;

break;

case 202:

var10000 = 111;

break;

case 203:

var10000 = 91;

break;

case 204:

var10000 = 23;

break;

case 205:

var10000 = 253;

break;

case 206:

var10000 = 147;

break;

case 207:

var10000 = 170;

break;

case 208:

var10000 = 226;

break;

case 209:

var10000 = 97;

break;

case 210:

var10000 = 39;

break;

case 211:

var10000 = 155;

break;

case 212:

var10000 = 79;

break;

case 213:

var10000 = 247;

break;

case 214:

var10000 = 215;

break;

case 215:

var10000 = 233;

break;

case 216:

var10000 = 218;

break;

case 217:

var10000 = 118;

break;

case 218:

var10000 = 175;

break;

case 219:

var10000 = 32;

break;

case 220:

var10000 = 135;

break;

case 221:

var10000 = 18;

break;

case 222:

var10000 = 69;

break;

case 223:

var10000 = 168;

break;

case 224:

var10000 = 242;

break;

case 225:

var10000 = 86;

break;

case 226:

var10000 = 245;

break;

case 227:

var10000 = 45;

break;

case 228:

var10000 = 25;

break;

case 229:

var10000 = 236;

break;

case 230:

var10000 = 180;

break;

case 231:

var10000 = 77;

break;

case 232:

var10000 = 157;

break;

case 233:

var10000 = 73;

break;

case 234:

var10000 = 187;

break;

case 235:

var10000 = 214;

break;

case 236:

var10000 = 232;

break;

case 237:

var10000 = 64;

break;

case 238:

var10000 = 131;

break;

case 239:

var10000 = 9;

break;

case 240:

var10000 = 146;

break;

case 241:

var10000 = 58;

break;

case 242:

var10000 = 47;

break;

case 243:

var10000 = 191;

break;

case 244:

var10000 = 140;

break;

case 245:

var10000 = 185;

break;

case 246:

var10000 = 177;

break;

case 247:

var10000 = 8;

break;

case 248:

var10000 = 90;

break;

case 249:

var10000 = 96;

break;

case 250:

var10000 = 190;

break;

case 251:

var10000 = 184;

break;

case 252:

var10000 = 113;

break;

case 253:

var10000 = 162;

break;

case 254:

var10000 = 217;

break;

default:

var10000 = 84;

}

short var4 = var10000;

int var5 = (var1 & 255) - var4;

if (var5 

var5 += 256;

}

int var6 = ((var1 & '\uffff') >>> 8) - var4;

if (var6 

var6 += 256;

}

for(int var7 = 0; var7 

int var8 = var7 % 2;

char var10002 = var3[var7];

if (var8 == 0) {

var3[var7] = (char)(var10002 ^ var5);

var5 = ((var5 >>> 3 | var5 <

} else {

var3[var7] = (char)(var10002 ^ var6);

var6 = ((var6 >>> 3 | var6 <

}

}

d[var2] = (new String(var3)).intern();

}

return d[var2];

}

}

反编译之后有1000行左右

static静态代码块采用异或的方式进行解密,并将结果存到静态变量数组c中

a方法采用流密码方式进行解密,第一个是数组偏移量,第二个是解密密钥。

简单分析之后,可以写出如下代码package com.vvvtimes.main;

public class ZKMDeCodeString {

private static String dexor(String str) { // 静态代码块改写,使用此方法可得到静态变量的字符串,但是有的是明文有的是密文

char key[] = new char[] { 116, 91, 57, 40, 121, 92, 118 };

char arr[] = str.toCharArray();

for (int i = 0; i 

arr[i] ^= key[i % 7];

}

return new String(arr);

}

private static String decryption(int iv, String str) {// a方法改写,去掉第一个变量,增加需要解密的字符串参数

char[] ch = str.toCharArray();

short key[] = new short[] { 181, 149, 85, 171, 128, 103, 238, 159, 225, 234, 14, 200, 138, 205, 127, 50, 186,

169, 68, 61, 10, 46, 121, 230, 80, 89, 0, 24, 167, 5, 132, 53, 81, 231, 141, 251, 241, 219, 173, 20, 38,

182, 229, 67, 183, 188, 222, 107, 248, 244, 156, 88, 246, 240, 13, 211, 49, 144, 40, 21, 130, 179, 202,

194, 201, 174, 117, 99, 137, 6, 12, 153, 213, 206, 93, 249, 33, 28, 120, 95, 37, 4, 55, 237, 102, 196,

34, 216, 143, 98, 133, 94, 203, 254, 92, 2, 16, 124, 48, 11, 3, 163, 221, 195, 192, 59, 119, 161, 72,

29, 160, 224, 198, 41, 42, 65, 114, 136, 176, 22, 122, 209, 129, 100, 112, 82, 43, 35, 83, 189, 255, 78,

239, 52, 252, 116, 60, 193, 207, 101, 142, 51, 74, 76, 154, 145, 105, 30, 31, 27, 204, 54, 7, 110, 166,

123, 150, 208, 115, 75, 134, 36, 199, 125, 210, 109, 17, 71, 152, 104, 178, 44, 165, 87, 235, 1, 220,

108, 106, 148, 56, 15, 250, 62, 151, 26, 243, 57, 172, 66, 197, 223, 228, 63, 19, 70, 126, 164, 212,

158, 227, 139, 111, 91, 23, 253, 147, 170, 226, 97, 39, 155, 79, 247, 215, 233, 218, 118, 175, 32, 135,

18, 69, 168, 242, 86, 245, 45, 25, 236, 180, 77, 157, 73, 187, 214, 232, 64, 131, 9, 146, 58, 47, 191,

140, 185, 177, 8, 90, 96, 190, 184, 113, 162, 217, 84 };

short v0 = key[ch[0] & 255]; // v0取字符串低8位,取映射

int v1 = (iv & 255) - v0; // iv取低8位 -v0

if (v1 

v1 += 256; // 这里相当于&0xff,因为上面做减法位数拓展,通过这个转回

}

int v2 = ((iv & '\uffff') >>> 8) - v0; // iv取高8位 -v0

if (v2 

v2 += 256;

}

for (int i = 0; i 

if (i % 2 == 0) {

ch[i] = (char) (ch[i] ^ v1);

v1 = ((v1 >>> 3 | v1 <

} else {

ch[i] = (char) (ch[i] ^ v2);

v2 = ((v2 >>> 3 | v2 <

}

}

return new String(ch);

}

public static void main(String args[]) {

String cipherText = "\u0093íè[Í\u0005ükçÀú";

String[] cipherArray = new String[] { cipherText.substring(0, 5), cipherText.substring(6, 11) };

System.out.println(cipherArray[0]); // íè[Í --> ç¶Ñs´ --> Hello

System.out.println(dexor(cipherArray[0]));

System.out.println(decryption(8444, dexor(cipherArray[0])));

System.out.println(cipherArray[1]); // ükçÀú --> 0Þè --> World

System.out.println(dexor(cipherArray[1]));

System.out.println(decryption(-25829, dexor(cipherArray[1])));

}

}

输出结果如下

3111c0056aa7bffabaff404239b3ac7e.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值