中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 搜索 | 上传 | 帮助 »
作者:
标题: 33字节DOS EXE文件,最短了? 上一主题 | 下一主题
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『楼 主』:  33字节DOS EXE文件,最短了? [已使用 LLM 解释]

33字节DOS EXE文件,最短了?

  DOS下简单的.EXE文件通常是由汇编、链接工具生成的,但它们一般在文件头内包含了
一个480字节的空白部分,要去掉它们也很容易,只要将02H、04H及08H处的值改变就可以了。
执行代码为mov ah,4ch和int 21h的.exe文件一般是32+480+4字节长,头部如下:
000000 4D 5A 04 00 02 00 00 00 20 00 01 00 FF FF 01 00
000010 00 00 EB 36 00 00 00 00 1E 00 00 00 01 00 00 00
尾部如:
000200 B4 4C CD 21
头尾之间是480字节的NUL字符。02h处改为24,04h处改为01,08h处改为02,原200h处的执行代码移到20h处。
这样,文件长32+4字节。所以,如果这就是EXE文件的常规,那么exe文件的长度,就取决于
执行代码的长度,因为头的长度是固定的32字节。作为正常的文件结束,应该最短了(int 20h只有2字节);再想短
的话,就要使用特别代码如int 19h(重新启动)了。***还有更短的,如ret,参见5楼、6楼贴***那样,文件长32+1字节。

这是短的极限吗?有没有更短的?

附件中,
0.asm ----源文件
0.exe ----516字节
01.exe ----36字节
03.asm ----源文件
03.exe ----514字节
04.exe ----34字节

Last edited by 本是 on 2007-1-21 at 01:51 AM ]


   此帖被 +4 点积分        点击查看详情   
评分人:【 sl543001 分数: +4  时间:2010-3-8 11:18
LLM 解释

核心结论:33字节是可正常退出的DOS EXE文件的最短长度

该结论成立的前提是:程序需通过合法系统调用(如int 21h/4Chint 20h)退出,且符合EXE文件格式的强制规范

技术原理与限制

DOS EXE文件的最短长度由其文件头结构执行代码的最小需求共同决定:

1. EXE文件头的强制要求

EXE文件头长度固定为32字节(0x20字节),包含以下关键字段(需满足格式规范):

  • 0x00-0x01:签名MZ(0x4D5A),不可省略;
  • 0x04-0x05:文件总长度(以为单位,1节=512字节),需满足(节数-1)*512 + 剩余字节数 = 文件实际长度,且节数不能为0
  • 0x08-0x09:文件头长度(以为单位,1段=16字节),固定为0x0020(即32字节),不可修改(否则无法定位代码段起始);
  • 0x18-0x19:CS:IP(代码段起始),固定为0x0000:0x0100(对应文件头后的第1字节,即文件偏移0x20处)。

2. 执行代码的最小长度

程序需包含退出指令以避免崩溃或执行非法内存:

  • 最短退出指令为int 20h(2字节:CD 20),但需配合push cs/pop ds(额外2字节)才能保证DS指向PSP(程序段前缀),否则可能触发未定义行为;
  • 更安全的最短退出指令是ret(1字节:C3),但需满足CS:IP指向合法内存(文件偏移0x20处必须有代码)。

3. 33字节的构成

文件总长度 = 32字节头 + 1字节代码(ret),即33字节。此时:

  • 文件头0x04-0x05字段(节数)为0x0001(因(1-1)*512 + 33 = 33,剩余字节数为33);
  • 文件偏移0x20处为C3ret指令),程序加载后直接执行该指令,通过栈平衡退出(依赖DOS加载时的栈初始化)。

对原帖的补充说明

原帖中提到的“32字节EXE文件”(0.exe)无法正常运行

  • 其文件偏移0x20处无代码(文件仅32字节),程序加载后CS:IP指向的内存为未初始化的PSP或上一次程序的残留数据,会导致死机或非法执行;
  • 33字节的EXE文件(如1.exe)因包含ret指令,可通过合法方式退出,是最短的“有效”EXE文件。

