驱动中给进程注入DLL,模拟GlobaHook,不完整,某些情况下报错

利用 PsSetLoadImageNotifyRoutine 设置回调,等有镜像被加载的时候,根据进程PID获取基址,然后和镜像基址对比,
如果相同,则加载的是进程EXE的镜像,这个时候通过修改镜像头中的导入表 来注入DLL。
修改导入表部分的代码,是修改的MS的detours库来的。
经过测试大部分进程注入都没问题,碰到一些比较特殊的进程运行的时候会报错,请教高手。。。
一下是核心代码:

//获取进程基址
PVOID GetProcessBaseAddress(IN HANDLE PID)
{
    NTSTATUS status;
    HANDLE hProcess = NULL;
    CLIENT_ID clientid;
    OBJECT_ATTRIBUTES ObjectAttributes;
    PPROCESS_BASIC_INFORMATION pProcessBaseInfo;
    ULONG returnedLength;
    PMY_PEB Peb;
    PVOID ImageBase = NULL;

    if(KeGetCurrentIrql() >= DISPATCH_LEVEL)
    { 
        return ImageBase;
    }

    InitializeObjectAttributes(&ObjectAttributes, 0, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, 0, 0);
    clientid.UniqueProcess = PID;
    clientid.UniqueThread = 0;
    //通过PID获得进程句柄
    status = ZwOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &ObjectAttributes, &clientid);
    if(!NT_SUCCESS(status))
    {
        DbgPrint("[GetProcessBaseAddress] ZwOpenProcess 调用失败\n");
        return ImageBase;
    }

    pProcessBaseInfo = (PPROCESS_BASIC_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESS_BASIC_INFORMATION), 'sam1');
    if (pProcessBaseInfo == NULL)
    {
        DbgPrint("[GetProcessBaseAddress]ExAllocatePoolWithTag 分配内存失败\n");
        ZwClose(hProcess);
        return ImageBase;        
    }
    RtlZeroMemory(pProcessBaseInfo, sizeof(PROCESS_BASIC_INFORMATION));

    //获得文件镜像名
    status = ZwQueryInformationProcess(hProcess, ProcessBasicInformation, pProcessBaseInfo, sizeof(PROCESS_BASIC_INFORMATION), &returnedLength);
    if(NT_SUCCESS(status)) 
    {
        Peb = (PMY_PEB)pProcessBaseInfo->PebBaseAddress;
        ImageBase = Peb->Reserved3[1];
    }
    else
    {
        DbgPrint("[GetProcessBaseAddress]2.ZwQueryInformationProcess 调用失败\n");
    }

    ZwClose(hProcess);
    ExFreePool(pProcessBaseInfo);
    return ImageBase;
}
//-----------------------------------------------------------------------------------------------------


//---------------------------------------
ULONG PadToDword(ULONG dw)
{
    return (dw + 3) & ~3u;
}

ULONG PadToDwordPtr(ULONG dw)
{
    return (dw + 7) & ~7u;
}

BOOLEAN StringCchCopyA(CHAR *pszDest, size_t cchDest, const CHAR *pszSrc)
{
    BOOLEAN hr = TRUE;

    if (cchDest == 0)
    {
        hr = FALSE;
    }
    else
    {
        while (cchDest && (*pszSrc != '\0'))
        {
            *pszDest++ = *pszSrc++;
            cchDest--;
        }

        if (cchDest == 0)
        {
            // we are going to truncate pszDest
            pszDest--;
            hr = FALSE;
        }

        *pszDest= '\0';
    }

    return hr;
}

