Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Limited Time Programs
#1
Ever wanted to give someone a timed trial of your program?  Let them download it, play around for a few days, and then pop up a nag screen telling them to buy your junk?  Well, now you can!!

First the timestamper!

Code: (Select All)
INPUT "File to stamp TimeStamp to =>"; file$

OPEN file$ FOR BINARY AS #1
filesize = LOF(1)
DIM TS AS _FLOAT
TS = TimeStamp(DATE$, TIMER)
PUT #1, filesize + 1, TS
t$ = "TS"
PUT #1, , t$
CLOSE #1
PRINT "TimeStamp Added"
SLEEP
SYSTEM

FUNCTION TimeStamp## (d$, t##) 'date and timer
    'Based on Unix Epoch time, which starts at year 1970.
    DIM l AS _INTEGER64, l1 AS _INTEGER64, m AS _INTEGER64
    DIM d AS _INTEGER64, y AS _INTEGER64, i AS _INTEGER64
    DIM s AS _FLOAT

    l = INSTR(d$, "-")
    l1 = INSTR(l + 1, d$, "-")
    m = VAL(LEFT$(d$, l))
    d = VAL(MID$(d$, l + 1))
    y = VAL(MID$(d$, l1 + 1))
    IF y < 1970 THEN 'calculate shit backwards
        SELECT CASE m 'turn the day backwards for the month
            CASE 1, 3, 5, 7, 8, 10, 12: d = 31 - d '31 days
            CASE 2: d = 28 - d 'special 28 or 29.
            CASE 4, 6, 9, 11: d = 30 - d '30 days
        END SELECT
        IF y MOD 4 = 0 AND m < 3 THEN 'check for normal leap year, and we're before it...
            d = d + 1 'assume we had a leap year, subtract another day
            IF y MOD 100 = 0 AND y MOD 400 <> 0 THEN d = d - 1 'not a leap year if year is divisible by 100 and not 400
        END IF

        'then count the months that passed after the current month
        FOR i = m + 1 TO 12
            SELECT CASE i
                CASE 2: d = d + 28
                CASE 3, 5, 7, 8, 10, 12: d = d + 31
                CASE 4, 6, 9, 11: d = d + 30
            END SELECT
        NEXT

        'we should now have the entered year calculated.  Now lets add in for each year from this point to 1970
        d = d + 365 * (1969 - y) '365 days per each standard year
        FOR i = 1968 TO y + 1 STEP -4 'from 1968 onwards,backwards, skipping the current year (which we handled previously in the FOR loop)
            d = d + 1 'subtract an extra day every leap year
            IF (i MOD 100) = 0 AND (i MOD 400) <> 0 THEN d = d - 1 'but skipping every year divisible by 100, but not 400
        NEXT
        s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
        TimeStamp## = -(s## + 24 * 60 * 60 - t##)
        EXIT FUNCTION
    ELSE
        y = y - 1970
    END IF

    FOR i = 1 TO m 'for this year,
        SELECT CASE i 'Add the number of days for each previous month passed
            CASE 1: d = d 'January doestn't have any carry over days.
            CASE 2, 4, 6, 8, 9, 11: d = d + 31
            CASE 3 'Feb might be a leap year
                IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
                    d = d + 29 'its a leap year
                    IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
                        d = d - 1 'the year is divisible by 100, and not divisible by 400
                    END IF
                ELSE 'year not divisible by 4, no worries
                    d = d + 28
                END IF
            CASE 5, 7, 10, 12: d = d + 30
        END SELECT
    NEXT
    d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
    FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
        d = d + 1 'add an extra day every leap year
        IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
    NEXT
    s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
    TimeStamp## = (s## + t##)
END FUNCTION

And, a program set up to showcase the basic workings of it:
Code: (Select All)
TYPE SYSTIME
    year AS INTEGER
    month AS INTEGER
    weekday AS INTEGER
    day AS INTEGER
    hour AS INTEGER
    minute AS INTEGER
    second AS INTEGER
    millis AS INTEGER
END TYPE
DECLARE DYNAMIC LIBRARY "Kernel32"
    SUB GetSystemTime (lpSystemTime AS SYSTIME)
    SUB GetLocalTime (lpSystemTime AS SYSTIME)
END DECLARE

AppendTimeStamp

