classfree
驱动小牛
驱动小牛
  • 注册日期2004-05-23
  • 最后登录2019-01-06
  • 粉丝1
  • 关注1
  • 积分873分
  • 威望276点
  • 贡献值0点
  • 好评度85点
  • 原创分0分
  • 专家分0分
  • 社区居民
阅读:3659回复:4

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

楼主#
更多 发布于:2013-03-06 12:44
利用 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);
        }
    }
}
低调点!
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
沙发#
发布于:2013-03-06 16:39
这类东东,它的价值在于稳定性。

不过鼓励楼上的创新精神 :)
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
板凳#
发布于:2013-03-06 16:41
 特殊进程,有可能是  pe 结构不规范,追一下就明白了
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
correy
驱动牛犊
驱动牛犊
  • 注册日期2007-11-12
  • 最后登录2017-04-07
  • 粉丝0
  • 关注0
  • 积分76分
  • 威望531点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
  • 社区居民
地板#
发布于:2013-03-06 20:36
不错,
给出一个思路。
要通用64位,
搞定pe+.
wawadj
驱动牛犊
驱动牛犊
  • 注册日期2013-04-08
  • 最后登录2013-04-08
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2013-04-08 16:08
这方法不错  
游客

返回顶部