//修改导入表注入DLL
BOOLEAN XXXXXDLL(IN HANDLE ProcessId,  IN PVOID pImageBase, PCHAR lpDlls[], ULONG nDlls)
{
    NTSTATUS ntStatus;

    PEPROCESS EProcess;
    KAPC_STATE ApcState;
    HANDLE hProcessHandle;
    CHAR curProcessName[16] = {0};

    PIMAGE_DOS_HEADER pDos;                            //DOS头
    PIMAGE_NT_HEADERS pHeader;                        //NT头
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc;    //原始导入表
    PDETOUR_CLR_HEADER pClr;

    ULONG nBound = 0;
    ULONG dwFileSize = 0;
    ULONG dwSec = 0;

    PVOID pbNewIid = NULL;
    PVOID pbNew = NULL;
    ULONG cbNew = 0;
    ULONG obRem = 0;
    ULONG obTab = 0;
    ULONG obDll = 0;
    ULONG obStr = 0;
    ULONG cbTmp = 0;
    ULONG obBase = 0;
    ULONG i=0, n=0;

    ULONG OldProtect = 0;
    PVOID lpTemp1 = NULL;
    ULONG dwTemp1 = 0;

    if(ProcessId == 0 || pImageBase == NULL)
    {
        return FALSE;
    }

    pDos =(PIMAGE_DOS_HEADER) pImageBase;
    pHeader = (PIMAGE_NT_HEADERS)((ULONG)pImageBase + (ULONG)pDos->e_lfanew);
    pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG)pImageBase + pHeader->IMPORT_DIRECTORY.VirtualAddress);

    if(pHeader->IMPORT_DIRECTORY.VirtualAddress == 0)
    {
        return FALSE;
    }

    if(PsLookupProcessByProcessId( (PVOID)ProcessId, (PEPROCESS *)&EProcess) != STATUS_SUCCESS) 
    {
        DbgPrint("[XXXXXDLL] PsLookupProcessByProcessId failed\n");
        return FALSE;
    }

    __try
    {
        KeStackAttachProcess(EProcess, &ApcState);

        ntStatus = ObOpenObjectByPointer(EProcess, OBJ_KERNEL_HANDLE, NULL, 0x008,  NULL, KernelMode, &hProcessHandle);
        if(!NT_SUCCESS(ntStatus)) 
        {
            DbgPrint("[XXXXXDLL] ObOpenObjectByPointer failed error [%08X]\n", ntStatus);
            __leave;
        }

        lpTemp1 = (PVOID)(&pHeader->BOUND_DIRECTORY.VirtualAddress);
        dwTemp1 = 4;
        ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect);
        pHeader->BOUND_DIRECTORY.VirtualAddress = 0;
        ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL);

        lpTemp1 = (PVOID)(&pHeader->BOUND_DIRECTORY.Size);
        dwTemp1 = 4;
        ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect);
        pHeader->BOUND_DIRECTORY.Size = 0;
        ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL);


        dwSec = (ULONG)pDos->e_lfanew + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + pHeader->FileHeader.SizeOfOptionalHeader;
        for (i=0; i<pHeader->FileHeader.NumberOfSections; i++) 
        {
            PIMAGE_SECTION_HEADER pSectionHeader;
            pSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG)pImageBase + dwSec + (sizeof(IMAGE_SECTION_HEADER) * i));

            // 如果该文件不具有IAT_DIRECTORY,我们创建一个.
            if (pHeader->IAT_DIRECTORY.VirtualAddress == 0 &&
                pHeader->IMPORT_DIRECTORY.VirtualAddress >= pSectionHeader->VirtualAddress &&
                pHeader->IMPORT_DIRECTORY.VirtualAddress < pSectionHeader->VirtualAddress +pSectionHeader->SizeOfRawData
                ) 
            {
                lpTemp1 = (PVOID)(&pHeader->IAT_DIRECTORY.VirtualAddress);
                dwTemp1 = 4;
                ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect);
                pHeader->IAT_DIRECTORY.VirtualAddress = pSectionHeader->VirtualAddress;
                ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL);

                lpTemp1 = (PVOID)(&pHeader->IAT_DIRECTORY.Size);
                dwTemp1 = 4;
                ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect);
                pHeader->IAT_DIRECTORY.Size = pSectionHeader->SizeOfRawData;
                ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL);
            }

            // Find the end of the file...
            if (dwFileSize < pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData)
            {
                dwFileSize = pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData;
            }
        }

        obRem = sizeof(IMAGE_IMPORT_DESCRIPTOR) * nDlls;
        obTab = PadToDwordPtr(obRem + pHeader->IMPORT_DIRECTORY.Size);
        obDll = obTab + sizeof(DWORD_PTR) * 4 * nDlls;
        obStr = obDll;
        cbNew = obStr;

        for(n=0; n<nDlls; n++) 
        {
            cbNew += PadToDword((DWORD)strlen(lpDlls[n]) + 1);
        }

        // 分配本地内存,先在本地内存中构造好输入表
        pbNew = ExAllocatePoolWithTag(NonPagedPool, cbNew, 'sam1');
        if (pbNew == NULL) 
        {
            DbgPrint("[XXXXXDLL] ExAllocatePoolWithTag cbNew faile\n");
            __leave;
        }
        RtlZeroMemory(pbNew, cbNew);

        // 在进程中分配和本地内存同样大小的虚拟内存
        cbTmp = cbNew;
        ntStatus = ZwAllocateVirtualMemory(hProcessHandle, &pbNewIid, 0, &cbTmp, MEM_COMMIT|MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
        if(!NT_SUCCESS(ntStatus))
        { 
            DbgPrint("[XXXXXDLL] ZwAllocateVirtualMemory pbNewIid failed error [%08X]\n", ntStatus);
            __leave;
        }
        RtlZeroMemory(pbNewIid, cbNew);

        // pbNewIid 是我们在远程线程分配的新的输入表的首地址,和pbModule想减后就得到它的RVA了
        obBase = (ULONG)((ULONG)pbNewIid - (ULONG)pImageBase);

        // 将旧的输入表读入到本地内存,注意有一个偏移obRem
        RtlCopyMemory((PUCHAR)((ULONG)pbNew + obRem), pImportDesc, pHeader->IMPORT_DIRECTORY.Size);

        {
            PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew;
            ULONG_PTR *pt = NULL;
            ULONG nOffset = 0;

            for(n=0; n<nDlls; n++)
            {
                if(!StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, lpDlls[n]))
                {
                    DbgPrint("StringCchCopyA 拷贝DLL路径失败\n");
                    __leave;
                }

                nOffset = obTab + (sizeof(ULONG_PTR) * (4 * n));
                piid[n].OriginalFirstThunk = obBase + nOffset;
                pt = ((ULONG_PTR*)((ULONG)pbNew + nOffset));
                pt[0] = IMAGE_ORDINAL_FLAG + 1;
                pt[1] = 0;

                nOffset = obTab + (sizeof(ULONG_PTR) * ((4 * n) + 2));
                piid[n].FirstThunk = obBase + nOffset;
                pt = ((ULONG_PTR*)((ULONG)pbNew + nOffset));
                pt[0] = IMAGE_ORDINAL_FLAG + 1;
                pt[1] = 0;

                piid[n].TimeDateStamp = 0;
                piid[n].ForwarderChain = 0;
                piid[n].Name = obBase + obStr;

                obStr += PadToDword((ULONG)strlen(lpDlls[n]) + 1);
            }
        }

        //Update the CLR header.
        if (pHeader->CLR_DIRECTORY.VirtualAddress != 0 && pHeader->CLR_DIRECTORY.Size != 0) 
        {
            ULONG flg = 0;
            pClr = (PDETOUR_CLR_HEADER)((ULONG)pImageBase + pHeader->CLR_DIRECTORY.VirtualAddress);
            flg = pClr->Flags & 0xfffffffe;

            lpTemp1 = (PVOID)(&pClr->Flags);
            dwTemp1 = 4;
            ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect);
            pClr->Flags = flg;
            ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL);
        }

        if(pHeader->IMPORT_DIRECTORY.VirtualAddress > 0)
        {
            //拷贝本地内存中的新的输入表数据到虚拟内存中
            ntStatus = ZwWriteVirtualMemory(hProcessHandle, pbNewIid, pbNew, obStr, NULL);
            if(!NT_SUCCESS(ntStatus))
            {
                DbgPrint("[XXXXXDLL] ZwWriteVirtualMemory pbNewIid failed error [%08X]\n", ntStatus);
                __leave;
            }


            KdPrint(("原导入表: [%08X] - [%d]\n", pHeader->IMPORT_DIRECTORY.VirtualAddress, pHeader->IMPORT_DIRECTORY.Size));
            //设置输入表的地址和大小,为刚才分配的虚拟内存
            lpTemp1 = (PVOID)(&pHeader->IMPORT_DIRECTORY.VirtualAddress);
            dwTemp1 = 4;
            ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect);
            pHeader->IMPORT_DIRECTORY.VirtualAddress = obBase;
            ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL);

            lpTemp1 = (PVOID)(&pHeader->IMPORT_DIRECTORY.Size);
            dwTemp1 = 4;
            ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect);
            pHeader->IMPORT_DIRECTORY.Size = cbNew;
            ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL);

            KdPrint(("新导入表: [%08X] - [%d]\n", pHeader->IMPORT_DIRECTORY.VirtualAddress, pHeader->IMPORT_DIRECTORY.Size));
        }
    }
    __finally
    {
        if(pbNew)
        {
            ExFreePool(pbNew);
        }

        if(hProcessHandle)
        {
            ZwClose(hProcessHandle);
            hProcessHandle = NULL;
        }

        KeUnstackDetachProcess(&ApcState);
    }

    ObDereferenceObject(EProcess);
    return TRUE;
}
//--------------------------------------------------------------------------------------


