原文:http://www.cnblogs.com/Y4ng/archive/2012/09/06/EnumProcessHandle_EnumMutex.html
相信做過遊戲多開的朋友就會發現,很多遊戲普遍使用互斥mutex來防止程式多開,說實話這種方式已經非常OUT了。但是由於時間和技術的沉澱關係,留下來的遊戲依然會存在這種方式。 最近接觸到一款遊戲是N前非常火熱的對戰遊戲,可以稱為經典之作;它就是用的Mutant來實現遊戲防止多開的,一般我們們測試的時候都是用Xuetr來關閉遊戲,但是要作為成品釋出不可能要求客戶拿Xuetr來列程式物件控制程式碼,關控制程式碼吧~
網上搜尋了半天都沒有找到列舉程式控制程式碼的例子,經過群裡的大牛提點指到 ZwQuerySystemInformation SystemHandleInformation 可以實現控制程式碼列舉功能;經過一番搜尋編碼測試 於是有了本文程式碼;
/*標頭檔案宣告*/ typedef LONG NTSTATUS; #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, // 0 Y N SystemProcessorInformation, // 1 Y N SystemPerformanceInformation, // 2 Y N SystemTimeOfDayInformation, // 3 Y N SystemNotImplemented1, // 4 Y N SystemProcessesAndThreadsInformation, // 5 Y N SystemCallCounts, // 6 Y N SystemConfigurationInformation, // 7 Y N SystemProcessorTimes, // 8 Y N SystemGlobalFlag, // 9 Y Y SystemNotImplemented2, // 10 Y N SystemModuleInformation, // 11 Y N SystemLockInformation, // 12 Y N SystemNotImplemented3, // 13 Y N SystemNotImplemented4, // 14 Y N SystemNotImplemented5, // 15 Y N SystemHandleInformation, // 16 Y N SystemObjectInformation, // 17 Y N SystemPagefileInformation, // 18 Y N SystemInstructionEmulationCounts, // 19 Y N SystemInvalidInfoClass1, // 20 SystemCacheInformation, // 21 Y Y SystemPoolTagInformation, // 22 Y N SystemProcessorStatistics, // 23 Y N SystemDpcInformation, // 24 Y Y SystemNotImplemented6, // 25 Y N SystemLoadImage, // 26 N Y SystemUnloadImage, // 27 N Y SystemTimeAdjustment, // 28 Y Y SystemNotImplemented7, // 29 Y N SystemNotImplemented8, // 30 Y N SystemNotImplemented9, // 31 Y N SystemCrashDumpInformation, // 32 Y N SystemExceptionInformation, // 33 Y N SystemCrashDumpStateInformation, // 34 Y Y/N SystemKernelDebuggerInformation, // 35 Y N SystemContextSwitchInformation, // 36 Y N SystemRegistryQuotaInformation, // 37 Y Y SystemLoadAndCallImage, // 38 N Y SystemPrioritySeparation, // 39 N Y SystemNotImplemented10, // 40 Y N SystemNotImplemented11, // 41 Y N SystemInvalidInfoClass2, // 42 SystemInvalidInfoClass3, // 43 SystemTimeZoneInformation, // 44 Y N SystemLookasideInformation, // 45 Y N SystemSetTimeSlipEvent, // 46 N Y SystemCreateSession, // 47 N Y SystemDeleteSession, // 48 N Y SystemInvalidInfoClass4, // 49 SystemRangeStartInformation, // 50 Y N SystemVerifierInformation, // 51 Y Y SystemAddVerifier, // 52 N Y SystemSessionProcessesInformation // 53 Y N } SYSTEM_INFORMATION_CLASS; typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; }CLIENT_ID,*PCLIENT_ID; typedef struct { USHORT Length; USHORT MaxLen; USHORT *Buffer; }UNICODE_STRING, *PUNICODE_STRING; typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; typedef struct _IO_COUNTERSEX { LARGE_INTEGER ReadOperationCount; LARGE_INTEGER WriteOperationCount; LARGE_INTEGER OtherOperationCount; LARGE_INTEGER ReadTransferCount; LARGE_INTEGER WriteTransferCount; LARGE_INTEGER OtherTransferCount; } IO_COUNTERSEX, *PIO_COUNTERSEX; typedef enum { StateInitialized, StateReady, StateRunning, StateStandby, StateTerminated, StateWait, StateTransition, StateUnknown } THREAD_STATE; typedef struct _VM_COUNTERS { SIZE_T PeakVirtualSize; SIZE_T VirtualSize; ULONG PageFaultCount; SIZE_T PeakWorkingSetSize; SIZE_T WorkingSetSize; SIZE_T QuotaPeakPagedPoolUsage; SIZE_T QuotaPagedPoolUsage; SIZE_T QuotaPeakNonPagedPoolUsage; SIZE_T QuotaNonPagedPoolUsage; SIZE_T PagefileUsage; SIZE_T PeakPagefileUsage; } VM_COUNTERS; typedef VM_COUNTERS *PVM_COUNTERS; typedef struct _SYSTEM_THREADS { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER CreateTime; ULONG WaitTime; PVOID StartAddress; CLIENT_ID ClientId; ULONG Priority; ULONG BasePriority; ULONG ContextSwitchCount; THREAD_STATE State; ULONG WaitReason; } SYSTEM_THREADS, *PSYSTEM_THREADS; typedef struct _SYSTEM_PROCESSES { // Information Class 5 ULONG NextEntryDelta; ULONG ThreadCount; ULONG Reserved1[6]; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ProcessName; ULONG BasePriority; ULONG ProcessId; ULONG InheritedFromProcessId; ULONG HandleCount; ULONG Reserved2[2]; VM_COUNTERS VmCounters; IO_COUNTERSEX IoCounters; // Windows 2000 only SYSTEM_THREADS Threads[1]; } SYSTEM_PROCESSES, *PSYSTEM_PROCESSES; typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG ProcessId; UCHAR ObjectTypeNumber; UCHAR Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; typedef enum _OBJECT_INFORMATION_CLASS { ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectAllInformation, ObjectDataInformation } OBJECT_INFORMATION_CLASS; typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING Name; } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; typedef NTSTATUS (NTAPI *NTQUERYOBJECT)( _In_opt_ HANDLE Handle, _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, _Out_opt_ PVOID ObjectInformation, _In_ ULONG ObjectInformationLength, _Out_opt_ PULONG ReturnLength ); typedef NTSTATUS (NTAPI *ZWQUERYSYSTEMINFORMATION)( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ); ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwQuerySystemInformation"); NTQUERYOBJECT NtQueryObject = (NTQUERYOBJECT)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQueryObject");
/*功能函式體*/ int _tmain(int argc, _TCHAR* argv[]) { DWORD dwSize = 0; PSYSTEM_HANDLE_INFORMATION pmodule = NULL; POBJECT_NAME_INFORMATION pNameInfo; POBJECT_NAME_INFORMATION pNameType; PVOID pbuffer = NULL; NTSTATUS Status; int nIndex = 0; DWORD dwFlags = 0; char szType[128] = {0}; char szName[512] = {0}; if(!ZwQuerySystemInformation) { goto Exit0; } pbuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); if(!pbuffer) { goto Exit0; } Status = ZwQuerySystemInformation(SystemHandleInformation, pbuffer, 0x1000, &dwSize); if(!NT_SUCCESS(Status)) { if (STATUS_INFO_LENGTH_MISMATCH != Status) { goto Exit0; } else { // 這裡大家可以保證程式的正確性使用迴圈分配稍好 if (NULL != pbuffer) { VirtualFree(pbuffer, 0, MEM_RELEASE); } if (dwSize*2 > 0x4000000) // MAXSIZE { goto Exit0; } pbuffer = VirtualAlloc(NULL, dwSize*2, MEM_COMMIT, PAGE_READWRITE); if(!pbuffer) { goto Exit0; } Status = ZwQuerySystemInformation(SystemHandleInformation, pbuffer, dwSize*2, NULL); if(!NT_SUCCESS(Status)) { goto Exit0; } } } pmodule = (PSYSTEM_HANDLE_INFORMATION)((PULONG)pbuffer+1); dwSize = *((PULONG)pbuffer); for(nIndex = 0; nIndex < dwSize; nIndex++) { Status = NtQueryObject((HANDLE)pmodule[nIndex].Handle, ObjectNameInformation, szName, 512, &dwFlags); if (!NT_SUCCESS(Status)) { goto Exit0; } Status = NtQueryObject((HANDLE)pmodule[nIndex].Handle, ObjectTypeInformation, szType, 128, &dwFlags); if (!NT_SUCCESS(Status)) { goto Exit0; } pNameInfo = (POBJECT_NAME_INFORMATION)szName; pNameType = (POBJECT_NAME_INFORMATION)szType; printf("%wZ %wZ\n", pNameType, pNameInfo); // 匹配是否為需要關閉的控制程式碼名稱 if (0 == wcscmp((wchar_t *)pNameType->Name.Buffer, L"Mutant")) { if (wcsstr((wchar_t *)pNameInfo->Name.Buffer, CLOSEMUTEXNAME)) { CloseHandle((HANDLE)pmodule[nIndex].Handle); goto Exit0; } } } Exit0: if (NULL != pbuffer) { VirtualFree(pbuffer, 0, MEM_RELEASE); } return 0; }
CLOSEMUTEXNAME 為互斥的控制程式碼名稱,需要為寬位元組;
程式執行結果如下:
為了測試方便直接把程式寫入了main函式中,大家使用的時候稍微修改便可, 不過!得理解程式意思才行啊。 copy程式碼不做思考的程式設計師不是好裁縫!
參考文章列表:
ZwQuerySystemInformation列舉核心模組及簡單應用 http://hi.baidu.com/_achillis/item/8b33ead8ccac28ea3cc2cb17