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
guest3456
  • Guests
  • Last active:
  • Joined: --

Could this be adapted so instead of copying the fingerprint to the clipboard, It launches the default email client and creates a basic email.




from examples at bottom
http://www.autohotke...ommands/Run.htm

Run, mailto:[email protected]?subject=This is the subject line&body=This is the message body's text.


TomT
  • Guests
  • Last active:
  • Joined: --
@guest3456

Thank you. can I pass values from AHK to the Mailto ?
I'll have a look at the link you posted to the docs ! :lol:

frazks
  • Guests
  • Last active:
  • Joined: --
would it be possible to replicate guest3456 php code in JavaScript so no php server was needed ?

florinn
  • Members
  • 45 posts
  • Last active: Feb 13 2014 04:49 AM
  • Joined: 01 Mar 2010

It launches the default email client and creates a basic email.

This is relative. I do not use Outlook, Thunderbird, or any others. If you use it, it does not mean that everyone does.
Instead, I would think on a simple method to make your program upload the fingerprint on your server. Even they have a firewall, a popup should appear on any puter asking confirmation and access. They can be informed about this required step and most of them (the legal users) would agree to allow your program to access the internet. If I would download a hacked version, hell no lol.

guest3456, going open source is a big step that cannot be reversed. This is a subject for a completely different topic, but what would you earn? I never donated a single usd for scripts that I use, and trust me, Laszlo, SKAN, VxE, Tic or other hundreds of names here would deserve that. If we would talk about open source, then why breaking our brains lol.
Yes, you can decompile and avoid the .ini request, did not tried to decompile ahk yet, but am sure it is possible. But I think the bottom line is that it would be great to create a automated activation online based on fingerprints, with a single click on a "register" button. UrlDownloadToFile would do the rest, even if the activation script would be hosted on a personal server.

computerspazzz
  • Members
  • 22 posts
  • Last active: Mar 19 2012 08:33 PM
  • Joined: 25 May 2010
So im not sure if we are on the right track, but post to a php file should be easy... i didnt read it fully yet cause i havent gotten this to work yet, but seems easy:
http://www.autohotke...ss variable php

computerspazzz
  • Members
  • 22 posts
  • Last active: Mar 19 2012 08:33 PM
  • Joined: 25 May 2010
I modified and meshed some features to give a script that will submit the info given to a php, retrieve the activation key, input it, write the ini, and continue as expected. Ini will write to AppData folder, can be easily modified to go to the folder you want. Fully functional if you have webhosting that supports php.

WhateverYouCallYourApp.ahk:

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
Website := "http://www.yourwebsite.com/validate.php?code="	;This must be first, modify to match your website, the validate.php?code= part should remain the same unless you make the correct modifications in the php file.

SWP_Initialize( 0x81645732, 0x19573549 )    ; Up to 8 secret keys,
SWP_CheckRegistration( "My Application Name", "[email protected]" )    ; Modify this info to match your program

;The following would be your program

Gui, Add, Text,, Hello Here I am.
Gui, Add, Button,, Nothing
Gui, Add, Button, Default gExitApp, Exit
Gui, Show, x150 y150, Test App
return

ExitApp:
ExitApp

; End your program area.

;Shouldnt have to modify anything below here except the location of the ini file

; SWProtect-GUI.ahk
;-------------------------------------------------------------------------------
;
; Software Protection Library - GUI Implementation 0.11
;
; This library contains a simple set of GUI functions to allow easy
; implementation of a software protection, using a registration code and a
; computer fingerprint.
;
; Requires: SWProtect-Internal.ahk
;
; Original Code:        Laszlo Hars <www.Hars.US>
; Library/GUI Version:  Icarus
;
; AutoHotkey Forum Thread:
; http://www.autohotkey.com/forum/viewtopic.php?t=5763&postdays=0&postorder=asc&start=0
;
; USAGE 1:
;   1. Include this file in your script
;   2. In your loading sequence, call SWP_Initialize() then
;      SWP_CheckRegistration( "AppName", "DeveloperEmail" )
;      to check/ask for a valid registration.
;
; USAGE 2:
;   1. Include this file in a new script
;   2. Call SWP_Initialize() then SWP_ShowKeyGen() to activate a KeyGen dialog
;
; TODO:
;   - See if there is a way to use less global variables
;   - See if there is a way to avoid using a fixed GUI ID (currently, 20) and
;     instead pass it as an optional parameter. The reason why this is not
;     implemented like this is because we need to have 20GuiEscape: labels
;
;-------------------------------------------------------------------------------
#Include SWProtect-Internal.ahk
#Include http.ahk
;-------------------------------------------------------------------------------
; TESTER - Comment or delete this tester when including the file
;

/*

#SingleInstance Force
SetWorkingDir %A_ScriptDir%

; USAGE 1: Add this in a separate file, to have your own keygen
;-------------------------
SWP_Initialize( 0x81645732, 0x19573549 )   ; Up to 8 secret keys,
SWP_ShowKeyGen()
Return
;-------------------------


; USAGE 2: Add this in your loading sequence to check/ask for a valid registration
;-------------------------
SWP_Initialize( 0x81645732, 0x19573549 )    ; Up to 8 secret keys,
SWP_CheckRegistration( "My Application", "[email protected]" )     
;-------------------------



Msgbox The program continues here`n`n`n`n`n`n`n`n
Return

*/

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

;-------------------------------------------------------------------------------
; Main GUI Function
;-------------------------------------------------------------------------------

SWP_CheckRegistration( appName, developerEmail ) {
;
; Checks for the existence of a valid registration file.
; If registration is valid, it will return the control to the caller, otherwise
; it will show a registration GUI (with an option to the user to ask for a
; registration key) and will only resume normal operation if a valid
; registration code is entered.
;
; When a valid key is entered, the registration details will be saved in an INI
; file (default: Reg.ini) so that next time this function is called, it will be
; able to find the registration code on its own.
;
;-------------------------------------------------------------------------------
    Global SWP_AppName, SWP_IniFilename, SWP_DeveloperEmail, SWP_LicenseOK
   
    SWP_AppName        := appName
    SWP_IniFilename    = %A_AppData%\MyProg\Reg.ini		; Modify as needed for placement of the Reg.ini file.
	FileCreateDir %A_AppData%\MyProg		;Create folder for INI placement.
    SWP_DeveloperEmail := developerEmail
    SWP_LicenseOK      := false
   
    If( Not FileExist( iniFilename ) ) {
        SWP_ShowRegisterDialog( appName )
        Loop
            If( SWP_LicenseOK )     ; Loop will be broken by a valid license
                Break

    }
    Else {                          ; File exists, read registration data and validate
        SWP_ReadRegFile( iniFilename )
        Sleep 1000      ; This is here since the Reload in SWP_ReadRegFile
                        ; seem to still give the application to continue running
                        ; before it actually reloads.
                        ; Deleteing this launches the "The program continues"
                        ; msgbox
                        ; *** TODO: Can be fixed?

    }

}

