首页
社区
课程
招聘
[原创]有关JAVA加密的例子比较少,为大家奉上一个。
发表于: 2007-3-9 10:35 12346

[原创]有关JAVA加密的例子比较少,为大家奉上一个。

2007-3-9 10:35
12346
【文章标题】: 一款JAVA CLASS加密软件的分析
【文章作者】: Rufus Xu
【作者邮箱】: my_home_page@163.com
【软件名称】: 保密
【软件大小】: 40K
【下载地址】: 无
【加壳方式】: 无
【保护方式】: 无
【编写语言】: VC++6.0
【使用工具】: OLLDBG
【操作平台】: WindowsXP
【软件介绍】: 加密JAVA编译好的CLASS,防止反编译
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
软件是用BAT启动的,内容如下:
@echo off

path = %path%;C:\Program Files\Java\jdk1.5.0\bin

java -agentlib:.\classloader -classpath "class;class/mssqlserver.jar;class/msbase.jar;class/msutil.jar;class/httpunit.jar;class/js.jar" startup.Start

就是使用自己写的DLL来装载JAVA CLASS类,以类装入以前完成解密过程。

查看导入表
Modul name:classloader.dll
More
        TimeDateStamp: 41BAC06B
        Version: 0.00
        Ordinal base: 00000001
        Number of functions: 0000000A
        Number of Names: 0000000A
       
  _Agent_OnLoad@12 rva: 00001000 ord:   1
  _Agent_OnUnload@4 rva: 00001470 ord:   2
  doExchange4Bits rva: 00001570 ord:   3
  doXor rva: 00001500 ord:   4
  encryptBuffer rva: 00001690 ord:   5
  getEncryptMarkSize rva: 000014C0 ord:   6
  getEncryptMarks rva: 000014F0 ord:   7
  getHeaderSize rva: 000014D0 ord:   8
  getLogined rva: 000014E0 ord:   9
  login rva: 000015D0 ord:  10

所以我们可以在_Agent_OnLoad的时候插入一个INT3,将OD设置成实时调试器。
运行该软件,OD会自动加载并停止在_Agent_OnLoad处,恢复代码,用OD插件查找有用的字符串信息可以找到如下过程:

