吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6819|回复: 14
收起左侧

[原创] R3下取伪句柄表的几种方式

[复制链接]
Aperodry 发表于 2018-4-7 12:57

R3下取伪句柄表的几种方式
目录

  1. 句柄(HANDLE)是什么?
    2.R3下获取句柄的几种方式
    • 通过 ZwQuerySystemInformation 函数获取        
    • 通过 ZwQueryInformationProcess 函数获取
  2. 关闭句柄的两种方式
    • 本地进程句柄的关闭
    • 远程进程句柄的关闭

最近碰到一个简单的老游戏,看了一下它的防多开就是通过 CreateFileMapping 函数以只读 方式创建了个文件映射对象 就和互斥体一样,本来劫持个DLL hook下就完事了,但是发现只有几个陌生的DLL可劫持 重点在于这个DLL加载时候对多开的检测已经完成,这就十分尴尬了。。。只好通过远程关闭文件映射句柄来实现多开 然后发现既然DLL可以劫持,又再句柄创建完成后,何不用DLL劫持来干掉句柄,这就滋生出来了几种操作了...

好了废话不多谈,开始写了,只适合小白看的基础性文章~~


一、句柄(HANDLE)是什么?

句柄(Handle)是Windows表示对象的(不是C++对象)
HWND就是其中一种,表示为窗口句柄。还有其他很多如图标句柄(hIco)、光标句柄(hCursor)、线程句柄(hThread)等等..

https://blog.csdn.net/shuyong1999/article/details/7171683
https://blog.csdn.net/ustbkuang/article/details/77862720
https://blog.csdn.net/maowei117/article/details/55254855
上面的为各大牛们对句柄的一些理解

对于句柄来说,我们只要获得了目标的句柄就可以为所欲为了,比如获得有权限的进程句柄就可以读写目标进程数据了(有保护的当我没说...),窗口句柄可以向指定窗口发送消息,线程句柄可以结束(Terminate)或是挂起Suspend指定线程(不是本地进程当我没说...)
当然对于互斥体句柄(Mutant)或是Section类型的句柄还是可以给它关闭为所欲为的。

二、R3下获取句柄的几种方式

我们知道系统层有句柄表,而用户层也能靠3环的几个函数获取:

通过 ZwQuerySystemInformation 函数获取

funQuerSystemInformation.png

此为查询系统信息的函数,当 SystemInformationClass 参数为 SystemHandleInformation(0x10)时查询系统句柄信息,
SystemInformationClass 如下定义:

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;

每一个enum元素对应着查询信息,而 SystemHandleInformation(0x10) 查询的为 SYSTEM_HANDLE_INFORMATIO 结构体指针的信息:

typedef struct _SYSTEM_HANDLE_INFORMATION
{
        ULONG            ProcessId;        //进程ID
        UCHAR            ObjectTypeNumber;
        UCHAR            Flags;
        USHORT            Handle;        //句柄
        PVOID            Object;        //句柄对象
        ACCESS_MASK        GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
        ULONG NumberOfHandles;    //数组数量
        SYSTEM_HANDLE Information[1];    //数组指针
}SYSTEM_HANDLE_INFORMATIO, *PSYSTEM_HANDLE_INFORMATION;

到了这里思路就很清晰了,那么怎么才能区分句柄获得我们想要的句柄呢 ?这里就用到另外一个函数 NtQueryObject :
funQuerObject.png
NtQueryObject 函数用来查询对象句柄信息,当 OBJECT_INFORMATION_CLASS参数为ObjectNameInformation(1)和ObjectTypeInformation(2)时分别查询句柄的名称和句柄类型 它们的定义和查询的结构体如下:

