首页
社区
课程
招聘
[原创]一个软件的逆向分析日志(一)(二)
发表于: 2007-5-10 21:50 13440

[原创]一个软件的逆向分析日志(一)(二)

2007-5-10 21:50
13440
在看雪论坛潜伏了好几年了 ,去年年底才注册帐号,现在忍不住了,上来发些帖子。
    我学过很多语言,但对Java只是纸上谈兵 ,看过两本书,但是几乎没写过代码。
    对于破解,我只是懂一点皮毛罢了,我用OD是为了看运行时一些变量的值,用IDA只是因为,用它看汇编比较好看 ……

    现在因为需要,要破解一个很大的软件系统,并写出注册机。这个系统,使用的语言包括Delphi、Java、C#三种,更郁闷的是,内部有个Delphi写的编译器,用来编译我在这个平台上写的代码,而在平台上写代码,所要调用的函数,由Delphi、Java、C#三种语言提供。它这个编译器,使用CLI规范,但又不完整……

软件限制就是:用这个平台的未注册版本开发的系统,限制了在线用户数量。
目前进度:已获释机器码产生算法,已确定注册后会生成一个授权文件。

    我想在这把对这个软件的破解记录下来,同时,也希望各位大侠帮忙解决一些碰到的问题。

    首先,我尝试了查找特征码的方法,因为在线用户超过限制时,会有提示,所以,我肯定这个信息来自Java写的一些类包。
    然后,我写了一段vbs脚本,调用最新版本的JAD,反编译了所有的jar包,包括JDK的,因为我担心它可能修改了JDK里面的jar,JDK是随着该软件发布的。用文本编辑工具UE,搜索所有反编译后的java文件,居然未发现该特征字符串。我已经打开JAD的-8选项,Unicode文字是可以显示了的,所以不存在乱码不能显示的可能。
那么,剩下两个可能:一,该字符串被加密了,如果是这样,我就肯定得放弃了,因为,仅仅jar包,就有四千多个,更不用说java文件了,我不可能找到它在哪里被解密,要不我也不用写脚本来处理了,我可是专门用了一台四CPU的服务器来反编译的;二,调用了外部程序取得该字符串,或者读配置文件了,配置文件我翻过了,没有。至于调用外部程序,这是常事,我今年才发现它调了一个DLL

    后来,通过网络抓包,我找到了在出错前它调用了服务器的最后的一个方法(它是用Hessian通信的)。正想到jar里面找这个方法,突然发现,这个目录怎么只有class没有java,手工再调一次jad,不行,提示不是java格式程序,开IDA,也说格式不对,用UE,天哪,都是十六进制的……
