登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

DOS编程技术

讨论在纯DOS下的编程技术

 
 
 

日志

 
 
关于我

1984年大学毕业,1985年底有机会开始接触PC机,1986年开始在PC机上做开发工作,曾接触过MS-DOS、CP/M、UNIX、VMS、LINUX、iRMX等众多的操作系统并在上面从事技术开发,擅长做底层与硬件相关的软件开发,目前主要在DOS和LINUX平台下工作,主要从事软件,在硬件开发上也有一定造诣,亦有在8051系列、6502系列(凌阳)、z80系列、ARM、X86等各类平台下开发软硬件的经历。更详细情况可以参考http://resume.whowin.net

程序倒运行的实现方法  

2008-12-09 13:34:52|  分类: 旧文回顾 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

注:此文为我17年前的文章,发表在《电脑》杂志1991年第二期,再次录入此文时并没有验证其中的正确性,同时由于录入错误,可能会有一些错误,如发现,请及时告知,谢谢!

通常的程序都是由低地址向高地址逐条指令的顺序执行,这样的程序可以用调试程序进行反汇编,也可以方便地进行跟踪,但是如果我们程序的机器码不按这种顺序排列,而是由高地址向低地址排列,运行时也让其按这种反向顺序执行,即从高地址向低地址运行,那么这样的程序既无法跟踪,也无法反汇编。

由于8086系列微机很容易设置单步中断,给以上想法的实现带来了可能,可以设想当执行完一条指令后将产生单步中断,我们利用该中断使一条指令复原,然后执行该指令,指令执行后又产生中断,根据此次中断和上次中断的返回地址即可算出该指令的长度,这样向低地址方向就可以找到下一条指令的起始地址,然后再把指令复原,再执行......;这样,程序的运行就好像是从高地址向低地址方向运行。

显然,这样的程序不能包含有循环和向回的转移指令,因为程序运行中已将原来的代码破坏掉,转移过去已无法在回复原来的指令,另外对调用软中断的过程要做特殊处理,否则在中断中也将使程序倒运行,那是不能允许的,同时,在程序倒运行过程中,应禁止硬件中断。

下面通过一个实例来说明该方法的实现,程序中首先把A盘第39磁道0面第一扇区中偏移为10h处的一个字节改为0e9h,然后设置一段倒运行程序,倒运行程序中读出A盘第39磁道0面第一扇区的内容,并判断偏移为10h处的字节是否为0e9h,如是ax=0,否则ax=1;然后再变为正常运行状态,,并在顺序运行中判断ax的值是否为1,如不是显示“OK!”退出,否则显示“ERROR!”退出。

要进入单步状态有两个条件,一是允许单步中断int1,二是标志寄存器的8位即单步允许位置为1,本例进入单步状态没有用绝对转移指令JMP,二是用中断返回指令IRET来改变标志位并直接转移到要运行的位置,由于8086系列芯片的指令最长为6个字节,所以在INT1中每次把指令代码前5个字节移到指令代码后,这样必定能组成一条完整的指令,当遇到指令代码为0时,则认为倒运行结束,回复为正常状态;当遇到指令代码为0cdh时,表明是一条int指令,为了保证中断程序的正确运行,必须变为顺序运行方式,并在int指令执行完后再恢复成逆运行方式,逆运行部分int 13h后的7条指令就是为此目的安排的,由于倒运行部分的第一条指令不会产生int1,所以倒运行部分的第一条指令应为单字节指令或顺序放置,本例为以单字节指令cli,offaddr初始值为第一条指令的地址,这样通过int1的返回地址就可算出刚执行的指令长度,从而得到下一条指令的地址,并把该地址存入offaddr,这样循环下去便使程序逆运行起来了。为了说明逆运行中转移指令的情况,本例逆运行部分有三条转移指令,第一条在int 13h后,为jc neg_run,它是当逆运行读盘失败时,退出逆运行方式,并重新初始化逆运行指令码,再运行逆运行部分,由于出现int指令时,int 1例程已将运行方式变为顺序运行方式,正式由于这一条件的存在,才使jc neg_run指令得以实现,在一般情况下,逆运行中采用向回的转移是不允许的;第二、三条转移指令分别为jnz error和jmp exit,这两条指令均为向前转移并为近转移,同时也没有转出逆行程序部分,所以无需任何改动就可以在逆运行中实现。

