首页
论坛
课程
招聘
[原创]Java编辑器 IntelliJ IDEA 5.0的逆向分析 附加 RSA算法的简单分析
2006-10-10 15:29 9698

[原创]Java编辑器 IntelliJ IDEA 5.0的逆向分析 附加 RSA算法的简单分析

2006-10-10 15:29
9698
好高兴,我的一篇文章被设成了精华贴,我会继续努力的。
下面发表,我在十一放假期间的,另一个成果,希望大家借鉴

      Crack IntelliJ IDEA 5.0

   这是一个Java IDE,含有非常好的功能,因此来进行分析。

作者:vhly[FR]
日期:2006/10/04 - 2006/10/05
目标:IntelliJ IDEA 5.0
工具:DJ Java Decompiler 3.7.7
方法:静态分析、爆破(修改类功能重新编译)

简述:当程序执行时,首先检测是否已注册,
      如果未注册(如下文件未找到)将执行注册对话框,否则无法使用,没有试用设置
      ConfigPath + File.separatorChar + "idea50.key";
      ConfigPath + File.separatorChar + "idea40.key";
      SystemPath + File.separatorChar + "idea.license";
      BinPath    + File.separatorChar + "idea.license";

    可以找到注册验证方法,但是由于使用了大数运算的 modPow 方法,进行逆向运算时需要大量时间,
因此只进行爆破。

操作步骤:
  请将Patch_TNT目录下的 LicenseDataImpl_TNT_by_vhly[FR].class重命名为 LicenseDataImpl.class
  将改名后的类添加到 idea.jar 文件的 com/intellij/licensecommon/license/ 目录下
  运行:完成注册:注意序列号应该是这种个是 XXXXX-XXXXX-XXXXX-XXXXX-XXXXX

步骤1:分析注册验证方法