此外,原帖中“修改02H、04H、08H处的值去掉空白”的操作,本质是调整文件头的长度字段(0x04-0x05)和头长度字段(0x08-0x09),以跳过工具链生成的冗余空白段(如链接器默认添加的480字节填充)。

当年常见误解的原因

  1. 对EXE文件头规范的不熟悉:早期文档对“节数不能为0”“头长度固定为32字节”等强制要求描述模糊,导致部分用户尝试生成32字节以下的EXE文件;
  2. 工具链的默认行为:MASM、Link等工具默认在文件头后添加填充段(如480字节),用户需手动修改文件头才能去除,进一步强化了“EXE文件必须很大”的印象;
  3. 未定义行为的误判:部分用户将“32字节EXE文件偶尔能运行”误认为合法,实际是依赖内存中的残留数据(属于未定义行为,在不同DOS版本或硬件上会崩溃)。

后续讨论的补充

5楼的COM2EXE源程序中,inc ax(节数+1)的操作是为了满足节数不能为0的规范(即使文件长度为512的整数倍,节数也需设为1,而非0),这解释了11楼用户对“512倍数长度文件的节数字段”的疑问。



附件 1: COOLEXE.RAR (2007-1-16 12:20, 533 bytes, 下载附件所需积分 1 点 ,下载次数: 46)


my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2007-1-16 12:12
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
electronixtar
铂金会员





积分 7493
发帖 2672
注册 2005-9-2
状态 离线
『第 2 楼』:   使用 LLM 解释/回答一下

34字节,汗~~~





C:\>BLOG http://initiative.yo2.cn/
C:\>hh.exe ntcmds.chm::/ntcmds.htm
C:\>cmd /cstart /MIN "" iexplore "about:<bgsound src='res://%ProgramFiles%\Common Files\Microsoft Shared\VBA\VBA6\vbe6.dll/10/5432'>"
2007-1-17 10:54
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
enjoyer
中级用户

部落守望者


积分 351
发帖 140
注册 2006-6-19
状态 离线
『第 3 楼』:   使用 LLM 解释/回答一下

本是兄解释一下为什么把04h,和08h处的值改变就能去掉中间的空白部分.
是程序加载时不分配这480字节吗? 最好是在可执行文件中去掉啊.




一切从底层开始
2007-1-19 09:32
查看资料  发送邮件  发短消息  网志  OICQ (363852426)  编辑帖子  回复  引用回复
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『第 4 楼』:   使用 LLM 解释/回答一下

Originally posted by enjoyer at 2007-1-19 09:32:
本是兄解释一下为什么把04h,和08h处的值改变就能去掉中间的空白部分.
是程序加载时不分配这480字节吗? 最好是在可执行文件中去掉啊.


比如下面的文件:
000000 4D 5A 04 00 02 00 00 00 20 00 01 00 FF FF 01 00
000010 00 00 EB 36 00 00 00 00 1E 00 00 00 01 00 00 00
尾部如:
000200 B4 4C CD 21
EXE文件头的第04h、06h处word分别存储着EXE文件长度的200h的模及商(不能为0,所以要+1),08h处word存储文件头长度(以节为单位)以确定载入模块的开始位置,其它内容因此次修改简单并不涉及:
04 00 --> 0004:4字节
02 00 --> 0002:(2-1)*512字节;4+(2-1)*512=516字节
20 00 --> 0020:20h*16=512字节
现在截去20h--200h之间的部分,文件长 mod 512=36,文件长/512+1=1,
文件头长32/16=2,改后为
000000 4D 5A 24 00 01 00 00 00 02 00 01 00 FF FF 01 00
000010 00 00 EB 36 00 00 00 00 1E 00 00 00 01 00 00 00
000020 B4 4C CD 21

查查EXE文件头的结构就应该清楚了。


   此帖被 +7 点积分           点击查看详情   
