Board logo

标题: 33字节DOS EXE文件,最短了? [打印本页]

作者: 本是     时间: 2007-1-16 12:12    标题: 33字节DOS EXE文件,最短了?

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 ]
附件 1: COOLEXE.RAR (2007-1-16 12:20, 533 bytes, 下载附件所需积分 1点 ,下载次数: 46)

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


  Quote:
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文件头的结构就应该清楚了。
作者: 本是     时间: 2007-1-21 01:20
再给个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        [loadword+2],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:[di+80h-2],'XE'
        mov        byte ptr ds:[di+80h],'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:[di+81h],'$'*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 ]
作者: 本是     时间: 2007-1-21 01:43
通过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)

作者: enjoyer     时间: 2007-1-21 10:03


  Quote:
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-22 04:58
这一点我已经试验并思考多次: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 ]
作者: nyuser     时间: 2007-1-25 01:37
强! 编程是艺术啊!!!
作者: Jneny     时间: 2007-1-25 01:52
我要学习到这个地步得多少年呀,想下就晕
作者: atoms     时间: 2010-3-7 14:59    标题: aaaaa

当文件字节为512的陪数时,02h为是0,04h为1?而不是为2,1-1=0*512不不成立了
作者: 本是     时间: 2010-3-8 10:18
请再看看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        [loadword+2],ax        ;pages
注意变红的行,它保证不能为零!
作者: sl543001     时间: 2010-3-8 11:29
坚决支持.