原文发表于百度空间,2008-11-20
==========================================================================
这个东西嘛,思路来自炉子,C版的最早貌似是sudami写的,我也写一个,练练手。
上次看到有人找资料时找到了我刚开博时的一篇挫文,并且引用到看雪上求助,令我汗颜不已,遂把这个代码加了N多注释,方便自己,也方便某些误打误撞到我这儿找资料的菜菜~
HANDLE LzOpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle, DWORD dwProcessId) { NTSTATUS status=0; char *pBuf=NULL; BOOLEAN wasEnabled; DWORD buflen=0x10000,needlen=0; DWORD HandleCnt=0; HANDLE hRetProcess=0,hOwnerProc,hTmp; PSYSTEM_HANDLE_INFORMATION pSysHandleInfo=NULL; PROCESS_BASIC_INFORMATION BasePsInfo; OBJECT_ATTRIBUTES objatr; CLIENT_ID Cid; //提升调试权限,否则有些进程,比如服务进程打不开 RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,TRUE,FALSE,&wasEnabled); InitializeObjectAttributes(&objatr,0,0,0,0); //先尝试正常方式打开 Cid.UniqueProcess=(HANDLE)dwProcessId; Cid.UniqueThread=0; status=ZwOpenProcess(&hRetProcess,dwDesiredAccess,&objatr,&Cid);//尝试直接打开 if (NT_SUCCESS(status)) { return hRetProcess; } //不成功,尝试把PID加1再打开,加2,加3也可以 //理由:有些HOOK函数中过滤PID时不完善,正确的做法应该是先用掩码忽略低两位之后再比较 Cid.UniqueProcess=(HANDLE)(dwProcessId+1); status=ZwOpenProcess(&hRetProcess,dwDesiredAccess,&objatr,&Cid);//尝试直接打开pid+1 if (NT_SUCCESS(status)) { return hRetProcess; } //都不成功,就找别的进程中的Handle,这才是本代码的核心, 这些Handle大部分是在Csrss.exe中 do { //申请查询句柄信息所需的内存 ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,0,&buflen,MEM_COMMIT,PAGE_READWRITE); //查询系统句柄信息,类型为16 status=ZwQuerySystemInformation(SystemHandleInformation,(PVOID)pBuf,buflen,&needlen); if (status==STATUS_SUCCESS) { break; } //不成功,则释放内存 //这里只要一块大内存够放这些内容就行,或者直接申请一块足够大的也可以 //返回的needlen可以做为参考 ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,&buflen,MEM_RELEASE); //然后把要申请的内存大小乘2,直至成功为止 buflen*=2; pBuf=NULL; } while(1); //返回的缓冲区内容的第一个DWORD是总的句柄的个数 HandleCnt=*(DWORD*)pBuf; //跳过句柄计数,才是真正的开始 pSysHandleInfo=(PSYSTEM_HANDLE_INFORMATION)((char*)pBuf+sizeof(DWORD)); for (DWORD i=0;i<HandleCnt;i++) { //只验证类型为PROCESS的,值为5 if (pSysHandleInfo->ObjectTypeNumber==OB_TYPE_PROCESS) { //打开这个句柄的所有者进程,要复制过来才能查询,否则只能看不能摸~ Cid.UniqueProcess=(HANDLE)(pSysHandleInfo->ProcessId); Cid.UniqueThread=0; status=ZwOpenProcess(&hOwnerProc,PROCESS_DUP_HANDLE,&objatr,&Cid); if (NT_SUCCESS(status)) { //打开成功,复制句柄到本进程,这里用了PROCESS_ALL_ACCESS以避免权限问题 status=ZwDuplicateObject(hOwnerProc, (HANDLE)(pSysHandleInfo->Handle), NtCurrentProcess(), &hTmp, PROCESS_ALL_ACCESS, FALSE, 0); if (NT_SUCCESS(status)) { //复制成功,查询此句柄所对应的进程PID,查询基本信息即可 status=ZwQueryInformationProcess(hTmp,ProcessBasicInformation,&BasePsInfo,sizeof(PROCESS_BASIC_INFORMATION),NULL); if (NT_SUCCESS(status)) { //成功,判断其PID if (BasePsInfo.UniqueProcessId==dwProcessId) { //句柄所有者是我们要的目标进程,再按所需的权限复制过来 ZwDuplicateObject(hOwnerProc, (HANDLE)(pSysHandleInfo->Handle), NtCurrentProcess(), &hRetProcess, dwDesiredAccess, FALSE, 0); //关掉为复制而打开的句柄所有者的句柄引用 ZwClose(hOwnerProc); break; } } } } } pSysHandleInfo++;//指向下一个结构 } if (pBuf) { ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,&buflen,MEM_RELEASE); } return hRetProcess; }