SWP_ShowKeyGen() {
;
; This function shows a simple generator for registration numbers.
; Once the user has sent you his Computer ID, use this function to generate
; a valid registration key for this user+computer.
;
; The proper use of this function, is to create a separate ahk code, including
; this library, then calling this function.
;
; Note that you need to call SWP_Initialize with the same seed keys as in your
; SWP_CheckRegistration function BEFORE you call this function.
;
;-------------------------------------------------------------------------------
    Global SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Key, SwpGuiVal_Fingerprint
        ,SWP_GuiID
   
    SWP_GuiID := 20
    GuiID := SWP_GuiID
   
    Gui %GuiID%:Margin, 10, 10

    ; Top introduction text
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Text, x10 y10 w352 h22 center, Please enter user details:
    Gui %GuiID%:Font, s10 norm

    ; Text labels
    Gui %GuiID%:Add, Text, xp y+15 w135 h22 right section, % "Name/Company: "
    Gui %GuiID%:Add, Text, xp y+2  wp   hp  right        , % "Email Address: "
    Gui %GuiID%:Add, Text, xp Y+2  wp   hp  right        , % "Computer ID: "
    Gui %GuiID%:Add, Text, xp Y+2  wp   hp  right        , % "Key: "
   
    ; Edit fields
    Gui %GuiID%:Add, Edit, xs+137 ys  wp+64 hp vSwpGuiVal_Name
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Email
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Fingerprint
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp readonly center vSwpGuiVal_Key
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Groupbox, xs ys-20 w352 h126
   
    ; Buttons
    Gui %GuiID%:Add, Button, xs  y+10 w109   h24 gSWP_RegisterDialogCancel  , E&xit
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Button, x+2    yp   wp+20 hp  default gSWP_KeygenGenerate  , &Generate
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Button, x+2    yp   wp-20 h24 gSWP_KeygenOk, &Copy && Exit
   
    Gui %GuiID%:Show, w372, Registration Key Generator
}

;-------------------------------------------------------------------------------
; Other GUI Functions (you should generally avoid calling these functions)
;-------------------------------------------------------------------------------

SWP_ShowRegisterDialog( appName ) {
    Global SWP_GuiID        ; *** TODO: See if there is a way to have a dynamically
                            ; created 20GuiEscape labels, so we can pass GuiID as
                            ; an optional parameter to the function

    Global SWP_AppName, SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Key
   
    SWP_GuiID := 20
    GuiID := SWP_GuiID
   
    Gui %GuiID%:Margin, 10, 10

    ; Top introduction text
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Text, x10 y10 w352 h22 center, %appName% is not registered.
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Text, xp y+0 wp hp center, Please enter your registration details:

    ; Text labels
    Gui %GuiID%:Add, Text, xp y+15 w135 h22 right section, % "Name/Company: "
    Gui %GuiID%:Add, Text, xp y+2  wp   hp  right        , % "Email Address: "
;    Gui %GuiID%:Add, Text, xp Y+2  wp   hp  right        , % "Registration Code: "
   
    ; Edit fields
    Gui %GuiID%:Add, Edit, xs+137 ys  wp+64 hp vSwpGuiVal_Name
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Email
;   Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Key
    Gui %GuiID%:Add, Groupbox, xs ys-20 w352 h102
   
    ; Buttons
    Gui %GuiID%:Add, Button, xs  y+10 w268 h24 default gSWP_RegisterDialogGetKey    , &Get a Registration Key (Internet Required)
    Gui %GuiID%:Add, Button, x+2 yp   w90  h24 gSWP_RegisterDialogCancel    , E&xit
    Gui %GuiID%:Font, s10 bold
;	Gui %GuiID%:Add, Text, xp-250 yp+30, Have a registration key already? ->
;    Gui %GuiID%:Add, Button, xp+250 yp   w90  h24 gSWP_RegisterDialogOk, Register
   
    Gui %GuiID%:Show, w372, %appName% Registration
}

20GuiEscape:
20GuiClose:
SWP_RegisterDialogCancel:
    ExitApp
Return

SWP_RegisterDialogOk:
    Gui %SWP_GuiID%:Submit, NoHide
    If( SwpGuiVal_Name = "" or SwpGuiVal_Email = "" or SwpGuiVal_Key = "" )
        MsgBox 16,Invalid Registration, Invalid Registration.`nPlease check your input.`t
    Else If( Not SWP_IsUserAuthenticated( SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Key ) ) {
        MsgBox 16,Invalid Registration, Invalid Registration.`nPlease check your input.`t
    }
    Else {
        ; Registration ok, write to ini file and exit happily
        IniWrite %SwpGuiVal_Name%, %SWP_IniFilename%, Registration, Name
        IniWrite %SwpGuiVal_Email%, %SWP_IniFilename%, Registration, Email
        IniWrite %SwpGuiVal_Key%, %SWP_IniFilename%, Registration, Key
        MsgBox 64,Registration Accepted, Your registration was accepted and saved.`t`nThank you for using %SWP_AppName%.
        SWP_LicenseOK := true
        Gui %SWP_GuiID%:Destroy
    }   
Return

SWP_RegisterDialogOkAuto:
    If( Not SWP_IsUserAuthenticated( SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Key ) ) ; find these variables so we can set them upon post
	{
        MsgBox 16,Invalid Registration, Invalid Registration.`nCode Transfer Error`t
    }
    Else {
        ; Registration ok, write to ini file and exit happily
        IniWrite %SwpGuiVal_Name%, %SWP_IniFilename%, Registration, Name
        IniWrite %SwpGuiVal_Email%, %SWP_IniFilename%, Registration, Email
        IniWrite %SwpGuiVal_Key%, %SWP_IniFilename%, Registration, Key
        MsgBox 64,Registration Accepted, Your registration was accepted and saved.`t`nThank you for using %SWP_AppName%.
        SWP_LicenseOK := true
    }   
Return
;Dont lose this variable %SwpGuiVal_Fingerprint%
SWP_RegisterDialogGetKey:
    SWP_ShowGetKeyDialog()
		URL =%Website%%SwpGuiVal_Name%%SwpGuiVal_Email%%SwpGuiVal_Fingerprint%
;		MsgBox %URL%		;Enable when testing to check contents of variable
		length := httpQuery(SwpGuiVal_Key2,URL)
		varSetCapacity(SwpGuiVal_Key2,-1)
		SwpGuiVal_Key = %SwpGuiVal_Key2% ; Swap the key to another variable so that all spaces are trimmed off properly
;		MsgBox %SwpGuiVal_Key%	;Enable when testing to check contents of variable
		
	GoTo SWP_RegisterDialogOkAuto
Return

SWP_ShowGetKeyDialog() {
    Global SWP_GuiID, SWP_AppName, SwpGuiVal_Fingerprint, SwpGuiButton_Ok
        ,SWP_DeveloperEmail
	Gui %SWP_GuiID%:Submit
    ; Destroy
    Gui %SWP_GuiID%:Destroy
   
    ; Then rebuild
    SwpGuiVal_Fingerprint := SWP_GetPcFingerprint()
   
    GuiID := SWP_GuiID
    
    ;Instead of showing the GUI we will simply POST this to the PHP file.

    
    
;     %SwpGuiVal_Fingerprint% ;This is the var with fingerprint
    
}

