毁掉自己的汇编程序

时间:2022-12-14 22:25:52

  下午的上机课,有位同学写的程序死了。她百思不得其解。
  我看了几遍程序,没有发现问题。
  多次观察后,发现程序修改数据时,由于循环次数错误地设多了,以致于改到了代码段——代码段的指令于是被当作数据改掉了,而此处的数据,当然它仍然还要被当作指令执行,恰好对应了wait指令!于是,程序进入了等待……
  那程序到底有没有问题?我看的程序没有问题,但运行的,却是老版本的.exe。开始时,源程序是错误的,她修改后,却没有再编译、接连!唉,这样的错也能犯?难为我当教师的了。麻子不叫麻子,叫什么来着?
  按下这个不表,想给大家展示能毁掉自己的奇葩代码。为简单化,我不再用她当时调试的程序,而是设计一个能说明问题的错误程序,把事情说清楚,大家也见识一下就行了。
  我要编的程序,其任务是:将数据区中的所有数据,变为其2倍并存储在原处。阅读下面的有逻辑错误的程序:

assume cs:codesg,ds:datasg
datasg segment
dw 1,2,3,4,5,6,7,8
datasg ends

codesg segment
start: mov ax, datasg
mov ds, ax
mov si, 0
mov cx, 16 ;这儿应该是8,修改8个字,但错误地写成16了
s: mov ax, [si]
add ax, ax
mov [si], ax
add si, 2
loop s

mov ax,4c00h
int 21h
codesg ends
end start

  把连接好的程序用debug装入内存观察:
毁掉自己的汇编程序
(图1)
  可见,数据从物理地址076A0H处开始,一共同8个字,由1到8;从076B0处始,是代码!图1中,用d命令看到的076B0处的值与用u命令看到的,是一样的值,只不过,前者被当作数据,后者被当作指令。内存中的数据就是那样的,到底是数据还是指令,取决于我们要将它当作什么。
  下面我们执行程序。
  我先揭晓了迷底,这个程序就是循环次数设错了。前8次的循环,完成的是任务中要求的事情,后8次循环,彻底的捣乱。
  用g命令和t命令交替,让循环执行8次:
毁掉自己的汇编程序
(图2)
  执行8次后,是这样的:
毁掉自己的汇编程序
(图3)
  注意:由(DS)=076AH, (SI)=0010H,(CS)=076BH,当再执行mov [si], ax指令时,修改的就是代码了!程序在毁掉自己!
  我们将循环再执行3次:
毁掉自己的汇编程序
(图4)
  再用d命令和u命令观察:
毁掉自己的汇编程序
(图5)
  快对照图2!看到了吗?076B0H处的mov ax, 076A呢?076B3H处的mov ds, ax呢?现在的代码已经被改的面目全非!
  再用t和g执行两次:
毁掉自己的汇编程序
(图6)
  *已经破败到如此境地,无法收拾了!

  好了,毁掉自己的汇编程序演示到此。说点什么。
  这种情况,放在高级语言中很难发生。在操作系统尽责的内存管理下,在各种机制约束下,程序安全地存储、运行。
  然而,汇编语言就这么任性!
  这需要我们这些专业人士要对底层熟悉,有足够的敏感不犯这些错误,当然也要有足够的职业道德,不用这种手段去搞破坏。
  当这种问题就要发生,我们还需要用debug之类的底层调试工具,找出bug,使之曝光于天下!
  自豪吧,小猿们!