Windows x86/ x64 Ring3层注入Dll总结

2019-10-16 15:36:08王振洲

  然后在比如插入Apc队列、挂起线程等等操作中,需要对目标进程的线程操作,所以获得线程Id也有必要,同样的我也提供了两种通过进程Id获得线程Id的方法。第一个仍然是使用TlHelp创建系统的线程快照,把所有的线程存入vector模板里(供Apc注入使用);第二个是利用ZwQuerySystemInformation大法,枚举系统进程信息,这个方法我只返回了一个线程Id,已经够用了。

// 枚举指定进程Id的所有线程,压入模板中
#include <vector>
#include <TlHelp32.h>
using namespace std;
BOOL GetThreadIdByProcessId(IN UINT32 ProcessId, OUT vector<UINT32>& ThreadIdVector)
{
HANDLE ThreadSnapshotHandle = NULL;
THREADENTRY32 ThreadEntry32 = { 0 };
ThreadEntry32.dwSize = sizeof(THREADENTRY32);
ThreadSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); // 给系统所有的线程快照
if (ThreadSnapshotHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
if (Thread32First(ThreadSnapshotHandle, &ThreadEntry32))
{
do
{
if (ThreadEntry32.th32OwnerProcessID == ProcessId)
{
ThreadIdVector.emplace_back(ThreadEntry32.th32ThreadID); // 把该进程的所有线程id压入模板
}
} while (Thread32Next(ThreadSnapshotHandle, &ThreadEntry32));
}
CloseHandle(ThreadSnapshotHandle);
ThreadSnapshotHandle = NULL;
return TRUE;
}

// ZwQuerySystemInformation+SystemProcessInformation

typedef
NTSTATUS(NTAPI * pfnZwQuerySystemInformation)(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN UINT32 SystemInformationLength,
OUT PUINT32 ReturnLength OPTIONAL);

BOOL GetThreadIdByProcessId(IN UINT32 ProcessId, OUT PUINT32 ThreadId)
{
BOOL bOk = FALSE;
NTSTATUS Status = 0;
PVOID BufferData = NULL;
PSYSTEM_PROCESS_INFO spi = NULL;
pfnZwQuerySystemInformation ZwQuerySystemInformation = NULL;
ZwQuerySystemInformation = (pfnZwQuerySystemInformation)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "ZwQuerySystemInformation");
if (ZwQuerySystemInformation == NULL)
{
return FALSE;
}
BufferData = malloc(1024 * 1024);
if (!BufferData)
{
return FALSE;
}
// 在QuerySystemInformation系列函数中,查询SystemProcessInformation时,必须提前申请好内存,不能先查询得到长度再重新调用
Status = ZwQuerySystemInformation(SystemProcessInformation, BufferData, 1024 * 1024, NULL);
if (!NT_SUCCESS(Status))
{
free(BufferData);
return FALSE;
}
spi = (PSYSTEM_PROCESS_INFO)BufferData;
// 遍历进程,找到我们的目标进程
while (TRUE)
{
bOk = FALSE;
if (spi->UniqueProcessId == (HANDLE)ProcessId)
{
bOk = TRUE;
break;
}
else if (spi->NextEntryOffset)
{
spi = (PSYSTEM_PROCESS_INFO)((PUINT8)spi + spi->NextEntryOffset);
}
else
{
break;
}
}
if (bOk)
{
for (INT i = 0; i < spi->NumberOfThreads; i++)
{
// 返出找到的线程Id
*ThreadId = (UINT32)spi->Threads[i].ClientId.UniqueThread;
break;
}
}
if (BufferData != NULL)
{
free(BufferData);
}
return bOk;
}

  嗯,目前为止,预备工作差不多完工,那我们就开始正题吧!