@Necrolis, liên kết của bạn tới “The covert way to find the Reference Count of DLL” quá hấp dẫn để tôi bỏ qua vì nó chứa các chi tiết kỹ thuật cần thiết để triển khai giải pháp thay thế này (mà tôi nghĩ đến ngày hôm qua, nhưng thiếu Windows Internals). Cảm ơn. Tôi đã bình chọn cho câu trả lời của bạn vì liên kết bạn đã chia sẻ.
Các bài viết liên quan cho thấy làm thế nào để đến được với các nội LDR_MODULE
:
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;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
Ngay ở đây chúng tôi có EntryPoint
, con trỏ bên trong Window để điểm nhập của module. Đối với một dll là DllMain
(hoặc chức năng thời gian chạy ngôn ngữ cuối cùng gọi là DllMain
). Nếu chúng ta thay đổi điều đó thì sao? Tôi đã viết một bài kiểm tra và có vẻ như nó hoạt động, ít nhất là trên XP. Móc DllMain
được gọi với lý do DLL_PROCESS_DETACH
ngay trước khi tải DLL xuống.
BaseAddress
có cùng giá trị với số HMODULE
và hữu ích cho việc tìm kiếm đúng LDR_MODULE
. Các LoadCount
là ở đây vì vậy chúng tôi có thể theo dõi đó.Và cuối cùng, FullDllName
hữu ích cho việc gỡ lỗi và giúp tìm kiếm tên DLL thay vì HMODULE
.
Đây là tất cả nội bộ của Windows. Đó là (chủ yếu) được ghi lại, nhưng the MSDN documentation cảnh báo “ZwQueryInformationProcess có thể bị thay đổi hoặc không khả dụng trong các phiên bản sau của Windows.”
Dưới đây là ví dụ đầy đủ (nhưng không kiểm tra lỗi đầy đủ). Dường như nó hoạt động nhưng không thấy nhiều thử nghiệm.
// HookDllEntryPoint.cpp by Jim Harkins (jimhark), Nov 2010
#include "stdafx.h"
#include <stdio.h>
#include <winternl.h>
#include <process.h> // for _beginthread, only needed for testing
typedef NTSTATUS(WINAPI *pfnZwQueryInformationProcess)(
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength);
HMODULE hmodNtdll = LoadLibrary(_T("ntdll.dll"));
// Should test pZwQueryInformationProcess for NULL if you
// might ever run in an environment where this function
// is not available (like future version of Windows).
pfnZwQueryInformationProcess pZwQueryInformationProcess =
(pfnZwQueryInformationProcess)GetProcAddress(
hmodNtdll,
"ZwQueryInformationProcess");
typedef BOOL(WINAPI *PDLLMAIN) (
__in HINSTANCE hinstDLL,
__in DWORD fdwReason,
__in LPVOID lpvReserved);
// Note: It's possible for pDllMainNew to be called before
// HookDllEntryPoint returns. If pDllMainNew calls the old
// function, it should pass a pointer to the variable used
// so we can set it here before we hook.
VOID HookDllEntryPoint(
HMODULE hmod, PDLLMAIN pDllMainNew, PDLLMAIN *ppDllMainOld)
{
PROCESS_BASIC_INFORMATION pbi = {0};
ULONG ulcbpbi = 0;
NTSTATUS nts = (*pZwQueryInformationProcess)(
GetCurrentProcess(),
ProcessBasicInformation,
&pbi,
sizeof(pbi),
&ulcbpbi);
BOOL fFoundMod = FALSE;
PLIST_ENTRY pcurModule =
pbi.PebBaseAddress->Ldr->InMemoryOrderModuleList.Flink;
while (!fFoundMod && pcurModule !=
&pbi.PebBaseAddress->Ldr->InMemoryOrderModuleList)
{
PLDR_DATA_TABLE_ENTRY pldte = (PLDR_DATA_TABLE_ENTRY)
(CONTAINING_RECORD(
pcurModule, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks));
// Note: pldte->FullDllName.Buffer is Unicode full DLL name
// *(PUSHORT)&pldte->Reserved5[1] is LoadCount
if (pldte->DllBase == hmod)
{
fFoundMod = TRUE;
*ppDllMainOld = (PDLLMAIN)pldte->Reserved3[0];
pldte->Reserved3[0] = pDllMainNew;
}
pcurModule = pcurModule->Flink;
}
return;
}
PDLLMAIN pDllMain_advapi32 = NULL;
BOOL WINAPI DllMain_advapi32(
__in HINSTANCE hinstDLL,
__in DWORD fdwReason,
__in LPVOID lpvReserved)
{
char *pszReason;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
pszReason = "DLL_PROCESS_ATTACH";
break;
case DLL_PROCESS_DETACH:
pszReason = "DLL_PROCESS_DETACH";
break;
case DLL_THREAD_ATTACH:
pszReason = "DLL_THREAD_ATTACH";
break;
case DLL_THREAD_DETACH:
pszReason = "DLL_THREAD_DETACH";
break;
default:
pszReason = "*UNKNOWN*";
break;
}
printf("\n");
printf("DllMain(0x%.8X, %s, 0x%.8X)\n",
(int)hinstDLL, pszReason, (int)lpvReserved);
printf("\n");
if (NULL == pDllMain_advapi32)
{
return FALSE;
}
else
{
return (*pDllMain_advapi32)(
hinstDLL,
fdwReason,
lpvReserved);
}
}
void TestThread(void *)
{
// Do nothing
}
// Test HookDllEntryPoint
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE hmodAdvapi = LoadLibrary(L"advapi32.dll");
printf("advapi32.dll Base Addr: 0x%.8X\n", (int)hmodAdvapi);
HookDllEntryPoint(
hmodAdvapi, DllMain_advapi32, &pDllMain_advapi32);
_beginthread(TestThread, 0, NULL);
Sleep(1000);
return 0;
}
là yêu cầu này để kiểm tra mã hoặc trong khi gỡ lỗi? – Chubsdad
@Chubsdad không chắc chắn chính xác ý bạn là gì bằng cách "kiểm tra mã" nhưng nó không phải để gỡ lỗi. –
Bạn có muốn kiểm tra progammatically nếu module đã được dỡ xuống? – Chubsdad