typedef enum _OBJECT_INFORMATION_CLASS {
        ObjectBasicInformation,
        ObjectNameInformation,
        ObjectTypeInformation,
        ObjectAllInformation,
        ObjectDataInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
//注释
//ObjectBasicInformation 对应结构为:OBJECT_BASIC_INFORMATION
//ObjectNameInformation 对应结构为:OBJECT_NAME_INFORMATION
//ObjectTypeInformation  对应结构为:OBJECT_TYPE_INFORMATION
//ObjectAllInformation  对应结构为:   OBJECT_ALL_INFORMATION
//ObjectDataInformation对应结构为:  OBJECT_DATA_INFORMATION

typedef struct
{
        USHORT Length;        //当前名称长度
        USHORT MaxLen;        //缓冲区最大长度
        USHORT *Buffer;        //Unicode 名称指针
}UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_NAME_INFORMATION {
        UNICODE_STRING          Name;
        WCHAR                   NameBuffer[0];
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;

typedef struct _OBJECT_TYPE_INFORMATION {
        UNICODE_STRING          TypeName;
        ULONG                   TotalNumberOfHandles;
        ULONG                   TotalNumberOfObjects;
        WCHAR                   Unused1[8];
        ULONG                   HighWaterNumberOfHandles;
        ULONG                   HighWaterNumberOfObjects;
        WCHAR                   Unused2[8];
        ACCESS_MASK             InvalidAttributes;
        GENERIC_MAPPING         GenericMapping;
        ACCESS_MASK             ValidAttributes;
        BOOLEAN                 SecurityRequired;
        BOOLEAN                 MaintainHandleCount;
        USHORT                  MaintainTypeList;
        POOL_TYPE               PoolType;
        ULONG                   DefaultPagedPoolCharge;
        ULONG                   DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;

到了这里就明了很多了,下面写个简单的Demo实现获取目的进程的句柄:

// 进程提权
bool EnableDebugPrivilege()
{
        HANDLE hToken;
        LUID sedebugnameValue;
        TOKEN_PRIVILEGES tkp;
        if( !OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken) )
        {
                return   FALSE;
        }
        if( !LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue) )
        {
                CloseHandle(hToken);
                return false;
        }
        tkp.PrivilegeCount = 1;
        tkp.Privileges[0].Luid = sedebugnameValue;
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        if( !AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL) )
        {
                CloseHandle(hToken);
                return false;
        }
        return true;
}
void LogOut(char *Format, ...)
{
        char szBuffer[1024];
        va_list pArgList;
        va_start(pArgList, Format);//参数列表初始化
        vsprintf_s(szBuffer, Format, pArgList);
        va_end(pArgList);
        OutputDebugString(szBuffer);
}

//初始化未文档化函数
BOOL InitUnDocumentProc()
{
        HMODULE hNtdll = GetModuleHandle("Ntdll.dll");
        if( hNtdll == NULL )        return FALSE;

        ZwQuerySystemInformation = \
                (pfnNtQuerySystemInformation)GetProcAddress(hNtdll, "NtQuerySystemInformation");
        ZwQueryObject = \
                (pfnNtQueryObject)GetProcAddress(hNtdll, "NtQueryObject");
        ZwQueryInformationProcess = \
                (pfnNtQueryInformationProcess)GetProcAddress(hNtdll, "NtQueryInformationProcess");

        if( (ZwQuerySystemInformation == NULL) || \
                (ZwQueryObject == NULL) || \
                (ZwQueryInformationProcess == NULL) )
                return FALSE;
        return TRUE;
}

SYSTEM_HANDLE_INFORMATIO_EX *GetSystemProcessHandleInfo()
{
        DWORD buffLen = 0x1000;
        NTSTATUS status;
        BYTE* buff = new BYTE[buffLen];
        do{
                status = ZwQuerySystemInformation(SystemHandleInformation, buff, buffLen, &buffLen);
                if( status == STATUS_INFO_LENGTH_MISMATCH )
                {
                        delete[] buff;
                        buff = new BYTE[buffLen];
                } else
                        break;

        } while( TRUE );
        return (SYSTEM_HANDLE_INFORMATIO_EX*)buff;
}
int _tmain(int argc, _TCHAR* argv[])
{
        EnableDebugPrivilege();
        InitUnDocumentProc();
        NTSTATUS Status;
        SYSTEM_HANDLE* CurHandle;
        OBJECT_NAME_INFORMATION *ObjectName;
        OBJECT_TYPE_INFORMATION *ObjectType;
        char BufferForObjectName[1024];
        char BufferForObjectType[1024];
        SYSTEM_HANDLE_INFORMATIO_EX *pInfo = GetSystemProcessHandleInfo();
        if( pInfo )
        {
                for( DWORD i = 0; i < pInfo->NumberOfHandles; i++ )
                {
                        CurHandle = &(pInfo->Information[i]);
                        if( CurHandle->ProcessId==GetCurrentProcessId())//自进程
                        {
                                ZeroMemory(BufferForObjectName, 1024);
                                ZeroMemory(BufferForObjectType, 1024);
                                //获取句柄类型
                                Status = ZwQueryObject((HANDLE)CurHandle->Handle, 
                                        ObjectTypeInformation,
                                        BufferForObjectType, 
                                        sizeof(BufferForObjectType), 
                                        NULL);

                                ObjectType = (OBJECT_TYPE_INFORMATION*)BufferForObjectType;
                                //if( Status == STATUS_INFO_LENGTH_MISMATCH || !NT_SUCCESS(Status) )
                                //        continue;

                                //获取句柄名
                                Status=ZwQueryObject((HANDLE)CurHandle->Handle, 
                                        ObjectNameInformation,
                                        BufferForObjectName, 
                                        sizeof(BufferForObjectName), 
                                        NULL);

                                ObjectName = (POBJECT_NAME_INFORMATION)BufferForObjectName;
                                //if( Status == STATUS_INFO_LENGTH_MISMATCH || !NT_SUCCESS(Status) )
                                //        continue;
                                LogOut("Type:%S Name:%S Handle=%X", ObjectType->TypeName.Buffer,
                                        ObjectName->Name.Buffer,
                                        CurHandle->Handle);
                        }
                }
                delete[] pInfo;
        }
        return 0;
}

上面写个获取自身进程句柄的整个逻辑,下面还有一种获取指定进程伪句柄表的方法


通过 ZwQueryInformationProcess 函数获取

funQuerInformtionProcess.png

这个为查询指定进程信息的函数,当 ProcessInformationClass参数为ProcessHandleCount(20) 时候查询进程的句柄引用计数(Count)

typedef enum _PROCESS_INFORMATION_CLASS {
        ProcessBasicInformation,
        ProcessQuotaLimits,
        ProcessIoCounters,
        ProcessVmCounters,
        ProcessTimes,
        ProcessBasePriority,
        ProcessRaisePriority,
        ProcessDebugPort,
        ProcessExceptionPort,
        ProcessAccessToken,
        ProcessLdtInformation,
        ProcessLdtSize,
        ProcessDefaultHardErrorMode,
        ProcessIoPortHandlers,
        ProcessPooledUsageAndLimits,
        ProcessWorkingSetWatch,
        ProcessUserModeIOPL,
        ProcessEnableAlignmentFaultFixup,
        ProcessPriorityClass,
        ProcessWx86Information,
        ProcessHandleCount,
        ProcessAffinityMask,
        ProcessPriorityBoost,
        MaxProcessInfoClass
} PROCESS_INFORMATION_CLASS, *PPROCESS_INFORMATION_CLASS;

查询这个干嘛呢?我们接下来穷举目标进程句柄。没错,是穷举...刚开始是在博客里看到一位大牛写的,发现他思路很清晰,但是代码有点问题,都把逻辑给混淆了。
句柄是以4开始,以4为单位递增...:
Count.png
从上图不难发现都是句柄值以4递增的,我们穷举的话判断句柄的有效性就可以用函数DuplicateHandle函数实现拷贝有效句柄,失败返回FALSE 从而就可以判断句柄的有效性了。

int _tmain(int argc, _TCHAR* argv[])
{
        EnableDebugPrivilege();
        InitUnDocumentProc();
        NTSTATUS Status;
        HANDLE hSource = NULL;
        HANDLE hDuplicate = NULL;
        DWORD HandleCount;
        OBJECT_NAME_INFORMATION *ObjectName;
        OBJECT_TYPE_INFORMATION *ObjectType;
        char BufferForObjectName[1024];
        char BufferForObjectType[1024];

        hSource = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_DUP_HANDLE | PROCESS_SUSPEND_RESUME, FALSE, GetCurrentProcessId());
        if( hSource != NULL )
        {
                DWORD dwHandle;
                Status = ZwQueryInformationProcess(hSource, ProcessHandleCount, &HandleCount, sizeof(HandleCount), NULL);

                for( DWORD i = 1; i <= HandleCount; i++ )//穷举句柄
                {
                        dwHandle = i * 4;
                        if( DuplicateHandle(hSource, //复制一个句柄对象 && 判断此句柄是否有效
                                (HANDLE)dwHandle,
                                GetCurrentProcess(),
                                &hDuplicate,
                                0, FALSE, DUPLICATE_SAME_ACCESS) )
                        {
                                ZeroMemory(BufferForObjectName, 1024);
                                ZeroMemory(BufferForObjectType, 1024);

                                //获取句柄类型
                                Status = ZwQueryObject(hDuplicate,
                                        ObjectTypeInformation,
                                        BufferForObjectType,
                                        sizeof(BufferForObjectType),
                                        NULL);

                                ObjectType = (OBJECT_TYPE_INFORMATION*)BufferForObjectType;
                                if( Status == STATUS_INFO_LENGTH_MISMATCH || !NT_SUCCESS(Status) )
                                        continue;

                                //获取句柄名
                                Status = ZwQueryObject((HANDLE)hDuplicate,
                                        ObjectNameInformation,
                                        BufferForObjectName,
                                        sizeof(BufferForObjectName),
                                        NULL);

                                //关闭复制的句柄
                                CloseHandle(hDuplicate);
                                ObjectName = (POBJECT_NAME_INFORMATION)BufferForObjectName;
                                if( Status == STATUS_INFO_LENGTH_MISMATCH || !NT_SUCCESS(Status) )
                                        continue;

                                printf("Type:%S|Name:%S|Handle:%X\n", ObjectType->TypeName.Buffer,
                                        ObjectName->Name.Buffer,hDuplicate);

                        }
                }
                CloseHandle(hSource);
        }
        return FALSE;
        return 0;

三、关闭句柄的两种方式

到这里就很简单了,上述已经获得了想到的句柄,但是关闭句柄也有两种不同的情况,本地句柄调用函数CloseHandle即可,而远程的句柄如何关闭呢 ?(就像知道目标的Patch地址而无法在本地执行操作一样),实际调用函数DuplicateHandle即可。

  • 本地进程句柄的关闭
    LocalCloseHandle.png

  • 远程进程句柄的关闭
    RemoteHandle.png
    这里我们关注的是函数DuplicateHandle的最后一个参数,我们查下msdn的定义:

    DUPLICATE_CLOSE_SOURCE(0x00000001) Closes the source handle. This occurs regardless of any error status returned.
    DUPLICATE_SAME_ACCESS(0x00000002)  Ignores the dwDesiredAccess parameter. The duplicate handle has the same access as the source handle.

    • *

小结:

对于远程和本地两种情况都有两种取的句柄的方法,从而针对不同的情况有4种方法,还有通过DuplicateHandle复制的句柄记得CloseHandle,这样才可以实现跨进程关闭句柄,本地的进程不用DuplicateHandle直接可以关闭,有点啰嗦了...

这里就不贴代码了,都打包在附件上。不然显得有点...占空间了...

Ps:

  • 这玩意不是网上有很多资料吗 ?为什么你还要发帖?

大牛们对于这种小问题都是一笔带过的,只给了我们这些小白点关键代码和思路,好让我这些 “跑龙套” 方便整理。。。
好了不瞎扯了,上面是一方面,另一方面是还是自己的代码看的习惯.....主要是在学 Markdown 哈哈哈!!

上述如有有误,还请各位指证!
如有例外,还请各位大侠补充!



GetHandleTable.zip (12.1 KB, 下载次数: 41)

免费评分

参与人数 7吾爱币 +12 热心值 +7 收起 理由
Hmily + 6 + 1 用心讨论,共获提升!
pk8900 + 1 + 1 用心讨论,共获提升!
s3233431 + 2 + 1 用心讨论,共获提升!
gunxsword + 1 + 1 谢谢@Thanks!
ScareCrowL + 1 + 1 我很赞同!
qaz003 + 1 谢谢分享。。
苏紫方璇 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

bester 发表于 2019-10-31 19:50
您好,楼主,我想请问一下您代码的一个问题,希望得到您的回复
if( Status == STATUS_INFO_LENGTH_MISMATCH || !NT_SUCCESS(Status) )
                                        continue;
请问这句代码是一个什么意思呢?作用是什么呢?
失去灯塔的孤帆 发表于 2018-4-7 14:59
这个学习了
之前也有接触过用CreateFileMapping的方式限制游戏多开,不过我是用挂起的标志创建进程,注入后hook ntCreatesection和ntopensection改名字
苏紫方璇 发表于 2018-4-7 13:24
感谢楼主分享,原来那种强制删除文件,貌似用的也是这种方法
 楼主| Aperodry 发表于 2018-4-7 13:33
苏紫方璇 发表于 2018-4-7 13:24
感谢楼主分享,原来那种强制删除文件,貌似用的也是这种方法

嗯,就是文件句柄(File) ,理论关闭掉就可以删除了
感谢支持 ~
gunxsword 发表于 2018-4-7 19:03
感谢分享,正需要这个,感谢!
廖道军 发表于 2018-4-9 10:04
佩服佩服   这么冷门的都有人分享  
头像被屏蔽
zd326379 发表于 2018-4-13 21:56
提示: 作者被禁止或删除 内容自动屏蔽
头像被屏蔽
xiao135140 发表于 2018-5-27 12:09
提示: 作者被禁止或删除 内容自动屏蔽
ppyyll7788 发表于 2018-6-20 09:32
学习了,谢谢分享
游戏丶死忠 发表于 2018-7-6 09:27
热血定点的工具求链接
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 16:48

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表