如何从Windows内核空间中的任意地址获取模块映像名称?

时间:2018-07-02 10:40:24

标签: c windows kernel portable-executable

我试图查看如何从内核代码中的任意地址获取已加载的模块映像名称。

在用户模式下,我会这样做:

void* pAddr;
VOID* pBase;
WCHAR buff[MAX_PATH] = {0};

//Get address of some function in some module (just to test it)
pAddr = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetCurrentProcess");

//Get module base address
RtlPcToFileHeader(pAddr, &pBase);

//Get module image file name
GetModuleFileNameEx(GetCurrentProcess(), (HMODULE)pBase, buff, SIZEOF(buff));

如果我有pAddr可以指向内核或用户空间中的某个地址,是否可以在内核模式下执行相同的操作?


编辑:在等待答案的同时,我想出了自己的代码(使用未记录的遍历PEB的方式):

#ifdef CALLING_FROM_KERNEL_MODE
//Kernel mode
TEB* pTEB = (TEB*)PsGetCurrentThreadTeb();

#else
//User mode

#if defined(_M_X64)
//64-bit
TEB* pTEB = reinterpret_cast<TEB*>(__readgsqword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#else
//32-bit
TEB* pTEB = reinterpret_cast<TEB*>(__readfsdword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#endif

#endif

PEB* p_PEB = pTEB->ProcessEnvironmentBlock;
PEB_LDR_DATA* pPLD = p_PEB->Ldr;

const WCHAR* pModName = NULL;

LIST_ENTRY* pLE = &pPLD->InMemoryOrderModuleList;
LIST_ENTRY* pLE_Head = pLE;
while(pLE_Head != pLE->Flink)
{
    PLDR_DATA_TABLE_ENTRY pLDTE = CONTAINING_RECORD(pLE, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);

    size_t szcbSizeOfImg = (size_t)pLDTE->Reserved3[1];
    if((size_t)pAddr - (size_t)pLDTE->DllBase < szcbSizeOfImg)
    {
        pModName = pLDTE->FullDllName.Buffer;

        break;
    }

    pLE = pLE->Flink;
}

问题在于,尽管它从用户模式运行,但从内核模式PsGetCurrentThreadTeb()似乎返回NULL。这是否意味着内核线程没有TEB

1 个答案:

答案 0 :(得分:1)

这可以通过使用availableMeals通过value创建所有已加载模块的列表来完成

ZwQuerySystemInformation