程序中,标号prom_start到cont之间的代码为逆运行部分,为了说明程序的运行状况,这段程序我们以顺序方式写出,而这部分的实际代码为prom这部分数据,neg_run后的一段程序把prom这段数据移到了prom_start处,由于prom的数据实际上是prom_start部分的逆向代码(即最后一个字节放到第一字节,倒数第二个字节放到第二字节......),所以这两部分的长度一定是相等的,当我们把程序编译,并用debug观察时,会发现prom并不完全是prom_start部分程序的逆向代码,有个别字节被改动了,这些改动是必须的,本例中改动了两处,第一处为int 13h后的jc neg_run因为当代码被逆向安排后,该指令的地址已和顺序方式下的地址不同,所以转移的偏移也必然不同;另一条改动为jc neg_run指令下的第三条指令mov ax, offset gggg,原因基本是一样的,因为代码逆向安排后,gggg标号位置已发生了变化,所以offset gggg也发生了变化,必须更改。

该例改写完A盘39磁道0面1扇区后,将缓冲区buf清0,然后等待键盘输入一字符后才继续运行,当我们看到A驱动器工作灯亮后又熄灭时,便是在等待键盘输入,此时敲任意键便可进入逆运行状态,如果在修改A盘扇区时出错,将重试5次,如果仍不成功,则显示“Disk Operation Error!”,然后退出;在实验时,我们分别可以试两种情况,首先插入一张已格式化好的盘在A驱动器,运行该程序,当等待键盘输入时敲入任意键,则应显示“OK!”退出;另一种情况,当等待键盘输入时,换上一张未被该程序修改过的盘,再键入任意键,则应显示“Error!”并退出。

改程序为演示性的,但逆运行这种方式可以为自己的应用程序增添光彩,我们已把该方法运用到应用程序的加密中,效果良好。

code            segment

                assume  cs:code, ds:code, es:code

                org     100h

start:

                mov     ax, 0

                push    ds

                push    ax

                push    cs

                pop     ds

                push    cs

                pop     es

                mov     cx, 5

repeat1:

                push    cx

                mov     ax, 0201h

                mov     bx, offset buf

                mov     cx, 2701h

                mov     dx, 0

                int     13h

                pop     cx

                jnc     edit

                dec     cx

                jnz     repeat1

error1:

                mov     dx, offset string3

                mov     ah, 09

                int     21h

                mov     ah, 4ch

                int     21h

edit:

                mov     si, offset buf

                mov     al, 0e9h

                mov     [si + 10h], al

                mov     cx, 5

repeat2:

                push    cx

                mov     ax, 0301h

                mov     bx, si

                mov     cx, 2701h

                mov     dx, 0

                int     13h

                pop     cx

                jnc     continue

                dec     cx

                jnz     repeat2

                jmp     error1

continue:

                mov     al, 0

                mov     di, offset buf

                mov     cx, 512

                cld

                repz stosb

                push    ds

                mov     ax, 0

                mov     ds, ax

                mov     si, 4

                cli

                MOV     ax, [si]

                MOV     es:int1_ip, ax

                MOV     ax, [si + 2]

                MOV     es:int1_cs, ax

                MOV     ax, offset int1

                MOV     [si], ax

                PUSH    cs

                POP     ax

                MOV     [si + 2], ax

                sti

                MOV     ah, 0

                int     16h

