远程线程注入
远程线程注入是最简单的一种注入方式.具体实现代码如下:
OpenProcess打开进程VirtualAllocEx在目标进程中申请内存WriteProcessMemory在目标进程中的内存中写入数据.CreateRemoteThread在目标进程中创建线程,线程执行函数LoadLibraryW(目标进程肯定会有该函数),入参为dll的路径.
// 远程线程注入
bool InjectRemoteThread(DWORD pid, const WCHAR* dllPath)
{
//1.打开进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
//2.在目标进程内申请一块内存,要可读可写,主要用于写入模块地址
LPVOID lpAddress = VirtualAllocEx(hProcess, NULL, 0x100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
SIZE_T sWriteLength = 0;
//写入模块地址
WriteProcessMemory(hProcess, lpAddress, dllPath, ((wcslen(dllPath) + 1) * 2), &sWriteLength);
//3.创建远程线程,把LoadLibrary作为回调函数,传入写入的地址,用于加载模块
HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryW, lpAddress, NULL, NULL);
//4.等待线程结束
WaitForSingleObject(hThread, INFINITE);
//5.释放资源
VirtualFreeEx(hProcess, lpAddress, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
启动进程注入
启动进程注入,注入的方式与远程线程注入是一致的.只是一个是OpenProcess 来获取有权限的句柄,一个是在进程启动的时候,得到句柄.
// 启动进程注入
BOOL InjectStartProcess(const WCHAR* exePath, const WCHAR* dllPath)
{
// 启动进程
STARTUPINFO si = { 0 };
si.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION pi = { 0 };
BOOL bRet = CreateProcess(exePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
if (!bRet)
{
MessageBox(NULL, L"Error", L"启动进程失败", MB_OK);
return FALSE;
}
// 在目标进程写入dll路径
LPVOID lpAddress = VirtualAllocEx(pi.hProcess, NULL, 0x100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
SIZE_T sWriteLength = 0;
WriteProcessMemory(pi.hProcess, lpAddress, dllPath, (((wcslen(dllPath) + 1) * 2)), &sWriteLength);
// 创建远程线程,把LoadLibrary作为回调函数,传入写入的地址,用于加载模块
HANDLE hThread = CreateRemoteThreadEx(pi.hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryW, lpAddress, 0, NULL, NULL);
// 等待线程结束
WaitForSingleObject(hThread, INFINITE);
// 唤起主线程
ResumeThread(pi.hThread);
// 释放资源
VirtualFreeEx(pi.hProcess, lpAddress, 0, MEM_RELEASE);
CloseHandle(hThread);
}
全局消息钩子注入
- 自身进程加载dll.
- 找到目标进程的主线程,将dll中的某个函数挂载到全局的消息钩子上实现dll加载.
// 全局消息钩子注入
BOOL InjectHook(DWORD dwPid, const WCHAR* dllPath)
{
// dll 中Add函数地址
HMODULE hModule = LoadLibrary(dllPath);
DWORD dwFuncAddress = (DWORD)GetProcAddress(hModule, "Add");
// 遍历线程
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwPid);
THREADENTRY32 te32 = { sizeof(THREADENTRY32) };
BOOL bRet = Thread32First(hSnap, &te32);
HHOOK g_Hook;
if (bRet)
{
do
{
if (te32.th32OwnerProcessID == dwPid)
{
// 钩子注入
g_Hook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)dwFuncAddress, hModule, te32.th32ThreadID);
break;
}
} while (Thread32Next(hSnap, &te32));
}
return TRUE;
}
UserAPC 异步调用注入
- 在目标进程空间分配dll路径的内存.
- 找到目标进程的主线程,在异步消息恢复队列中添加加载dll的函数.
BOOL InjectAPC(DWORD dwPid, const WCHAR* dllPath)
{
SIZE_T dwWrite = 0;
HMODULE hModule = LoadLibraryA("Kernel32.dll");
auto dwFuncAddress = GetProcAddress(hModule, "LoadLibraryW");
// 参数写入到目标内存中
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
PVOID pAddress = VirtualAllocEx(hProcess, NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
WriteProcessMemory(hProcess, pAddress, dllPath, ((wcslen(dllPath) + 1) * 2), &dwWrite);
// 指定进程内所有线程遍历
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwPid);
THREADENTRY32 te32 = { sizeof(THREADENTRY32) };
BOOL bRet = Thread32First(hSnap, &te32);
if (bRet)
{
do
{
// 线程的进程ID与目标进程ID一致,则添加APC
if (te32.th32OwnerProcessID == dwPid)
{
// 打开线程
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
QueueUserAPC((PAPCFUNC)dwFuncAddress, hThread, (ULONG_PTR)pAddress);
}
} while (Thread32Next(hSnap, &te32));
}
return TRUE;
}
ZwCreateThreadEx 注入
- 在目标进程申请并覆写dll路径的内存.
- 查到当前进程
ntdll.dll的函数ZwCreateThreadEx地址.通过ZwCreateThreadEx函数实现dll的加载函数执行.(类似于远程线程的注入)
eg. 这个我自己测试没成功,目前还没找到原因..
我测试的代码如下:
// 提权函数
BOOL EnableDebugPrivilege()
{
HANDLE hToken;
BOOL fOk = FALSE;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
// 查找debug 权限
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// 设置权限
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
fOk = (GetLastError() == ERROR_SUCCESS);
CloseHandle(hToken);
}
return fOk;
}
// 定义ZwCreateThreadEx函数指针64位
typedef DWORD(WINAPI* _ZwCreateThreadEx64)(
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);
// 定义ZwCreateThreadEx函数指针32位
typedef DWORD(WINAPI* _ZwCreateThreadEx32)(
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);
// ZwCreateThreadEx 注入
BOOL InjectZwCreateThreadEx(DWORD pid, const WCHAR* dllPath)
{
// 提权
BOOL upRight = EnableDebugPrivilege();
if (!upRight)
{
printf("提权失败\n");
return FALSE;
}
//
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hProcess == NULL)
{
printf("OpenProcess - Error!\n\n");
return FALSE;
}
// 申请一块内存,用于写入模块地址
LPVOID dllAddress = VirtualAllocEx(hProcess, NULL, 0x100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (NULL == dllAddress)
{
printf("申请内存失败 - Error!\n\n");
return FALSE;
}
// 写入模块地址
SIZE_T sWriteLength = 0;
BOOL bool_ = WriteProcessMemory(hProcess, dllAddress, dllPath, ((wcslen(dllPath) + 1) * 2), &sWriteLength);
if (!bool_)
{
printf("写入模块地址失败\n");
return FALSE;
}
// 获取函数地址
HMODULE hNtdll = LoadLibraryA("ntdll.dll");
_ZwCreateThreadEx64 ZwCreateThreadEx = (_ZwCreateThreadEx64)GetProcAddress(hNtdll, "ZwCreateThreadEx");
if (NULL == ZwCreateThreadEx)
{
printf("获取ZwCreateThreadEx函数地址失败\n");
return FALSE;
}
// 创建线程
HANDLE hRemoteThread = NULL;
// FARPROC loadLibrary = GetProcAddress(GetModuleHandle(L"Kernel32.dll"), "LoadLibraryW");
NTSTATUS dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)LoadLibraryW, dllAddress, 0, 0, 0, 0, NULL);
if (dwStatus != 0)
{
printf("创建远程线程失败\n");
return FALSE;
}
// 释放资源
CloseHandle(hProcess);
FreeLibrary(hNtdll);
return TRUE;
}
利用输入法注入
待整理...
通过shellcode注入
待整理...