强制运行受限程序

  运行一个EXE程序如果出现无法运行的情况,比如受限制或者程序被替换掉,一般有两种情况,第一种是外壳限制。双击一个程序通常调用Shell开头的函数来执行,比如ShellExecute,这个函数并非真正执行了EXE,而是会做出许多选择,例如是否被外壳限制(注册表RestrictRun项),检查文件的关联等。第二种是执行限制。当EXE文件关联被改变的情况下,Windows的任务管理器还是可以运行的,因为它用的是直接执行方式CreateProcess,所以它不会受到关联的影响。然而CreateProcess并非最底层,它也会被拦截,CreateProcess之后是CreateProcessInternal,后者会做各种检查,比如以下三种方式:

    1.映像劫持(IFEO) 
    这种技术如今已经过时了,在这里简单说一下。通过IFEO可以对目标程序进行Hook,原理是利用了Windows的调试机制。在执行一个程序时,系统会检查注册表中Image File Execution Options项,若存在同名程序,则放弃执行原程序,而用Debugger后面的程序用来调试原来的程序,这里实际上运行了调试器,原程序只是一个参数而已。系统不会检查是否循环调用,出现这种情况则会卡死直到超出路径最大长度进而出错。这种技术可以被病毒利用达到偷梁换柱的目的,也可以用来限制某个程序运行。关于IFEO有个错误的说法,说是以lpApplicationName方式运行EXE就不会被调试,事实证明这种方式无效,只要有debugger就会被调试,除非指定DEBUG_PROCESS或者DEBUG_ONLY_THIS_PROCESS。

    2.软件限制策略
    系统组策略中有一项叫软件限制策略,用于限制一个程序运行,可以根据路径限制,也可以根据文件MD5来限制。比如禁止一个路径规则?:\*就会限制运行所有程序。

    3.Manifest文件
    这是一个程序集文件,有些软件会带有一个这样的文件,文件命名方式是在原EXE文件名后加上个.Manifest后缀。大多数软件是没有这个文件的,如果在软件目录里建了一个这样的空文件或文件夹,那么软件运行时因为读取出错就会终止运行。这种方式作用同IFEO差不多,都可以根据文件名来限制其运行,只是不能替换文件。
    
    那么如何摆脱它们的限制呢?其实也很简单,通用调试CreateProcess会发现,中间会对上面的三者分别进程检查。检查的顺序是,软件限制策略->映像劫持->Manifest文件。首先是软件限制策略,执行到这一步系统会调用四个函数:SaferIdentifyLevel、SaferComputeTokenFromLevel、SaferCloseLevel和SaferRecordEventLogEntry。这4个函数位于advapi32.dll库中,其中SaferComputeTokenFromLevel比较关键,它的返回值决定了是去还是留,若返回0则表示校验失败,说明存在限制,若返回1代表校验成功,程序会往下执行。我们直接内部Hook掉SaferComputeTokenFromLevel返回1,便可无视软件限制策略。接下来再看映像劫持,程序之所以会被劫持是因为注册表中存在同名程序,所以系统势必会查询“Image File Execution Options”项,我们直接Hook掉ntdll.dll的NoOpenKey这个存根函数,一旦发现在查询IFEO就返回,程序就会跳过IFEO的检查了。其实这种方法比较烦琐一些,还有个更为简单的方法,ntdll.dll中有一个LdrQueryImageFileExecutionOptions函数,它负责管理IFEO,直接干掉它让它返回0即可。当然,如果还是感觉麻烦干脆如开头所说的直接在创建进程时加个DEBUG_PROCESS标志,运行后再结束调试即可。再来看最后一个,这个比较特别,因为我没有找到哪个函数在检查Manifest,找不到也无所谓,因为不管是什么函数在检查它,实质是要判断是否存在Manifest这个文件,系统一般会采用打开文件的方法来判断,也就是NtOpenFile,现在我们将NtOpenFile回调一下,只要监控到manifest则返回一个STATUS_OBJECT_NAME_NOT_FOUND,意思是没有找到对象名称,这样也就绕过了Manifest机制。剩余的就是系统的任务了,比如NtCreateSection、NtCreateProcessEx等等,到NtCreateProcessEx也就说明进程已经创建。

 

示例代码:

'Form1
Option Explicit

Private Sub cmdRun_Click()
        If txtRun.Text <> "" Then
                If RunExe(txtRun.Text) = False Then MsgBox "运行失败", vbCritical, ""
        End If