我在所有java文件中全面搜索这个jar的名字,发了在一个java中使用了它,也发现了它旁边的System.load方法,赶快上百度。看到这里,别笑我,我真的不懂Java!
我不仅搜到了这个方法的用法,还知道了它跟Java加密技术密切相关。原来是一个Java中用户动态加载类的方法,许多人重写了该方法的实现来保护Java代码。
下一步,搜索ClassLoader。得到近千条结果,不怕,服务器都不怕累,我也不怕,呵呵。慢慢检查发现,有一个类继承了URLClassLoader,重写的方法,与网上的保护方法极为类似,记下,继续看(我可不会因为找到一个而放弃后面的,那可是服务器大哥花了好几分钟帮我找到的呀),后面都没有可疑文件了。看来,这个类就是我要找的目标。
    重点查看构造函数和defineClass方法,因为构造函数可能初始化一些东西(使用了上面提到的那个jar包的路径),而加载类的核心,就在defineClass中。在defineClass中,只是做了一些准备工作,最重要的加载,而通过调用另外一个方法完成的,但我只看到该方法声明是这样的:public native Class。我猜测(真的不懂Java,反正C#中是这样的),它应该是调用外部native代码(不懂该怎么理解,反正我理解成PE格式之类的)。继续查找该类的可疑地方,发现一个static{}代码段,晕倒,又不懂是干嘛用的,我学过的语言里面,都没有这样的写法。不过不要紧,懂里面的代码就行了。哈哈,用System.load调了一个dll,它应该就是上面那个方法的所在地了。
    找到那个dll,首先PEid商场,“什么都没发现”。这已经没什么奇怪的啦,1G多的文件,鬼才知道哪个是用那种工具写的呢,再说,它自身就有编译器,搞不好就是他自己编译出来的。不管了,用IDA能打开就行。真的得来不费功夫,唯一的导出函数,名字就是上面的那个方法。赶紧进去看,好恐怖哦,好多好多var_xxx。看到下面的代码,哭笑不得:
sub     esp, 666h
mov     eax, dword_10066060
xor     eax, esp
mov     [esp+666h+var_4], eax
mov     eax, [esp+666h+arg_8]
mov     edx, [esp+666h+arg_14]
mov     ecx, [esp+666h+arg_10]
esp先减去一个数,然后用的时候,每次都加上……不知道是哪门子编译器搞的。
往下直到第一个call:
push    esi
mov     esi, [esp+688h+arg_0]
mov     edx, [esi]
mov     eax, [edx+18h]
push    esi
call    eax
这种方法,很像OO中调用一个对象的方法的做法(昨天刚学会的一点皮毛)。似乎esi就是这个对象,在call eax前,用了push esi,可能是想把这个对象做法参数传进去。
Java中那个方法声明有6个参数,而这里有7个arg,呵呵,真的很像。

现在只是想说 阿你托佛 ,保佑这个dll里面,没有再调用别的程序……毕竟是千山万水追到这里来的。

昨天发现的注册窗体的线索断了,现在正在请教vhly。解决了再发出来。

好了今天就写到这里了,我前天才刚开始接触Java的逆向,欢迎大家赐教!

[课程]Linux pwn 探索篇!

收藏
免费 7
支持
分享
最新回复 (14)
雪    币: 257
活跃值: (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
  嘿嘿~~~~~~~~顶一下
你又弄这些高级语言的东西了, 看得头很大的
2007-5-11 06:01
0
雪    币: 44229
活跃值: (19960)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
3
期待续篇,等全部完成再设精华
2007-5-11 09:13
0
雪    币: 79
活跃值: (35)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
4
ViperDodge
你真强!我这都让你发现了。

帮帮忙哦
2007-5-11 23:12
0
雪    币: 79
活跃值: (35)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
5
继续昨天的活。
    大概分析了一下DLL的那个导出函数,下面把它成为Load吧。
    一开始减esp,创建一块很大的栈区域用于存储本地变量。
    然后,把六个参数复制到本地变量中。除了这六个参数外,第一个参数可能是jvm函数表的地址,因为后面可以简单大量的:
    mov     esi, [esp+688h+jvm_base] ;jvm_base是我重命名后的
    mov     edx, [esi]
    mov     eax, [edx+18h]      ;18h可能是别的。有点类似于位移
    call    eax            ;动态调试发现,这个eax的值是jvm.dll里面的jvm.6D7355CE,可惜我没有这个库的sig,不知道它名字
    为了方便阅读,我在IDA中对这些变量进行了重命名。
    往下是是两个jvm的call,不知道干嘛的,不管它。第一个call前面,把那个重写ClassLoader的类的路径压栈。第二call后就是一个长长的跳转,跳到函数尾部的,嗯,这一般是参数检查之类的写法。结合那个类路径,我猜测是检查调用者是否是那个类,如果不是,则返回。工作还挺到位的。
    再往下,数百行都是mov指令,把常量一个个拷贝到本地变量中。变量名几乎是递减的。为什么说几乎呢?那是因为,有个别的顺序是乱的,不过在别的地方,肯定能找到“丢失”了的指令。这可真是费尽心思哦,如果我没猜错,这个就应该是一个密码之类的东西。往往破解者习惯搜索字符串常量来获得密码,这种方法,在这里就无效了,它其实已经是相当于把密码写在指令里面了,还故意搞乱了顺序,因而,这个库,很有可能是手工修改过的,甚至可能就是人工写的。因此,可以猜测,这是很重要的字符串(密码?)
    往下,就开始不断调用jvm的方法了,我整理了一下字符串参考,如下:
    "java/security/spec/X509EncodedKeySpec")
  "<init>")
  "java/security/KeyFactory")
  "(Ljava/lang/String;)Ljava/security/KeyFactory;")
  "getInstance")
  "(Ljava/security/spec/KeySpec;)Ljava/security/PublicKey;")
  "generatePublic")
  "java/security/Signature")
  "com/要创建的类名以及路径.class")
  "(Ljava/lang/String;)Ljava/security/Signature;")
  "getInstance")
  "(Ljava/security/PublicKey;)V")
  "initVerify")
  "update")
  "verify")
  "java/io/FileInputStream")
  "(Ljava/lang/String;)V")
  "<init>")
  "available")
  "read")
  "close")
  "DSA")
  "SHA1withDSA")
  "java/security/SecureClassLoader")
  "(Ljava/lang/String;[BIILjava/security/CodeSource;)Ljava/lang/Class;")
  "defineClass")
  看字符串参考,或者IDA识别出来的函数名,望文生义,是我在搞逆向中的常用方法。因为我比较熟悉VB,上次逆向一个VB的DLL的时候,几乎等于看VB代码,因为流程不是很复杂,所以,根本不用管本地变量怎么赋值,直接看函数名,就直到它想干嘛了。
  言归正传,从上面的字符串参考可以大概看出:先初始化了一个X509编码的实例,然后取得一个密钥工厂,生成一个公钥,接着取得数字签名对象,并用公钥初始化签名对象,取得被签名的数据,验证。
  然后声明FileInputStream,呵呵,开始读取文件了,不多说。
  DSA,鼎鼎大名的DSA非对称加密算法。
  SHA1withDSA,看到这,我只知道SHA1是一种散列算法,一般来说,散列算法和DSA结合起来使用,主要用于数字签名。其实,如果不懂这个是什么东西,只要上百度搜索一遍,马上就会明白了。
  综合上面的分析,可以发现,这里主要进行了数字签名,用于判断目标(可能就是那个类)是否被修改过。而上面猜测的那个密码,正是公钥。
  在信息安全中,为了确保信息的完整性,可以对信息进行数字签名。签名者持有一对密钥,分别是公钥和私钥,他使用私钥对信息进行签名,然后签名后的信息和公钥一起分发出去。另一方,就可以使用该公钥对信息进行签名验证,判断信息是否被修改过。公钥和私钥是唯一对应的。
  在这里,公钥存储与程序中,并且做了很好的保护,就是为了防止被人轻易获取。若第三方(比如我们)获取公钥,并可以修改,那么,他完全可以使用另外的一对密钥中的对信息进行签名,并把这里的公钥也换掉,那么,就算修改了信息,这里也会认为是没有修改过。这正是作者花费那么多心思来保护这个公钥的原因。
  回过头来,才发现,我的问题,根本就还没有解决。我猜测这里是解密class的,但并没有明显的痕迹。
  从上面的字符串参考可以看到,它已经调用SecureClassLoader的defineClass方法返回类对象了。从网络上的资料来看,调用defineClass前,类的字节码会作为参数传进去的。因此,我们可以修改SecureClassLoader类的defineClass方法拦截这些字节码。可惜,我不会Java,更不知道如何修改这个方法,这方面,我觉得 舵手 可以帮上忙。
  上面的字符串参考中间,穿插着一些本地的函数调用,偶然(对于破解工作来说,需要很多偶然)发现其中一个方法,其大无比,在IDA的流程图中,可以看到很多层循环。很遗憾,我没认真研究过各种加密算法的写法,不知道它是什么算法。直觉告诉我,这里是解密用的。因此,有了第二个获取class字节码的方法:把这个方法抽取出来,直接对class文件进行解密,希望除了这个函数外,作者没做过别的处理。
  第三种方法:动态调试,直接从内存中抽取解密后的字节码。这个方法对我来说,相对容易很多。但是,到现在为止,我还无法确定它把字节码存放在哪个地方。没有Client/JVM.dll的函数名,看到的全都是数字,想猜都猜不来。对于Java中方法的参数规范又不熟悉……
  
  这几天公司项目要很忙,这个软件的下一步逆向,就暂时压后一点,同时,也留一点时间查资料,已经请求论坛上各位高手的帮助。
