【文章标题】: 一款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传上来,我功力不够,请大牛逆向一下这种方式的加密原理。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
上传的附件: