i read that Purebasic allow you to create preprocessors, so here is my simple attempt, lol. Im really happy how easy it has made it to use plain strings in my source and encrypt them only at compiletime!

This is just a minimalist template.
Ive set my compiled preprocessor to be always on, but selectively activated from within my sourcecode if I simply type "#XSTR=1" near the top of my code.
When it detects #XSTR=1 it goes through the temporary copy of the source code its about to compile, and encrypts all XStr("") strings. In this demo to keep things basic, encryption is simply Chr+127, so we're just shifting the entire normal character set of 0-127 into the extended range of 128-255, making it look garbled under a hex editor in one quick swoop.
So a sample program might look like this:
Code: Select all
#XSTR=1
MessageRequester("Normal", XStr("Protected"),0)
Code: Select all
Procedure.s XStr(strbuf.s)
;-snip-...decrypt strbuf...
EndProcedure
MessageRequester("Normal", XStr("Ðòïôåãôåä"), 0)
The strings are only decrypted when they're accessed, so if you simply run the program and dump memory they should still be encrypted if you havent accessed them.
Here is XSTR.PB which is basically just the decryption code that the preprocessor string-replaces "#XSTR=1" with:
Code: Select all
CompilerIf #PB_Compiler_Unicode = 1
MessageRequester("PREPROCESSOR", "UNICODE NOT SUPPORTED",0)
End
CompilerEndIf
Procedure.s XStr(buf.s)
If Len(buf) = 0
ProcedureReturn
EndIf
Protected *pbyte.ASCII = @buf
For i.l = 1 To Len(buf)
*pbyte\a = *pbyte\a - 127 ;Decrypt
*pbyte + 1
Next i
ProcedureReturn buf
EndProcedure
Here is the PREPROCESSOR.PB. Compile it as an EXE in the same location as the XSTR.PB file
(this version doesnt support INCLUDEs. See next post for one that does)
Code: Select all
#XSTR=0 ;Tells the preprocessor (yes, this one!) to ignore this file.
Procedure EncStr(bufaddr.l, buflen.l)
If buflen = 0
ProcedureReturn
EndIf
Protected *pbyte.ASCII = bufaddr
For i.l = 1 To buflen
*pbyte\a = *pbyte\a + 127 ;Encrypt
*pbyte + 1
Next i
EndProcedure
;---------------------------------------------------------------------------------------------------------------------
If CountProgramParameters() = 0
MessageRequester("PreProcessor error", "No parameters!")
End
EndIf
;Parameter = temp copy of the source code that the compiler is about to compile
sFile.s = ProgramParameter(0)
sFile = RemoveString(sFile, Chr(34))
If ReadFile(0, sFile)
length = Lof(0) ; get the length of opened file
bytes.s = ReadString(0, #PB_UTF8 | #PB_File_IgnoreEOL, length)
CloseFile(0)
EndIf
;Check to see if the source file has been marked for preprocessing ... if not we'll simply exit (no preprocessing required)
If FindString(bytes,"#XSTR=0") <> 0 Or FindString(bytes,"#XSTR=1") = 0
End
EndIf
;Create a lowercase version of the source code so we can search case-insensitively
lbytes.s = LCase(bytes)
Repeat
i.l = FindString(lbytes, "xstr(", i+1)
If i = 0
Break
EndIf
i.l = FindString(lbytes, Chr(34), i)
i2.l = FindString(lbytes, Chr(34), i+1)
If i = 0 Or i2 = 0
Break
EndIf
;We've found an Xstr("") string... lets encrypt it
EncStr(@bytes + i, i2-i-1)
Until i = 0
XstrFile.s = GetPathPart(ProgramFilename()) + "\XSTR.PB"
lFilesize.l = FileSize(XstrFile)
If lFilesize = 0
MessageRequester("PreProcessor error", XstrFile + " filesize = 0",0)
End
EndIf
If ReadFile(0, XstrFile)
XStrFunc.s = ReadString(0, #PB_UTF8 | #PB_File_IgnoreEOL, lFilesize)
CloseFile(0)
EndIf
;Replace "#XSTR=1" with the actual decryption function
bytes = ReplaceString(bytes, "#XSTR=1", #CRLF$ + XStrFunc)
If Left(bytes,1) = Chr($3F) ;need to get rid of utf8 byte
bytes = Right(bytes, Len(bytes) - 1)
EndIf
;Save the modified temporary source file
DeleteFile(sFile)
OpenFile(0, sFile)
WriteData(0, @bytes, Len(bytes))
CloseFile(0)
TO INSTALL
1) Compile preprocessor as an EXE, and save it and XSTR.PB to the same location
2) In Purebasic go to Tools, then Configure Tools, and click New, and add the preprocessor Exe
3) Set the Arguments to: "%COMPILEFILE"
4) Give it a name, "XStr Preprocessor" or something, and check "Wait for tool to finish"
5) for Event To Trigger The Tool, set to "Before Compile/Run"
Now repeat steps 2 to 5, but set the second Event Trigger to "Before Create Executable"
That's all! You can choose to use it on a per-case basis, but I just always leave it enabled because it does nothing if you dont specify in your code you want it (which you do simply by specifying "#XSTR=1", and then simply add XStr("") around any strings you want to protect)

Does anyone have any similar preprocessors, or any tips to share about this? I searched the forums but couldnt find many
ps. When designing your encryption/obfuscation routine remember that (at least in this simple implementation that uses PB's ascii native null-terminated string type) we cannot encode any character to either Chr(0) null, or Chr(34) speechmark, and I'm pretty sure Chr(13) and Chr(10) would break it also due to becoming a new line. Remember the encrypted text still needs to read as valid text within valid code. All other characters should be safe to use, including ones that dont look valid in the IDE, because the IDE isn't a part of the compile chain in this sense.