PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV 2024 → [WD 18] Two machines with identical ID's!
[WD 18] Two machines with identical ID's!
Débuté par Charles U. Schneiter, 26 mar. 2014 16:05 - 17 réponses
Posté le 26 mars 2014 - 16:05
Hi folks!

I am deriving the machine's harddisk-ID through this function: gsComputerID is string = fDriveInfo("C:", fdSerialNumber)
The context this is used is locking down an app by issuing an activation code which is based on the machines harddisk ID.

When I run the above code I get two absolutely identical H/D-ID's!! :confused:

My development takes place on two identical machines running Win 7 Pro 32 Bit, one having been created by cloning the other <- and I guess that this is at the root of the problem?

I am aware of the fact that the coded function uses an ID which is created at formatting the drive. It seems not to be the s/n given by the manufacturer of the drive. So when using a cloned workstation, we can therefore not use the above code to obtain a really unique machine ID since one is cloning the 'formatted ID' (in lack of a better word) as well (e.g. whenever I set up a new workstation in a network, I do so by cloning a 'default' disk and hence end up having a whole network consisting of workstations with the same H/D-ID and thus preventing me from using a machine based activation scheme ..).

My question then: How could I get at the H/D-ID as supplied by the manufacturer of the disk - this number would be unique for all practical purposes, OK? Unforunately, I haven't found a solution by browsing the help...

Thanks for your thoughts!
Posté le 26 mars 2014 - 16:51
Hi,

Why dont you use a GUID pr machine? - will be unique :)
Saved someplace (registry, file)

example:
procedure ChkUnique() s is string = iniread("ID","MachID","",GSMyInifile) if s = "" then s = GetGUID(guidFormatted) iniwrite("ID","MachID",s,GSMyInifile) End result s

Cheers
Tor-Bjarne
Posté le 26 mars 2014 - 17:04
Hi Charles

Getting the hdd's serials varies from one manufacturer to another, I think no windows api is implemented because of diversity of getting it. My thought is you need a third-party library where you hope they reach most of the current hdd's on the market.
You can try http://www.devlib.net/getdiskserial.htm they have a trial version so you can test it before buying.

Regards
Adrian
Posté le 26 mars 2014 - 17:43
Charles,

What you could try is adding the network card serial number or MAC code to your hardware ID code. I do not know if WinDev has native functions for this but I have the code in VFP for accessing it via Windows API.
Posté le 26 mars 2014 - 18:44
Hi Charles,

I would not recommend doing that yourself, this is a lot of problems when deployment starts to grow. But you may have a look at "Functions for managing the activation keys": http://doc.pcsoft.fr/fr-FR/?1000018998

But there are issues with these functions. You can refer to this message and also to the whole thread: http://27130.foren.mysnip.de/read.php…

At that time (of the above thread) we choose to go with HASP dongles for one big application we have. We never deployed much because this is a lot of work maintaining the keys and updates. It's also expensive.

Now we have a new project and we use LimeLM: https://wyday.com/limelm/ We are much satisfied with their product and their support. (And for the price, we do not bother making our own system. Our Website is fully integrated, licences sent right after payment. And we can control licences remotely if desired, etc. We have only good things to say. We also use their floating licence server and it's great too - still in development but already deployed with success.)

Best regards,
Alexandre Leclerc

PS: Hi JP, for your question this would be NetMACAddress().
Posté le 26 mars 2014 - 19:17
Hi,

Found this on http://windevfr.free.fr/com2006.html#

//Le nom d'un disque, son numéro de série et le type :

lpRootPathName est une chaine="C:\"
lpVolumeNameBuffer est une chaine asciiz de 13
nVolumeNameSize est un entier long=12
lpVolumeSerialNumber est un entier long
lpMaximumComponentLength est un entier long
lpFileSystemFlags est un entier long
lpFileSystemNameBuffer est une chaine asciiz de 32
nFileSystemNameSize est un entier long=32

si AppelDLL32("kernel32" , "GetVolumeInformationA" , lpRootPathName , &lpVolumeNameBuffer , nVolumeNameSize , &lpVolumeSerialNumber , &lpMaximumComponentLength , &lpFileSystemFlags , &lpFileSystemNameBuffer , nFileSystemNameSize)

info("Nom du Volume : "+lpVolumeNameBuffer,
"N° Série : "+poidsfort(lpVolumeSerialNumber)+"-"+poidsfaible(lpVolumeSerialNumber),
"Type :"+lpFileSystemNameBuffer)

