Chinaunix首页 | 论坛 | 博客
  • 博客访问: 563228
  • 博文数量: 287
  • 博客积分: 27
  • 博客等级: 民兵
  • 技术积分: 547
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-01 20:20
文章分类

全部博文(287)

文章存档

2015年(1)

2014年(95)

2013年(90)

2012年(101)

分类: Windows平台

2014-01-16 12:31:39

        最近阅读王爽《汇编语言》第二版,第九章“转移指令的原理”实验8中提到分析一个奇怪的程序,程序完整如下:

点击(此处)折叠或打开

  1. assume cs:codesg
  2. codesg segment
  3.     mov ax, 4c00h
  4.     int 21h
  5.     
  6. start: mov ax, 0
  7.     s: nop
  8.      nop
  9.     
  10.      mov di, offset s
  11.      mov si, offset s2
  12.      mov ax, cs:[si]
  13.      mov cs:[di], ax
  14.     
  15.    s0: jmp short s
  16.    s1: mov ax, 0
  17.      int 21h
  18.      mov ax, 0
  19.    s2: jmp short s1
  20.         nop
  21.     
  22. codesg ends
  23. end start
     按照程序分析,经过如下四个语句:
  1.      mov di, offset s
  2.      mov si, offset s2
  3.      mov ax, cs:[si]
  4.      mov cs:[di], ax     
    意思就是将s2处的代码复制到s处。继续运行如下语句:
     s0: jmp short s

    程序重新跳转回到s:处,由于我们已经使用了s2出的代码替换s处的代码,所以应该就会执行s2处的代码,跳转到s1处。
    可是实际问题来了,并没有发现跳转到s1处。而是直接退出。

      于是使用debug对其分析,果然如标题所说,发现一个很奇怪的现象:
      使用debug加载程序,然后u选项查看,嗯,汇编都能够对上,没有问题。

               
                                                                                           (图1)
        然后一直t选项运行下来,重新跳转回到s处执行,问题来了,重新使用u选项查看汇编代码,尼玛,红框中竟然变成了jmp 0000指令。

                
                                                                                            (图2)
        不是说好的要执行s2处的指令跳转到s1处执行的么?
       于是仔细核对s2出的机器码和s0处的机器码,如图2和图3所示,都是EBF6,但是对应的汇编指令,一个是“jmp 0000”,一个是“jmp 0018”。同一个机器码竟然可以解释成为两种不同的汇编代码,不得不感叹神奇。
               
                                                                                    (图3)
        无奈之下只好度娘了,答案经过整理理解如下:
       1. 程序在编译时,段内直接短转移指令所对应的机器码中,并不包含转移的目的地址,而包含的是转移的位移量。这是该问题的核心。
          那么在编译时,s2处的代码编译之后的机器码为EBF6,对应的EB为跳转指令,F6是-10d的掩码,即对应跳转到13f7:0018处s1的指令。此处s2的地址为13f7:0020,s1处地址为13f7:0018,正好位移量是-10d,没有问题。
      2. 复制的是机器码,而不是汇编语言。
          机器哪儿认识汇编语言啊,只认识机器码呀。所以我们将s2处的指令复制到s处,复制的是EBF6,而不是"JMP 0018"。
      3. 跳转到s处后,当机器执行到EBF6机器码时,EB为跳转指令,F6是-10d的掩码,所以就是在ip指针的基础上减去位移为10的地址,此时ip指针为10,那么运行这条指令后,ip变为0,当然就跳转到13f7:0这个地址了。这个地址对应的代码就是程序开头的代码:
          
  1. codesg segment
  2.     mov ax, 4c00h
  3.     int 21h
    执行这两条指令后,程序正常退出。
阅读(1073) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~