作者:舵手
申明:如转载请保证文章的完整性
来源:www.blogjava.net/galaxyp/
软件下载:www.e-t.com
软件简介:
Jshrink extracts the minimal set of Java class files for an application, removes unused code and data,
obfuscates symbolic names, finalizes code for optimized execution, and stores the results in a Java archive
.jar file.
Jshrink typically reduces program size by 30-40%. Jshrink obfuscated code is much harder to comprehend
when decompiled, a claim that can be readily verified using Jshrink’s built-in Java decompiler. What at first
glance seems to be meaningful names in Jshrink obfuscated code are often reused system names, a Jshrink
obfuscation technique called semantic recycling.
一直没怎么用过,闲来无聊想研究下它的功能,用jshrink打开一个class文件双击提示“Missing license key, see www.e-t.com/jshrink.html to request evaluation license”,以前申请了一个试用的license key,恢复过系统,早丢了。java写的,反编译出来看看,解压jar,并反编译所有的class文件,类被混淆过,这里要注意的是,有些方法混淆后名称和类名一样,但千万不要把它当作构造函数,否则可能会带来一点麻烦。在整个源代码中查找上面的报错字符串,居然没找到。在解压后的目录里找了一下,发现I.gif挺可怀,打开一看果然是加密了的东东,并不是gif文件,在I.I.class反编译源代码中果然发现了I.gif,如下:
InputStream inputstream = (new I()).getClass().getResourceAsStream("" + 'I' + '.' + 'g' + 'i' + 'f');
即然建立输入流读取方文件,肯定有解密过程,分析原代码后写出一个解密代码:
import java.io.InputStream;
public class I
{
static byte COWY[];
static String append[] = new String[256];
static int close[] = new int[256];
public String td(int i)
{
int j = i & 0xff;
if(close[j] != i)
{
close[j] = i;
if(i < 0)
i &= 0xffff;
String s = new String(COWY, i, COWY[i - 1] & 0xff);
append[j] = s;
}
System.out.println(append[j]);
return append[j];
}
public static void main(String[] args)
{
try
{
InputStream inputstream = (new I()).getClass().getResourceAsStream("" + 'I' + '.' + 'g' + 'i' + 'f');
//这里他用'I' + '.' + 'g' + 'i' + 'f',如果我们直接查找I.gif,肯定没有结果,所以当搜索I.gif没找到时,
//一定要试试这种方法,还有数组形式存放。
if(inputstream != null)
{
int i = inputstream.read() << 16 | inputstream.read() << 8 | inputstream.read();
COWY = new byte[i];
int j = 0;
byte byte0 = (byte)i;
byte abyte0[] = COWY;
while(i != 0)
{
int k = inputstream.read(abyte0, j, i);
if(k == -1)
break;
i -= k;
for(k += j; j < k; j++)
abyte0[j] ^= byte0;
}
inputstream.close();
}
}
catch(Exception exception) { }
I i = new I();
for (int j=0; j<7200; j++ )//为什么这个j最大值为7200,因为大概查看了一下源代码中调
//用I.I.I()这个方法的最大值就是这个,试图加大后,抛出异常。
{
System.out.print(j+":");
i.td(j);
}
}
}
当上面的循环体里j为4088时字符串是Missing license key, see www.e-t.com/
jshrink.html to request evaluation license,在整个原代码是搜索4088,发现只在A.class中有,
switch(getViewRect)
{
case -1:
case 0: // '\0'
return true;
case 1: // '\001'
getChildCount();
getJarEntry(I.I.I(4088));
//Missing license key, see www.e-t.com/jshrink.html to request evaluation license
//I.I.I(4088)返回的串
return false;
case 2: // '\002'
getChildCount();
getJarEntry(I.I.I(4168));
//Evaluation license key has expired, purchase new key at www.e-t.com/jshrink.html
//I.I.I(4168)返回的串
return false;
case 3: // '\003'
getChildCount();
getJarEntry(I.I.I(4249));
//Invalid license key
//I.I.I(4249)返回的串
return false;
case 4: // '\004'
getJarEntry(I.I.I(4269));
//Internal error verifying license key
//I.I.I(4269)返回的串
return false;
}
return false;
不想分析注册key详细算法,暴破试一下,把上面每个case子句里的代码变为 return true; 可能问题就能解决,用十六进制编辑器打开A.class,查找03AC,连续五个在一起,改为04AC,现在程序已经可以正常运行,只是还有无License的提示对话框,那么把04AC(前面已修改)前的十个四字节,如:2AB7016B2A110FF8B8056DB7003A全改为00,相当于汇编里的nop保存打包,运行就再没有提示对话框了。这样不完全暴破就已经成功,之所以说不完全是因为还有Z.class有类A.class的功能,读取I.gif文件并解密,我们并没有对A.class这个类的调用做跟踪分析,这样很有可能还有一些地方有限制而我们没有破除掉。
没什么技术性,但能为菜鸟破JAVA程序提示一点思路。今天搜了一下,才发现这个早有人已经写出注册机了,牛人多多。不过想研究暴破的可以从下面下载本人修改过的和原版程序:
链接暂时不再提供