鱼C论坛

 找回密码
 立即注册
查看: 170|回复: 7

[已解决]单步调试出现ü, 然后就卡死了

[复制链接]
发表于 2022-7-22 15:39:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
子程序功能: 在屏幕中间依次显示'a'~'z', 一个字母要在屏幕中间停留一段时间。在显示过程中, 按下'Esc'键后, 改变显示的颜色
问题: 每次调试到mov es:[4 * 9 + 2], cs(第27行), 就会出现一个ü然后什么都没法输入
GEW8}}MLV9NFEHT8QCS1X.png
  1. assume cs: code, ss: stack, ds: data

  2. stack segment
  3.     db 128 dup(0)
  4. stack ends

  5. data segment
  6.     dw 0, 0
  7. data ends

  8. code segment
  9.     start:
  10.         mov ax, stack
  11.         mov ss, ax
  12.         mov sp, 128
  13.         mov ax, data
  14.         mov ds, ax
  15.         mov ax, 0
  16.         mov es, ax

  17.         push es:[9 * 4]
  18.         pop ds:[0]
  19.         push es:[9 * 4 + 2]
  20.         pop ds:[2]                  ; 将9号例程的入口地址保存起来

  21.         mov word ptr es:[4 * 9], offset int9
  22.         mov es:[4 * 9 + 2], cs      ; 设置新的9号例程的入口地址

  23.         mov ax, 0b800h
  24.         mov es, ax
  25.         mov ah, 'a'
  26.     s:
  27.         mov es:[160 * 12 + 40], ah
  28.         call delay
  29.         inc ah
  30.         cmp ah, 'z'
  31.         jna s
  32.         mov ax, 0
  33.         mov es, ax

  34.         push ds:[0]
  35.         pop es:[4 * 9]
  36.         push ds:[2]
  37.         pop es:[4 * 9 + 2]          ; 恢复int9中断例程的地址

  38.         mov ax, 4c00h
  39.         int 21h
  40.     delay:
  41.         push ax
  42.         push dx
  43.         mov dx, 06h
  44.         mov ax, 0                            ; 延迟每个字母的显示时间
  45.     s_:
  46.         sub ax, 1
  47.         sbb dx, 0
  48.         cmp ax, 0
  49.         jne s_
  50.         cmp dx, 0
  51.         jne s_

  52.         pop dx
  53.         pop ax
  54.         ret
  55. ; -----------以下为新的int9中断例程----------
  56.     int9:
  57.         push ax
  58.         push bx
  59.         push es

  60.         in al, 60h                  ; 读取60h端口数据, 获取键盘扫描码, 60h端口默认与键盘输入挂钩

  61.         pushf                       ; 保留原本的标志寄存器的值
  62.         pushf
  63.         pop bx
  64.         and bx, 11111100b           
  65.         push bx                     
  66.         popf                        ; 把IF和TF置零
  67.         call dword ptr ds:[0]       ; 模拟int指令, 调用原来的int9中断例程

  68.         cmp al, 1                   ; 1是ESC键的键盘扫描码
  69.         jne int9ret

  70.         mov ax, 0b800h
  71.         mov es,ax
  72.         inc byte ptr es:[160 * 12 + 40 + 1]  ;属性增加1,改变颜色

  73.     int9ret:
  74.         pop es
  75.         pop bx
  76.         pop ax
  77.         iret
  78. code ends
  79. end start
复制代码
最佳答案
2022-7-22 22:11:59
1.png

可以看到用g命令连续执行这两条指令,一切正常
int9入口地址成功的从 0x04b3:0x1923 修改成了 0x11b3:0x007f
注意看图,最后显示出的寄存器中,cs寄存器的值是 0x11b3

2.png
如果是用t命令分开执行这两条指令,就出问题了
我是先输入字符 t,然后下的内存读断点和写断点
然后按下回车键,然后触发了内存断点
如果在输入字符 t 之前就下断点,那在输入字符 t 的时候也会触发内存断点
这样会输出更多的数据,会影响对输出的这些数据的分析,这样不好,所以我先输入字符 t,然后下的内存读断点和写断点
从图中可以看到,按下回车键后,int9入口从 0x04b3:0x1923 修改成了 0x04b3:0x007f
你没有看错,的确是修改成了 0x04b3:0x007f
因为你只改了偏移地址,改段地址的指令还没有执行,所以段地址还保持之前的值
接下来又触发了一次中断,执行了 0x04b3:0x007f 位置的指令,这里无法理解?
这里我解释一下
你按下键盘上的某一个键,然后松开,这会发生两次键盘中断
一次是按键按下的中断,另一次是按键弹起的中断
所以,在按键按下的中断中把int9入口改成 0x04b3:0x007f
在弹起的这一次中断就执行 0x04b3:0x007f
0x04b3:0x007f 这里是什么?
看反汇编的结果,这里不像是指令,你硬是把数据作为指令来执行,然后就出问题了