10001280 >/.  55            PUSH EBP
10001281  |.  8BEC          MOV EBP,ESP
10001283  |.  51            PUSH ECX
10001284  |.  837D 20 1C    CMP DWORD PTR SS:[EBP+20],1C
10001288  |.  0F8E C2000000 JLE <classloa.loc_10001350>
1000128E  |.  6A 04         PUSH 4
10001290  |.  68 28820010   PUSH classloa.10008228
10001295  |.  8B45 24       MOV EAX,DWORD PTR SS:[EBP+24]
10001298  |.  50            PUSH EAX
10001299  |.  E8 620B0000   CALL <classloa._memcmp>
1000129E  |.  83C4 0C       ADD ESP,0C
100012A1  |.  85C0          TEST EAX,EAX
100012A3  |.  0F85 A7000000 JNZ <classloa.loc_10001350>
100012A9  |.  E8 22FFFFFF   CALL <classloa.sub_100011D0>
100012AE  |.  85C0          TEST EAX,EAX
100012B0  |.  74 05         JE SHORT <classloa.loc_100012B7>
100012B2  |.  E9 99000000   JMP <classloa.loc_10001350>
100012B7 >|>  8B0D 688B0010 MOV ECX,DWORD PTR DS:[10008B68]
100012BD  |.  83C1 01       ADD ECX,1
100012C0  |.  890D 688B0010 MOV DWORD PTR DS:[10008B68],ECX
100012C6  |.  8B55 20       MOV EDX,DWORD PTR SS:[EBP+20]
100012C9  |.  83EA 1C       SUB EDX,1C
100012CC  |.  8B45 28       MOV EAX,DWORD PTR SS:[EBP+28]
100012CF  |.  8910          MOV DWORD PTR DS:[EAX],EDX
100012D1  |.  8B4D 28       MOV ECX,DWORD PTR SS:[EBP+28]
100012D4  |.  8B11          MOV EDX,DWORD PTR DS:[ECX]
100012D6  |.  52            PUSH EDX                                 ; /Arg2
100012D7  |.  8B45 08       MOV EAX,DWORD PTR SS:[EBP+8]             ; |
100012DA  |.  50            PUSH EAX                                 ; |Arg1
100012DB  |.  E8 80000000   CALL <classloa.sub_10001360>             ; \classloa.10001360
100012E0  |.  83C4 08       ADD ESP,8
100012E3  |.  8B4D 2C       MOV ECX,DWORD PTR SS:[EBP+2C]
100012E6  |.  8901          MOV DWORD PTR DS:[ECX],EAX
100012E8  |.  8B55 28       MOV EDX,DWORD PTR SS:[EBP+28]
100012EB  |.  52            PUSH EDX                                 ; /Arg4
100012EC  |.  8B45 2C       MOV EAX,DWORD PTR SS:[EBP+2C]            ; |
100012EF  |.  8B08          MOV ECX,DWORD PTR DS:[EAX]               ; |
100012F1  |.  51            PUSH ECX                                 ; |Arg3
100012F2  |.  8B55 20       MOV EDX,DWORD PTR SS:[EBP+20]            ; |
100012F5  |.  52            PUSH EDX                                 ; |Arg2
100012F6  |.  8B45 24       MOV EAX,DWORD PTR SS:[EBP+24]            ; |
100012F9  |.  50            PUSH EAX                                 ; |Arg1
100012FA >|.  E8 01050000   CALL <classloa.sub_10001800>             ; \classloa.10001800
100012FF  |.  83C4 10       ADD ESP,10
10001302  |.  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX
10001305  |.  837D FC 00    CMP DWORD PTR SS:[EBP-4],0
10001309  |.  74 1A         JE SHORT <classloa.loc_10001325>
1000130B  |.  8B4D FC       MOV ECX,DWORD PTR SS:[EBP-4]
1000130E  |.  51            PUSH ECX                                 ; /Arg4
1000130F  |.  8B55 18       MOV EDX,DWORD PTR SS:[EBP+18]            ; |
10001312  |.  52            PUSH EDX                                 ; |Arg3
10001313  |.  68 40810010   PUSH classloa.10008140                   ; |Arg2 = 10008140 ASCII "Decrypt class: %s fail! Return code: %d
"
10001318  |.  68 90820010   PUSH classloa.10008290                   ; |Arg1 = 10008290
1000131D  |.  E8 A6060000   CALL <classloa._fprintf>                 ; \classloa.100019C8
10001322  |.  83C4 10       ADD ESP,10
10001325 >|>  833D 6C8B0010>CMP DWORD PTR DS:[10008B6C],0
1000132C  |.  74 22         JE SHORT <classloa.loc_10001350>
1000132E  |.  8B45 28       MOV EAX,DWORD PTR SS:[EBP+28]
10001331  |.  8B08          MOV ECX,DWORD PTR DS:[EAX]
10001333  |.  51            PUSH ECX                                 ; /Arg5
10001334  |.  8B55 18       MOV EDX,DWORD PTR SS:[EBP+18]            ; |
10001337  |.  52            PUSH EDX                                 ; |Arg4
10001338  |.  A1 688B0010   MOV EAX,DWORD PTR DS:[10008B68]          ; |
1000133D  |.  50            PUSH EAX                                 ; |Arg3 => 00000000
1000133E  |.  68 6C810010   PUSH classloa.1000816C                   ; |Arg2 = 1000816C ASCII "%d. class %s decrypted successfully, class data size: %d bytes.
"
10001343  |.  68 90820010   PUSH classloa.10008290                   ; |Arg1 = 10008290
10001348  |.  E8 7B060000   CALL <classloa._fprintf>                 ; \classloa.100019C8
1000134D  |.  83C4 14       ADD ESP,14
10001350 >|>  8BE5          MOV ESP,EBP
10001352  |.  5D            POP EBP
10001353  \.  C2 2800       RETN 28

