- UID
 - 28002
 
 注册时间2007-2-20
阅读权限20
最后登录1970-1-1
以武会友 
   
 
 
 
TA的每日心情  | 开心 2024-9-24 14:39 | 
|---|
 
  签到天数: 12 天 [LV.3]偶尔看看II  
 | 
 
这两天因学习需要,研究起了一款行业软件的逆向。该软件是Java编写的,主要功能就是作为服务器提供网络服务。 
    软件的许可方式是发布文件许可,以计算机名+时间为限制,条件全符合方可正常运行服务。因为许可服务那里有几个这样的文件,故确定是 Sentinel RMS 保护的:StartSenLM.bat、lservnt.exe、loadls.exe。 
    因为有关Java的逆向分析文章简直是太少了,仅找到过一篇像样的,主要是关于如何解包jar,反编译Class文件为java文件,或者根据JVM指令查找相应Class文件中的二进制指令并用HEX修改器修改的教程。没办法,自己就摸索着尝试搞一下。以下是流程,但到后面遇到了问题,不知如何解决,希望高手们帮忙看看。 
 
1.观察软件的log文件得到以下信息: 
============================================== 
2007-8-30 15:09:47 com.XXX.logging.Logger create 
信息: Logger(Service1) is created. 
2007-8-30 15:09:48 com.XXX.logging.Logger debug 
良好: 开始检查正式许可 
2007-8-30 15:09:58 com.XXX.logging.Logger warning 
警告: 检查正式许可发生错误,错误码:XXXXXXXXX 
2007-8-30 15:09:58 com.XXX.logging.Logger debug 
良好: 开始检查临时许可 
2007-8-30 15:09:58 com.XXX.logging.Logger severe 
严重: 检查临时许可发生错误,错误码:1 
2007-8-30 15:09:58 com.XXX.logging.Logger severe 
严重: Failed in starting service(Service1):  
java.lang.Exception: 检查临时许可发生错误,错误码:1 
 
com.XXX.service.Service.<init>(Service.java:94) 
com.XXX.service.ServiceFactory.getLocalService(ServiceFactory.java:421) 
com.XXX.server.Server.start(Server.java:77) 
com.XXX.server.Server.main(Server.java:180) 
2007-8-30 15:09:58 com.XXX.logging.Logger info 
信息: Server is to be exited. 
================================================ 
可以看出,该软件的许可有两种: 
 正式许可:肯定是没有时间限制的,估计与计算机名和硬件绑定。 
 临时许可:提供给开发人员临时开发用的许可,经验证申请到的临时许可,得知只与计算机名和系统时间有关。 
    如果服务启动时在指定目录下找不到许可文件或者找到错误的许可文件,就会:Server is to be exited. 
 
    下面开始动手: 
    检查软件安装目录,在Bin目录下发现 Server.jar 以及众多Dll文件,其中 startServer.cmd 中内容如下: 
..\thirdparty\jdk\bin\java -Xms128m -Xmx1024m -Djava.library.path=. -cp Server.jar com.XXX.server.Server -start Service1 
      说明服务功能基本上都是在 Server.jar 中实现的,当然可能也包含许可的验证。 
    关于Jar包,可以用WinRAR解压。解压 Server.jar 后得到一大堆的 class 文件。 
    接着上网又一通寻找 class 的反编译工具,经过验证发现 DJ Java Decompiler 几乎能反编译所有的 class。。。。 
    对 Server.jar 包中上百个文件的扫视,最后在 Service.class 中找到了重要的代码,反编译后关键内容如下: 
=============================================== 
       Logger.debug("\u5F00\u59CB\u68C0\u67E5\u6B63\u5F0F\u8BB8\u53EF");\\开始检查正式许可 
        long licValue = chkLic(true); 
        if(licValue != 0L) 
        { 
            String msg = "\u68C0\u67E5\u6B63\u5F0F\u8BB8\u53EF\u53D1\u751F\u9519\u8BEF\uFF0C\u9519\u8BEF\u7801\uFF1A" + licValue;\\检查正式许可发生错误,错误码: 
            Logger.warning(msg); 
            Logger.debug("\u5F00\u59CB\u68C0\u67E5\u4E34\u65F6\u8BB8\u53EF");\\开始检查临时许可 
            licValue = chkTrialLic(); 
            if(licValue != 0L) 
            { 
                msg = "\u68C0\u67E5\u4E34\u65F6\u8BB8\u53EF\u53D1\u751F\u9519\u8BEF\uFF0C\u9519\u8BEF\u7801\uFF1A" + licValue;\\检查临时许可发生错误,错误码: 
                Logger.severe(msg); 
                throw new Exception(msg); 
            } 
            Logger.info("\u68C0\u67E5\u4E34\u65F6\u8BB8\u53EF\u901A\u8FC7");\\检查临时许可通过 
        } else 
        { 
            Logger.info("\u68C0\u67E5\u8BB8\u53EF\u901A\u8FC7");\\检查正式许可通过 
        } 