fin
Posté le 27 mars 2014 - 15:05
Hi Folks!

Hey these are so many good tipps :spos: that I have to digest that further, before posting a sensible reply!

I'll chat back as soon as I know which path to take.

In the mean time: Thanks everybody for your time - much appreciated!
Posté le 28 mars 2014 - 09:28
Hello,

Be careful, the serial number returned by those function is the partition serial number, it will change each time there is a format and will be copied when cloning a partition. it's not very secure.

Regards,

Fred.
Posté le 28 mars 2014 - 16:23
Try to read HDD Firmware number using WMI! It is safer and guaranted to work on all Windows PC as WMI comes preinstalled on all modern Windows versions.
Posté le 31 mars 2014 - 07:03
This is probably out of context but here is a Class in VB6 that I have been using for many years for reading HDD Firmware number as an alternative to using WMI.

See if you can translate it. It does not require Administrative prevelage for the app using this code but in case of using WMI on some machined we have observed we requrie to elevate the prevelage of our app.

VERSION 1.0 CLASS BEGIN MultiUse = -1 'True Persistable = 0 'NotPersistable DataBindingBehavior = 0 'vbNone DataSourceBehavior = 0 'vbNone MTSTransactionMode = 0 'NotAnMTSObject END Attribute VB_Name = "HDSN" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = True Attribute VB_PredeclaredId = False Attribute VB_Exposed = True Attribute VB_Ext_KEY = "SavedWithClassBuilder6" ,"Yes" Attribute VB_Ext_KEY = "Top_Level" ,"Yes" Option Explicit ' ' Costants Private Const VER_PLATFORM_WIN32S = 0 Private Const VER_PLATFORM_WIN32_WINDOWS = 1 Private Const VER_PLATFORM_WIN32_NT = 2 ' Costants for driver IDE Private Const DFP_RECEIVE_DRIVE_DATA = &H7C088 ' Costants to create file Private Const FILE_SHARE_READ = &H1 Private Const FILE_SHARE_WRITE = &H2 Private Const GENERIC_READ = &H80000000 Private Const GENERIC_WRITE = &H40000000 Private Const OPEN_EXISTING = 3 Private Const CREATE_NEW = 1 ' enumeration for CmnGetHDData Private Enum HDINFO HD_MODEL_NUMBER HD_SERIAL_NUMBER HD_FIRMWARE_REVISION End Enum ' structure for OS Info data Private Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformId As Long szCSDVersion As String * 128 End Type ' Structure for SENDCMDINPARAMS Private Type IDEREGS bFeaturesReg As Byte bSectorCountReg As Byte bSectorNumberReg As Byte bCylLowReg As Byte bCylHighReg As Byte bDriveHeadReg As Byte bCommandReg As Byte bReserved As Byte End Type ' Structure for driver of IDE Private Type SENDCMDINPARAMS cBufferSize As Long irDriveRegs As IDEREGS bDriveNumber As Byte bReserved(1 To 3) As Byte dwReserved(1 To 4) As Long End Type ' Structure for SENDCMDOUTPARAMS Private Type DRIVERSTATUS bDriveError As Byte bIDEStatus As Byte bReserved(1 To 2) As Byte dwReserved(1 To 2) As Long End Type ' Structure for driver IDE Private Type SENDCMDOUTPARAMS cBufferSize As Long DStatus As DRIVERSTATUS bBuffer(1 To 512) As Byte End Type ' Private Declare Function GetVersionEx _ Lib "kernel32" Alias "GetVersionExA" _ (lpVersionInformation As OSVERSIONINFO) As Long ' Private Declare Function CreateFile _ Lib "kernel32" Alias "CreateFileA" _ (ByVal lpFileName As String, _ ByVal dwDesiredAccess As Long, _ ByVal dwShareMode As Long, _ ByVal lpSecurityAttributes As Long, _ ByVal dwCreationDisposition As Long, _ ByVal dwFlagsAndAttributes As Long, _ ByVal hTemplateFile As Long) As Long ' Private Declare Function CloseHandle _ Lib "kernel32" _ (ByVal hObject As Long) As Long ' Private Declare Function DeviceIoControl _ Lib "kernel32" _ (ByVal hDevice As Long, _ ByVal dwIoControlCode As Long, _ lpInBuffer As Any, _ ByVal nInBufferSize As Long, _ lpOutBuffer As Any, _ ByVal nOutBufferSize As Long, _ lpBytesReturned As Long, _ ByVal lpOverlapped As Long) As Long ' Private Declare Sub ZeroMemory _ Lib "kernel32" Alias "RtlZeroMemory" _ (dest As Any, _ ByVal numBytes As Long) ' Private Declare Sub CopyMemory _ Lib "kernel32" Alias "RtlMoveMemory" _ (Destination As Any, _ Source As Any, _ ByVal Length As Long) Private Declare Function GetLastError _ Lib "kernel32" () As Long Private mvarCurrentDrive As Byte ' Private mvarPlatform As String ' Public Property Get Copyright() As String ' Copyright Copyright = "Every VB Developer" End Property ' Method GetModelNumber Public Function GetModelNumber() As String ' GetModelNumber = CmnGetHDData(HD_MODEL_NUMBER) End Function ' Method GetSerialNumber Public Function GetSerialNumber() As String ' GetSerialNumber = CmnGetHDData(HD_SERIAL_NUMBER) End Function ' Method GetFirmwareRevision Public Function GetFirmwareRevision() As String ' GetFirmwareRevision = CmnGetHDData(HD_FIRMWARE_REVISION) End Function ' Property CurrentDrive Public Property Let CurrentDrive(ByVal vData As Byte) ' If vData < 0 Or vData > 3 Then Err.Raise 10000, , "Illegal drive number" ' IDE drive 0..3 End If ' mvarCurrentDrive = vData End Property ' Property CurrentDrive Public Property Get CurrentDrive() As Byte ' CurrentDrive = mvarCurrentDrive End Property ' Property Platform Public Property Get Platform() As String ' Platform = mvarPlatform End Property Private Sub Class_Initialize() ' Dim OS As OSVERSIONINFO OS.dwOSVersionInfoSize = Len(OS) Call GetVersionEx(OS) mvarPlatform = "Unk" Select Case OS.dwPlatformId Case Is = VER_PLATFORM_WIN32S mvarPlatform = "32S" ' Win32S Case Is = VER_PLATFORM_WIN32_WINDOWS If OS.dwMinorVersion = 0 Then mvarPlatform = "W95" ' Win 95 Else mvarPlatform = "W98" ' Win 98 End If Case Is = VER_PLATFORM_WIN32_NT mvarPlatform = "WNT" ' Win NT/2000 End Select End Sub Private Function CmnGetHDData(hdi As HDINFO) As String ' IDE Dim bin As SENDCMDINPARAMS Dim bout As SENDCMDOUTPARAMS Dim hdh As Long Dim br As Long Dim ix As Long Dim hddfr As Long Dim hddln As Long Dim s As String Select Case hdi Case HD_MODEL_NUMBER hddfr = 55 hddln = 40 Case HD_SERIAL_NUMBER hddfr = 21 hddln = 20 Case HD_FIRMWARE_REVISION hddfr = 47 hddln = 8 Case Else Err.Raise 10001, "Illegal HD Data type" End Select Select Case mvarPlatform Case "WNT" hdh = CreateFile("\\.\PhysicalDrive" & mvarCurrentDrive, _ GENERIC_READ + GENERIC_WRITE, FILE_SHARE_READ + FILE_SHARE_WRITE, _ 0, OPEN_EXISTING, 0, 0) Case "W95", "W98" hdh = CreateFile("\\.\Smartvsd", _ 0, 0, 0, CREATE_NEW, 0, 0) Case Else Err.Raise 10002, , "Illegal platform (only WNT, W98 or W95)" ' Altre piattaforme non gestite End Select If hdh = 0 Then Err.Raise 10003, , "Error on CreateFile" End If ZeroMemory bin, Len(bin) ZeroMemory bout, Len(bout) With bin .bDriveNumber = mvarCurrentDrive .cBufferSize = 512 With .irDriveRegs If (mvarCurrentDrive And 1) Then .bDriveHeadReg = &HB0 Else .bDriveHeadReg = &HA0 End If .bCommandReg = &HEC .bSectorCountReg = 1 .bSectorNumberReg = 1 End With End With DeviceIoControl hdh, DFP_RECEIVE_DRIVE_DATA, _ bin, Len(bin), bout, Len(bout), br, 0 s = "" For ix = hddfr To hddfr + hddln - 1 Step 2 If bout.bBuffer(ix + 1) = 0 Then Exit For s = s & Chr(bout.bBuffer(ix + 1)) If bout.bBuffer(ix) = 0 Then Exit For s = s & Chr(bout.bBuffer(ix)) Next ix CloseHandle hdh CmnGetHDData = Trim(s) End Function
Posté le 31 mars 2014 - 16:16
Hi Folks,

