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