1) 寻找程序执行流程
   分析bin目录中的idea.bat文件,找出如下语句(用于执行软件)
         "%JAVA_EXE%" %JVM_ARGS% -cp "%CLASS_PATH%" %IDEA_MAIN_CLASS_NAME% %*
   其中JAVA_EXE 指向 java.exe; IDEA_MAIN_CLASS_NAME 指向 com.intellij.idea.Main
   因此要分析 com.intellij.idea.Main类的执行过程(IDEA采用了插件的方式,即使是Main类也是用插件管理的方式来运行)

   Main的执行流程:
       public static void main(String ... args) 执行软件入口点,该方法调用了插件管理器
              PluginManager.main(args, (com.intellij.idea.Main.class).getName(), "start");
                      此处执行插件管理器的调用 指定类的指定方法 即:调用 com.intellij.idea.Main类的方法 start() 参数为 args
                      由此可知 实际上执行了 Main.start(args);
       protected static void start(String as[]) 可以将这个方法看作类的入口之一
              if(!checkStartupPossible())   // 检查版本以及只可以有一个实例  支持 1.4以上
                    System.exit(-1);
              ......  // 日志设置
              mainImpl(as);  // 执行入口点 真正的main的实现
       protected static void mainImpl(String as[])
              .... // 界面设置 装载本地库
              if("Compuware".equals(ApplicationInfoImpl.getShadowInstance().getPackageCode())) // 返回空
                LicenseManager.setInstance(new CompuwareLicense());
              if("Fabrique".equals(ApplicationInfoImpl.getShadowInstance().getPackageCode()))  // 返回空
                LicenseManager.setInstance(new FabriqueLicense());
               
                由于上面的语句不会执行因此 LicenseManager.getInstance() 实际上会返回 IdeaLicense对象             

              LicenseManager.getInstance().startUp(new com.intellij.ide.license.LicenseManager.StartupAction(as) {  // 指定调用 方法 a(String args[])
                        // 调用验证的方法在此处调用
                        public void proceed()
                        {
                                        Main.a(args);
                        }

                        public void cancel()
                        {
                                System.exit(-1);
                        }
                });  // 调用startUp方法实际上执行了 proceed()方法 程序流程为 调用 Main类的 a(String args[])方法

        private static void a(String as[]) //执行程序
                IdeaApplication app = new IdeaApplication(as); // 此处为软件的执行过程 已经没有License验证le
                SwingUtilities.invokeLater(new Runnable(app) {
                            public void run()
                        {
                                app.run();
                        }
                });
   LicenseManager实例 对应 LicenseManager.getInstance();
        同时该类是个不完全抽象类
        private static LicenseManager a;
        public abstract boolean supportsRegistration(); // 是否可以注册
        public abstract void register(); // 调用注册
        public abstract void startUp(StartupAction startupaction); // 执行相应的命令
        public abstract String licensedToMessage();   // 显示 License To:
        public abstract String licensedRestrictionsMessage();
        public abstract LicenseFactory createLicenseFactory(); // 设置 LicenseFactory 用于或去注册数据 LicenseData
        public abstract boolean shouldCheckForUpdates(); // 检测升级
        public LicenseManager()
        {
        }
        public static LicenseManager getInstance()
        {
                if(a == null)
                    a = new IdeaLicense(); // 默认为 IdeaLicense (包路径com\intellij\ide\license\impl)
                return a;
        }
        public boolean isEap()  // what meen the "isEap"? HAHAHAHAAAA
        {
                return false;
        }

    通过startUp方法调用 Main.a(args);
        a(String args[])方法的步骤
                IdeaApplication app = new IdeaApplication(as); // 设定IdeaApplication
                同时由于 app又是一个 Runnable
                new Thread(app).start(); // 调用 IdeaApplication类的 run方法

    IdeaApplication类的执行流程
        protected IdeaApplication(String as[])  // 首先为构造方法 由 Main.a调用
        {
                c = true; //
                a.assertTrue(d == null); // a 使用了 log4J 的 Logger
                d = this;
                b = as;
                boolean flag = "true".equals(System.getProperty("idea.is.internal"));
                ApplicationManagerEx.createApplication("componentSets/IdeaComponents", flag, false, "idea");
               
                e = a(); // 返回 属性 com.intellij.appStarter 指定的类
                e.premain(as); // 内部类 IdeaApplication$IdeaStarter
                        premain(String args[]) // 方法预处理
                                final Splash splash = new Splash(ApplicationInfoImpl.getShadowInstance().getLogoUrl());
                                    SwingUtilities.invokeLater(new Runnable() {splash.show();});
                                装载开始画面
                                IdeaApplication.b(); // 调用 IdeaApplication方法 b()
                                        // 设置Alloy外观 注意以下为 Alloy 的注册信息 哈哈
                                        AlloyLookAndFeel.setProperty("alloy.licenseCode", "4#JetBrains#1ou2uex#6920nk");
                                        AlloyLookAndFeel.setProperty("alloy.isToolbarEffectsEnabled", "false");
                                        ...............
        }
        调用 IdeaApplication类的 run()方法
                public void run()
                {
                ApplicationEx applicationex = ApplicationManagerEx.getApplicationEx();
                                // 装载附加类库
                e.main(b); 调用 IdeaStarter 的 main方法 main(String ... args)
                e = null;
                }
        调用 IdeaStarter类的main方法
        public void main(String args[])
                ... // 应用程序扩展
                ((WindowManagerImpl)WindowManager.getInstance()).showFrame();  // 显示界面
        // 此时的程序如果可以执行到这里那么程序就可以使用了

但是 LicenseManager 和 IdeaLicense不会让程序执行到上述代码。
       
