问题描述
有人知道Windows 8上LDR_MODULE.LoadCount在哪里吗?
Does anyone know where LDR_MODULE.LoadCount is on windows 8?
以下代码始终打印6作为参考计数:S我用RemoteDLLTool和基地址检查了所有其他信息是否正确.但是,LoadCount始终是6,这是错误的.我读到,如果它是6,则意味着DLL是动态加载的;如果它是-1,则它是静态的.
The following code always prints 6 for the reference count :SI checked with a RemoteDLLTool and the baseaddress and all other information is correct. However, LoadCount is wrong as it is always 6. I read that if it is 6, it means the DLL is loaded dynamically and if it is -1, it is static.
还有没有一种方法可以让我迭代链接列表,而不必不断读取ReadProcessMemory?
Also is there a way I can just iterate the linked list without having to constantly ReadProcessMemory?
我需要以某种方式弄清楚引用计数..基本上,Windows 7上的以下代码将告诉我DLL被加载了多少次..也就是DLL的引用计数.
I need to figure out the reference count somehow.. Basically the code below on Windows 7 will tell me how many times a DLL is loaded.. aka the reference count to the DLL.
#include <winternl.h>
typedef struct _LDR_MODULE
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
int GetModuleLoadCount()
{
DWORD dwBytesRead = 0;
PROCESS_BASIC_INFORMATION PBI = {0};
HANDLE ProcessHandle = GetCurrentProcess();
if (NT_SUCCESS(NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &PBI, sizeof(PBI), &dwBytesRead)))
{
PEB_LDR_DATA LdrData;
LDR_MODULE LdrModule;
PPEB_LDR_DATA pLdrData = nullptr;
PLDR_MODULE pLdrModule = nullptr;
char* LdrDataOffset = reinterpret_cast<char*>(PBI.PebBaseAddress) + offsetof(PEB, Ldr);
ReadProcessMemory(ProcessHandle, LdrDataOffset, &pLdrData, sizeof(pLdrData), &dwBytesRead);
ReadProcessMemory(ProcessHandle, pLdrData, &LdrData, sizeof(LdrData), &dwBytesRead);
LIST_ENTRY* Head = LdrData.InMemoryOrderModuleList.Flink;
LIST_ENTRY* Next = Head;
do
{
LDR_DATA_TABLE_ENTRY LdrEntry;
LDR_DATA_TABLE_ENTRY* Base = CONTAINING_RECORD(Head, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (ReadProcessMemory(ProcessHandle, Base, &LdrEntry, sizeof(LdrEntry), &dwBytesRead))
{
char* pLdrModuleOffset = reinterpret_cast<char*>(Head) - sizeof(LIST_ENTRY);
ReadProcessMemory(ProcessHandle, pLdrModuleOffset, &pLdrModule, sizeof(pLdrModule), &dwBytesRead);
ReadProcessMemory(ProcessHandle, pLdrModule, &LdrModule, sizeof(LdrModule), &dwBytesRead);
if (LdrEntry.DllBase)
{
std::cout<<"BaseAddress: "<< LdrModule.BaseAddress<<std::endl;
std::cout<<"Reference Count: "<< LdrModule.LoadCount<<std::endl;
}
Head = LdrEntry.InMemoryOrderLinks.Flink;
}
}
while (Head != Next);
}
CloseHandle(ProcessHandle);
return 0;
}
关于如何在Windows 8上执行相同操作的任何想法?
Any ideas on how to do the same on Windows 8?
推荐答案
在Windows 8.1上进行了测试.无法保证此功能将在较新的Windows上运行(例如,不过10个-根据文档,应该可以正常工作)
Tested on Windows 8.1. Will not guarantee that this will work on newer windows (e.g. 10, however - according to documentation should be working)
#include <winternl.h> //PROCESS_BASIC_INFORMATION
// warning C4996: 'GetVersionExW': was declared deprecated
#pragma warning (disable : 4996)
bool IsWindows8OrGreater()
{
OSVERSIONINFO ovi = { 0 };
ovi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
GetVersionEx(&ovi);
if( (ovi.dwMajorVersion == 6 && ovi.dwMinorVersion >= 2) || ovi.dwMajorVersion > 6 )
return true;
return false;
} //IsWindows8OrGreater
#pragma warning (default : 4996)
bool ReadMem( void* addr, void* buf, int size )
{
BOOL b = ReadProcessMemory( GetCurrentProcess(), addr, buf, size, nullptr );
return b != FALSE;
}
#ifdef _WIN64
#define BITNESS 1
#else
#define BITNESS 0
#endif
typedef NTSTATUS (NTAPI *pfuncNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
//
// Queries for .dll module load count, returns 0 if fails.
//
int GetModuleLoadCount( HMODULE hDll )
{
// Not supported by earlier versions of windows.
if( !IsWindows8OrGreater() )
return 0;
PROCESS_BASIC_INFORMATION pbi = { 0 };
HMODULE hNtDll = LoadLibraryA("ntdll.dll");
if( !hNtDll )
return 0;
pfuncNtQueryInformationProcess pNtQueryInformationProcess = (pfuncNtQueryInformationProcess)GetProcAddress( hNtDll, "NtQueryInformationProcess");
bool b = pNtQueryInformationProcess != nullptr;
if( b ) b = NT_SUCCESS(pNtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof( pbi ), nullptr ));
FreeLibrary(hNtDll);
if( !b )
return 0;
char* LdrDataOffset = (char*)(pbi.PebBaseAddress) + offsetof(PEB,Ldr);
char* addr;
PEB_LDR_DATA LdrData;
if( !ReadMem( LdrDataOffset, &addr, sizeof( void* ) ) || !ReadMem( addr, &LdrData, sizeof( LdrData ) ) )
return 0;
LIST_ENTRY* head = LdrData.InMemoryOrderModuleList.Flink;
LIST_ENTRY* next = head;
do {
LDR_DATA_TABLE_ENTRY LdrEntry;
LDR_DATA_TABLE_ENTRY* pLdrEntry = CONTAINING_RECORD( head, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
if( !ReadMem( pLdrEntry , &LdrEntry, sizeof(LdrEntry) ) )
return 0;
if( LdrEntry.DllBase == (void*)hDll )
{
//
// http://www.geoffchappell.com/studies/windows/win32/ntdll/structs/ldr_data_table_entry.htm
//
int offDdagNode = (0x14 - BITNESS) * sizeof(void*); // See offset on LDR_DDAG_NODE *DdagNode;
ULONG count = 0;
char* addrDdagNode = ((char*)pLdrEntry) + offDdagNode;
//
// http://www.geoffchappell.com/studies/windows/win32/ntdll/structs/ldr_ddag_node.htm
// See offset on ULONG LoadCount;
//
if( !ReadMem(addrDdagNode, &addr, sizeof(void*) ) || !ReadMem( addr + 3 * sizeof(void*), &count, sizeof(count) ) )
return 0;
return (int)count;
} //if
head = LdrEntry.InMemoryOrderLinks.Flink;
}while( head != next );
return 0;
} //GetModuleLoadCount
用于注入的.dll的用途:
Usage for injected .dll's:
// Someone reserved us, let's force us to shutdown.
while( GetModuleLoadCount( dll ) > 1 )
FreeLibrary(dll);
FreeLibraryAndExitThread(dll, 0);
(2016年12月31日更新)但是请注意-建议从主线程使用此功能.主要问题是当您迭代dll时-DLL也可以释放,此后无限循环挂起"while-loop".
(Update 3.12.2016) Please notice however - that it's recommended to use this function from main thread. The main problem is when you're iterating dll's - dll's can be freed as well, after which "while-loop" hungs infinitely.
如果侧线程正在释放dll,那么也可能从主线程中发生这种令人惊讶的dll删除,但是这种情况很少发生.
Such surprise dll removal can happen also from main thread as well, if side thread is freeing dll, but this happens more rarely.
这篇关于Windows 8上的DLL LoadCount的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!