通过复制已有程序的令牌,可以获得比普通管理员更高级的System权限,也可以获取低权限进程的令牌实现降权,System权限可以做很多平时做不了的事,正因如此也非常危险,不要拿来干坏事!
2021.12.2
- 新增V1版本
- 更新 使用RtlAdjustPrivilege方法获取SeDebugPrivilege
2021.12.3
- 新增RunAsUser方法,强制降权默认以管理员权限启动的程序,由@dbgba提供
V1版本:
/********************************************************************************
* @brief 获取指定进程的令牌,可借此以System权限或低权限用户身份启动进程,使用时需要管理员权限
* @param targetPID 进程标识,将复制其令牌
* @param exePath 可执行程序路径, 使用获取的令牌启动的可执行程序
* @param cmd optional 启动命令
* @return 成功返回新进程id
* @example
RunAsAdmin()
StealToken(FindProcess("winlogon.exe"), "cmd.exe", "/k whoami") ; 以system身份打开cmd
StealToken(FindProcess("explorer.exe"), "cmd.exe", "/k whoami") ; 以普通用户身份打开cmd
*******************************************************************************
*/
StealToken(targetPID, exePath, cmd := "") {
; Enable SeDebugPrivilege
; http://pinvoke.net/default.aspx/ntdll/RtlAdjustPrivilege.html
DllCall("Ntdll\RtlAdjustPrivilege", "uint", 0x14, "char", 1, "char", 0, "ptr*", 0)
; Get handle of target process
; PROCESS_QUERY_INFORMATION (0x0400) PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
; https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
if (!hProcess := DllCall("OpenProcess", "uint", 0x0400, "int", 1, "uint", targetPID))
if (!hProcess := DllCall("OpenProcess", "uint", 0x1000, "int", 1, "uint", targetPID))
throw Exception(A_LastError)
; https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken
; TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY
if (!DllCall("OpenProcessToken", "ptr", hProcess, "uint", 0x0002 | 0x0001 | 0x0008, "ptr*", hTokenTargetProcess)) {
err := A_LastError, DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", hTokenTargetProcess)
throw Exception(err)
}
; https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-impersonateloggedonuser
if !DllCall("Advapi32\ImpersonateLoggedOnUser", "ptr", hTokenTargetProcess){
err := A_LastError, DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", hTokenTargetProcess)
throw Exception(err)
}
DllCall("Advapi32\RevertToSelf")
; Duplicate Token now
; https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-duplicatetokenex
; TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY , SecurityImpersonation(2), TokenPrimary(1)
if !DllCall("Advapi32\DuplicateTokenEx", "ptr", hTokenTargetProcess, "uint", 0x0080 | 0x0100 | 0x0008 | 0x0002 | 0x0001, "ptr", 0, "uint", 2, "uint", 1, "ptr*", hTokenDuplicate, "int"){
err := A_LastError, DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", hTokenTargetProcess)
throw Exception(err)
}
; Prepare for startupinfo and processinfo struct
; https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexa
VarSetCapacity(pStartInfo, startInfoSize := 104, 0), VarSetCapacity(pProcessInfo, 24)
NumPut(startInfoSize, pStartInfo, 0, "uint"), NumPut(&str := "winsta0\default", pStartInfo, 16, "ptr"), NumPut(1, pStartInfo, 64, "ushort")
; Create process with duplicate token
; https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithtokenw
if !DllCall("Advapi32\CreateProcessWithTokenW", "ptr", hTokenDuplicate, "uint", 0, "ptr", &exePath, "ptr", &(cmd := A_Space cmd), "uint", 0x00000010, "ptr", 0, "ptr", 0, "ptr", &pStartInfo, "ptr", &pProcessInfo){
err := A_LastError, DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", hTokenTargetProcess), DllCall("CloseHandle", "ptr", hTokenDuplicate)
throw Exception(err)
}
; Close all handles
DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", NumGet(pProcessInfo, 0, "ptr")), DllCall("CloseHandle", "ptr", NumGet(pProcessInfo, 8, "ptr"))
return NumGet(pProcessInfo, 16, "uint")
}
/********************************************************************************
* @brief 查找指定文件的创建的进程
* @param exeName 可执行文件名,不包含路径
* @return 找到符合条件的第一个进程反回其进程id,否则返回0
* @example MsgBox FindProcess("winlogon.exe")
*******************************************************************************
*/
FindProcess(exeName) {
VarSetCapacity(pPssInfo, size := 304), NumPut(size, pPssInfo, 0, "uint")
; CreateToolhelp32Snapshot https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot
if (-1 = pssSnap := DllCall("CreateToolhelp32Snapshot", "uint", 0x2, "uint", 0, "ptr"))
throw Exception(A_LastError)
if (!DllCall("Process32First", "ptr", pssSnap, "ptr", &pPssInfo, "int")){
err := A_LastError, DllCall("CloseHandle", "ptr", pssSnap)
throw Exception(err)
}
loop {
; PROCESSENTRY32 structure https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/ns-tlhelp32-processentry32
if (exeName = StrGet(&pPssInfo + 44, "CP936")){
DllCall("CloseHandle", "ptr", pssSnap)
return NumGet(pPssInfo, 8, "uint")
}
} until !DllCall("Process32Next","ptr", pssSnap, "ptr", &pPssInfo, "int")
DllCall("CloseHandle", "ptr", pssSnap)
return 0
}
/********************************************************************************
* @brief 放在脚本开头,如果不是system身份,则以system身份重启
* @example
RunAsSystem()
MsgBox, 当前身份:%A_UserName%
*******************************************************************************
*/
RunAsSystem(){
; try{
if ("SYSTEM" == A_UserName)
return
if (A_IsAdmin)
if (A_IsCompiled)
StealToken(FindProcess("winlogon.exe"), A_AhkPath, "/restart")
else
StealToken(FindProcess("winlogon.exe"), A_AhkPath, "/restart " A_ScriptFullPath)
else if !(DllCall("GetCommandLine", "str") ~= " /restart(?!\S)")
if (A_IsCompiled)
Run *RunAs "%A_ScriptFullPath%" /restart
else
Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
; }
ExitApp
}
/********************************************************************************
* @brief 放在脚本开头,以普通用户权限重启
* @example
RunAsUser()
MsgBox, 是否为管理员:%A_IsAdmin%
*******************************************************************************
*/
RunAsUser(){
if A_IsAdmin {
RegRead, AhkPathReg, HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers,%A_AhkPath%
if (AhkPathReg!="")
RegDelete, HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers,%A_AhkPath%
if A_IsCompiled
StealToken(FindProcess("explorer.exe"), A_ScriptFullPath, "/restart")
else
StealToken(FindProcess("explorer.exe"), A_AhkPath, "/restart """ A_ScriptFullPath """")
if (AhkPathReg!="")
RegWrite, REG_SZ, HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers,%A_AhkPath%, %AhkPathReg%
ExitApp
}
}
; 以管理员权限重启
RunAsAdmin(){
full_command_line := DllCall("GetCommandLine", "str")
if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)")) {
try {
if A_IsCompiled
Run *RunAs "%A_ScriptFullPath%" /restart
else
Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
}
ExitApp
}
}
V2 版本:
/********************************************************************************
* @brief 获取指定进程的令牌,可借此以System权限和其他用户身份启动进程,使用时需要管理员权限
* @param targetPID 进程标识,将复制其令牌
* @param exePath 可执行程序路径, 使用获取的令牌启动的可执行程序
* @param cmd optional 启动命令
* @return 成功返回新进程id
* @example
RunAsAdmin()
StealToken(FindProcess("winlogon.exe"), "cmd.exe", "/k whoami") ; 以system身份打开cmd
StealToken(FindProcess("explorer.exe"), "cmd.exe", "/k whoami") ; 以普通用户身份打开cmd
********************************************************************************/
StealToken(targetPID, exePath, cmd := "") {
; Enable SeDebugPrivilege
; http://pinvoke.net/default.aspx/ntdll/RtlAdjustPrivilege.html
DllCall("Ntdll\RtlAdjustPrivilege", "uint", 0x14, "char", 1, "char", 0, "ptr*", 0)
; Get handle of target process
; PROCESS_QUERY_INFORMATION (0x0400) PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
; https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
if !hProcess := DllCall("OpenProcess", "uint", 0x0400, "int", 1, "uint", targetPID)
if !hProcess := DllCall("OpenProcess", "uint", 0x1000, "int", 1, "uint", targetPID)
throw Error(err := A_LastError)
; https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken
; TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY
if !DllCall("OpenProcessToken", "ptr", hProcess, "uint", 0x0002 | 0x0001 | 0x0008, "ptr*", &hTokenTargetProcess := 0) {
err := A_LastError, DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", hTokenTargetProcess)
throw Error(err)
}
; https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-impersonateloggedonuser
if !DllCall("Advapi32\ImpersonateLoggedOnUser", "ptr", hTokenTargetProcess){
err := A_LastError, DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", hTokenTargetProcess)
throw Error(err)
}
DllCall("Advapi32\RevertToSelf")
; Duplicate Token now
; https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-duplicatetokenex
; TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY , SecurityImpersonation(2), TokenPrimary(1)
if !DllCall("Advapi32\DuplicateTokenEx", "ptr", hTokenTargetProcess, "uint", 0x0080 | 0x0100 | 0x0008 | 0x0002 | 0x0001, "ptr", 0, "uint", 2, "uint", 1, "ptr*", &hTokenDuplicate := 0, "int"){
err := A_LastError, DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", hTokenTargetProcess)
throw Error(err)
}
; Prepare for startupinfo and processinfo struct
; https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexa
pStartInfo := Buffer(104, 0), pProcessInfo := Buffer(24)
NumPut("uint", pStartInfo.Size, pStartInfo, 0), NumPut("ptr", StrPtr("winsta0\default"), pStartInfo, 16), NumPut("ushort", 1, pStartInfo, 64)
; Create process with duplicate token
; https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithtokenw
if !DllCall("Advapi32\CreateProcessWithTokenW", "ptr", hTokenDuplicate, "uint", 0, "ptr", StrPtr(exePath), "ptr", cmd ? StrPtr(A_Space cmd) : 0, "uint", 0x00000010, "ptr", 0, "ptr", 0, "ptr", pStartInfo, "ptr", pProcessInfo){
err := A_LastError, DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", hTokenTargetProcess), DllCall("CloseHandle", "ptr", hTokenDuplicate)
throw Error(err)
}
; Close all handles
DllCall("CloseHandle", "ptr", hProcess), DllCall("CloseHandle", "ptr", NumGet(pProcessInfo, 0, "ptr")), DllCall("CloseHandle", "ptr", NumGet(pProcessInfo, 8, "ptr"))
return NumGet(pProcessInfo, 16, "uint")
}
/********************************************************************************
* @brief 查找指定文件的创建的进程
* @param exeName 可执行文件名,不包含路径
* @return 找到符合条件的第一个进程反回其进程id,否则返回0
* @example MsgBox FindProcess("winlogon.exe")
********************************************************************************/
FindProcess(exeName){
pProcessInfo := Buffer(304), NumPut("uint", pProcessInfo.Size, pProcessInfo, 0)
; CreateToolhelp32Snapshot https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot
if -1 = processSnapShot := DllCall("CreateToolhelp32Snapshot", "uint", 0x2, "uint", 0, "ptr")
throw Error(A_LastError)
; Process32First Process32Next https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32first
if (!DllCall("Process32First", "ptr", processSnapShot, "ptr", pProcessInfo.Ptr, "int")){
err := A_LastError, DllCall("CloseHandle", "ptr", processSnapShot)
throw Error(err)
}
loop {
; PROCESSENTRY32 structure https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/ns-tlhelp32-processentry32
if exeName = found := StrGet(pProcessInfo.Ptr + 44, "CP936"){
DllCall("CloseHandle", "ptr", processSnapShot)
return NumGet(pProcessInfo, 8, "uint")
}
} until !DllCall("Process32Next", "ptr", processSnapShot, "ptr", pProcessInfo.Ptr, "int")
DllCall("CloseHandle", "ptr", processSnapShot)
return 0
}
/********************************************************************************
* @brief 放在脚本开头,如果不是system身份,则以system身份重启
* @example RunAsSystem(), MsgBox("当前身份:" A_UserName)
********************************************************************************/
RunAsSystem(){
try{
if "SYSTEM" = A_UserName
return
if A_IsAdmin
if A_IsCompiled
StealToken(FindProcess("winlogon.exe"), A_AhkPath, "/restart")
else
StealToken(FindProcess("winlogon.exe"), A_AhkPath, "/restart " A_ScriptFullPath)
else if !(DllCall("GetCommandLine", "str") ~= " /restart(?!\S)")
if A_IsCompiled
Run '*RunAs "' A_ScriptFullPath '" /restart'
else
Run '*RunAs "' A_AhkPath '" /restart "' A_ScriptFullPath '"'
}
ExitApp
}
/********************************************************************************
* @brief 放在脚本开头,以普通用户权限重启
* @example RunAsUser(), MsgBox("是否为管理员:" A_IsAdmin)
********************************************************************************/
RunAsUser() {
if A_IsAdmin {
if "" != AhkPathReg := RegRead("HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", A_AhkPath)
RegDelete("HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", A_AhkPath)
if A_IsCompiled
StealToken(FindProcess("explorer.exe"), A_ScriptFullPath, "/restart")
else
StealToken(FindProcess("explorer.exe"), A_AhkPath, "/restart `"" A_ScriptFullPath "`"")
if "" != AhkPathReg
RegWrite(AhkPathReg, "REG_SZ", "HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", A_AhkPath)
ExitApp
}
}
RunAsAdmin(){
if not (A_IsAdmin or RegExMatch(DllCall("GetCommandLine", "str"), " /restart(?!\S)")){
try{
if A_IsCompiled
Run '*RunAs "' A_ScriptFullPath '" /restart'
else
Run '*RunAs "' A_AhkPath '" /restart "' A_ScriptFullPath '"'
}
ExitApp
}
}
学习中
执行 StealToken(FindProcess(“explorer.exe”), “cmd.exe”, “/k whoami”) 报错 环境:Windows 11 & AHK_V1_H Error in #include file “C:Users22677OneDriveProgramsrocketLibtoken.ahk”: Unhandled exception. Specifically: 87 Line# 549: Gosub,%ExecLabel% 550: Return,true 551: } 013: { 016: DllCall(“NtdllRtlAdjustPrivilege”, “uint”, 0x14, “char”, 1, “char”, 0, “ptr*”, 0) 020: if (!hProcess := DllCall(“OpenProcess”, “uint”, 0x0400, “int”, 1, “uint”, targetPID)) 021: if (!hProcess := DllCall(“OpenProcess”, “uint”, 0x1000, “int”, 1, “uint”, targetPID)) —> 022: Throw,Exception(A_LastError)
原来是FindProcess(“explorer.exe”)返回了0