=================================================== 
 
    看过这些心里就应该有数了吧,关键代码就是这一句: 
        if(licValue != 0L) 
   如果能把它改为: 
        if(licValue == 0L) 
    岂不是大功告成了。 
 
    问题又来了,总不能把反编译的源代码修改后再编译回去吧,没有了最初的开发环境,我想这是不可能的,唯一的办法就是直接修改 class 文件,但这样做首先要找到 JVM 指令对应的二进制代码地址。 
    在这里我想到了一个最蠢的办法:编写两段一样的简单的Java代码,然后修改一处指令,编译出只有这一出差异的两个 class 文件,用文件比较工具一看就知道代码差别了,于是开始动手写代码,并将文件Test1.java放于C盘根下: 
=================================================== 
public class Test1 { 
  public static void main(String[] args) { 
    int a=1; 
    if(a==0); 
  } 
} 
=================================================== 
    执行 c:\javac Terst1.java 得到了 Test1.class 
    将 if(a==0); 修改为 if(a!=0);,备份 Test1.java 后再次编译,得到另一个 class 文件,使用 UltraCompar 对照后发现只有一个字节的数据发生了变化,对应关系是: 
==  :   9A 
!=   :   99 
    也就是说,在 Server.class 只要找到 if(licValue != 0L) 这一句对应的 99 改为 9A 就可以完成指令的修改了。从上到下数了一下,这个不等号大概是第三个出现的,于是使用 UE 打开 Server.class 文件,搜索 99 ,的确找到了很多处,将代码区的第三个修改为 9A 后保存。为了验证修改是否到位,运行 DJ Java Decompiler 打开修改后的 Server.class 反编译,发现 
if(licValue != 0L) 这一句的确变成了 if(licValue == 0L),呵呵,理论上应该是成功了。 
   接下来使用 WinRAR 将修改后的 Server.class 保存到 Server.jar 中,运行程序,查看记录文件,赫然发现变成了如下内容: 
=================================================== 
2007-8-30 16:05:57 com.XXX.logging.Logger create 
信息: Logger(Service1) is created. 
2007-8-30 16:05:57 com.XXX.logging.Logger debug 
良好: 开始检查正式许可 
2007-8-30 16:06:07 com.XXX.logging.Logger info 
信息: 检查许可通过 
=================================================== 
    看到这些信息后心情无比激动,心里就一个念头:Java 破解原来这么简单啊!!!马上打开网页检查自己的成果,结果一下傻了眼,发现预期的功能并没有实现!到底哪里出了错?为什么检查许可都成功了还不能用? 
   带着这些疑问我又开始研究起来了.查看进程时,发现 Java 虚拟机并没有运行,列表中没有 Java.exe 这个进程,于是知道了程序可能还有暗桩,没准在哪里还有许可的判断。于是又开始读起代码来了,经过了数个小时的查找,发现其余的地方并没有与许可有关的指令,希望基本上破灭了。 
    正当我郁闷的时候,突然发现 bin 目录下赫然多出来一个文件:hs_err_pid2100.log 
上网一查,知道了这是 Java 虚拟机的错误报告,说明 Java 进程发生致命错误,崩溃后留下的日志。难道是我修改的地方有误导致进程崩溃?为了验证这一想法,我又自己编写了大量代码,用同样的方法修改,结果发现我的修改并不会引起程序的崩溃,所以断定不是由于修改错误代码引起的崩溃。 
    无奈之下看了看 hs_err_pid2100.log 中的内容: 
=================================================== 
# 
# An unexpected error has been detected by HotSpot Virtual Machine: 
# 
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x4925f9b0, pid=2100, tid=3176 
# 
# Java VM: Java HotSpot(TM) Client VM (1.5.0_04-b05 mixed mode) 
# Problematic frame: 
# C  [XxXxxxxxxxxxxx.dll+0xf9b0] 
# 
 
---------------  T H R E A D  --------------- 
 
Current thread (0x000362d0):  JavaThread "main" [_thread_in_native, id=3176] 
 
siginfo: ExceptionCode=0xc0000005, reading address 0x00000054 
 
Registers: 
EAX=0x00000000, EBX=0x430042e8, ECX=0x0000004c, EDX=0x00000000 
ESP=0x0007f914, EBP=0x0007f944, ESI=0x430042e8, EDI=0x000362d0 
EIP=0x4925f9b0, EFLAGS=0x00010283 
 
Top of Stack: (sp=0x0007f914) 
............................ 
==================================================== 
    到此为止已经一头雾水了,难道与 # C  [XxXxxxxxxxxxxx.dll+0xf9b0] 这个dll有关,可是挂上OD检查Dll一通后没有发现问题,真不知道究竟怎么回事。。。。。。 
。。。。。 
    经过FileMon的跟踪最后发现加密算法主要在 Wrapj.dll 中,但是偶的实力实在是搞不定了。 
。。。。。。。。。。。。。。。。。。 
    各位大侠看在我写了这么多分析文字后,一定要帮帮我啊,我先在这里谢谢啦。 
哪位有兴趣帮忙分析的话请PM我,我好告知具体软件和下载地址,但请不要公开软件名称,毕竟是国产软件嘛。 |   
 
 
 
 |