点击蓝字 关注我们
日期: 2022-06-13 作者: Mr-hello 介绍: JDB是基于文本和命令行的Java调试工具。
0x00 前言
前段时间在群里看到了一份 WP
里面关于一道 CTF
题目在解题的时候用到了 JDB
这款工具,当时研究了一点将那道题目给复现了出来,然后就过去了很长时间,最近突然又想详细的去学习下 JDB
这款工具。
0x01 工具介绍
JDB
这款工具集成在 JDK
中,在安装 Java
时已经自带,不需要特殊安装。它是一款基于文本和命令行的调试工具,现在很多的 Java IDE
中都提供了完善的断点调试功能,很方便,这也导致很多的开发人员认为这很原始,既然有更好的调试工具选择,很多人都放弃使用这款工具。
0x02 工具使用
JDB
基本用法如下代码所示。
jdb <options> <class> <arguments>
#<class> 是要开始调试的类的名称
#<arguments> 是传递到 <class> 的 main() 方法的参数
options
其中的 options
包括用于以有效的方式调试Java
程序的命令行选项。JDB
启动器接受所有选项(例如 -D
,-classpath
和 -X
)和一些其他高级选项,如(-attach
,-listen
,-launch
等)。
-help 输出帮助并退出
-sourcepath <由 ":" 分隔的目录>
要在其中查找源文件的目录
-attach <address> 使用标准连接器附加到指定地址处正在运行的 VM
-listen <address> 等待正在运行的 VM 使用标准连接器在指定地址处连接
-listenany 等待正在运行的 VM 使用标准连接器在任何可用地址处连接
-launch 立即启动 VM 而不是等待 'run' 命令
-listconnectors 列出此 VM 中的可用连接器
-connect <connector-name>:<name1>=<value1>,...
使用所列参数值通过指定的连接器连接到目标 VM
-dbgtrace [flags] 输出信息供调试jdb
-tclient 在 HotSpot(TM) 客户机编译器中运行应用程序
-tserver 在 HotSpot(TM) 服务器编译器中运行应用程序
转发到被调试进程的选项:
-v -verbose[:class|gc|jni] 启用详细模式
-D<name>=<value> 设置系统属性
-classpath <由 ":" 分隔的目录>
列出要在其中查找类的目录
-X<option> 非标准目标 VM 选项
0x03 调试
断点
首先我们需要编写一个 Java
代码文件,然后使用 Javac
命令进行编译产生 class
文件。然后使用 JDB
工具进行挂载运行。
Javac -g XXX.Java # 使用-g参数在编译时会帮你生成局部变量表、指令和代码行偏移量映射等信息
jdb XXX #在挂载运行时,不需要带后缀。
然后我们可以使用 stop
指令设置断点位置。比如我们在 XXX
类的 main()
方法上设置断点。
stop in XXX.main # 不用加括号
stop
指令的基本用法如下:
# 在特定行号上设置断点
stop at <class id>:<line>
# 在特定方法上设置断点
stop in <class id>.<method>
设置完断点之后使用 run
指令将程序运行起来,程序将会运行到前文指定断点处之后停下,输出相关信息。如果想要继续执行可以使用 cont
、 step
和 step up
指令,其中 cont
是直接运行到下一个断点处;step
指令是只运行下一条语句并停止;step up
指令是运行到该方法退出并停止。
调试 jar
上文简述了一下本地调试 class
的基本命令,但是使用上述方法是无法对 jar
文件进行调试的。一般我们运行 jar
文件时直接使用 Java -jar xxx.jar
即可,但是如果想使用 jdb
工具对其进行调试,需要添加额外的命令行参数,与此同时,在启用 JDB
时也需要添加额外命令行参数。
Java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -jar xxx.jar
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8000
这种方式同时也用来远程调试 Java
文件。
其他
除去上文提到的几种指令,jdb
工具还提供了很多操作指令,例如跟踪方法、获取指定错误类型、对象锁消息、操作表达式、查看变量等。
print <expr> -- 输出表达式的值
dump <expr> -- 输出所有对象信息
eval <expr> -- 对表达式求值 (与 print 相同)
set <lvalue> = <expr> -- 向字段/变量/数组元素分配新值
locals -- 输出当前堆栈帧中的所有本地变量
watch [access|all] <class id>.<field name> -- 监视对字段的访问/修改
unwatch [access|all] <class id>.<field name> -- 停止监视对字段的访问/修改
trace methods [thread] -- 跟踪方法进入和退出。
trace method exit | exits [thread] -- 跟踪当前方法的退出, 或者所有方法的退出
clear <class id>.<method>[(argument_type,...)] -- 清除方法中的断点
clear <class id>:<line> -- 清除行中的断点
clear -- 列出断点
0x04 演示
关于最开始的那个 CTF
题目,后来我找了一下,发现是国外的一个比赛,可能大家都没什么印象。这里我就不详细说了,那个题目是给了一个 jar
包,使用 jd-gui
那款工具进行反编译的话,会有部分函数代码无法识别成功。使用 jadx
可以编译出大部分函数,但是仍有一个函数无法正常反编译。
最后解决办法,换了一个版本的 jadx
进行编译,但是低版本的 jadx
无法反编译其他函数,但是两个版本的反编译一结合,也就算是全部反编译出来了。
最后回归题目本身,发现该题目对 Java
函数进行了混淆,里面的逻辑性很难读懂。
但是在分析过程中发现,每次对我们的输入进行比较时,均有一个中间变量存储着每个关键函数的返回值,每次比较都是与中间变量进行比较,那么这道题目我们就可以使用 JDB
工具的监控方法状态的 trace
指令对每个方法的返回值进行捕捉。从而一步步分析出最终结果。
首先,我们将 jar
文件挂载到 JDB
工具上进行调试,并捕获所有方法。
因为在使用 trace
指令时需要挂载到对应线程上,所以我们先找到我们对应的线程,然后根据 id
进行捕获即可。
然后我们通过去改变输入,一步步的过所有认证函数即可。例如下图中的两个函数,分别代表输入为 39
位长度,并且其中 0 ~ 6
需要为特定字符串,结尾应该为 }
。
所以我们先编造一个长为 39
位数的输入,因为前面 0 ~ 6
位是来自于 a
函数,但是该函数逻辑太难读懂,所以我们直接捕获该函数返回值即可。
反复重复上述步骤,最终分阶段确认最终答案。
0x05 总结
其实 JDB
这个工具前面也说到,很多的 Java IDE
现在已经集成了调试功能,但是那只是对于有源码的情况下方便调试,真实情况下的 Java
逆向上的动态调试,或许比不过 JDB
这款工具呢,比如它可以跟踪方法退出,捕获返回值,又比如它可以监视字段的访问及修改,各有利弊吧!
免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。
宸极实验室
Cyber Security Lab
宸极实验室隶属山东九州信泰信息科技股份有限公司,致力于网络安全对抗技术研究,是山东省发改委认定的“网络安全对抗关键技术山东省工程实验室”。团队成员专注于 Web 安全、移动安全、红蓝对抗等领域,善于利用黑客视角发现和解决网络安全问题。
原文始发于微信公众号(宸极实验室):『工具使用』JDB-Java调试器
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论