吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 9560|回复: 15
收起左侧

[原创] 海颐应用开发平台v4.0算法分析手记

[复制链接]
datochan 发表于 2009-2-12 22:53
刚来这里学习,发现刚注册的用户限制太多,由于没时间写新文章,只有帖点以前的东西来混点权限,希望各位大大包含,各位朋友理解!
        刚在这个版块看了一下,破解几乎就是OD,所以我发个Java程序的完美破解方法,希望能给像我一样才的朋友开阔一下视野,不要只限于眼前的东西,努力抓好编程基础!
        进入正文:
        这个程序是我们地方的一个软件公司(海颐软件,不知道大家听过没有!)基于Struts和Spring等技术开发并整理的一个傻瓜式的J2EE应用程序开发平台,它是以Eclipse插件的形式发布出来的,其功能非常的强大,它可以让我们仅通过简单的配置,利用它提供的各种强大的组件(如AJAX树,导航菜单,工具栏,动态表格等等),自动的生成一个J2EE程序(可以自动生成JSP页面和WEB配置页面哦~),更可贵的是它几乎兼容了所有现在流行的数据库和应用服务器。
功能看图片:

【破解分析】:

    我在看雪潜水这么长时间,一篇精华都没有,怎么说也说不过去,可是我水平有限,如果自己再不努力争取,精华可真的就与我无缘了,最近学校的事又比较多,整天瞎忙活。就发一个前几天破解我们本地一家软件公司产品时的破解手记。
      论坛上关于JAVA的程序分析不是很多哈,或许还让我给骗个精华呢,嘎嘎!
      废话不多说了,分析JAVA的程序我还是第一次,不知道该从哪里开始。在网上找了好久也没有什么具体的结果,只知道JAVA程序用JAD可以反编译  

      
         用WinRAR将JAR解压缩,开始大概的浏览一下这个程序的结构,在com.highsoft.tools_1.0.0/toolset/jars/highsoft/mr-25-free包中找到了很多0oO组合的文件夹,还有很多类似的CLASS文件,在看雪精华中有过介绍,是“舵手”老大写的《浅谈JAVA程序破解》,说是这种混淆方式在JAVA程序的加密保护中很常见,我用JAD反编译了几个,也没有看出个所以然来,郁闷。

自己尝试着在Eclipse中建了个插件工程,我发现:似乎每个Eclipse插件程序都有这个配置文件,还有一个激活器叫Activator的类。就从这里入手了!

    在designtool包中找到了,Activator.class文件而且还发现了一个可疑的文件:license.adp,从字面上讲就是“证书,许可”可是用HEX编辑器打开全是乱码,估计应该是加密了……

        先不管它,用JAD将Activator.class反编译过来分析一下,找到了两个方法,代码如下:
public boolean checkLicense()
{
String as[] = new String[8];
int i = getUserInfo(as);
if(!c)
{
String s = null;
if(i == -5)
s = "\u65E0\u6548\u7684\u6D77\u9890\u5E94\u7528\u5F00\u53D1\u5E73\u53F0license,\u8BF7\u8054\u7CFB0535-6582295\uFF01";//无效的海颐应用开发平台license,请联系0535-6582295! 
else
if(i == -1)
s = "\u6D77\u9890\u5E94\u7528\u5F00\u53D1\u5E73\u53F0" + as[4];//海颐应用开发平台
else
if(i >= 0)
{
s = "\u6D77\u9890\u5E94\u7528\u5F00\u53D1\u5E73\u53F0" + as[4];//海颐应用开发平台
c = true;
}
}
return i != -5 && i != -1;
}
public int getUserInfo(String as[])
{
g g1 = null;
d d1 = null;
b b = null;
if(d1 == null)
return -5;
g1 = d1.getLicenseInfo();
as[0] = g1.getUserID();
as[1] = d1.getCompanyName();
as[2] = g1.getProductName();
if(!g1.isDevelopEdition())
{
as[3] = "\u6B63\u5F0F\u7248";//正式版
as[4] = "\u65E0\u671F\u9650\u9650\u5236";//无期限限制 
return -2;
}
if(g1.isEvalEdition() && g1.isTempEdition())
{
as[3] = "\u6B63\u5F0F\u7248";//正式版
as[4] = "\u65E0\u671F\u9650\u9650\u5236";//无期限限制 
return -3;
}
if(g1.getEvalExpDate() == null)
as[3] = "\u8BD5\u7528\u7248";//试用版 
int i = b.verifyLicense(g1);
if(i < 0)
{
as[4] = "license\u5DF2\u8FC7\u671F";//license已过期
return -1;
}
switch(i)
{
case 0: // '\0'
as[4] = "\u8BD5\u7528\u671F\u9650\u5373\u5C06\u5230\u671F";//试用期限即将到期
break;
case 1: // '\001'
as[4] = "1\u5929\u540E\u5230\u671F";//1天后到期
break;
default:
as[4] = i + "\u5929\u540E\u5230\u671F";//i天后到期 
break;
}
return i;

}。