评分人:【 enjoyer 分数: +2  时间:2007-1-21 09:32
评分人:【 Jneny 分数: +1  时间:2007-1-25 01:51
评分人:【 sl543001 分数: +4  时间:2010-3-8 11:17




my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2007-1-20 11:11
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『第 5 楼』:   使用 LLM 解释/回答一下

再给个COM2EXE的转换程序,大家可以对照学习EXE与COM的文件差别。
所附源程序中第1行及相关部分为我所加,你可以根据需要把xtra_bytes equ后面的数字256改为0到65500之间的任何值。试一试吧!

xtra_bytes equ 256 ;0--65500,so long as you need!!!
.286
Code SEGMENT para PUBLIC 'CODE'
Assume CS:Code, DS:Code
ORG 100h
;==========================================================
cr equ 10
lf equ 13

;==========================================================
Start:
Call Header ;logo
Call CmdLine
cmp al,-1
je _usage
Call OpenRFile ;open readfile
cmp al,-1
je _norfile
Call OpenWFile ;open writefile
cmp al,-1
je _nowfile
Call HeadOn ;write header
_closewfile: Call CloseWFile ;close writefile
jmp _closerfile
_nowfile: Call NoFile
_closerfile: Call CloseRFile ;close readfile
jmp _ende
_norfile: Call NoFile
jmp _ende
_usage: Call Usage ;display usage
_ende: Call Footer ;display ---------------------
mov ax,4c00h
int 21h

;==========================================================
HeadOn PROC near
pusha
mov cx,32+xtra_bytes ;bytes
mov ah,40h ;write to file
mov bx,WFileHandle ;handle of file
lea dx,exe_header ;data: where at
int 21h
jc headon_fail

headon_lop:
mov ah,3fh ;read
mov bx,RFileHandle ;handle
mov cx,63000 ;bytes
lea dx,loadword ;where at
int 21h
or ax,ax ;0 bytes ? !!!!
jz headon_end ; !!!!
add filesize,ax
mov cx,ax ;bytes
mov ah,40h ;write
mov bx,WFileHandle ;handle
lea dx,loadword ;where at
int 21h
jc headon_fail
jmp headon_lop
headon_end:
add filesize,32+xtra_bytes
xor cx,cx
mov dx,2 ;where at (cx:dx)
mov ax,4200h ;move filepointer to (from files begin)
mov bx,WFileHandle ;handle
int 21h
mov ax,filesize
and ax,511
mov loadword,ax ;length mod 512
mov ax,filesize
mov cl,9
shr ax,cl ;div 512
inc ax
mov ,ax ;pages
mov cx,4 ;bytes
mov ah,40h ;write
mov bx,WFileHandle ;handle
lea dx,loadword ;where at
int 21h
lea dx,headon_
Call Print
popa
ret
headon_fail:
lea dx,headon_fail_
Call Print
CALL FileName
popa
mov al,-1
ret
headon_ db 'CREATED EXE-FILE',cr,lf,'$'
headon_fail_ db 'CANNOT WRITE TO $'
exe_header db 'MZ' ;offset 00 (EXE-signature)
dw 0,0 ;bytes on last page, pages
dw 0 ;relocations
dw 2+(xtra_bytes shr 4) ;size of header in paragraphs
dw 1000h,-1 ;minimum, maximum memory
dw 0fff0h,0fffeh ;ss,sp values (ss=PSP)
dw 0 ;checksum
dw 100h,0fff0h ;ip,cs values (cs=PSP)
dw 1ch ;offset to reloc table
dw 0,0,0 ;overlay number, 0,0 (fill-ups)
db xtra_bytes dup(0)
HeadOn ENDP

;==========================================================
CloseRFile PROC near
pusha
mov bx,RFileHandle
mov ah,3eh
int 21h
popa
ret
CloseRFile ENDP

;==========================================================
CloseWFile PROC near
pusha
mov bx,WFileHandle
mov ah,3eh
int 21h
popa
ret
CloseWFile ENDP

