Levante la restricción de apertura múltiple del juego, cierre el mango mutex

Hay muchas formas de limitar el juego.

Por ejemplo, atravesar ventanas, atravesar procesos, archivos de configuración, registro, mutexes, direcciones mac, ip, archivos públicos, mapeo de memoria, etc. Hay muchos métodos.
Pero la gran mayoría de los juegos están limitados por el uso de mutexes.
En esta lección, explicaremos cómo cerrar el identificador mutex para lograr múltiples aperturas. El ejemplo es CQYH

 

(La sugerencia de protección aquí es agregar una variedad de restricciones de apertura múltiple y aumentar el uso de múltiples mutexes en la lógica, para evitar que se cierre directamente de manera maliciosa)

1. Más restricciones en la verificación

Primero abrimos el juego
Luego abre una segunda ventana
Se comprueba que hemos detectado que hemos abierto una ventana, pero no hay restricción

La restricción se produce al abrir la tercera ventana

Es obvio que hay más aperturas restringidas, solo se pueden abrir 2

 

2. La herramienta mira el mutex y lo cierra.

Podemos usar herramientas para ver mutexes, puede usar XT, PCH y otras herramientas
También puedes descargar directamente Pyark.zip desde la cuenta oficial: Ren Niaofei Reverse
Abra el software, encuentre nuestro proceso, haga clic derecho para ver el identificador

Hay muchos identificadores, encuentra el identificador de tipo Mutante

Encontré que hay muchos, ningún nombre puede ser ignorado.
Quedan 20-30 mangos con nombres
Cerrémoslos uno por uno para ver cuál está cerrado y luego podemos abrir más ventanas.
Se comprueba que con cerrar esto es suficiente, el nombre es AOD_Game

Puede abrir 3 ventanas

Tercero, escriba código para cerrar el identificador mutex

Agregue un archivo de encabezado "Mutex.h"
Se utiliza como identificador de mutex cerrado
 
#pragma once
#include <string.h>
#include <windows.h>
#include <winternl.h>
#include <TlHelp32.h>

// 定义需要的宏
#define STATUS_SUCCESS 0x00UL
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004

#define SystemHandleInformation 16
#define SE_DEBUG_PRIVILEGE 0x14

// 定义需要用到的结构体
typedef enum _OBJECT_INFORMATION_CLASSEX {
ObjBasicInformation = 0,
ObjNameInformation,
ObjTypeInformation,
} OBJECT_INFORMATION_CLASSEX;

typedef enum _PROCESSINFOCLASSEX
{
ProcessHandleInformation = 20,
}PROCESSINFOCLASSEX;

typedef struct _SYSTEM_HANDLE
{
ULONG ProcessId;
BYTE ObjectTypeNumber;
BYTE Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantAccess;
}SYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
DWORD HandleCount;
SYSTEM_HANDLE Handles[1];
}SYSTEM_HANDLE_INFORMATION;

typedef struct _OBJECT_NAME_INFORMATION
{
UNICODE_STRING ObjectName;
}OBJECT_NAME_INFORMATION;

// 声明未导出API
typedef NTSTATUS(WINAPI* ZwQueryInformationProcessProc)(HANDLE, PROCESSINFOCLASSEX, LPVOID, DWORD, PDWORD);
ZwQueryInformationProcessProc ZwQueryInformationProcess;

typedef NTSTATUS(WINAPI* ZwQuerySystemInformationProc)(DWORD, PVOID, DWORD, DWORD*);
ZwQuerySystemInformationProc ZwQuerySystemInformation;

typedef NTSTATUS(WINAPI* ZwQueryObjectProc)(HANDLE, OBJECT_INFORMATION_CLASSEX, PVOID, ULONG, PULONG);
ZwQueryObjectProc ZwQueryObject;

typedef NTSTATUS(WINAPI* RtlAdjustPrivilegeProc)(DWORD, BOOL, BOOL, PDWORD);
RtlAdjustPrivilegeProc RtlAdjustPrivilege;

typedef DWORD(WINAPI* ZwSuspendProcessProc)(HANDLE);
ZwSuspendProcessProc ZwSuspendProcess;

typedef DWORD(WINAPI* ZwResumeProcessProc)(HANDLE);
ZwResumeProcessProc ZwResumeProcess;

#pragma warning (disable: 6011) 
#pragma warning (disable: 6001) 
#pragma warning (disable: 6387) 
#include <stdio.h>

// 提升进程权限
BOOL ElevatePrivileges()
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
tkp.PrivilegeCount = 1;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
return FALSE;
}

return TRUE;
}

// 初始化未导出API
BOOL GetUnDocumentAPI()
{
ZwSuspendProcess = (ZwSuspendProcessProc)
GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwSuspendProcess");

ZwQuerySystemInformation = (ZwQuerySystemInformationProc)
GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQuerySystemInformation");

ZwQueryObject = (ZwQueryObjectProc)
GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQueryObject");

ZwResumeProcess = (ZwResumeProcessProc)
GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwResumeProcess");

ZwQueryInformationProcess = (ZwQueryInformationProcessProc)
GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQueryInformationProcess");

if ((ZwSuspendProcess == NULL) || \
(ZwQuerySystemInformation == NULL) || \
(ZwQueryObject == NULL) || \
(ZwResumeProcess == NULL) || \
(ZwQueryInformationProcess == NULL))
return FALSE;

return TRUE;
}

// 关闭指定Mutex 有问题关注公众号 任鸟飞逆向
BOOL closeMutexHandle(UINT Proc_id, const wchar_t* Mutex_name)
{
HANDLE duplicateHnd, sourceHnd = 0;
DWORD procHndNum;
SYSTEM_HANDLE* currnetHnd;
DWORD buffLen = 0x1000;
NTSTATUS status;
SYSTEM_HANDLE_INFORMATION* buff = (SYSTEM_HANDLE_INFORMATION*)malloc(buffLen);
UINT count = 0;
if ((ElevatePrivileges() == FALSE) || (GetUnDocumentAPI() == FALSE))
return FALSE;

do
{
status = ZwQuerySystemInformation(SystemHandleInformation, buff, buffLen, &buffLen);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
free(buff);
buff = (SYSTEM_HANDLE_INFORMATION*)malloc(buffLen);
}
else
break;

} while (1);

OBJECT_NAME_INFORMATION* objNameInfo = (OBJECT_NAME_INFORMATION*)malloc(0x1000);
OBJECT_NAME_INFORMATION* objTypeInfo = (OBJECT_NAME_INFORMATION*)malloc(0x1000);

for (int idx = 0; idx < (int)buff->HandleCount; idx++)
{
currnetHnd = &(buff->Handles[idx]);

if (currnetHnd->ProcessId == Proc_id)
{
sourceHnd = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_DUP_HANDLE | PROCESS_SUSPEND_RESUME, FALSE, Proc_id);
(ZwSuspendProcess)(sourceHnd);
(ZwQueryInformationProcess)(sourceHnd, ProcessHandleInformation, &procHndNum, sizeof(DWORD), NULL);
//进程有效句柄从4开始,每次以4递增
unsigned short hndNum = 4;
for (int idx = 0; idx < (int)procHndNum; hndNum += 4)
{
//判断是否为有效句柄,返回TRUE,就是有效句柄
if (!DuplicateHandle(sourceHnd,
(HANDLE)hndNum,
GetCurrentProcess(),
&duplicateHnd, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
continue;
}
else
{
memset(objNameInfo, 0, 0x1000);
memset(objTypeInfo, 0, 0x1000);

ZwQueryObject((HANDLE)duplicateHnd, ObjNameInformation, objNameInfo, 0x1000, NULL);
ZwQueryObject((HANDLE)duplicateHnd, ObjTypeInformation, objTypeInfo, 0x1000, NULL);

//找到互斥体 比较名字
if (wcscmp(objTypeInfo->ObjectName.Buffer, L"Mutant") == 0)
{
if (objNameInfo->ObjectName.Length != 0 && wcsstr(objNameInfo->ObjectName.Buffer, Mutex_name) != 0)
{
printf("%ws\n", objNameInfo->ObjectName.Buffer);
CloseHandle(duplicateHnd);

if (DuplicateHandle(sourceHnd,
(HANDLE)hndNum,
GetCurrentProcess(),
&duplicateHnd, 0, FALSE, DUPLICATE_CLOSE_SOURCE))
{
CloseHandle(duplicateHnd);
(ZwResumeProcess)(sourceHnd);
return TRUE;
}
}
count++;
if (count == 20) { return FALSE; }
}

CloseHandle(duplicateHnd);
idx++;
}
}
}
}
return FALSE;

Entonces llamamos
 
closeMutexHandle(sm[i].pid,L"AOD_Game");

Cuarto, ajuste la posición de la ventana para abrir más
Luego hacemos el diseño de la ventana.

Ok, nuestro efecto está logrado.

Supongo que te gusta

Origin blog.csdn.net/qq_43355637/article/details/130072675
Recomendado
Clasificación