Anteaus Posted June 9, 2010 Share Posted June 9, 2010 (edited) expandcollapse popup#Include <StructureConstants.au3> #cs RunLimited - replacement for DropMyRights/StripMyRights with enhancements. Copyright IWR Consultancy, June 2010, under GPL v3. - Fixes bug where browsers can't create new folders in userpace. - Allows loading of Image File Execution entries from an inifile - no more registry hacking. - Tags the titlebar, making it easier to tell when a process has been successfully restricted. Disclaimer: No responsibility accepted for any consequence of use. Any. #ce opt("TrayIconHide",1) global $baseKey="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" global $debug=0 global $limitedUserRights="" GetCmdLine() if $limitedUserRights="undefined" then global $limitedUserRights=IniRead($inifile,"General","LimitedUserRights","Normal") global $defaultMode=IniRead($inifile,"General","DesktopRights","Admin"); Not yet used global $debug=IniRead($inifile,"General","Debug",0) select case $mode="I" ProcessINI("I") case $mode="U" ProcessINI("U") case $targs<>"" $p_Handle=SaferLaunchProcess($targs,$limitedUserRights) ChangeTitle($p_Handle) case else ; Possibly add user-interactive mode here $WorkingDir=@WorkingDir $exeTarget=FileOpenDialog ( "Select a program to Launch as Limited User",@ProgramFilesDir, "Executables|*.exe",3 ) if @error=0 and $exeTarget <>"" then SaferLaunchProcess($exeTarget) FileChangeDir($WorkingDir) exit endselect exit func GetCmdLine() global $inifile="" $args=$cmdLine[0] if $args=0 or stringinstr($cmdLineRaw,"/?") then ShowOptions() exit endif global $targs="" global $mode="" if $args=0 then return "" $initarg=1 do select case stringleft($cmdLine[$initarg],2)="/C" ; Set inifile if stringlen($cmdLine[$initarg])=2 then if $initarg<$args then $inifile=$cmdLine[$initarg+1] $initarg=$initarg+2 else $inifile=stringmid($cmdLine[$initarg],4,255) $initarg=$initarg+1 if stringleft($inifile,1)=":" then $inifile=stringreplace($inifile,":","",1) endif if not FileExists($inifile) then if $inifile="" then $inifile="<Empty Variable>" msg(16,"Error in commandline","Specified configuration-file " & $inifile & " does not exist.",11) exit endif case stringleft($cmdLine[$initarg],2)="/I" ; Install $mode="I" $initarg=$initarg+1 case stringleft($cmdLine[$initarg],2)="/U" $mode="U" $initarg=$initarg+1 case stringleft($cmdLine[$initarg],2)="/L" ; Level of user if stringlen($cmdLine[$initarg])=2 then ;Allow for StripMyRights level syntax with space: if $initarg<$args then $limitedUserRights=$cmdLine[$initarg+1] $initarg=$initarg+2 else $limitedUserRights=stringmid($cmdLine[$initarg],3,255) $limitedUserRights=stringreplace($limitedUserRights,":","") $initarg=$initarg+1 endif case stringleft($cmdLine[$initarg],2)="/D" ; Debug mode ; Note: /D is not necessary with this version but is retained for compatibility. $initarg=$initarg+1 case stringleft($cmdLine[$initarg],1)="/" msg(16,"Unrecognized Command",$cmdLine[$initarg] & " is not a valid commandline item",11) $initarg=$initarg+1 case else exitloop endselect until $initarg>$args ; Apply remaining args to target executable: for $ct=$initarg to $args if $targs = "" then $targs=$cmdLine[$ct] else $targs &= " " & $cmdLine[$ct] endif next ;Get inifile name if none currently set: if $inifile="" then $exename=@scriptname if stringright($exename,4)=".exe" OR stringright($exename,4)=".au3" then global $inifile=stringleft($exename,stringlen($exename)-4) & ".ini" else global $inifile="RunLimited.ini" endif endif return endfunc ;saferlaunchprocess("c:\program files\seamonkey\seamonkey.exe") func SaferLaunchProcess($thisProcess,$Trustworthiness="N") local $SAFER_LEVELID_FULLYTRUSTED = 0x40000 local $SAFER_LEVELID_CONSTRAINED = 0x10000 local $SAFER_LEVELID_NORMALUSER = 0x20000 local $SAFER_LEVELID_UNTRUSTED = 0x01000 local $SAFER_SCOPEID_USER = 2 local $SAFER_LEVEL_OPEN = 1 select case stringleft($Trustworthiness,1)="N" $LevelID=0x20000 case stringleft($Trustworthiness,1)="C" $LevelID=0x10000 case stringleft($Trustworthiness,1)="U" $LevelID=0x01000 case stringleft($Trustworthiness,1)="F" $LevelID=0x40000 case stringleft($Trustworthiness,2)="0x" $LevelID=$Trustworthiness case else $LevelID=0x20000 endselect ;Open handle $a_iCall = DllCall("advapi32.dll", "int", "SaferCreateLevel", _ "dword", $SAFER_SCOPEID_USER, _ "dword", $LevelID, _ "dword", $SAFER_LEVEL_OPEN, _ "hwnd*", 0, _ "ptr", 0) If @error Or Not $a_iCall[0] Then msg(0,"Error","Failure opening handle occured!",11) EndIf $hHandle = $a_iCall[4] msg(0,"Handle Created","SAFER_LEVEL_HANDLE = " & $hHandle,2) $a_LCall = DllCall("advapi32.dll", "int", "SaferComputeTokenFromLevel", _ "dword", $hHandle, _ "ptr",0, _ "hwnd*",0, _ "ptr",0, _ "ptr",0) If @error Or Not $a_iCall[0] Then msg(0,"Error","Failure computing Token occured",11) return 0 EndIf $hToken=$a_LCall[3] $lpCommandline=$thisProcess $flags=0x00000000 ;DLLStructSetData($si,"lpDesktop","winsta0\default") $lpCurrentDirectory=@WorkingDir $si=dllstructcreate($tagSTARTUPINFO) $pi=dllstructcreate($tagPROCESS_INFORMATION) $pi_size=dllstructgetsize($pi) $si_size=dllstructgetsize($si) DLLStructSetData($pi,"Size",$pi_size) DLLStructSetData($si,"Size",$si_size) #cs ; Trance DllCall("advapi32.dll", "bool", "CreateProcessAsUser", _ ; W is better "handle", $hToken, _ "ptr", 0, _ ; you don't need this "str", $lpCommandline, _ ; wstr for CreateProcessAsUserW "ptr", DllStructGetPtr($lpProcessAttributes), _ "ptr", DllStructGetPtr($lpThreadAttributes), _ "bool", $bInheritHandles, _ "dword", $dwCreationFlags, _ "ptr", 0, _ ; you don't need this "ptr", 0, _ ; you don't need this "ptr", DllStructGetPtr($si), _ "ptr", DllStructGetPtr($pi)) #ce $thisPKey=filename($thisProcess) $dbgValue=RegRead($baseKey & "\" & $thisPKey,"Debugger") $rluValue=RegRead($baseKey & "\" & $thisPKey,"RunAsLimitedUser") msg(0,"Debugger",$rluValue & " > " & $thisPKey & " > " & $dbgValue,1) if $rluValue>0 AND $dbgValue <>"" then RegDelete($baseKey & "\" & $thisPKey,"Debugger") endif $a_PCall = DllCall("advapi32.dll", "bool", "CreateProcessAsUserW", _ "ptr", $hToken, _ "ptr", 0, _ "wstr",$lpCommandline, _ "ptr", 0, _ "ptr", 0, _ "bool",False, _ "dword",$flags, _ "ptr", 0, _ "ptr", 0, _ "ptr", dllstructgetptr($si), _ "ptr", dllstructgetptr($pi)) ; "wstr",$lpCurrentDirectory, _ $dllerr=@error if $rluValue>0 then RegWrite($baseKey & "\" & $thisPKey,"Debugger","REG_SZ",$dbgValue) endif $rtn="" ; for $ct=0 to 11 ; $rtn &= $ct & " : " & $A_PCall[$ct] & @lf ; next for $ct=1 to 4 $rtn &= "pi" & $ct & " : " & DllStructGetData( $pi, $ct ) & @lf next msg(0,"Process Info" & $dllerr,$rtn,5) if $a_Pcall[0]>0 then $pHandle=DllStructGetData( $pi, 3 ) else $pHandle=0 endif ;Close handle $a_iCall = DllCall("advapi32.dll", "int", "SaferCloseLevel", _ "hwnd", $hHandle) If @error Or Not $a_iCall[0] Then msg(0,"Error","Failure closing handle occured!",1) EndIf ; Release allocated memory: $pi="" $si="" $lpThreadAttributes="" $lpProcessAttributes="" ;ConsoleWrite("Handle succesfully closed" & @CRLF) return $pHandle endfunc func setLimitedRun($limitedApps,$policyDebugger=@scriptfullpath) if stringright($policyDebugger,4)=".au3" then msg(16,"Inadvisable action","Setting or modifying the debug option with an interpreted script is not advised, as it may lead to trouble. Compile as an executable before taking this action",11) endif $lApps=stringsplit($limitedApps,",") local $ct=0 local $idx=0 local $ifos[100][3] While 1 $idx+=1 if $idx=ubound($ifos) then redim $ifos[$idx+10][0] $thisifo = RegEnumKey($baseKey, $idx) If @error <> 0 then $ifos[0][0]=$ct ExitLoop endif if $thisifo="DLLNXOPTIONS" or stringinstr($thisifo,"Your Image File")=1 THEN continueloop endif $thisDebugger=RegRead($baseKey & "\" & $thisifo,"Debugger") if $thisDebugger="" then continueloop $ct+=1 $ifos[$ct][0]=$thisifo $ifos[$ct][1]=$thisDebugger $var="" For $i = 1 to 100 $v = RegEnumVal($baseKey & "\" & $thisifo, $i) if @error <> 0 Then ExitLoop $var = $var & "|" & $v next if $var<>"|" then $var=$var & "|" $ifos[$ct][2]=$var Wend ;0 = this exe ;1 = debug app ;2 = value list $out="" for $ct=1 to $ifos[0][0] $out = $out & $ifos[$ct][0] & "->" & $ifos[$ct][1] & $ifos[$ct][2]& @cr next msg(0,"imagefiles",$out,1) for $ct=1 to $ifos[0][0] ; Delete ifos no longer required. if stringinstr($limitedApps,$ifos[$ct][0]) = 0 then $isPolicyItem=RegRead($baseKey & "\" & $ifos[$ct][0],"RunAsLimitedUser") if stringinstr(RegRead($baseKey & "\" & $ifos[$ct][0], "Debugger"),"MyRights")>0 then $isPolicyItem=1 if $isPolicyItem=1 then msg(0,"delitemstrings",$ifos[$ct][2],2) if ($ifos[$ct][2]="|Debugger|RunAsLimitedUser|") then msg(0,"deletefully",$ifos[$ct][0],2) if RegRead($baseKey & "\" & $ifos[$ct][0], "Debugger")<>"" then RegDelete($baseKey & "\" & $ifos[$ct][0]) else msg(0,"delete",$ifos[$ct][2],2) RegDelete($baseKey & "\" & $ifos[$ct][0], "Debugger") RegDelete($baseKey & "\" & $ifos[$ct][0], "RunAsLimitedUser") endif endif endif next for $ct=1 to $lApps[0] if $lApps[$ct] <> "" then $PrevDebugger=RegRead($baseKey & "\" & $lApps[$ct],"Debugger") if $prevDebugger<>$policyDebugger then msg(0,$prevDebugger,$policyDebugger,3) RegWrite($baseKey & "\" & $lApps[$ct],"Debugger","REG_SZ",$policyDebugger) RegWrite($baseKey & "\" & $lApps[$ct],"RunAsLimitedUser","REG_DWORD","1") msg(0,"Updated",$baseKey & "\" & $lApps[$ct] & " " & @error,3) endif endif next $lrAction="Updated" if $limitedApps="" then $lrAction="Removed" msg(64,"Settings Updated","The specified LimitedRights entries have been " & $lrAction) endfunc func Processini($action="I") $lApps="" if $action="I" then $iniApps=IniReadSection($inifile, "RunLimited" ) if @error or $iniApps[0][0]=0 then $limitedApps="" else For $ct=1 to $iniApps[0][0] if $lApps="" then $lApps = $iniApps[$ct][1] else $lApps &= "," & $iniApps[$ct][1] endif next endif endif setLimitedRun($lApps) endfunc func filename ($_pathtostrip) return stringmid($_pathtostrip,stringinstr($_pathtostrip,"\",0,-1) +1 ,255) endfunc func msg($_icon,$_title,$_text,$_mode=0) ; mode 0 general message ; mode 1-9 debug levels ; mode > 10 terminal error $_timeout=30 $_opts=0 if $_mode < 10 then $_opts=4 if $_mode=0 then $_opts=0 if ($debug - $_mode >= 0) OR ($_mode>10) then $_msg=msgbox($_icon + $_opts,$_title,$_text,$_timeout) if $_msg=7 or $_opts=0 then exit endif endfunc func ChangeTitle($_pHandle) if $_pHandle=0 then return for $_ct=1 to 100 sleep(100) $_thispid=WinGetProcess("[ACTIVE]") ; msgbox(0,"pids",$_thisPID & " " & $_phandle,5) if $_thispid=$_pHandle then $_newtitle=WinGetTitle("[ACTIVE]","") & ": Limited User" WinSetTitle("[ACTIVE]","",$_newtitle) exitloop endif next endfunc func ShowOptions() msgbox(64,"RunLimited - Run a program with reduced user-rights","RunLimited [Options] Program.exe [Parameters]" & @crlf & @crlf & "Options:" & @crlf & "/C:settings_file.ini - Load custom settings" & @crlf & "/I /U -Install/Uninstall settings" & @crlf & "/L:[NCUF] Privelege Level OR" & @crlf & "/L:0xnnnnn Privelege identifier in hex",120) endfunc If you've encountered DropMyRights or StripMyRights you'll know what this is for. Basically, if you're one of those live-dangerous bods who logs-on as an Admin, you can prepend RunLimited.exe to the commandline of your browser or email prog, and it's launched as a limited process which (given correct NTFS permissions) can only write to folders in userspace. This greatly reduces the risk of Internet malware being able to gain a foothold. Includes a few enhancements, notably that if you wish to use the ImageFileExecution method of hooking processes, you can do this with an .ini file instead of having to hack the registry. Just add the progs you want to restrict to RunLimited.ini like so: [RunLimited] Mozilla Firefox=firefox.exe Seamonkey=Seamonkey.exe Opera=opera.exe Internet Liability=iexplore.exe and run Runlimited /i to install these values. Note that once installed like this you should not move or delete RunLimited.exe without first running it with the /u switch to unset these values, or the affected programs will no longer launch. You don't of course need to do any of the above for a simple test. Just compile with 3.2.6.1 and run RunLimited <path\program.exe> to create a limited process. So far only tested on XP Pro/32, and still in development so use with care. BTW, thx to Trancexxx for help with system-calls. Edited June 10, 2010 by Anteaus Link to comment Share on other sites More sharing options...
ripdad Posted June 10, 2010 Share Posted June 10, 2010 (edited) Hi AnteausScript is looking good.Just shows that Debuggers can be put to good use! But, it does go both ways.AutoIt is reporting this error when browser is clicked on ...#Include <StructureConstants.au3>. Edited June 10, 2010 by ripdad "The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward Link to comment Share on other sites More sharing options...
Anteaus Posted June 10, 2010 Author Share Posted June 10, 2010 (edited) #Include <StructureConstants.au3>Oops, that's what happens when you decide to 'tidy things up a bit' Well spotted.On the subject of debuggers and malware, it did occur to me to have it clear all unidentified debug hooks, regardless of what set them. Not sure if this might annoy some coders though. Edited June 10, 2010 by Anteaus Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now