Skip to content

Commit

Permalink
Merge pull request #9 from DartVanya/main
Browse files Browse the repository at this point in the history
Add user friendly GUI installer on AutoHotkey
  • Loading branch information
0xda568 authored Jul 30, 2024
2 parents e4f358f + 7ab1089 commit 8ec46f3
Show file tree
Hide file tree
Showing 9 changed files with 445 additions and 0 deletions.
Binary file added Installer GUI/Compiled/UWD-OSS.exe
Binary file not shown.
Binary file added Installer GUI/Compiled/UWD-OSS_x86.exe
Binary file not shown.
114 changes: 114 additions & 0 deletions Installer GUI/Lib/Inject.ahk
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
Inject(PID, dll)
{
static PROCESS_ALL_ACCESS := 0x1F0FFF, MEM_COMMIT := 0x1000, MEM_RELEASE := 0x8000, PAGE_EXECUTE_READWRITE := 64
,hKernel32 := DllCall("LoadLibrary", "Str", "kernel32.dll", "PTR")
,LoadLibraryW := DllCall("GetProcAddress", "PTR", hKernel32, "AStr", "LoadLibraryW", "PTR")

hProc := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int", 0, "UInt", PID, "PTR")
If !hProc
throw Exception("Could not open process for PID: " PID ". LastError: " A_LastError, -1)

nDirLength := VarSetCapacity(nDir, (StrLen(dll)+1) << 1, 0)
,StrPut(dll, &nDir, "UTF-16")

If !pBufferRemote := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nDirLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr") {
DllCall("CloseHandle", "PTR", hProc)
throw Exception("Could not reseve memory for process: " A_LastError, -1)
}

DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferRemote, "Ptr", &nDir, "PTR", nDirLength, "Ptr", 0)

hThread := DllCall("CreateRemoteThread", "PTR", hProc, "PTR", 0, "PTR", 0, "PTR", LoadLibraryW, "PTR", pBufferRemote, "UInt", 0, "PTR", 0, "PTR")
lasterr := A_LastError

if (hThread) {
; waits until the specified object is in the signaled state or the time-out interval elapses
WaitResult := DllCall("WaitForSingleObject", "ptr", hThread, "uint", 0xFFFFFFFF)
}

DllCall("VirtualFreeEx","PTR", hProc, "PTR", pBufferRemote, "PTR", nDirLength, "Uint", MEM_RELEASE)
DllCall("CloseHandle", "PTR", hProc)
If !hThread
throw Exception("Could not load " dll " in remote process: " lasterr, -1)
return hThread
}

