0%

在应用层远程线程注入DLL到R3进程(1)

简介

由于各进程内存空间隔离,所以要想修改目标进程的数据,就需要先注入到目标进程中,
这里介绍最常见的一种注入方法,也就是远程线程注入

工作原理

先从目标进程中申请一段内存,保存注入的DLL路径,然后获取 LoadLibraryW 函数的地址,
作为 CreateRemoteThread 创建线程的函数,参数就是DLL的路径。同理还可以注入自定义
的shellcode代码,来实现其他的操作。注意x86和x64程序需要对应版本的DLL才能注入

相关代码

设置进程调试权限 SE_DEBUG_NAME 的函数如下所示(注:不提权也能注入)

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <windows.h>
BOOL EnableDebugPrivilege()
{
HANDLE hToken = NULL;
TOKEN_PRIVILEGES priv = { 1,{ 0, 0, SE_PRIVILEGE_ENABLED } };
BOOL ret = LookupPrivilegeValueW(0, SE_DEBUG_NAME, &priv.Privileges[0].Luid);
if (!ret) return FALSE;
ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
if (!ret) return FALSE;
ret = AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof(priv), 0, 0);
CloseHandle(hToken);
return ret;
}

如果想要注入到UWP程序中,还需要给DLL文件设置 ALL APPLICATION PACKAGES 访问权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <accctrl.h>
#include <aclapi.h>
#include <sddl.h>
BOOL SetAccessControl(PCWSTR pPath)
{
if (!pPath || !pPath[0]) return FALSE;

PACL pACLCurr = NULL;
PSECURITY_DESCRIPTOR pSecurity = NULL;
DWORD dwError = GetNamedSecurityInfoW(pPath, SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION, NULL, NULL, &pACLCurr, NULL, &pSecurity);
if (dwError != ERROR_SUCCESS) return FALSE;

PSID pSID = NULL;
PACL pACLNew = NULL;
BOOL bRet = FALSE;
do
{
// 用户和组 ALL APPLICATION PACKAGES
if(!ConvertStringSidToSidW(L"S-1-15-2-1", &pSID)) break;

EXPLICIT_ACCESSW stExplicit = { 0 };
stExplicit.grfAccessPermissions = GENERIC_ALL;
stExplicit.grfAccessMode = SET_ACCESS;
stExplicit.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
stExplicit.Trustee.TrusteeForm = TRUSTEE_IS_SID;
stExplicit.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
stExplicit.Trustee.ptstrName = (PWSTR)pSID;

dwError = SetEntriesInAclW(1, &stExplicit, pACLCurr, &pACLNew);
if (dwError != ERROR_SUCCESS) break;

dwError = SetNamedSecurityInfoW((PWSTR)pPath, SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION, NULL, NULL, pACLNew, NULL);
if (dwError != ERROR_SUCCESS) break;

bRet = TRUE;
} while (0);

if (pSecurity) LocalFree((HLOCAL)pSecurity);
if (pACLNew) LocalFree((HLOCAL)pACLNew);
if (pSID) LocalFree((HLOCAL)pSID);
return bRet;
}

获取目标进程PID的函数为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <tlhelp32.h>
DWORD GetPidByName(PCWSTR pName)
{
if (!pName) return 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) return 0;
PROCESSENTRY32W pe32 = { 0 };
pe32.dwSize = sizeof(PROCESSENTRY32W);
if (!Process32FirstW(hSnapshot, &pe32))
{
CloseHandle(hSnapshot);
return 0;
}
do
{
if (!_wcsicmp(pe32.szExeFile, pName))
{
CloseHandle(hSnapshot);
return pe32.th32ProcessID;
}
ZeroMemory(&pe32, sizeof(PROCESSENTRY32W));
pe32.dwSize = sizeof(PROCESSENTRY32W);
} while (Process32NextW(hSnapshot, &pe32));
CloseHandle(hSnapshot);
return 0;
}

注入到目标进程的函数为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
BOOL LoadInjectDll(DWORD dwPid, PCWSTR pPath)
{
if (!dwPid || !pPath) return FALSE;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (!hProcess) return FALSE;
BOOL result = FALSE;
do
{
SIZE_T nLen = (wcslen(pPath) + 1) * sizeof(WCHAR);
PVOID pBuffer = VirtualAllocEx(hProcess, NULL, nLen, MEM_COMMIT, PAGE_READWRITE);
if (!pBuffer) break;
SIZE_T nRet = 0;
if (!WriteProcessMemory(hProcess, pBuffer, pPath, nLen, &nRet)) break;
if (nLen != nRet) break;
PTHREAD_START_ROUTINE pFunc = (PTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandleW(L"Kernel32"), "LoadLibraryW");
if (!pFunc) break;
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pFunc, pBuffer, 0, NULL);
if (!hThread) break;
CloseHandle(hThread);
result = TRUE;
} while (0);
CloseHandle(hProcess);
return result;
}