Question

I am creating an application in VB.NET (for windows) in which the license expires after a year. What date can I use that the user can not manipulate to see if a year has gone by?

I don't want the user to have to be online to use the software, so an online check is not a valid option.

Thanks.

Was it helpful?

Solution

A date based expiry without NIST (network time servers) is precarious because the only alternative is the local clock, which the user can fiddle with. Checking once in a while, such as every week or two, presents a very large vulnerability: This requires the app write down the date of the last check somewhere and it is simply impossible to keep that a secret on the user's machine.

One way to get the approximate date is to calculate it from the last boot datetime:

Public Class WMI

    Friend Shared Function GetWMISetting(wmiClass As String, value As String) As String
        Dim retVal As String = ""
        Dim query = String.Format("SELECT {0} FROM {1}", value, wmiClass)

        Using searcher As New System.Management.ManagementObjectSearcher(query)
            For Each item As System.Management.ManagementObject In searcher.Get
                For Each p As System.Management.PropertyData In item.Properties
                    If String.Compare(value, p.Name,
                                      StringComparison.InvariantCultureIgnoreCase) = 0 Then
                        If p.Value IsNot Nothing Then
                            retVal = p.Value.ToString
                        End If
                        Exit For
                    End If
                Next
            Next
        End Using
        Return retVal

    End Function

    Friend Shared Function GetMinSystemDateTime() As DateTime

        Dim lastBoot = WMI.GetWMISetting("Win32_OperatingSystem", "LastBootUpTime")
        Dim uptime = WMI.GetWMISetting("Win32_PerfFormattedData_PerfOS_System", 
                   "SystemUpTime")

        Dim ts As New TimeSpan(0, 0, Convert.ToInt32(uptime))
        Dim MinimumDate = ManagementDateTimeConverter.ToDateTime(lastBoot).Add(ts)

        Return MinimumDate  
    End Function
End Class

The calculates the approximate date from the LastBootUp date, and the SystemUpTime values. The latter can be seen on the Performance tab of TaskManager. The date format is peculiar, so the System.Management namespace provides a converter.

The Date returned is approximate because the "UpTime" does not include time sleeping. Otherwise, it gives you an idea of the approximate minimum date.

They could probably spoof this using a VM, and it could be totally wrong if the battery is dead, they wont let Windows set the time so the PC is permanently off date. If your license includes an install/issue date (set by you at the Home Office, not the client PC), you could test if the Date returned is less than the install and treat that as expired.

Then the trick becomes protecting those values. When you issue the license, serialize the user name, serial, install date and expiry date to a MemoryStream. Then run a RSA hash on the data to create an asymmetric signature.

Create a class to hold the license data as a base64 string and the signature hash and serialize it to a file. At runtime, open it and validate the signature using the license data and the Private Key. If it validates, the data in the "license" portion is valid.1

Ultimately, they really just need to patch your code:

' from:
IsRegistered = ValidateLicense()
' to:
IsRegistered = (True = True)

Obfuscate your app to slow them down on that.

Now, if you think something like that will thwart say, 80% of your likely user base, then go for it.

The the user can not manipulate part is not do-able, but you can concoct a solution that will work to a fair degree. WHO you are trying to keep out (crackers vs super users vs AOL-LoLs) determines how extensive or sophisticated you need to be.

1 Such a file is read only on the client. You cant write to it without invalidating the signature. And you cannot update/change it without including the Private Key in the app which is suicide.

OTHER TIPS

If you are not willing to look at an online clock/service/etc, this cannot be done, because the user can change the time, whenever they want and you cannot prevent it.

You can however, check for tampering by using 2 dates. One for the expiration and one as a check for tampering. Everytime they load your app, it should always be > Expiration Date - 1 year and it should be greater than last time they started your app. Of coarse, you want these encrypted so they cannot tamper with these dates.

This makes it where it becomes more of a hassle than it is worth for the user and they eventual will get locked out, it just might take another year, but it will happen.

Think about this issue, what will prevent them from removing your file/registry setting and starting over. How about formating thier hard drive or doing a system restore. Perhaps they use a virtual PC or some type of undo disks. How do you overcome this?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top