SWP_GetDialogOk:
    Gui %SWP_GuiID%:Submit
    Clipboard := "Computer ID: " SwpGuiVal_Fingerprint
    MsgBox 64,Copied to Clipboard, Your Computer ID was copied to the clipboard.`nPlease send it along with your name and email address to`t`n%SWP_DeveloperEmail%.
    ExitApp
Return


SWP_ReadRegFile( iniFilename ) {
    Global SWP_LicenseOK
    IniRead Name, %iniFilename%, Registration, Name
    IniRead Email, %iniFilename%, Registration, Email
    IniRead Key, %iniFilename%, Registration, Key
    SWP_LicenseOK := false
    If( Not SWP_IsUserAuthenticated( Name, Email, Key ) ) {
        MsgBox 16,Invalid Registration, Your registration details seem to be invalid.`t`n
        FileDelete %iniFilename%
        Reload
    }
    SWP_LicenseOK := true
}

SWP_KeygenGenerate:
    Gui %SWP_GuiID%:Submit, NoHide
    SwpGuiVal_Key := SWP_GenerateKey( SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Fingerprint )
    GuiControl ,%SWP_GuiID%:,SwpGuiVal_Key,%SwpGuiVal_Key%
Return

SWP_KeygenOK:
    Gui %SWP_GuiID%:Submit, NoHide
    Clipboard =
        ( LTRIM
            -----------------------------------
            Username: %SwpGuiVal_Name%
            Email:    %SwpGuiVal_Email%
            Key:      %SwpGuiVal_Key%
            -----------------------------------
        )
    Gui %SWP_GuiID%:Destroy

Return


;-------------------------------------------------------------------------------
; Revision History
;-------------------------------------------------------------------------------
/*

    0.11  2007 09 04
        - Added  : Keygen
        - Changed: Initialize function (secret seeds) now needs to be called
          separately prior to calling any of the other main GUI functions.
          This is done to allow different key generation for every software
          you develop.
          If this is not a requirement, the Initialize function can be put
          back into the two main GUI functions (only make sure you are using
          the same seeds)
       
    0.10  2007 09 03
        - First version



*/ 



; httpQuery-0-3-5.ahk
httpQuery(byref Result, lpszUrl, POSTDATA="", HEADERS="")
{   ; v0.3.5 (w) Sep, 8 2008 by Heresy & derRaphael / zLib-Style release
   ; updates Aug, 28 2008   
   ; currently the verbs showHeader, storeHeader, and updateSize are supported in httpQueryOps
   ; in case u need a different UserAgent, Proxy, ProxyByPass, Referrer, and AcceptType just
   ; specify them as global variables - mind the varname for referrer is httpQueryReferer [sic].
   ; Also if any special dwFlags are needed such as INTERNET_FLAG_NO_AUTO_REDIRECT or cache
   ; handling this might be set using the httpQueryDwFlags variable as global
   global httpQueryOps, httpAgent, httpProxy, httpProxyByPass, httpQueryReferer, httpQueryAcceptType
       , httpQueryDwFlags
   ; Get any missing default Values
   defaultOps =
   (LTrim Join|
      httpAgent=AutoHotkeyScript|httpProxy=0|httpProxyByPass=0|INTERNET_FLAG_SECURE=0x00800000
      SECURITY_FLAG_IGNORE_UNKNOWN_CA=0x00000100|SECURITY_FLAG_IGNORE_CERT_CN_INVALID=0x00001000
      SECURITY_FLAG_IGNORE_CERT_DATE_INVALID=0x00002000|SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE=0x00000200
      INTERNET_OPEN_TYPE_PROXY=3|INTERNET_OPEN_TYPE_DIRECT=1|INTERNET_SERVICE_HTTP=3
   )
   Loop,Parse,defaultOps,|
   {
      RegExMatch(A_LoopField,"(?P<Option>[^=]+)=(?P<Default>.*)",http)
      if StrLen(%httpOption%)=0
         %httpOption% := httpDefault
   }

   ; Load Library
   hModule := DllCall("LoadLibrary", "Str", "WinINet.Dll")

   ; SetUpStructures for URL_COMPONENTS / needed for InternetCrackURL
   ; http://msdn.microsoft.com/en-us/library/aa385420(VS.85).aspx
   offset_name_length:= "4-lpszScheme-255|16-lpszHostName-1024|28-lpszUserName-1024|"
                  . "36-lpszPassword-1024|44-lpszUrlPath-1024|52-lpszExtrainfo-1024"
   VarSetCapacity(URL_COMPONENTS,60,0)
   ; Struc Size               ; Scheme Size                  ; Max Port Number
   NumPut(60,URL_COMPONENTS,0), NumPut(255,URL_COMPONENTS,12), NumPut(0xffff,URL_COMPONENTS,24)
   
   Loop,Parse,offset_name_length,|
   {
      RegExMatch(A_LoopField,"(?P<Offset>\d+)-(?P<Name>[a-zA-Z]+)-(?P<Size>\d+)",iCU_)
      VarSetCapacity(%iCU_Name%,iCU_Size,0)
      NumPut(&%iCU_Name%,URL_COMPONENTS,iCU_Offset)
      NumPut(iCU_Size,URL_COMPONENTS,iCU_Offset+4)
   }

   ; Split the given URL; extract scheme, user, pass, authotity (host), port, path, and query (extrainfo)
   ; http://msdn.microsoft.com/en-us/library/aa384376(VS.85).aspx
   DllCall("WinINet\InternetCrackUrlA","Str",lpszUrl,"uInt",StrLen(lpszUrl),"uInt",0,"uInt",&URL_COMPONENTS)

   ; Update variables to retrieve results
   Loop,Parse,offset_name_length,|
   {
      RegExMatch(A_LoopField,"-(?P<Name>[a-zA-Z]+)-",iCU_)
      VarSetCapacity(%iCU_Name%,-1)
   }
   nPort:=NumGet(URL_COMPONENTS,24,"uInt")
   
   ; Import any set dwFlags
   dwFlags := httpQueryDwFlags
   ; For some reasons using a selfsigned https certificates doesnt work
   ; such as an own webmin service - even though every security is turned off
   ; https with valid certificates works when
   if (lpszScheme = "https")
      dwFlags |= (INTERNET_FLAG_SECURE|SECURITY_FLAG_IGNORE_CERT_CN_INVALID
               |SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)

   ; Check for Header and drop exception if unknown or invalid URL
   if (lpszScheme="unknown") {
      Result := "ERR: No Valid URL supplied."
      Return StrLen(Result)
   }

   ; Initialise httpQuery's use of the WinINet functions.
   ; http://msdn.microsoft.com/en-us/library/aa385096(VS.85).aspx
   hInternet := DllCall("WinINet\InternetOpenA"
                  ,"Str",httpAgent,"UInt"
                  ,(httpProxy != 0 ?  INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_DIRECT )
                  ,"Str",httpProxy,"Str",httpProxyBypass,"Uint",0)

   ; Open HTTP session for the given URL
   ; http://msdn.microsoft.com/en-us/library/aa384363(VS.85).aspx
   hConnect := DllCall("WinINet\InternetConnectA"
                  ,"uInt",hInternet,"Str",lpszHostname, "Int",nPort
                  ,"Str",lpszUserName, "Str",lpszPassword,"uInt",INTERNET_SERVICE_HTTP
                  ,"uInt",0,"uInt*",0)

   ; Do we POST? If so, check for header handling and set default
   if (Strlen(POSTDATA)>0) {
      HTTPVerb:="POST"
      if StrLen(Headers)=0
         Headers:="Content-Type: application/x-www-form-urlencoded"
   } else ; otherwise mode must be GET - no header defaults needed
      HTTPVerb:="GET"   

   ; Form the request with proper HTTP protocol version and create the request handle
   ; http://msdn.microsoft.com/en-us/library/aa384233(VS.85).aspx
   hRequest := DllCall("WinINet\HttpOpenRequestA"
                  ,"uInt",hConnect,"Str",HTTPVerb,"Str",lpszUrlPath . lpszExtrainfo
                  ,"Str",ProVer := "HTTP/1.1", "Str",httpQueryReferer,"Str",httpQueryAcceptTypes
                  ,"uInt",dwFlags,"uInt",Context:=0 )

   ; Send the specified request to the server
   ; http://msdn.microsoft.com/en-us/library/aa384247(VS.85).aspx
   sRequest := DllCall("WinINet\HttpSendRequestA"
                  , "uInt",hRequest,"Str",Headers, "uInt",Strlen(Headers)
                  , "Str",POSTData,"uInt",Strlen(POSTData))

   VarSetCapacity(header, 2048, 0)  ; max 2K header data for httpResponseHeader
   VarSetCapacity(header_len, 4, 0)
   
   ; Check for returned server response-header (works only _after_ request been sent)
   ; http://msdn.microsoft.com/en-us/library/aa384238.aspx
   Loop, 5
     if ((headerRequest:=DllCall("WinINet\HttpQueryInfoA","uint",hRequest
      ,"uint",21,"uint",&header,"uint",&header_len,"uint",0))=1)
      break

   If (headerRequest=1) {
      VarSetCapacity(res,headerLength:=NumGet(header_len),32)
      DllCall("RtlMoveMemory","uInt",&res,"uInt",&header,"uInt",headerLength)
      Loop,% headerLength
         if (*(&res-1+a_index)=0) ; Change binary zero to linefeed
            NumPut(Asc("`n"),res,a_index-1,"uChar")
      VarSetCapacity(res,-1)
   } else
      res := "timeout"

   ; Get 1st Line of Full Response
   Loop,Parse,res,`n,`r
   {
      RetValue := A_LoopField
      break
   }
   
   ; No Connection established - drop exception
   If (RetValue="timeout") {
      html := "Error: timeout"
      return -1
   }
   ; Strip protocol version from return value
   RetValue := RegExReplace(RetValue,"HTTP/1\.[01]\s+")
   
    ; List taken from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
   HttpRetCodes := "100=Continue|101=Switching Protocols|102=Processing (WebDAV) (RFC 2518)|"
              . "200=OK|201=Created|202=Accepted|203=Non-Authoritative Information|204=No"
              . " Content|205=Reset Content|206=Partial Content|207=Multi-Status (WebDAV)"
              . "|300=Multiple Choices|301=Moved Permanently|302=Found|303=See Other|304="
              . "Not Modified|305=Use Proxy|306=Switch Proxy|307=Temporary Redirect|400=B"
              . "ad Request|401=Unauthorized|402=Payment Required|403=Forbidden|404=Not F"
              . "ound|405=Method Not Allowed|406=Not Acceptable|407=Proxy Authentication "
              . "Required|408=Request Timeout|409=Conflict|410=Gone|411=Length Required|4"
              . "12=Precondition Failed|413=Request Entity Too Large|414=Request-URI Too "
              . "Long|415=Unsupported Media Type|416=Requested Range Not Satisfiable|417="
              . "Expectation Failed|418=I'm a teapot (RFC 2324)|422=Unprocessable Entity "
              . "(WebDAV) (RFC 4918)|423=Locked (WebDAV) (RFC 4918)|424=Failed Dependency"
              . " (WebDAV) (RFC 4918)|425=Unordered Collection (RFC 3648)|426=Upgrade Req"
              . "uired (RFC 2817)|449=Retry With|500=Internal Server Error|501=Not Implem"
              . "ented|502=Bad Gateway|503=Service Unavailable|504=Gateway Timeout|505=HT"
              . "TP Version Not Supported|506=Variant Also Negotiates (RFC 2295)|507=Insu"
              . "fficient Storage (WebDAV) (RFC 4918)|509=Bandwidth Limit Exceeded|510=No"
              . "t Extended (RFC 2774)"
   
   ; Gather numeric response value
   RetValue := SubStr(RetValue,1,3)
   
   ; Parse through return codes and set according informations
   Loop,Parse,HttpRetCodes,|
   {
      HttpReturnCode := SubStr(A_LoopField,1,3)    ; Numeric return value see above
      HttpReturnMsg  := SubStr(A_LoopField,5)      ; link for additional information
      if (RetValue=HttpReturnCode) {
         RetMsg := HttpReturnMsg
         break
      }
   }

   ; Global HttpQueryOps handling
   if strlen(HTTPQueryOps)>0 {
      ; Show full Header response (usefull for debugging)
      if (instr(HTTPQueryOps,"showHeader"))
         MsgBox % res
      ; Save the full Header response in a global Variable
      if (instr(HTTPQueryOps,"storeHeader"))
         global HttpQueryHeader := res
      ; Check for size updates to export to a global Var
      if (instr(HTTPQueryOps,"updateSize")) {
         Loop,Parse,res,`n
            If RegExMatch(A_LoopField,"Content-Length:\s+?(?P<Size>\d+)",full) {
               global HttpQueryFullSize := fullSize
               break
            }
         if (fullSize+0=0)
            HttpQueryFullSize := "size unavailable"
      }
   }

   ; Check for valid codes and drop exception if suspicious
   if !(InStr("100 200 201 202 302",RetValue)) {
      Result := RetValue " " RetMsg
      return StrLen(Result)
   }

   VarSetCapacity(BytesRead,4,0)
   fsize := 0
   Loop            ; the receiver loop - rewritten in the need to enable
   {               ; support for larger file downloads
      bc := A_Index
      VarSetCapacity(buffer%bc%,1024,0) ; setup new chunk for this receive round
      ReadFile := DllCall("wininet\InternetReadFile"
                  ,"uInt",hRequest,"uInt",&buffer%bc%,"uInt",1024,"uInt",&BytesRead)
      ReadBytes := NumGet(BytesRead)    ; how many bytes were received?
      If ((ReadFile!=0)&&(!ReadBytes))  ; we have had no error yet and received no more bytes
         break                         ; we must be done! so lets break the receiver loop
      Else {
         fsize += ReadBytes            ; sum up all chunk sizes for correct return size
         sizeArray .= ReadBytes "|"
      }
      if (instr(HTTPQueryOps,"updateSize"))
         Global HttpQueryCurrentSize := fsize
   }
   sizeArray := SubStr(sizeArray,1,-1)   ; trim last PipeChar
   
   VarSetCapacity(result,fSize+1,0)      ; reconstruct the result from above generated chunkblocks
   Dest := &result                       ; to a our ByRef result variable
   Loop,Parse,SizeArray,|
      DllCall("RtlMoveMemory","uInt",Dest,"uInt",&buffer%A_Index%,"uInt",A_LoopField)
      , Dest += A_LoopField
     
   DllCall("WinINet\InternetCloseHandle", "uInt", hRequest)   ; close all opened
   DllCall("WinINet\InternetCloseHandle", "uInt", hInternet)
   DllCall("WinINet\InternetCloseHandle", "uInt", hConnect)
   DllCall("FreeLibrary", "UInt", hModule)                    ; unload the library
   return fSize                          ; return the size - strings need update via VarSetCapacity(res,-1)
}

And here is validate.php

<?php

\\ validate.php

SWP_Initialize(0x81645732,0x19573549);

$str=$_GET['code'];

$key=XCBC($str);
echo $key;

function XCBC($str)
   {
   global $str,$u,$v,$l0,$l1,$m0,$m1;
   $u=0;
   $v=0;
   $str = bin2hex($str);


   // full length intermediate message blocks
   $flimbs = ceil(strlen($str)/16)-1;

   for($i=0; $i<$flimbs; $i+=1)
      {
      XCBCstep();
      }
     

   if (strlen($str)==16)
      {
      $u = $u ^ $l0;               
      $v = $v ^ $l1;

      XCBCstep();
      }else{
      $u = $u ^ $m0;               
      $v = $v ^ $m1;

      $str = $str."100000000000000";

      XCBCstep();
      }


$u = dechex($u);
$v = dechex($v);
while (strlen($u) < 8) { $u='0'.$u; }
while (strlen($v) < 8) { $v='0'.$v; }

return $u.$v;




}

function XTEA()
   {
   global $u,$v,$key;
   $s = 0;
   $d = 0x9e3779b9;
   for($i=0; $i<32;$i++)
      {
      $u = _add($u ,_add($v << 4 ^ _rshift($v,5), $v) ^ _add($s,$key[$s & 3] ) );
      $s =  ($s + $d) ;
      $s= 0xffffffff & $s ;
      $v = _add($v ,_add($u << 4 ^ _rshift($u,5), $u) ^ _add($s,$key[_rshift($s, 11) & 3]));
      }
   return;
   }



function XCBCstep()
   {
   global $u,$v,$str;
   $p = substr($str,0,8);
   $q = substr($str,8,8);
   $str = substr($str,16);
   $p=hexdec($p);
   $q=hexdec($q);
   $u = $u ^ $p;
   $v = $v ^ $q;
   XTEA();
   return;
   }



function _add($i1, $i2) {
        $result = 0.0;
        foreach (func_get_args() as $value)
      {
           if (0.0 > $value) {
                $value -= 1.0 + 0xffffffff;
               }
               $result += $value;
           }


           // convert to 32 bits
           if (0xffffffff < $result || -0xffffffff > $result) {
                  $result = fmod($result, 0xffffffff + 1);
              }

           // convert to signed integer
           if (0x7fffffff < $result) {
               $result -= 0xffffffff + 1.0;
           } elseif (-0x80000000 > $result) {
                  $result += 0xffffffff + 1.0;
           }

           return $result;
          }


function hex2bin($h)
   {
     if (!is_string($h)) return null;
     $r='';
     for ($a=0; $a<strlen($h); $a+=2) { $r.=chr(hexdec($h{$a}.$h{($a+1)})); }
     return $r;
     }


function _rshift($integer, $n) {
        // convert to 32 bits
        if (0xffffffff < $integer || -0xffffffff > $integer) {
            $integer = fmod($integer, 0xffffffff + 1);
        }

        // convert to unsigned integer
        if (0x7fffffff < $integer) {
            $integer -= 0xffffffff + 1.0;
        } elseif (-0x80000000 > $integer) {
            $integer += 0xffffffff + 1.0;
        }

        // do right shift
        if (0 > $integer) {
            $integer &= 0x7fffffff;                     // remove sign bit before shift
            $integer >>= $n;                            // right shift
            $integer |= 1 << (31 - $n);                 // set shifted sign bit
        } else {
            $integer >>= $n;                            // use normal right shift
        }

        return $integer;
    }

function SWP_Initialize($mk0=0x11111111, $mk1=0x22222222, $mk2=0x33333333, $mk3=0x44444444 ,$ml0=0x12345678,$ml1=0x12345678,$mm0=0x87654321, $mm1=0x87654321)
{
   
    global $l0,$l1,$m0,$m1 ,$key;

    $key[0] = $mk0;                 
    $key[1] = $mk1;
    $key[2] = $mk2;
    $key[3] = $mk3;

   
    $l0 = $ml0;                 
    $l1 = $ml1;
   
    $m0 = $mm0;                 
    $m1 = $mm1;


return;

}

?>


Just in case you dont have it, here is the include file you will need.
SWProtect-Internal.ahk
; SWProtect-Internal.ahk
;-------------------------------------------------------------------------------
;
; Software Protection Library 0.12
;
; This library contains a set of functions to generate a registration key
; based on a user fingerprint.
; To be used separately or together with the GUI library - SWProtect-GUI.ahk
;
; Original Code:    Laszlo Hars <www.Hars.US>
; Library Version:  Icarus
; modifications:    guest3456          (see changelog at bottom)
;
; 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 )
;
;-------------------------------------------------------------------------------


#NoEnv





;-------------------------------------------------------------------------------
; 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() {
    EnvGet, COMPUTERNAME, COMPUTERNAME
    EnvGet, HOMEPATH, HOMEPATH
    EnvGet, USERNAME, USERNAME
    EnvGet, PROCESSOR_ARCHITECTURE, PROCESSOR_ARCHITECTURE
    EnvGet, PROCESSOR_IDENTIFIER, PROCESSOR_IDENTIFIER
    EnvGet, PROCESSOR_LEVEL, PROCESSOR_LEVEL
    EnvGet, PROCESSOR_REVISION, PROCESSOR_REVISION

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

    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
}


;-------------------------------------------------------------------------------
; Revision History
;-------------------------------------------------------------------------------
/*

    0.12  2010-04-29
        - guest3456: changed script to use #NoEnv and GetFingerprint to use EnvGet
          to solve this bug: http://www.autohotkey.com/forum/post-347395.html#347395


    0.11  2007 09 04
        - Fixed  : IsUserAuthenticated returned -1 in case of an uninitialized
                   globals, now returning false.
       
    0.10  2007 09 03
        - First version



*/ 
Ive been thinking it might be nice to have some sort of more advanced php system. Could have people register on your site with a username / password that they would enter instead of their Name and Email address. Have the php store that along with the fingerprint / regkey, and have the program check everytime it runs. If the fingerprint doesnt match the one on file, then they are trying to use their username/password on a different computer. I might have to learn php lol.

nathalie
  • Guests
  • Last active:
  • Joined: --
HI

Is it poisable when the message apear with the Fingerprint pc key, this not to place them in clipbord to sent by email, but send this by url, like this:

http://www.domain.co...inform.php?key=%OutputVar%

where OutputVar the key is? and then fill in the key on php page?

Thanks

Z_Gecko
  • Guests
  • Last active:
  • Joined: --
the post right above yours from computerspazzz shows exactly that.

nathalie
  • Guests
  • Last active:
  • Joined: --
sorry, there was something going wrong here.
I have http.ahk biuld witin:
Website := http://www.mydomain....idate.php?code=

but have a error:

the following varable name has illgal caraters:
www.mydomain.net

the program wil be exit

I understand that i must use myne website adres in http.ahk right?

Z_Gecko
  • Guests
  • Last active:
  • Joined: --
this is not a valid syntax
[color=red]Website := http://www.mydomain.net/validate.php?code=[/color]
use
Website = http://www.mydomain.net/validate.php?code=
or
Website := "http://www.mydomain.net/validate.php?code="
and please read http://www.autohotke...cs/Tutorial.htm

natahle
  • Guests
  • Last active:
  • Joined: --
thanks

i has a error again:

invalid registration
code transfer error

BobyDj
  • Guests
  • Last active:
  • Joined: --
In my Gui Script have the 2 lines:

#Include SWProtect-Internal.ahk
#Include SWProtect-GUI.ahk

Now i want to export the gui to a exe file.
What is the best way to do this with this lines? I can the hole script from SWProtect-Internal.ahk copy and paste it on the line:
#Include SWProtect-Internal.ahk

And also the same with:
#Include SWProtect-GUI.ahk

But in the script SWProtect-GUI.ahk is also a inlcude to:
#Include SWProtect-Internal.ahk

So thats not gonna working, is here a page or document to read how make exe with ahk including rules?
But i that the good way to do this? I see also that

Jamie
  • Members
  • 129 posts
  • Last active: Dec 02 2012 04:59 AM
  • Joined: 26 Mar 2010
I think a good way to do it is to insert a randomly generated license key into a database when a product is purchased. This license key is also emailed to the user. The user then enters the key into the program, and the program automatically sends the machine fingerprint and fetches the unlock code from a web script and begins working.

The database keeps track not only of which license keys exist and are valid, but also records which machine fingerprint is associated with the key. The machine fingerprint is stored the first time a key is used. Subsequent attempts to register with the same key will be rejected if the machine fingerprint doesn't match. If a user's ini file gets corrupted, they can reactivate their software with the same key as long as the machine fingerprint matches. You could even make it so the unlock code is not saved, because regardless of how many times they activate, only one unlock code will be generated for each license key and it will be locked to a single machine fingerprint.

If necessary, an administrator can wipe out the machine fingerprint in the database to allow registration with a new machine fingerprint. This may be useful if a user upgrades their machine and invalidates the unlock code, and complains that the software quit working.

For the encryption in the unlock code, I chose to concatenate the license key, the product id, and the machine fingerprint, and hash with md5. In my scripts I also add some "secret" extra junk before hashing so people can't just pull this code here and generate their own keys. Md5 is built-in to php and on the client it's easily available through the windows crypto API. (Plus that php implementation of xtea appears to be buggy.)

Here's the ahk program:
#noenv

#include mcode.ahk
#include internetfileread.ahk

mfp := MachineFingerprint()
StringUpper, mfp, mfp

product := "myproduct"
StringUpper, product, product

inifile := "license.ini"

IniRead, license, %inifile%, License, Key, %A_Space%
IniRead, unlock, %inifile%, License, UnlockCode, %A_Space%

StringUpper, license, license
hashme := license . product . mfp
hash := AuthHash(hashme, strlen(hashme), 3) ; 3 for md5

if (hash == unlock) {
  MsgBox, this version is licensed
}
else {
  Loop {
    InputBox, license, Enter your license key, Please enter your license key:
    if (ErrorLevel) {
      MsgBox, You must enter a license key.  The program will now exit.
      ExitApp
    }
    urlbase := "http://[color=darkred]www.example.com[/color]/license.php"
    sz := InternetFileRead(var, urlbase . "?license=" . license . "&mfp=" . mfp . "&prod=" . product)
    StringUpper, license, license
    hashme := license . product . mfp
    hash := AuthHash(hashme, strlen(hashme), 3) ; 3 for md5    
    if (var == hash) {
      MsgBox, license is valid
      IniWrite, %license%, %inifile%, License, Key
      IniWrite, %var%, %inifile%, License, UnlockCode
      break
    }
    else {
      MsgBox, license does not appear to be valid: '%hashme%' %var% %hash%
    }
  }
}

MsgBox, here is where the program would do its work

MachineFingerprint() {
  PCdata := CPUInfo()
  EnvGet, ovar, COMPUTERNAME
  PCdata .= ovar
  EnvGet, ovar, HOMEPATH
  PCdata .= ovar
  EnvGet, ovar, USERNAME
  PCdata .= ovar
  EnvGet, ovar, PROCESSOR_ARCHITECTURE
  PCdata .= ovar
  EnvGet, ovar, PROCESSOR_IDENTIFIER
  PCdata .= ovar
  EnvGet, ovar, PROCESSOR_LEVEL
  PCdata .= ovar
  EnvGet, ovar, PROCESSOR_REVISION
  PCdata .= ovar
  EnvGet, ovar, A_OSType
  PCdata .= ovar
  EnvGet, ovar, A_OSVersion
  PCdata .= ovar
  EnvGet, ovar, Language
  PCdata .= ovar
;  PCdata = %PCdata%%COMPUTERNAME%%HOMEPATH%%USERNAME%%PROCESSOR_ARCHITECTURE%%PROCESSOR_IDENTIFIER%
;  PCdata = %PCdata%%PROCESSOR_LEVEL%%PROCESSOR_REVISION%%A_OSType%%A_OSVersion%%Language%

  RunWait, %comspec% /c vol c: > machine.tmp, , Hide
  Loop, Read, machine.tmp
  {
    PCdata := PCdata . A_LoopReadLine
  }
  FileDelete, machine.tmp
  fingerprint := AuthHash(PCdata, StrLen(PCdata))
  fingerprint := SubStr(fingerprint, 1, 16)
  return Fingerprint
}

CPUInfo() {
  MCode(CPUID,"538b4424080fa2508b44241489188b44241889088b44241c89105b8b44240c89185bc3")
  VarSetCapacity(a,4,0), VarSetCapacity(b,4,0), VarSetCapacity(c,4,0), VarSetCapacity(d,4,0)
  dllcall(&CPUID,"UInt",0, "Str",a, "Str",b, "Str",c, "Str",d, "CDECL")
  s := b . d . c . " "

  format = %A_FormatInteger%       ; save original integer format
  
  SetFormat Integer, Hex
  VarSetCapacity(a,4,0), VarSetCapacity(b,4,0), VarSetCapacity(c,4,0), VarSetCapacity(d,4,0)
  dllcall(&CPUID,"UInt",1, "Uint*",a, "UInt*",b, "UInt*",c, "UInt*",d, "CDECL")
  ;s .= a . " " . b . " " . c . " " . d . " "
  ; skip ebx because it appears to contain inconsistent garbage
  s .= a . " " . c . " " . d . " "
  
  VarSetCapacity(a,4,0), VarSetCapacity(b,4,0), VarSetCapacity(c,4,0), VarSetCapacity(d,4,0)
  dllcall(&CPUID,"UInt",2, "Uint*",a, "UInt*",b, "UInt*",c, "UInt*",d, "CDECL")
  s .= a . " " . b . " " . c . " " . d

  ; don't bother with processor serial since it is not implemented
  ;VarSetCapacity(a,4,0), VarSetCapacity(b,4,0), VarSetCapacity(c,4,0), VarSetCapacity(d,4,0)
  ;dllcall(&CPUID,"UInt",3, "Uint*",a, "UInt*",b, "UInt*",c, "UInt*",d, "CDECL")
  ;s = %s%A = 3: %a% %b% %c% %d%`n
  
  SetFormat Integer, %format%      ; restore original format
  return s
}

AuthHash(ByRef sData, nLen, SID = 4) {  ; SID: 3 for MD5, 4 for SHA
  DllCall("advapi32\CryptAcquireContextA", "UintP", hProv, "Uint", 0, "Uint", 0, "Uint", 1, "Uint", 0xF0000000)
  DllCall("advapi32\CryptCreateHash", "Uint", hProv, "Uint", 0x8000|0|SID , "Uint", 0, "Uint", 0, "UintP", hHash)
  DllCall("advapi32\CryptHashData", "Uint", hHash, "Uint", &sData, "Uint", nLen, "Uint", 0)
  DllCall("advapi32\CryptGetHashParam", "Uint", hHash, "Uint", 2, "Uint", 0, "UintP", nSize, "Uint", 0)
  VarSetCapacity(HashVal, nSize, 0)
  DllCall("advapi32\CryptGetHashParam", "Uint", hHash, "Uint", 2, "Uint", &HashVal, "UintP", nSize, "Uint", 0)
  DllCall("advapi32\CryptDestroyHash", "Uint", hHash)
  DllCall("advapi32\CryptReleaseContext", "Uint", hProv, "Uint", 0)

  format = %A_FormatInteger%       ; save original integer format
  SetFormat, Integer, H
  Loop, %nSize% {
    nValue := *(&HashVal + A_Index - 1)
    StringReplace, nValue, nValue, 0x, % (nValue < 16 ? 0 :)
    sHash .= nValue
  }
  SetFormat Integer, %format%      ; restore original format

  Return sHash
}

Here are the php functions for manipulating the database, inserting keys and so forth (red values will need to be modified)
config.php:
<?php
	define('DB_HOST', 'localhost');
  define('DB_USER', '[color=darkred]db_user[/color]');
  define('DB_PASSWORD', '[color=darkred]db_password[/color]');
  define('DB_DATABASE', '[color=darkred]db_database[/color]');
  
  function mysql_setup() {
    $link = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);  // Connect to mysql server
    if(!$link) {
      die('Failed to connect to server: ' . mysql_error());
    }

    $db = mysql_select_db(DB_DATABASE);  // Select database
    if(!$db) {
      die("Unable to select database");
    }
  }

  class License {
    public $tablename = 'registration';

    // strip out everything except letters, numbers, and underscore
    function cleanse($str) {  
      $str = strtoupper($str);
      return preg_replace('/\\W/', '', $str); 
    }

    // create a random string with the specified number of digits
    function randstring($ndigits) {
      $alphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";  // 32 unambiguous characters
      $s = "";
      for ($j=0; $j < $ndigits; $j++) {
        $s .= substr($alphabet, mt_rand(0, strlen($alphabet)-1), 1);
      }
      return $s;
    }
    
    function maketable() {
      $sql = "CREATE TABLE IF NOT EXISTS " . $this->tablename . " (
        regid int(11) NOT NULL AUTO_INCREMENT,
        license varchar(32) NOT NULL,
        product varchar(32) NOT NULL,
        mfp varchar(32) NOT NULL,
        PRIMARY KEY (regid), UNIQUE KEY license (license) )";
      $result=mysql_query($sql);
      if (!$result) {
        return true;
      }
      return false;
    }
    
    // create a new random license string and insert it into the database (with a blank mfp)
    function create($product) {
      do {
        $license = $this->randstring(6);  // six digits is 30 bits of entropy, hard to guess
      } while ($this->exists($license));  // in case of collisions (very rare), keep generating
      $this->insert($license, $product);
      return $license;
    }
    
    // check if a license exists in the database
    function exists($license) {
      $license = $this->cleanse($license);  
      $sql = "SELECT * FROM " . $this->tablename . " WHERE license='$license'";
      $result=mysql_query($sql);
      if (!$result) {
        die("query failed");
      }
      if (mysql_num_rows($result) > 0) {
        return true;
      }
      return false;
    }
    
    // get the product id associated with a license
    function getproduct($license) {
      $license = $this->cleanse($license);
      $sql = "SELECT product FROM " . $this->tablename . " WHERE license='$license'";
      $result=mysql_query($sql);
      if (!$result) {
        die("query failed");
      }
      if (mysql_num_rows($result) <= 0) {
        return "";
      }
      return mysql_result($result, 0);
    }
    
    // get the machine fingerprint associated with a license
    function getmfp($license) {
      $license = $this->cleanse($license);
      $sql = "SELECT mfp FROM " . $this->tablename . " WHERE license='$license'";
      $result=mysql_query($sql);
      if (!$result) {
        die("query failed");
      }
      if (mysql_num_rows($result) <= 0) {
        return "";
      }
      return mysql_result($result, 0);
    }
    
    // put a new license into the database (with a blank mfp)
    function insert($license, $product) {
      $license = $this->cleanse($license);  
      $product = $this->cleanse($product);
      $sql = "INSERT INTO " . $this->tablename . " (license, product, mfp) VALUES ('$license', '$product', '')";
      $result=mysql_query($sql);
      if (!$result) {
        return true;
      }
      return false;
    }
    
    // assign the mfp for an existing license
    function setmfp($license, $mfp) {
      $license = $this->cleanse($license);  
      $mfp = $this->cleanse($mfp);  
      $sql = "UPDATE " . $this->tablename . " SET mfp='$mfp' WHERE license='$license'";
      $result=mysql_query($sql);
      if (!$result) {
        return true;
      }
      return false;
    }
    
    // returns true if it's okay, or false if there is a problem
    function setOrCheck($license, $product, $mfp) {
      $license = $this->cleanse($license);
      $product = $this->cleanse($product);
      $mfp = $this->cleanse($mfp);
      if (!$this->exists($license)) {
        return false;  // license does not exist
      }
      if ($mfp == "") {
        return false;  // can't validate with a blank machine fingerprint
      }
      if ($product != $this->getproduct($license)) {
        return false;  // license is for the wrong product
      }
      $prevmfp = $this->getmfp($license);
      if ($prevmfp == '') {
        $this->setmfp($license, $mfp);
        return true;   // previous fingerprint was blank, now assigned and valid
      }
      elseif ($prevmfp != $mfp) {
        return false;  // previous fingerprint doesn't match specified one
      }
      else {
        return true;   // previous mfp exists and matches the specified mfp
      }
    }
  }