End Sub

Private Sub Form_Load()
        SetHook
End Sub

Private Sub Form_Unload(Cancel As Integer)
        UnHook
End Sub


'modHook.bas
'用于拦截本进程API

Option Explicit

Private Declare Function NtOpenFile Lib "NTDLL.DLL" (ByRef Filehandle As Long, _
                                                ByVal DesiredAccess As Long, _
                                                ByRef ObjectAttributes As OBJECT_ATTRIBUTES, _
                                                ByRef IoStatusBlock As IO_STATUS_BLOCK, _
                                                ByVal ShareAccess As Long, _
                                                ByVal OpenOptions As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal ByteLen As Long)
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long

Private Const STATUS_OBJECT_NAME_NOT_FOUND = &HC0000034

Private Type IO_STATUS_BLOCK
        Status   As Long
        Information As Long
End Type

Private Type OBJECT_ATTRIBUTES
        Length   As Long
        RootDirectory   As Long
        ObjectName  As Long
        Attributes   As Long
        SecurityDescriptor   As Long
        SecurityQualityOfService   As Long
End Type

Private Hook_IFEO As clsHookInfo
Private Hook_Safer As clsHookInfo
Private Hook_Manifest As clsHookInfo

'Hook
Public Function SetHook()

        Dim hProcessCurrent As Long
        
        '定义两个Hook对象
        Set Hook_Safer = New clsHookInfo '用于拦截软件限制策略
        Set Hook_IFEO = New clsHookInfo '用于拦截IFEO
        Set Hook_Manifest = New clsHookInfo '用于拦截Manifest文件
        
        hProcessCurrent = GetCurrentProcess '得到当前进程
        
        '挂钩
        Hook_Safer.HookApi "advapi32.dll", "SaferComputeTokenFromLevel", GetFunAddr(AddressOf SaferComputeTokenFromLevelCallback), hProcessCurrent
        Hook_IFEO.HookApi "ntdll.dll", "LdrQueryImageFileExecutionOptions", GetFunAddr(AddressOf LdrQueryImageFileExecutionOptionsCallback), hProcessCurrent
        Hook_Manifest.HookApi "ntdll.dll", "NtOpenFile", GetFunAddr(AddressOf NtOpenFileCallback), hProcessCurrent
        
End Function

'函数地址
Public Function GetFunAddr(lngFunAddr As Long) As Long
        GetFunAddr = lngFunAddr
End Function

'SaferComputeTokenFromLevel回调
Public Function SaferComputeTokenFromLevelCallback(ByVal LevelHandle As Long, ByVal InAccessToken As Long, OutAccessToken As Long, ByVal dwFlags As Long, lpReserved As Long) As Long
        SaferComputeTokenFromLevelCallback = 1 '非0表示查询失败,以跳过策略检查
End Function

'LdrQueryImageFileExecutionOptions回调
Public Function LdrQueryImageFileExecutionOptionsCallback() As Long
        LdrQueryImageFileExecutionOptionsCallback = 0 '欺骗系统让它认为执行失败从而跳过映像劫持
End Function

'NtOpenFile回调
Public Function NtOpenFileCallback(Filehandle As Long, ByVal DesiredAccess As Long, ObjectAttributes As OBJECT_ATTRIBUTES, IoStatusBlock As IO_STATUS_BLOCK, ByVal ShareAccess As Long, ByVal OpenOptions As Long) As Long
        Dim lRetVal As Long
        Hook_Manifest.HookStatus False
        'Debug.Print ObjectAttrToName(ObjectAttributes)
        
        '如果是Manifest文件就改掉
        If LCase(Right$(ObjectAttrToName(ObjectAttributes), 9)) = LCase(".Manifest") Then
                lRetVal = STATUS_OBJECT_NAME_NOT_FOUND '返回值改为对象不存在
        Else
                lRetVal = NtOpenFile(Filehandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions)
        End If
        Hook_Manifest.HookStatus True
        NtOpenFileCallback = lRetVal
End Function

