首页
社区
课程
招聘
[原创]纯手工Divbrush-V1.8算号器及Java程序拆解过程
2013-7-13 18:49 10204

[原创]纯手工Divbrush-V1.8算号器及Java程序拆解过程

2013-7-13 18:49
10204
今日写成Divbrush_v1.8的算号器,算是(部分)完美破解,因为机器码还不能通过程序直接计算出来。
下面是算号器效果图:
            
上图中的机器码是Divbrush软件中注册对话框上显示的机器码,使用该算号器时要填写这个机器码(本程序美中不足的地方)。
Divbrush软件的注册界面如下:
            

下面简单讲一下该软件的拆解过程

    1. 准备工具
    必备工具:jd-gui(因为关键程序是java程序)
    其他工具:PeID, ProtectionID, Spy++(不是必需)

    2. 检查程序
    用PeID和ProtectionId检查该程序都说本程序是MinGW编译的(?),但是用Spy++查看界面时看到是“SunAwtFrame”,所以断定该程序是java程序。
    所以这个时候就不要管exe主程序了,要找它的.jar包(即java可执行程序)!在相同目录下找到“dist”,然后找到out.jar。

    3. 反编译java程序包out.jar
    用jd-gui打开out.jar,在Main目录下找到RegJDialog,单击一下,在右侧会显示RegJDialog包的源程序。往下一翻就会看到“正式个人版”……字符串,这里就是判断验证码的关键代码。
    继续往下翻,找到真正有用的函数:private void jdMethod_if(ActionEvent paramActionEvent)。通过阅读这段函数知道这个函数就是注册对话框上的验证逻辑。
    后面就是顺藤摸瓜,把Divbrush程序的验证逻辑还原回来。

    4. 还原验证逻辑
    仔细研究刚才提到的函数:private void jdMethod_if(ActionEvent paramActionEvent),其中有这两句:
String str = this.txtNum1.getText() + this.txtNum2.getText() + this.txtNum3.getText() + this.txtNum4.getText();
if (this.serialNumber.a().equals(str))
{
    this.registerCompare.jdMethod_try();
    jdMethod_if();
}


    这两句就是把用户输入的验证码跟程序计算出来的验证码做了一个简单的对比。这里最重要的是函数:this.serialNumber.a()
这个函数用来计算出本机器的验证码。
    这个时候就请各位找到this.serialNumber(即class b)的定义吧,然后找到this.serialNumber.a()函数。

    5. 验证码如何计算出来
    顺着刚才的步骤,找到this.serialNumber.a()函数:
public String a()
{
    String str1 = jdMethod_if();
    try
    {
        MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
        localMessageDigest.update((str1 + "yolan").getBytes("UTF-8"));
        byte[] arrayOfByte = localMessageDigest.digest();
        k localk = new k();
        String str2 = localk.a(arrayOfByte);
        str2 = str2.toUpperCase();
        str2 = str2.replace('0', 'O');
        str2 = str2.replace('+', 'A');
        str2 = str2.replace('-', 'B');
        str2 = str2.replace('*', 'C');
        str2 = str2.replace('/', 'D');
        str2 = str2.replace('\\', 'E');
        str2 = str2.replace('!', 'F');
        str2 = str2.replace('@', 'G');
        str2 = str2.replace('#', 'H');
        str2 = str2.replace('$', 'I');
        str2 = str2.replace('%', 'J');
        str2 = str2.replace('^', 'K');
        str2 = str2.replace('&', 'L');
        str2 = str2.replace('(', 'M');
        str2 = str2.replace(')', 'N');
        str2 = str2.replace('=', 'W');
        str2 = str2.replace('|', 'P');
        str2 = str2.replace(',', 'Q');
        str2 = str2.replace('"', 'R');
        str2 = str2.replace(':', 'S');
        str2 = str2.replace(';', 'T');
        str2 = str2.replace('.', 'U');
        str2 = str2.replace('?', 'V');
        return str2.substring(0, 20);
    }
    catch (Exception localException)
    {
      localException.printStackTrace();
    }
    return null;
}


    6. 验证码的计算逻辑
    验证码的计算逻辑其实很简单:先计算出机器码的MD5值,然后把MD5中的字符做个一个很明确的替换,最后取字符串的前20位。验证码的计算到此完毕!

    7. 补充
    本人基本不懂Java,对反编译也入门较浅。请各位不吝赐教。
    不知道在文中张贴算号器源代码是否违反看雪的版规,望版主指点。

    8. 测试邀请
    算号器的源码暂时不张贴了,有需要验证码的兄弟就请把本人的机器码发给我吧,我把验证码发回去。

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞3
打赏
分享
最新回复 (3)
雪    币: 434
活跃值: (73)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zyicai 2013-7-15 11:41
2
0
谢谢楼主分享
雪    币: 235
活跃值: (160)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
XF[BCG] 1 2013-7-17 12:21
3
0
1、看了下,机器码应该是从这里传来的:jdMethod_if(); 分析下这个内容
2、注册是机器码加 yolan 字符串再MD5的吧?
        MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
        localMessageDigest.update((str1 + "yolan").getBytes("UTF-8"));
        byte[] arrayOfByte = localMessageDigest.digest();