?>

Here is a simple page to demonstrate how values are created and inserted. This is triggered on a form submission but this is just an example. In real life you would probably not want to do this. With PayPal for example you can have it validate a payment and execute php scripts all automatically, so you would hook that to send email and insert the key into the database.
gen.php:
<?php
  require_once('config.php');

  echo("<html><head></head><body>");
  
  if ($_POST['email'] && $_POST['product']) {
    $recipient_email = $_POST['email'];
    if (preg_match("/^[-a-zA-Z0-9_.+][email protected](?:[-a-zA-Z0-9]+\.)+[a-zA-Z]+$/", $recipient_email)) {
      // recipient_email looks valid
      mysql_setup();
      $lm = new License;
      $license = $lm->create($_POST['product']);
      $subject = "Here is your license number";
      $fromheader = 'From: [color=darkred]Jamie <[email protected]>[/color]';
      $body = "Thank you for your purchase of " . $lm->cleanse($_POST['product']) . ".\n\nHere is your license number: $license";
      if (mail($recipient_email, $subject, $body, $fromheader)) {
        echo "<p>Email sent</p>";
      }
      else {
        echo "<p>Email couldn't be sent</p>";
      }
    }
    else {
      echo "<p>Invalid email</p>";
    }
  }
  else {
    echo '<form action="gen.php" method="post">
      <fieldset> Email: <input type="text" name="email"/><br/>
      Product: <select name="product"> <option value="abc">abc</option> 
      <option value="xyz123">xyz123</option><option value="myproduct">myproduct</option>
      </select><br/>
      <input type="submit" value="Submit"/>
      </fieldset></form>';
  }

  echo("</body></html>");