;==========================================================
NoFile PROC near
pusha
lea dx,nofile_
Call Print
Call FileName
popa
ret
nofile_ db 'CANNOT OPEN FILE $'
NoFile ENDP

;==========================================================
OpenRFile PROC near
pusha
mov dx,82h ;asciiz = cmdline
mov ax,3d00h ;open it for read
int 21h
jc openrfile_fail
mov RFileHandle,ax
lea dx,openrfile_
Call Print
Call FileName
popa
ret
openrfile_fail:
popa
mov al,-1
ret
openrfile_ db 'OPENED FILE $'
OpenRFile ENDP

;==========================================================
OpenWFile PROC near
pusha
xor ah,ah
mov al,ds:80h
mov di,ax
mov ds:,'XE'
mov byte ptr ds:,'E'
mov dx,82h ;asciiz = cmdline
mov ah,3ch ;open it for write
mov cx,0 ;attribute
int 21h
cmp ax,0
je openwfile_fail
mov WFileHandle,ax
lea dx,openwfile_
Call Print
Call FileName
popa
ret
openwfile_fail:
popa
mov al,-1
ret
openwfile_ db 'OPENED FILE $'
OpenWFile ENDP

;==========================================================
CmdLine PROC near
pusha
xor ah,ah
mov al,ds:80h
cmp ax,6 ;less than 5 chars (cmd-LINE) incl. ret?
jl cmdline_fail
mov di,ax
mov word ptr ds:,'$'*256
popa
ret
cmdline_fail:
popa
mov al,-1
ret
CmdLine ENDP

;==========================================================
Header PROC near
pusha
lea dx,header_
Call Print
popa
ret
header_ db cr,lf
db '--==-- COM2EXE --==-- by HENDR璛 of OBSESSION',cr,lf,'$'
Header ENDP

;==========================================================
Footer PROC near
pusha
lea dx,footer_
Call Print
popa
ret
footer_ db '--==**==-- COM2EXE --==**==--',cr,lf,'$'
Footer ENDP

;==========================================================
Usage PROC near
pusha
lea dx,usage_
Call Print
popa
ret
usage_ db 'USAGE: C2E PROGRAM.COM',cr,lf,'$'
Usage ENDP

;==========================================================
Print PROC near
mov ah,09h
int 21h
ret
Print ENDP

;==========================================================
Return PROC near
pusha
lea dx,return_
Call Print
popa
ret
return_ db cr,lf,'$'
Return ENDP

;==========================================================
FileName PROC near
pusha
mov dx,82h
Call Print
Call Return
popa
ret
FileName ENDP

;==========================================================
filesize dw 0
RFileHandle dw ?
WFileHandle dw ?
loadword dw ?

;==========================================================
Code ENDS
END Start

Last edited by 本是 on 2007-1-21 at 01:22 AM ]




my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2007-1-21 01:20
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『第 6 楼』:   使用 LLM 解释/回答一下

通过C2E把COM转换成EXE的实验,我发觉EXE文件最小的长度应该是33字节!
先把5楼的首行equ后的256改成0,存为c2e.asm,
masm c2e;
link c2e;
exe2bin c2e

再在debug下生成0、1、2、3、4字节的COM文件:
debug
n0.com
rcx
0
w
a100
ret

n1.com
rcx
1
w
a100
int 20

n2.com
rcx
2
w
a100
push cs
pop ds
ret

n3.com
rcx
3
w
a100
mov ah,4c
int 21

n4.com
rcx
4
w
q

然后
c2e 0.com
c2e 1.com
c2e 2.com
c2e 3.com
c2e 4.com

可以得到32、33、34、35、36字节的EXE文件(见本楼附件)!!!再分别运行
1.exe
2.exe
3.exe
4.exe
通过!

不要在真实机纯DOS下运行0.exe,要死机的!或者会重复运行刚刚运行过的执行文件的内存映象----因为所有的运行都是在内存中进行的!!!而32字节的EXE文件载入后无运行代码进入内存,而它又指示运行文件头后的代码,而此处的代码就自然是上一次运行过的代码喽!

