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

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6219|回复: 21
收起左侧

[原创] 一个从基因测序系统分离出来的基因算法(或遗传算法)组件包的注册分析及注册机

  [复制链接]
solly 发表于 2020-4-17 23:33
本帖最后由 solly 于 2020-4-17 23:43 编辑

    有一段时间没有发贴了,前段时间研究了一个基因测序软件有关的注册破解,当然我并不知道如何使用这个软件,并且没有仪器,软件也跑不起来,其代码是java编译的,
但是通过 Excelior Jet 7.6 预编译为一个 300 多兆的EXE执行文件了,是不能反编译成java源码的,不过其编译后,会在数据节中保留所有class和jar包的信息,但所有的jar包
的class文件都清成0字节长度了,只保留了 *.properties, *.xml 等资源文件,没有其它可用的信息了。本软件采用的是 FlexLM.jar + EccpressoAll.jar 进行授权管理的,但这两个
jar包中的class也已经被清成0字节了,经研究是采用的 11.9 版本的flexlm.jar。
    但是,由于java的jar库可存在多级打包的原因,以及其版本管理的问题(版本冲突,会出现一些jar包改名,导致没有编译),有几个jar包中的class没有被 Excelior Jet 清零,
其中就包括了本贴所含的算法组件,并且这个算法组件包自带单独的注册校验部分,应该是一个比较完整的算法库。
    这个组件是 GAComponents.jar,GA 表示 Genetic Algorithm 的意思,给有兴趣的各位玩玩,不懂的或没兴趣的,就不要看了。该jar包附在后面作附件
该组件目录结果如下:
20.png
上图中已反编译的几个类,就是这个组件的注册类,用来注册组件,如果注册成功,则生成一个UDP监听线程(端口5000,地址230.0.0.1),用于给算法授权。
其中 Registrar.class 主要代码如下:
[Java] 纯文本查看 复制代码
    public boolean checkLicense() {
        boolean licenseValidity = false;
        if (this.isLicenseExpired()) {
            this.displayMessage("This license has been expired. Please contact PE Biosystems Sales Representative.");
            return false;
        }
        final String licenseString = this.readLicense();
        if (licenseString != null) {
            licenseValidity = this.checkLicense(licenseString);
        }
        if (!licenseValidity) {
            final Frame aFrame = new Frame();
            aFrame.setIconImage(this.iconImage);
            final RegistrarView registrarView = new RegistrarView(aFrame, this);
            registrarView.show();
            if (this.license == null) {
                return false;
            }
            if (!this.checkLicense(this.license)) {
                this.displayMessage("The application could not start because the registration code is not valid.");
                return false;
            }
            this.writeLicense();
            licenseValidity = true;
        }
        if (this.validLicense == null) {
            return false;
        }
        this.appNumber = this.validLicense.getAppNumber();
        this.serialNumber = this.validLicense.getSerialNumber();
        this.numUsers = this.validLicense.getNumUsers();
        if (this.validLicense.isExceedsLegalLicenseCount(this.numUsers, this.license)) {
            this.displayMessage("The maximum concurrent user number of this license has been reached.");
            return false;
        }
        this.validLicense.startListening(this.license);
        return true;
    }

这个类调用另一个类进行注册码校验,这个类是 License.class,如下图所示:
21.png

