Suggestions and comments are welcome.
Code: Select all
/*
AutoLock - locks your laptop when not at home.
This is done by checking which wireless networks (SSIDs) are visible, and comparing them to a predefined list.
If there is at least one match, the computer is considered to be "at home", otherwise possibly stolen.
Normally, Autologon for Windows (see below) logs you in automatically.
But if your laptop is not "at home", your computer will be locked and you must press the correct unlock key (PassChar).
Failing to do that, you get one (1) chance to enter the correct password, thus unlocking and restoring Autologon.
The wrong password takes you to the login screen, where you from now on must log in manually.
(Until you reset the password).
Prerequisites:
1) A password-protected Windows account
2) Autologon for Windows, a nifty little utility from SysInternals, which you can get at
http://technet.microsoft.com/en-us/sysinternals/bb963905.aspx
Mostly for fun, I stored the passcharacter and password in an Alternate Data Stream (ADS) in the script file itself (or in the compiled exe)
Not many editors can handle ADS, although Notepad.exe actually does.
You can use "t" as PassChar for testing purposes; this will always assume you are not at home.
If you feel uncomfortable storing your Windows password, you can use any other password.
In this case, you will have to manually reset your password in AutoLogon for Windows.
Note: UAC may cause trouble (it usually does!), especially on Win8.
You need to run the script with elevated privileges, thus also raising Autologon's privileges.
To do this, you can, instead of creating an ordinary shortcut to the script in Autostart, use Task Scheduler:
Schtasks /Create /RU "<mycomputername>\<myusername>" /SC ONLOGON /TN "AUTOLOCK" /TR "'C:\Program Files (x86)\AHK\AutoLock.ahk'" /IT /V1
(of course, use your own path, computername and username)
NOTE!!! This will create a task that will *not* run when the computer is on battery power. You must manually
(there is no way to do this via the command line, afaik (please correct me if I'm wrong)) uncheck
"Start the task only if the computer is on AC power" and "Stop if the computer switches to battery power"
in the "Conditions" tab in the GUI of Task Scheduler!
OR
try Jeff Main's cool Program Elevator at http://www.autohotkey.com/board/topic/61042-create-a-scheduled-task-natively-ahk-l/
You might also try ElevatedShortcut, which can be found at http://winaero.com/comment.php?comment.news.152
Written by BON 2014-04-29 for AHK_L. Should work for AHK Basic, but not tested.
*/
#SingleInstance force
#NoEnv
SetWorkingDir %A_ScriptDir%
Menu, Tray, Icon, Shell32.dll, -259
Menu, Tray, NoStandard
Menu, Tray, Add, Reset, Reset
Menu, Tray, Add, Exit, Exit
Menu, Tray, Disable, Reset
Menu, Tray, Disable, Exit
Menu, Tray, Tip, Location unknown
FileReadLine, Pass, %A_ScriptFullPath%:ini,1 ; Password and -character are hidden in an alternate stream in this file
If Pass =
{
MsgBox, 36, No password,No password found!`rWould you like to set a password and passcharacter now?
IfMsgBox Yes
{
Loop
{
InputBox, PassChar,,Type the character you want to use as passcharacter`r(only one character!),,250,200
If ErrorLevel
ExitApp
If StrLen(PassChar) = 1
Break
MsgBox,48,,Only ONE character!`rTry again!
}
InputBox, PassWord,Enter password,
(
Enter your Windows password:
Make sure you get it right!
It is used to set the Autologon password.
If you enter the wrong password here, you must
reset all passwords from the menu.
)
,HIDE,400,350
If ErrorLevel
ExitApp
;Write encrypted passchar & password to ADS
Pass := Encrypt(PassChar Password, "We dont want no stinkin unencrypted password")
RunWait, %comspec% /c "echo %Pass%>"%A_ScriptFullPath%":ini",,Hide
;Enable Autologon with the given password
AutoLogonLocation := A_ProgramFiles "\Autologon.exe" ; An educated guess
If !FileExist(AutoLogonLocation)
{
FileSelectFile AutoLogonLocation, 1, Autologon.exe, Show me where AutoLogon is:, Autologon.exe
If ErrorLevel
ExitApp
}
RunWait, %comspec% /c "echo %AutoLogonLocation%>>"%A_ScriptFullPath%":ini",,Hide
Run, %AutoLogonLocation% %A_UserName% %A_ComputerName% %PassWord%
;Create a list of "safe" networks
x := ListOfNetworks()
RegExReplace(x,",",",",y) ; Count # commas, ie networks-1
If ++y > 0
{
RunWait, %comspec% /c "echo %x%>>"%A_ScriptFullPath%":ini",,Hide
MsgBox, 64,, List of %y% home networks successfully created.
}
}
}
Pass := Decrypt(Pass, "We dont want no stinkin unencrypted password")
global PassChar := Substr(Pass, 1, 1) ; PassChar: First character
global PassWord := SubStr(Pass, 2) ; PassWord: Your Windows account pw, starting in col 2
If PassWord =
ExitApp
global AutoLogonLocation
FileReadLine, AutoLogonLocation, %A_ScriptFullPath%:ini,2
If !FileExist(AutoLogonLocation)
{
MsgBox,48,,Cannot find AutoLogon.exe - quitting!,10
RunWait, %comspec% /c "echo.>"%A_ScriptFullPath%":ini",,Hide ;Empty the ini-ADS -> forces initialization on next run
ExitApp
}
global AllPredefinedNetworks
FileReadLine, AllPredefinedNetworks, %A_ScriptFullPath%:ini,3
If AllPredefinedNetworks =
{
MsgBox,48,,No visible networks - cannot continue!,10
RunWait, %comspec% /c "echo.>"%A_ScriptFullPath%":ini",,Hide ;Empty the ini-ADS -> forces initialization on next run
ExitApp
}
OnMessage(0x218, "PowerChg") ; Will kick in as soon as the computer wakes up from sleep
SetTimer LockIfNotAtHome, -30000 ; Wait half a minute; then check ONCE
Return
PowerChg(wParam, lParam)
{
If wParam In 7,8,18 ; Waking up...
SetTimer LockIfNotAtHome, -30000 ; Wait half a minute; then check ONCE
}
LockIfNotAtHome:
SetTimer LockIfNotAtHome, 1800000 ; Check every 30 minutes, in case stolen while not sleeping
If PassChar <> T ; Test
If AtHome()
{
Menu, Tray, Tip, At home
Menu, Tray, Enable, Reset
Menu, Tray, Enable, Exit
Return
}
Menu, Tray, DeleteAll
Run, %AutoLogonLocation% "" "" "" ; Disable Autologon
Hotkey !Tab, NULL ; Disable alt-tab
BlockInput, MouseMove ; Disable MouseMoves
ToolTip Locked! Waiting for Input
SoundPlay *48 ; Exclamation sound
Input, SingleKey, L1 ; Wait for user to press a key
ToolTip ; Remove tooltip
If (SingleKey <> PassChar) ; PassChar?
{ ; No, so demand full password
String =
InputBox String, Computer is locked!, Password:, HIDE, 250, 150
If String <> %PassWord%
{
Shutdown, 0 ; Log off
ExitApp
}
}
SoundPlay *-1 ; Play sound to announce computer successfully unlocked
Hotkey !Tab, Off ; Restore alt-tab
BlockInput MouseMoveOff ; Restore Mouse moves
Run, %AutoLogonLocation% %A_UserName% %A_ComputerName% %PassWord% ; Enable Autologon with the given password
x := ListOfNetworks()
If x <>
{
MsgBox,33,,Do you wish to add the currently visible locations to the list of predefined home locations?
IfMsgBox OK
{
AllPredefinedNetworks .= "," x
Pass := Encrypt(PassChar Password, "We dont want no stinkin unencrypted password")
RunWait, %comspec% /c "echo %Pass%>"%A_ScriptFullPath%":ini",,Hide
RunWait, %comspec% /c "echo %AutoLogonLocation%>>"%A_ScriptFullPath%":ini",,Hide
RunWait, %comspec% /c "echo %AllPredefinedNetworks%>>"%A_ScriptFullPath%":ini",,Hide
}
}
Menu, Tray, Tip, Not at home
Menu, Tray, Enable, Reset
Menu, Tray, Enable, Exit
Return
AtHome()
{
x := ListOfNetworks()
If x Contains %AllPredefinedNetworks%
Return True
}
NULL: ; Dummy routine for alt-tab (does nothing)
Return
ListOfNetworks()
{
RunWait, %comspec% /c netsh wlan show networks > %A_Temp%\Nets.txt,,Hide
FileRead, Nets, %A_Temp%\Nets.txt
Loop
{
Nets := TL_Rightof(Nets, "SSID ")
Networks := Networks . TL_Between(Nets, " : ","`r") . ","
} Until Nets = ""
Networks := TL_Leftof(Networks, ",,")
If Networks = ,
Networks =
Else
FileDelete %A_Temp%\Nets.txt ; Delete in case of success; otherwise keep for debugging
Return Networks
}
Reset:
RunWait, %comspec% /c "echo.>"%A_ScriptFullPath%":ini",,Hide ;Empty the ini-ADS -> forces initialization on next run
Reload
Return
Exit:
ExitApp
Return
/*
***************************************************************************************************************
Some helper routines
***************************************************************************************************************
*/
TL_Word(Haystack, Nr, Delim)
;Returns any "word" in Haystack ("word" being defined as anything between delimiters)
;If Nr is negative, count from back
;Examples:
;TL_Word("c:\abc\def.x", 1, "\") returns "c:"
;TL_Word("c:\abc\def.x", -1, "\") returns "def.x"
;TL_Word("c:\abc\def.x", -2, "\") returns "abc"
{
StringReplace, X, Haystack, %Delim%, ¢, All ;Make sure delim is only one character
If Nr < 0
StringReplace, X, X, ¢, ¢, UseErrorLevel ;Count # occurences
MaxInd := ++ErrorLevel
Loop, Parse, X, ¢
If (A_Index = Nr) || (A_Index = MaxInd + Nr + 1)
Return, A_LoopField
}
TL_LeftOf(Haystack, Needle)
;Returns substring of Haystack from beginning of Haystack up to, but not including, Needle
;If Needle is not found, returns entire string
;Note: works diffently than RightOf - might seem awkward, but imagine a virtual delimiter at the end of Haystack
{
i := InStr(Haystack, Needle)
If i
Return SubStr(Haystack, 1, --i)
Else
Return Haystack
}
TL_RightOf(Haystack, Needle)
;Returns substring of Haystack from Needle to end of Haystack
;If Needle is not found, returns empty string
;Note: works diffently than LeftOf - might seem awkward, but imagine a virtual delimiter at the end of Haystack
{
i := InStr(Haystack, Needle)
If i
Return SubStr(Haystack, i + StrLen(Needle))
}
TL_Between(Haystack, Needle1, Needle2="")
;Returns substring of Haystack between Needles
;If Needle1 is not found, returns empty string
;If Needle2 is not found, returns from Needle1 to end of Haystack
;Needle2 is optional
{
If Needle2 =
Needle2 := Needle1
Return TL_LeftOf(TL_RightOf(Haystack, Needle1), Needle2)
}
/*
Encrypt / decrypt
Stolen from Laszlo, http://www.autohotkey.com/board/topic/6316-rc4-encryption-to-hex-stream/
*/
Encrypt(Data,Pass) {
Format := A_FormatInteger
SetFormat Integer, Hex
b := 0, j := 0
VarSetCapacity(Result,StrLen(Data)*2)
Loop 256
a := A_Index - 1
,Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
,sBox%a% := a
Loop 256
a := A_Index - 1
,b := b + sBox%a% + Key%a% & 255
,sBox%a% := (sBox%b%+0, sBox%b% := sBox%a%) ; SWAP(a,b)
Loop Parse, Data
i := A_Index & 255
,j := sBox%i% + j & 255
,k := sBox%i% + sBox%j% & 255
,sBox%i% := (sBox%j%+0, sBox%j% := sBox%i%) ; SWAP(i,j)
,Result .= SubStr(Asc(A_LoopField)^sBox%k%, -1, 2)
StringReplace Result, Result, x, 0, All
SetFormat Integer, %Format%
Return Result
}
Decrypt(Data,Pass) {
b := 0, j := 0, x := "0x"
VarSetCapacity(Result,StrLen(Data)//2)
Loop 256
a := A_Index - 1
,Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
,sBox%a% := a
Loop 256
a := A_Index - 1
,b := b + sBox%a% + Key%a% & 255
,sBox%a% := (sBox%b%+0, sBox%b% := sBox%a%) ; SWAP(a,b)
Loop % StrLen(Data)//2
i := A_Index & 255
,j := sBox%i% + j & 255
,k := sBox%i% + sBox%j% & 255
,sBox%i% := (sBox%j%+0, sBox%j% := sBox%i%) ; SWAP(i,j)
,Result .= Chr((x . SubStr(Data,2*A_Index-1,2)) ^ sBox%k%)
Return Result
}