Append text to exe then read it
Append text to exe then read it
I was wondering if someone could tell me how to bind text to an exe then let the program read itself and get the text. See i'm creating a very small interpreter and need to be a ble to create standalone exe's
If someone has a better method please tell me
If someone has a better method please tell me
1. Create your EXE
2. Write a utility that makes a copy of your EXE, adds your text/data and a long (or byte or whatever) which contains the length of the text/data. (textsize)
3. In your original EXE PB code, open the EXE file and read the last 4 bytes (if you used a long) to get the text size. Use Fseek()
4. Fseek(filelength-textlength-4) and read in the text/data.
Hope this helps.
2. Write a utility that makes a copy of your EXE, adds your text/data and a long (or byte or whatever) which contains the length of the text/data. (textsize)
3. In your original EXE PB code, open the EXE file and read the last 4 bytes (if you used a long) to get the text size. Use Fseek()
4. Fseek(filelength-textlength-4) and read in the text/data.
Hope this helps.
Save the following file as program.pb and compile it to program.exe. Don't run it just yet
Save the following listing as append.pb and compile to append.exe. Launch the append exe and a new exe will be created called output.exe. Make sure both program.exe and append.exe are in the same directory. Output.exe is a copy of program.exe with the message appended to it, plus a 4 byte long describing it's length.
When you launch output.exe it should display the appended message. I wrote this code very late at night so please excuse any errors.
This code only works with a single line message (ending with CRLF). It would need to be enhanced to support multi-line strings or memory buffers. It's just a starting point.
Code: Select all
; program.pb
; EXE Message Extractor by Griz Oct 2004
; API Call to get EXE Name
Procedure.s GetExeName()
sApp.s=Space(256)
GetModuleFileName_(GetModuleHandle_(0), @sApp, 256)
ProcedureReturn sApp
EndProcedure
; read last 4 bytes of exe as a long to determine how large
; the appended message is, and then retrieve it.
Procedure GetExeData()
pfile.s=getexename()
psize=FileSize(pfile)
infile=ReadFile(#pb_any, pfile)
If infile
FileSeek(psize-4)
msize=ReadLong()
FileSeek(psize-4-msize)
message.s=ReadString()
MessageRequester("Success!", message)
CloseFile(infile)
ProcedureReturn 1
Else
MessageRequester("Error", "Can't open "+pfile)
ProcedureReturn 0
EndIf
EndProcedure
getexedata()
Code: Select all
; append.pb
; EXE Message Appender by Griz Oct 2004
Global exein.s, exeout.s, messageout.s
exein="program.exe" ; this is the source program file
exeout="output.exe" ; this is the output exe filename
messageout="Made with PURE BASIC!" ; the message to append
; API Call to get EXE Name
Procedure.s GetExeName()
sApp.s=Space(256)
GetModuleFileName_(GetModuleHandle_(0), @sApp, 256)
ProcedureReturn sApp
EndProcedure
; Append a string to the end of an EXE + 4 byte long for size
Procedure PutExeData(pfile.s, message.s)
; add a cr+lf to identify end of string if required
If FindString(message,Chr(13),1)=0
message+Chr(13)+Chr(10)
EndIf
psize=FileSize(pfile)
If psize>0
; delete old output exe file if one exists
DeleteFile(GetPathPart(pfile)+exeout)
; make a copy of the original exe
If CopyFile(pfile,GetPathPart(pfile)+exeout)
infile=OpenFile(#pb_any, exeout)
If infile
FileSeek(psize)
WriteString(message) ; add the message
WriteLong(Len(message)) ; last 4 bytes (long) = the length of message
MessageRequester("Status", "Message appended to EXE!")
CloseFile(infile)
ProcedureReturn 1
Else
MessageRequester("Error", "Can't open "+exeout)
ProcedureReturn 0
EndIf
Else
MessageRequester("Error", "Can't copy "+pfile)
ProcedureReturn 0
EndIf
Else
MessageRequester("Error", "Can't open "+pfile)
ProcedureReturn 0
EndIf
EndProcedure
PutExeData(GetPathPart(getexename())+exein,messageout)
This code only works with a single line message (ending with CRLF). It would need to be enhanced to support multi-line strings or memory buffers. It's just a starting point.
Last edited by griz on Sun Oct 24, 2004 7:17 pm, edited 1 time in total.
-
- Enthusiast
- Posts: 781
- Joined: Fri Apr 25, 2003 6:51 pm
- Location: NC, USA
- Contact:
Something like this might do what you want easier.
Code: Select all
TextString.s
Restore NextLabel:
Read TextString
MessageRequester("Example","The last embedded text is: " + Chr(10) + TextString,0)
TextString = ""
Restore TextLabel:
Read TextString
MessageRequester("Example","The first embedded text is: " + Chr(10) + TextString,0)
DataSection
TextLabel:
IncludeBinary "C:\Autoexec.bat"
Data.s "" ; Make sure we have a nul to stop the string read
NextLabel:
IncludeBinary "C:\Purebasic\Beta-R~1.txt"
Data.s "" ; Make sure we have a nul to stop the string read
EndDataSection
Maybe another suitable approach to this is to use ADS streams.
First some links:
Streams overview http://lists.gpick.com/pages/NTFS_Alter ... treams.htm
StreamsExplorer Utility http://www.rekenwonder.com/streamexplorer.htm
Purebasic Code by Rings http://www.robsite.de/php/pureboard/vie ... ht=streams
Code by Rings very slightly adopted:
Test if it worked
Works also if streams.exe is still in memory. 
First some links:
Streams overview http://lists.gpick.com/pages/NTFS_Alter ... treams.htm
StreamsExplorer Utility http://www.rekenwonder.com/streamexplorer.htm
Purebasic Code by Rings http://www.robsite.de/php/pureboard/vie ... ht=streams
Code by Rings very slightly adopted:
Code: Select all
;1. Compile this program to C:\Streams.exe and run it
;2. Use the StreamsExplorer or the second snippet to check the results
FILENAME.s="C:\streams.exe"
Filetoadd.s=":testme.txt"
F.s=FILENAME+Filetoadd
If CreateFile(1,F)
Debug "yes"
WriteStringN("Test me")
CloseFile(1)
If ReadFile(1,F)
nop.s=ReadString()
Debug nop.s
CloseFile(1)
EndIf
EndIf
Code: Select all
;run this after compiling and executing streams.exe
;leave the debugger enabled
FILENAME.s="C:\streams.exe"
Filetoadd.s=":testme.txt"
F.s=FILENAME+Filetoadd
If ReadFile(1,F)
nop.s=ReadString()
Debug nop.s
CloseFile(1)
EndIf

Hi guys,
I've added to my code above so it now supports any file to be attached as a data stub to an EXE. As well, it supports packing and RC4 encryption. I haven't tested it much but it has worked for me on several attempts.
newcoder : I think you would appreciate packing and encryption on the program listings you intend to imbed on your interpreter runtime exe.
terryhough : I believe newcoder wanted to attach a data stub to an existing EXE rather than creating it in the PB IDE as you suggest.
Geotrail : thanks!
Max2 : ADS streams look interesting! Maybe I re-invent the wheel too much?
append.pb is a simple, generic utility that allows you to attach a data stub to any executable. The data stub can be a text file or any binary file.
program.pb demonstrates accessing the data stub that append.pb added to the exe. This demonstration will show the
first 512 bytes of a text file, but it should work on binary files too.
I've added to my code above so it now supports any file to be attached as a data stub to an EXE. As well, it supports packing and RC4 encryption. I haven't tested it much but it has worked for me on several attempts.
newcoder : I think you would appreciate packing and encryption on the program listings you intend to imbed on your interpreter runtime exe.
terryhough : I believe newcoder wanted to attach a data stub to an existing EXE rather than creating it in the PB IDE as you suggest.
Geotrail : thanks!
Max2 : ADS streams look interesting! Maybe I re-invent the wheel too much?
append.pb is a simple, generic utility that allows you to attach a data stub to any executable. The data stub can be a text file or any binary file.
Code: Select all
; ... EXE Data Stub Appender 0.1d by Griz October 2004 ...
; Appends a data stub to EXE : exe+data+packedsize(long)+unpackedsize(long)
Global datafile.s : datafile=""
Global exein.s : exein=""
Global exeout.s : exeout=""
Global messageout.s : messageout=""
Global password.s : password=""
Global originalsize
Procedure Mod(a,b)
ProcedureReturn a-(a/b)*b
EndProcedure
; RC4 from Pille / Rings
Procedure.l RC4Mem(Mem.l, memLen.l, Key.s)
Dim S.w(255)
Dim K.w(255)
i.l=0: j.l=0: t.l=0: x.l=0
temp.w=0: Y.w=0
Outp.s=""
For i = 0 To 255
S(i) = i
Next
j = 1
For i = 0 To 255
If j > Len(key)
j = 1
EndIf
K(i) = Asc(Mid(key, j, 1))
j = j + 1
Next i
j = 0
For i = 0 To 255
j = Mod(j + S(i) + K(i), 256)
temp = S(i)
S(i) = S(j)
S(j) = temp
Next i
i = 0
j = 0
For x = 0 To memLen-1
i = Mod(i + 1, 256)
j = Mod(j + S(i),256)
temp = S(i)
S(i) = S(j)
S(j) = temp
t = Mod(S(i) + Mod(S(j), 256) , 256)
Y = S(t)
PokeB(Mem+x, PeekB(Mem+x)!Y)
Next
ProcedureReturn Mem
EndProcedure
MessageRequester("Appender","version 0.1d by Griz",#PB_MessageRequester_Ok)
exein=OpenFileRequester("Choose Source EXE", "", "Executable (*.exe)|*.exe|All files (*.*)|*.*" , 0)
If exein
datafile=OpenFileRequester("Choose Source Data File", "", "Text (*.txt)|*.txt;*.bat|All files (*.*)|*.*" , 0)
If datafile
exeout=SaveFileRequester("Filename for output EXE", "", "Executable (*.exe)|*.exe;*.bat|All files (*.*)|*.*" , 0)
If exeout
password.s=InputRequester("RC4 Encryption","Please enter a password :","test123")
If ReadFile(0, datafile)
FileLength = Lof()
source=AllocateMemory(FileLength)
If filelength And source
; read data stub into memory
ReadData(source,filelength)
; pack the data
originalsize=filelength
sourcetemp=AllocateMemory(filelength+8)
If sourcetemp
f=PackMemory(source,sourcetemp,filelength)
FreeMemory(source)
source=AllocateMemory(f)
CopyMemory(sourcetemp,source,f)
FreeMemory(sourcetemp)
filelength=f
; read the exe into memory
If ReadFile(1,exein)
exefilelength=Lof()
destination=AllocateMemory(filelength+exefilelength+4+4)
If destination
ReadData(destination,exefilelength)
CopyMemory(source,destination+exefilelength,filelength)
; size of data (packed)
PokeL(destination+exefilelength+filelength,filelength)
; size of data (unpacked)
PokeL(destination+exefilelength+filelength+4,originalsize)
; encrypt the data stub
rc4mem(destination+exefilelength,filelength,password)
; write the destination exe
If OpenFile(2,exeout)
WriteData(destination,exefilelength+filelength+4+4)
MessageRequester("Success!", "EXE Generated")
EndIf
FreeMemory(destination)
EndIf
EndIf
EndIf
FreeMemory(source)
EndIf
CloseFile(0)
EndIf
EndIf
EndIf
EndIf
End
first 512 bytes of a text file, but it should work on binary files too.
Code: Select all
; .. EXE Data Stub Decoder 0.1d by Griz October 2004 ..
; Read the last 4 bytes (long) as Data size then
; Read the data stub appended to end of the EXE
Global password.s : password="test123" ; rc4 password
Global originalsize
; API Call to get EXE Name
Procedure.s GetExeName()
sApp.s=Space(256)
GetModuleFileName_(GetModuleHandle_(0), @sApp, 256)
ProcedureReturn sApp
EndProcedure
Procedure Mod(a,b)
ProcedureReturn a-(a/b)*b
EndProcedure
; RC4 from Pille / Rings
Procedure.l RC4Mem(Mem.l, memLen.l, Key.s)
Dim S.w(255)
Dim K.w(255)
i.l=0: j.l=0: t.l=0: x.l=0
temp.w=0: Y.w=0
Outp.s=""
For i = 0 To 255
S(i) = i
Next
j = 1
For i = 0 To 255
If j > Len(key)
j = 1
EndIf
K(i) = Asc(Mid(key, j, 1))
j = j + 1
Next i
j = 0
For i = 0 To 255
j = Mod(j + S(i) + K(i), 256)
temp = S(i)
S(i) = S(j)
S(j) = temp
Next i
i = 0
j = 0
For x = 0 To memLen-1
i = Mod(i + 1, 256)
j = Mod(j + S(i),256)
temp = S(i)
S(i) = S(j)
S(j) = temp
t = Mod(S(i) + Mod(S(j), 256) , 256)
Y = S(t)
PokeB(Mem+x, PeekB(Mem+x)!Y)
Next
ProcedureReturn Mem
EndProcedure
Procedure GetExeData()
pfile.s=getexename()
psize=FileSize(pfile)
infile=ReadFile(#pb_any, pfile)
If infile
; read packed size of data stub
FileSeek(psize-8)
msize=ReadLong()
; read unpacked size of data stub
FileSeek(psize-4)
originalsize=ReadLong()
FileSeek(psize-8-msize)
source=AllocateMemory(msize)
If source
; read data stub into memory buffer
ReadData(source,msize)
; decrypt the data stub
rc4mem(source,msize,password)
; unpack the data stub
sourcetemp=AllocateMemory(originalsize)
If sourcetemp
UnpackMemory(source,sourcetemp)
FreeMemory(source)
source=AllocateMemory(originalsize)
CopyMemory(sourcetemp,source,originalsize)
FreeMemory(sourcetemp)
; ----------------------------------------
; data is now contained in 'source' memory bank
; below we simply capture it all as a string (for example)
d$=PeekS(source,originalsize)
If Len(d$)>512 ; only show the first 100 characters in messagebox
d$=Left(d$,512)+" <more...>"
EndIf
MessageRequester("Success!", "data size ="+Str(msize)+"/"+Str(originalsize)+Chr(13)+Chr(10)+Chr(13)+Chr(10)+d$)
FreeMemory(source)
; ----------------------------------------
EndIf
EndIf
CloseFile(infile)
EndIf
EndProcedure
getexedata()
Wow griz you are a great programmer, Actually the same day you posted that code I managed to get a very very very simple interpreter going. It was meant to be simple batch language replacement for my own use.
The thing about it thanks to PureBasic and your tight code, the runtime is only 10 kb.
It has Commands like MoveFile ,Run , CopyFile, just simple functions. But I have plans for another interpreter that is actually useful. Its going to be a console mode interpeter. That is designed to create real small exe's.
Thank you Griz and Fred! for purebasic
The thing about it thanks to PureBasic and your tight code, the runtime is only 10 kb.
It has Commands like MoveFile ,Run , CopyFile, just simple functions. But I have plans for another interpreter that is actually useful. Its going to be a console mode interpeter. That is designed to create real small exe's.
Thank you Griz and Fred! for purebasic
-
- Addict
- Posts: 1264
- Joined: Wed Feb 28, 2007 9:13 am
- Location: London
Hi,
I'm trying to do exactly what the OP was trying to do.
I've made an app using Griz's code but the exe's it produces don't work. When you run them, they give this error:
Multimedia Player
Corrupted Stand Alone File (1)
"Multimedia Player" is probably to do with the input exe, which was made with Multimedia Builder.
The problem may be that (I think) Griz's code is not PB 4.0 compliant. I got a few debugging messages with the Lof, ReadData and WriteData lines, so I added the 1 and 0 as I thought appropriate. For example, I changed:
Can anyone help?
Thanks in advance,
Seymour.
I'm trying to do exactly what the OP was trying to do.
I've made an app using Griz's code but the exe's it produces don't work. When you run them, they give this error:
Multimedia Player
Corrupted Stand Alone File (1)
"Multimedia Player" is probably to do with the input exe, which was made with Multimedia Builder.
The problem may be that (I think) Griz's code is not PB 4.0 compliant. I got a few debugging messages with the Lof, ReadData and WriteData lines, so I added the 1 and 0 as I thought appropriate. For example, I changed:
to:If OpenFile(2,exeout)
WriteData(destination,exefilelength+filelength+4+4)
MessageRequester("Success!", "EXE Generated")
EndIf
I also tried it this way:If OpenFile(2,exeout)
WriteData(destination,2,exefilelength+filelength+4+4)
MessageRequester("Success!", "EXE Generated")
EndIf
but the result is the same.If OpenFile(2,exeout)
WriteData(2,destination,exefilelength+filelength+4+4)
MessageRequester("Success!", "EXE Generated")
EndIf
Can anyone help?
Thanks in advance,
Seymour.