2) 分析 LicenseManager、IdeaLicense
重点分析 IdeaLicense
构造方法
public IdeaLicense()
    {
        Log.FACTORY = new IdeaLoggerFactory();
        d = LicenseFile.create();        // LicenseFile d; 创建授权文件类 便于 存储、读取
        MessagePolicy.setMessages(new LicenseMessagesImpl()); // LicenseMessageImpl 包含了全部的授权信息提示 包括出错、过期等信息
        g = createLicenseClient();  // ClientImplementation g; // 可以从这个类分析,但是现在没用
        NetworkLicenseSource networklicensesource = new NetworkLicenseSource(g);    // 网络认证 尚不考虑
        a(networklicensesource);
        a();  // 此处重要
    }

    private void a()
    {
        e = new LicenseAuthorizorImpl();  // LicenseAuthorizor 用于授权验证
        GetFromUser getfromuser = new GetFromUser(e, createLicenseFactory()); // GetFromUser 包含了通过用户获得的 Name & Key
        createLicensePolicyBuilder().createRegister(e, getfromuser, this, d, g);  // 重要 通过分析这个方法,可以找到验证
                // createLicensePolicyBuilder() 返回 PolicyBuild 类
        调用 PolicyBuild的如下方法流程:
                public void createRegister(LicenseAuthorizor licenseauthorizor, GetFromUser getfromuser, LicenseTarget licensetarget, LicenseTarget licensetarget1, LicenseClient licenseclient)
                {
                        addValidation(licenseauthorizor, getfromuser, licensetarget, licensetarget1, licenseclient);
                }  // 创建注册属性  // addValidation 添加 CheckValid命令类

                protected void addValidation(LicenseAuthorizor licenseauthorizor, GetFromUser getfromuser, LicenseTarget licensetarget, LicenseTarget licensetarget1, LicenseClient licenseclient)
                {
                licenseauthorizor.addPolicy(new NotNull(getfromuser));    // 注册信息不能为空 LicenseData
                addPoliciesForValidity(licenseauthorizor, getfromuser);     // 检测注册信息是否正确
                licenseauthorizor.addPolicy(new CheckNeedUpgrade(getfromuser)); // 检测升级
                licenseauthorizor.addPolicy(new CheckEvaluationExpired(getfromuser));  // 检测是否过期
                licenseauthorizor.addPolicy(new UserAcceptsLicense(new Cancel()));  // 当注册显示正确之后 显示授权内容 用户必须  accept
                licenseauthorizor.addPolicy(new SaveToTarget(licensetarget));  // 保存授权
                licenseauthorizor.addPolicy(new SaveFromUser(licensetarget1)); // 保存授权
                licenseauthorizor.addPolicy(new BroadcastUsing(licenseclient));  // 网络认证广播
                licenseauthorizor.addPolicy(new CheckWillNeedUpgrade(licensetarget1));  // 检查是否需要升级
                licenseauthorizor.addPolicy(new CheckWillExpire());   // 检查是否要过期
                licenseauthorizor.addPolicy(new Proceed()); // 执行正常的程序
                }  // 其中 addPolicy方法就是添加执行的命令

                protected void addPoliciesForValidity(LicenseAuthorizor licenseauthorizor, GetFromUser getfromuser)
                {
                        licenseauthorizor.addPolicy(new CheckCancelled(getfromuser));  // 检查是否被取消 即尚未注册
                        licenseauthorizor.addPolicy(new CheckValid(getfromuser));   // 检查是否正确
                }
               
                public class CheckCancelled extends MessagePolicy // 可以暂时不考虑

                public class CheckValid extends MessagePolicy
                {
                        public LicenseData check(AuthorizationAction auth, LicenseData licensedata)
                                throws TerminateCheckException
                        {
                                if(licensedata.isValid())  // 处理 isValid即可
                                        return licensedata;   // 着重分析 LicenseData
                                if(licensedata.isFromUser())
                                        getMessages().showLicenseInvalidMessage(); // 显示 出错信息
                                else
                                        getMessages().showLicenseCorruptMessage(); // 显示 推出
                                return myFail.check(auth, licensedata);
                        }
                }
    }

    public void register()
    {
        MessagePolicy.getMessages().setShowLicenseEntryAsDialog(true);  // 显示用户注册对话框
        MessagePolicy.getMessages().setRegistering(true);
        e.checkPolicy(new AuthorizationAction() {});
    }

3) 分析 LicenseData
LicenseData被定义为一个接口

