0

std::lock_guard の使用中に奇妙なことに遭遇しました。注: MSVS 2012 と、このバージョンに含まれて出荷された新しい c++11 ヘッダーのミューテックス ヘッダーで宣言されている std::lock_guard を使用しています。

以下は、この動作を再現するためのコードです。この関数を使用すると、何らかの理由で dll の LoadCount がインクリメントされるようです。私の質問は、だれかが理由を説明できるかどうかです。また、LoadCount を混乱させない、使用できるより良いロック関数はありますか?

#include <windows.h>
#include <mutex>

typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;


typedef struct _LSA_UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;
typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;

typedef struct _RTL_USER_PROCESS_PARAMETERS {
   BYTE           Reserved1[16];
   PVOID          Reserved2[10];
   UNICODE_STRING ImagePathName;
   UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

typedef VOID (NTAPI *PPS_POST_PROCESS_INIT_ROUTINE) (VOID);

typedef struct _PEB {
    BYTE                          Reserved1[2];
    BYTE                          BeingDebugged;
    BYTE                          Reserved2[1];
    PVOID                         Reserved3[2];
    PPEB_LDR_DATA                 Ldr;
    PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
    BYTE                          Reserved4[104];
    PVOID                         Reserved5[52];
    PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
    BYTE                          Reserved6[128];
    PVOID                         Reserved7[1];
    ULONG                         SessionId;
} PEB, *PPEB;
typedef struct _PROCESS_BASIC_INFORMATION
{
    PVOID Reserved1;
    PPEB PebBaseAddress;
    PVOID Reserved2[2];
    ULONG_PTR UniqueProcessId;
    PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
typedef enum _PROCESSINFOCLASS
{
    ProcessBasicInformation = 0,
} PROCESSINFOCLASS, *PPROCESSINFOCLASS;

typedef struct _LDRP_CSLIST
{
    PSINGLE_LIST_ENTRY Tail;
} LDRP_CSLIST, *PLDRP_CSLIST;
typedef enum _LDR_DDAG_STATE
{
LdrModulesMerged = -5,
LdrModulesInitError = -4,
LdrModulesSnapError = -3,
LdrModulesUnloaded = -2,
LdrModulesUnloading = -1,
LdrModulesPlaceHolder = 0,
LdrModulesMapping = 1,
LdrModulesMapped = 2,
LdrModulesWaitingForDependencies = 3,
LdrModulesSnapping = 4,
LdrModulesSnapped = 5,
LdrModulesCondensed = 6,
LdrModulesReadyToInit = 7,
LdrModulesInitializing = 8,
LdrModulesReadyToRun = 9
} LDR_DDAG_STATE;
typedef struct _LDR_DDAG_NODE
{
LIST_ENTRY Modules;
PVOID ServiceTagList;
ULONG LoadCount;//this is where its located in windows 8
ULONG ReferenceCount;
ULONG DependencyCount;
union
{
    LDRP_CSLIST Dependencies;
    SINGLE_LIST_ENTRY RemovalLink;
};
LDRP_CSLIST IncomingDependencies;
LDR_DDAG_STATE State;
SINGLE_LIST_ENTRY CondenseLink;
ULONG PreorderNumber;
ULONG LowestLink;
} LDR_DDAG_NODE, *PLDR_DDAG_NODE;
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;
    USHORT obsoleteLoadCount;//in windows 8 this is obsolete
    USHORT TlsIndex;//but we can still use it in win 7 and below
union
{
        LIST_ENTRY HashLinks;
        struct CheckPtr
        {
            PVOID SectionPointer;
            ULONG CheckSum;
        };
};
union
{
        ULONG TimeDateStamp;
        PVOID LoadedImports;
};
struct _ACTIVATION_CONTEXT *EntryPointActivationContext;
PVOID PatchInformation;
PLDR_DDAG_NODE DdagNode;
} LDR_MODULE, *PLDR_MODULE;

typedef NTSTATUS (__stdcall *pfnZwQueryInformationProcess) (HANDLE, PROCESSINFOCLASS,
    PVOID, ULONG, PULONG);
pfnZwQueryInformationProcess ZwQueryInformationProcess;

DWORD GetModuleLoadCount(HMODULE hmod)
{
    HMODULE hModule = LoadLibrary("ntdll.dll");
    if(hModule==NULL)
       return NULL;
    ZwQueryInformationProcess = (pfnZwQueryInformationProcess) GetProcAddress(hModule, 
        "ZwQueryInformationProcess");
    if (ZwQueryInformationProcess == NULL) {
        FreeLibrary(hModule)
        return NULL;    // failed to get PEB
    }

PROCESS_BASIC_INFORMATION pbi;
    PROCESSINFOCLASS pic = ProcessBasicInformation;
    if (ZwQueryInformationProcess(GetCurrentProcess(), pic, &pbi, sizeof(pbi), NULL) 
        != STATUS_SUCCESS)
    {
        // ZwQueryInformationProcess failed...
        FreeLibrary(hModule);
        return NULL;
    }
    FreeLibrary(hModule);

LDR_MODULE *peb_ldr_module = (LDR_MODULE 
        *)pbi.PebBaseAddress->Ldr->InLoadOrderModuleList.Flink;
while((peb_ldr_module = (LDR_MODULE 
        *)peb_ldr_module->InLoadOrderModuleList.Flink)!=(LDR_MODULE 
        *)pbi.PebBaseAddress->Ldr->InLoadOrderModuleList.Blink) {
    if(peb_ldr_module->BaseAddress==hmod) {
        //well this actualy works in windows 8...
        //and probably vista with aero enabled as well...
        //anyway if it is obsolete its always 6
        //so we can if it out like this...
        if(peb_ldr_module->obsoleteLoadCount==6)
            return peb_ldr_module->DdagNode->LoadCount;
        else
            return peb_ldr_module->obsoleteLoadCount;
    }
}
if(peb_ldr_module->BaseAddress==hmod) {
    if(peb_ldr_module->obsoleteLoadCount==6)
        return peb_ldr_module->DdagNode->LoadCount;
    else
        return peb_ldr_module->obsoleteLoadCount;
}
}

mutable std::mutex g_logMutex;
void test()//test is just a function inside of my dll
{          //which is injected and running under low privileges in internet explorer as
           //an addon, I dont think that matters, but i dont want to leave any info out 
           //that might help answer my question.
int loadcount = GetModuleLoadCount((HMODULE)gModule);//its 1 here
    std::lock_guard<std::mutex> lock(g_logMutex);
loadcount = GetModuleLoadCount((HMODULE)gModule);//now its 2
}
4

1 に答える 1

0

もしそうなら、それは未定義の動作です。C++ は DLL について「認識」しません (DLL は Windows 固有であるため)。

多くの場合、動作中に競合状態が発生しているか、使用している std::lock_guard 実装がモジュール ハンドルをリークしています。

于 2012-09-01T23:07:19.370 に答える