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]
Real men don't use Interrupt 21h.