 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sat Oct 08, 2005 5:57 pm Post subject: SW copy protection |
|
|
Here is a "proof of concept" script providing SW copy protection. It needs the SafeSW.ini file with the user information and an unlock code, without it the script request registration and exits. The unlock code is computed by the same process at the provider of the SW (AuthData), and it has to be emailed back to the user.
1. To protect the code the AHK script has to be compiled to an executable with ahk2exe, which is part of the AHK distribution. To prevent de-compilation a (good) password has to be provided. This way the program runs normally, but an attacker would have difficulties modifying the program or getting out secrets (keys).
2. Collect some data specific to the target machine. For simplicity we use the following environment variables:
COMPUTERNAME
HOMEPATH
USERNAME
PROCESSOR_ARCHITECTURE
PROCESSOR_IDENTIFIER
PROCESSOR_LEVEL
PROCESSOR_REVISION
AHK built in variables:
A_OSVersion
A_OSType
These should not change at OS updates or changing the network environment.
In addition one can use disk volume identifiers by running the consol command VOL > info.txt:
Volume in drive C has no label.
Volume Serial Number is 24B5-2345
The MAC (Media Access Controller) address of the network cards can be used, too, by Getmac /NH >> info.txt:
00-20-30-F0-F1-F2 Media disconnected
…
(To be safe only the first 17 characters should be used, the MAC of the first network card.)
Instead of saving this data in a temporary file, one can use CMDret - return output from console programs [DLL version]
3. Having the machine/user specific data, we hash them all (Message Authentication Code = MAC with key 0), so no confidential data can be retrieved from it (for privacy concerns) and everybody can verify that no user secret is hidden in there. This is called the PC fingerprint. We ask the user to register the program via email, with the PC fingerprint and with a username and valid return email address, where we would send the unlock code.
4. We generate an unlock code from the data and send the whole SafeSW.ini file back to the user. S/he saves it into the script's working directory. At startup the program verifies if the user info, the PC fingerprint and the unlock code match. If not, it asks for registering the SW, otherwise it starts working.
Fingerprint = MAC(0_key; PC_data)
Registration_data = Username, Email, Fingerprint → emailed for registration
Authentication_data = Username, Email, MAC(secret_key, Username, Email, Fingerprint) ← emailed back from registration site
5. Operation
- If no or invalid format Authentication_data: Request registration, Exit
- Retrieve PC_data, Username, Email (from stored Authentication_data)
- Compute MAC(secret_key; Username, Email, Fingerprint)
- If invalid Authentication_data in the SafeSW.ini file: Request registration, Exit
- Else: display Username, Email; Start working
- Periodically re-compute Fingerprint, at change: Exit.
6. SafeSW.ini
It contains the following information:
[Registration]
User = Laszlo Hars
Email = Laszlo@Hars.US
UnlockCode = d0e8fd5f48edbc00
7. Notes
A malicious user could change the environment variables before the program starts, but it prevents normal operation, so he has to change it back. The periodic check of the PC fingerprint should make this attack more difficult.
MAC was used with key 0 for the Fingerprint, so users could verify the information sent for registration does not contain their secrets. A general, un-keyed hash is safer, as it is harder in the wrong PC to modify just one environmental variable to get a desired Fingerprint. We used MAC for simplicity.
There is more information that can be included in the machine specific data, like the physical serial number of the primary disk, the BIOS version, checksum, etc. You can make the sample script arbitrarily complex.
Some random, secret info can be written at installation somewhere hidden on the disk (e.g. in the registry) and it could be read back. (It is easy to catch the writing action, so this does not look very secure.) This random number could modify the executable itself, but it is complicated by the need of re-encrypting the code.
It is still possible to disassemble the program, and read the secret keys, but it is hard. Stronger protection is possible, but things would soon get very complicated. | Code: | ; AutoHotkey Version: 1.0.39+
; Language: English
; Platform: Win2000/XP
; Author: Laszlo Hars <www.Hars.US>
; Function: SW copy protection
k0 = 0x11111111 ; 128-bit secret key (example)
k1 = 0x22222222
k2 = 0x33333333
k3 = 0x44444444
l0 = 0x12345678 ; 64- bit 2nd secret key (example)
l1 = 0x12345678
m0 = 0x87654321 ; 64- bit 3rd secret key (example)
m1 = 0x87654321
IniFile = SafeSW.ini
GoSub CheckAuth
SetTimer CheckAuth,1000
MsgBox,,,This SW is registered to`n%User% at %Email%,4
MsgBox OK ; add your code here
Sleep 10000 ; add your code here
ExitApp
;---- End autoexecute secsion ----;
CheckAuth:
IniRead User, %IniFile%, Registration, User
IniRead Email,%IniFile%, Registration, Email
IniRead Code, %IniFile%, Registration, UnlockCode
PCdata = %COMPUTERNAME%%HOMEPATH%%USERNAME%%PROCESSOR_ARCHITECTURE%%PROCESSOR_IDENTIFIER%
PCdata = %PCdata%%PROCESSOR_LEVEL%%PROCESSOR_REVISION%%A_OSType%%A_OSVersion%%Language%
Fingerprint := XCBC(Hex(PCdata,StrLen(PCdata)), 0,0, 0,0,0,0, 1,1, 2,2)
Together = %User%%Email%%Fingerprint%
AuthData := XCBC(Hex(Together,StrLen(Together)), 0,0, k0,k1,k2,k3, l0,l1, m0,m1)
If (User="Error" || Email="Error" || Code <> AuthData)
{
S =
( LTrim
To: Registration@MyOwn.com
Username = <enter your full name here>
Your email address = <where you want the unlock code sent>
PC Fingerprint = %Fingerprint%
)
ClipBoard = %S%
MsgBox Please Register! Email the following information`n`n%S%`n`n(it has been copied to the ClipBoard)
ExitApp
}
Return
;---- Crypto functions ----;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TEA cipher ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Block encryption with the TEA cipher
; [y,z] = 64-bit I/0 block
; [k0,k1,k2,k3] = 128-bit key
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TEA(ByRef y,ByRef z, k0,k1,k2,k3)
{ ; need SetFormat Integer, D
s = 0
d = 0x9E3779B9
Loop 32 ; could be reduced to 8 for speed
{
k := "k" . s & 3 ; indexing the key
y := 0xFFFFFFFF & (y + ((z << 4 ^ z >> 5) + z ^ s + %k%))
s := 0xFFFFFFFF & (s + d) ; simulate 32 bit operations
k := "k" . s >> 11 & 3
z := 0xFFFFFFFF & (z + ((y << 4 ^ y >> 5) + y ^ s + %k%))
}
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; XCBC-MAC ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; x = long hex string input
; [u,v] = 64-bit initial value (0,0)
; [k0,k1,k2,k3] = 128-bit key
; [l0,l1] = 64-bit key for not padded last block
; [m0,m1] = 64-bit key for padded last block
; Return 16 hex digits (64 bits) digest
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
XCBC(x, u,v, k0,k1,k2,k3, l0,l1, m0,m1)
{
Loop % Ceil(StrLen(x)/16)-1 ; full length intermediate message blocks
XCBCstep(u, v, x, k0,k1,k2,k3)
If (StrLen(x) = 16) ; full length last message block
{
u := u ^ l0 ; l-key modifies last state
v := v ^ l1
XCBCstep(u, v, x, k0,k1,k2,k3)
}
Else { ; padded last message block
u := u ^ m0 ; m-key modifies last state
v := v ^ m1
x = %x%100000000000000
XCBCstep(u, v, x, k0,k1,k2,k3)
}
Return Hex8(u) . Hex8(v) ; 16 hex digits returned
}
XCBCstep(ByRef u, ByRef v, ByRef x, k0,k1,k2,k3)
{
StringLeft p, x, 8 ; Msg blocks
StringMid q, x, 9, 8
StringTrimLeft x, x, 16
p = 0x%p%
q = 0x%q%
u := u ^ p
v := v ^ q
TEA(u,v,k0,k1,k2,k3)
}
Hex8(i) ; 32-bit integer -> 8 hex digits
{
format = %A_FormatInteger% ; save original integer format
SetFormat Integer, Hex
i += 0x100000000 ; convert to hex, set MS bit
StringTrimLeft i, i, 3 ; remove leading 0x1
SetFormat Integer, %format% ; restore original format
Return i
}
Hex(ByRef b, n=0) ; n bytes data -> stream of 2-digit hex
{ ; n = 0: all (SetCapacity can be larger than used!)
format = %A_FormatInteger% ; save original integer format
SetFormat Integer, Hex ; for converting bytes to hex
m := VarSetCapacity(b)
If (n < 1 or n > m)
n := m
Loop %n%
{
x := 256 + *(&b+A_Index-1) ; get byte in hex, set 17th bit
StringTrimLeft x, x, 3 ; remove 0x1
h = %h%%x%
}
SetFormat Integer, %format% ; restore original format
Return h
} |
Last edited by Laszlo on Sun Oct 09, 2005 5:33 am; edited 1 time in total |
|
| Back to top |
|
 |
Atomhrt
Joined: 02 Sep 2004 Posts: 124 Location: Sunnyvale
|
Posted: Sun Oct 09, 2005 1:18 am Post subject: |
|
|
Weird. I did kind of a similar thing just two days ago. I really wanted to prevent a users ini file that contained some info about their account (not passwords or anything like that) from being used by someone else. One of the things that I did was save some info about the users environment to the ini file (computer name was one of them), but in encrypted format. This prevents anyone from knowing what it is in plain text. Then when the program starts up, it verifies that its running on the machine that it was first authenticated on.
What you've done looks pretty cool. I know that I will be using it soon. _________________ I am he of whom he speaks! |
|
| Back to top |
|
 |
JohnL
Joined: 04 Oct 2005 Posts: 35
|
Posted: Sun Oct 09, 2005 3:39 am Post subject: |
|
|
I hate to ask, simply because this code is so far advanced from anything I could ever make, but could you please write a short script for creating the unlock code?
also, in this line there is a spelling error:
If (User="Error" || Eamil="Error" || Code <> AuthData)
I think I speak for everyone when I say... wow.. what a great contribution for the community. Thanks! |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sun Oct 09, 2005 5:31 am Post subject: |
|
|
I fixed in the original post a couple of bugs. Thanks, JohnL!
To generate the SafeSW.ini file replace the code between the line IniFile = ... and ExitApp with the following: | Code: | InputBox User, User, Enter the User's name,, 220,140
InputBox Email,Email, Enter the User's Email,, 220,140
InputBox FGprt,FGprt, Enter the PC Fingerprint,,220,140
Together = %User%%Email%%FGprt%
Auth := XCBC(Hex(Together,StrLen(Together)), 0,0, k0,k1,k2,k3, l0,l1, m0,m1)
IniWrite %User%, %IniFile%, Registration, User
IniWrite %Email%,%IniFile%, Registration, Email
IniWrite %Auth%, %IniFile%, Registration, UnlockCode | You can remove the CheckAuth subroutine, too, but it does not matter. |
|
| Back to top |
|
 |
Bonzo Guest
|
Posted: Mon Oct 17, 2005 4:31 am Post subject: I would skip the HardDrive test... |
|
|
Hi,
All very cool, but I would skip the Hard Drive test... of all the computers I've owned, every single one of them, had a new hard drive installed at one point.
I would be very annoyed (as an end customer), if my Software didn't work, after a clean install.
Just my 2 cents. |
|
| Back to top |
|
 |
Thalon
Joined: 12 Jul 2005 Posts: 633
|
Posted: Mon Oct 17, 2005 7:00 am Post subject: |
|
|
I think that's the post I was looking for!
I didn't read the code, only description but it looks like that what I need!
Big thanks to Laszlo (and to Bonzo who put the topic on top )!
@Bonzo
I think this way of protecting is very personal, so it wouldn't be hard to tell the user that he has to re-register the programm after changing hardware!
THX!
Thalon |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Mon Oct 17, 2005 3:26 pm Post subject: |
|
|
The more information on the user's system we include in the PC fingerprint, the more often s/he needs to re-register the SW. Network cards get also replaced or new adapters added, the original disk could become secondary, when a larger one is installed, BIOS can be updated, etc. Using fewer pieces of configuration data makes the copy protection easier to break. I think the information used in the original post represent a good security/convenience tradeoff, and also high speed, simple code.
Another variation of the theme is when the user first receives (downloads) the compiled script, without the code doing the useful work. In response of the registration we send back the fully functional program with the information User, Email and UnlockCode hard coded. The original setup program then can be deleted. This way there is no need for the .ini file, but our email response has to contain a large attachment. |
|
| Back to top |
|
 |
hotControler
Joined: 07 Nov 2005 Posts: 10 Location: Germany
|
Posted: Wed Nov 09, 2005 5:50 pm Post subject: |
|
|
Laszlo, thanks for this great solution - you are a genious!
I am developing a somewhat bigger program and want to share it.
But I definitely cannot give away the source by now, only the exe file (too much nights without getting sleep and too much justified complaints
by my family members). I would like to know, how many people still use it after a period of 90 days.
So I want to ask your permission to integrate this solution in my script.
Of course I could give credits to you, in whatever form you want
(in the registration-Gui, in the email with the code, in the documentaion, ...) |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Wed Nov 09, 2005 6:42 pm Post subject: |
|
|
| Whatever I post in the AHK forum is FREE, you can use it without any restriction, but I cannot guarantee anything about the scripts, either. I would be glad if you give me credit for the copy protection scheme in the documentation (my website is in my AHK profile). |
|
| Back to top |
|
 |
hotControler
Joined: 07 Nov 2005 Posts: 10 Location: Germany
|
Posted: Wed Nov 09, 2005 8:34 pm Post subject: |
|
|
Thank you!
I expected an answer like that, but anyway, I felt bad to use it without your
explicit permission.
The credits will be given, and I hope, my program will be of some use for you too, so I can give something back. |
|
| Back to top |
|
 |
Guest
|
Posted: Mon Jul 17, 2006 12:25 pm Post subject: |
|
|
so when i get the persons info sent to my email
do i edit the .ini file or something please explian how i edit it |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Mon Jul 17, 2006 7:13 pm Post subject: |
|
|
| As described above, you need a second version of the script, with the replacement code. You run it, enter (copy & paste) the user information you received via email, and it creates the ini file for you. Its path\name is assigned to "IniFile". |
|
| Back to top |
|
 |
i3egohan
Joined: 18 Jul 2006 Posts: 403
|
Posted: Tue Jul 18, 2006 11:20 am Post subject: |
|
|
| got it thanks nice work |
|
| Back to top |
|
 |
HCProfessionals
Joined: 18 Jun 2007 Posts: 166
|
Posted: Mon Jun 25, 2007 7:04 pm Post subject: |
|
|
| I'm just not understanding the 2nd part of this, how do i create the ini file and the location of it, lol? |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Mon Jun 25, 2007 8:31 pm Post subject: |
|
|
| This post explains how you generate the personalized ini file. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|