(转载)Java类加载过程解析

前言

最近分析了一款叫VeSys的软件,未对这个软件做深入了解,只奔着需求点分析

需求点就是分析出新建用户的默认密码是什么,这个软件也够奇葩的,新建的用户密码不能修改,也看不到默认密码(非空密码),就导致新建的用户也登录不上…
分析过程中遇到*.cjar文件,里面是加密的class的文件,需要先把class文件解密了才能愉快的分析需求…

在这里插入图片描述

以下为记录分析*.cjar的过程,本文仅研究学习使用

开始分析

程序类型

首先看看软件由什么语言编写的
运行起来,确定主进程是VeSys.exe

再用Detect It Easy扫一下主程序文件
在这里插入图片描述
好家伙,是个64位的程序,但是并不妨碍我们继续分析,这里使用x64dbg附加一下这个进程
再看看调用的模块都有什么
在这里插入图片描述
发现Java虚拟机一套,到这里可以确定这个程序应该是Java编写的

分析调用的Jar包

使用x64dbg查看一下文件句柄
在这里插入图片描述

记录调用的Jar包路径都有哪些,然后就可以转移阵地了,使用IDEA远程调试
主要jar包路径是
C:\MentorGraphics\VeSys\jre\lib
C:\MentorGraphics\VeSys\lib

使用IDEA新建一个工程,导入以上路径的Jar包
在这里插入图片描述
发现有一部分jar包并没有被识别到,这些jar包后缀名都有点特别,都是叫*.cjar
在这里插入图片描述

挑一个,把后缀名改成rar,用解压软件打开看看是否能识别
在这里插入图片描述
发现还是可以识别的,初步怀疑是不是IDEA只认*.jar的后缀名,其他后缀名一律不认,尝试把*.cjar改成*.jar文件,然后再导入IDEA试一下
在这里插入图片描述
导入之后IDEA可以识别了,但是反编译的class文件一片空白,这里再使用UE单独打开Class文件确认一下里面的内容
在这里插入图片描述
好家伙,除了头部4字节是正常的class文件的标志,其余数据都是加密的,到这里就可以确定*.cjar的文件都是加密的Class

分析解密Class文件

猜一下这些Class文件都是用什么加密的
首先可以排除的就是简单的异或运算加密,因为加密的内容毫无规律,相邻的几个字节基本上都不会重复
猜测可能用了对称加密算法,对称加密我第一想到的就是AES和DES算法

先百度一下,看看AES算法怎么加密的
1.使用java实现AES加密
https://www.cnblogs.com/codegeekgao/p/8336118.html
在这里插入图片描述

挑出关键的接口,如SecretKeySpec,加密肯定要生成key的
接下来回到IDEA,找到SecretKeySpec实现的地方,都打上断点
在这里,IDEA作为监听端,VeSys.exe作为客户端,重新启动VeSys.exe等待进入远程调试环境
在这里插入图片描述
果然命中断点了,查看调用栈,发现两个比较敏感的名字:DecryptClass、MGClassLoader(解密Class,加载Class文件)
马上就能看到解密的代码了,兴奋的点击DecryptClass,发现没有找到对应的Class文件!MGClassLoader同样也没有找到!
在这里插入图片描述

此时怀疑可能有遗漏的jar包没有导入到工程里,所以找不到对应的Class文件
这里再次使用x64dbg附加一下进程,再检查一遍调用的jar包文件句柄
在这里插入图片描述

程序刚启动初期,被加载的jar包实在少的可怜,只有这3个
单独挑出这3个jar包:charset.jar、jce.jar、rt.jar
然后使用解压文件,将里面所有class文件解压出来,然后搜索一下DecryptClass、MGClassLoader
最后一无所获,到这里,可以排除导入jar包遗漏的问题了
那么这2个class文件到底藏在哪里呢

寻找隐藏的DecryptClass…

首先猜测DecryptClass、MGClassLoader这两个class文件,可能被嵌入到exe里面了

经过一番百度,发现一片文章讲得不错,恶补了一下关于ClassLoad的相关知识
参考文章:Java 类是如何被加载
https://www.sohu.com/a/331624683_612370

ClassLoader

Class文件再怎么玩,最后也是调用ClassLoader进行加载,只要找到ClassLoader相关的地方,打上断点就能看到所有加载的Class文件

尝试1

在IDEA里面找到与ClassLoader相关的代码、接口都打上了断点
参考文章:Java 类是如何被加载,关于ClassLoader的我挑了3个接口:FindSystemClass、LoadClass、DefineClass
全都打上断点,然后重启程序,发现都没有触发断点…
FindSystemClass
在这里插入图片描述
LoadClass
在这里插入图片描述
DefineClass

在这里插入图片描述

尝试2

上面使用x64dbg查看过jvm.dll模块,发现调用的是目标程序路径下自己的jvm.dll
猜测jvm.dll应该做过手脚,在C++层实现一些不为人知的秘密

转到x64dbg,找到jvm的导出接口,通样挑出了3个比较可疑的接口:JVM_DefineClass、JVM_DefineClassWithSource、JVM_LoadClass0都打上断点
然后重启程序,发现都没有触发断点…
在这里插入图片描述

尝试3