其主要注册算法代码如下:
[Java] 纯文本查看 复制代码
    public boolean areLicenseDigitsValid() {
        final byte[] digit = new byte[11];
        this.appNumber = 0;
        this.serialNumber = 0;
        this.numUsers = 0;
        final long scrambleCode = this.licenseDigits[9] * 16 + this.licenseDigits[10];
        this.unscrambleDigits(this.licenseDigits, digit, scrambleCode);
        final byte crc = this.getCRCDigits(digit, 8L);
        final byte testCrc = digit[8];
        boolean valid = crc == testCrc;
        if (valid) {
            final int testSerialNumber = digit[0] * 4096 + digit[1] * 256 + digit[2] * 16 + digit[3];
            final int testAppNumber = digit[4] * 256 + digit[5] * 16 + digit[6] * 1;
            final int testNumUsers = digit[7];
            final int testScrambleCode = this.scrambleCode(testSerialNumber + testAppNumber + testNumUsers);
            valid = (scrambleCode == testScrambleCode);
            if (valid) {
                this.licenseHasBeenValidated = true;
                this.appNumber = (short)testAppNumber;
                this.serialNumber = (short)testSerialNumber;
                this.numUsers = (short)testNumUsers;
            }
        }
        return valid;
    }
    
    private byte getNthRandomByte(final long num) {
        final long kTwoToThe31MinusOne = 2147483647L;
        final long kTwoToThe31MinusTwo = kTwoToThe31MinusOne - 1L;
        final long kByteScaling = (kTwoToThe31MinusOne - 1L) / 256L;
        final long kTwoToThe32Plus1 = kTwoToThe31MinusOne * 2L + 2L;
        final long kSevenToThe5 = 16807L;
        long r = 1L;
        for (int k = 0; k < num + 12L; ++k) {
            r *= kSevenToThe5;
            r = (int)r;
            if (r < 0L) {
                r += kTwoToThe32Plus1;
            }
            r %= kTwoToThe31MinusOne;
        }
        final byte b = (byte)(r / kByteScaling);
        return b;
    }
    
    private void unscrambleDigits(final byte[] scramDigits, final byte[] clearDigits, final long scrambleCode) {
        for (int k = 0; k < 9; ++k) {
            final long scramblebyte = 9L * scrambleCode + k;
            final byte nthrandombyte = this.getNthRandomByte(scramblebyte);
            clearDigits[k] = (byte)(scramDigits[k] - nthrandombyte & 0xF);
        }
    }
    
    private byte getCRCDigits(final byte[] digit, final long numToCRC) {
        long crc = 0L;
        for (int k = 0; k < (int)numToCRC; ++k) {
            crc <<= 1;
            if (crc > 15L) {
                crc |= 0x1L;
            }
            crc += digit[k];
            crc &= 0xFL;
        }
        return (byte)crc;
    }
    
    private short scrambleCode(final long number) {
        short key = 0;
        final int scrambleCase = (int)number % 451;
        switch (scrambleCase) {
            case 0: {
                key = 90;
                break;
            }
            case 1: {
                key = 181;
                break;
            }
            //这里省略了400多个分支,可自己去反编译看源码
            case 449: {
                key = 101;
                break;
            }
            case 450: {
                key = 231;
                break;
            }
        }
        return key;
    }



    上面代码中的方法 areLicenseDigitsValid() 是注册码校验算法,注册码由11个字节组成,其中前8个字节是注册信息(含 3 字节的appNumber,4 字节的 serialNumber,1 字
节的userNumbers),第 9 字节是 CRC 32 较验,不过用了 4 bit,第10,11字节是一个加密key的索引值,用该key对前面的9字节进行加密。
注册检查时,会要求输入用户名,机构名和注册码,注册成功则会保存注册信息,下次再调用该检查函数时,就不会要求输入注册码了。
    注册算法并不复杂,看其源码很容易理解,注册机代码如下,两个 java 类文件:
主java类文件:Main.java 如下:
[Java] 纯文本查看 复制代码
import com.apldbio.gacomponents.library.registration.License;
import com.apldbio.gacomponents.library.registration.Registrar;

public class Main {
        
        public static void main(String[] args) {
                // TODO Auto-generated method stub
                //
                reg();
        }
        
        public static void reg() {
                
        short appNumber = 0x555;     /// 12 bits (1~0xFFF)
        short serialNumber = 0x6666; /// 16 bits (1~0x7FFF)
        short numUsers = 0x0F;       /// 4 bits (1~0x0F)
        
                LicenseKey key = new LicenseKey();
                String sn = key.getSN(serialNumber, appNumber, numUsers);

                System.out.println("SN: " + sn);
                
                //// check
//        License aLicense = new License(sn);
//        
//        if (aLicense.getCodeValidity()) {
//                        System.out.println("check1: ok");
//                } else {
//                        System.out.println("check1: fail");
//                }
//        
//        if (aLicense.areLicenseDigitsValid()) {
//                        System.out.println("check2: ok");
//                } else {
//                        System.out.println("check2: fail");
//                }
//
//        if (aLicense.getAppNumber() == appNumber) {
//                        System.out.println("check3: ok");
//                } else {
//                        System.out.println("check3: fail");
//                }
//
//        System.out.println("App No.: " + aLicense.getAppNumber());
//        System.out.println("Serial: " + aLicense.getSerialNumber());
//        System.out.println("Users: " + aLicense.getNumUsers());
                
                Registrar reg1 = new Registrar("d:/reg.txt", "991231", appNumber, null);
                boolean b = reg1.checkLicense();
        if (b) {
                        System.out.println("check: ok");
                } else {
                        System.out.println("check: fail");
                }
                
        }

}

其生成注册码在控制台显示,然后调用组件的注册函数,弹出一个对话框,要求输入注册码信息,注册码就是在控制台中显示的注册码。成功后就会生成注册文件 d:/reg.txt,
不过该文件不是文本格式的文件,生成该文件后,下次运行注册机就不会要求输入注册信息了,直接在Eclipse的控件台中显示校验成功。
上面代码中的 Registrar reg1 = new Registrar("d:/reg.txt", "991231", appNumber, null); 就是组件的校验类,调用其 checkLicense() 方法进行校验,第1个参数是注册文件名,
第2个参数是过期时间,“991231”表示 2099 年 12 月 31 日,第三个参数是appNumber,必须与注册码中的一致,第4个参数是一个图标,可设置为 null。

另一个是注册码计算的 java 类,文件是: LicenseKey.java,如下所示:
[Java] 纯文本查看 复制代码
public class LicenseKey
{
    private byte[] licenseDigits;
    private short appNumber;
    private short serialNumber;
    private short numUsers;
    
    final static short[] scrambleKeys = { /// 451 elements
                    90, 181, 255, 226, 162, 202, 55, 51, 228, 37, 43, 14, 183, 198, 199, 118, 137, 122, 38, 7, 8, 244, 50, 193, 218, 
                    241, 25, 235, 147, 185, 26, 227, 169, 127, 22, 107, 58, 142, 215, 130, 20, 141, 110, 66, 180, 182, 174, 150, 46, 
                    45, 210, 5, 170, 135, 149, 65, 54, 173, 146, 247, 74, 158, 19, 245, 9, 203, 248, 240, 222, 160, 129, 88, 108, 82, 
                    80, 49, 113, 84, 1, 176, 12, 3, 64, 6, 191, 47, 163, 184, 100, 251, 189, 73, 212, 39, 211, 239, 166, 188, 232, 
                    121, 17, 159, 42, 128, 161, 18, 109, 249, 79, 53, 116, 81, 167, 0, 77, 134, 139, 187, 56, 152, 168, 164, 83, 194, 
                    209, 172, 126, 151, 192, 145, 60, 196, 178, 94, 197, 186, 27, 224, 34, 230, 234, 213, 15, 96, 48, 44, 123, 231, 
                    52, 220, 179, 219, 148, 76, 41, 11, 29, 91, 36, 62, 144, 156, 28, 153, 92, 206, 106, 236, 204, 61, 89, 217, 223, 
                    238, 115, 40, 207, 86, 63, 154, 132, 68, 177, 102, 254, 131, 32, 175, 136, 229, 67, 75, 30, 114, 70, 237, 157, 93, 
                    120, 95, 165, 171, 71, 201, 221, 205, 125, 216, 97, 112, 119, 98, 99, 101, 140, 155, 24, 31, 250, 10, 4, 195, 72, 
                    138, 111, 59, 16, 246, 13, 200, 143, 23, 252, 124, 21, 105, 35, 57, 242, 117, 243, 103, 69, 85, 214, 133, 104, 33, 
                    233, 225, 253, 78, 2, 190, 208, 87, 204, 6, 241, 110, 140, 111, 200, 73, 56, 247, 188, 30, 237, 7, 240, 252, 217, 
                    87, 104, 131, 196, 130, 39, 14, 21, 41, 190, 107, 5, 211, 122, 230, 248, 78, 213, 177, 67, 102, 60, 195, 138, 79, 
                    84, 181, 141, 219, 245, 33, 222, 218, 36, 212, 244, 183, 186, 57, 234, 71, 156, 246, 154, 193, 129, 108, 225, 40, 
                    115, 151, 146, 253, 11, 109, 159, 135, 149, 116, 18, 194, 65, 152, 51, 2, 8, 228, 163, 62, 168, 150, 81, 192, 27, 
                    185, 13, 124, 16, 250, 61, 113, 83, 82, 167, 214, 98, 42, 31, 136, 93, 236, 95, 173, 139, 197, 32, 189, 207, 145, 
                    227, 117, 132, 224, 19, 176, 74, 191, 68, 216, 127, 208, 96, 0, 35, 172, 15, 29, 126, 48, 106, 174, 49, 220, 23, 
                    148, 166, 97, 64, 105, 158, 25, 4, 3, 38, 72, 24, 91, 9, 239, 10, 20, 55, 26, 88, 143, 77, 133, 75, 223, 155, 90, 
                    210, 164, 52, 242, 58, 238, 160, 125, 86, 85, 215, 182, 226, 251, 123, 187, 99, 112, 92, 147, 89, 203, 184, 76, 
                    44, 101, 231
    };
    