Again many thanks for your various answers to my question - much appreciated! :spos:

Examining these replies thoroughly, I am leaning more and more away from a webservices based approach towards a hardware-based solution, using inexpensive standard usb-sticks.

There seem to be several reasons speaking for such a solution.
The Pro's:
-With a dongle, you can install an app on any number of machines but only use it on one at any given time - so, concurrency is handled just nicely.
- If a clients hardware fails, deploying it on another workstation is done in minutes without my being involved in any way!
- Easy handling of demo-versions: No dongle means it's a demo.

Well, the Cons should not be omitted:
- When a customer looses his stick, that's it. He/she has to buy a new licence (as we know it from PCS's dongle policy).
- The time it takes to replace a damaged but present dongle. The customer has to send it in and only upon receiving it, will I send a new one. Perhaps we can overcome this by sending a temporary but time limited key by email which allows the customer to contiunue working until the replacement arrives.

Alexandre kindly linked to a post dealing with this extensively (thanks, I somehow missed that one when searching). Amongst the replies to that thread I found a link to a small project written by Guenter (USBFind() which seems to be very helpful, thanks Guenter!

The cost of these dongles as sold by specialized manufacturers did seem prohibitive - and still are! But Guenter advocates the use of standard usb-sticks,which are almost 10 to a penny nowadays.

So there remains one question: How safe are these cheap usb-sticks, esp. their manufacturer-serial-number???
True, each and every usb-stick does have it's unique manufacturer-serial-number. But can it be spoofed? Are there hardware hacks or other kit that make it possible to alter a serial-number?

Is there anything peculiar in choosing a specific brand or kind of usb-stick? Perhaps preferably one with a metal case (sturdyness?) Or are there usb-sticks which are hacker-proof or shoot themselfes as soon as somebody tries to tamper with them? What are your experiences?

On the other hand: If I write a license file onto this very usb-stick and, say, encrypt the serial-number of the stick, together with other relevant info (program version, number of concurrent users, etc.) into this license file, I should be safe? Or?...
Posté le 31 mars 2014 - 16:57
Whilst you are researching USB sticks and dongles I would suggest you consider 3 questions regarding the type of security you want to implement and you should implement.

1) What are you trying to protect?
2) From who are you trying to protect it?
3) For how long do you wish the protection to last?

