[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2804
  • Last Modified:

Getting unique machine id for software copy protection

I am deploying a microsoft access application, and I would like, as best as I can to keep people from just copying it and giving it to someone else.

I'm thinking of using (and storing) the host id of the machine on which it was first installed.  Is this possible?  Is this the best way to do this?

2 Solutions
John HurstBusiness Consultant (Owner)Commented:
Yes, you can do that. Ad-Aware does that.

I set it up on a Virtual Machine to test because of reports of major problems and they told me: "Too bad for you, you have used up your license". I no longer am a customer of Ad-Aware (although I used to be), and now instead of having some money, they have none. I use a different product.

Yes, you can do that.

... Thinkpads_User
Scott McDaniel (Microsoft Access MVP - EE MVE )Infotrakker SoftwareCommented:
There is no such thing as a Machine ID value, at least for what you're looking to do.

In terms of copy protection, a "MachineID" is nothing more than some value you contrive, based on various hardware item information you get from a machine. For example, you can get the MAC address, cpu version and such, and then generate some value based on that.

If you really want to employ copy protection, use a 3rd party utility to do this. I've tested this one, and it works very well:

zorvek (Kevin Jones)ConsultantCommented:
The copy protection schemes I have used grab a NIC MAC address. A NIC (Network Interface Controller or the network card) is installed on every machine and every NIC is unique amongst all NICs manufactured to date and in the future. Another trick is to generate a GUID which is a Windows generated "key" that is unique in the universe and based on various items such as the active NIC MAC, date and time, etc.

This code gets the active NIC MAC:

Public Function GetNetworkConnectionMACAddress() As String

' Return the currently used network adapter's MAC address

' Syntax
' GetNetworkConnectionMACAddress()

    Dim oWMIService As Object
    Dim vAdapters As Variant
    Dim oAdapter As Object
    Dim lIndex As Long
    Dim lMatchIndex As Long
    Dim vResult As Variant
    ' Adapters are pulled from the Windows Management Instrumentation database
    ' The currently used adapter has a MAC address and an IP address that is not
    Set oWMIService = GetObject("winmgmts:\\" & "." & "\root\cimv2")
    Set vAdapters = oWMIService.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True")
    For Each oAdapter In vAdapters
        If Not IsNull(oAdapter.MACAddress) And IsArray(oAdapter.IPAddress) Then
            lMatchIndex = -1
            For lIndex = 0 To UBound(oAdapter.IPAddress)
                If Not oAdapter.IPAddress(lIndex) = "" Then
                    lMatchIndex = lIndex
                    Exit For
                End If
            Next lIndex
            If Not lMatchIndex < 0 Then
                GetNetworkConnectionMACAddress = oAdapter.MACAddress
            End If
        End If

End Function

This code generates a GUID:

Private Type tGUID
   l1 As Long
   l2 As Long
   l3 As Long
   l4 As Long
End Type

Private Declare Function CoCreateGuid Lib "ole32.dll" ( _
      lpGuid As tGUID _
   ) As Long

Private Declare Function StringFromGUID2 Lib "ole32.dll" ( _
      lpGuid As tGUID, _
      ByVal lpString As String, _
      ByVal cbBytes As Integer _
   ) As Integer

Public Function CreateGUID() As String

' Create and return a unique GUID string.

   Dim GUID As tGUID
   Dim Temp As String
   Dim Result As Long
   Dim Length As Long
   Result = CoCreateGuid(GUID)
   If (Result = 0) Then
      Temp = StrConv(String(38, Chr(0)), vbUnicode)
      Length = StringFromGUID2(GUID, Temp, Len(Temp))
      Temp = StrConv(Temp, vbFromUnicode)
      If (Length > 0) Then
         If (Left(Temp, 1) = "{") Then Temp = Right(Temp, Len(Temp) - 1)
         If (Right(Temp, 1) = "}") Then Temp = Left(Temp, Len(Temp) - 1)
         Length = InStr(Temp, "-")
         Do While (Length <> 0)
            Temp = Left(Temp, Length - 1) & Right(Temp, Len(Temp) - Length)
            Length = InStr(Temp, "-")
         Temp = ""
      End If
   End If
   CreateGUID = Temp

End Function

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Jim Dettman (Microsoft MVP/ EE MVE)PresidentCommented:
I would go with the NIC as well. Just watch out for the dial-up adapters and VPN interfaces, which may or may not exist at the time the code runs.
I have VBA code that does not rely on the winmgmts object if you want it, but I'm what Kevin has posted will work fine.
One other note: believe it or not, a GUID is not guaranteed to unique. I didn't believe it myself either when someone told me (after all they call it a "globally unique ID"), but I reasearched and found out that it is true. However the odds of getting a duplicate are so infinitesimally small that you can consider it to be one, so the other routine that Kevin posted would work as well.
I forget what the odds were, but there were a LOT of zeros after it....
Paul ThompsonIT ConsultantCommented:
This method is very simple but effective.

Use the Hard Drive volume serial number created when the drive was formatted.

The code below extracts this serial number.

The user provides you with this serial number...
You provide a key code that only works with that serial number...
The application has a simple algorithm that allows the app to run when a valid key is entered...
The app should be able to run in a reduced functionality mode without a key...
The key will not work on other unregistered machines.

You will of course need to write a small key-code generator app.

This protects you from people who just give away the key to their friends.

If the user reformats or replaces the drive, they will need another key code.

'-- Put this in a module
Public Declare Function GetVolumeInformation& Lib "kernel32" Alias "GetVolumeInformationA" (ByVal lpRootPathName As String, ByVal pVolumeNameBuffer As String, ByVal nVolumeNameSize As Long, lpVolumeSerialNumber As Long, lpMaximumComponentLength As Long, lpFileSystemFlags As Long, ByVal lpFileSystemNameBuffer As String, ByVal nFileSystemNameSize As Long)
Public Const MAX_FILENAME_LEN = 256

Public Function DriveSerial(ByVal sDrv As String) As Long
Dim RetVal As Long
Dim str As String * MAX_FILENAME_LEN
Dim str2 As String * MAX_FILENAME_LEN
Dim a As Long
Dim b As Long

Call GetVolumeInformation(sDrv & ":\", str, MAX_FILENAME_LEN, RetVal, a, b, str2, MAX_FILENAME_LEN)
DriveSerial = Abs(RetVal)

End Function

'-- Put this on a form
Private Sub Command1_Click()
    Text1.Text = DriveSerial("C") ' where "C" is the drive volume.
End Sub

Open in new window

Éric MoreauSenior .Net ConsultantCommented:
you can get ActiveLock for free: http://www.activelock.com/index.html
Jim Dettman (Microsoft MVP/ EE MVE)PresidentCommented:

<<you can get ActiveLock for free>>

That site seems to be quite old and mostly non-functional. I'd also hesitate to download something that says it's "open source", yet it wants to collect info for you to download the source. That goes against open source guide lines.


Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now