    public LicenseKey() {
        this.licenseDigits = new byte[11];
        this.appNumber = 1;
        this.serialNumber = 1;
        this.numUsers = 1;
    }
    
    public String getSN(short serialNumber, short appNumber, short numUsers) {
        byte[] digit = new byte[11];
        for (int k = 0; k < 11; ++k) {
//                digit[k] = 0;
                this.licenseDigits[k] = 0;
        }
//        this.serialNumber = 0x6666;
//        this.appNumber = 0x555;
//        this.numUsers = 15;
        this.serialNumber = serialNumber;
        this.appNumber = appNumber;
        this.numUsers = numUsers;

        long scrambleCode =  this.scrambleCode(this.serialNumber + this.appNumber + this.numUsers);
//        System.out.println("Scramble Code: " + scrambleCode);

        digit[0] = (byte) ((this.serialNumber / 4096));
        digit[1] = (byte) ((this.serialNumber % 4096) / 256);
        digit[2] = (byte) ((this.serialNumber % 256) / 16);
        digit[3] = (byte) ((this.serialNumber % 16));
        
        digit[4] = (byte) ((this.appNumber / 256));
        digit[5] = (byte) ((this.appNumber % 256) / 16);
        digit[6] = (byte) ((this.appNumber % 16));
        
        digit[7] = (byte) this.numUsers;
        
        digit[8] =  this.getCRCDigits(digit, 8L);
        
        digit[9]  = (byte) (scrambleCode / 16);
        digit[10] = (byte) (scrambleCode % 16);
        
        this.getScrambleDigits(this.licenseDigits, digit, scrambleCode);
        
        licenseDigits[9]  = digit[9];
        licenseDigits[10] = digit[10];
        
        
        String sn = convertLicenseDigitsToString();
        
        return sn;
    }
    
    private String convertLicenseDigitsToString( ) {
            String ss = "RBCDSWGHTJKLMNVP";
            StringBuffer sn = new StringBuffer();
            for(int i=0; i<11; i++) {
                    sn.append(ss.charAt(this.licenseDigits[i]));
            }
                
            return sn.toString();
    }