到这里,依然没有找到结果
参考文章:Java 类是如何被加载
先简单捋一下文章提及到的ClassLoad加载要点

1.利用ClassLoader加载类
2.调用ClassLoder类的loadClass()方法即可
3.loadClass()方法最终会调用到ClassLoader.definClass1()中,这是一个 Native 方法
4.definClass1()对应的 JNI 方法为 Java_java_lang_ClassLoader_defineClass1()
5.Java_java_lang_ClassLoader_defineClass1()主要是调用了JVM_DefineClassWithSource()加载类,最终调用jvm_define_class_common()方法
6.在jvm_define_class_common()方法中利用 ClassFileStream 将要加载的 class 文件转成文件流
7.调用SystemDictionary::resolve_from_stream(),将 Class 文件流加载成内存中的 Klass
8.Klass 是一个Java Class文件被加载到内存后的形式
9.最后,**resolve_from_stream()**便是重中之重

所以得出了一个结果,找到Native层的resolve_from_stream就能找到隐藏的DecryptClass、MGClassLoader

先把jvm.dll丢到IDA里面分析一波
通过文件版本信息,简单的查看一下jvm是什么版本的:7.0.510.13
在这里插入图片描述
再到IDA里面看看关键的字符串,再次确认版本:jdk7u51
在这里插入图片描述
Jdk7是开源的,可以到网上下载一份相近版本的源码观摩一下
提供一个下载链接:http://hg.openjdk.java.net/

找到jdk7u链接
在这里插入图片描述
似乎没有jdk7u5的,可以找个相近的版本,尽量找个比原版本高的,这里挑个jdk7u6的,然后点击hotspot链接
在这里插入图片描述
再点一下browse链接
在这里插入图片描述
最后点一下zip链接,将里面的源码打包成zip下载下来
在这里插入图片描述
整个压缩包大概12.84MB左右,下载完之后解压
使用UE,在源码路径下全局搜索SystemDictionary::resolve_from_stream字符串
在这里插入图片描述
稍等一会儿,就能搜出4个结果
找到SystemDictionary::resolve_from_stream实现的地方,在systemDictionary.cpp文件内
在这里插入图片描述

查看实现的代码,可以找一些比较关键的字符串,便于在IDA里面搜索定位到
这里挑出几个字符串:Prohibited package name: %s、external class name format used internally
在这里插入图片描述

这里使用Prohibited package name: %s,搜索后定位到IDA对应的伪代码,对比一下,应该就是这里了
Jvm.dll基址 = 0x5E770000
当前接口地址:resolve_from_stream_5E7D4490
在这里插入图片描述

接下来查看一下源码,传入的参数都是什么
klassOop SystemDictionary::resolve_from_stream(Symbol class_name*,
Handle class_loader,
Handle protection_domain,
ClassFileStream st,*
bool verify,
TRAPS)

这里主要关注Symbol* class_nameClassFileStream* st
class_name可以看到加载的Class名字,st可以看到Class的buff

回到x64dbg内,找到对应的地址,打上断点,重启程序马上命中断点
查看第一个参数ecx寄存器,转到内存中,果然可以看到熟悉的名字:MGClassLoader
马上就可以揭晓这个Class的到底是从哪里冒出来的
在这里插入图片描述
通过栈回溯,结合源码,在IDA里找到上一层调用resolve_from_stream的地方:jni_DefineClass_5E88DB50
在这里插入图片描述
对应jni.cpp源码
在这里插入图片描述
到这里,突然恍然大悟,之前找的导出接口JVM_DefineClass、JVM_DefineClassWithSource,似乎是java层调入到Native才用到的
如果使用C++层调用,则是走jni_DefineClass…

接下来继续回溯,到达了VeSys.exe领域
将VeSys.exe丢到IDA分析一下
在这里插入图片描述

终于看到DecryptClass、MGClassLoader的庐山真面目了
程序把这两个Class文件的二进制数据嵌入到data段里了,还做了个加密,不过是个简单异或运算
在这里插入图片描述

解密之后调用jni_DefineClass将Class文件加载至内存
分析到这里,基本上摸透了整个解密、加载Class文件的流程了,让我获益良多

最后把解密后的Class文件直接dump下来,导入到IDEA工程里面,就可以直接调试分析解密.*cjar的代码了
在这里插入图片描述

分析解密*.cjar

在DecryptClass.class中,可以看到相关的解密过程
调用DecryptClass类初始化AES的key,最后传入buff调用doFinal解密
整个解密过程还是比较简单的
在这里插入图片描述
解密完成后回到上一层MGClassLoader.class,
调用loadAllClasses加载所有解密的class文件
在这里插入图片描述

实现批量解密*.jar

新建一个工程,将关键的代码复制粘贴,改到能跑就行
在这里插入图片描述

最后成功的将所有*.cjar内的class文件解密了,重新打包成*.jar包
再次导入到IDEA内可以正常反编译class文件
在这里插入图片描述

至此解决了所有影响分析的绊脚石,后面就是愉快的分析需求点了

引用说明

本文引用链接
1.使用java实现AES加密
https://www.cnblogs.com/codegeekgao/p/8336118.html

2.你知道 Java 类是如何被加载的吗?
https://www.sohu.com/a/331624683_612370

3.OpenJDK
http://hg.openjdk.java.net

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值