; https://www.autohotkey.com/boards/viewtopic.php?t=68716
DllUnInject(ProcessID, ModuleName)
{
static TH32CS_SNAPMODULE := 0x00000008
, STANDARD_RIGHTS_REQUIRED := 0x000F0000
, SYNCHRONIZE := 0x00100000
, PROCESS_ALL_ACCESS := (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF)
, INFINITE := 0xFFFFFFFF
, WAIT_FAILED := 0xFFFFFFFF
, WAIT_OBJECT_0 := 0x00000000

try
{
; take a snapshot of all modules in the specified process
if !(hSnapshot := DllCall("CreateToolhelp32Snapshot", "uint", TH32CS_SNAPMODULE, "uint", ProcessID, "ptr"))
throw Exception("CreateToolhelp32Snapshot failed: " A_LastError, -1)

; set the size of the structure before using it.
NumPut(VarSetCapacity(MODULEENTRY32, (A_PtrSize = 8 ? 568 : 548), 0), MODULEENTRY32, "uint")
; retrieve information about the first module and exit if unsuccessful
if !(DllCall("Module32First", "ptr", hSnapshot, "ptr", &MODULEENTRY32))
throw Exception("Module32First failed: " A_LastError, -1)

; walk the module list of the process and gets the base address of the module
while (DllCall("Module32Next", "ptr", hSnapshot, "ptr", &MODULEENTRY32))
if (ModuleName = StrGet(&MODULEENTRY32+ (A_PtrSize = 8 ? 48 : 32), 256, "cp0")) {
modBaseAddr := NumGet(MODULEENTRY32, (A_PtrSize = 8 ? 24 : 20), "uptr")
break
}

; exit if module is not found
if !(modBaseAddr)
throw Exception("Module not found", -1)

; opens an existing local process object
if !(hProcess := DllCall("OpenProcess", "uint", PROCESS_ALL_ACCESS, "int", 0, "uint", ProcessID, "ptr"))
throw Exception("OpenProcess failed: " A_LastError, -1)

; retrieves a module handle for the specified module
if !(hModule := DllCall("GetModuleHandle", "str", "kernel32.dll", "ptr"))
throw Exception("GetModuleHandle failed: " A_LastError, -1)

; retrieves the address of an exported function or variable from the specified dynamic-link library (DLL)
if !(pThreadProc := DllCall("GetProcAddress", "ptr", hModule, "astr", "FreeLibrary", "ptr"))
throw Exception("GetProcAddress failed with: " A_LastError, -1)

; creates a thread that runs in the virtual address space of another process
if !(hThread := DllCall("CreateRemoteThread", "ptr", hProcess, "ptr", 0, "uptr", 0, "ptr", pThreadProc, "ptr", modBaseAddr, "uint", 0, "uint*", 0))
throw Exception("CreateRemoteThread failed with: " A_LastError, -1)

; waits until the specified object is in the signaled state or the time-out interval elapses
if ((WaitResult := DllCall("WaitForSingleObject", "ptr", hThread, "uint", INFINITE)) = WAIT_FAILED)
throw Exception("WaitForSingleObject failed with: " A_LastError, -1)

; if the state of the specified object is signaled (thread has terminated)
if (WaitResult = WAIT_OBJECT_0) {
; retrieves the termination status of the specified thread
if !(DllCall("GetExitCodeThread", "ptr", hThread, "uint*", ExitCode))
throw Exception("GetExitCodeThread failed with: " A_LastError, -1)
}
}
catch exception
{
; represents errors that occur during application execution
throw Exception
}
finally
{
; cleaning up resources
if (hThread)
DllCall("CloseHandle", "ptr", hThread)
if (hProcess)
DllCall("CloseHandle", "ptr", hProcess)
if (hSnapshot)
DllCall("CloseHandle", "ptr", hSnapshot)
}

return ExitCode
}
141 changes: 141 additions & 0 deletions Installer GUI/Lib/TrustedInstaller.ahk
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
ImpersonateTrustedInstaller() {
return ImpersonateProcess(GetTrustedInstallerPid())
}

RevertToSelf() {
return DllCall("Advapi32.dll\RevertToSelf")
}

