Contributor: DUNCAN MCNIVEN { Most suggestions for modifying EXE files involve storing and searching for a marker value. This seems clumsy. An alternative is given in "PC Techniques C/C++ Power Tools" by Duntemann & Weiskamp. This involves deducing the position in the disk file at which initialised constants are stored, based on their address in RAM at run time. I have produced a demo Pascal program based on these ideas. The code is given below. It works fine, but only in real mode. Can anyone see any way to use the same approach in protected mode or, ideally, in Windows ? } program TestMod; type TEXEHeader = record EXEID : Word; {EXE File identifier } ByteMod : Word; {Load module image size mod512} Pages : Word; {File size (inc hdr) div 512 } RelocCnt : Word; {No. of relocation table items} Size : Word; {Header size in 16-byte paras } MinParas : Word; {Min. No. of paras above prog } MaxParas : Word; {Max. No. of paras above prog } StackSeg : Word; {Displacement of stack segment} spreg : Word; {Initial SP register value } CheckSum : Integer;{Negative checksum (unused) } ipreg : Word; {Initial IP register value } CodeSeg : Word; {Displacement of code segment } Reloc1 : Word; {First relocation item } ovln : Word; {Overlay number } end; const MyStr : String = 'Original string in EXE file'; PSPSize = 16; { Size of Program Segment Prefix = 16 paragraphs } ParaSize = 16; { 1 paragraph = 16 bytes } fmShareDenyWrite = $0020; { EXE File open mode } var EXEHdrSize : Integer; EXEName : String; DiskPos : LongInt; F : File; procedure GetEXENameAndHdrSize; var EXEHdr : TEXEHeader; begin EXEName := ParamStr(0); Assign(F,EXEName); FileMode := fmShareDenyWrite; Reset(F,1); BlockRead(F,EXEHdr,SizeOf(TEXEHeader)); close(F); EXEHdrSize := EXEHdr.Size; end; procedure RestoreDefaultStr( var S : String ); var DiskPos : LongInt; begin assign(F,EXEName); FileMode := fmShareDenyWrite; reset(F,1); DiskPos := (Seg(S)-(PrefixSeg+PSPSize)+EXEHdrSize)*ParaSize+Ofs(S); seek(F,DiskPos); blockread(F,S[0],1); { Find size of default value for string } blockread(F,S[1],Integer(S[0])); { Read the string itself } close(F); end; procedure SetNewDefaultStr( var S : String ); var DiskPos : LongInt; begin assign(F,EXEName); FileMode := fmShareDenyWrite; rewrite(F,1); DiskPos := (Seg(S)-(PrefixSeg+PSPSize)+EXEHdrSize)*ParaSize+Ofs(S); seek(F,DiskPos); blockwrite(F,S[0],Length(S)+1); close(f); end; begin GetEXENameAndHdrSize; writeln(MyStr); { Show original string value } MyStr := 'Changed in RAM'; { Change string so we can tell} Writeln(MyStr); { if we read EXE file OK. } RestoreDefaultStr( MyStr );{ Read original from EXE file } Writeln(MyStr); MyStr := 'Written to EXE'; { Change the string and } SetNewDefaultStr( MyStr ); { write new value to EXE file } MyStr := 'Temp RAM value'; { Change again so we can test } writeln(MyStr); { if new value read from EXE } RestoreDefaultStr( MyStr );{ Read the value we earlier } Writeln(MyStr); { wrote to the EXE file. } end.