2007-5-11 23:16
0
雪    币: 79
活跃值: (35)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
6
这个软件的逆向,还远远未完成.
这个DLL破解后,我才可以拿到那个jar包的字节码,还不知道能不能正常反编译呢.
要是能正常反编译,应该不用费多少时间,就可以分析里面的注册算法了.
不过,要是里面又是调用DLL来调用注册算法,我可就真晕了.
2007-5-12 15:37
0
雪    币: 79
活跃值: (35)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
7
早两天,在一个文件中文件了调用这个LoadClass的痕迹,现在是想这么做的:
另外仿造这个文件写一个java程序,任意加载一个被加密的jar包内部的类,使得它调用那个DLL。然后,我就可以用OD跟踪了。如果好运的话,可以从内存中把那些类的字节码抽取出来。反正我只是需要逆向那些字节码,从中得到注册算法,而不需要重新编译。

另外一种办法,就是强行分析DLL,看看它所调用的jvm.dll中的函数究竟干嘛用的。这样或许能得到加密算法。这种办法可能比较完美一点
2007-5-19 23:39
0
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
这种活还能搞下去,佩服你
2007-5-20 00:05
0
雪    币: 79
活跃值: (35)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
9
呵呵,都到了这个份上了,没什么好佩服的。

这个系统,安装文件就1G多,我是猜测并反了无数文件后,才把目标定位到这里来的。

同时,这里几乎可以说是它的最后防线了,因为别的文件,我几乎都看完了

它引用了很多别人的开源项目,那些文件我就不看了。

因为它自身就带有编译器,我花了很长时间才摸清这个系统的总体构架。

所以,来之不易。继续干活……
2007-5-20 02:44
0
雪    币: 328
活跃值: (39)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
10
今天才看到,不好意思,终于找到工作了,干得就是 Java Reverse Enginee,本来想在看雪
发一篇感谢的文章呢,不过真没时间,一天到晚跟 J2me Browser呢,
感觉你的这个 target 应该使用了 JNI,有一些 核心的东西 应该在 dll库中,
看了上面的 ConstantPool String 发现这个软件中至少一部分使用了 DSA算法,
大概是什么软件,如果使用 OD的话只能使用 JVM跟,那么工作量就太大了,我感觉可以使用
某些工具先把软件中的字符串信息找到,即使是英文的,同样也可以先理解以下,

不过最近开始对Java逆向,感觉多了个朋友了,哥们现在靠这个吃饭了。
还是要感谢一下看雪的各位朋友,没有你们,空拍我还在 Study Java呢,现在却是 Reverse Java
再次感谢。

auThOr: vhly[FR]
Date: 2007/05/29
2007-5-29 14:36
0
雪    币: 79
活跃值: (35)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
11
恭喜恭喜!

的确,DLL中对jar中的类进行解密,然后再调用LoadClass来加载类返回。
这些我知道,字符串参考究上面那些。
最麻烦的就是jvm,这个DLL用了很多jvm的函数,我连猜测都不可能了。就算我想硬来,也都不行……看来,我应该查查PE代码怎么调用jvm函数。
2007-5-29 16:38
0
雪    币: 44229
活跃值: (19960)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
12
真为你找到工作感到高兴
2007-5-29 19:38
0
雪    币: 79
活跃值: (35)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
13
谢谢vhly!

对这个软件的分析,在两条路线上,我都有了进展。

1,从注册程序入手。我修改反编译后的注册程序,再编译,调试,终于找出了注册授权文件的格式,前面是一些授权信息,后面似乎是一个校验码。我试过修改前面的授权信息,但是系统马上发现文件被修改过。所以,我肯定后面是校验码。但是,我也纳闷,它是47个字节的,实在想不到哪种校验方式是47字节的。因为是Java的原因,可能要出去三个字节,那就是44了。

2,上面分析的这个DLL,它根本不调用任何C/C++/API函数,调的全部都是JVM没有公开的函数。我在想,它是不是作者用软件把java程序转成DLL,然后手工混淆汇编代码。不过,我已经想办法取得了里面用到的大部分JVM函数的意义,也已经把部分汇编,反写成Java代码了。因为对JVM函数的参数传递搞不清楚,所以,目前还存在一些问题。

真想不到,为了这个,我学会了一点Java
2007-6-3 00:39
0
雪    币: 79
活跃值: (35)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
14
成功解决那些jvm函数的问题。
经过查找资料,最终确定,那个DLL,就是用JNI编译的。然后我也做了一个JNI的DLL,把可能的函数写进去,编译,用IDA看,对应一下就知道哪个地址是哪个函数了。
此外,我还发现一个更惊人的事情,在IDA中新建一个结构体用于存放JNI方法名的时候,发现,方法的顺序居然和jni.h头文件中方法顺序一致……呵呵,这回不用一个个猜了。

好了,吃饭了,先把jni的idc发上来,希望对大家有用。迟点我再把这些日子做的写上来。
目前一切顺利,已经到了最后一关了,正在破解DSA的私钥中……
上传的附件:
2007-6-7 12:09
0
雪    币: 325
活跃值: (97)
能力值: ( LV13,RANK:530 )
在线值:
发帖
回帖
粉丝
15
补充一句。 搂主的那个”哪门子“编译器应该就是Visual C++ 的编译模型,而且风格和VC6接近。如果真是自己的编译器或者VM。就不会这么写了哈  绝对不弄一个在堆栈执行代码是过不得哈:)
2007-6-7 13:13
0
游客
登录 | 注册 方可回帖
返回
//