SUB AppendTimeStamp
    DIM AS _FLOAT TS
    f = FREEFILE
    OPEN COMMAND$(0) FOR BINARY AS #f
    FileSize = LOF(f)
    check$ = "  "
    GET #f, FileSize - 1, check$
    SELECT CASE UCASE$(check$)
        CASE "VC" 'verified copy.  All is good
            PRINT "You have a paid copy of this software.  All is good, kindly feel free to carry on with your existence, puny human."
        CASE "TS" 'already has a timestamp, is a limited time test version.  Toss NAG Screen.
            GET #1, FileSize - 33, TS
            PRINT "Original TimeStamp:"; TS
            PRINT "Current TimeStamp: "; TimeStamp(DATE$, TIMER)
            PRINT USING "This is a trial version of the program.  You have been testing it for ###,####.#### seconds"; TimeStamp(DATE$, TIMER) - TS
        CASE ELSE 'first run.
            PRINT "Illegal copy of software!  Terminating Now!"
            SLEEP
            SYSTEM
    END SELECT
    CLOSE #f
END SUB

FUNCTION TimeStamp## (d$, t##) 'date and timer
    'Based on Unix Epoch time, which starts at year 1970.
    DIM l AS _INTEGER64, l1 AS _INTEGER64, m AS _INTEGER64
    DIM d AS _INTEGER64, y AS _INTEGER64, i AS _INTEGER64
    DIM s AS _FLOAT

    l = INSTR(d$, "-")
    l1 = INSTR(l + 1, d$, "-")
    m = VAL(LEFT$(d$, l))
    d = VAL(MID$(d$, l + 1))
    y = VAL(MID$(d$, l1 + 1))
    IF y < 1970 THEN 'calculate shit backwards
        SELECT CASE m 'turn the day backwards for the month
            CASE 1, 3, 5, 7, 8, 10, 12: d = 31 - d '31 days
            CASE 2: d = 28 - d 'special 28 or 29.
            CASE 4, 6, 9, 11: d = 30 - d '30 days
        END SELECT
        IF y MOD 4 = 0 AND m < 3 THEN 'check for normal leap year, and we're before it...
            d = d + 1 'assume we had a leap year, subtract another day
            IF y MOD 100 = 0 AND y MOD 400 <> 0 THEN d = d - 1 'not a leap year if year is divisible by 100 and not 400
        END IF

        'then count the months that passed after the current month
        FOR i = m + 1 TO 12
            SELECT CASE i
                CASE 2: d = d + 28
                CASE 3, 5, 7, 8, 10, 12: d = d + 31
                CASE 4, 6, 9, 11: d = d + 30
            END SELECT
        NEXT

        'we should now have the entered year calculated.  Now lets add in for each year from this point to 1970
        d = d + 365 * (1969 - y) '365 days per each standard year
        FOR i = 1968 TO y + 1 STEP -4 'from 1968 onwards,backwards, skipping the current year (which we handled previously in the FOR loop)
            d = d + 1 'subtract an extra day every leap year
            IF (i MOD 100) = 0 AND (i MOD 400) <> 0 THEN d = d - 1 'but skipping every year divisible by 100, but not 400
        NEXT
        s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
        TimeStamp## = -(s## + 24 * 60 * 60 - t##)
        EXIT FUNCTION
    ELSE
        y = y - 1970
    END IF

    FOR i = 1 TO m 'for this year,
        SELECT CASE i 'Add the number of days for each previous month passed
            CASE 1: d = d 'January doestn't have any carry over days.
            CASE 2, 4, 6, 8, 9, 11: d = d + 31
            CASE 3 'Feb might be a leap year
                IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
                    d = d + 29 'its a leap year
                    IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
                        d = d - 1 'the year is divisible by 100, and not divisible by 400
                    END IF
                ELSE 'year not divisible by 4, no worries
                    d = d + 28
                END IF
            CASE 5, 7, 10, 12: d = d + 30
        END SELECT
    NEXT
    d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
    FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
        d = d + 1 'add an extra day every leap year
        IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
    NEXT
    s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
    TimeStamp## = (s## + t##)
END FUNCTION


So, to start with, run the second file first.  It'll make an EXE for you and tell you that it's illegal!  You're not allowed to use it.  This is all someone that grabs your program out of the blue will see.

Now, if you want to send someone a timestamped trial version, run the first program and point it to your other program's compiled EXE.  It'll stick a timestamp to the end of it for you, and now you can now run that EXE and have it make use of that timestamp however you want.

If they buy your junk, send (or change) the last 2 bytes of the EXE to "VC" for "Verified Copy", and they're good to go without any message for illegal downloading or nag screen to buy your stuff.

