首页
社区
课程
招聘
[原创]一款JAVA商业软件的Class加密方法破解
发表于: 2012-12-28 15:40 15297

[原创]一款JAVA商业软件的Class加密方法破解

2012-12-28 15:40
15297

由于工作原因,经常与一款工业CAM软件打交道,对其中的一些算法非常感兴趣,便打算研究。
改软件核心代码全部是由JAVA写的,但是进行了加密,不能直接用反编译软件进行反编译。
查询运行java命令行发现其首先允许的是一个secure.jar中的SecureLoader类,此类没有进行加密。

使用JAVA反编译软件对SecureLoader进行反编译,可见其中存在如下native 方法的定义:

private native Class defineEncryptedClass(byte abyte0[], String s);

此native方法是在其secureloader.dll中定义的,用WIN32ASM打开,找到关键代码段如下:

:10001052 53                      push ebx
:10001053 57                      push edi
:10001054 6A04                    push 00000004
:10001056 55                      push ebp
:10001057 56                      push esi
:10001058 FF9220030000            call dword ptr [edx+00000320]
:1000105E 57                      push edi                             ;待解密数据长度
:1000105F 53                      push ebx                             ;待解密数据的地址
:10001060 E85B050000              call 100015C0                        ;解密函数
:10001065 8B442424                mov eax, dword ptr [esp+24]
:10001069 83C408                  add esp, 00000008
:1000106C 85C0                    test eax, eax
:1000106E 0F84AE000000            je 10001122
:10001074 50                      push eax

* Reference To: MSVCRT.??2@YAPAXI@Z, Ord:000Fh
                                  |
:10001075 E84C0D0000              Call 10001DC6
:1000107A 83C404                  add esp, 00000004
:1000107D 8BE8                    mov ebp, eax
:1000107F 6A04                    push 00000004
:10001081 6A04                    push 00000004
:10001083 6A04                    push 00000004
:10001085 6A04                    push 00000004
:10001087 6A04                    push 00000004
:10001089 6A04                    push 00000004
:1000108B 6A04                    push 00000004
:1000108D 6A04                    push 00000004
:1000108F 6A02                    push 00000002
:10001091 6860100000              push 00001060
:10001096 E895080000              call 10001930                       ;调用lzo_init()函数
:1000109B 83C428                  add esp, 00000028
:1000109E 85C0                    test eax, eax
:100010A0 7419                    je 100010BB

* Possible StringData Ref from Data Obj ->"lzo_init() failed !!!
"
                                  |
:100010A2 683C300010              push 1000303C

* Reference To: MSVCRT.printf, Ord:029Bh
                                  |
:100010A7 FF1508200010            Call dword ptr [10002008]
:100010AD 83C404                  add esp, 00000004
:100010B0 6A01                    push 00000001

* Reference To: MSVCRT.exit, Ord:0246h
                                  |
:100010B2 FF151C200010            Call dword ptr [1000201C]
:100010B8 83C404                  add esp, 00000004

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100010A0(C)
|
:100010BB 8B44241C                mov eax, dword ptr [esp+1C]
:100010BF 8D4C2414                lea ecx, dword ptr [esp+14]
:100010C3 6A00                    push 00000000
:100010C5 51                      push ecx
:100010C6 55                      push ebp
:100010C7 57                      push edi
:100010C8 53                      push ebx
:100010C9 89442428                mov dword ptr [esp+28], eax
:100010CD E80E090000              call 100019E0                      ;调用lzo_decompress()函数进行解密
:100010D2 83C414                  add esp, 00000014

对于解密方法和解压缩方法没必要进行详细研究,直接调用其函数即可,由此我写了一个类来实现,具体如下:

头文件:
#pragma once

#define LZO_E_OK (0)
typedef int (*LZO_INIT)(unsigned v, int s1, int s2, int s3, int s4, int s5,
                          int s6, int s7, int s8, int s9);
typedef int (*LZO_DECOMPRESS)( const BYTE * in , DWORD  in_len, BYTE * out, DWORD* out_len,int wrkmem);
typedef void(*XXX_DECODER)(BYTE *in,DWORD in_len);