//LoadImage回调,在此注入DLL
VOID LoadImageRoutine(
                      IN PUNICODE_STRING  FullImageName,
                      IN HANDLE  ProcessId, // where image is mapped
                      IN PIMAGE_INFO  ImageInfo
                      )
{
    PVOID pProcessBase = NULL;

    if(ImageInfo->SystemModeImage)
    {
    }
    else
    {
        pProcessBase = GetProcessBaseAddress(ProcessId);
        if(pProcessBase == ImageInfo->ImageBase)
        {
            //注入DLL
            CHAR *rlpDlls[2];
            ULONG nDlls = 0;
            rlpDlls[nDlls++] = "HookReg.dll";
            XXXXXDLL(ProcessId, ImageInfo->ImageBase, rlpDlls, nDlls);
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
郁金香VC++过驱动保护全套 免key版 天異赤提供 教程下载地址获取方法: 第一步:打开下方链接,填写QQ邮箱,系统会往QQ邮箱发一封确认订阅邮件 第二步:打开QQ邮箱查看邮件,确认订阅,订阅成功后系统会自动把下载地址和解压密码一起发送到你QQ邮箱http://list.qq.com/cgi-bin/qf_invite?id=585e150c59f30e1213af9a9352367711b2e45c217582cf35 最近时间有些多,一时对网络游戏的保护机制感兴趣了,来研究了一下,听说QQ系列的TesSafe.sys 有些强,于是拿来看看驱动都做了些什 么.以下是对DNF和QQffo(自由幻想)研究结果(xp sp2) 在网上找了些TesSafe的资料,说TesSafe并不怎么样 现在这个版本保护的结果为:任务管理器可以看到游戏进程,但OD和CE看不见,更不用说什么调试了,iceword可以 看到EPROCSS,但WSysCheck看 郁金香驱动 不见,自己写程序,也不能注入受保护的游戏进程. 可见,NtOpenProcess被Hook了,恢复SSDT后,没有任何效果,可见是inline hook , 用一般的软件检测一下,没有发现inline hook,看来hook得比较深,在网上一找资料才发现,原来的确够隐藏的 郁金香驱动 以下是上一个TesSafe版本的分析结果 从网上找出来的资料,TesSafe.sys保护原理(DNF的保护,我听说,QQ系列游戏的保护机制都是一样的) ================================================================= 保护得比较没有意思,强度也不高.可能隐藏性稍好一些. 用IDA反汇编TesSafe.sys可以看到: 这个驱动一加载,ExAllocPoolWithTag分配了一块内存,然后将一个函数写进这块内存,接着做好保护,然后 PsCreateSystemThread()创建的 郁金香驱动 线程调用ZwUnloadDriver将驱动卸载。虽 然驱动被卸载了,但是ExAllocPoolWithTag分配的内存仍然在起作用。 具体来看它如何进行保护: 郁金香驱动 先是得到了ObOpenObjectByPointer的地址,然后在 NtOpenProcess搜索0xe8 ,也就是跳转指令,直到遇见RET为止。 一但得到0xe8,比较后面的四个字节,如果转换后为 ObOpenObjectByPointer的地址,就把这个地址用自己代理函数的地址转换后替换掉,达到 保护自己的目的。 郁金香驱动 用WinDbg看了看,果然在我的机器上:0x80570e41这个在 NtOpenProcess的区域被TesSafe.sys修改,原来这里是:80570e41 e87c8dffff call nt!ObOpenObjectByPointer (80569bc2) 系统通过ObOpenObjectByPointer来通过 EPROCESS得到Handle返回给调用者。TENCENT在这里下了一个跳转:(TesSafe.sys加载后。)80570e41 e826542a78 call f881626c 很明显,系统执行到这里就会调用0x6881626c的函数,也就是 TesSafe.sys的 ObOpenObjectByPointer代理函数。这 样,Client.exe就会在这里被过滤掉,从而让R3程序无法得到QQT的句柄,从而保护进程。 郁金香驱动 ================================================================================= 我手头拿到的版本是2008年8月5号的,把TesSafe逆出来一看,比上个版本有所加强. 在这个新版本,TesSafe一共InLine Hook了六个函数,我只逆出并恢复了五个 其: 1. KeAttachProcess NtOpenProcess NtOpenThread 这三个函数的HOOK方式与上一个版本一样,就是上面蓝色字体的方法,把本应该call ObOpenObjectByPointe的代码修改成了call他自己的代码, 然后在他自己的代码处理保护的进程 上面三个函数,原来正常的代码为 80581ce3 e8a658ffff call nt!ObOpenObjectByPointer (8057758e) 被HOOK后的代码变成了 call a8724af4(TesSafe自己搞出来的函数) lkd> u a8724af
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值