; https://github.com/winsiderss/systeminformer/blob/master/SystemInformer/runas.c#L2123;
RunAsTrustedInstaller(cmd_line, work_dir := "") {
static PROCESS_CREATE_PROCESS := 0x80, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS := 0x20000
, CREATE_NEW_CONSOLE := 0x10, EXTENDED_STARTUPINFO_PRESENT := 0x80000, CREATE_DEFAULT_ERROR_MODE := 0x4000000

if not (PID_TI := GetTrustedInstallerPid())
return false

if !EnablePrivilege() ; need SeDebugPrivilege to open with PROCESS_CREATE_PROCESS
return false
hProcTi := DllCall("OpenProcess", "UInt",PROCESS_CREATE_PROCESS, "Int",false, "UInt",PID_TI, "Ptr")
if (!hProcTi)
return false

VarSetCapacity(PROCESS_INFORMATION, A_PtrSize*2 + 8, 0)
size := VarSetCapacity(STARTUPINFOEX, A_PtrSize*10 + 32, 0)
NumPut(size, &STARTUPINFOEX + 0, "UInt")

DllCall("InitializeProcThreadAttributeList", "Ptr",0, "UInt",1, "UInt",0, "UPtrP",size)
size := VarSetCapacity(PROC_THREAD_ATTRIBUTE_LIST, size, 0)
DllCall("InitializeProcThreadAttributeList", "Ptr",&PROC_THREAD_ATTRIBUTE_LIST, "UInt",1, "UInt",0, "UPtrP",size)

DllCall("UpdateProcThreadAttribute", "Ptr",&PROC_THREAD_ATTRIBUTE_LIST, "UInt",0
, "UPtr",PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, "PtrP",hProcTi, "UPtr",A_PtrSize, "Ptr",0, "Ptr",0)
NumPut(&PROC_THREAD_ATTRIBUTE_LIST, &STARTUPINFOEX + A_PtrSize*9 + 32)

pwork_dir := (work_dir ? &work_dir : 0) ; doesn't work on one line, v1 bug?
res := DllCall("CreateProcess", "ptr", 0
, "str", cmd_line
, "ptr", 0, "ptr", 0
, "int", false
, "uint", CREATE_NEW_CONSOLE|EXTENDED_STARTUPINFO_PRESENT|CREATE_DEFAULT_ERROR_MODE
, "ptr", 0, "ptr", pwork_dir
, "ptr", &STARTUPINFOEX, "ptr", &PROCESS_INFORMATION)
last_err := A_LastError

if (res) {
DllCall("CloseHandle", "Ptr",NumGet(&PROCESS_INFORMATION + 0))
DllCall("CloseHandle", "Ptr",NumGet(&PROCESS_INFORMATION + A_PtrSize))
}
DllCall("DeleteProcThreadAttributeList", "Ptr",&PROC_THREAD_ATTRIBUTE_LIST)
DllCall("CloseHandle", "Ptr",hProcTi)

return res
}

GetTrustedInstallerPid() {
static SC_MANAGER_CONNECT := 0x1, SC_MANAGER_ENUMERATE_SERVICE := 0x4
, SERVICE_QUERY_STATUS := 0x4, SERVICE_START := 0x10, SERVICE_RUNNING := 0x4
, SC_STATUS_PROCESS_INFO := 0

hSC := DllCall("Advapi32.dll\OpenSCManager", "Ptr",0, "Ptr",0, "UInt",SC_MANAGER_ENUMERATE_SERVICE, "Ptr")
if (hSC) {

hTI := DllCall("Advapi32.dll\OpenService", "Ptr",hSC, "Str","TrustedInstaller", "UInt",SERVICE_QUERY_STATUS|SERVICE_START, "Ptr")
if (hTI) {
size := VarSetCapacity(SERVICE_STATUS_PROCESS, 36, 0)
DllCall("Advapi32.dll\QueryServiceStatusEx", "Ptr",hTI, "UInt",SC_STATUS_PROCESS_INFO, "Ptr",&SERVICE_STATUS_PROCESS, "UInt",size, "UIntP",returnLength:=0)

if (NumGet(&SERVICE_STATUS_PROCESS + 4, "UInt") != SERVICE_RUNNING) {
DllCall("Advapi32.dll\StartService", "Ptr",hTI, "Ptr",0, "Ptr",0)
Loop {
DllCall("Advapi32.dll\QueryServiceStatusEx", "Ptr",hTI, "UInt",SC_STATUS_PROCESS_INFO, "Ptr",&SERVICE_STATUS_PROCESS, "UInt",size, "UIntP",returnLength:=0)
if (NumGet(&SERVICE_STATUS_PROCESS + 4, "UInt") = SERVICE_RUNNING)
break
Sleep 500
if (A_Index = 10)
return false
}
}
}
DllCall("Advapi32.dll\CloseServiceHandle", "Ptr",hTI)
}
DllCall("Advapi32.dll\CloseServiceHandle", "Ptr",hSC)

return hTI ? NumGet(&SERVICE_STATUS_PROCESS + 28, "UInt") : false
}

