Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

SW copy protection


  • Please log in to reply
305 replies to this topic
sweety
  • Guests
  • Last active:
  • Joined: --
can someone explain to me hoe it works again?
which 2 scripts do i need?
and how do i put is in the script? can't understand it for some reason :oops:

sweety
  • Guests
  • Last active:
  • Joined: --
hi friends! finally i got it to work :)

one more question (even if my first one wasen't answerde) how secure is it??

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Hard to put a measure on it.
- The PC signature can be faked, by setting environment variables, user names, OS versions to the same value as they are in another computer. This prevents normal operation, so it has to be reversed, and set again in succession, to have the right values when the script asks about them. The necessary steps can be automated in another AHK script, but writing and debug it would take weeks of hard work, and the PC would periodically stop, which is annoying.
- The code can be reverse engineered, but it would require to run it in a debugger, single step over large portions of the code. It can be done by an expert in a couple of weeks hard work.
- The used xTEA cipher is pretty secure, but in theory, someone can break it. I guess it would take months and years of hard work.

sweety
  • Guests
  • Last active:
  • Joined: --
thx for your answer and the code Laszlo.

Murp-e
  • Members
  • 531 posts
  • Last active: Sep 27 2011 11:44 AM
  • Joined: 12 Jan 2007
I have had some really odd experiences when trying to figure out this SW Protection Scheme.

1. The problems started already when I copy/pasted the code to Notepad++. It gave me syntax errors on virtually every line of code, I had to remove the spaces infront of every codeline for Notepadd++ and the AHK interpreter to recognize the lines as valid code.

2. The If... end if braces{} weren't properly recognized.

3. A bunch of lines in the code seem to be missing commas (,) such as these:
GoSub    CheckAuth
SetTimer CheckAuth,1000
IniRead User, %IniFile%, Registration, User
Loop % Ceil(StrLen(x)/16)-1
4. After trying to iron out all of these oddities, I have yet to create a working script file which will generate a fingerprint which is something other than 0000000000000000. The PCData variable works fine and holds valid data, but the ensuing fingerprint is bogus.

Surely there are some relatively simple explanations to some of this. I'd be mighty greatfull for some help. Also, perhaps someone could compile a working script file and send it my way to check if the returned fingerprint is valid.

Thanks in advance.

Murp-e
  • Members
  • 531 posts
  • Last active: Sep 27 2011 11:44 AM
  • Joined: 12 Jan 2007
Well I definetly found the biggest source to my problems, phpBB's "code copy" function. It's really weird. When I use the copy button and paste the code into notepad it looks fine. But when I save, the contents of the file go completely weird, all line feeds are screwed and the code doesn't work.

If I manually scroll and copy/paste the code, then everything worked, the script file created what seems to be a legitimate fingerprint and the other script file created what seems to be a legitimate auth code. I think it's all good then.

Still curious as to why the copy function suddenly started to give me problems. Also still curious with regards to what seems to be an alternative syntax with the first comma.

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
This is excellent!

I intend to convert it to an include file, with nicely wrapped functions.
Will post here if I manage to do something nice, and if someone is interested.

Laszio - can you please tell me what is the purpose of the additional timer call
SetTimer CheckAuth,1000

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

what is the purpose of the additional timer call
SetTimer CheckAuth,1000

This version only checks directory names, environment variables, etc., (that is, no HW, like processor ID), so an attacker can temporarily change them to the values of another PC, where the protected SW was registered, to pass the authenticity check. These changes prevent normal work on the PC, so he has to undo them. The timer, therefore, checks periodically if the PC fingerprint is still OK.

You could make these checks unpredictable if (before return) the subroutine CheckAuth sets itself to be activated again after a random period of time, e.g. between 100 and 2000 ms. It should help against a cheater script, which changes the above variables once in a second, and then changes them back.

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
I see, so there is no other reason.

Lets face it - everything is crackable, and usually qith ease.

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
Ok,

As promised, I have wrapped the nice concept by Laszlo into something I can use as an include file.

This is just the first version, and was not thoroughly tested, so if you recognize bugs, let me know.

There are four functions in this version:

SWP_Initialize( [ secret1, secret 2, ... , secret 8 ] )
Fingerprint := SWP_GetPcFingerprint()
UserOK := SWP_IsUserAuthenticated( username, email, key )
Key := SWP_GenerateKey( username, email, fingerprint )


I have also included an autoexecute tester, so just copy and run

;-------------------------------------------------------------------------------
;
; Software Protection Library 0.10
; 
; Original Code:    Laszlo Hars <www.Hars.US>
; Library Version:  Icarus
;
; Original proof of concept by Laszlo, taken from AutoHotkey Forum at
; http://www.autohotkey.com/forum/viewtopic.php?t=5763&postdays=0&postorder=asc&start=0
;
;
; Functions in this version
; 
;   SWP_Initialize( [ secret1, secret 2, ... , secret 8 ] )
;   Fingerprint := SWP_GetPcFingerprint()
;   UserOK      := SWP_IsUserAuthenticated( username, email, key )
;   Key         := SWP_GenerateKey( username, email, fingerprint )
;
;-------------------------------------------------------------------------------


;-------------------------------------------------------------------------------
; TESTER - Comment or delete this tester when including the file
;



; Initialize the required globals
;----------------------------------------
SWP_Initialize()        ; May be called with up to 8 secret keys


; Get a hardware fingerprint
;----------------------------------------
Fingerprint := SWP_GetPcFingerprint()
MsgBox 32,,Your computer ID is`n%Fingerprint%


; Generate a license key for this user
;----------------------------------------
Username    := "Icarus"
Email       := "[email protected]"
Key         := SWP_GenerateKey( Username, Email, Fingerprint )
MsgBox 32,,Your registration details are:`nUser:`t%Username%`nEmail:`t%Email%`nKey:`t%Key%


; Check if a user's registration code is ok
;----------------------------------------
;Key := "some invalid key by the user"                      ; Uncomment to test
UserOK      := SWP_IsUserAuthenticated( Username, Email, Key )
If( UserOK )
    MsgBox 32,OK,User is authenticated
Else
    MsgBox 16,INVALID,User is NOT authenticated`n%Username%`n%Email%`n%Key%
    
    
Return



;
; END OF TESTER
;-------------------------------------------------------------------------------




;-------------------------------------------------------------------------------
; API Functions
;-------------------------------------------------------------------------------
;  
; SWP_Initialize( [ secret1, secret 2, ... , secret 8 ] )
; Fingerprint := SWP_GetPcFingerprint()
; UserOK      := SWP_IsUserAuthenticated( username, email, key )
; Key         := SWP_GenerateKey( username, email, fingerprint )
;
;-------------------------------------------------------------------------------
SWP_Initialize( mk0=0x11111111, mk1=0x22222222, mk2=0x33333333, mk3=0x44444444
    ,ml0=0x12345678, ml1=0x12345678, mm0=0x87654321, mm1=0x87654321 ) {
    
    Global

    k0 := mk0                  ; 128-bit secret key (example)
    k1 := mk1
    k2 := mk2
    k3 := mk3
    
    l0 := ml0                  ; 64- bit 2nd secret key (example)
    l1 := ml1
    
    m0 := mm0                  ; 64- bit 3rd secret key (example)
    m1 := mm1

}


SWP_GetPcFingerprint() {
    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)
    Return Fingerprint
}

