⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exe2bin.c

📁 将 DOS 下包含重定位信息的 .EXE 文件转换成指定起始加载位置的 .BIN 文件。在 BIOS 开发和 X86 嵌入式开发中极有用。
💻 C
字号:
/*
 *           File: exe2bin.c
 *        Version: 3.14
 *   Last Updated: July 25, 2004
 * 
 *  Copyright (C) 2002, ChipLink Microsystem Labs. All Rights Reserved.
 *
 *    Description: This file is a part of my Micro-Kernel RTOS (QNX like),
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef char		int8;
typedef short		int16;
typedef long		int32;

typedef unsigned char	uint8;
typedef unsigned short  uint16;
typedef unsigned long	uint32;


#pragma  pack(push,1)

typedef struct
{
	uint16	Signature;	/* offset 00-01 */
	uint16	ExtraBytes;	/* offset 02-03 */
	uint16	Pages;		/* offset 04-05 */
	uint16	RelocItems;	/* offset 06-07 */
	uint16	HeaderSize;	/* offset 08-09 */
	uint16	MinAlloc;	/* offset 0A-0B */
	uint16	MaxAlloc;	/* offset 0C-0D */
	uint16	InitSS;		/* offset 0E-0F */
	uint16	InitSP;		/* offset 10-11 */
	uint16	CheckSum;	/* offset 12-13 */
	uint16	InitIP;		/* offset 14-15 */
	uint16	InitCS;		/* offset 16-17 */
	uint16	RelocTable;	/* offset 18-19 */
	uint16	Overlay;	/* offset 1A-1B */

	/*
	Hack here(July-24-2004):
	以下两个字段 Borland 用来标志 Linker 的版本号 
	*/
	uint16  Reserved1;	/* offset 1C-1D */
	uint8   Reserved2[2];	/* offset 1E-1F */

} exe_header;


#pragma  pack(pop)


#define EXE_MAGIC1	0x5a4d	/* "MZ" */
#define EXE_MAGIC2	0x4d5a	/* "ZM" */

#define EXE_NE_MAGIC	0x454e	/* "NE" --- Windows 3.x(win16) App */
#define EXE_LE_MAGIC	0x454c	/* "LE" --- Windows 3.x(win16) VxD */
#define EXE_PE_MAGIC	0x4550	/* "PE"	--- Windows NT(win32) App */
#define EXE_LX_MAGIC	0x584c	/* "LX" --- OS/2 App */


#define GOT_EXENAME	0x01
#define GOT_BINNAME	0x02
#define GOT_SEGMENT	0x04

#define GOT_MASK	(GOT_EXENAME | GOT_BINNAME | GOT_SEGMENT )



void	copyright(void)
{
	printf("EXE2BIN Version 3.14, Copyright (c) 1993-2004 ChipLink Microsystem Labs.\n\n\r");
}

void	usage(void)
{
	printf("Usage: \n");
	printf("       EXE2BIN [/EXE=]exe_file[.exe] [[/BIN=]bin_file[.bin]] [/SEG=nnnn]\n");
	printf("where:\n");
	printf("       nnnn --- Segment in Hexadecimal system, default=0000H\n\n\r");
}