ImpersonateProcess(ProcessID) {
static THREAD_DIRECT_IMPERSONATION := 0x0200, SecurityImpersonation := 2

if (!ProcessID || !EnablePrivilege())
return false

tid := GetProcessThreads(ProcessID, true)
if (!tid)
return false
hThread := DllCall("OpenThread", "UInt",THREAD_DIRECT_IMPERSONATION, "Int",false, "UInt",tid, "Ptr")
if (!hThread)
return false

size := VarSetCapacity(SECURITY_QUALITY_OF_SERVICE, 12, 0)
NumPut(size, &SECURITY_QUALITY_OF_SERVICE+0, "UInt")
NumPut(SecurityImpersonation, &SECURITY_QUALITY_OF_SERVICE + 4, "Int")
status := DllCall("ntdll.dll\NtImpersonateThread", "Ptr",DllCall("GetCurrentThread", "Ptr"), "Ptr",hThread, "Ptr",&SECURITY_QUALITY_OF_SERVICE)
DllCall("CloseHandle", "Ptr",hThread)
return status = 0
}

GetProcessThreads(ProcessID, bFirstOnly := false) {
if !(hSnapshot := DllCall("CreateToolhelp32Snapshot", "uint", 0x4, "uint", ProcessID))
return false

NumPut(VarSetCapacity(THREADENTRY32, 28, 0), THREADENTRY32, "uint")
if !(DllCall("Thread32First", "ptr", hSnapshot, "ptr", &THREADENTRY32))
return false, DllCall("CloseHandle", "ptr", hSnapshot)

Threads := []
while (DllCall("Thread32Next", "ptr", hSnapshot, "ptr", &THREADENTRY32)) {
if (NumGet(THREADENTRY32, 12, "uint") = ProcessID) {
if (bFirstOnly)
return NumGet(THREADENTRY32, 8, "uint"), DllCall("CloseHandle", "ptr", hSnapshot)
Threads.Push(NumGet(THREADENTRY32, 8, "uint"))
}
}
return Threads.Count() ? Threads : false, DllCall("CloseHandle", "ptr", hSnapshot)
}

EnablePrivilege(Name := "SeDebugPrivilege") {
hProc := DllCall("GetCurrentProcess", "UPtr")
If DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", Name, "Int64P", LUID := 0, "UInt")
&& DllCall("Advapi32.dll\OpenProcessToken", "Ptr", hProc, "UInt", 32, "PtrP", hToken := 0, "UInt") { ; TOKEN_ADJUST_PRIVILEGES = 32
VarSetCapacity(TP, 16, 0) ; TOKEN_PRIVILEGES
, NumPut(1, &TP + 0, "UInt")
, NumPut(LUID, &TP + 4, "Int64")
, NumPut(2, &TP + 12, "UInt") ; SE_PRIVILEGE_ENABLED = 2
, DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", hToken, "UInt", 0, "Ptr", &TP, "UInt", 0, "Ptr", 0, "Ptr", 0, "UInt")
}
LastError := A_LastError
If (hToken)
DllCall("CloseHandle", "Ptr", hToken)
Return !(ErrorLevel := LastError)
}
22 changes: 22 additions & 0 deletions Installer GUI/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# GUI installer on AutoHotkey
Also open source, written on AHK v1.1
## Installation / Removal
Download compiled standalone installer for your OS: [64-bit](https://github.com/DartVanya/uwd-oss/raw/main/Installer%20GUI/Compiled/UWD-OSS.exe) / [32-bit](https://github.com/DartVanya/uwd-oss/raw/main/Installer%20GUI/Compiled/UWD-OSS_x86.exe). EXE packed with UPX.
### Installation
Run (accept UAC prompt if needed), click Install. Watermark should gone.

### Removal
Run (accept UAC prompt if needed), click Uninstall.

*****
## Features
- No need to restart Explorer or logoff.
- changes are applied immediately by inject/uninject dll into/from Explorer process and force redraw of the desktop
- Script acquire TrustedInstaller privileges when making changes to the registry
- Support both x64 and x86 (note: compiled x86 version cannot run on 64-bit OS)
*****
![installer_window](installer_window.png)

# Compability
Tested on Windows 11 23H2, removes Test Mode and Safe Mode watermarks.\
To run installer script from source, clone repo and run UWD-OSS.ahk from admin IDE or from "Run with UI Access" menu (AutoHotkey v1.1 should be installed).
Loading

0 comments on commit 8ec46f3

Please sign in to comment.