The first question goes to the degree of effort and cost you are prepared to expend. There is a difference between protecting your recipes and protecting state secrets and each should be protected to a level which provides the correct cost benefit.

The second question addresses your adversary. If you want to protect from the average end-user then that can be achieved really quite easily with minimal expense, even without dongles. But if, on the other extreme, you want to protect against professional grade hackers/crackers then I can assure you that if your application gets into their hands then you can consider it lost. Once the target system is in the hands of the professional grade hacker it will be broken sooner or later (which leads to question 3).

Question 3 addresses how long the protection should last for. If you are protecting data which has a useful time span then you only need to protect it until it is no longer useful, for example, a public company’s financial results; once disclosed to the public they no longer need to be protected. The duration you want to protect something for again goes to the degree of effort and expense you will be prepared to expend. Even software has a life-span - if you are continually upgrading and improving your application then you are also making your older versions redundant.

These three questions will help you think about the level of security you really need.

In respect of dongles - yes they are all crackable and not with too much effort. There are several approaches but the main one is sniffing the comms. between your app and what is being read from the dongle and then spoof that for future use. But here again, who can do this? not the average user certainly. And not legitimate users who mostly have no interest in breaking the law. But professional hackers will bypass most dongles within a very short time.

Ultimately the code can also be hacked to prevent the dongle call, or the phone-home, or the hard disk serial number read, etc. This is time consuming but certainly all possible.
Posté le 31 mars 2014 - 17:37
Hi Charles,

1 - imho, the unique serial number of usb-sticks is in the hardware and unalterable. Means no one's able to change that. And, by definition, this serial# has to be unique in order to enable computers and the OS to tell them apart.

2 - it is possible to read the usb-stick from a stored procedure. Means, a single usb-stick could be put onto the server (with HFSQL) and can be read from all the client computers. The stored procedure just gives back its license file, decryption is done on the client then and therein you can have the number of licensed seats and immediately check whether the number of onnected users is exceeded or not. The stored procedure has to read the usb-stick's physical serial# too, that's a must! The physical serial# ist to be transferred to the client as well as the license file. Searching for the usb-stick on the server is much enhanced by using a unique volume name for the license-sticks. Having the usb-stick on the server means that no device in the networks needs another usb-stick - one of the many points against the use of dongles.

