【发布时间】:2018-12-10 13:40:31
【问题描述】:
我正在尝试查看如何从内核代码中的任意地址获取已加载的模块映像名称。
在用户模式下我会这样做:
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?
【问题讨论】:
-
ZwQuerySystemInformation或Nt*(取决于以前的模式)与 SystemModuleInformation 并通过RTL_PROCESS_MODULES迭代 -
你称之为什么线程?内核模式线程没有 TEB。它为 0。所以我假设您在内核模式线程的上下文中调用它
-
@RbMm 是的内核模式。那么PEB呢?还有一个侧面问题。如果没有 TEB 为什么会有
nt!PsGetCurrentThreadTeb函数? -
因为
PsGetCurrentThreadTeb返回当前线程的 TEB 值。这里不清楚什么? 那么 PEB 怎么样? - 怎么样 - 用于什么过程? -
看起来你不明白。我的意思是在你调用的线程的上下文中。不是来自内核或用户模式。仅存在内核模式线程。存在用户模式线程。
标签: c windows kernel portable-executable