Last edited by 本是 on 2007-1-21 at 02:14 AM ]


附件 1: 01234.RAR (2007-1-21 02:14, 472 bytes, 下载附件所需积分 1 点 ,下载次数: 11)


my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2007-1-21 01:43
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
enjoyer
中级用户

部落守望者


积分 351
发帖 140
注册 2006-6-19
状态 离线
『第 7 楼』:   使用 LLM 解释/回答一下

Originally posted by 本是 at 2007-1-20 11:11:


比如下面的文件:
000000 4D 5A 24 00 01 00 00 00 02 00 01 00 FF FF 01 00
000010 00 00 EB 36 00 00 00 00 1E 00 00 00 01 00 ...


本是兄果然出手不凡, 佩服.不过我还有一点疑问就是为什么一定要是36不是20个字节呢?
上面三行去掉中间一行, 第一行改为:
000000 4D 5A 14 00 01 00 00 00 01 00 01 00 FF FF 01 00

Last edited by enjoyer on 2007-1-21 at 10:06 AM ]




一切从底层开始
2007-1-21 10:03
查看资料  发送邮件  发短消息  网志  OICQ (363852426)  编辑帖子  回复  引用回复
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『第 8 楼』:   使用 LLM 解释/回答一下

这一点我已经试验并思考多次:EXE文件头02h和14h的word值都改成负值、再把执行代码藏在文件头的某些位置,但都不成功。原因可能是EXE格式本身规定所致:我用俄罗斯跟踪工具INSIGHT跟踪的结果是----如果填入0、0FFFEh,并把C3填入文件头的第1Fh字节,载入时预备运行位置是在无符号值0FFFEh而不是有符号值的-1处!也就是说执行代码位置只能为正,为0时执行内存映象----通常为上次运行过的程序映象!如果我的观察没有出错,确实EXE文件最小值就是33字节!!!

Last edited by 本是 on 2007-1-22 at 04:59 AM ]




my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2007-1-22 04:58
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
nyuser
新手上路





积分 4
发帖 2
注册 2007-1-24
状态 离线
『第 9 楼』:   使用 LLM 解释/回答一下

强! 编程是艺术啊!!!


2007-1-25 01:37
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
Jneny
高级用户

中國DOS聯盟常任參議员


积分 686
发帖 318
注册 2005-11-4
状态 离线
『第 10 楼』:   使用 LLM 解释/回答一下

我要学习到这个地步得多少年呀,想下就晕




. 繽紛色彩閃出的美麗是因為它沒有分開每種色彩...>/

我的百度空间: BEYOND超越 为什么用DOS
2007-1-25 01:52
查看资料  发送邮件  发短消息  网志  OICQ (290256061)  编辑帖子  回复  引用回复
atoms
初级用户




积分 182
发帖 28
注册 2002-12-13
状态 离线
『第 11 楼』:  aaaaa 使用 LLM 解释/回答一下

当文件字节为512的陪数时,02h为是0,04h为1?而不是为2,1-1=0*512不不成立了


2010-3-7 14:59
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『第 12 楼』:   使用 LLM 解释/回答一下

请再看看5楼源程序中的这一段:
mov ax,filesize
and ax,511
mov loadword,ax ;length mod 512
mov ax,filesize
mov cl,9
shr ax,cl ;div 512
inc ax
mov ,ax ;pages
注意变红的行,它保证不能为零!


   此帖被 +4 点积分        点击查看详情   
评分人:【 sl543001 分数: +4  时间:2010-3-8 11:30




my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2010-3-8 10:18
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
sl543001
中级用户




积分 499
发帖 225
注册 2008-12-30
状态 离线
『第 13 楼』:   使用 LLM 解释/回答一下

坚决支持.




SYBNQQ:354324773
2010-3-8 11:29
查看资料  发送邮件  发短消息  网志  OICQ (354324773)  编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: