zoukankan      html  css  js  c++  java
  • 进程保护

    关于这篇文章的题目。思索良久,事实上一些技术术语一直是我的软肋。高大上标题。别人会觉得你言过事实上。低调隐晦的标题,又根本提不起别人打开这篇博文的兴趣。许久之后。就下定决心,那么就起一个朴实无华的名字算了,所以就想到了“进程保护”。但细致想想,事实上这也是一个很大的技术专题,包含众多的技术细节。所以就此声明,事实上这仅仅是一篇利用了一个简单的小技术,在一定程度上达到防止你的程序被结束的技术而已。通过读这篇文章,你可能会了解,什么叫 inline hook ?怎样利用 inline hook 来保护进程的。

    Hook 有非常多种,那些多如牛毛的术语,如 IAT HOOK, Inline Hook, SSDT Hook, Message Hook 等。要想知道这些名词。搜索引擎会帮助你。而为了保护进程。也有非常多 Hook 方法来完毕。这里我选用了inline hook。

    简单地介绍下 inline hook 。所谓 inline hook 就是,在所要被拦截的函数的里,通过指令跳转。来达到跳转到目的函数的手段,当跳转到目标函数以后。就能够在堆栈中得到调用被拦截函数的參数。当然,此时你就能够做一些自己的逻辑,比方记录一些信息。然后放行,或者直接返回到调用者。以达到欺骗调用者的目的,让它误以为调用该函数失败。

    那么本文用的到原理也就显而易见,大致原理就是,利用 inline hook 技术。拦截 NtOpenProcess API 调用,当检測到正在打开我们想要保护的进程的时候,就直接返回失败,让调用失败。

    由于想要结束一个进程,往往会先打开该进程,然后得到句柄,假设打开进程都失败了,那么自然就不能结束掉我们的进程了。

    代码例如以下:

    #define DBG 1
    
    #include <ntifs.h>
    #include <ntddk.h>
    #include <ntstrsafe.h>
    
    VOID PPUnload(PDRIVER_OBJECT driverObject);
    
    
    #define HAPI    unsigned int
    #define PFUNC   void *
    
    
    #define SHELLCODE_SHADOW_OFFSET          0xD + 1
    #define TARTGET_HEADE                    0x28
    #define SHELLCODE_TARGET_OFFSET          0x2D + 1
    #define HOOKAPI                          _cdecl
    #define HOOK_PARAMETERS                  ULONG henzox_hookIsBlock, ULONG henzox_hookCount, ULONG henzox_hookRet,
    #define HookBlock(block, count)           *&henzox_hookCount = 4*(count);  *&henzox_hookIsBlock = block;                             
                                                                                 
                           
    void __declspec(naked) GhostTemplate()
    {
    	_asm {
            push    0                                   ; 压入 block 參数
            push    0                                   ; 压入 count 參数
            call    _SAVE_EIP
    _SAVE_EIP:
            add     dword ptr[esp], 9
            ; 跳转到影子函数处运行
            _emit   0xE9
            _emit   0x00
            _emit   0x00
            _emit   0x00
            _emit   0x00
    _BACK:
            ; 推断是否放行
            cmp     dword ptr[esp], 0
            jz      _PASS                               ; 放行
    		; 被阻止,返回到调用者
            mov     edx, dword ptr 8[esp]               ; 保存返回地址
            add     esp, dword ptr 4[esp]
            add     esp, 0xC                            ; 略去压入的我们的两个參数和原返回地址
            push    edx
            ret
    _PASS:
    		add     esp, 8
            ; 目标函数的头五个字节
            _emit   0x00
            _emit   0x00
            _emit   0x00
            _emit   0x00
            _emit   0x00 
    _JMP_2_TAR:                                         ; 跳转到目标函数处运行
            _emit   0xE9
            _emit   0x00
            _emit   0x00
            _emit   0x00
            _emit   0x00
        }
    }
    
    
    
    
    HAPI HookApi(PFUNC target, PFUNC shadow)
    {
        unsigned char shellCode[] = {0xE9,0x00,0x00,0x00,0x00};
        DWORD dwBytes = 0;
        int nOffset;
        unsigned char *tmpCode = NULL;
        void * addrGhost;
        int count = 64;
    
    
        /* 申请一段可运行的内存作为跳转代码并调整里面的跳转 */
        tmpCode = (unsigned char *)ExAllocatePool(NonPagedPool, 0x1000);
        RtlZeroMemory(tmpCode, 0x1000);
        // 写入目标函数被改动的地址
        *(ULONG *)((ULONG)tmpCode + 0x1000 - 4) = (ULONG)target;
        // 拷贝模板代码
        // DEBUG addrGhost = (ULONG)GhostTmplate + *(ULONG *)((PUCHAR)GhostTmplate + 1) + 5;
        addrGhost = (ULONG)GhostTemplate;
        RtlMoveMemory(tmpCode, addrGhost, 512);
        // 改动跳转到 Shadow 函数的地址
        *(ULONG *)&tmpCode[SHELLCODE_SHADOW_OFFSET] = (ULONG)shadow - (ULONG)&tmpCode[SHELLCODE_SHADOW_OFFSET] - 4;
        // 改动跳转到目标函数的地址
        *(ULONG *)&tmpCode[SHELLCODE_TARGET_OFFSET] = (ULONG)target + 5 - (ULONG)&tmpCode[SHELLCODE_TARGET_OFFSET] - 4;
        
        // 保存原来的五个字节
        memcpy(&tmpCode[TARTGET_HEADE], (ULONG)target,5);
        /* 写入跳转地址 */
        nOffset = (ULONG)tmpCode - (ULONG)target - 5;
        *(ULONG *)&shellCode[1] = nOffset;
        memcpy(target, shellCode, sizeof(shellCode));
    
        return (HAPI)tmpCode;
    }
    
    NTSTATUS UnHookApi(HAPI handle)
    {
        DWORD dwBytes = 0;
    	int i = 10000;
        unsigned char *tmpCode = (unsigned char *)handle;
        void *target = *(ULONG *)((ULONG)tmpCode + 0x1000 - 4);
    
        memcpy(target, &tmpCode[TARTGET_HEADE], 5);
        while (i-- > 0) {
            i = i;
        }
        ExFreePool((void *)handle);
    
        return STATUS_SUCCESS;
    }
    
    NTSTATUS
    HOOKAPI
    MyNtOpenProcess (
        HOOK_PARAMETERS
        __out PHANDLE ProcessHandle,
        __in ACCESS_MASK DesiredAccess,
        __in POBJECT_ATTRIBUTES ObjectAttributes,
        __in_opt PCLIENT_ID ClientId
        )
    {
        PEPROCESS process;
        char *imageName;
        //KdPrint(("MyNtOpenProcess.
    "));
    
    	if (!ClientId) {
            goto _NONBLOCK;
        }
    
        PsLookupProcessByProcessId(ClientId->UniqueProcess, &process);
    	if (!process) {
            goto _NONBLOCK;
        }
    
        imageName = (char *)((PUCHAR)process + 0x164);
        if (!strcmp(imageName, "notepad.exe")) {
            HookBlock(TRUE, 4);
    		KdPrint(("Pid: %d, Image: %s is blocked!
    ", ClientId->UniqueProcess, imageName));
    
            return STATUS_INVALID_PARAMETER_MIX;
        }
        
    _NONBLOCK:
    	HookBlock(FALSE, 4);
        return STATUS_SUCCESS;
    }
    
    static HAPI s_hNtOpenProcess;
    
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject,IN PUNICODE_STRING serviceRegPath)
    {
        KdPrint(("DriverEntry.
    "));
    
        driverObject->DriverUnload = PPUnload;
    
        s_hNtOpenProcess = HookApi(NtOpenProcess, MyNtOpenProcess);
        
    
        return STATUS_SUCCESS;
    }
    
    VOID PPUnload(PDRIVER_OBJECT driverObject)
    {
        KdPrint(("PPUnload.
    "));
    
        UnHookApi(s_hNtOpenProcess);
    }

      我一直觉得,所以的细节都体如今源代码中,代码和原理都非常easy。以上代码能够编译为一个驱动程序。它会 Hook 掉 NtOpenProcess ,在我们自己的函数中,我保护了 Notepad.exe 进程。

    执行后。通过任务管理器结束掉 notepad.exe 时的效果:

    写博客真是一件值得的事情。或许非常多年后,我都忘了怎么敲代码的时候。翻一翻如今的文章,也能够感叹下此时的时光!


  • 相关阅读:
    AjaxPro.HttpSessionStateRequirement.ReadWrite
    C#关键字abstract virtual interface new override
    ASP.NET ViewState详解
    DataTable的Select方法
    DWR学习笔记 Hello World
    JSP标签分页实现
    php图片验证码类
    使用php发送Http请求,抓取网页数据
    JdbcTemplate 排序查询结果不一致问题
    ANT 和 JDK 的设置
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/7351430.html
Copyright © 2011-2022 走看看