搜索
查看: 542|回复: 0

安卓Hacking:Part 5:使用JDB调试Java应用

[复制链接]

1839

主题

2255

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
11913
发表于 2018-5-19 13:43:59 | 显示全部楼层 |阅读模式
原文链接:http://bobao.360.cn/learning/detail/138.html

本期将为大家演示如何使用JDB命令行工具调试Java应用,尽管本文并不会涉及Android的相关内容,但却是理解本系列下一期“寻找可调试的安卓应用”前提。

什么是JDB?

JDB是一个简单的Java命令行调试器,包含在JDK中。

我们在本文中将会使用一台Ubuntu主机,我们可以在/usr/bin中找到JDB:

         #cd /usr/bin

         #ls | grep jdb

提示:如果你使用的是Windows,可以在Java目录下的bin目录中找到JDB,本文的示例主要在Ubuntu下完成,但即使在windows中相关的技术也基本是相同的。

简介

本文将会接合一个实例来理解如何用JDB命令调试Java程序,而不是直接去看JDB的用法。

以下是本文用作示例的代码:

文件名:Debug.java

编译生成的Class文件:Debug.class

[/url]

这段代码片段中,Debug类的main方法调用了该类中的其他两个方法,编译后执行,会产生以下输出,如图:

[url=http://p1.qhimg.com/t012e6c2f8c696a4609.png]

我们使用了-g选项来编译程序,编译器会在类文件中生成一些调试信息。

运行JDB

要调试Java程序,我们需要一条JDB到JVM的通信信道,因为我们的Java程序实际上是运行在JVM(java虚拟机)中的

如下所示,有多种连接JDB和JVM的方法。

方法1

使用这个方法,我们直接使用JDB来加载类文件,JDB会自动创建一个JAVA虚拟机,并建立连接。

[/url]

图中的Debug代表编译后生成的类文件

方法2

使用这种方法,我们先使用以下命令启动一个Java虚拟机,Java虚拟机会监听54321端口。

java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=54321 Debug

[url=http://p1.qhimg.com/t01c053b31783c3864d.png]

然后使用如下命令启动JDB连接到JVM。

jdb -attach 54321

[/url]

这种方法也可以用于远程调试,在下一期中,我们会使用这种方法来远程调试Android应用。本文中会使用第一种方法。

开始调试

我们现在开始用第一种方法来调试示例程序,但我们需要执行一条run命令来让JDB启动Java虚拟机,如下图:

[url=http://p2.qhimg.com/t01ca4c427ef5533f32.png]

图中显示,启动了Java虚拟机后,程序立刻执行完成并退出了。

为了中断程序执行以便手工单步调试,我们需要在程序运行之前设置断点。

我们可以用”stop in”命令在方法开始的地方设置断点,如下图:

[/url]

值得注意的是,设置断点的时候,除了指定类和方法名之外,还要指定参数类型。

我们已经在Debug类中的main方法上设置了断点。

现在我们就能运行程序来触发断点,这里一样使用之前提到的run命令。

[url=http://p2.qhimg.com/t0160495479188aa708.png]

触发断点后,JDB会自动显示将要执行的下一行代码:

System.out.println(“We are in main method”);

可以使用“list“命令来查看当前的上下文代码

[/url]

使用“clear“命令查看设置的所有断点:

[url=http://p3.qhimg.com/t01a6150709707963c9.png]

如图,clear命令显示出来我们设置断点及位置

使用”threadgroups”命令查看所有的线程组。

[/url]

如图,当前有两个线程组:“system“和”main“

使用”threads”查看所有线程:

[url=http://p5.qhimg.com/t01d38ff070595fa5e9.png]

如上图,我们当前的system线程组中有三个线程,而main线程组中有一个线程,这就是我们要调试的。

使用”classes”命令查看当前Java虚拟机所加载的类的信息:

[/url]

上图中显示了当前Java虚拟机所加载的类(为节省空间,截短了输出)

要查看特定类的更加详细的信息,可以使用以下命令:

>class <classname>

下图显示了Debug类的详细信息:

[url=http://p0.qhimg.com/t013842c84bb15053e3.png]

同样,我们也能查看其它类的详细信息,例如下图就显示了 java.io.DatqaInputStream类的详细信息:

[/url]

使用”methods <classname>”命令查看所加载的方法:

[url=http://p8.qhimg.com/t0171b63349333d9ac3.png]

以上介绍了以下常用的重要命令,现在我们将深入程序的执行流程,看怎样用JDB来帮助我们调试程序。

我们可以使用”next”命令执行下一行代码:

[/url]

执行完当前代码后,JDB会自动显示下一行代码:调用test方法。

这里,我们再执行”next”命令后,会执行完test方法并中断到下一行代码:passCheck:

[url=http://p7.qhimg.com/t01a3472b41c083e3b3.png]

现在,如果我们想进入passCheck方法进行调试,就应该使用”step”命令,而不再是”next”。

我重启了程序,在test方法处输入了step命令:

[/url]

现在,输入”next”命令继续运行下一条代码:

[url=http://p4.qhimg.com/t01bda35450cce8c0ca.png]

现在,如果我们因为某些原因希望直接离开该方法,而不是运行余下的代码,我们可以使用”step up”命令。

[/url]

当前代码已经离开test方法,回到main方法,等待执行下一条。

下面几行会毕竟有趣,我们将会学到如何查看变量中储存的数据,在此之前,我们先介绍一天更有趣的命令:“where”。

“where”命令会打印显示当前的调用栈。我们先在main方法中运行该命令,然后在另一个方法中运行同样的命令:

[url=http://p1.qhimg.com/t015c89e3a013121b59.png]

如图,当前程序正在main方法中,

现在使用”step”命令进入方法,并检查调用栈:

[/url]

[url=http://p8.qhimg.com/t0134e8c41e450c4891.png]

如上图,程序当前正在”Debug.passCheck”中运行,而”Debug.passCheck”又是被“Debug.main”调用的

假如我现在对passCheck这个方法比较干兴趣,想看看该方法的局部变量中有不有一些敏感信息,我们可以使用”locals”命令查看所有的局部变量。(如果程序没有使用-g选项编译,该命令无效).

[/url]

如图显示,该方法接收了一个main方法传入的密码变量,因为参数还没有被赋值给局部变量,所有上图只显示了参数而没有局部变量,我们先执行下一行代码再查看局部变量”password”。

可以使用”print”命令打印出指定变量的内容:

[url=http://p4.qhimg.com/t01bebd40af32aabe20.png]

总结

本文简介介绍了JDB,以及几个常用的JDB命令的用法。

相关链接

http://docs.oracle.com/javase/7/docs/technotes/tools/windows/jdb.html


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?Join BUC

x
过段时间可能会取消签到功能了
您需要登录后才可以回帖 登录 | Join BUC

本版积分规则

Powered by Discuz!

© 2012-2015 Baiker Union of China.

快速回复 返回顶部 返回列表