bochs利用中断调试dos程序
本文主要内容:在bochs中运行dos程序,如何在程序的开始处中断
使用bochs调试,如何在程序的任意位置下断点
虽然在程序的入口处中断后,我们就可以随意使用bochs下断点了,但是毕竟不能像C/C++那么方便,使用函数名,或者文件名+行号就可以下断点,而是需要自己算偏移地址等。因此需要一种更加方便的下断点方法。
因为TD不能调试保护模式下的DOS程序,因此必须(或者是可选方法之一)用bochs自身的调试功能。可是在网上找了很久,没有什么特别合适的方法,归纳起来主要有以下几种:
在程序入口加上jmp $,这是个死循环,运行程序后,ctrl+c中断bochs就停在我们程序的入口处了,然后使用set $eip=XXX命令修改eip,继续执行自己的程序。
,我们可以从主程序跳转到某个固定地址(如0x400),在这个固定地址写一段程序,目的是再跳回到我们主程序的入口。然后在bochs中将这个固定地址作为断点。
使用3号中断,也就是int 3,但是悲催的我始终没发现它有用过。
使用int 3貌似是一种非常好的方法,因为调试器就是通过int 3来给程序下断点的。但是,在bochs中,这个方法不给力啊,少年。因为我们平时使用的调试器,加载以后,会主动修改int 3,让int 3的中断服务程序指向自己的代码。这样客户程序调用int 3以后,就会走入调试器的代码。但是,启动DOS以后,在实模式下通过infoivt检查中断向量表,你会发现int 3里只有一条iret指令。也就是说,bochs并没有把int 3指向任何有意义的代码,也就是说,你在程序中调用int 3,什么也不会发生。毕竟DOS是bochs中的一个客户操作系统,bochs怎么能修改DOS的中断向量表呢。(如果在DOS中运行TD,然后在bochs中使用infoidt命令,你会发现TD把IDT重写了)。
实际上,我们可以参考方法2,只要有一个固定地址可以让我们中断,那么就大功告成了,虽然int 3里只有一条简单的iret,但它也是有地址的。我们只要把bochs的断点设置到int 3中断服务程序的地址,那么当我们在程序中执行int 3,bochs就会中断下来。
这应该是一个好方法,但当我让bochs在int 3的中断服务程序处下断点的时候,会发现bochs不停的被int 3中断,也不知道在哪里调用了.....。因此我决定使用int5中断,反正它是一个打印屏幕的中断,目前还没用到,关键是在DOS下打印ivt,发现int 5里也只是一条简单的iret。
下面是整个过程:
启动bochs,加载DOS,等待DOS启动完毕。
在bochs中执行info ivt,检查中断向量表(16位实模式下检查ivt,32位保护模式下检查idt),得到int 5中断的服务程序入口
<bochs:2> info ivt
INT# 00 > 00D1:10BA (0x00001dca) DIVIDE ERROR
INT# 01 > 00D1:1085 (0x00001d95) SINGLE STEP ; dummy iret
INT# 02 > F000:FF53 (0x000fff53) NON-MASKABLE INTERRUPT ; dummy iret
INT# 03 > 00D1:1085 (0x00001d95) BREAKPOINT ; dummy iret
INT# 04 > F000:FF53 (0x000fff53) INT0 DETECTED OVERFLOW ; dummy iret
INT# 05 > F000:FF53 (0x000fff53) BOUND RANGE EXCEED ; dummy iret
上面的0x000fff53就是int 5的入口地址。
在bochs中,给0x000fff53处下一个断点
pb 0x000fff53
然后执行我们的程序吧(记得在程序需要断点的位置加上int 5啊,少年!),bochs会在int 5的服务程序处中断,然后在bochs中使用n命令,就会回到我们自己的程序了。
这个方法,也许就是网上说的使用int3给bochs下断点的方法吧。通过这个方法,我们可以在程序代码的任意处下断点(而且是多个),只要手工在程序的该处加上int 5就可以了。
进入保护模式以后,使用的是IDT,但是应该可以使用同样的方法,只是断点的位置需要重新设置。
同时,我们可以不借助int 5中断,毕竟256个中断入口中,有一部分是留给用户自定义的,这个我还没试过,等有时间了吧。
补充:综合编程 , 其他综合 ,