public interface LicenseData  // 由 LicenseDataImpl 实现 也就是要修改的地方
{
    public abstract boolean willNeedUpgrade();
    public abstract boolean isAccepted();   // 是否接受
    public abstract void setAccepted(boolean flag);
    public abstract boolean needsUpgrade(Date date);
    public abstract String getKey(); // 获得序列号
    public abstract boolean isEvaluationExpired(Date date); // 是否过期
    public abstract boolean isValid();         // 重点分析 爆破点
    public abstract boolean isFromUser();
    public abstract boolean willExpire();
    public abstract long getTimeStamp();
    public abstract Date getExpirationDate(); // 获得过期时间 如果为 null 则永不过期
    public abstract String getUserName();        // 获得注册用户名
    public abstract boolean isNonCommercial();       // 注册类型
    public abstract boolean shouldDetectDuplicates();
    public abstract Date getUpgradeDeadline();
    public abstract boolean isPersonal();           // 注册类型
    public abstract boolean isYearAcademic();  // 注册类型
    public abstract boolean isOpenSource();       // 注册类型
    public abstract int getMajorVersion();  // 版本号
    public abstract int getProductId();         // 产品id
}

类 LicenseDataImpl

public class LicenseDataImpl extends AbstractLicenseData
{

    public static final int CURRENT_MAJOR_VERSION = 5;
    public static final Date DEAD_LINE_DATE = makeDate(2005, 8, 1);
    public static final Date FREE_UPGRADE_DATE = makeDate(2005, 4, 1);
    private static final long f = 0xa4cb80L;
    public static final String IDEA_VERSION = "IntelliJ IDEA 5";
    private LicenseInfo g;

    protected static Date makeDate(int i, int j, int k)
    {
        Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("Europe/Prague"));
        calendar.clear();
        calendar.set(i, j, k);
        return calendar.getTime();
    }
    public LicenseDataImpl(String s, String s1)
    {
        super(s, s1);
        g = null;
    }
    public LicenseDataImpl(String s, String s1, long l)
    {
        super(s, s1, l);
        g = null;
    }
    public String toString()
    {
        return getUserName() + ":" + getKey();
    }
    public boolean willNeedUpgrade()
    {
        if(getMajorVersion() >= getCurrentMajorVersion())
            return false;
        if(g.generationDate == null)
            return true;
        else
            return a(g.generationDate, FREE_UPGRADE_DATE);
    }
    protected int getCurrentMajorVersion()
    {
        return 5;
    }
    private boolean a(Date date, Date date1)
    {
        long l = date.getTime();
        long l1 = date1.getTime();
        return l < l1 - 0xa4cb80L;
    }
    public boolean needsUpgrade(Date date)
    {
        if(date == null)
            return false;
        if(date.before(getUpgradeDeadline()))
            return false;
        else
            return willNeedUpgrade();
    }
    public boolean isEvaluationExpired(Date date)
    {
        if(date == null)
            return false;
        if(!willExpire())
            return false;
        else
            return date.after(g.expirationDate);
    }
    public boolean isValid()
    {
            a();
        return true; // 注意 ******************* 修改之前为 return g != null;
   }
    private void a()
    {
        if(b())
            return;
        g = new LicenseInfo();   // 修改之前为 g = LicenseDecoder.decodeLicenseKey(s,s1); 用于验证 用户名序列号
        g.userName = "vhly[FR]"; // 由于 LicenseInfo 实际为数据类(可以直接修改变量)那么就用这种方法 可以修改为 g.userName = getUserName();
        g.customerId = 830213;   // My BirthDay is Good Luck!
        g.licenseType = 0;        // isCommercial() => true
        g.majorVersion = 2;
        g.minorVersion = 5;
        g.generationDate = new Date(2006,10,4);  // 生成时间
        g.expirationDate = null;          // 完成爆破 修改 LicenseDataImpl 类之后添加到 idea.jar文件中即可
                                        // 但是第一次的注册还是必须的
    }
    private boolean b()
    {
        return g != null;
    }
    public boolean willExpire()
    {
        return getExpirationDate() != null;
    }
    public Date getExpirationDate()
    {
        a();
        return g.expirationDate;
    }
    public boolean isNonCommercial()
    {
        a();
        return g.licenseType == 1;
    }
    public boolean isCommercial()
    {
        a();
        return g.licenseType == 0;
    }
    public boolean isSite()
    {
        a();
        return g.licenseType == 2;
    }
    public boolean isOpenSource()
    {
        a();
        return g.licenseType == 3;
    }
    public boolean isYearAcademic()
    {
        a();
        return g.licenseType == 5;
    }
    public boolean shouldDetectDuplicates()
    {
        return !isSite() && !willExpire();
    }
    public Date getUpgradeDeadline()
    {
        return DEAD_LINE_DATE;
    }
    public boolean isPersonal()
    {
        a();
        return g.licenseType == 4;
    }
    public Date getGenerationDate()
    {
        a();
        return g.generationDate;
    }
    public int getMajorVersion()
    {
        a();
        return g.majorVersion;
    }
    public int getProductId()
    {
        return g.productId;
    }
    public static LicenseDataImpl create(String s, String s1)
    {
        return new LicenseDataImpl(s, s1);
    }
    public static LicenseDataImpl createFromUser(String s, String s1)
    {
        LicenseDataImpl licensedataimpl = new LicenseDataImpl(s, s1);
        licensedataimpl.setFromUser(true);
        licensedataimpl.setAccepted(false);
        return licensedataimpl;
    }
    public static LicenseDataImpl create(String s, String s1, long l)
    {
        return new LicenseDataImpl(s, s1, l);
    }
}

4) 分析注册认证

LicenseDecoder 类的验证方法

需要使用的常量

    private static final BigInteger a = new BigInteger("86f71688cdd2612ca117d1f54bdae029", 16);
    private static final BigInteger b = new BigInteger("10001", 16);
    private static final BigInteger c = new BigInteger("846d7cf2385dddd654629dd2ba94ca87", 16);
    private static final BigInteger d = new BigInteger("10001", 16);
    private static final BigInteger e = new BigInteger("1030230a52c274c376605b2c1", 16);
    private static final BigInteger f = new BigInteger("10001", 16);

    public static LicenseInfo decodeLicenseKey(String name, String key)  throws InvalidLicenseKeyException
    {
        if(key.length() < 25)
            return a(name, key);
        LicenseInfo licenseinfo = new LicenseInfo();
        licenseinfo.userName = name;
        int i = 0;
        for(int j = 0; j < key.length(); j++)
        {
            char c1 = key.charAt(j);
            if(c1 == '-')
                i++;
        }  // 寻找 分隔符 - 的个数

        if(i != 5 && i != 4)          // 必须是4个或者5个
            throw new InvalidLicenseKeyException();
        if(i == 5)   // 当为5个的情况
        {
            int k = s1.indexOf('-');
            try
            {
                licenseinfo.customerId = Integer.parseInt(s1.substring(0, k));   // 开始的为用户ID 格式 XXXX-
                s1 = s1.substring(k + 1); // 真正的序列号为后面的4个 - 即格式为 XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
            }
            catch(NumberFormatException numberformatexception)
            {
                throw new InvalidLicenseKeyException();
            }
        } else //包含4个-的用户Id为-1
        {
            licenseinfo.customerId = -1;
        }
        
        BigInteger biginteger = LicenseUtil.decodeGroups(s1);  将序列号计算成 BigInteger
           /*调用
          public static BigInteger decodeGroups(String s) throws InvalidLicenseKeyException
         
                对于 s1的生成 可以使用 LicenseUtil.encodeGroups(BigInteger big) 使用任意 big
        */
        
        BigInteger biginteger1 = biginteger.modPow(b, a);     //   big **(b) mod a  序列号的大数 big 的 b次方 模 a
        byte abyte0[] = biginteger1.toByteArray();                    //  长度必须为12
                                                // 取结果的字节数组
        if(abyte0.length != 12)                             // 在此处目前无法找出长度为 12 的数值 只能到 16 或者 17
            if(abyte0.length == 13)
            {
                if(abyte0[0] == 0)
                {
                    byte abyte1[] = new byte[12];
                    System.arraycopy(abyte0, 1, abyte1, 0, 12);
                    abyte0 = abyte1;
                } else
                {
                    throw new InvalidLicenseKeyException();
                }
            }
            else if(abyte0.length < 12)
            {
                byte abyte2[] = new byte[12];
                System.arraycopy(abyte0, 0, abyte2, 12 - abyte0.length, abyte0.length);
                abyte0 = abyte2;
            }
            else
            {
                throw new InvalidLicenseKeyException();
            }
                         // 由于 使用了 modPow方法 对于逆向求解我还未找到相应的解法!!!!!!!!!!
                                need Help!!!!!!!!!!!!!!!!1
                    
        if(name != null)
        {
            short word0 = LicenseUtil.calculateCheckSum(name, licenseinfo.customerId, abyte0);  // 计算校验和
                                                                                //对于生成的数组 最后两位不会参与 CRC32计算
                                                                                // 也就时说 计算完 word0之后再设置
            if(abyte0[10] != (byte)(word0 & 0xff))                     // [10] = word0 & 0xff
                throw new InvalidLicenseKeyException();
            if(abyte0[11] != (byte)(word0 >> 8 & 0xff))                // [11] = word0 >> 8 & 0xff
                throw new InvalidLicenseKeyException();
        }

        licenseinfo.licenseType = abyte0[0] >> 4;                  // 0 - 5
        licenseinfo.productId = abyte0[0] & 0xf;                   // 5
        licenseinfo.minorVersion = abyte0[1] >> 4;                 // 2
        licenseinfo.majorVersion = abyte0[1] & 0xf;                // 5
        long l = ((long)abyte0[2] & 255L) + (((long)abyte0[3] & 255L) << 8) + (((long)abyte0[4] & 255L) << 16) + (((long)abyte0[5] & 255L) << 24) << 16;
        licenseinfo.generationDate = new Date(l);   // 4个字节 的long 作为创建时的时间数
        int i1 = (abyte0[6] & 0xff) + ((abyte0[7] & 0xff) << 8);  // 0 为0 则证明 永不过期
        if(i1 != 0)
            licenseinfo.expirationDate = new Date(l + (long)i1 * 24L * 60L * 60L * 1000L);
        return licenseinfo;   // 返回生成的 LicenseInfo 对象 如果执行成功 证明 验证正确
    }

