/* Example code to place values into an executable file. */ /**************************************************************************** * The process is relatively simple, but the explanation is lengthy. A little * knowledge of executable file format is all that is necessary. * * The .EXE file format is as follows: * Offset Length Name Comment * ------ ------ --------- ----------------------------------------------------- * 0h 2 Signature The values 4Dh, 5Ah. Telss DOS this is a valid * Executable. * 2h 2 Length1 The length of the load image modulus 512. * 4h 2 Length2 Size of file in 512 byte pages including header. * 6h 2 Items Number of segment relocation items in relocation * table. * 8h 2 Length3 The length of the header in 16 byte paragraphs. * Ah 2 MinAlloc Minimum number of paragraphs required above the * end of the load image. * Ch 2 MaxAlloc Maximum number of paragraphs required above the * end of the load image. * Eh 2 Stack Displacement in paragraphs of the stack segment * within the load image. * 10h 2 StackP Offset to use for initial Stack Pointer. * 12h 2 ChkSum Defined as the negative sum of all the words in * the file ignoring overflow. Every one I've seen * is just set to 0. * 14h 2 InstP Offset to place in the IP. * 16h 2 InstSeg Displacement of initial Code Segment. * 18h 2 FirstI File offset of first relocation item. * 1Ah 2 OvlN Overlay number = 0 for resident program. * * From this information, the file locations of all data can be found in the * following manner: * * Base_Of_Load_Image = Length3*16 * Location_Of_Data_Item = Base_Of_Load_Image + Data_Segment*16 + Data_Offset * * The only other thing you need is to make sure that the data you wish to * modify is initialized explicity. This is because, uninitialized data is * not stored in the executable if its segment is the last segment in the * program. That's what the MinAlloc variable is for. It tells the DOS * loader how much data space to allocate at runtime for uninitialized * data. * * You must also know, how many data items you wish to be able to self * modify, what their structure is and where they are in the file. * * This program: * Will attempt to double the values of 5 separate locations in its * executable file each time run. * * To accomplish this, you must link the program with maps set to publics * or detailed. This will give you the locations of the following vars: * theLocations is an array holding the load image offsets of each * location to change. * Location1-5 are the locations to be modified. * * I compiled this with maps set to publics and large memory model. From * the generated map(WRTEXE.MAP) the following information is seen: * * Address Publics by Name * * 01CA:00A4 _Location1 * 01CA:00BA _Location2 * 01CA:00D0 _Location3 * 01CA:00E6 _Location4 * 01CA:00FC _Location5 * 01CA:0090 _theLocations * * Using this information the file offset of: * theLocations = 1CAh * 10h + 90h = 1D30h into the load image. * Location1 = 1CAh * 10h + A4h = 1D44h * Location2 = 1CAh & 10h + BAh = 1D5Ah * Location3 = 1CAh & 10h + D0h = 1D70h * Location4 = 1CAh & 10h + E6h = 1D86h * Location5 = 1CAh & 10h + FCh = 1D9Ch * * What I need to do by hand then, is to change locations: * 1D30h ==> 1D44h * 1D34h ==> 1D5Ah * 1D38h ==> 1D70h * 1D3Ch ==> 1D86h * 1D40h ==> 1D9Ch * * this I'll do through debug by renaming WRTEXE.EXE to WRTEXE.DBG and * loading this into debug and using the following info provided by * Borland's TDUMP: * * DOS File Size 349Fh ( 13471. ) * Load Image Size 2230h ( 8752. ) * Relocation Table entry count 0043h ( 67. ) * Relocation Table address 003Eh ( 62. ) * Size of header record (in paragraphs) 0020h ( 32. ) * Minimum Memory Requirement (in paragraphs) 0000h ( 0. ) * Maximum Memory Requirement (in paragraphs) FFFFh ( 65535. ) * File load checksum 0000h ( 0. ) * Overlay Number 0000h ( 0. ) * * Initial Stack Segment (SS:SP) 021B:0080 * Program Entry Point (CS:IP) 0000:0000 * * * The start of the load image is then 20h * 10h = 200h * * the debug session is then * * DEBUG WRTEXE.DBG * -DDS:2030 * 2030 = 200h+100h+1D30h where 200h is the beginning of the load image * 100h is the offset that debug loads * 1D30h is where theLocations is in the * load image * debug then shows this area as being: * 42 42 00 00 42 42 00 00 42 42 00 00 42 42 00 00 * 42 42 00 00 .... * * -EDS:2130 44 1D 00 00 5A 1D 00 00 70 1D 00 00 86 1D 00 00 9C 1D 00 00 * this changes the 5 locations to the load image relative offsets * of the 5 locations I want to change. * * -W * -Q * * then rename WRTEXE.DBG back to WRTEXE.EXE and you can run the demo. * * */ #include /* printf/sprintf */ #include /* _open, _write, _read, lseek, _close */ #include /* O_RDWR, O_BINARY, O_DENYNONE */ #include /* strlen */ typedef unsigned short word; typedef unsigned long dword; typedef unsigned char byte; /* define an executable header. */ typedef struct { word Signature; word Length1; word Length2; word Items; word Length3; word MinAlloc; word MaxAlloc; word Stack; word StackP; word ChkSum; word InstP; word InstSeg; word FirstI; word OvlN; }exeHeader; /* open an executable and check its header for validity! return an open file handle on success or -1 on failure */ int openEXE( char *itsName, exeHeader *itsHeader ) { /* do I really exist */ if( !access( itsName, 0 ) ) { int aHandle; /* open the file */ if( (aHandle = _open( itsName, O_RDWR | O_BINARY | O_DENYNONE )) != -1 ) { /* read the header */ if( _read( aHandle, itsHeader, sizeof( exeHeader ) ) == sizeof( exeHeader ) ) { /* check for validity! remember that byte order is reversed on Intel machines */ if( itsHeader->Signature == 0x5a4d ) { return aHandle; /* its good */ } } /* oops!!! */ _close( aHandle ); } } return -1; } #define LocationsToChange 5 /* locations to make changes to, this must be initialized to make sure they are in the executable file */ dword theLocations[ LocationsToChange ]={ 0x4242, 0x4242, 0x4242, 0x4242, 0x4242 /* made this like this to be sure I have correct location when I hand modify this file */ }; typedef struct { word aValue; char aString[20]; }someData; someData Location1={ 1, "Location 1" }; word Filler1; someData Location2={ 2, "Location 2" }; word Filler2; someData Location3={ 3, "Location 3" }; word Filler3; someData Location4={ 4, "Location 4" }; word Filler4; someData Location5={ 5, "Location 5" }; /* just so I have a quick way to reference my data */ someData *quickRef[]={ &Location1, &Location2, &Location3, &Location4, &Location5 }; /* this function will make the changes to the Executable. This may not be run until the executable has been processed to make the data locations known */ int changeLocations( char *whoIAm ) { int Count; int aHandle; exeHeader aHeader; dword itsStart; /* open the executable up */ if( (aHandle = openEXE( whoIAm, &aHeader )) != -1 ) { /* get the start of the load image */ itsStart = (dword)aHeader.Length3 * 16; /* for each location we wish to change */ for( Count = 0; Count < LocationsToChange; Count++ ) { /* double the value */ quickRef[Count]->aValue <<= 1; /* update the string */ sprintf( quickRef[Count]->aString, "Location %u", quickRef[Count]->aValue ); /* locate its entry */ lseek( aHandle, itsStart + theLocations[ Count ], SEEK_SET ); /* write the new info to the executable */ _write( aHandle, quickRef[Count], sizeof( someData ) ); } /* all done */ _close( aHandle ); /* far out */ return 0; } return -1; } /* main routine */ void main( int argC, char **argL ) { int Count; argC = argC; /* eliminates variable not used warning */ /* DOS >= 3.2 first argument is full path name of executable program */ if( !strlen( argL[0] ) ) { printf( "Need DOS version 3.2 or higher to run this\n\n" ); abort( ); } /* demo what current values are */ printf( "WRTEXE values currently set to:\n" ); for( Count = 0; Count < LocationsToChange; Count++ ) { printf( "\t%u: %s\n", quickRef[Count]->aValue, quickRef[Count]->aString ); } printf( "\n" ); /* attempt to modify the exe file */ if( !changeLocations( argL[0] ) ) { /* did OK */ printf( "Next time you run this the values will be doubled\n" ); } else { /* something went wrong */ printf( "Error unable to change executable %s\n", argL[0] ); } exit( 0 ); }