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
但是有些初始值怎么定还是个问题

No comments:

Post a Comment