完整的注册流程

String name,key;

if(key has 5 '-')
        getCustomerId(the first XXXXX)
        key = substring(4 -)
end if

long sum = 0
long temp = 0x39aa400L
for x each - splite key  // BigInteger LicenseUtil.decodeGroups(String key)
  // 每一个 XXXXX 从最后一格 XXXXX开始向前循环
  int k = decodeGroup(XXXXX)
  sum *= temp
  sum += k
end for

sum**b mod a => sum.modPow(b,a) -> result

result -> toByteArray -> buf

buf .length must 12

short crcsum (name, id, buf) buf的最后2位不参与运算 用于保存计算出的 crc校验和
0    1   2 3 4 5 6 7 8 9 10  11
T I MI MA D D D D E E X X  S   S

生成的字节数组格式

T  4bit  授权类型   0 - 5
I  4bit  产品ID     5
MI 4bit  min Version 5
MA 4bit  maj Version 2
D D D D  4Bytes    创建时间
E E      2Bytes    过期时间 0 永不过期
X X      2Bytes unknown  未知
S S      2Bytes CRC32    校验和

function decodeGroup(XXXXX) : return int
int k =0
  for each X in XXXXX // 逆序运算
        X = X to number  // if  '0' -> 0; '9' -> 9; 'A' -> 'A' -65 +10
        k *= 36
        k += X
  end for