3 - yes, of course, the serial number of the usb-stick has to be contained within the encrypted license file.

4 - the client computer just checks the decrypted serial# against the hardware serial# from the stick. However, make check-sum(s) using a secret algorithm over the license info and add that to the license file as well. Even if the unthinkable happens and they would be able to decrypt the licence info on their own, they wouldn't be able to make their own stick / license file because they don't know the algorithm for calculating the check sum(s).


5 - if the client's usb-stick becomes defective you can let them choose/buy their own empty stick and let a small program read the serial# of it and write the unique volume-id to it. Using that you could send them a new license file by e-mail. It's up to you to manage the sending back of the usb-stick. If you enclose the client's name in the license file and show it on each client's first window, no one will dare to hand it over to another company.
Posté le 31 mars 2014 - 17:41
Quote
JP
Ultimately the code can also be hacked to prevent the dongle call, or the phone-home, or the hard disk serial number read, etc. This is time consuming but certainly all possible.
I think this is not that easy because WD seems to calculate some kind of CRC or something similar so modigying the EXE renders it useless!

I tried to protect my software using the famous Enigma Protector but could not as Enigma Protector is modifying the EXE in subtle way to inject protection code into it. But the moment you protect any EXE created by WD that particular EXE stops loading and starts crashing.

Just my two cents. :)

Yogi Yang
Posté le 01 avril 2014 - 17:09
Hi Folks - thank you very much for your thoughts! :cheers:

@ JP:
Your questions are certainly very relevant to the issue at hand.
Quote

1) What are you trying to protect? -> Business Rules, App-Logic, Process Flow, Code, etc.. In a general way: to prevent the use of the app without paying for it.

2) From who are you trying to protect it? -> the average Admin or Developer, in fact from anybody short of the hackers form the CCC ;-)

3) For how long do you wish the protection to last? -> since the items mentioned in answer #1 do not expire over the lifespan of he app; for, say, 20 years?

According to my research, it seems to be very difficult to hack a usb-stick's ID without destroying it.

@ Guenter:
Thaks for this very detailed list of things to check and do.
Never thought to include a stored procedure on the server side! Only the part in Item #4 I didn't get. Are you talking about making a hashed string out of a concatenated string consisting of, say, usb-ID - program version - name of customer - xyz by using one of the hash functions and a secret salt phrase?

@ Yogi:
Thats what I gathered from my research as well. One source said, that if you try to alter a stick's ID, you practically turn it into a brick. Often this ID seems to be written into the firmware. Or so they say...
But by using Guenter's suggestion above, I suspect that hacking the stick alone won't do them any good...

Thanks for your input on this!
Posté le 02 avril 2014 - 11:26
Sorry to say, but it is not that much trouble to alter the ID of an USB-stick.

I'm sometimes involved in forensic investigations (not as a suspect!) and therefore has some interest in this domain. As this blogspot tells it more detailed than I can do ... http://digfor.blogspot.be/2012/04/usb-flash-drive-serial-numbers-unique.html

Of course, it is a matter of hiding how you protect your software, as this might take the investigating user/developer a long time to find out and they might give it up before even finding out how the protection works.

Our commercial software (at this moment not in Windev) is protected by dongles since 1996. Each year, with a necessary update, we change the way we adress the dongle. So, if someone pays for a 'dongle-replacement-software/hack' he has to do that year after year and those hacks do not come cheap.

Yes, the dongles are not cheap, but unless you oblige your software/user to contact your server at least once a month (like Adobe) it is a proven way to limit piracy
Posté le 06 avril 2014 - 18:16
Hi Rudolph,

First of all: Sorry for me being somewhat late for the show - only by coincidence did I see that you answered to my thread which I made on the mysnip forum. Obviously your contribution was not replicated over from here, where I roam only very seldomly...

Thanks for your insight into this matter! I will peruse the link you provided.

Well, it probably depends on the price of the software, if - like you say - those hacks are not cheap, this will probably be more expensive than buying a licnec from me, hopefully, cross fingers :o ..

Regards

Charles
Posté le 24 avril 2015 - 00:19
Charles...
What I did long time ago when I used to work with Clarion, I peek memory at address hex FE00:0 and pick up the rom bios serial number and in the address FFFF:5 the rom bios date.
With this information and the hard disk label it is pretty hard to have 2 computers with same information.

Hope work for you...
Francisco Estrada
ConstruData Mexico