[原创]几个简单的内核InlineHook 汇编例程 By 旖旎(于2009-1-21发表)

;===============================================================================
;程序设计:中国·旖旎
;版权所有:旖旎 2004-2007
;禁止任何修改与盗版
;请访问旖旎个人网站 Http://Www.****.Com 获得详细资料
;电子邮件 Admin@*****.Com Tel:139******** 138******** QQ:6405035 6405038 
;===============================================================================
.code
;--------------------------------------------------------------------------------
HookSeSinglePrivilegeCheck    PROC    @LuidPrivilegeLowPart:DWORD,@LuidPrivilegeHighPart:DWORD,@PreviousMode:DWORD
    
    .if    @LuidPrivilegeLowPart==SE_SHUTDOWN_PRIVILEGE    ;关机特权=SE_SHUTDOWN_PRIVILEGE
        if    DEBUG
        movzx eax,byte ptr [@PreviousMode]        ;取得调用者身份信息,此信息为字,所以我们必须扩展并转化.
        invoke DbgPrint,\
        CRLFTXT("检测到特权检验操作,传入参数LowPart为:%d,传入参数HighPart为:%d,传入参数PreviousMode为:%d"),\
        @LuidPrivilegeLowPart,@LuidPrivilegeHighPart,eax
        invoke DbgPrint,\
        CRLFTXT("警告:你无权关闭/重新启动此计算机,请与你的管理员联系!")
        endif
        
        mov    eax,FALSE    ;注意,该函数返回FALSE表示验证特权失败,TRUE或者其他表示成功
        ret            ;因此要使其验证特权失败,必须返回FALSE
    .endif
    
    
    push    @PreviousMode        ;压入参数3
    push    @LuidPrivilegeHighPart    ;压入参数2
    push    @LuidPrivilegeLowPart    ;压入参数1
    push    offset @F        ;必须手工压入返回地址
    
    RealSeSinglePrivilegeCheck    INLINE_HOOK_TAIL_EX    <,,lpSeSinglePrivilegeCheck,,INLINE_HOOK_HEAD_SIZE,,>
@@:
    ret
    
HookSeSinglePrivilegeCheck     ENDP
;--------------------------------------------------------------------------------
HookNtShutdownSystem    PROC    @Action:DWORD
    
    if    DEBUG
    invoke DbgPrint,CRLFTXT("检测到关闭系统操作,操作代码:%d,此行为已被驱动程序阻止"),@Action
    endif
    ;0为关闭计算机并不重新启动计算机
    ;1为关闭计算机并重新启动计算机
    ;2为关闭计算机并关闭电源!
    
    mov eax, STATUS_ACCESS_DENIED
    ret

    
    push    @Action            ;压入参数1
    push    offset @F        ;必须手工压入返回地址
    
    RealNtShutdownSystem    INLINE_HOOK_TAIL_EX    <,,lpNtShutdownSystem,,INLINE_HOOK_HEAD_SIZE,,>        ;调用原始函数
@@:
    ret
    
HookNtShutdownSystem     ENDP
;--------------------------------------------------------------------------------
HookObReferenceObjectByHandle    PROC    @Handle:DWORD,@DesiredAccess:DWORD,@ObjectType:DWORD,@AccessMode:DWORD,@lpObject:DWORD,@HandleInformation:DWORD
    ;注意:该函数必须运行在PASSIVE_LEVEL级IRQL
    push    @HandleInformation    ;压入参数6
    push    @lpObject        ;压入参数5
    push    @AccessMode        ;压入参数4
    push    @ObjectType        ;压入参数3
    push    @DesiredAccess        ;压入参数2
    push    @Handle            ;压入参数1
    push    offset @F        ;必须手工压入返回地址
    
    RealObReferenceObjectByHandle    INLINE_HOOK_TAIL_EX    <,,lpObReferenceObjectByHandle,,INLINE_HOOK_HEAD_SIZE,,>        ;调用原始函数
