Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How can I embed files into an EXE?

Package Deployment

How can I embed files into an EXE?

by  msc0tt  Posted    (Edited  )
Q: How can I embed files into an EXE?

A: An executable program (.EXE) doesn't appear to care if 'stuff' has been appended to the end of the binary file. This behaviour can exploited to 'embed' files into an exe (i.e. single-file installer). There are some commecial products available that facilitate this, plus a handful of freeware classes and routines. In general, I will describe my own process to accomplish adding/extracting attachments within an exe.

At the end of the EXE, we append one or more attachments. Each attachment contains the actual file attached, and a footer record describing the attachment. So, a program with 2 attachments would be layed out as follows:
[our EXE program]
[attachment #1]
[footer record for attach #1]
[attachment #2]
[footer record for attach #2]

The reason for the footer records is because it would be difficult (programically) to determine where the EXE ends and the attachments start. Therefore, we work backwards from the bottom of the file, extracting the files. Every footer record has the following format:
filenameLength as Integer
filename as String
filesize as Long
filePosition as Long
footerID as String
footerPosition as Long

The size of the footer is variable, since we want to have filenames of an arbitrary length. The filePosition and footerPosition both indicate absolute byte positions in the EXE file. The footerID string will have a fixed value, such as "ATTACHED-FILE".

Obviously, we need to get our files attached before we can extract them.

ATTACHING THE FILES:

I have a simple program I created to append files to an .EXE. It proceeds something like this:
1. open the .EXE
2. open attachment file, read into a String var, close attachment
3. write attachment (String var) at end of .EXE
4. calculate values for footer record
5. write footer record at end of .EXE
6. IF MORE FILES to attach, go to Step 2
7. close the .EXE

EXTRACTING THE FILES:

Typically the extration routine is performed by the .EXE itself. That's the whole point.
1. open the .EXE (himself!)
2. keep track of our file position with a Long (initially set to EOF)
3. read the last 2 fields of footer...... if it 'IS' a footer
4. look for the footerID string
5. if the data there is not the footerID string, this ain't no attachment, so exit Step 12.
6. now that we have the footerPosition, we read the top portion of the footer.
7. we've read the whole footer, so read the actual embedded file into a String var.
8. create a new file, using 'filename' from our footer
9. write the String var to this new file, and close, creating our attachment as a separate file
10. we know the size of this file, plus the size of the footer we just read, so calculate where the bottom of the next attachment footer will be (working backwards up the .EXE).
11. goto Step 3.
12. close the .EXE cause we're done

Notes:
My needs were simple. All the files to be extracted were destined for the same directory, so I didn't keep directory information in the attachment footer. Obviously, this footer record could be extended to include whatever you wish. Also, of the files I needed to attach, the largest was just over 1MB, so I was comfortable slurping the whole attachment into a String. To be truly scalable, this could be enhanced for multiple reads/writes of a maximum size per slurp. For those unfamiliar to binary I/O and GETing a string, the number of characters read into a String var is determined by the current size of the var. For example, to read a 5 character string into myString, you first need to initialize myString with 5 characters. I use: "myString = String(5, chr(0))", but any 5 characters will do.

Good Luck with your own versions of this concept.
Mike Scott, Canada


---------- [ THE CODE ] ---------------------

[color green]' Project: AddFiles.VB6
Option Explicit

Private Sub Form_Load()
Dim sFilesAdded As String
Dim outputFile As String

outputFile = App.Path & "\setup.exe"
Open outputFile For Binary As #1

Call appendFile("client.exe")
Call appendFile("admutil.dll")
Call appendFile("sample.dat")

Close #1
End Sub

Private Sub appendFile(filename As String)
Dim fileBuf As String
Dim filenameLen As Integer
Dim filesize As Long
Dim filePosition As Long
Dim footerIdent As String
Dim footerPosition As Long

footerIdent = "MIKES-FOOTER-IDENT"
filenameLen = Len(filename)
filePosition = LOF(1) + 1

'read in file to append, slurp into a String
Open App.Path & "\" & filename For Binary As #2
filesize = LOF(2)
fileBuf = String(filesize, Chr(0))
Get #2, 1, fileBuf
Close #2

' append the file
Put #1, filePosition, fileBuf

' write the footer record
footerPosition = filePosition + filesize
Put #1, , filenameLen
Put #1, , filename
Put #1, , filesize
Put #1, , filePosition
Put #1, , footerIdent
Put #1, , footerPosition
End Sub[/color]


---------- [ THE CODE ] ---------------------

[color green]
' Project: MyInstaller.VB6
' this is the routine you would call from the main()

Option Explicit
Const destDir = "C:\Program Files\myProgram"

Private Sub extractFiles()
Dim footerIdentPosition As Long
Dim inputFile As String
Dim footerIdentTag As String

Dim fileBuf As String
Dim filenameLen As Integer
Dim filename As String
Dim filesize As Long
Dim filePosition As Long
Dim footerIdent As String
Dim footerPosition As Long

footerIdentTag = "MIKES-FOOTER-IDENT"

inputFile = App.Path & "\" & App.EXEName & ".exe"
Open inputFile For Binary As #1

footerIdentPosition = LOF(1) - 21
footerIdent = footerIdentTag
Get #1, footerIdentPosition, footerIdent

Do While (footerIdent = footerIdentTag)

' read the file footer record
Get #1, , footerPosition
Get #1, footerPosition, filenameLen
filename = String(filenameLen, Chr(0))
Get #1, , filename
Get #1, , filesize
Get #1, , filePosition

' read the file
fileBuf = String(filesize, Chr(0))
Get #1, filePosition, fileBuf

' create the premanent file
Open destDir & "\" & filename For Binary As #2
Put #2, 1, fileBuf
Close #2

' check for next (earlier) file attachment
footerIdentPosition = filePosition - 22
Get #1, footerIdentPosition, footerIdent
Loop

Close #1 ' our input .EXE file
End Sub
[/color]
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top