如上代码,在100012FA处的CALL一定是完成解密的过程,我们在此下断,F9运行。OD断下以后,可以在堆栈如下:
0007EC84   00C1A9F8  |Arg1 = 00C1A9F8
0007EC88   0000071B  |Arg2 = 0000071B
0007EC8C   00C1B120  |Arg3 = 00C1B120
0007EC90   0007ED20  \Arg4 = 0007ED20
0007EC94   10001280  <classloa.sub_10001280>
0007EC98  /0007ED38
0007EC9C  |6D6F78EE  返回到 jvm.6D6F78EE
0007ECA0  |00035930  ASCII "xAxm"
0007ECA4  |000368A4
0007ECA8  |00000000
0007ECAC  |00BD54D4
0007ECB0  |000363C8  ASCII "startup/Start"

对比该软件发现startup/Start就是其中的一个类了。
对比Start.Class文件,发现
Arg1 = 00C1A9F8  <----存放解密前的文件。
Arg2 = 0000071B  <----存放解密前的文件大小
Arg3 = 00C1B120  <----存放解密后的文件
Arg4 = 0007ED20  <----存放解密后的文件大小

F8单步运行,再把以00C1B120为起始地址的数据拷贝出来(大小DS:[0007ED20]),另存为Start.Class再拿JAVA的反编译工具反编译就可以得到CLASS的源码了。

把DLL传上来,我功力不够,请大牛逆向一下这种方式的加密原理。

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

上传的附件:
收藏
免费 0
支持
分享
最新回复 (10)
雪    币: 238
活跃值: (116)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
...

很幸运的最近写了一篇关于这个技术的文章

http://ccfblog.com/blog/FiNALSErAPH/archives/2007/3039.shtml
2007-3-9 17:15
0
雪    币: 259
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
我不是想得到加密算法,而是想知道JAVA的代理原理。
2007-3-9 17:31
0
雪    币: 238
活跃值: (116)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
最初由 rufus 发布
我不是想得到加密算法,而是想知道JAVA的代理原理。


就是将加密后的class在内存中动态解密然后交给JVM执行咯。JAVA本身支持的一种自定义classloader机制,只是这里用来加密罢了...
2007-3-9 17:37
0
雪    币: 208
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
学习一下~~~~~~~~~~
2007-3-9 18:04
0
雪    币: 259
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
6
就是将加密后的class在内存中动态解密然后交给JVM执行咯。JAVA本身支持的一种自定义classloader机制,只是这里用来加密罢了...


这样的解释网上多的是,有没有详细的设计规范呢?
2007-3-9 20:58
0
雪    币: 238
活跃值: (116)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
最初由 rufus 发布
这样的解释网上多的是,有没有详细的设计规范呢?


你的问题写的并不明确,要求回答到何等程度也没个说明。你这样的回复比较打击别人回复的积极性!

遇到问题你应该仔细利用搜索引擎!尽量找官方的解释文档...

关于java classloader,我刚搜了一下,找到如下连接:

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html

http://www.panix.com/~mito/articles/articles/classloader/j-classloader-ltr.pdf

个人认为
_Agent_OnLoad@12
_Agent_OnUnload@4

这两个输出函数就是关键了!

这部分内容应该隶属于JVMTI(Java 虚拟机工具接口 Java Virtual Machine Tool Interface)

http://java.sun.com/developer/technicalArticles/Programming/jvmti/

http://www.chinaitpower.com/A200508/2005-08-05/183486.html
2007-3-9 23:27
0
雪    币: 259
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
8
最后一个链接比较喜欢。

为什么微软的.net不提供这样一个接口呢?
2007-3-10 08:50
0
雪    币: 257
活跃值: (105)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
9
个人认为利用classloader对class进行加密起不了什么作用,因为在把class交给jvm前,必须进行正确的解密,classloader往往就是解密程序,或者调用解密程序,但你不能再对解密程序进行加密(可以混淆),反编译classloader所在类就能很容易写出一个用来还原加密的class。
2007-3-10 08:56
0
雪    币: 259
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
10
只不过将中间语言的保护转化成传统的WIN32可执行程序的保护。
2007-3-10 10:28
0
雪    币: 79
活跃值: (35)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
11
一般来说,这样方式加密,最大的弱点就是classloader自身的安全问题。正因为这样,才有了调用DLL的想法的。

在ClassLoader中,调用某个DLL的函数来加载类,然后DLL中读取目标文件,解密,然后又调用系统的ClassLoader来加载这个类。因此,做好DLL的保护工作就可以了
2007-5-20 03:05
0
游客
登录 | 注册 方可回帖
返回
//