computer-use-ootb-internal 0.0.162__py3-none-any.whl → 0.0.163__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- computer_use_ootb_internal/guard_service.py +162 -65
- computer_use_ootb_internal/launch_ootb_elevated.ps1 +69 -0
- {computer_use_ootb_internal-0.0.162.dist-info → computer_use_ootb_internal-0.0.163.dist-info}/METADATA +1 -1
- {computer_use_ootb_internal-0.0.162.dist-info → computer_use_ootb_internal-0.0.163.dist-info}/RECORD +6 -5
- {computer_use_ootb_internal-0.0.162.dist-info → computer_use_ootb_internal-0.0.163.dist-info}/WHEEL +0 -0
- {computer_use_ootb_internal-0.0.162.dist-info → computer_use_ootb_internal-0.0.163.dist-info}/entry_points.txt +0 -0
@@ -23,6 +23,7 @@ import psutil # For process/user info
|
|
23
23
|
from flask import Flask, request, jsonify # For embedded server
|
24
24
|
from waitress import serve # For serving Flask app
|
25
25
|
import json # Needed for status reporting
|
26
|
+
import shutil # Added for shutil.which
|
26
27
|
|
27
28
|
# --- Configuration ---
|
28
29
|
_SERVICE_NAME = "OOTBGuardService"
|
@@ -226,7 +227,9 @@ class GuardService(win32serviceutil.ServiceFramework):
|
|
226
227
|
self.log_info(f"Using target executable: {self.target_executable_path}")
|
227
228
|
|
228
229
|
_service_instance = self
|
229
|
-
|
230
|
+
# Determine path to the signal script
|
231
|
+
self.signal_script_path = self._find_signal_script()
|
232
|
+
self.log_info(f"Service initialized. Target executable: {self.target_executable_path}. Signal script: {self.signal_script_path}")
|
230
233
|
|
231
234
|
def SvcStop(self):
|
232
235
|
self.log_info(f"Service stop requested.")
|
@@ -708,7 +711,7 @@ class GuardService(win32serviceutil.ServiceFramework):
|
|
708
711
|
try:
|
709
712
|
# 1. Ensure scheduled task exists (still useful fallback/persistence)
|
710
713
|
try:
|
711
|
-
task_created = self.create_or_update_logon_task(user
|
714
|
+
task_created = self.create_or_update_logon_task(user)
|
712
715
|
task_created_status = "task_success" if task_created else "task_failed"
|
713
716
|
except Exception as task_err:
|
714
717
|
self.log_error(f"Internal trigger: Exception creating/updating task for {user}: {task_err}", exc_info=True)
|
@@ -756,58 +759,96 @@ class GuardService(win32serviceutil.ServiceFramework):
|
|
756
759
|
self.log_error(f"Internal trigger: Error checking existing processes for {user}: {e}")
|
757
760
|
# Continue and attempt start despite error?
|
758
761
|
|
759
|
-
# 4.
|
760
|
-
immediate_start_status = "
|
761
|
-
self.log_info(f"Internal trigger: User '{user}' is active and not running. Attempting start via
|
762
|
+
# 4. Attempt immediate start using CreateProcessAsUser to run helper script
|
763
|
+
immediate_start_status = "start_attempted_helper_script"
|
764
|
+
self.log_info(f"Internal trigger: User '{user}' is active and not running. Attempting start via helper script...")
|
765
|
+
|
766
|
+
if not self.target_executable_path:
|
767
|
+
self.log_error("Internal trigger: Cannot start process - target executable path not found.")
|
768
|
+
final_status = "failed_exe_not_found"
|
769
|
+
return final_status
|
762
770
|
|
763
|
-
# --- Start Task Scheduler logic ---
|
764
771
|
try:
|
765
|
-
#
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
final_status = "failed_task_creation"
|
772
|
+
# Find helper script path
|
773
|
+
helper_script_path = self._find_helper_script("launch_ootb_elevated.ps1")
|
774
|
+
if not helper_script_path:
|
775
|
+
self.log_error("Internal trigger: Cannot start process - helper script not found.")
|
776
|
+
final_status = "failed_helper_script_not_found"
|
771
777
|
return final_status
|
772
|
-
|
773
|
-
#
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
778
|
+
|
779
|
+
# Get PowerShell executable path
|
780
|
+
powershell_executable = self._find_powershell_executable()
|
781
|
+
if not powershell_executable:
|
782
|
+
self.log_error("Internal trigger: Cannot start process - powershell.exe not found.")
|
783
|
+
final_status = "failed_powershell_not_found"
|
784
|
+
return final_status
|
785
|
+
|
786
|
+
# Prepare arguments for the helper script (paths need quoting if they contain spaces)
|
787
|
+
target_exe_unquoted = self.target_executable_path.strip('"')
|
788
|
+
target_exe_dir = os.path.dirname(target_exe_unquoted) # Use directory of unquoted path
|
789
|
+
|
790
|
+
# Quote paths/args for command line - IMPORTANT: Use double quotes for PowerShell args
|
791
|
+
helper_script_arg = f'"{helper_script_path}"' if " " in helper_script_path else helper_script_path
|
792
|
+
target_exe_arg = f'"{target_exe_unquoted}"' if " " in target_exe_unquoted else target_exe_unquoted
|
793
|
+
working_dir_arg = f'"{target_exe_dir}"' if " " in target_exe_dir else target_exe_dir
|
794
|
+
# Username might need quoting if it contains special characters, double quote should be safe
|
795
|
+
target_user_arg = f'"{user}"'
|
796
|
+
|
797
|
+
# Construct the command line to execute powershell with the helper script and args
|
798
|
+
lpCommandLine = (
|
799
|
+
f'"{powershell_executable}" -NoProfile -ExecutionPolicy Bypass -NoExit '
|
800
|
+
f'-File {helper_script_arg} '
|
801
|
+
f'-TargetExePath {target_exe_arg} '
|
802
|
+
f'-Port {calculated_port} '
|
803
|
+
f'-TargetUser {target_user_arg} '
|
804
|
+
f'-WorkingDirectory {working_dir_arg}'
|
785
805
|
)
|
786
806
|
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
807
|
+
# Use CreateProcessAsUser to launch this command in the user's session
|
808
|
+
token = win32ts.WTSQueryUserToken(session_id)
|
809
|
+
env = win32profile.CreateEnvironmentBlock(token, False)
|
810
|
+
startup = win32process.STARTUPINFO()
|
811
|
+
# Ensure the window is visible on the user's desktop
|
812
|
+
startup.lpDesktop = "winsta0\\default"
|
813
|
+
creation_flags = win32con.CREATE_NEW_CONSOLE | win32con.NORMAL_PRIORITY_CLASS
|
814
|
+
lpApplicationName = None # Must be None when using lpCommandLine
|
815
|
+
# Working directory for powershell itself? Let it default or use script dir?
|
816
|
+
# Let's use the script's directory as CWD for powershell.exe
|
817
|
+
cwd = os.path.dirname(helper_script_path) # Use directory of unquoted path
|
818
|
+
|
819
|
+
self.log_info(f"Internal trigger: Launching helper script via CreateProcessAsUser:")
|
820
|
+
self.log_info(f" lpCommandLine: {lpCommandLine}")
|
821
|
+
self.log_info(f" lpCurrentDirectory: {cwd}")
|
822
|
+
|
823
|
+
# Execute the command in the user's session
|
824
|
+
hProcess, hThread, dwPid, dwTid = win32process.CreateProcessAsUser(
|
825
|
+
token, lpApplicationName, lpCommandLine, None, None, False,
|
826
|
+
creation_flags, env, cwd, startup
|
827
|
+
)
|
828
|
+
self.log_info(f"Internal trigger: CreateProcessAsUser call for helper script succeeded (Launcher PID: {dwPid}). Helper script should now run and trigger elevation.")
|
829
|
+
win32api.CloseHandle(hProcess)
|
830
|
+
win32api.CloseHandle(hThread)
|
831
|
+
|
832
|
+
# Assume success if CreateProcessAsUser succeeded.
|
833
|
+
# The actual success depends on the user interacting with UAC triggered by the helper.
|
834
|
+
immediate_start_status = "start_success_helper_launched"
|
835
|
+
final_status = "success_helper_launched"
|
836
|
+
|
837
|
+
except FileNotFoundError as fnf_err:
|
838
|
+
# This might now be powershell.exe OR the helper script
|
839
|
+
self.log_error(f"Internal trigger: File not found during helper script launch: {fnf_err}")
|
840
|
+
immediate_start_status = "start_failed_file_not_found"
|
841
|
+
final_status = "failed_file_not_found"
|
842
|
+
except Exception as launch_err:
|
843
|
+
self.log_error(f"Internal trigger: Exception during CreateProcessAsUser for helper script (user '{user}'): {launch_err}", exc_info=True)
|
844
|
+
immediate_start_status = "start_failed_launch_exception"
|
845
|
+
final_status = "failed_launch_exception"
|
846
|
+
finally:
|
847
|
+
if 'token' in locals() and token: # Ensure token is defined before trying to close
|
848
|
+
try:
|
849
|
+
win32api.CloseHandle(token)
|
850
|
+
except: # Ignore errors closing handle
|
851
|
+
pass
|
811
852
|
|
812
853
|
# Combine results (mostly determined by start attempt now)
|
813
854
|
# Example: final_status = f"{task_created_status}_{immediate_start_status}"
|
@@ -818,35 +859,48 @@ class GuardService(win32serviceutil.ServiceFramework):
|
|
818
859
|
return "failed_trigger_exception"
|
819
860
|
|
820
861
|
|
821
|
-
def create_or_update_logon_task(self, username
|
862
|
+
def create_or_update_logon_task(self, username):
|
822
863
|
"""Creates/updates task to trigger the internal signal script on session connect."""
|
823
|
-
if not self.
|
824
|
-
self.log_error(f"Cannot create task for {username}:
|
864
|
+
if not self.signal_script_path:
|
865
|
+
self.log_error(f"Cannot create task for {username}: Signal script path is not set.")
|
825
866
|
return False
|
867
|
+
if not sys.executable:
|
868
|
+
self.log_error(f"Cannot create task for {username}: sys.executable is not found.")
|
869
|
+
return False
|
870
|
+
|
871
|
+
# Use the python executable that the service itself is running under
|
872
|
+
python_exe = sys.executable
|
873
|
+
if ' ' in python_exe and not python_exe.startswith('"'):
|
874
|
+
python_exe = f'"{python_exe}"'
|
826
875
|
|
827
876
|
task_name = f"OOTB_UserConnect_{username}"
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
#
|
877
|
+
# Action: Run python.exe with the signal script and username argument
|
878
|
+
action_executable = python_exe
|
879
|
+
# Ensure script path is quoted if needed
|
880
|
+
script_arg = self.signal_script_path # Should be quoted already by _find_signal_script
|
881
|
+
# Username might need quoting if it contains spaces, though unlikely
|
882
|
+
user_arg = username # Keep simple for now
|
883
|
+
action_arguments = f'{script_arg} "{user_arg}"' # Pass username as quoted arg
|
884
|
+
safe_action_executable = action_executable.replace("'", "''") # Escape for PS
|
885
|
+
safe_action_arguments = action_arguments.replace("'", "''") # Escape for PS
|
886
|
+
|
887
|
+
# Working directory for the script (likely its own directory)
|
833
888
|
try:
|
834
|
-
|
835
|
-
if not
|
836
|
-
safe_working_directory =
|
889
|
+
script_dir = os.path.dirname(self.signal_script_path.strip('"'))
|
890
|
+
if not script_dir: script_dir = "."
|
891
|
+
safe_working_directory = script_dir.replace("'", "''")
|
837
892
|
working_directory_setting = f"$action.WorkingDirectory = '{safe_working_directory}'"
|
838
893
|
except Exception as e:
|
839
|
-
self.log_error(f"Error determining working directory for
|
894
|
+
self.log_error(f"Error determining working directory for signal script task: {e}. WD will not be set.")
|
840
895
|
working_directory_setting = "# Could not set WorkingDirectory"
|
841
896
|
|
842
897
|
# PowerShell command construction
|
843
898
|
ps_command = f"""
|
844
899
|
$taskName = "{task_name}"
|
845
|
-
|
846
|
-
$principal = New-ScheduledTaskPrincipal -UserId "{username}" -LogonType Interactive -RunLevel Highest
|
900
|
+
$principal = New-ScheduledTaskPrincipal -UserId "{username}" -LogonType Interactive
|
847
901
|
|
848
|
-
# Action: Run
|
849
|
-
$action = New-ScheduledTaskAction -Execute '{
|
902
|
+
# Action: Run python signal script
|
903
|
+
$action = New-ScheduledTaskAction -Execute '{safe_action_executable}' -Argument '{safe_action_arguments}'
|
850
904
|
{working_directory_setting}
|
851
905
|
|
852
906
|
# Trigger: On session connect (Event ID 21)
|
@@ -916,6 +970,49 @@ class GuardService(win32serviceutil.ServiceFramework):
|
|
916
970
|
self.log_info(f"Attempted removal of scheduled task '{task_name}' for user '{username}'.")
|
917
971
|
return True
|
918
972
|
|
973
|
+
def _find_signal_script(self):
|
974
|
+
"""Finds the signal_connection.py script relative to this service file."""
|
975
|
+
return self._find_helper_script("signal_connection.py") # Reuse helper finding logic
|
976
|
+
|
977
|
+
def _find_helper_script(self, script_name):
|
978
|
+
"""Finds a helper script relative to this service file."""
|
979
|
+
try:
|
980
|
+
# Use __file__ which should be reliable when run as a service via pythonservice.exe
|
981
|
+
base_dir = os.path.dirname(os.path.abspath(__file__))
|
982
|
+
script_path = os.path.join(base_dir, script_name)
|
983
|
+
if os.path.exists(script_path):
|
984
|
+
self.log_info(f"Found helper script '{script_name}' at: {script_path}")
|
985
|
+
# Return unquoted path for potential quoting later
|
986
|
+
return script_path
|
987
|
+
else:
|
988
|
+
self.log_error(f"Helper script '{script_name}' not found near {base_dir}")
|
989
|
+
return None
|
990
|
+
except Exception as e:
|
991
|
+
self.log_error(f"Error finding helper script '{script_name}': {e}")
|
992
|
+
return None
|
993
|
+
|
994
|
+
def _find_powershell_executable(self):
|
995
|
+
"""Finds powershell.exe, preferring the system path."""
|
996
|
+
try:
|
997
|
+
# Check System32 first
|
998
|
+
system32_path = os.path.join(os.environ.get('SystemRoot', 'C:\\Windows'), 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe')
|
999
|
+
if os.path.exists(system32_path):
|
1000
|
+
self.log_info(f"Found powershell.exe at: {system32_path}")
|
1001
|
+
return system32_path
|
1002
|
+
else:
|
1003
|
+
# Fallback to checking PATH using shutil.which (requires Python 3.3+)
|
1004
|
+
# Make sure to import shutil at the top of the file if not already present
|
1005
|
+
powershell_path = shutil.which("powershell.exe")
|
1006
|
+
if powershell_path:
|
1007
|
+
self.log_info(f"Found powershell.exe via PATH: {powershell_path}")
|
1008
|
+
return powershell_path
|
1009
|
+
else:
|
1010
|
+
self.log_error("powershell.exe not found in System32 or PATH.")
|
1011
|
+
return None
|
1012
|
+
except Exception as e:
|
1013
|
+
self.log_error(f"Error finding powershell.exe: {e}")
|
1014
|
+
return None
|
1015
|
+
|
919
1016
|
# --- Main Execution Block ---
|
920
1017
|
if __name__ == '__main__':
|
921
1018
|
if len(sys.argv) > 1 and sys.argv[1] == 'debug':
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# launch_ootb_elevated.ps1
|
2
|
+
param(
|
3
|
+
[Parameter(Mandatory=$true)]
|
4
|
+
[string]$TargetExePath,
|
5
|
+
|
6
|
+
[Parameter(Mandatory=$true)]
|
7
|
+
[string]$Port,
|
8
|
+
|
9
|
+
[Parameter(Mandatory=$true)]
|
10
|
+
[string]$TargetUser,
|
11
|
+
|
12
|
+
[Parameter(Mandatory=$true)]
|
13
|
+
[string]$WorkingDirectory
|
14
|
+
)
|
15
|
+
|
16
|
+
try {
|
17
|
+
Write-Host "--- OOTB Elevation Helper ---"
|
18
|
+
Write-Host "Timestamp: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
|
19
|
+
Write-Host "Received parameters:"
|
20
|
+
Write-Host " Target Exe Path : $TargetExePath"
|
21
|
+
Write-Host " Port : $Port"
|
22
|
+
Write-Host " Target User : $TargetUser"
|
23
|
+
Write-Host " Working Dir : $WorkingDirectory"
|
24
|
+
Write-Host ""
|
25
|
+
|
26
|
+
# Validate paths
|
27
|
+
if (-not (Test-Path -Path $TargetExePath -PathType Leaf)) {
|
28
|
+
throw "Target executable not found at '$TargetExePath'"
|
29
|
+
}
|
30
|
+
if (-not (Test-Path -Path $WorkingDirectory -PathType Container)) {
|
31
|
+
throw "Working directory not found at '$WorkingDirectory'"
|
32
|
+
}
|
33
|
+
|
34
|
+
# Construct the second argument for cmd.exe /K, precisely matching the working command
|
35
|
+
# Format: "<quoted_exe_path>" --port <port> --target_user ''<username>''
|
36
|
+
# Note: PowerShell handles escaping within double quotes differently.
|
37
|
+
# Using backticks ` before inner quotes is safer here.
|
38
|
+
$cmdKSecondArg = "`"`"$TargetExePath`"`" --port $Port --target_user ''$TargetUser''"
|
39
|
+
|
40
|
+
# Construct the argument list array for Start-Process launching cmd.exe
|
41
|
+
$startProcessArgs = @('/K', $cmdKSecondArg)
|
42
|
+
|
43
|
+
Write-Host "Constructed cmd.exe /K arguments: $cmdKSecondArg"
|
44
|
+
Write-Host "Constructed Start-Process arguments array: $($startProcessArgs -join ' ')" # For logging
|
45
|
+
Write-Host "Executing elevated process..."
|
46
|
+
Write-Host "Command: Start-Process -FilePath cmd.exe -ArgumentList @('/K', '$cmdKSecondArg') -WorkingDirectory '$WorkingDirectory' -Verb RunAs"
|
47
|
+
Write-Host "--- Waiting for UAC prompt if necessary ---"
|
48
|
+
|
49
|
+
# Execute the command to launch cmd elevated, which runs the target app
|
50
|
+
Start-Process -FilePath cmd.exe -ArgumentList $startProcessArgs -WorkingDirectory $WorkingDirectory -Verb RunAs
|
51
|
+
|
52
|
+
Write-Host "--- OOTB Elevation Helper: Start-Process command executed. ---"
|
53
|
+
# The calling powershell window (started by CreateProcessAsUser with -NoExit) will remain open.
|
54
|
+
|
55
|
+
} catch {
|
56
|
+
Write-Error "--- OOTB Elevation Helper Error ---"
|
57
|
+
Write-Error "Error launching elevated process: $($_.Exception.Message)"
|
58
|
+
Write-Error "Script Parameters:"
|
59
|
+
Write-Error " Target Exe Path : $TargetExePath"
|
60
|
+
Write-Error " Port : $Port"
|
61
|
+
Write-Error " Target User : $TargetUser"
|
62
|
+
Write-Error " Working Dir : $WorkingDirectory"
|
63
|
+
Write-Host "Press Enter to exit..."
|
64
|
+
Read-Host # Keep window open on error
|
65
|
+
Exit 1
|
66
|
+
}
|
67
|
+
|
68
|
+
# Exit gracefully if successful
|
69
|
+
Exit 0
|
{computer_use_ootb_internal-0.0.162.dist-info → computer_use_ootb_internal-0.0.163.dist-info}/RECORD
RENAMED
@@ -2,7 +2,8 @@ computer_use_ootb_internal/README.md,sha256=FxpW95lyub2iX73ZDfK6ML7SdEKg060H5I6G
|
|
2
2
|
computer_use_ootb_internal/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
3
3
|
computer_use_ootb_internal/app_teachmode.py,sha256=hiUTiX4jl1-5yqs3AwrOjNmToL5LbUb42o5XS4fiKAA,23805
|
4
4
|
computer_use_ootb_internal/dependency_check.py,sha256=y8RMEP6RXQzTgU1MS_1piBLtz4J-Hfn9RjUZg59dyvo,1333
|
5
|
-
computer_use_ootb_internal/guard_service.py,sha256=
|
5
|
+
computer_use_ootb_internal/guard_service.py,sha256=SV8vnxBUiu3Y7_RS4g7R3khzW7Ewh-5ooC7RO2DL4-c,55398
|
6
|
+
computer_use_ootb_internal/launch_ootb_elevated.ps1,sha256=h6CnpDd8pRwDqFu42E5GUuLdPrCHJWDuc_zOXaE9mtQ,2793
|
6
7
|
computer_use_ootb_internal/requirements-lite.txt,sha256=5DAHomz4A_P2BmTIXNkNqkHbnIF0AyZ4_1XAlb1LaYs,290
|
7
8
|
computer_use_ootb_internal/run_teachmode_ootb_args.py,sha256=eUPpfA7bB3bdBBiIBIxKJSS-Jpz2G6R46fpDO440Jyo,7687
|
8
9
|
computer_use_ootb_internal/service_manager.py,sha256=SD8jzfn0VVXBOr_nP6zmBWSC2TzrU_sp2e5JJkSlQFU,9734
|
@@ -34,7 +35,7 @@ computer_use_ootb_internal/computer_use_demo/tools/run.py,sha256=xhXdnBK1di9muaO
|
|
34
35
|
computer_use_ootb_internal/computer_use_demo/tools/screen_capture.py,sha256=L8qfvtUkPPQGt92N-2Zfw5ZTDBzLsDps39uMnX3_uSA,6857
|
35
36
|
computer_use_ootb_internal/preparation/__init__.py,sha256=AgtGHcBpiTkxJjF0xwcs3yyQ6SyUvhL3G0vD2XO-zJw,63
|
36
37
|
computer_use_ootb_internal/preparation/star_rail_prepare.py,sha256=r0b19M_c1sXkN3_MRFjql8w_ThC9nZUe8zbSLYUvKS8,4635
|
37
|
-
computer_use_ootb_internal-0.0.
|
38
|
-
computer_use_ootb_internal-0.0.
|
39
|
-
computer_use_ootb_internal-0.0.
|
40
|
-
computer_use_ootb_internal-0.0.
|
38
|
+
computer_use_ootb_internal-0.0.163.dist-info/METADATA,sha256=sOJ6C_wWzwu6jp5zsWX9GseG1pabVxpIaEjkIRH-pRU,1048
|
39
|
+
computer_use_ootb_internal-0.0.163.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
40
|
+
computer_use_ootb_internal-0.0.163.dist-info/entry_points.txt,sha256=bXfyAU_qq-G1EiEgAQEioXvgEdRCFxaTooqdDD9Y4OA,258
|
41
|
+
computer_use_ootb_internal-0.0.163.dist-info/RECORD,,
|
{computer_use_ootb_internal-0.0.162.dist-info → computer_use_ootb_internal-0.0.163.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|