下面的文字,主要是为了分享给和我一样的菜鸟,而且这些东西都是很多大牛的文章中的一个非常小的部分。您们直接飘过吧。
一些程序限制多开的方法很多,比如采用窗口名,进程名,内核对象等等,论坛中也有很多关于这方面的介绍,但是好像没有一个具体的例子,估计是觉得太简单了吧。我研究的这程序的限制多开的方法采用的是“内核对象信号量”。
要破解其多开也有很多方法:
1、直接找到其创建信号量的代码,暴力修改相关的跳转代码。
但是这种方法,需要定位代码位置,然后修改它,随着这个程序的更新,其位置也会改变,需要根据特征码来获得其地址,比较麻烦,不是很通用。
2、hook api,hook创建信号量的API,然后根据创建的名字判断是否是限制多开的信号量,如果是,修改其返回值来解决问题。
这个方法看起来比较好,但是对于一些带驱动保护,又带代码校验的程序来说,就有些困难。而且也需要修改程序的代码。
3、获取这个信号量的句柄,直接关闭它,减少其引用计数,从而解决问题。
自己认为这个方法相对比较好,首先不需要修改代码,其次对于采用内核对象进行多开的程序,具有通用性和移植性。
当然还有其他的方法。不过我没想到。所以我选择方案3。
要解决这个问题:
1)去掉它的驱动保护。在拜读论坛前辈的相关文章后已经实现。
2)将DLL插入到这个程序的进程中。这个也已经实现。
3)根据信号量的名字获取它的句柄。未实现。
4)关闭这个句柄。 很容易,直接CloseHandle就可以了。
因此关键是根据名字获取它的句柄这个步骤。在论坛胡乱goole了一通,第一次没找到头绪,太菜,连搜索找东西都慢。于是就在论坛发个求助帖,请大牛们指点。等待的回复还是挺折磨人的,一边刷新求助的页面,一边自己找方法。
在搜索的过程中,我发现很多前辈写的文章中,有类似的应用,虽然不是针对信号量的,但是比如枚举系统的所有进程等。我就是从枚举进程入手的。这里用到的一个 native API函数 "ZwQuerySystemInformation"。使用这个函数可以获取整个系统的所有句柄的信息,在论坛提供的“Crack_New_Year_Presents_2009”中的“Windows NT 2000 Native API Reference.pdf”,我找到了这个函数的具体应用。
“Crack_New_Year_Presents_2009”中的很多工具和资料对我的帮助很大,省去了我搜索下载的大量时间,马上2010就到了,期待kanxue老大的“Crack_New_Year_Presents_2010”。
下面的代码很多是在前辈代码基础上修改的,感谢他们。
更加通用的是不需DLL插入到进程中,而是直接采用打开进程,复制对象,进行名字判断,如果是,则采用创建远线程的方式关闭对象。但是对于我这个程序来说,由于有进程保护,所以没有采用。
#pragma once
#include "StdAfx.h"
#include <malloc.h>
#include <memory.h>
typedef enum _SYSTEM_INFORMATION_CLASS
{
SystemBasicInformation = 0, // 0
SystemProcessorInformation, // 1
SystemPerformanceInformation, // 2
SystemTimeOfDayInformation, // 3
SystemNotImplemented1, // 4
SystemProcessesAndThreadsInformation = 5, // 5
SystemCallCounts, // 6
SystemConfigurationInformation, // 7
SystemProcessorTimes, // 8
SystemGlobalFlag, // 9
SystemNotImplemented2, // 10
SystemModuleInformation, // 11
SystemLockInformation, // 12
SystemNotImplemented3, // 13
SystemNotImplemented4, // 14
SystemNotImplemented5, // 15
SystemHandleInformation, // 16
SystemObjectInformation, // 17
SystemPagefileInformation, // 18
SystemInstructionEmulationCounts, // 19
SystemInvalidInfoClass1, // 20
SystemCacheInformation, // 21
SystemPoolTagInformation, // 22
SystemProcessorStatistics, // 23
SystemDpcInformation, // 24
SystemNotImplemented6, // 25
SystemLoadImage, // 26
SystemUnloadImage, // 27
SystemTimeAdjustment, // 28
SystemNotImplemented7, // 29
SystemNotImplemented8, // 30
SystemNotImplemented9, // 31
SystemCrashDumpInformation, // 32
SystemExceptionInformation, // 33
SystemCrashDumpStateInformation, // 34
SystemKernelDebuggerInformation, // 35
SystemContextSwitchInformation, // 36
SystemRegistryQuotaInformation, // 37
SystemLoadAndCallImage = 38, // 38
SystemPrioritySeparation, // 39
SystemNotImplemented10, // 40
SystemNotImplemented11, // 41
SystemInvalidInfoClass2, // 42
SystemInvalidInfoClass3, // 43
SystemTimeZoneInformation, // 44
SystemLookasideInformation, // 45
SystemSetTimeSlipEvent, // 46
SystemCreateSession, // 47
SystemDeleteSession, // 48
SystemInvalidInfoClass4, // 49
SystemRangeStartInformation, // 50
SystemVerifierInformation, // 51
SystemAddVerifier, // 52
SystemSessionProcessesInformation // 53
} SYSTEM_INFORMATION_CLASS;
typedef enum _OBJECT_INFORMATION_CLASS
{
ObjectBasicInformation = 0,
ObjectNameInformation = 1,
ObjectTypeInformation = 2,
} OBJECT_INFORMATION_CLASS;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG ProcessId; //进程标识符
UCHAR ObjectTypeNumber; //打开的对象的类型
UCHAR Flags; //句柄属性标志
USHORT Handle; //句柄数值,在进程打开的句柄中唯一标识某个句柄
PVOID Object; //句柄对应的EPROCESS的地址
ACCESS_MASK GrantedAccess; //句柄对象的访问权限
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
ULONG NumberOfHandles; //句柄数目
SYSTEM_HANDLE_INFORMATION Information[1];
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _OBJECT_NAME_INFORMATION
{
UNICODE_STRING Name;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
typedef LONG NTSTATUS;
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
typedef NTSTATUS (WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);
typedef NTSTATUS (WINAPI *ZWQUERYOBJECT)(IN HANDLE OPTIONAL,IN OBJECT_INFORMATION_CLASS,OUT PVOID OPTIONAL,IN ULONG,OUT PULONG OPTIONAL);
/***********************************************************************************************
* 函数名称 : CloseObjectByName
* 函数用途 : 根据输入的对象名,将其关闭。
* 输入参数 : char *pObjectName 要关闭的对象名。
* 返 回 : 略
* 注 意 : 只适用用于本进程。
/**********************************************************************************************/
bool CloseObjectByName(char *pObjectName)
{
int i;
ULONG pid;
ULONG ulSize;
ULONG* pHandleInfor;
CHAR pName[200];
NTSTATUS ntStatus;
HMODULE hHanlde;
POBJECT_NAME_INFORMATION ObjName;
PSYSTEM_HANDLE_INFORMATION_EX Handles;
ZWQUERYOBJECT ZwQueryObject;
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation;
//初始化变量
ulSize = 0x4000;
pHandleInfor = NULL;
ZwQueryObject = NULL;
ZwQuerySystemInformation =NULL; //由于ZwQueryObject和ZwQuerySystemInformation是未导出的函数,需要动态加载Ntdll,dll,然后通过函数GetProcAddress
//得到它们的函数地址,由于这个dll一般的进程都会在创建的时候加载,所以省略加载,直接获取其模块地址
hHanlde = GetModuleHandle("ntdll.dll");
if(NULL == hHanlde)
{
//加载Ntdll.dll失败
return false;
}
//获取ZwQuerySystemInformation函数地址
ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hHanlde, "ZwQuerySystemInformation");
if(NULL == ZwQuerySystemInformation)
{
//获取ZwQuerySystemInformation函数地址失败
return false;
}
//获取ZwQueryObject函数地址
ZwQueryObject = (ZWQUERYOBJECT)GetProcAddress(hHanlde, "ZwQueryObject");
if(NULL == ZwQueryObject)
{
//获取ZwQueryObject函数地址失败
return false;
}
//获取系统所有句柄信息
do
{
//申请内存
pHandleInfor = (ULONG*)malloc(ulSize);
if(NULL == pHandleInfor)
{
//申请内存失败
return false;
}
ntStatus = ZwQuerySystemInformation( SystemHandleInformation, pHandleInfor, ulSize, NULL);
if(!NT_SUCCESS(ntStatus))
{
//空间不足继续申请。
free(pHandleInfor);
ulSize = ulSize * 2;
//为防止ZwQuerySystemInformation一直失败,程序陷入死循环,当申请的空间超过64M时则返回失败
if(ulSize > 0x4000000)
{
return false;
}
}
}while(!NT_SUCCESS(ntStatus));
//转换数据结构类型
Handles = (PSYSTEM_HANDLE_INFORMATION_EX)pHandleInfor;
if(NULL == Handles)
{
return false;
}
//获取当前进程pid
pid = GetCurrentProcessId();
//申请空间,用于存储对象的名字信息
ObjName = (POBJECT_NAME_INFORMATION)malloc(0x2000 );
//开始搜索获取的句柄信息,并对句柄对应的对象名进行比较,如果与要求关闭的名字相同,则关闭此句柄
for(i = 0; i < Handles->NumberOfHandles; i++)
{
//对于不是本进程的句柄对象,直接pass掉,如果要实现关闭其它进程的对象,则可以首先根据PID打开这个句柄所在的进程,
//然后复制此对象,然后进行名字比较,如果相同,则可以通过创建远程线程的方式,关闭掉。
if(pid != Handles->Information[i].ProcessId)
{
continue;
}
//获取这个对象的名字信息
ntStatus = ZwQueryObject((HANDLE)Handles->Information[i].Handle, ObjectNameInformation, ObjName, 0x2000, NULL);
if(!NT_SUCCESS(ntStatus))
{
//查询对象失败,进行下一个
continue;
}
//将unicode 字串转换为 ansi字串
WideCharToMultiByte(CP_ACP, 0, ObjName->Name.Buffer, -1, pName, 200, NULL, NULL);
if( 0 == strcmp(pName, pObjectName))
{
//找到对应名字的对象,将其关闭
CloseHandle((HANDLE)Handles->Information[i].Handle);
}
}
//释放申请的空间
free(Handles);
free(ObjName);
return true;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)