SWP_GenerateKey( username, email, fingerprint ) {
    Global k0,k1,k2,k3,l0,l1,m0,m1
    
    If( not k0 ) {
        MsgBox 16,Error,Error in SWP_GenerateKey - values are not initialized.`nPlease call SWP_Initialize() first.
        Return -1
    }
        
    Together = %username%%email%%fingerprint%
    Auth := XCBC(Hex(Together,StrLen(Together)), 0,0, k0,k1,k2,k3, l0,l1, m0,m1)
    Return Auth
}


SWP_IsUserAuthenticated( username, email, key ) {
    Global k0,k1,k2,k3,l0,l1,m0,m1
    
    If( not k0 ) {
        MsgBox 16,Error,Error in SWP_IsUserAuthenticated - values are not initialized.`nPlease call SWP_Initialize() first.
        Return -1
    }

    Fingerprint := SWP_GetPcFingerprint()
    Together = %username%%email%%Fingerprint%

    AuthData := XCBC(Hex(Together,StrLen(Together)), 0,0, k0,k1,k2,k3, l0,l1, m0,m1)
    
    Return Key=AuthData
}




;-------------------------------------------------------------------------------
; Internal Functions by Laszlo
;-------------------------------------------------------------------------------

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 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
}


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
This definitely makes the concept easier to use. Thanks for sharing your work!

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
One more thing to consider: Instead of using the TEA cipher for hashing, one could use SHA-1. The base CSP in all Windows versions > 95 supports MD5 and SHA-1. The details are here, with the right context. It makes the script smaller and faster.

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
Oh... - I am good with the If Elses, I'll leave the ciphering to you... :)

I will take a look but I doubt if I will have enough courage to touch your code.

(of course, feel free to copy the library code, replace whatever you want and repost - open source team work cant hurt anyone right?)

Murp-e
  • Members
  • 531 posts
  • Last active: Sep 27 2011 11:44 AM
  • Joined: 12 Jan 2007
Does this mean that the SW protection can be integrated just by adding an "#include swprotection.ahk" at the beginning of the code that needs to be protected? That would be a much cleaner way of doing things indeed!

(No comments to my questions above? Suppose it doesn't really matter anymore since I've got it working...)

Keep up the good work guys!

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005

Does this mean that the SW protection can be integrated just by adding an "#include swprotection.ahk" at the beginning of the code that needs to be protected?


Almost.

I left any GUI related and INI related functions out of this code, allowing any developer to do what they wish (e.g. to decide how the GUI looks, and where the INI is stored)

This library is purely internal - it can generate keys and generate PC fingerprint - the rest is up to you.

Adding some GUI wrappers to it should be simple enough - I intend to do some GUI for my own application, so if I decide to make it generic enough, I will post the GUI functions here as well.