另一个问题,按LZ说的:然后把MD5中的字符做个一个很明确的替换,最后取字符串的前20位。
像:str2 = str2.replace('@', 'G'); 是把@换成G,但MD5里不可能有@的吧...

以上说法如有错误,敬请指正。
雪    币: 95
活跃值: (85)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
ingvar 2013-7-17 21:40
4
0
[QUOTE='XF[BCG];1199755']1、看了下,机器码应该是从这里传来的:jdMethod_if(); 分析下这个内容
2、注册是机器码加 yolan 字符串再MD5的吧?
        MessageDigest localMessageDigest = MessageDigest.getInstance("MD5&...[/QUOTE]

非常荣幸得到您的批评指正

前面两点说的都非常正确:
1. 机器码确实是由 jdMethod_if(); 算出来的,它的实现是这样:
  
public String jdMethod_if()
  {
    DiskID localDiskID = new DiskID();
    return DiskID.DiskID().toUpperCase();
  }

其中DiskID这个类是在一个单独的DLL里面的,由于Divbrush程序是java做的,用C重写一遍会比较麻烦,所以我就偷懒了。
2. 第二条说的很对
3. 关于我说的“一个很明确的替换”也是偷懒了,其实字符串替换有两个地方,除了前面代码中显示出来的,还有一个是这一句:
      MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
      localMessageDigest.update((str1 + "yolan").getBytes("UTF-8"));
      byte[] arrayOfByte = localMessageDigest.digest();
[B]      k localk = new k();
      String str2 = localk.a(arrayOfByte);[/B]
      str2 = str2.toUpperCase();

    k这个类就是做字符串替换的:
public class k
{
  private static char[] a = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };

  public String a(byte[] paramArrayOfByte)
  {
    int i = paramArrayOfByte.length * 8;
    int j = i % 6;
    int k = 0;
    StringBuffer localStringBuffer = new StringBuffer();
    while (k < i)
    {
      int m = k / 8;
      int n;
      switch (k % 8)
      {
      case 0:
        localStringBuffer.append(a[((paramArrayOfByte[m] & 0xFC) >> 2)]);
        break;
      case 2:
        localStringBuffer.append(a[(paramArrayOfByte[m] & 0x3F)]);
        break;
      case 4:
        if (m == paramArrayOfByte.length - 1)
        {
          localStringBuffer.append(a[((paramArrayOfByte[m] & 0xF) << 2 & 0x3F)]);
        }
        else
        {
          n = ((paramArrayOfByte[m] & 0xF) << 2 | (paramArrayOfByte[(m + 1)] & 0xC0) >> 6) & 0x3F;
          localStringBuffer.append(a[n]);
        }
        break;
      case 6:
        if (m == paramArrayOfByte.length - 1)
        {
          localStringBuffer.append(a[((paramArrayOfByte[m] & 0x3) << 4 & 0x3F)]);
        }
        else
        {
          n = ((paramArrayOfByte[m] & 0x3) << 4 | (paramArrayOfByte[(m + 1)] & 0xF0) >> 4) & 0x3F;
          localStringBuffer.append(a[n]);
        }
        break;
      case 1:
      case 3:
      case 5:
      }
      k += 6;
    }
    if (j == 2)
      localStringBuffer.append("==");
    else if (j == 4)
      localStringBuffer.append("=");
    return localStringBuffer.toString();
  }
}
游客
登录 | 注册 方可回帖
返回