I have an encryption program, and I would like to use it to encrypt certain executable files. Unfortunately, I get an error when I use and open statement to read the files. Why is this, and how do I get around it?
1) plese clarify what are you going to achieve.
Encrypted file would not be executable any more, wouldn't it?
2) Did you open it in binary mode? (AS BINARY)
3) What errormessage you get?
The file would not be executable until it is unencrypted. I did not try opening the file in binary mode, but I will try that. This happened awhile ago, so I don't remeber the error. I have come to the conclusion that it would not be practical to encrypt exe files with qbasic. It would be to slow to do it line by line. Thanks.
Do you really want to encrypt programs... or do you simply want to prevent the wrong people from using them? Your application can spend a great deal of time turning EXE machine code into an amorphous blob... but what will it really be hiding? Aside from the occasional string literal, EXE's contain very little readable text. They are, for the most part, amorphous blobs of unreadable code. On the other hand, certain disassemblers can read the machine code with ease. If you are worried that somebody might decompile your code, you can thwart most simple attempts by changing a few bytes in the EXE.
The sample code I listed below just toggles the usability of an EXE file. The first time it runs, it modifies the EXE so that it can't load into memory. The second time it runs, it restores the EXE's ability to load. This is accomplished by saving and restoring the PagesInExe field in the EXE file header.
You really don't need the following DosEXEfileHeader type declaration because the main function of this program can be accomplished by reading and writing two bytes from the correct locations in the EXE file. I've included the layout of the DOS EXE file header so you can see what's there (and to allow every novice programmer's god-given right to fiddle with settings they don't understand - how else are we going to learn?). Just keep in mind that changing anything other than the items this program modifies will crash the EXE (when you try to run it) and probably crash your system (depending on the OS).
[tt]
DEFINT A-Z
TYPE DosEXEfileHeader
Id AS STRING * 2
BytesInLastPage AS INTEGER
PagesInExe AS INTEGER
RelocationEntries AS INTEGER
ParagraphsInHeader AS INTEGER
MinimumExtraParagraphs AS INTEGER
MaximumExtraParagraphs AS INTEGER
InitialSS AS INTEGER
InitialSP AS INTEGER
CheckSum AS INTEGER
EntryPoint AS LONG
RelocationTableOffset AS INTEGER
OverlayNumber AS INTEGER
END TYPE
DIM DosEXEheader(0) AS DosEXEfileHeader 'Substitute the name of the EXE you are working with 'for the following EXE file name....
FiName$ = "qbexe.exe"
'...read the DOS EXE header...
ff = FREEFILE
OPEN FiName$ FOR BINARY AS #ff
GET #ff, 1, DosEXEheader(0)
'We're going to deal with the PagesInExe field in the EXE header...
'In order to keep the program from running we set it to a very unlikely value
'and the OS will refuse to load it into memory....
IF DosEXEheader(0).PagesInExe = 32767 THEN 'This EXE has aleady been modified...
DosEXEheader(0).PagesInExe = DosEXEheader(0).CheckSum '...so retrieve the value we saved in the CheckSum field 'and use it to restore PagesInExe to the correct value.
ELSE 'This EXE hasn't been modified yet... '...so save the PagesInExe value in an unused field 'so we can restore it later....
DosEXEheader(0).CheckSum = DosEXEheader(0).PagesInExe
DosEXEheader(0).PagesInExe = 32767
END IF 'Write the changes back to the EXE.
PUT #ff, 1, DosEXEheader(0)
[/tt]
...back to the problem of preventing a successful disassembly of your program... I think you will find that altering a few of the values in the EXE header will prevent most attempts to decompile. Disassemblers rely on the values in the EXE header to do their stuff.... If the values are wrong, they certainly can't do their stuff very well....
Ed Fair
Any advice I give is my best judgement based on my interpretation of the facts you supply. Help increase my knowledge by providing some feedback, good or bad, on any advice I have given.
Thank you Alt255. Your help was invaluable. Is there anyway that I could store a password in the exe file that my program could retrieve. The user would then have to enter that password so that my program would fix the file.
Sure.... but you probably don't want to actually save the password in the EXE. That would leave it somewhat vulnerable. It might be better to store a sort of "hash" value in the EXE. This is a series of characters generated at random, based on the value of the password. The password can't be retrieved from the hash value but whenever the user enters a password we can generate a new hash and compare it to the one stored in the EXE. If the new hash matches the stored hash, we can be reasonably certain that they were generated by the same password.
(The practicality of this scheme should be reviewed with Alt255's Uncertainty Principle in mind. I've tested Microsoft's random number generator using VB and found that certain random seeds will always generate the same series of random values: ie., 4 and 16387 will generate the same series of numbers, as do 5 and 20483, 6 and 24579, 7 and 28675, and so on.... QB doesn't seem to follow the same rules... but you might want to test the potential for generating identical hash values based on different passwords.... Especially if the results will determine whether or not NORAD launches its missles. Have fun with the following code. Just make sure you back up your EXEs before you modify them.)
[tt]
DEFINT A-Z
TYPE DosEXEfileHeader
Id AS STRING * 2
BytesInLastPage AS INTEGER
PagesInExe AS INTEGER
RelocationEntries AS INTEGER
ParagraphsInHeader AS INTEGER
MinimumExtraParagraphs AS INTEGER
MaximumExtraParagraphs AS INTEGER
InitialSS AS INTEGER
InitialSP AS INTEGER
CheckSum AS INTEGER
EntryPoint AS LONG
RelocationTableOffset AS INTEGER
OverlayNumber AS INTEGER
END TYPE
DIM DosEXEheader(0 TO 1) AS DosEXEfileHeader
CLS 'TEST.EXE will be the name of the file we want to work on.
FiName$ = "test.exe"
'...read the DOS EXE header...
ff = FREEFILE
OPEN FiName$ FOR BINARY AS #ff
GET #ff, 1, DosEXEheader(0) 'Check the size of the EXE based on the information stored in the header...
IF DosEXEheader(0).PagesInExe = 32767 THEN
MemPages = DosEXEheader(0).CheckSum
ELSE
MemPages = DosEXEheader(0).PagesInExe
END IF
FileSize& = MemPages * 512& - (512& - DosEXEheader(0).BytesInLastPage) 'Use LOF to check the actual size of the EXE...
IF LOF(ff) > FileSize& THEN 'The file is larger than the original file image, 'so it probably contains a password hash at the end.
Checkhash$ = STRING$(64, 1)
GET #ff, FileSize& + 1, Checkhash$
END IF
IF DosEXEheader(0).PagesInExe = 32767 THEN
Restart$ = "No"
MyPassword$ = "": Hash$ = ""
PassMessage$ = "Enter existing password:"
GOSUB GetPassword
IF LEN(MyPassword$) < 1 THEN
PRINT "Password required!"
SYSTEM
END IF
Pwd$ = MyPassword$
GOSUB MakeHashString
IF Hash$ <> Checkhash$ THEN
PRINT "Wrong Password!"
SYSTEM
END IF 'The password is correct, 'so restore the original values to the EXE header....
DosEXEheader(0).PagesInExe = DosEXEheader(0).CheckSum
ELSE
Restart$ = "Yes"
MyPassword$ = "": Hash$ = ""
PassMessage$ = "Enter new password for this EXE:"
GOSUB GetPassword
IF LEN(MyPassword$) < 1 THEN
PRINT "Password required!"
SYSTEM
END IF
Pwd$ = MyPassword$
GOSUB MakeHashString 'Store the hash string at the end of the EXE file...
PUT #ff, FileSize& + 1, Hash$
DosEXEheader(0).CheckSum = DosEXEheader(0).PagesInExe
DosEXEheader(0).PagesInExe = 32767
END IF 'Make the changes to the EXE header...
PUT #ff, 1, DosEXEheader(0)
CLOSE #ff
IF Restart$ = "Yes" THEN 'We have just added a password hash to the EXE, 'so restart the app so we can check the password 'and run the program.
RUN
END IF
'Run the program in a shell....
SHELL FiName$
'Finished running the program... 'so make that magical change in the EXE header that will 'prevent the wrong people from running it....
ff = FREEFILE
OPEN FiName$ FOR BINARY AS #ff
GET #ff, 1, DosEXEheader(0)
DosEXEheader(0).CheckSum = DosEXEheader(0).PagesInExe
DosEXEheader(0).PagesInExe = 32767
PUT #ff, 1, DosEXEheader(0)
CLOSE #ff
SYSTEM
GetPassword:
LOCATE 1, 1: PRINT PassMessage$
LOCATE 2, 1
Ink$ = ""
DO WHILE Ink$ <> CHR$(13)
DO WHILE Ink$ = ""
Ink$ = INKEY$
LOOP
IF Ink$ = CHR$(13) THEN EXIT DO
PRINT "*";
MyPassword$ = MyPassword$ + Ink$
Ink$ = ""
LOOP
RETURN
MakeHashString:
FOR re = 1 TO LEN(Pwd$)
Sum$ = Sum$ + RIGHT$("00" + LTRIM$(STR$(ASC(MID$(Pwd$, re, 1)) - 27)), 2)
NEXT
RndKey# = VAL(Sum$) 'You would use this statement in VB: Tmp = RND(-1)
RANDOMIZE RndKey 'Create a hash string 64 characters long from "random" values.
StartChar = 37
EndChar = 255
Hash$ = ""
FOR re = 1 TO 64
Hash$ = Hash$ + CHR$(INT((EndChar - StartChar + 1) * RND + StartChar))
NEXT
RETURN
[/tt]
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.