@@:
    ;检查被保护进程是否设置
    .if    !dwCurrentProcessId
        ;直接返回
        ret
    .endif
    .if     @Handle==NtCurrentProcess || @Handle==NtCurrentThread    ;是取自身的进程或线程的对象
        ;直接返回
        ret                        
    .endif
    pushad
    pushfd                                        
    .if    eax==STATUS_SUCCESS            ;返回成功,说明取得了对象,这样输出的对象指针才是有效的
                            ;否则我们直接忽略掉就可以,因为这个时候输出的对象缓冲区里是无效内容
                            ;取得的对象有效,处理
        mov    eax,@ObjectType
        .if    eax==dwPsProcessType
            invoke PsGetCurrentProcessId
            ;如果是当前进程取得自身信息则忽略,否则继续
            .if    eax!=dwCurrentProcessId
                mov    eax,@lpObject                    ;注意:@lpObject是指向保存执行体地址指针                
                mov    eax,[eax]                    ;我们需要用指针取得执行体对象的指针
                invoke PsGetProcessId,eax
                .if    eax==dwCurrentProcessId
                ;试图取得信息的进程为被保护进程
                    mov ebx,@lpObject
                    mov ebx,[ebx]                        
                    invoke ObDereferenceObject,ebx            ;递减对对象的引用,以免引起资源泄露,
                                            ;注意:对于永久属性的对象(属性里包含OBJ_PERMANENT)调用递减引用将导致蓝屏
                
                    xor        eax,eax                ;我们需要清除已经输出的内容,否则敌方忽略了返回值直接引用还是会成功
                    mov            ecx,@lpObject            ;通过指针,取得对象输出缓冲区的内容;翻译成汇编语言如下
                    lock xchg        [ecx],eax
                
                    if    DEBUG
                    invoke PsGetCurrentProcessId
                    invoke DbgPrint,CRLFTXT("检测到进程%d试图获取受保护的进程对象执行体,拒绝访问"),eax
                    endif
                
                    popfd
                    popad
                    mov eax, STATUS_ACCESS_DENIED            ;返回:拒绝访问
                    ret
                .endif
            .endif
        .elseif eax==dwPsThreadType
            invoke PsGetCurrentProcessId
            ;如果是当前进程取得自身信息则忽略,否则继续
            .if    eax!=dwCurrentProcessId
                mov    eax,@lpObject                    ;注意:@lpObject是指向保存执行体地址指针            
                mov    eax,[eax]                    ;我们需要用指针取得执行体对象
                invoke PsGetThreadProcessId,eax
                .if    eax==dwCurrentProcessId
            ;试图取得信息的进程为被保护进程
                
                    mov ebx,@lpObject
                    mov ebx,[ebx]            
                    invoke ObDereferenceObject,ebx            ;递减对对象的引用,以免引起资源泄露
                                            ;注意:对于永久属性的对象(属性里包含OBJ_PERMANENT)调用递减引用将导致蓝屏
                
                    xor        eax,eax                ;我们需要清除已经输出的内容,否则敌方忽略了返回值直接引用还是会成功
                    mov            ecx,@lpObject            ;通过指针,取得对象输出缓冲区的内容;翻译成汇编语言如下
                    lock xchg        [ecx],eax            
                
                    if    DEBUG
                    invoke PsGetCurrentProcessId
                    invoke DbgPrint,CRLFTXT("检测到进程%d试图获取受保护的进程内线程对象执行体,拒绝访问"),eax
                    endif
                
                    popfd
                    popad
                    mov eax, STATUS_ACCESS_DENIED            ;返回:拒绝访问
                    ret
                .endif
            .endif
        .endif
    .endif

    popfd
    popad
    
    ret
    
HookObReferenceObjectByHandle     ENDP
;--------------------------------------------------------------------------------
HookObReferenceObjectByPointer    Proc    @Object:DWORD,@DesiredAccess:DWORD,@ObjectType:DWORD,@AccessMode:DWORD
    LOCAL    @dwCurreProcessId:DWORD
    .if    dwCurrentProcessId
    ;检查被保护进程是否设置
        mov    eax,@ObjectType
        .if    eax==dwPsProcessType
            ;取当前进程ID
            invoke    PsGetCurrentProcessId
            mov    @dwCurreProcessId,eax
            ;当前进程如果是被保护进程获取自身则直接放行
            .if    eax!=dwCurrentProcessId
                ;取得进程ID
                invoke PsGetProcessId,@Object
                ;是受保护进程ID
                .if    eax==dwCurrentProcessId
                    if    DEBUG
                    invoke DbgPrint,CRLFTXT("检测到进程:%d试图获取受保护的进程对象信息,此请求已被驱动程序阻止"),@dwCurreProcessId
                    endif
                    mov eax,STATUS_ACCESS_DENIED
                    ret
                .endif
            .endif
        .elseif eax==dwPsThreadType
            ;取当前进程ID
            invoke    PsGetCurrentProcessId
            mov    @dwCurreProcessId,eax
            ;当前进程如果是被保护进程获取自身则直接放行
            .if    eax!=dwCurrentProcessId
                ;取得进程ID
                invoke PsGetThreadProcessId,@Object
                ;是受保护进程ID
                .if    eax==dwCurrentProcessId
                    if    DEBUG
                    invoke DbgPrint,CRLFTXT("检测到进程:%d试图获取受保护的进程内线程对象信息,此请求已被驱动程序阻止"),@dwCurreProcessId
                    endif
                    mov eax,STATUS_ACCESS_DENIED
                    ret
                .endif
            .endif
    
        .endif
    .endif
    push    @AccessMode        ;压入参数4
    push    @ObjectType        ;压入参数3
    push    @DesiredAccess        ;压入参数2
    push    @Object            ;压入参数1
    push    offset @F        ;必须手工压入返回地址
    
    RealObReferenceObjectByPointer    INLINE_HOOK_TAIL_EX    <,,lpObReferenceObjectByPointer,,INLINE_HOOK_HEAD_SIZE,,>

@@:
    ret

HookObReferenceObjectByPointer endp
;--------------------------------------------------------------------------------

并不是所有的贴子都是原创,此时作者均指发表的人而不是文章的作者,作者会说明是否是转贴