备份 DIY的一个DOS MZ EXE file loader

来源:互联网 发布:vb getdc 编辑:程序博客网 时间:2024/05/21 08:38
备份原百度空间的文章

2011-04-14 08:56

DIY的一个DOS MZ EXE file loader, 是这几天复习PE文件格式的副产品

; mzLoader.asm
; 自已写的一个MZ EXE文件加载运行器,要求EXE的可重定位程序映像部分不要太大,不要超过64KB-100H(psp)的大小

include common16.inc

assume  cs: code, ds: data, ss: stack, es: mzExeImage

stack   segment stack
        db      512 dup (?)
stack   ends

data    segment
mzHeader db     800h dup (?)  ; 800H字节用来保存MZ文件头
msgGreeting db  'BigBlue''s MZ exe file lorder: $'
msgPrompt db    'Please input MZ exe file name: ', CR, LF, '$'
inputBuf  label byte
        maxSize db 8+1+3+1 ; 包括结尾的回车 8.3
        inSize db ?
        inBuf  db 8+1+3+1 dup (?)
msgErrFileNotExist db 'MZ exe file not found$'        
msgErrFileRead db 'failed to read file$'
msgErrFileInvalid db 'invalid MZ file$'
msgErrFileMovePointer db 'failed to move file pointer$'
msgNewPrompt db CR, LF, 'Bigblue''s MZ loader>', CR, LF, '$'
msgBack db      CR, LF, 'I''m back!$'
data    ends

mzExeImage segment
psp     db      100h dup (?)
mzImage db      (0FFFFH-100h+1) dup (?) ; 汇编时会认为10000h太大了,报错
mzExeImage ends

code    segment
start:
        push    ds
        xor     ax, ax
        push    ax

        mov     ax, data
        mov     ds, ax

        mov     ax, mzExeImage
        mov     es, ax
        
greeting:        
        lea     dx, msgGreeting
        mov     ah, 9
        int     21h

        lea     dx, inputBuf
        mov     ah, 10
        int     21h
        
        xor     bx, bx
        mov     bl, inSize
        test    bx, bx
        jz      bye
        
        mov     inBuf[bx], 0
        lea     dx, inBuf
        mov     al, 0   ; read
        mov     ah, 3Dh ; open file
        int     21h
        jc      err_file_not_exist
        
        mov     bx, ax
        lea     dx, mzHeader
        mov     cx, type IMAGE_DOS_HEADER ;取结构体字节数,共计40H
        mov     ah, 3Fh ; read file
        int     21h
        jc      err_file_read
        cmp     ax, cx
        jb      err_file_invalid
        
        lea     si, mzHeader
        assume  si: ptr IMAGE_DOS_HEADER
        cmp     [si].e_magic, 'ZM'
        jne     err_file_invalid
        
         ; 读重定位表到内存
        mov     ax, [si].e_crlc
        mov     cl, 2   ; 重定位项占4个字节,是个远指针
        shl     ax, cl
        add     ax, [si].e_lfarlc
        cmp     ax, type IMAGE_DOS_HEADER
        jbe     rlc_loaded
        
        xor     cx, cx
        mov     dx, [si].e_lfarlc
        mov     al, 0
        mov     ah, 42h ; move file pointer
        int     21h
        jc      err_file_move_pointer
        
        ; 读重定位表
        mov     dx, [si].e_lfarlc
        add     dx, offset mzHeader
        mov     ax, [si].e_crlc
        test    ax, ax
        jz      rlc_loaded
        mov     cl, 2   ; 重定位项占4个字节
        shl     ax, cl
        mov     cx, ax
        mov     ah, 3Fh ; read file
        int     21h
        jc      err_file_read
        
        cmp     ax, cx
        jb      err_file_invalid
        
rlc_loaded:
        ; 加载可重定位程序映像到内存
        mov     ax, [si].e_cp
        cmp     [si].e_cblp, 0
        je      calcImageSize
        
        dec     ax
        
calcImageSize:
        mov     cl, 9
        shl     ax, cl; 512 = 2^9
        add     ax, [si].e_cblp  ; 可重定位程序映像加上已文件对齐的文件头的大小
        
        mov     dx, [si].e_cparhdr
        mov     cl, 4   ;  以节计,16B
        shl     dx, cl    ; *10h,得到已文件对齐的文件头的大小,这个也是可重定位程序映像在文件中的偏移
        sub     ax, dx  ; 得到可重定位程序映像的大小
        
        xor     cx, cx
        push    ax      ;
        mov     al, 0
        mov     ah, 42h ; move file pointer
        int     21h
        pop     cx      ;
        jc      err_file_move_pointer
        
        push    ds
        mov     ax, es
        mov     ds, ax
        lea     dx, mzImage
        mov     ah, 3Fh ; read file
        int     21h
        
        pop     ds
        jc      err_file_read
        
        cmp     ax, cx
        jb      err_file_invalid
        
        mov     ah, 3Eh ; close file
        int     21h
        
; relocate 重定位
        mov     bx, [si].e_lfarlc
        add     bx, offset mzHeader ; ->重定位表
        mov     cx, [si].e_crlc

        jcxz    setUpPsp
        
@@:
        mov     di, [bx].0 ; YY
        mov     ax, [bx].2 ; ZZ
        
        mov     dx, es  ;
        add     dx, 10h ; 将重定位映像加载于es+10h:0处  , XX = es+10h
        
        add     ax, dx  ; ZZ+XX
        
        push    es
        mov     es, ax
        add     es:[di], dx     ; 重定位:修正段地址
        pop     es
        
        add     bx, 4   ; 重定位表项长为4
        loop    @B

