首页
社区
课程
招聘
DashO Pro 3.2 (Java软件)试用版 注册机
发表于: 2006-10-9 11:10 19769

DashO Pro 3.2 (Java软件)试用版 注册机

2006-10-9 11:10
19769
续:
http://bbs.pediy.com/showthread.php?s=&threadid=32484


舵手兄终于处理了 Zelix KlassMaster,为了回应舵手的功劳。
我再次奉献 DashO Pro Evaluation 3.2 版本的逆向分析

DashO Pro 3.2 试用版 注册机
    对于Java软件来说,安全性一直是非常脆弱的。虽然出现了很多保护手段,但是都并不完善。对于Java软件来说使用最多的保护手段就是使用混乱器了。这里使用DashO Pro作为混乱器的效果是很好的。但是怎样才能无限制的使用这个版本呢。制作出注册机就可以了吧?!
Author:vhly[FR]
Tools:DJ Java Decompiler 3.8.8

对于如今的混乱器而言,字符串加密简直是必备的功能,如果哪一个混乱器没有此项功能,那么并不算一个好的混乱器。同时混乱器还应该包含控制流程混乱、堆栈混乱、字节代码混乱等等。只有符合上述功能才算一个好的软件吧?!

1. 思路
对于经过自身混乱的DashO Pro 3.2 Evaluation来说,他的保护非常好,首先,如果按照程序启动顺序的话,就跟本不可能破解。因为这个软件GUI部分使用DashoProGuiEval类作为主类,同时主类会调用b类的方法 a(String [] args),但是最为关键的是,b类当使用DJ Java Decompiler 也就是 jad 时出现非法操作。针对这种情况,应该可以推断,要么使用了自定义类装载器,要么使用了字节代码陷阱或者畸形的类文件。鉴于以前破解Smokescreen时的经验,针对这种大型的,包含许多类文件的软件,首先要找到关键信息。可以直接通过类文件中的常数池读出String类型的常量就可以了。同时DashO使用了字符串加密,解密方法如下:
public static String A_B_C_D(String s)  // DashO 所使用的字符串加密/解密方法
    {
        char ac[] = new char[s.length()];
        s.getChars(0, s.length(), ac, 0);
        char c = '\0';
        for(int i = 0; i < ac.length; i++)
            ac[i] = (char)(ac[i] - 1 ^ c++);

        return new String(ac);
}

就可以制作字符串提取器了 如下 com.vhly.anti.dasho.DecodeString 类

package com.vhly.anti.dasho;

import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.util.jar.*;

import com.vhly.classfile.*;  // 添加了我的类文件分析库

public class DecodeString
{
        private String targetName;
        private String outName;
       
        public DecodeString()
        {
                Debug.setEnable(false);
        }

        public static String decodeString(String oldString)
        {
                char ac[] = new char[oldString.length()];
                oldString.getChars(0, oldString.length(), ac, 0);
                char c = '\0';
                for(int i = 0; i < ac.length; i++)
                        ac[i] = (char)(ac[i] - 1 ^ c++);
                return new String(ac);
        }
       
        public void setTargetName(String fn)
        {
                targetName = fn;
        }
       
        public void setOutName(String on)
        {
                outName = on;
        }
       
        public void doWork() throws IOException
        {
                JarFile target = new JarFile(targetName);
                FileWriter out = new FileWriter(outName);
                BufferedWriter bout = new BufferedWriter(out);
                PrintWriter pw = new PrintWriter(bout);
                Enumeration en = target.entries();
                JavaClass jc = null;  // 通过输入流获取类
                InputStream in = null;
                while(en.hasMoreElements())
                {
           JarEntry je = (JarEntry)(en.nextElement());
                        String name = je.getName();
                        if( name.endsWith(".class") )
                        {
                        in = target.getInputStream(je);
                                jc = new JavaClass();
                                jc.read(in);
                        pw.println("Find The Class:"+name);
                        ConstantPool cp = jc.getCP();
                                int size = cp.size();
                                for(int i=1; i< size; i++)
                                {
                CPEntry cpe = cp.getCPEntryAtIndex(i);
                if( cpe.getType() == CPEntry.TYPE_STRING )
            {                                        CPString cps = (CPString)cpe;                                int sindex = cps.getStringIndex();
        CPUtf8 utf8 = (CPUtf8)(cp.getCPEntryAtIndex(sindex));
        String data = utf8.getString();
                                                pw.println("    String data["+data+"]:");
                                                pw.println("          \""+decodeString(data)+"\";");
                                        }
                                }
                        }
                }
                jc = null;
                in = null;
                pw.close();
                bout.close();
                out.close();
                target = null;
                System.gc();
        }
       
