Dennis
Full Member
Old but still active
Posts: 147
|
Post by Dennis on Sept 1, 2021 16:59:31 GMT -5
I need to copy protect my software. Has anybody out there done it or is doing it? I have tried a number of commercially available systems which all wrap the EXE hence my need for LB to create an EXE. I succesfully used different copy protection software systems to copy protect (wrap) LB EXE's. But when I attempt to run the protected EXE, I get a Smalltalk compiler memory error. This error occurs irrespective of the Windows version or different computer tried. Does anybody know of a software protection system compatible with LB source code or EXE. Systems that I have already tried are: PELock,Obsidium, ElecKey, ASProtect 32 (amongs others). Thanks
|
|
|
Post by Chris Iverson on Sept 1, 2021 17:25:58 GMT -5
I bet I know why they don't work; they don't preserve the original EXE well enough.
I'm honestly curious how those EXE packers do their work.
You might be able to get it to work if you get one of those wrappers that wraps all the files up into one EXE first, and protect that, but I'm not sure.
Unfortunately, I've not done much work with copy protection programs, so I don't really have a recommendation.
Random technical info below:
I suspect the reason why it doesn't work for LB executables is the way that Visual Smalltalk(the programming language LB itself is written in) embeds the compiled code for your program to run in its runtime(in this case, LB itself, or the LB JIT) in the EXE as a non-standard section called ".vimage". The Smalltalk engine loads this into memory, and starts executing it as Smalltalk code.
Here's the sections from LB's EXE:
Summary
10000 .bss 10000 .data 10000 .idata 10000 .rdata 10000 .reloc 10000 .rsrc 10000 .text 1E0000 .vimage
Most of those are standard, and you'll find them(or similar ones) in every EXE program.
"vimage" is not standard, and something that's manipulating PE-format files(that is, EXE files) might be choking on it. It's not invalid, but it's not expected, either.
Here's the same listing of the LB exe, after protecting it with PELock Demo:
Summary
30000 .bss 10000 .bss 1F0000 .bss 180000 .rdata 10000 .rsrc 10000 .text
Notice that the "vimage" section is gone?
Now, I suspect that the vimage data is still there, but the Smalltalk engine can no longer find it, and therefore, it technically has nothing to run.
|
|
Dennis
Full Member
Old but still active
Posts: 147
|
Post by Dennis on Sept 2, 2021 2:08:26 GMT -5
Ahhh thanks Chris - you've cleared up what I assumed might be happening.
When I spoke to the companies PELock etc., most pointed to the .EXE as being the issue. What you have established is just that.
PELock looked the most promising solution but as you have shown, it won't work with LB generated EXEs and nor will the others that wrap the EXE. Most of the available "wrap" type solutions do not have "tweaking" options to try and control how they modify EXEs but I will recheck...
I will also approach the PELock developer with what you have pointed out and will see what he has to say.
Don't other developers using LB protect their software if they make it available for commercial use?
Thanks for your efforts and for confirming what I have been told. If PELock cannot resolve the issue then I will have to look for another solution to protecting my software.
|
|
|
Post by Chris Iverson on Sept 2, 2021 2:43:57 GMT -5
When I said "wrapper", I was referring to some types of programs that take all the files your program depends on(EXE, DLLs, images, etc.) and wraps them up into one single EXE file. When you run that, it unpacks the program files into a temporary folder, and runs the real program. I know some have been used with LB in the past with success, but I no longer recall the names of them. Depending on how the wrapper worked, it might still function after being "protected", and the original LB EXE is untouched. Not sure, though. As for protecting their software, other developers have generally implemented their own methods of enforcing licensing or copy protection. I actually posted one method myself, here: libertybasiccom.proboards.com/thread/1253/public-key-based-license-systemYou can utilize that method, along with something unique to the computer it's intended to be installed on, to lock the license to that machine. The example I give is a program that the company I work for uses; part of the license includes the IP address of the server it's hosted on. By including that, the server won't run on any system that doesn't have that IP address.
|
|
Dennis
Full Member
Old but still active
Posts: 147
|
Post by Dennis on Sept 2, 2021 3:36:48 GMT -5
Thanks Chris - much appreciated. I will look at your system although I need to try and steer away from having an Internet connection because of the unique environment that I am targeting.
Probably some sort of hardware "tie-in" might be the way to go.
I contacted the developer of PELock with the info you gave and I am still awaiting for a reply.
|
|
|
Post by Rod on Sept 2, 2021 3:46:02 GMT -5
I believe there is a way to tie the programs to the USB Stick they ship with. If I recall each stick has a unique id that can be checked via an api call and cannot be copied stick to stick.
|
|
Dennis
Full Member
Old but still active
Posts: 147
|
Post by Dennis on Sept 2, 2021 3:50:41 GMT -5
Thanks Rod, I will research that. In my case, it is a good idea to use the USB rather than the machine the client is using. Do you know if a special API is required?
To Chris... My WIN 10 blocks the libsodium.dll download as "blocked - could harm your computer" so going to try to create my own copy protection method along the "hardware" tie-in approach.
|
|
|
Post by Rod on Sept 2, 2021 3:54:35 GMT -5
From John's site. Needs more research and experimentation, perhaps someone who has done it before can chip in.
open "HardwareIDExtractorC.dll" for dll as #id CallDLL #id, "GetIDESerialNumber", DriveNumber as long, ret as ulong print winstring(ret) close #id
|
|
Dennis
Full Member
Old but still active
Posts: 147
|
Post by Dennis on Sept 2, 2021 4:16:02 GMT -5
Thanks Rod!! I downloaded the zipped file from John's site but have not taken a closer look at what is on it. I will do so now. I researched the USB flash drive unique id suggestion. Apparantly not all drives have a unique id and you can manipulate the id on some of them I will research further. Thanks!! You and Chris have got me moving in the right direction (I hope)
|
|
Dennis
Full Member
Old but still active
Posts: 147
|
Post by Dennis on Sept 2, 2021 8:29:53 GMT -5
OK, this is where I am at. I downloaded the zipped file from John's site and ran it. It worked, but the DLL came up with a lot of "nag" messages because it is an unregistered product. I found my way to the developer's site for the DLL (soft.tahionic.com) and purchased the latest version of the DLL etc. They sent me a set of instructions on how to activate the DLL to stop the "nag" messages. It's quite simple. All that needs to happen is to first call the DLL (after opening it) with the given key and and all subsequent calls then work cleanly i.e., no "nagging". The problem is that I am struggling to call the EnterKey function as the details for the call are given in C and Pascal and I cannot understand them. I have tried using a sub, function, etc. with and without parameters but no joy. I am too dumb to work the call out looking at the LB demo program from John and supplied by the developer. Can anybody make sense of the instructions and show me what the call should look like? Any help appreciated! Here are the instructions sent to me....
How to activate the DLL ============================ Download the demo DLL from our web site. This DLL will generate a nag message box at random intervals, if you use it as unregistered user. To switch the DLL from demo mode to registered mode, please call the EnterKey function with the number 222222222 as parameter, when you initialize your application. Please check the result of the function before you continue the execution of your program! The Key function is declared like this: function EnterKey(Value: integer): boolean; stdcall; external 'HardwareIDExtractor.DLL'; How to use it: *Example Pascal: procedure TForm1.FormCreate(Sender: TObject); begin if not EnterKey(222222222) then MessageDialog('Invalid key'); end; *Example C: function AppInitialize() { EnterKey(222222222) }
|
|
|
Post by Walt Decker on Sept 2, 2021 17:26:50 GMT -5
If this: HardwareIDExtractor.DLL
is the name of the dll then I suspicion that this might work:
OPEN "'HardwareIDExtractor.DLL" FOR DLL AS #HIDEX
CALLDLL #HIDEX, "EnterKey", 222222222 AS ULONG, RetVal AS LONG IF RetVal = 0 THEN PRINT "FUNCTION FAILED"
|
|
|
Post by Chris Iverson on Sept 2, 2021 18:19:39 GMT -5
You can also try to download libsodium from the official website. download.libsodium.org/libsodium/releases/libsodium-1.0.18-stable-msvc.zipGetting a warning for it is just obnoxious, considering many high-profile applications(including web browsers!) use libsodium internally. I chose the method I did so that only you would be able to generate new licenses. Depending on how you verify licenses, you may wind up with others being able to make a keygen. Using a public-key-crypto based system means others would only be able to generate valid licenses if they somehow steal your encryption key.
|
|
Dennis
Full Member
Old but still active
Posts: 147
|
Post by Dennis on Sept 2, 2021 23:31:12 GMT -5
Thanks Walt. Will give it a try. I tried something similar but used boolean as the "RetVal"
Thanks Chris, I will download the zip..
I get "block" messages for almost all DLL and CHM files. If they are in a zipped file then they get through...
****EDIT*** It did not work Walt, I tried variations as well. Made the key a variable, retval boolean, etc. - keep getting your "FUNCTION FAILED" message. I have also had no answers from the developer so I think I have been had. According to the website, a member of this forum, Stefan Pendl, did the conversion to LB. I don't think he has seen this thread. Perhaps he can help?
|
|
|
Post by Brandon Parker on Sept 3, 2021 13:10:00 GMT -5
Dennis, If you do not get it working, you can take a look at this bit of code below. It should search for the specified USB ID stored in myKey$. You will obviously have to get the ID first...
Also, in the CurrentUserName$() function you can change or omit this line if you wish...
CurrentUserName$ = "A Default Name Here"
If you wish to store the ID within and retrieve it from the LB Runtime Engine using my functions just let me know and I can post them as well. Obviously, no security method is 100% effective, but at if you encrypt the ID, store it in the LB Runtime Engine, and then check against that immediately after your program starts it will offer a more solid and obfuscated solution which makes it just a little more painful for someone to work around.
'Created by Brandon R. Parker 'Credit in your program would be sufficient for allowed use
Global True : True = 1 Global False : False = 0 Global CRLF$ : CRLF$ = chr$(13) + chr$(10)
'Need to Encrypt this to the end of the EXE and then retrieve it to check 'Yes, you can embed information at the end of LB's runtime engine. I have some functions 'that handle this fairly well 'You need to run the CreatePNPDeviceIDDAT() function and get the ID of the USB you want to tie to 'Then, you just place that ID below as a string; encrypting it first would be best, but your program 'would have to decrypt it after retrieving it from wherever you store it to check it Global myKey$ : myKey$ = "This is the key that is associated with the USB Drive"
DefaultDir$ = DefaultDir$ + " ." DefaultDir$ = ReplaceString$(1, DefaultDir$, "\ ./\ .", "", "/\", True)
'Create the Generic Size Struct Struct Size, value As long
Dim Info$(0, 0)
'Returns 1 if key is installed or the timeOutMS value if the code failed or a timeout occurs Print USBKeyInstalled(myKey$, CurrentComputerName$(), 5000)
End
Function USBKeyInstalled(myKey$, ComputerName$, timeOutMS) IDDAT = CreatePNPDeviceIDDAT(ComputerName$, timeOutMS) If Not(IDDAT) Then USBKeyInstalled = timeOutMS : Exit Function If fileExists(DefaultDir$ + "\", ComputerName$ + "PNPDeviceIDDAT.bat") Then result = destroyFile(DefaultDir$ + "\" + ComputerName$ + "PNPDeviceIDDAT.bat") startTime = Time$("ms") Do Scan If Time$("ms") >= (startTime + timeOutMS) Then USBKeyInstalled = timeOutMS : Exit Function result = Sleep(1500) Loop Until fileExists(DefaultDir$ + "\", ComputerName$ + "PNPDeviceIDDAT.txt") keySerial$ = ReplaceString$(1, OpenFile$(DefaultDir$ + "\" + ComputerName$ + "PNPDeviceIDDAT.txt", "Input", ""), chr$(0), "", "", True) If fileExists(DefaultDir$ + "\", ComputerName$ + "PNPDeviceIDDAT.txt") Then result = destroyFile(DefaultDir$ + "\" + ComputerName$ + "PNPDeviceIDDAT.txt") While Word$(keySerial$, (i + 1), CRLF$) <> "" If Word$(Word$(keySerial$, (i + 1), CRLF$), 1, "\") = "USBSTOR" Then If Trim$(Word$(Word$(keySerial$, (i + 1), CRLF$), 3, "\")) = myKey$ Then USBKeyInstalled = True : Exit While End If i = (i + 1) Wend End Function
'_________________________________________________________________________________________________________________________________________________________ '_________________________________________________________________________________________________________________________________________________________
Function CreatePNPDeviceIDDAT(ComputerName$, timeOutMS) result$ = OpenFile$(DefaultDir$ + "\" + ComputerName$ + "PNPDeviceIDDAT.bat", "Output", "wmic diskdrive get PNPDeviceID > " + _ chr$(34) + DefaultDir$ + "\" + ComputerName$ + "PNPDeviceIDDAT.txt" + chr$(34)) startTime = Time$("ms") Do Scan If Time$("ms") >= (startTime + timeOutMS) Then Exit Function result = Sleep(1) Loop Until fileExists(DefaultDir$ + "\", ComputerName$ + "PNPDeviceIDDAT.bat") 'Run DefaultDir$ + "\" + ComputerName$ + "PNPDeviceIDDAT.bat", HIDE result = ShellExecute(0, "Open", chr$(34) + DefaultDir$ + "\" + ComputerName$ + "PNPDeviceIDDAT.bat" + chr$(34), _ "", chr$(34) + DefaultDir$ + chr$(34), _SW_HIDE) result = Sleep(1000) CreatePNPDeviceIDDAT = True End Function
'_________________________________________________________________________________________________________________________________________________________ '_________________________________________________________________________________________________________________________________________________________
Function destroyFile(file$) On Error GoTo [Error] Kill file$ destroyFile = True [Error] End Function
'_________________________________________________________________________________________________________________________________________________________ '_________________________________________________________________________________________________________________________________________________________
Function OpenFile$(filepath$, InOut$, data$) If InOut$ = "Input" Then Open filepath$ For Input As #OpenFile OpenFile$ = Trim$(Input$(#OpenFile, LOF(#OpenFile))) Else If InOut$ = "Output" Then Open filepath$ For Output As #OpenFile End If If InOut$ = "Append" Then Open filepath$ For Append As #OpenFile End If #OpenFile data$ OpenFile$ = str$(True) End If Close #OpenFile End Function
'_________________________________________________________________________________________________________________________________________________________ '_________________________________________________________________________________________________________________________________________________________
Function Sleep(milliseconds) CallDLL #kernel32, "Sleep", milliseconds As ulong, Sleep As void End Function
'_________________________________________________________________________________________________________________________________________________________ '_________________________________________________________________________________________________________________________________________________________
Function fileExists(path$, filename$) Files path$, filename$, Info$() fileExists = Val(Info$(0, 0)) ReDim Info$(0, 0) End Function
'_________________________________________________________________________________________________________________________________________________________ '_________________________________________________________________________________________________________________________________________________________
Function ReplaceString$(startpos, ReplaceString$, searchfor$, replacewith$, delim$, conditional) If Not(conditional) Then Exit Function 'searchfor$/ replacewith$ can now be multiple items, but should be matched pairs 'if not then any remaing replaces will be with a NULL string searchForMe$ = searchfor$ : replacewithMe$ = replacewith$ If searchfor$ <> " " Then searchForMe$ = Word$(searchfor$, (myWord + 1), delim$) replacewithMe$ = Word$(replacewith$, (myWord + 1), delim$) End If Do While searchForMe$ <> "" 'ReplaceString$ = "" foundPosition = Instr(ReplaceString$, searchForMe$, startpos) If foundPosition Then Do While (foundPosition <> _NULL) ReplaceString$ = Left$(ReplaceString$, (foundPosition - 1)) + replacewithMe$ + _ Mid$(ReplaceString$, (foundPosition + Len(searchForMe$))) foundPosition = Instr(ReplaceString$, searchForMe$, (foundPosition + Len(replacewithMe$))) Loop End If myWord = (myWord + 1) ': string$ = ReplaceString$ searchForMe$ = Word$(searchfor$, (myWord + 1), delim$) replacewithMe$ = Word$(replacewith$, (myWord + 1), delim$) Loop End Function
'_________________________________________________________________________________________________________________________________________________________ '_________________________________________________________________________________________________________________________________________________________
Function ShellExecute(hWnd, lpOperation$, lpFile$, lpParameters$, lpDirectory$, nShowCmd) lpOperation$ = lpOperation$ + chr$(0) : lpFile$ = lpFile$ + chr$(0) lpParameters$ = lpParameters$ + chr$(0) : lpDirectory$ = lpDirectory$ + chr$(0) CallDLL #shell32, "ShellExecuteA", hWnd As ulong, _ lpOperation$ As ptr, _ lpFile$ As ptr, _ lpParameters$ As ptr, _ lpDirectory$ As ptr, _ nShowCmd As long, _ ShellExecute As ulong End Function
'_________________________________________________________________________________________________________________________________________________________ '_________________________________________________________________________________________________________________________________________________________
Function CurrentUserName$() lpBuffer$ = Space$(_MAX_PATH) + chr$(0) Size.value.struct = Len(lpBuffer$)
Open "advapi32.dll" For DLL As #ADVAPI32 CallDLL #ADVAPI32, "GetUserNameA", lpBuffer$ As ptr, _ Size As Struct, _ result As long Close #ADVAPI32
If result Then CurrentUserName$ = Trim$(Left$(lpBuffer$, Size.value.struct)) Else CurrentUserName$ = "A Default Name Here" End If End Function
'_________________________________________________________________________________________________________________________________________________________ '_________________________________________________________________________________________________________________________________________________________
Function CurrentComputerName$() lpBuffer$ = Space$(_MAX_PATH) + chr$(0) Size.value.struct = Len(lpBuffer$)
CallDLL #kernel32, "GetComputerNameA", lpBuffer$ As ptr, _ Size As Struct, _ result As long CurrentComputerName$ = Trim$(Left$(lpBuffer$, Size.value.struct)) End Function
{:0)
Brandon Parker
|
|
Dennis
Full Member
Old but still active
Posts: 147
|
Post by Dennis on Sept 3, 2021 14:52:47 GMT -5
Thanks Brandon! I really appreciate this. I will work through it and see if I can understand what it is doing.. I'm really desperate at the moment and have even resorted to running .bat files to pipe wmic results to the clipboard and then read the clipboard in a LB program. Using wmic I can get serial numbers etc into the clipboard. That seem to work but it is not stable. It works for a few reads of the clipboard and then LB dies with a "primitive" error or it just hangs and I have to use task manager to kill it. Once I restart the program, it sometimes dies immediately or after a few interactions with the clipboard. I have used parts of Alyce Watson and Dennis McKinney's demo with the same result. Very unpredictable. I think it has something to do with timing. I will definitely credit you in the documentation if I get to use it. I haven't looked at your code yet but I am hoping that it helps to circumvent having to use he wmic / clipboard approach.... ***EDIT*** Had a quick scan and I see that you are also using "wmic" in places... If I can get the HardwareIDex DLL calling to work (see an earlier post in this thread), then I could eliminate the need to use wmic... ***EDIT 2*** I must admit I am dumb.. I am trying to understand what you are doing in the program and having some difficulty. Will work throught it slowly - will probably take a few reads to get to grips with it.... Not your code to blame but my old and slow brain ***EDIT 3*** Ahhh I see what you are doing and I see what my problem is. I was "piping" to the clipboard and then reading from there whereas you are using a file to "pipe" to and then reading the data... I originally thought of doing that but all I could think of was "|clip"... I had forgotten about the ">" I used in my MSDOS days
|
|