Showing posts with label zend studio. Show all posts
Showing posts with label zend studio. Show all posts

Thursday, July 2, 2009

zend studio 7.0 beta的keygen写出来了。。。

十多行代码的函数
分析的时间超过了5天
但是官方的key却没法通过之前根据java代码重写的验证算法

anyway,

注册成功了 :P


感谢傅奎的支持和帮助



Zend Studio
Professional Edition

Build ID: 20090621

Licensed to: sskaje
Expires on: Never

Copyright (c) 1998-2008 Zend Technologies Ltd. All rights reserved.
Visit http://www.zend.com

This product is based on Eclipse technology.
Visit http://www.eclipse.org

Sunday, June 28, 2009

Zend Studio 7.0 Beta 注册验证分析(未完待补充)

查找 所有.class 文件夹,发现有一个 文件名为:RegisterAction.class的
在
Zend\Zend Studio - 7.0.0\plugins\com.zend.php.ui_7.0.0.v20090614-1641\com\zend\php\ui\actions
从目录看,应该是eclipse的图形化界面的shell接口操作

上一级目录中,有 PHPUIMessages.properties
其中发现有
RegisterAction.3=You will need to restart the workbench for the changes to take effect.\nRestart now?
SerialNumberDialog.5=The entered license key is invalid

等字样


使用jd-gui查看RegisterAction.class的代码
发现有

import com.zend.php.core.core.basic.c;
import com.zend.php.core.core.basic.d;

导入了两个class文件,这两个文件在一个jar中,直接解压
public void run(IAction paramIAction)
中
c localc = c.a(localr.a(), localr.b());
这个c就是import进来的basic.c
往下看
    if (localc == null)
    {
      MessageDialog.openError(this.a.getShell(), PHPUIMessages.a("RegisterAction.4"), PHPUIMessages.a("RegisterAction.0"));
      return;
    }
    try
    {
      d.b(localc);
      if (!(MessageDialog.openQuestion(this.a.getShell(), PHPUIMessages.a("RegisterAction.6"), PHPUIMessages.a("RegisterAction.3"))))
        return;
      PlatformUI.getWorkbench().restart();
    }
查查刚才的PHPUIMessages.properties
确认了一个事实:
可以猜测 localr.a() 和 localr.b() 取出的分别是 username 和 password
那么,首先用 c.a(a, b)进行计算,如果返回不为空,则进行 d.b(c) 的过程
根据返回值确定结果
PHPUIMessages.a()这个函数的参数,对应的那个 properties 文件的内容看,这个推断应该没错


好吧,首先看看 com.zend.php.core.core.basic.c
Zend\Zend Studio - 7.0.0\plugins\com.zend.php.core_7.0.0.v20090607-1658\com\zend\php\core\core\basic
用jd-gui打开 c.class
根据重载参数,找到
  public static c a(String paramString1, String paramString2)
  {
    c localc = null;
    try
    {
      if (localc != null)
        break label34;
      int k = Integer.parseInt(paramString2.substring(0, 1), 16);
      localc = f.a(k).a(paramString1, paramString2);
    }
    catch (Exception localException)
    {
    }
    label34: return localc;
  }

其中,f 是 com.zend.php.core.core.basic.parser.f
打开 Zend\Zend Studio - 7.0.0\plugins\com.zend.php.core_7.0.0.v20090607-1658\com\zend\php\core\core\basic\parser
再看参数
  public static b a(int paramInt)
  {
    if (3 == paramInt)
      return new e();
    throw new IllegalStateException("Unknown license version");
  }
也就是说,paramInt必须为3
那么回到前边的代码
localc = f.a(k).a(paramString1, paramString2);
k必须为3,这样就会返回一个 e();
于是,Integer.parseInt(paramString2.substring(0, 1), 16) == 3 ………………………………………………………………………………………… p2 第一个字符为3

进入 com.zend.php.core.core.basic.parser.e
看参数和返回值(localc = f.a(k).a(paramString1, paramString2);):
public c a(String paramString1, String paramString2)

这个代码:
      int i = Integer.parseInt(paramString2.substring(0, 1), 16);
      if (i != 3)
        return null;
再次验证了 p2[0] == 3的事实
String str1 = paramString2.substring(1, 3);
取出p2 的 [1] [2] 两个字符
String str2 = a(paramString2.substring(3, 16), str1 + paramString2.substring(16));
返回值是 String,看函数
private static String a(String paramString1, String paramString2)
其中是一个循环
算法的php实现是:
<?php
function a($p1, $p2) {
 $s = '';
 $i = 0;
 do {
  $j = 0;
  do {
   $s .= dechex(
    hexdec($p1[$i+$j]) ^ hexdec($p2[$j])
    );
  } while ($j < strlen($p2) && $i+$j < strlen($p1));
  $i += strlen($p2);
 } while( $i < strlen($p1) );
 return $s;
}
?>
根据这个16进制串的返回值,继续往后走,回到刚才的 a()
      int j = Integer.parseInt(str2.substring(0, 1), 16);
      int k = Integer.parseInt(str2.substring(1, 2), 16);
j 为 上一个返回 str2 的 [0], k 为 [1],两个都是10进制整数。
      int l = Integer.parseInt(str2.substring(2, 4), 16);
      int i1 = Integer.parseInt(str2.substring(4, 5), 16);
      int i2 = Integer.parseInt(str2.substring(5, 7), 16);
又是三个整数变量 然后根据前边定义的
Date localDate = null;
判断:
      if ((l != 0) || (i1 != 0) || (i2 != 0))
      {
        Calendar localCalendar = GregorianCalendar.getInstance();
        localCalendar.set(5, l);
        localCalendar.set(2, i1 - 1);
        localCalendar.set(1, 2000 + i2);
        localDate = localCalendar.getTime();
      }
//……………………………………………………………………………………………………………………代码求解释
      int i3 = Integer.parseInt(str2.substring(7, 9), 16);
      long l1 = Long.parseLong(str2.substring(9, 13), 16);
      long l2 = a(paramString1, i, str1, j, k, localDate, i3, l1).longValue();
      long l3 = Long.parseLong(paramString2.substring(16), 16);
又是对 str2的运算 其中,又将刚才算出来的localDate代入到另外一个a里边
private static Long a(String paramString1, int paramInt1, String paramString2, int paramInt2, int paramInt3, Date paramDate, int paramInt4, long paramLong)
这个函数里边主要做了一些字符串的合并,和时间数据的字符串化(ddMMyy),猜测可能是与expiration有关 补了00000在串后 而后加了一个crc32的计算校验 这个函数的返回值就是 那个 crc32的long值 而其中的那个00000的补全就不知道有何意义了………………莫非函数引用传值? 再次回到最初的a()
if (l3 != l2)
        break label403;
也就是说,l3 == l2 下边又是一个循环
      do
      {
        if ((()Math.pow(2.0D, i4) & l1) != 0L)
        {
          int i5 = 0;
          if (bool);
          do
          {
            localArrayList.add(d[i4][i5].getId());
            ++i5;
          }
          while (i5 < d[i4].length);
        }
        ++i4;
      }
      while (i4 < d.length);
这里的 localArrayList 在循环结束后
return new c(i, paramString1, j, k, localDate, i3, (String[])localArrayList.toArray(new String[localArrayList.size()]));
送进构造另外一个对象 这个c是 com.zend.php.core.core.basic.c ======================================================================================== 跳出加密验证部分 回到对话框界面的数据获取 还是 RegisterAction.class
    r localr = new r(this.a.getShell());
    if (localr.open() == 1)
      return;
    c localc = c.a(localr.a(), localr.b());
看看 r这个类的东西 package com.zend.php.ui.core.dialogs; 看看两个参数的获取:
  public String a()
  {
    return this.j.getText().trim();
  }

  public String b()
  {
    return this.k.getText().trim();
  }
i和j的定义在:
    this.j = new StringDialogField();
    this.j.setLabelText(PHPUIMessages.a("SerialNumberDialog.1"));
    this.j.setDialogFieldListener(new i(this));
    this.j.doFillIntoGrid(localComposite, 2);
    LayoutUtil.setHorizontalGrabbing(this.j.getTextControl(null));
    this.j.setFocus();
    this.k = new StringDialogField();
    this.k.setLabelText(PHPUIMessages.a("SerialNumberDialog.2"));
    this.k.setDialogFieldListener(new j(this));
    this.k.doFillIntoGrid(localComposite, 2);
    LayoutUtil.setHorizontalGrabbing(this.k.getTextControl(null));
对应的串:
SerialNumberDialog.1=User Name / Order #:
SerialNumberDialog.2=License Key:
断定数据肯定是在这儿了 但是刚才看了看6版的注册机,license首字节不是限制在1,2,-1之间(虽然6.1代码里只有这三个判断数据) 所以,我觉得这里肯定会有一些数据的预处理过程 继续找
Zend\Zend Studio - 7.0.0\plugins\com.zend.php.ui_7.0.0.v20090614-1641\com\zend\php\ui\core\dialogs
r.class
i.class
现在先尝试按照ui的流程将验证过程实现
然后再做keygen
但是有些初始值怎么定还是个问题