别的不说,单从方法名称上讲,我就应该兴奋的跳楼了,哈哈,至于“\u65E0\u6548\u7684\u6D77\u9890\u5E94\u7528\u5F00\u53D1\u5E73\u53F0license,\u8BF7\u8054\u7CFB0535-6582295\uFF01”之类的字符串,难不倒我,哈哈,这些是宽字节的ASCII,我们直接用IE就可以识别它们,连查表都省了,写一个HTML页面,代码如下:
<html>

<head><script>

document.write("\u65E0\u6548\u7684\u6D77\u9890\u5E94\u7528\u5F00\u53D1\u5E73\u53F0license,\u8BF7\u8054\u7CFB0535-6582295\uFF01");

</script>

</head>

</html>

        依此类推,给源程序加上注释,(我已经加好了,嘿嘿~)
         效果如下图:

      当然,这样子直接改代码?好像不能编译哈!按照驼手老大说的,难道让我直接修改它的字节码?不太现实哈!
        既然爆破行不通,那我们就回过头来,仔细的想一下,我们还有一个文件license.adp没有用上,我们搜索文件夹中包含license字符的文件(我用的是DreamWeaver 8来查找,比较方便!)
经过分析筛选我定位到了iv.java的Write方法和c.java的Read方法,我分别给出它们的代码:
iv.java中的关键代码如下:
 public void write(d d1)

throws IOException

{



String s = null;

s = "." + File.separator + "license";

File file = new File(s);

if((new File(s + ".bak")).exists())

(new File(s + ".bak")).delete();

if(file.exists())

file.renameTo(new File(s + ".bak"));



try

{

a = new BufferedOutputStream(new FileOutputStream(s));



byte abyte0[] = a(d1.getUserID());

a(abyte0);

abyte0 = a(d1.getLicenseKey());

a(abyte0);

abyte0 = a(d1.getCompanyName());

a(abyte0);

abyte0 = a(d1.getInstallRoot());

a(abyte0);

try

{

System.out.println(String.valueOf(a(d1)));

abyte0 = a(String.valueOf(a(d1)));

}

catch(Throwable throwable)

{

System.out.println(throwable.toString());

abyte0 = a(String.valueOf("false"));

}

a(abyte0);

if(d1.getMacAddress() != null)

a(a(d1.getMacAddress()));

if((new File(s + ".bak")).exists())

(new File(s + ".bak")).delete();

}

catch(Exception exception)

{

exception.printStackTrace();

if(a != null)

{

a.close();

a = null;

}

File file1 = new File(s);

if(file1.exists())

file1.delete();

if((new File(s + ".bak")).exists())

(new File(s + ".bak")).renameTo(new File(s));

}

finally

{

if(a != null)

a.close();

}

return;

}

byte[] a(String s)

{

try {

return s.getBytes("utf-8");

} catch (UnsupportedEncodingException e) {

// TODO 自动生成 catch 块

e.printStackTrace();

}

return s.getBytes();

}

public boolean a(d d1)

throws Exception

{

if(!d1.getFlag())

return false;

g g1 = (new e()).getLicenseInfo(d1.getUserID(), d1.getLicenseKey());

if(g1.isTempEdition() || g1.isEvalEdition())

{

System.out.println("Evaluation");

return false;

}

String s = null;

if(System.getProperty("os.name").startsWith("Windows"))

{

String s1 = System.getProperty("java.library.path");

if(s1 == null || s1.length() == 0)

{

System.out.println("old JVM");

return false;

}

for(StringTokenizer stringtokenizer = new StringTokenizer(s1, ";", false); stringtokenizer.hasMoreElements();)

{

String s2 = stringtokenizer.nextToken();

int i = s2.toLowerCase().indexOf("system32");

if(i != -1)

{

s2 = s2.substring(0, i + 8);

s = s2 + "\\highsoft.dll";

break;

}

}

} else

{

s = "/usr/lib/.highsoft.so";

}

if(s == null)

{

System.out.println("System can not be identified.");

return false;

}

byte abyte0[] = a(System.getProperty("user.name"));

byte abyte1[] = a(d1.getLicenseKey());

byte abyte2[] = new byte[abyte1.length + abyte0.length];

System.arraycopy(abyte0, 0, abyte2, 0, abyte0.length);

System.arraycopy(abyte1, 0, abyte2, abyte0.length, abyte1.length);

byte abyte3[] = (new iw()).encode(abyte2);

BufferedOutputStream bufferedoutputstream = new BufferedOutputStream(new FileOutputStream(s, true));

bufferedoutputstream.write(abyte3.length);

for(int j = 0; j < abyte3.length; j++)

{

abyte3[j] ^= 61482;

bufferedoutputstream.write(abyte3[j]);

}

bufferedoutputstream.close();

return true;

}