    private void getScrambleDigits(final byte[] scramDigits, final byte[] clearDigits, final long scrambleCode) {
        for (int k = 0; k < 9; ++k) {
            final long scramblebyte = 9L * scrambleCode + k;
            final byte nthrandombyte = this.getNthRandomByte(scramblebyte);
            scramDigits[k] = (byte)(clearDigits[k] + nthrandombyte & 0xF);
        }
    }

    
    private byte getNthRandomByte(final long num) {
        final long kTwoToThe31MinusOne = 2147483647L;
        //final long kTwoToThe31MinusTwo = kTwoToThe31MinusOne - 1L;
        final long kByteScaling = (kTwoToThe31MinusOne - 1L) / 256L;
        final long kTwoToThe32Plus1 = kTwoToThe31MinusOne * 2L + 2L;
        final long kSevenToThe5 = 16807L;
        long r = 1L;
        for (int k = 0; k < num + 12L; ++k) {
            r *= kSevenToThe5;
            r = (int)r;
            if (r < 0L) {
                r += kTwoToThe32Plus1;
            }
            r %= kTwoToThe31MinusOne;
        }
        final byte b = (byte)(r / kByteScaling);
        return b;
    }
    
    private byte getCRCDigits(final byte[] digit, final long numToCRC) {
        long crc = 0L;
        for (int k = 0; k < (int)numToCRC; ++k) {
            crc <<= 1;
            if (crc > 15L) {
                crc |= 0x1L;
            }
            crc += digit[k];
            crc &= 0x0FL;   // 4 bits
        }
        return (byte)crc;
    }
    
    private short scrambleCode(final long number) {
        int scrambleIndex = (int)(number % 451);
        return scrambleKeys[scrambleIndex];
    }
    
}



直接在 Eclipse 中运行注册机,如下图所示,在 eclipse 中的控制台输出中显示了注册码。
22.png
注册码输入界面如下图所示:
23.png



分析完毕,算法组件见附件:

GAComponent.rar (666.36 KB, 下载次数: 44)

免费评分

参与人数 13威望 +1 吾爱币 +27 热心值 +12 收起 理由
xiaokuntime + 1 + 1 我很赞同!
haoren + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Black_山猫 + 1 鼓励转贴优秀软件安全工具和文档!
sangong -1 + 1 用心讨论,共获提升!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
制冷设备 + 1 + 1 用心讨论,共获提升!
cdaxcy + 1 热心回复!
wfygyeeqy + 1 + 1 谢谢@Thanks!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
pubeer + 1 + 1 用心讨论,共获提升!
天空藍 + 1 + 1 用心讨论,共获提升!
王星星 + 1 谢谢@Thanks!
dzc999 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

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

 楼主| solly 发表于 2020-4-19 21:07
gzwking 发表于 2020-4-19 20:40
好吧 前一段想把这软件安装到中文版的win7 64上结果最后到登陆那 一直提示什么连接不到数据库 真是郁闷。 ...

是的,这个系统的原版也是英文系统正常,换成中文系统就有些问题,不过我只看其前面授权部分,后面连接设备及登陆不正常也无影响。
gzwking 发表于 2020-4-19 20:40
solly 发表于 2020-4-19 00:18
不是这个。是这公司之子品牌的另一个软件。

好吧 前一段想把这软件安装到中文版的win7 64上结果最后到登陆那 一直提示什么连接不到数据库 真是郁闷。虚拟机里的win7英文版就一路绿灯了
头像被屏蔽
王星星 发表于 2020-4-18 00:19
maya4610 发表于 2020-4-18 00:43
好高端的样子
烛光与香水 发表于 2020-4-18 07:09
不明嚼栗
雨落惊鸿, 发表于 2020-4-18 07:44
大哥牛逼
东方学痞 发表于 2020-4-18 08:05
学习一下,支持
wzzjnb2006 发表于 2020-4-18 08:16
很高端啊,看不懂。
头像被屏蔽
wzlmwyFLy2019 发表于 2020-4-18 08:47
提示: 作者被禁止或删除 内容自动屏蔽
一个辣鸡 发表于 2020-4-18 09:24
这个...真大佬
ZHANGZHILING 发表于 2020-4-18 09:31
好厉害。。。。大佬

您需要登录后才可以回帖 登录 | 注册[Register]

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

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

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

GMT+8, 2024-3-29 10:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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