Windows x86/ x64 Ring3层注入Dll总结

2019-10-16 15:36:08王振洲

int main()
{
......
ThreadCount = ThreadIdVector.size();
for (INT i = ThreadCount - 1; i >= 0; i--)
{
UINT32 ThreadId = ThreadIdVector[i];
InjectDllByApc(ProcessId, ThreadId);
}
......
}
BOOL InjectDllByApc(IN UINT32 ProcessId, IN UINT32 ThreadId)
{
BOOL bOk = 0;
HANDLE ThreadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadId);
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
UINT_PTR LoadLibraryAddress = 0;
SIZE_T ReturnLength = 0;
UINT32 DllFullPathLength = (strlen(DllFullPath) + 1);
// 全局,申请一次内存
if (DllFullPathBufferData == NULL)
{
//申请内存
DllFullPathBufferData = VirtualAllocEx(ProcessHandle, NULL, DllFullPathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (DllFullPathBufferData == NULL)
{
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return FALSE;
}
}
// 避免之前写操作失败,每次重复写入
bOk = WriteProcessMemory(ProcessHandle, DllFullPathBufferData, DllFullPath, strlen(DllFullPath) + 1,
&ReturnLength);
if (bOk == FALSE)
{
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return FALSE;
}
LoadLibraryAddress = (UINT_PTR)GetProcAddress(GetModuleHandle(L"Kernel32.dll"), "LoadLibraryA");
if (LoadLibraryAddress == NULL)
{
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return FALSE;
}
__try
{
QueueUserAPC((PAPCFUNC)LoadLibraryAddress, ThreadHandle, (UINT_PTR)DllFullPathBufferData);
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
}
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return TRUE;
}

0x06.修改注册表

  注册表注入算得上是全局Hook了吧,毕竟新创建的进程在加载User32.dll时,都会自动调用LoadLibrary去加载注册表中某个表项键值里写入的Dll路径。

  我们关心的这个注册表项键是:HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWindows,我们要设置的键值是AppInit_DLLs = “Dll完整路径”,LoadAppInit_Dlls = 1(让系统使用这个注册表项)

  ps:由于注入的Dll在进程创建的早期,所以在Dll中使用函数要格外小心,因为有的库可能还没加载上。

int main()
{
LSTATUS Status = 0;
WCHAR* wzSubKey = L"SOFTWAREMicrosoftWindows NTCurrentVersionWindows";
HKEY hKey = NULL;
// 打开注册表
Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, // 要打开的主键
wzSubKey, // 要打开的子键名字地址
0, // 保留,传0
KEY_ALL_ACCESS, // 打开的方式
&hKey); // 返回的子键句柄
if (Status != ERROR_SUCCESS)
{
return 0;
}
WCHAR* wzValueName = L"AppInit_DLLs";
DWORD dwValueType = 0;
UINT8 ValueData[MAX_PATH] = { 0 };
DWORD dwReturnLength = 0;
// 查询注册表
Status = RegQueryValueExW(hKey, // 子键句柄
wzValueName, // 待查询键值的名称
NULL, // 保留
&dwValueType, // 数据类型
ValueData, // 键值
&dwReturnLength);
WCHAR wzDllFullPath[MAX_PATH] = { 0 };
GetCurrentDirectoryW(MAX_PATH, wzDllFullPath);
#ifdef _WIN64
wcscat_s(wzDllFullPath, L"x64NormalDll.dll");
#else
wcscat_s(wzDllFullPath, L"x86NormalDll.dll");
#endif
// 设置键值
Status = RegSetValueExW(hKey,
wzValueName,
NULL,
dwValueType,
(CONST BYTE*)wzDllFullPath,
(lstrlen(wzDllFullPath) + 1) * sizeof(WCHAR));
if (Status != ERROR_SUCCESS)
{
return 0;
}
wzValueName = L"LoadAppInit_DLLs";
DWORD dwLoadAppInit = 1;
// 查询注册表
Status = RegQueryValueExW(hKey, wzValueName, NULL, &dwValueType, ValueData, &dwReturnLength);
// 设置键值
Status = RegSetValueExW(hKey, wzValueName, NULL, dwValueType, (CONST BYTE*)&dwLoadAppInit, sizeof(DWORD));
if (Status != ERROR_SUCCESS)
{
return 0;
}
printf("Input Any Key To Resumern");
getchar();
getchar();
// 恢复键值
dwLoadAppInit = 0;
Status = RegQueryValueExW(hKey, wzValueName, NULL, &dwValueType, ValueData, &dwReturnLength);
Status = RegSetValueExW(hKey, wzValueName, NULL, dwValueType, (CONST BYTE*)&dwLoadAppInit, sizeof(DWORD));
wzValueName = L"AppInit_DLLs";
ZeroMemory(wzDllFullPath, (lstrlen(wzDllFullPath) + 1) * sizeof(WCHAR));
Status = RegQueryValueExW(hKey, wzValueName, NULL, &dwValueType, ValueData, &dwReturnLength);
Status = RegSetValueExW(hKey, wzValueName, NULL, dwValueType, (CONST BYTE*)wzDllFullPath, 0);
return 0;
}