Screenshots follow:

   

   

   
Reply
#2
One thing to note -- this isn't any sort of super secure encryption or anything going on here.  All we're doing is appending a timestamp and verification code to the end of your program.  Any "hacker" who learns this simple trick and just go in and change the last 2 byte of your EXE for "TS" (for "Time Stamped") to "VC" (for "Verified Copy"), and then they'll be good to go.  Hacking this would take very little effort for anyone who really wants to do so, but let's all take a moment and be honest with ourselves:  Who's making and distributing such awesome programs with QB64 that somebody will actually go through the effort to hack them??

A simple system works just fine for the type of simple programs which are generally generated and shared via QB64.  If you're good enough to make something fancy that requires better security for trial versions, then you're more than likely skilled enough to sort out this type of issue for yourself and you'll skip this type of simplex utility security.  

This won't stop Hacker Bob from hacking your program, but it'll probably be all that's needed for your Aunt Suzie and her 27 kidlings. Wink
Reply
#3
If only there was a way to lodge it somewhere inside the EXE file instead of tacking it to the end. I would have preferred a validation which is included as object file but which is different from "DATA" statements. For the example shown on this thread it should employ encryption. Even fewer hackers could employ tools to examine the EXE file header and discover that file was tampered with before they could tamper with it.

If I were doing something like this I would gladly invite Aunt Suzie as beta-tester and force her relatives to buy my software. Big Grin
Reply
#4
I've given this same topic a thought now and then over the years too. This is a really easy way to accomplish this. My idea always revolved around writing an entry to the registry but that's potentially dangerous, tricky, and probably not so easy with BASIC. Also, no matter which method you would use to limit time the hackers will always find a way around, so you might as well use something easy to implement like this any way.

Personally, if I were to ever offer software that I though may be good enough for a little compensation I would probably go the old school shareware route. Either offer the fist level of the game (aka shareware DOOM) with more levels in the paid version or a limited set of features with all the features unlocked in the paid version. You still have the problem of people sharing the paid version though. Luckily (or unfortunately?) I have not written anything that I felt a need to get a little compensation for yet, although I would like to take a stab with Swift and iOS just to see if I could manage a few dollars on an app store.
Reply
#5
(02-06-2023, 01:21 AM)mnrvovrfc Wrote: If only there was a way to lodge it somewhere inside the EXE file instead of tacking it to the end. I would have preferred a validation which is included as object file but which is different from "DATA" statements. For the example shown on this thread it should employ encryption. Even fewer hackers could employ tools to examine the EXE file header and discover that file was tampered with before they could tamper with it.

If I were doing something like this I would gladly invite Aunt Suzie as beta-tester and force her relatives to buy my software. Big Grin

Inside an EXE is a little tricky, as the OS doesn't like you writing to the file while it's loading in memory and running, but there's no reason why you can't embed that data inside a different file.  For you old timers out there, how many of you remember playing games with an unusual border around the screen which tweaked and danced waay back in the day?  How many of you know what that was all about, besides just adding a little "flare" to the screen/program?

That was a lot of the program's data stored in video memory!

Back in the day, one was lucky to have 64kb of memory to use, so programmers would tweak their work to try and find ways to maximize how much they could use.  One trick was to use border blocks of video memory to store information in.  Pixel (0,0) might be the character's health.  Pixel (0,1) might be the character's mana.  Pixel (0,2) might be the character's attack, while pixel (0,3) was the character's defense, and so on and so on...

There's absolutely nothing that says you can't do the same thing in modern programs, but in a sneaker manner.  Create a splash screen which works as a title screen for your game, and use the leastmost significant bit to toggle and represent the bits in your timestamp.  *Nobody* is ever going to eyeball and tell the difference between _RGBA(255,255,255,254) and _RGBA(255,255,255,255).  <-- right there is a toggle bit difference and with that you can embed whatever the heck you want into your splash screen, making it effectively a security screen.

If anyone wants a demo, I'll be happy to whip something up to showcase the basic process for you guys.  Imbedding data in images is something that I've been doing for ages and ages, just to store important information to myself on them, like people's names, places, dates, occasions, ect.  

Be creative.  Think a little outside the box.  It's really not that hard to sneakily embed and hide a few bytes of information into a program to use as a timestamp for a trial period.  YOU'RE the programmer -- you can store whatever data you want, in whatever order/sequence you want, in your programs.   Just add an 8-byte header to your user's inventory data if you want to!   

Let's see... umm.... my hero has a saved data of: "0206202303260107987234"

Now, who sees that timestamp in there?  Look close.  Start at the left and break it down as we go right...
02-06-2023 Date
03:46 Time
01 -- Hero has "The Sword of Heroes"
07 -- Hero is wearing "Chain Armor"
987 -- Hero's 3 digit health
234 -- Hero's 3 digit mana