private BufferedOutputStream a;

}





C.java中的关键代码如下:
 public d read()

throws IOException

{

PushbackInputStream pushbackinputstream;

Exception exception1;

pushbackinputstream = null;

d d2;

try

{

String s = "license.adp";

pushbackinputstream = new PushbackInputStream(a(s));

String s1 = a(a(pushbackinputstream));

String s2 = a(a(pushbackinputstream));

String s3 = a(a(pushbackinputstream));

String s4 = a(a(pushbackinputstream));

System.out.println(s1);

System.out.println(s2);

System.out.println(s3);

System.out.println(s4);

boolean flag = Boolean.valueOf(a(a(pushbackinputstream))).booleanValue();

String s5 = null;

if(pushbackinputstream.available() > 0)

s5 = a(a(pushbackinputstream));

d d1 = new d();

d1.setUserID(s1);

d1.setLicenseKey(s2);

d1.setCompanyName(s3);

d1.setInstallRoot(s4);

d1.setFlag(flag);

d1.setMacAddress(s5);

d2 = d1;

}

catch(IOException ioexception)

{

throw ioexception;

}

catch(Exception exception)

{

throw new IOException(exception.toString());

}

finally

{



}

return d2;

}

String a(byte abyte0[])

{

try {

return new String(abyte0, "utf-8");

} catch (UnsupportedEncodingException e) {

// TODO 自动生成 catch 块

e.printStackTrace();

}



return new String(abyte0);

}

private byte[] a(PushbackInputStream pushbackinputstream)

throws IOException

{

int i = pushbackinputstream.read();

byte abyte0[] = new byte[i];

for(int j = 0; j < i; j++)

abyte0[j] = (byte)(pushbackinputstream.read() ^ 0xf02a);

return abyte0;

}

static Class a;

}




哈哈,不用我多说了哦~

很明显c.java的Read方法就是分析并读取license.adp文件的哦,我们用Eclipse新建一个工程,将C.java文件复制到工程目录中,然后将license.adp文件放到工程的根目录下,然后新建一个类,编写代码如下:
package src;
import java.io.*;
import java.util.*;
public class Cstr {
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成方法存根

c c1 = new c();
try {
c1.read();
} catch (IOException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
}


运行结果如下:

         
        哈哈,分析出来了,问题也很明显了哦……
        至于iv.java的Write方法,这个需要我们有点耐性,通过它的代码我们可以知道,它需要我们准备好KEY,用户ID,还有公司名称,用户ID,和公司名称这个好说,但是这个KEY怎么弄呢?
经过分析代码,我发现,在iw.java中有一个createKey方法,代码如下:
public String createKey(g g1)
{
for(int i = 0; i < b.length; i++)
b[i] = 0;
b[0] = (byte)g1.getProductID();
if(g1.canOLAP())
b[0] |= 0x80;
if(g1.canRunWithServer())
b[0] |= 0x40;
long l = 0L;
if(g1.isTempEdition() || g1.isEvalEdition())
{
l = g1.getEvalExpDate().getTime();
b[0] |= 0x20;
if(g1.isTempEdition())
b[0] |= 0x10;
} else if(!g1.isEvalEdition() && !g1.isTempEdition())
{
l = g1.getMaintainExpDate().getTime();
b[0] |= 0x10;
}
b[1] |= 0x2;
if(g1.isDevelopEdition())
b[1] |= 0x10;
b[2] = (byte)g1.getConcurrentUser();
b[3] = (byte)g1.getConcurrentEngin();
b[4] = (byte)g1.getCPUNumber();
if(g1.isUpgrade())
b[4] |= 0x80;
l -= d;
l /= 0x5265c00L;
b[5] = (byte)(int)(l & 255L);
b[6] = (byte)(int)(l >> 8 & 255L);
b[7] |= g1.getConcurrentUser() >> 8 & 0x3;
b[7] |= (g1.getConcurrentEngin() >> 8 & 0x3) << 2;
int j = 0;
for(int k = 0; k < b.length - 2; k++)
j += b[k] & 0xff;
b[13] = (byte)j;
int i1 = (int)(Math.random() * 10D);
int j1 = (int)(Math.random() * 10D);
b[14] |= (byte)(i1 & 0xf);
b[14] <<= 4;
b[14] |= (byte)(j1 & 0xf);
if(!g1.isEvalEdition() && !g1.isTempEdition())
a(b);
for(int k1 = 0; k1 < j1; k1++)
{
byte byte0 = b[k1];
b[k1] = b[Math.abs(i1 - k1)];
b[Math.abs(i1 - k1)] = byte0;
}
a(g1);
byte abyte0[] = encode(b);
return new String(abyte0);
}