        public static void main(String args[]) throws IOException
        {
                DecodeString ds = new DecodeString();
                ds.setTargetName(args[0]);
                ds.setOutName(args[1]);
                ds.doWork();
                ds = null;
        }
}
由于DashO对类文件进行了处理,上面代码会在某些类上出错。
提取出的字符串内容 (节选完整内容另存文件)

Find The Class:c6.class 包含了程序第一次运行和注册失败后的用户信息注册对话框类
    String data[Sefkxrug}aff ]:
          "Registration?";
    String data[Fmdki&Ucpaz?j? ]:
          "Email Register";      注册的两种方式 必须使用此种方式
    String data[Xea$Wabo|~pz ]:
          "Web Register";      web注册
    String data[Damabj ]:
          "Cancel";
    String data[Cabi ]:
          "Back";
    String data[Tuaonr ]:
          "Submit";
Find The Class:c7.class   构造第一次注册用户信息的对话框
    String data[Giqqq&Igfm ]:
          "First Name?";
    String data[Marx%Lhkn ]:
          "Last Name?";
    String data[Fmdki&hdm|py? ]:
          "Email addres联?";
    String data[Qjnnb&Isflpz ]:
          "Phone Number?";
    String data[Ga{$Kqlfn| ]:
          "Fax Number?";
    String data[Doptfl?)Jpmcaep|z} ]:
          "Compan?/Affiliation?";
    String data[Uiwpb ]:
          "Title?";
    String data[Bfgrbwv(: ]:
          "Address 1?";
    String data[Bfgrbwv(; ]:
          "Address 2?";
    String data[Diw{ ]:
          "City?";
    String data[Tvdxb ]:
          "State?";
    String data[[is-Ukvtjf+Idjl ]:
          "Zip/Postal Code?";
    String data[Doxnqx?)[mncdd ]:
          "Countr?/Region?";
    String data[Teqkfj'J~eio ]:
          "Serial Number?";
    String data[Tvdxrw'Kn{zkli ]:
          "Status Message?";
    String data[uzwFnxvtGiho ]:
          "txtFirstName?";
    String data[Qnhcxa'cg~pz-ub{c2}szq7w:otz>YwSSW kELC        PDOAJ  ]:
          "Please enter your name in the First Name field.?";
部分出错信息以及控件位置信息未列出
    String data[Qjnnb&isflpz-a|}e2qw5uc8u}|ii>00 FLENRV. ]:
          "Phone number must be at least 10 digits
?";
    String data[Fpwgw&h(igci.~kcyt?5|d{{}i ]:
          "Enter a valid serial number┳";
    String data[Fpwgw&ei}b+nf?~|1q}x5zxem:u{ryn  ]:
          "Enter both fi曼st and last names

2. 寻找软件关键点
当找到程序第一次注册的类之后,第二次运行时,会出现 “Step 2” 注册对话框。对话框中出现:“Serial Number”、“Confirmation Code”等字段,那么在我们提取的字符串文件中寻找 “Confirmation Code”字符串 发现,在d0 类中有着部分信息,同时会安装事件处理类 d1 反汇编这个类,发现如下代码片断:
class d1   implements ActionListener
    {
        private final d0 a; /* synthetic field */
        public final void actionPerformed(ActionEvent actionevent)
        {
            boolean flag = true;
            if(d0.a(a))   // return d0.i;
            {
                String s = d0.b(a).getText().trim();
                if(s.length() > 0)
     d0.c(a).t(s);   // cw d0.c(d0 a)  cw.t(s); 就是设置cw.m = s
                else
                 flag = false;
            }
            try
            {
    d0.c(a).b(Integer.parseInt(d0.d(a).getText().trim()));
       // 设置cw.al = int;
            }
            catch(NumberFormatException numberformatexception)
            {
                flag = false;
            }
            if(flag && d0.c(a).ag())  //  cw.ag() -> 真正的序列号校验
            {
                d0.c(a).e(true);
                d0.a(a, 0);
                d0.e(a);
            } else
            {
                d0.c(a).e(false);                JOptionPane.showMessageDialog(((Component)actionevent.getSource()).getParent().getParent(), "Invalid Confirmation Code.  Please try again.", "Error", 0);
            }
        }
            public d1()
            {}
    }

3. 注册算法
关键点  cw类的 ag()方法
    public final boolean ag()
    {
        boolean flag = false;  // al 为软件 Confirmation Code 可以自定义
        int i1 = (al & 0xff) << 8;
        i1 |= (al & 0xff00) >> 8;
        if(m != null)
            try
            {
                if((i1 ^ 0x30cd) == Integer.parseInt(m))  // m为序列号
                    flag = true;
            }
            catch(NumberFormatException numberformatexception) { }
        return flag;
    }

4. 制作注册机
package com.vhly.keygen.dasho;

public class ConfirmCodeSum
{
        public static String gen(String conf)
        {
                int tmp = Integer.parseInt(conf);
                int i1 = (tmp & 0xff) << 8;
                i1 |= (tmp & 0xff00) >> 8;
                i1 ^= 0x30cd;
                String ret = Integer.toString(i1);
                return ret;
        }
       
        public static void main(String args[])
        {
                String conf = "99334827";  // 此处可以随意修改,但必须为十进制数!
System.out.println("Confirm Code:"+conf+"   Gen Serial Code:"+gen(conf));
        }
}

我的注册界面是:



其中的 vhly FR是在第一次注册时填上的 注意第一次输入序列号时候,注册码可以随意,但是必须选择使用 Email Register方式

5. 软件的逆向工程
第一步、去除(EVALUATION ONLY)标记,去除生成类文件中的 DashoEval_前缀,可修改为 DashO_,也就是去除所有的试用信息

首先:由于软件中使用了字符串加密的方式,因此如果我们要加入任何信息,都必须使用加密后的内容,根据解密程序,分析出DashO的字符串加密方法。

代码见下一页:

public class GenString
{
    public static String gen(String s)
    {
        char ac[] = new char[s.length()];
        s.getChars(0, s.length(), ac, 0);
        char c = '\0';
        for(int i = 0; i < ac.length; i++)
            ac[i] = (char)((ac[i] ^ c++)+1);
        return new String(ac);
    }
   
    public static void main(String args[])
    {
            String my_title = "=(Modified by vhly[FR])=";
            System.out.println("Gen String:"+gen(my_title));
            System.out.println("     Method     "+ gen("Method"));
  System.out.println("DashO_Pro_cracked_:"+ gen("DashO_Pro_cracked_"));
    }
   
}

找到关于对话框中的 EVALUATION COPY 的相应加密内容
         String data[!*HVFJTG]AFF-OB`J9 ]:
          " (EVALUATION COPY)";

   使用直接修改类文件的方式,找到 上述内容
进行体换,替换为  [>*Pmamaonn+jv.yh}iJVGI@+] => “=(Modified by vhly[FR])=”

结果如下:



此画面为修给后的对话框,之前的 EVALUATION COPY 消失了,取代的是我的信息。

关于对于类生成后重命名的修改,由于生成的类,使用试用版会使用 DashEval_
作为前缀。我希望修改为 自定义的类名称

重点在于处理 hp.class,采用十六进制编辑器直接修改 CPUtf8

找到 DashEval_的字符串

Gen String:>*Pmamaonn+jv.yh}iJVGI@+
     Method     Newllb
DashO_Pro_cracked_:EarlL[WvhWjznofkuO
vwwwwvvwv_ gen:wwvuttqqW  // 使用这个
Gen String:>*Pmamaonn+jv.yh}iJVGI@+

在hp.class中找到两处包含 Earl的地方 注意时 CPUtf8格式
即: 01 short_len Ear....
     01 short_len Ear...

修改为  wwvuttqqW =〉 vwwwwvvwv_
        wwvuttqq =〉  vwwwwvvwv

之后的生成结果

类名为: vwwwwvvwv_a vwwwwvvwv_b vwwwwvvwv_c 等等
成员变量: 同理

最后对于舵手兄说的 JProbe我现在上班只有周日有时间,不过会继续努力的

Author: vhly[FR]
Date: 2006/10/03
Time: 03:33:33 AM
Have A Good Time And I will Sleep
All The Time Gen This 5 Hours

[课程]Android-CTF解题方法汇总!

收藏
免费 8
支持
分享
最新回复 (10)
雪    币: 328
活跃值: (39)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
2
vhly's JClassFile 类库 用于分析Java的 .class文件,同时提供修改类文件的能力。同时也可以对类文件进行再修改。

比如上面我们通过字符串获取程序 ,可以在将近几百个类文件中,恢复经过加密的字符串内容。

对于Zelix KlassMaster,可以使用者各类来获取他的字符串对象
2006-10-9 17:18
0
雪    币: 225
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ywb
3
呵呵,难得VHLY出来 一转,时间差,老是不见人
2006-10-9 18:10
0
雪    币: 450
活跃值: (552)
能力值: ( LV9,RANK:690 )
在线值:
发帖
回帖
粉丝
4
精华
舵手再回应vhly
2006-10-9 20:16
0
雪    币: 257
活跃值: (105)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
5
好文章,有空了下载一个试试,不知道这个软件的功能怎么样?

类修改的东西俺也写了一个,就是没你的功能强:)

winndy 把你压箱低的东西拿出来回应一下,让我们学习一下嘛!
2006-10-10 08:52
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
6
强烈学习中~~

另外,大哥,不要打击我的信心哦~~~我很菜的~
2006-10-10 10:22
0
雪    币: 257
活跃值: (105)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
7
申请一个试用版还没成功,whly有时间了给我发一个
2006-10-10 10:27
0
雪    币: 257
活跃值: (105)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
8
混淆效果还行,
注册成功后重新运行程序后报注册错误,
估计还是桩桩没除掉,还没细看

看来vhly上网时间不多,
破解时也没上网吧!
拔掉网线就不报错,
抓了一下包,果然有网络验证

POST /dotf/ARS HTTP/1.0
Content-type: application/x-www-form-urlencoded
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0rc3) Gecko/20020523
Host: www.preemptive.com
Connection: Keep-Alive
Content-length: 116

"2","oldpayreg","00112544CB4F","48625","12345","1.4.2_08","0","1","16","3.2","1160456783532","1160458814833","zh_CN"
2006-10-10 12:47
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
9
kava的文章一直少见啊.LZ强
2006-10-10 16:09
0
雪    币: 328
活跃值: (39)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
10
舵手兄,还是蛮行的,我家没有网,所以没法检测出网络验证的部分。

希望舵手兄提供一些
出错信息,我在处理以下。

为了提高这个帖子的人气,我会很快的处理分析的,但是最短
也要周日才能完成,其余实在没有时间
2006-10-10 17:04
0
雪    币: 257
活跃值: (105)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
11
从抓包的数据我猜测可能是网络验证,
跟了一下,找到问题所在,修改了一下就OK,
没有详细的看程序,所以还不能断定是网络验证:)

问题在cv这个类的h方法中
    public static c4 h() throws al {//this
                c4 var_c4 = b();
                if (!d()) {
                        var_c4 = a();
                        if (var_c4.b() == null)
                                throw new al((DashoProGuiEval.A_B_C_D("Zox$jqvt)|pmf\u007f{kc2|~5{et~l;pt>lmF\002")) + ae.d + DashoProGuiEval.A_B_C_D("/"));
                } else if (!e()) {
                        var_c4 = a();
                        if (var_c4.b() == null)
                                throw new al((DashoProGuiEval.A_B_C_D("Zox$jqvt)|pmf\u007f{kc2|~5{et~l;pt>lmF\002")) + ae.d + DashoProGuiEval.A_B_C_D("/"));
                } else {
                        var_c4 = b(ah);
                        if (ah) {
                                if (ac) {
                                        String string= (DashoProGuiEval.A_B_C_D("Ujlq%aqge}l\u0080fca0t\u007fck5{q8]yjtT1OnP\002KCX\006D`YAYOI\004\017\020a^XSHQ\027UXXO[`J\037G051d3!)$(<k@$n?;#3;3(1w$1={*:*@7\rB\025\007\027\027\020\t\007J\006\016M*\020\035\031?`$\007\033Y"));
                                        throw new al(string);
                                }
                                if (var_c4.b() == null && !ad) {
                                        if (var_c4.e()) {
                                                String string= (DashoProGuiEval.A_B_C_D("Jv#lfw'fnme,ycb0}\u007f}u5g\u0080z|};puun@eARLl\twVH\np~nb|oey~~\025DTFLQVV\035V`Ma#+'(/$$i0&:m9?,2&8!{vw\024:+3\025r\016-1A\t\022D\013\013\022H\r\001\032\013\017\002\014\014Q\005\035\010\036\032W\017\030\r[\033\021\022\022\t\u00a1\u00f6\u00eb\u00eb\u00f8\u00a6\u00e6\u00f0\u00ee\u00eb\u00e2\u00a8\u00ad\u00fb\u00e7\u00e7\u00f4\u00fa\u00b3\u00e2\u00f2\u00e5\u00e4\u00ff\u00eb\u00fd\u00ea\u00bc\u00f6\u00f4\u00eb\u00fb\u00d3\u00d0\u00c8\u00d8\u0085\u00c5\u00c6\u00c5\u00ce\u00db\u00da\u0086\u008d\u008e\u00e1\u00c1\u00c5\u00d5\u0093\u00c8\u00dd\u00d5\u00c3\u0098\u00cd\u00d2\u00e0\u009c\u00cf\u00d9\u00cb\u00df\u00aa\u00ae\u00e3\u00b6\u00a2\u00b8\u00b6\u00af\u00a8\u00a8\u00eb\u00b0\u00a4\u00a9\u00be\u00f0\u00bf\u00bf\u00a7\u00f4\u00a7\u00b1\u00a8\u00a3\u00b2\u00ac\u00c0\u00fc\u00a6\u00b3\u00ac\u0100\u0095\u008f\u00c3\u0081\u008d\u0081\u0086\u008d\u00c9\u0090\u0086\u009a\u00cd\u0099\u009f\u008c\u0092\u0086\u0098\u0081\u00db"));
                                                throw new al(string);
                                        }
                                        String string= (DashoProGuiEval.A_B_C_D("Zoxr%BhuaG(\\\u007fc/~vw|aahxdrwu<vo?wOXDPNB\t\010\tzGON_L\020T_]HVWC\030BWPJ\035L\\R%/1d4-30i1&??n?>@6(1!v&3+1<8}4,3\003\005\021D\003\013\025H\001\r\007\034C"));
                                        throw new al(string);
                                }
                        }
                }
                try {
                        c();
                } catch (Exception exception) {
                        /* empty */
                }
                return var_c4;
        }

可惜无法上传附件,不然可以把修改好了的传上来
2006-10-10 17:14
0
游客
登录 | 注册 方可回帖
返回
//