如果你足够细心,你会发现中断向量表中的地址是 0x04b3:0x007f,捕获到内存断点停下来显示出的地址是 0x04b3:0x0081
这是因为在捕获到这个内存读写信号的时候,读写内存的那条指令已经执行了,调试器选择显示cs:ip的位置
要显示修改内存的那条指令我不知道能不能做到,就算能,也真的很麻烦(我感觉是这样),而显示cs:ip的位置会很简单

评分

参与人数 1鱼币 +1 收起 理由
Passepartout + 1 无条件支持楼主!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2022-7-22 20:08:32 | 显示全部楼层

回帖奖励 +4 鱼币

  1.         mov word ptr es:[4 * 9], offset int9
  2.         mov es:[4 * 9 + 2], cs      ; 设置新的9号例程的入口地址
复制代码

这两条指令用g命令连续执行
这两个指令同时修改中断向量表的段地址和偏移地址
int9是键盘中断,你在用debug调试程序的时候,这个键盘中断也仍然工作
只要你按下键盘,硬件就会从 36 的位置读取偏移地址,从 38 的位置读取段地址,然后跳转到这个位置执行
记得修改完ss寄存器后,debug 无法显示出下一条修改sp寄存器的指令吗?
只不过修改中断向量表是没有硬件保护的,而修改完ss寄存器后硬件强制 不响应中断,使得下一条修改sp寄存器的指令顺利执行
继续往后看吧,我记得书上讲了,要在这两条指令前后加上 cli 和 sti 指令
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2022-7-22 20:12:07 | 显示全部楼层
但是,你就算是加了这两条指令,用debug调试程序的时候也依然会出问题
仔细想一想,如果debug老老实实的执行了cli指令,那它还怎么调试程序?
要知道debug也是使用中断机制来调试程序的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2022-7-22 22:11:59 | 显示全部楼层    本楼为最佳答案   
1.png

可以看到用g命令连续执行这两条指令,一切正常
int9入口地址成功的从 0x04b3:0x1923 修改成了 0x11b3:0x007f
注意看图,最后显示出的寄存器中,cs寄存器的值是 0x11b3

2.png
如果是用t命令分开执行这两条指令,就出问题了
我是先输入字符 t,然后下的内存读断点和写断点
然后按下回车键,然后触发了内存断点
如果在输入字符 t 之前就下断点,那在输入字符 t 的时候也会触发内存断点
这样会输出更多的数据,会影响对输出的这些数据的分析,这样不好,所以我先输入字符 t,然后下的内存读断点和写断点
从图中可以看到,按下回车键后,int9入口从 0x04b3:0x1923 修改成了 0x04b3:0x007f
你没有看错,的确是修改成了 0x04b3:0x007f
因为你只改了偏移地址,改段地址的指令还没有执行,所以段地址还保持之前的值
接下来又触发了一次中断,执行了 0x04b3:0x007f 位置的指令,这里无法理解?
这里我解释一下
你按下键盘上的某一个键,然后松开,这会发生两次键盘中断
一次是按键按下的中断,另一次是按键弹起的中断
所以,在按键按下的中断中把int9入口改成 0x04b3:0x007f
在弹起的这一次中断就执行 0x04b3:0x007f
0x04b3:0x007f 这里是什么?
看反汇编的结果,这里不像是指令,你硬是把数据作为指令来执行,然后就出问题了

如果你足够细心,你会发现中断向量表中的地址是 0x04b3:0x007f,捕获到内存断点停下来显示出的地址是 0x04b3:0x0081
这是因为在捕获到这个内存读写信号的时候,读写内存的那条指令已经执行了,调试器选择显示cs:ip的位置
要显示修改内存的那条指令我不知道能不能做到,就算能,也真的很麻烦(我感觉是这样),而显示cs:ip的位置会很简单

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
6YKT6ZKm5LqI + 5 + 5 + 3 无条件支持楼主!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2022-7-23 10:56:23 | 显示全部楼层

回帖奖励 +4 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2022-7-23 15:06:16 | 显示全部楼层
人造人 发表于 2022-7-22 22:11
可以看到用g命令连续执行这两条指令,一切正常
int9入口地址成功的从 0x04b3:0x1923 修改成了 0x11b3: ...

感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2022-7-23 18:20:35 | 显示全部楼层

回帖奖励 +4 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2022-7-23 19:57:32 | 显示全部楼层

回帖奖励 +4 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1

GMT+8, 2022-10-3 02:51

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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