取 一个数的 三十六进制数值
end function

6) 猜测的注册机方法

public String genKey(String name, int cid)
{
        byte buf[] = new byte[12];
        buf[0] = 5;
        buf[1] = 0x52;
        long l = System.currentTimeMills();
        l >>= 16;
        buf[2] = l & 0xff;
        buf[3] = l >> 8 & 0xff;
        buf[4] = l >> 16 & 0xff;
        buf[5] = l >> 24 & 0xff;
        buf[6] = 0;
        buf[7] = 0;
        buf[8] = 1;
        buf[9] = 1;
       
        short word = LicenseUtil.calculateCheckSum(name, id, buf);
        buf[10] = word & 0xff;
        buf[11] = word >> 8 & 0xff;

        BigInteger bt = new BigInteger(buf);
        // 计算出了 结果

        x**b mod a = bt  (bt = x.modPow(b,a));

        x = ?

        // 尚未找出正确的序列号
        BigInteger bigKey = ?
        String key = LicenseUtil.encodeGroups(bigKey);
        if(cid == -1)
                return key;
        else
                key = Integer.toString(cid).toUpperCase()+key;
        return key;
}

10月10日,经过这几天的分析。我终于发现
实际上序列号,是使用RSA的方法计算的
主要是

用户序列号 S (BigInteger)
授权信息   I (BigInteger) toByteArray()-〉授权数据

其中 LicenseDecoder中的 BigInteger a 为RSA公钥的指数部分
     LicenseDecoder中的 BigInteger b 为RSA公钥的指数部分

由于 IntelliJ 公司有 RSA 的私钥,所以只有 该公司才可以生成符合格式的
序列号。

对于这种方式,我们需要将 a,b替换为我们的公钥参数,
并且使用我们的私钥参数(e, b)执行序列号生成

byte [] buf = .... // 根据格式生成授权数据
BigInteger I = new BigInteger(buf);
BigInteger S = I.modPow(b, e); // 生成我们的 S序列号数值
String serial = LicenseUtil.encodeGroups(S);

完成

[2022冬季班]《安卓高级研修班(网课)》月薪两万班招生中~

收藏
点赞0
打赏
分享
最新回复 (5)
雪    币: 222
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
舵手 活跃值 3 2006-10-10 17:20
2
0
牛,看来又多一篇精华
雪    币: 4656
活跃值: 活跃值 (11830)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2006-10-10 17:56
3
0
最初由 vhly 发布
好高兴,我的一篇文章被设成了精华贴,我会继续努力的。
........


这是你自己努力结果,谢谢你与大家分享自己的心得。
雪    币: 331
活跃值: 活跃值 (155)
能力值: ( LV9,RANK:690 )
在线值:
发帖
回帖
粉丝
winndy 活跃值 17 2006-10-10 19:42
4
0
[QUOTE]最初由 舵手 发布
牛,看来又多一篇精华 [/QUOTE
舵手觅到知音了
雪    币: 11640
活跃值: 活跃值 (826)
能力值: ( LV12,RANK:779 )
在线值:
发帖
回帖
粉丝
readyu 活跃值 12 2006-10-10 22:23
5
0
不错。你的算法已经完全分析出来了。

这个是RSA-128,可以写keygen的。分解也就几s的时间。
把D和N套进你的算法,就是keygen了。
另外一个也一样的分解846d7cf2385dddd654629dd2ba94ca87。
推荐用RSAtool2:
http://www.pediy.com/tools/Cryptography/RSATool/RSATool.zip

N:
86F71688CDD2612CA117D1F54BDAE029
P1:
89EFF3CEE0AD466B
P2:
FA7BE669E19550BB
E:
10001
D:
430D187DE8BB3F18FB0A986E6B7163BD
雪    币: 114
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:530 )
在线值:
发帖
回帖
粉丝
lnn1123 活跃值 13 2006-10-10 23:55
6
0
文章不错,学习了
游客
登录 | 注册 方可回帖
返回