?>

Then here is the script that the ahk script will query to determine whether the license is valid or not.
license.php:
<?php
  require_once('config.php');

  if ($_GET['license'] && $_GET['mfp'] && $_GET['prod']) {
    mysql_setup();
    $lm = new License;
    $license = $_GET['license'];
    $mfp = $_GET['mfp'];
    $product = $_GET['prod'];
    if ($lm->setOrCheck($license, $product, $mfp)) {
      // license is good, send back auth code
      echo md5(strtoupper($license) . strtoupper($product) . strtoupper($mfp));
    }
    else {
      echo "bad";
    }
  }
  else {
    echo "bad";
  }
?>


guest3456
  • Guests
  • Last active:
  • Joined: --
nice alternative Jamie, i'll give it a deeper look when i have time. just a few things:

Md5 is built-in to php and on the client it's easily available through the windows crypto API. (Plus that php implementation of xtea appears to be buggy.)


1. ive corrected the php xtea in one of my recent posts in the last few pages

2. do those windows crypto functions require the windows Service "Cryptography Service" to be running? because i know a lot of people turn that off..

Jamie
  • Members
  • 129 posts
  • Last active: Dec 02 2012 04:59 AM
  • Joined: 26 Mar 2010
The errors in the php script are deeper than the SWP_Initialize function spanning multiple lines. It's a problem with the original from php-einfach.de, not your fault.