       前后对应的看一下代码,思路就很清晰了,把相关的JAVA文件都考到工程中,作相应的修改,然后编写如下代码:
package src;
import java.io.*;
import java.util.*;
public class Cstr {
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成方法存根

g g = new g();
Date date = new Date();
g.setAllowedBuilderNumber(1);
g.setCPUNumber(1);
g.setConcurrentUser(1);
g.setConcurrentEngin(1);
g.setProductID(1);
g.setProductName("聚星亭");
g.setDevelopEdition(false);
g.setIsUpgrade(true);
g.setUserID("美丽の破船");
g.setEvalExpDate(date);
g.setMaintainExpDate(date);
System.out.println(g.createKey());
}
}

运行结果如下:
         

哈哈,这个就应该是KEY了哦……

那我们在看这个iv.java的Write方法,就很明了了,它的功能大概是在功能的根目录下生成一个名叫license的文件没有扩展名,好像还要在我们的系统目录的System32目录下生成一个名叫highsoft.dll的文件,我们没有办法手工去创建它,我们让它运行,一切不就OK了,好,我们在写如下的代码:

package src;
import java.io.*;
import java.util.*;
public class Cstr {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成方法存根
        d d1 = new d();
        g g1 = null;
        iv iv = new iv();
                
        d1.setCompanyName("聚星亭");
        d1.setInstallRoot("D:\\编程开发工具\\J2EE工具\\eclipse3.2.1\\plugins");
        d1.setMacAddress("00-17-31-EC-64-16");
        d1.setUserID("美丽の破船");
        d1.setFlag(true);
        g1 = d1.getLicenseInfo();
        Date date = new Date();
        g1.setAllowedBuilderNumber(12);
        g1.setCPUNumber(1);
        g1.setConcurrentUser(1);
        g1.setConcurrentEngin(1);
        g1.setProductID(1);
        g1.setProductName("聚星亭");
        g1.setDevelopEdition(false);
        g1.setIsUpgrade(true);
        g1.setUserID("美丽の破船");
        g1.setMaintainExpDate(date);
        d1.setLicenseKey(g1.createKey());
        try {
            iv.write(d1);
        } catch (IOException e) {
            // TODO 自动生成 catch 块
            e.printStackTrace();
        }
    }
}


运行结果如下:


         
好了,我们再看一下工程的根目录,的确多了一个名叫license的文件!!!


         哈哈,可以读取,也就是它们的格式是一样的哦!我们试者用现在的这个license.adp去替换程序原本的那个文件试试,由于我自己用JAR打包的jar文件在Eclipse中不干活,我们就不破坏它的结构,用WinRAR打开com.highsoft.tools_1.0.0目录下的designtool.jar文件,然后将现在的这个license.adp文件拖到WinRAR窗口中完成替换,再同样打开com.highsoft.tools_1.0.jar文件,将designtool.jar替换掉包中原先的那个文件,最后把现在的这个com.highsoft.tools_1.0.jar放到Eclipse的plugins目录下,重新启动Eclipse程序,查看效果,显示正版了!

      
    【最后小结】
              好了,破解就告一段落,下面总结一下,至于JAVA程序的破解,我等菜菜没有什么资格去评论。所以总结就是,要破解JAVA程序,要学好JAVA是必须的,最好再就是研究一下javassist!
    好了,总结完毕,睡觉~~~

[ 本帖最后由 bester 于 2009-2-13 03:49 编辑 ]

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

wgz001 发表于 2009-2-12 23:07
欢迎来到52   发表精彩文章   
52有你更精彩   
zapline 发表于 2009-2-12 23:07
tbf2008 发表于 2009-2-13 13:05
满不懂 发表于 2009-2-13 15:06
研究JAVA的文章比较少,感谢分享。收藏学习。
 楼主| datochan 发表于 2009-2-14 01:48
原帖由 tbf2008 于 2009-2-13 13:05 发表
楼主请问下这个中文版哪里有下呢?12679


下的英文版,然后用了中文的语言包~~~~~
ycs 发表于 2009-2-16 21:11
没得实践对象,印象不深刻啊。:Q
什么也不是 发表于 2009-2-17 15:34
:D
Eclipse 是学JAVA 必备工具哦 只可惜JAVA只开了半年 才上了10+节课
:'(  
惭愧啥也没学到...
cjteam 发表于 2009-2-17 18:02
[s:364] 文章有很好的引导作用,感谢
fuma255 发表于 2009-2-18 21:45
学习下,多谢楼主了:)
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-7 19:19

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表