'得到文件名称
Private Function ObjectAttrToName(ObjectAttr As OBJECT_ATTRIBUTES) As String
        Dim bytCode() As Byte
        Dim dwName As Long
        Dim dwLength As Integer
        CopyMemory dwLength, ByVal ObjectAttr.ObjectName, 2
        If dwLength > 0 Then
                CopyMemory dwName, ByVal ObjectAttr.ObjectName + 4, 4
                ReDim bytCode(dwLength - 1)
                CopyMemory bytCode(0), ByVal dwName, dwLength
                ObjectAttrToName = StrConv(StrConv(bytCode, vbUnicode), vbFromUnicode)
                ObjectAttrToName = Replace(ObjectAttrToName, "\??\", "")
        End If
        Erase bytCode
End Function

'删除Hook
Sub UnHook()
        Set Hook_Safer = Nothing
        Set Hook_IFEO = Nothing
        Set Hook_Manifest = Nothing
End Sub

 

'mod_RunEXE,运行EXE
Option Explicit

Private Declare Function NtClose Lib "NTDLL.DLL" (ByVal ObjectHandle As Long) As Long
Private Declare Function CreateProcessInternalA Lib "kernel32" (ByVal hToken As Long, _
                                                        ByVal lpApplicationName As String, _
                                                        ByVal lpCommandLine As String, _
                                                        lpProcessAttributes As Any, _
                                                        lpThreadAttributes As Any, _
                                                        ByVal bInheritHandles As Long, _
                                                        ByVal dwCreationFlags As Long, _
                                                        lpEnvironment As Any, _
                                                        ByVal lpCurrentDriectory As String, _
                                                        lpStartupInfo As STARTUPINFO, _
                                                        lpProcessInformation As PROCESS_INFORMATION, _
                                                        ByVal hNewToken As Long) As Long

Private Type PROCESS_INFORMATION
        hProcess As Long
        hThread As Long
        dwProcessId As Long
        dwThreadId As Long
End Type

Private Type STARTUPINFO
        cb As Long
        lpReserved As String
        lpDesktop As String
        lpTitle As String
        dwX As Long
        dwY As Long
        dwXSize As Long
        dwYSize As Long
        dwXCountChars As Long
        dwYCountChars As Long
        dwFillAttribute As Long
        dwFlags As Long
        wShowWindow As Integer
        cbReserved2 As Integer
        lpReserved2 As Long
        hStdInput As Long
        hStdOutput As Long
        hStdError As Long
End Type

'运行EXE程序
Public Function RunExe(ByVal szFileName As String) As Boolean
        Dim lRet As Long
        Dim lp As PROCESS_INFORMATION
        Dim si As STARTUPINFO
        si.cb = Len(si)
        lRet = CreateProcessInternalA(0&, vbNullString, szFileName, ByVal 0&, ByVal 0&, 0, &H80, ByVal 0&, vbNullString, si, lp, 0&)
        If lRet <> 0 Then
                NtClose lp.hThread
                NtClose lp.hProcess
                RunExe = True
        End If
End Function


'类模块clsHookInfo

Option Explicit

Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private mbytOldCode(5)  As Byte
Private mbytNewCode(5)  As Byte
Private mlngFunAddr     As Long
Private mhProcess       As Long

Public Function HookApi(ByVal strDllName As String, ByVal strFunName As String, ByVal lngFunAddr As Long, ByVal hProcess As Long) As Boolean
        Dim hModule As Long, dwJmpAddr As Long
        mhProcess = hProcess
        hModule = LoadLibrary(strDllName)
        If hModule = 0 Then
                HookApi = False
                Exit Function
        End If
        mlngFunAddr = GetProcAddress(hModule, strFunName)
        If mlngFunAddr = 0 Then
                HookApi = False
                Exit Function
        End If
        CopyMemory mbytOldCode(0), ByVal mlngFunAddr, 6
        mbytNewCode(0) = &HE9
        dwJmpAddr = lngFunAddr - mlngFunAddr - 5
        CopyMemory mbytNewCode(1), dwJmpAddr, 4
        HookStatus True
        HookApi = True
End Function

Public Function HookStatus(ByVal blnIsHook As Boolean) As Boolean
        If blnIsHook Then
                If WriteProcessMemory(mhProcess, ByVal mlngFunAddr, mbytNewCode(0), 5, 0) <> 0 Then HookStatus = False '拦截
        Else
                If WriteProcessMemory(mhProcess, ByVal mlngFunAddr, mbytOldCode(0), 5, 0) <> 0 Then HookStatus = False '恢复
        End If
End Function

Private Sub Class_Terminate()
        HookStatus False
End Sub

 

2012-10-4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值