The type conversions in the _rshift and _add functions are creepy, but more importantly, they break on some platforms. My host is apparently 64 bit, meaning integers don't wrap the way the code expects them to. Specifically, consider this:
function XTEA()
   {
   global $u,$v,$key;
   $s = 0;
   $d = 0x9e3779b9;
   for($i=0; $i<32;$i++)
      {
      $u = _add($u ,[color=red]_add($v << 4 ^ _rshift($v,5), $v)[/color] ^ _add($s,$key[$s & 3] ) );
      $s =  ($s + $d) ;
      $s= 0xffffffff & $s ;
      $v = _add($v ,[color=red]_add($u << 4 ^ _rshift($u,5), $u)[/color] ^ _add($s,$key[_rshift($s, 11) & 3]));
      }
   return;
   }


function _add($i1, $i2) {
        $result = 0.0;
        foreach (func_get_args() as $value)
      {
           if (0.0 > $value) {
                $value -= 1.0 + 0xffffffff;
               }
               $result += $value;
           }


           // convert to 32 bits
           if (0xffffffff < $result || -0xffffffff > $result) {
                  $result = fmod($result, 0xffffffff + 1);
              }

           // convert to signed integer
           if (0x7fffffff < $result) {
              [color=red] $result -= 0xffffffff + 1.0;[/color]
           } elseif (-0x80000000 > $result) {
                  $result += 0xffffffff + 1.0;
           }

           return $result;
          }