Or is it?  Maybe that's a completely different data structure than what I told you it was, and my timestamp is embedded into my enemy database!  Or maybe it's somewhere in the middle of my compressed text files which represent the story line itself.  "On 20.23.0206, by the Antarian Calendar, the end of the world occurred at 03:46 PM.  Well, at least the beginning of the end of the world started at that time.  This is the story of how it all came to an ending after that..."

At the end of the day, all you need is someway to store a timestamp for when the user got your program and whether it's a valid copy or not.  If you're making a game, there's a ton of places where you can hide such a small amount of information in your program.  Just be creative a little, and you shouldn't have any issues at all in making a "Limited Activation" program.  Smile
Reply
#6
I barely remember way way back in late 80's, in the times of physical disc distributions, you could not allow copies to be made by embedding disc number into the exe when compiled from QB. If the exe found itself on wrong disk number it deleted itself. You could have probably done that with dates as well for time limit samples.
b = b + ...
Reply
#7
I would write it in the program like this is even smaller.


Code: (Select All)
'Print Date$
month$ = Left$(Date$, 2): M = Val(month$)
day$ = Mid$(Date$, 4, 2): D = Val(day$)
day$ = Str$(D) ' eliminate any leading zeros
year$ = Right$(Date$, 4): Y = Val(year$)

Print "Test Zeitraum betr„gt 30 Tage" 'Vom 6,2,2023 bis 19,3,2023
'Print D
'Print M
'Print Y
Tage = 30
If Y > 2023 Then System
If M > 3 Then System
If D > 6 And M = 2 Then Tage = Tage - D + 6
If D < 6 And M > 2 Then Tage = Tage - 17 - D
If D >= 6 And M > 2 Then Tage = Tage - 23 - D

Print "Sie haben noch "; Tage; " Tage Demozeit"
If Tage <= 0 Then
    Print " Ihr Testzeitraum ist abgelaufen"
    Sleep
    System
End If
Print " Viel Spass"
Reply
#8
(02-06-2023, 03:08 AM)TerryRitchie Wrote: I've given this same topic a thought now and then over the years too. This is a really easy way to accomplish this. My idea always revolved around writing an entry to the registry but that's potentially dangerous, tricky, and probably not so easy with BASIC. Also, no matter which method you would use to limit time the hackers will always find a way around, so you might as well use something easy to implement like this any way.

Personally, if I were to ever offer software that I though may be good enough for a little compensation I would probably go the old school shareware route. Either offer the fist level of the game (aka shareware DOOM) with more levels in the paid version or a limited set of features with all the features unlocked in the paid version. You still have the problem of people sharing the paid version though. Luckily (or unfortunately?) I have not written anything that I felt a need to get a little compensation for yet, although I would like to take a stab with Swift and iOS just to see if I could manage a few dollars on an app store.

I can help with that. I have a registry library that I wrote for QB64.
Tread on those who tread on you

Reply
#9
(02-07-2023, 02:30 PM)Balderdash Wrote:
(02-06-2023, 03:08 AM)TerryRitchie Wrote: I've given this same topic a thought now and then over the years too. This is a really easy way to accomplish this. My idea always revolved around writing an entry to the registry but that's potentially dangerous, tricky, and probably not so easy with BASIC. Also, no matter which method you would use to limit time the hackers will always find a way around, so you might as well use something easy to implement like this any way.

Personally, if I were to ever offer software that I though may be good enough for a little compensation I would probably go the old school shareware route. Either offer the fist level of the game (aka shareware DOOM) with more levels in the paid version or a limited set of features with all the features unlocked in the paid version. You still have the problem of people sharing the paid version though. Luckily (or unfortunately?) I have not written anything that I felt a need to get a little compensation for yet, although I would like to take a stab with Swift and iOS just to see if I could manage a few dollars on an app store.

I can help with that. I have a registry library that I wrote for QB64.

I'm interested. Where can I obtain it?
Reply
#10
(02-07-2023, 04:05 PM)TerryRitchie Wrote: I'm interested. Where can I obtain it?

@TerryRitchie
Attached are my BI and BM files. Here is a link to the post I made on the old forum about it which has example usage. Windows Registry Library (BI & BM) (alephc.xyz)


Attached Files
.bi   WinReg.BI (Size: 370 bytes / Downloads: 30)
.bm   WinReg.BM (Size: 32.29 KB / Downloads: 33)
Tread on those who tread on you

Reply




Users browsing this thread: 2 Guest(s)