惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - F4ncy Blog

没有钱我们能爱多久 编译器C-Free V352注册算法分析 深入分析Windows和Linux动态库应用异同 从头到脚了解缓冲溢出 反垃圾邮件技术解析 实例解析网络钓鱼攻击的幕后 防范网络嗅探 Oracle数据库性能优化技术 获取成功人生的40条守则 计算机加密反跟踪技术密文技术 Rootkit 真刀真枪的权限保卫战 人在职场走不得不明白的八项管理定律 数据库系统防黑客入侵技术综述 女孩子要做妻子前应该知道的10件事 新高性能I/O技术现状和发展趋势综述 利用IP地址欺骗突破防火墙深层技术解析 Cast-128 加密算法和 MyPassWord 的破解 DialogBlocks2.0的注册算法 如何编写Loader
从管理员身份获得 SYSTEM 权限的四种方法
F4ncy Blog · 2005-07-24 · via 博客园 - F4ncy Blog

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

作者: 一块三毛钱

本文总结了 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 运行后不知道跑到哪里去了。