When the values are left-shifted by 4, they become substantially larger than 2^32, and when added, the high bits are not truncated. These numbers eventually exceed the precision of double-precision floating point and then the conversion to floating point and back starts corrupting low bits that matter.

The style of the code suggests to me that the original author had a poor understanding of machine representation and hacked together something that works, but only barely.

Again, it's not your fault that the original has errors.

As it happens, I am using xtea in another context where I wanted encrypted communication between php and ahk, and I had to implement a workaround, using an ugly if/else structure.
function block_decrypt($y, $z) {
    $delta=0x9e3779b9;
    $sum=0xC6EF3720;
    $n=32;
    
    if (PHP_INT_SIZE > 4) {
      for ($i=0; $i<32; $i++) {
        $z = ($z - ((($y << 4 ^ $y >> 5) + $y) ^ ($sum + $this->key[($sum >> 11) & 3]))) & 0xFFFFFFFF;
        $sum = ($sum - $delta) & 0xFFFFFFFF;
        $y = ($y - ((($z << 4 ^ $z >> 5) + $z) ^ ($sum + $this->key[$sum & 3]))) & 0xFFFFFFFF;
      }
    }
    else {
      for ($i=0; $i<32; $i++) {
	      $z    = $this->_add($z, -($this->_add($y << 4 ^ $this->_rshift($y, 5), $y) ^
	                  	      $this->_add($sum, $this->key[$this->_rshift($sum, 11) & 3])));
	      $sum  = $this->_add($sum, -$delta);
	      $y    = $this->_add($y, -($this->_add($z << 4 ^ $this->_rshift($z, 5), $z) ^
	                          $this->_add($sum, $this->key[$sum & 3])));
	    }
    }
    return array($y,$z);
  }
But this is just a band-aid. I'd say the php xtea needs to be rewritten.


As for the dependence on the Cryptography Service, that's a good question I hadn't thought of. After doing some digging, I found that:

Most CSPs contain the implementation of all of their own functions. Some CSPs, however, implement their functions mainly in a Windows-based service program managed by the Windows service control manager.

The code requests the 'default' CSP, but this is not safe because

The default CSP can change between operating system releases. To ensure interoperability on different operating system platforms, the CSP should be explicitly set by using this parameter instead of using the default CSP.

So the program should specifically request the basic context instead of the 'default' context. Then, as long as the basic context continues to provide its own functions without the service dependency, it should continue to work even if the service is not running.