setUpPsp:
        ;mov     psp, 0CDH       ;
        ;mov     psp+1, 20H      ; write INT 20H instruction to PSP 实际执行时却报异常出错
        
        mov     psp,  0EAH      ; jmp far ptr imBack: 0EAH, offset imBack, seg imBack
        mov     word ptr psp+1, offset imBack
        mov     word ptr psp+3, seg imBack
        
        lea     dx, msgNewPrompt
        mov     ah, 9
        int     21h
        
setUpRegs:
        mov     dx, es  ;
        add     dx, 10h ; 将重定位映像加载于es+10h:0处  , XX = es+10h
        
        add     [si].e_cs, dx
        
        mov     ax, [si].e_cs
        mov     entryPoint+2, ax
        mov     ax, [si].e_ip
        mov     entryPoint, ax
        
        ;cmp     [si].e_ss, 0
        ;jne
        ;cmp     [si].e_sp, 0
        add     [si].e_ss, dx
        mov     ss, [si].e_ss   ;
        mov     sp, [si].e_sp   ;
        
        mov     ax, mzExeImage  
        mov     ds, ax  
        mov     es, ax  ; ds, es-> PSP
        
jmpToMzImage:
        ;jmp     dword ptr [si].e_ip     ; 注意写法
        ; 因为前几条指令改了ds
        assume  si: nothing
        
        jmp     dword ptr cs:entryPoint
        
entryPoint dw      ?, ?


imBack:
        mov     ax, data
        mov     ds, ax
        lea     dx, msgBack
        mov     ah, 9
        int     21h

bye:        
        mov     ah, 4ch
        int     21h   
; ------------------------
err_file_move_pointer:
        mov     ah, 3Eh ; close file
        int     21h       
        
        lea     dx, msgErrFileMovePointer
        mov     ah, 9
        int     21h
        jmp     bye
        
err_file_invalid:
        mov     ah, 3Eh ; close file
        int     21h       
        
        lea     dx, msgErrFileInvalid
        mov     ah, 9
        int     21h
        jmp     bye
        
err_file_read:
        mov     ah, 3Eh ; close file
        int     21h       
        
        lea     dx, msgErrFileRead
        mov     ah, 9
        int     21h
        jmp     bye
           
err_file_not_exist:
        lea     dx, msgErrFileNotExist
        mov     ah, 9
        int     21h
        jmp     bye        
      
code    ends

        end     start

--------------------------------------------------------------------------------------------------------------------------------

相关的文件:

--------------------------------------------------------------------------------------------------------------------------------

; common16.inc

CR      EQU     0DH
LF      EQU     0AH


; MZ header 取自MASM32的windows.inc
IMAGE_DOS_HEADER STRUCT
  e_magic           WORD      ?
  e_cblp            WORD      ?
  e_cp              WORD      ?
  e_crlc            WORD      ?
  e_cparhdr         WORD      ?
  e_minalloc        WORD      ?
  e_maxalloc        WORD      ?
  e_ss              WORD      ?
  e_sp              WORD      ?
  e_csum            WORD      ?
  e_ip              WORD      ?
  e_cs              WORD      ?
  e_lfarlc          WORD      ?
  e_ovno            WORD      ?
  e_res             WORD   4 dup(?)
  e_oemid           WORD      ?
  e_oeminfo         WORD      ?
  e_res2            WORD  10 dup(?)
  e_lfanew          DWORD      ?
IMAGE_DOS_HEADER ENDS

----------------------------------------

测试程序的源代码:

----------------------------------------

; test.asm 用来测试mzLoader的正确性

include common16.inc

assume  cs: code, ds: data, ss: stack


data    segment
msgHello db      'Hello, MZ file format', CR, LF, '$'        
data    ends

extra0   segment
        db      'extra0 segment', CR, LF, '$'
extra0   ends

extra1  segment
        db      'extra1 segment', CR, LF, '$'
extra1  ends

extra2  segment
        db      'extra2 segment', CR, LF, '$'
extra2  ends

extra3  segment
        db      'extra3 segment', CR, LF, '$'
extra3  ends

extra4  segment
        db      'extra4 segment', CR, LF, '$'
extra4  ends

extra5  segment
        db      'extra5 segment', CR, LF, '$'
extra5  ends

extra6  segment
        db      'extra6 segment', CR, LF, '$'
extra6  ends

extra7  segment
        db      'extra7 segment', CR, LF, '$'
extra7  ends

extra8 segment
        db      'extra8 segment', CR, LF, '$'
extra8  ends

extra9  segment
        db      'extra9 segment', CR, LF, '$'
extra9 ends


stack   segment stack
        db      256 dup (?)
stack   ends

code    segment
        mov     ax, stack       ; 这三条指令不用执行鸟
        mov     ss, ax
        mov     sp, 256
        
start:
        push    ds
        xor     ax, ax
        push    ax
     
        mov     ax, data
        mov     ds, ax
        
        mov     dx, offset msgHello
        mov     ah, 9
        int     21h
        
        mov     ax, extra0
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
        
        mov     ax, extra1
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
        
        mov     ax, extra2
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
        
        mov     ax, extra3
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
        
        mov     ax, extra4
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
        
        mov     ax, extra5
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
        
        mov     ax, extra6
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
        
        mov     ax, extra7
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
        
        mov     ax, extra8
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
        
        mov     ax, extra9
        mov     ds, ax
        mov     dx, 0
        mov     ah, 9
        int     21h
                
        mov     ax, code
        mov     ds, ax
        lea     dx, msgHello2
        mov     ah, 9
        int     21h
        
        retf
        
msgHello2 db    'code segment', CR, LF, '$'
   
code    ends

        end     start