int main(int argc, char **argv)
{
	exe_header   hdr;
	FILE       * src, * dst;
	uint32       flen, plen, addr;
	uint8      * img = NULL;
	
	uint16       i, opt, rseg, roff, * tab = NULL, segment=0x0000;
	char         ename[256]={0}, bname[256]={0}, tmp[256]={0}, * p;

	copyright();


	/* 命令行分析 */
	for ( opt=0, --argc, ++argv; (argc > 0) && (opt!=GOT_MASK); --argc, ++argv ) 
	{
		/* 先判是否是 seg 参数 */
		if( strnicmp( *argv, "/EXE", 4 )==0 )
		{
			strcpy( ename , (*argv)+5 );
			opt |= GOT_EXENAME;
		}
		else if( strnicmp( *argv, "/BIN", 4 )==0 )
		{
			strcpy( bname , (*argv)+5 );
			opt |= GOT_BINNAME;
		}
		else if( strnicmp( *argv, "/SEG", 4 )==0 )
		{
			segment = (uint16)strtoul( (*argv)+5, NULL, 16);
			opt |= GOT_SEGMENT;
		}
		else {
			
			if( (opt & GOT_EXENAME)==0 )
			{
				strcpy( ename , *argv );
				opt |= GOT_EXENAME;
			}
			else if( (opt & GOT_BINNAME)==0 )
			{
				strcpy( bname , *argv );
				opt |= GOT_BINNAME;
			}
		}
	}


	/* 用户在命令行中未给出 EXE 文件名 */
	if(  !(opt & GOT_EXENAME) )
	{
		usage();
		return -1;
	}


	//首先确定 EXE 文件名中有无 '.' 分割符, 需要先找到最后一个 '\' 目录分隔符 
	p = strrchr( ename, '\\' );

	if( !p )
	{
		p = strrchr( ename, '.' );
	}
	else {
		p = strrchr( p, '.' );
	}

	
	if( !(opt & GOT_BINNAME) )
	{
		//EXE 文件名中有 '.' 分割符
		if( p )
		{
			strncpy( bname, ename, p-ename );
		}
		else 
		{
			//如果 EXE 文件名中未给出 '.' 分割符
			strcpy( bname, ename );	
		}

		strcat( bname, ".bin" );
	}



	if( !p )
	{
		strcpy( tmp, ename );
		strcat( tmp, ".exe" );
		printf("    EXE File: '%s' or '%s'(I Guess:-)\n", ename, tmp );
	}
	else 
	{
		printf("    EXE File: '%s'\n", ename );
	}
	
	printf("    BIN File: '%s'\n", bname );
	printf("     Segment: %04X (Hex)\n\n\r", segment );

	src = fopen( ename, "rb");
	
	if( !src )
	{
		//若打开失败,则在用户未给出 .EXE 扩展名的情况下尝试补齐扩展名再打开
		if( !p )
		{
			src = fopen( tmp, "rb" );
		}

		//若补齐扩展名仍不能打开, 报错退出
		if( !src )
		{
			printf("Cannot open file: neither %s or %s!\n", ename, tmp );
			return -2;
		}
	}
	
	
	fread( &hdr, 1, sizeof(hdr), src );

	if( hdr.Signature != EXE_MAGIC1 && hdr.Signature != EXE_MAGIC2 )
	{
		printf("This is not a EXE file!\n");
		fclose(src);
		return -3;
	}
	
	/*
	需再增加对 NE/LE/PE 格式的检查,确保只处理 DOS 的 Old EXE 格式
	*/
	if( hdr.RelocTable >= 0x40 )
	{
		fseek( src, 0x3cL, SEEK_SET );
		fread( &roff, 1, sizeof(uint16), src );
		
		fseek( src, (long)roff, SEEK_SET );
		fread( &opt, 1, sizeof(uint16), src );

		if( opt==EXE_NE_MAGIC || opt==EXE_LE_MAGIC || opt==EXE_PE_MAGIC || opt==EXE_LX_MAGIC )
		{
			printf("Windows NE/LE/PE or OS/2 LX format EXE file is not supported!\n");
			fclose(src);
			return -4;
		}
	}


	dst = fopen( bname, "wb");
	if( !dst )
	{
		printf("Cannot create file: %s!\n", bname );
		fclose(src);
		return -5;
	}

	flen = hdr.ExtraBytes?( (hdr.Pages-1) *512L + hdr.ExtraBytes): (hdr.Pages *512L);
	plen = flen - (hdr.HeaderSize*16L);

	printf("DOS File size:                              \t%Xh ( %u )\n", flen, flen );
	printf("Load Image Size:                            \t%Xh ( %u )\n", plen, plen);

	printf("Relocation Table entry count:               \t%04Xh ( %5u )\n", hdr.RelocItems, hdr.RelocItems );
	printf("Relocation Table address:                   \t%04Xh ( %5u )\n", hdr.RelocTable, hdr.RelocTable );
	printf("Size of header record      (in paragraphs): \t%04Xh ( %5u )\n", hdr.HeaderSize, hdr.HeaderSize );
	printf("Minimum Memory Requirement (in paragraphs): \t%04Xh ( %5u )\n", hdr.MinAlloc, hdr.MinAlloc );
	printf("Maximum Memory Requirement (in paragraphs): \t%04Xh ( %5u )\n", hdr.MaxAlloc, hdr.MaxAlloc );
	printf("File load checksum:                         \t%04Xh ( %5u )\n", hdr.CheckSum, hdr.CheckSum );
	printf("Overlay Number:                             \t%04Xh ( %5u )\n\n", hdr.Overlay, hdr.Overlay );


	if( hdr.Reserved1==0x0001 && hdr.Reserved2[0]==0xFB )
	{
		printf("Linker: Borland TLINK Version %u.%02u\n\n", (hdr.Reserved2[1]>>4)&0x0f, hdr.Reserved2[1] & 0x0f );
	}

	printf("Initial Stack Segment  (SS:SP):             \t%04X:%04X\n", hdr.InitSS, hdr.InitSP );
	printf("Program Entry Point    (CS:IP):             \t%04X:%04X\n\n\r", hdr.InitCS, hdr.InitIP );


	if( hdr.RelocItems )
	{
		/* 重单位项 */
		fseek( src, (long)hdr.RelocTable, SEEK_SET );
		
		tab = (uint16 *)malloc( hdr.RelocItems * 4 );

#if 0
		printf("malloc %d size for %d RelocateTable Items!\n", 
			hdr.RelocItems * 4, hdr.RelocItems );
#endif
		
		if( !tab )
		{
			printf("Cannot allocate memory for Relocation Items!\n");
			fclose(src);
			fclose(dst);
			return -6;
		}
		
		memset( tab, 0, hdr.RelocItems * 4 );
		
		fread( tab, 1, hdr.RelocItems * 4, src );
		
		printf("Relocation Locations (%u Entries)\n\n", hdr.RelocItems );

		for( i=0; i<hdr.RelocItems; i++ )
		{
			roff = tab[ 2*i ];
			rseg = tab[ 2*i+1 ];
			
			printf("    %04X:%04X", rseg, roff );
			
			if( i%5==4 ) printf("\n");
		}
		
		
		printf("\n\n\r");
	}
	

	/* Ok, Let's doing the real works */
	fseek( src, (hdr.HeaderSize*16L), SEEK_SET );


	img = (uint8 *)malloc( plen );
	if( !img )
	{
		printf("Cannot allocate memory for image!\n");
		if( tab ) free(tab);
		fclose(src);
		fclose(dst);
		return -7;
	}

	memset( img, 0, plen );

	fread( img, 1, plen, src );


	for(i=0;i<hdr.RelocItems;i++)
	{
		roff = tab[ 2*i ];
		rseg = tab[ 2*i+1 ];

		addr = ( (uint32)(rseg << 4 ) + roff  );

		*((uint16 *)( (uint8 *)img + addr) ) += segment;

#if 0		
		printf("address( %08X = %04X:%04X ) = %04X(File offset: %lu )\n", addr, rseg, roff, 
			*((uint16 *)( img + addr)), addr + (hdr.HeaderSize*16L)  );
#endif	
	}


	fwrite( img, 1, plen, dst );
	
	
	if( tab ) free(tab);
	if( img ) free(img);

	fclose(src);
	fclose(dst);


	printf("File was successfully converted!\n\r");

	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -