好久没写日志了,实在是没有时间啊!写日志也成了浪费时间,无奈啊!
最近研究了下如何用 Native API 打开指定进程,从而实现根据 PID 来返回进程句柄,从而达到内存填 0 来查杀进程的目的!下面贴出来代码,当然参考了很多大牛的代码:
HANDLE __stdcall ScOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) { NTSTATUS status; BOOLEAN wasEnabled; char *pBuf = NULL; DWORD buflen = 0x10000, needlen = 0; DWORD HandleCnt = 0; HANDLE hRetProcess; PSYSTEM_HANDLE_INFORMATION pSysHandleInfo = NULL; OBJECT_ATTRIBUTES objatr = {sizeof(OBJECT_ATTRIBUTES), 0, NULL, NULL}; CLIENT_ID cid; if ( bInheritHandle ) objatr.Attributes |= OBJ_INHERIT; // 提权 RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &wasEnabled); // 尝试正常方式打开 cid.UniqueProcess = (HANDLE)dwProcessId; cid.UniqueThread = 0; status = ZwOpenProcess(&hRetProcess, dwDesiredAccess, &objatr, &cid); if (NT_SUCCESS(status) ) return hRetProcess; // 查询句柄信息 do { // 申请查询句柄信息所需要的内存 ZwAllocateVirtualMemory( NtCurrentProcess(), (PVOID *)&pBuf, 0, &buflen, MEM_COMMIT, PAGE_READWRITE); // 查询系统句柄信息 status = ZwQuerySystemInformation( SystemHandleInformation, (PVOID)pBuf, buflen, &needlen); if (status == STATUS_SUCCESS) break; // 若不成功则释放内存 ZwFreeVirtualMemory( NtCurrentProcess(), (PVOID *)&pBuf, &buflen, MEM_RELEASE); // 加大申请的内存块, 一直到成功为止 buflen *= 2; pBuf = NULL; } while ( TRUE ); // 返回的缓冲区内容第一个 DWORD 是句柄的个数 HandleCnt = *(DWORD *)pBuf; pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)( (char *)pBuf + sizeof(DWORD) ); for (DWORD i = 0; i < HandleCnt; i ++) { // 只验证类型为 PROCESS 的 if ( pSysHandleInfo->ObjectTypeNumber == OB_TYPE_PROCESS) { HANDLE hOwnerProc; HANDLE hTmpProc; cid.UniqueProcess = (HANDLE)pSysHandleInfo->ProcessId; cid.UniqueThread = 0; status = ZwOpenProcess( &hOwnerProc, PROCESS_DUP_HANDLE, &objatr, &cid); if ( NT_SUCCESS(status) ) { // 打开成功,则把句柄复制过来 status = ZwDuplicateObject( hOwnerProc, (HANDLE)pSysHandleInfo->Handle, NtCurrentProcess(), &hTmpProc, PROCESS_ALL_ACCESS, FALSE, 0); if ( NT_SUCCESS(status) ) { PROCESS_BASIC_INFORMATION BasicInfo = {0}; status = ZwQueryInformationProcess( hTmpProc, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL); if ( NT_SUCCESS(status) ) { if (BasicInfo.UniqueProcessId == dwProcessId) { // 按需要的权限把句柄复制过来 ZwDuplicateObject( hOwnerProc, (HANDLE)pSysHandleInfo->Handle, NtCurrentProcess(), &hRetProcess, dwDesiredAccess, FALSE, 0); ZwClose(hOwnerProc); ZwClose(hTmpProc); break; } } ZwClose(hTmpProc); } ZwClose(hOwnerProc); } } pSysHandleInfo ++; } // 释放内存 if (pBuf) ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *)&pBuf, &buflen, MEM_RELEASE); return hRetProcess; }
由此可以内存暴力枚举进程的雏形,关键是ZwQueryInformationProcess啊!通过抹掉自己进程在csrss里的句柄可以逃过这种方法。如今R3下的方法已经变得科普了,真正的技术还是在R0啊!打好基础,努力向R0迈进吧!