neg_run:

                MOV     cx, count

                MOV     si, offset prom

                MOV     di, offset prom_start

                cld

                repz movsb

                pushf

                POP     ax

                or      ax, 100h

                PUSH    ax

                PUSH    cs

                MOV     ax, offset exit

                PUSH    ax

                iret

prom_start:

                db      0

                cli

                MOV     ax, 0201h

                MOV     bx, offset buf

                MOV     cx, 2701h

                MOV     dx, 0

                int     13h

                JC      neg_run

                MOV     ax, flag

                PUSH    ax

                MOV     ax, offset gggg

                PUSH    cs

                PUSH    ax

                iret

gggg:

                MOV     si, offset buf

                ADD     si, 10h

                cmp     byte ptr [si], 0e9h

                JNZ     error

                MOV     ax, 0

                JMP     exit

error:

                MOV     ax, 1

exit:

                sti

                db      10 dup(?)

cont:

                cmp     ax, 1

                JZ      error2

                MOV     dx, offset string1

                MOV     ah, 09

                int     21h

                JMP     exit1

error2:

                MOV     dx, offset string2

                MOV     ah, 09

                int     21h

exit1:

                cli

                PUSH    ds

                MOV     ax, 0

                MOV     dx, ax

                MOV     si, 4

                MOV     ax, es:int1_ip

                MOV     [si], ax

                MOV     ax, es:int1_cs

                MOV     [si + 2], ax

                POP     ds

                sti

                MOV     ah, 4ch

                int     21h

buf             db      512 dup(?)

string1         db      0dh, 0ah, "OK!$"

string2         db      0dh, 0ah, "ERROR!$"

string3         db      0dh, 0ah, "Disk Operation Error!$"

int1_ip         dw      ?

int1_cs         dw      ?

prom            db      0, 0fbh, 0, 1, 0b8h, 90h, 4, 0ebh, 0, 0, 0b8h, 6

                db      75h, 0e9h, 3ch, 80h, 10h, 0c6h, 83h, 2, 6

                db      0beh, 0cfh, 50h, 0eh, 0c9h, 0b8h, 50h, 4, 0d9h, 0a1h

                db      0c0h, 72h, 13h, 0cdh, 0, 0, 0bah, 27h, 1, 0b9h, 2

                db      6, 0bbh, 2, 1, 0b8h, 0fah

                db      10 dup(0)

count           dw      3bh

int1            proc

                cli

                PUSH    bp

                MOV     bp, sp

                PUSH    ds

                PUSH    es

                PUSH    ax

                MOV     ax, [bp + 4]

                MOV     es, ax

                PUSH    cs

                POP     ds

                MOV     ax, [bp + 2]

                sub     ax, offaddr

                sub     offaddr, ax

                MOV     ax, offaddr

                MOV     [bp + 2], ax

                PUSH    di

                PUSH    si

                PUSH    cx

                PUSH    es

                POP     ds

                MOV     si, ax

                cmp     byte ptr [si], 0

                JZ      rept2

                MOV     di, ax

                MOV     cx, 5

                cmp     byte ptr [di], 0cdh

                JNZ     rept3

                MOV     ax, [bp + 6]

                MOV     flag, ax

                and     ax, 0feffh

                MOV     [bp + 6], ax

                MOV     cx, 19

rept3:

                INC     di

                DEC     si

rept1:

                MOV     al, [si]

                MOV     [di], al

                INC     di

                DEC     si

                DEC     cx

                JNZ     rept1

int1_exit:

                POP     cx

                POP     si

                POP     di

                POP     ax

                POP     es

                POP     ds

                POP     bp

                sti

                iret

rept2:

                MOV     ax, offset count

                MOV     [bp + 2], ax

                MOV     ax, [bp + 6]

                and     ax, 0feffh

                MOV     [bp + 6], ax

                JMP     int1_exit

offaddr         dw      offset exit

flag            dw      0

int1            endp

code            ends

                END start

  评论这张
 
阅读(2057)| 评论(1)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018