class CLzoDecompress
{
public:
  CLzoDecompress(void);
  ~CLzoDecompress(void);

private:
  CString m_strDLLName;
  HMODULE m_hDLL;
  DWORD dwOff_init;
  DWORD dwOff_prevTreat;
  DWORD dwOff_decomp;
  DWORD dwOff_check;
  LZO_INIT fn_lzo_init;
  LZO_DECOMPRESS fn_lzo_decompress;
  xxx_DECODER fn_xxx_decoder;
private:
  bool CheckOffset(const BYTE * buff)
  {
    return (BYTE)buff[0] == (BYTE)0xE8 && (BYTE)buff[1] == (BYTE)0x0E && (BYTE)buff[2] == (BYTE)0x09;
  }
  void Init()
  {
    m_strDLLName = "secureloader.dll";
    dwOff_init = 0x00001930;
    dwOff_prevTreat=0x000015C0;
    dwOff_decomp = 0x000019E0;
    dwOff_check = 0x000010CD;
    fn_lzo_init = NULL;
    fn_lzo_decompress = NULL;
    fn_xxx_decoder = NULL;

    m_hDLL = LoadLibrary(m_strDLLName);
    if(m_hDLL == NULL)
    {
      AfxMessageBox("LoadLibrary failed!");
      return;
    }
    
    dwOff_check += (DWORD)m_hDLL;
    BYTE * szBuff = (BYTE *) dwOff_check;
    if(!CheckOffset(szBuff))
    {
      AfxMessageBox("CheckOffset failed!");
      FreeLibrary(m_hDLL);
      m_hDLL = NULL;
      return;
    }
    fn_lzo_init = (LZO_INIT)((DWORD)m_hDLL + dwOff_init);
    fn_lzo_decompress = (LZO_DECOMPRESS)((DWORD)m_hDLL + dwOff_decomp);
    fn_xxx_decoder = (xxx_DECODER)((DWORD)m_hDLL + dwOff_prevTreat);

    int r = fn_lzo_init(0x1060,2,4,4,4,4,4,4,4,4);
    if(r != LZO_E_OK)
    {
      AfxMessageBox("lzo_init failed!\n");
      FreeLibrary(m_hDLL);
      m_hDLL = NULL;
      return;
    }
  }
  void Destroy()
  {
    if(m_hDLL!=NULL)
    {
      FreeLibrary(m_hDLL);
    }
    dwOff_init = 0;
    dwOff_decomp = 0;
    dwOff_check = 0;
    fn_lzo_init = NULL;
    fn_lzo_decompress = NULL;
    fn_xxx_decoder = NULL;
  }
public:
  int LzoDecompress(LPCTSTR strFileIn, LPCTSTR strFileOut);
};

CPP文件

#include "StdAfx.h"
#include "LzoDecompress.h"

CLzoDecompress::CLzoDecompress(void)
{
  Init();
}

CLzoDecompress::~CLzoDecompress(void)
{
  Destroy();
}

int CLzoDecompress::LzoDecompress(LPCTSTR strFileIn, LPCTSTR strFileOut)
{
  CFile in;
  if(!in.Open(strFileIn,CFile::modeRead))
  {
    return -1;
  }
  CFile out;
  if(!out.Open(strFileOut,CFile::modeCreate|CFile::modeReadWrite))
  {
    in.Close();
    return -1;
  }
  //读取输入文件
  DWORD dwInLen = (DWORD)in.GetLength();
  BYTE *inBuff = (BYTE *)malloc(dwInLen);
  dwInLen = in.Read(inBuff,dwInLen);
  in.Close();
  //解压缩
  DWORD dwOutLen = 0;
  DWORD offset = 4;
  memcpy((void *)&dwOutLen,inBuff,4);
  BYTE *outBuff = (BYTE *)malloc(dwOutLen);
  ZeroMemory(outBuff,dwOutLen);
  
  BYTE *inBuff2 = inBuff + offset;
  fn_xxx_decoder(inBuff2,dwInLen - offset);

  int ret = fn_lzo_decompress(inBuff2,dwInLen - offset,outBuff,&dwOutLen,0);
  if(ret == LZO_E_OK)
  {
    out.Write(outBuff,dwOutLen);
  }else
  {
    CString str;
    str.Format("fn_lzo_decompress failed! %d",ret);
    AfxMessageBox(str);
  }
  free(inBuff);
  free(outBuff);
  out.Close();
  return ret;
}


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (9)
雪    币: 40
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
Java的商业保护加壳不多见啊! 顶一下楼主。

另外,能否告知加壳软件的链接?
2012-12-28 16:28
0
雪    币: 216
活跃值: (28)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
是这个公司自己开发的,暂时没发现有地方下载
2012-12-28 18:54
0
雪    币: 211
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不上软件 对别人来说简直在听人吹牛啊! - -!
2012-12-29 11:19
0
雪    币: 1579
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
  我这才发现,原来大牛们都不挂等级的,等级越低的,技术越牛啊,呵呵
2012-12-29 11:34
0
雪    币: 130
活跃值: (66)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习java加密技术,mark
2013-2-4 09:03
0
雪    币: 353
活跃值: (57)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
7
要是解压时需要读USB-Key就会麻烦许多,这样自解强度几乎为0。
2013-2-5 19:18
0
雪    币: 164
活跃值: (39)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
原来是这样啊~哈哈哈哈~我也在挂呢~
2013-2-11 12:42
0
雪    币: 164
活跃值: (39)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
这段时间正在苦学java,希望能用它玩儿一些加密的东西、
2013-2-11 12:42
0
雪    币: 164
活跃值: (39)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
这句话真犀利哦~
2013-2-11 12:43
0
游客
登录 | 注册 方可回帖
返回
//