CreateRemoteThread 这个函数可以用于远程注入,无DLL的注入,是一个功能非常强大的函数,下面是它的原型:
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
);
参数都比较好理解,但是用法却有一些难度,下面通过一个代码分析:
做一个简单动态库:
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
MessageBox(0, L"123", L"456", 0);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
{
MessageBox(0, L"xiezai", L"卸载", 0);
break;
}
}
return TRUE;
}
里面在进程加载和卸载的时候分别弹框。
然后写调用程序:
#include "stdafx.h"
#include <windows.h>
#include <TlHelp32.h>
BOOL WINAPI LoadDll(DWORD ProcessId, char* DllFullPathName);
BOOL WINAPI FreeDll(DWORD ProcessId, char* DllFullPathName);
int main()
{
// DLL文件全路径名.
char DllFullPathName[MAX_PATH] = { 0 };
char CurrentPath[MAX_PATH] = { 0 };
GetCurrentDirectoryA(MAX_PATH, CurrentPath);
strcat(DllFullPathName, CurrentPath);
strcat(DllFullPathName, "\\Hide.dll");
DWORD ProcessId = 0;
HWND hWnd = FindWindow(L"notepad",NULL);
if (!hWnd)
{
printf("Can't find the file!\n");
return 0;
}
// 获得目标进程的进程号pid.
GetWindowThreadProcessId(hWnd, &ProcessId);
LoadDll(ProcessId, DllFullPathName);
FreeDll(ProcessId, DllFullPathName);
}
BOOL WINAPI LoadDll(DWORD ProcessId, char* DllFullPathName)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
if (hProcess == NULL)
{
return 0;
}
int DllLength = strlen(DllFullPathName) + sizeof(char);
PVOID DllAddress = VirtualAllocEx(hProcess,
NULL,
DllLength,
MEM_COMMIT,
PAGE_READWRITE);
if (DllLength == NULL)
{
CloseHandle(hProcess);
return 0;
}
SIZE_T WriteNum = 0;
BOOL v1 = WriteProcessMemory(hProcess, DllAddress, DllFullPathName, DllLength, &WriteNum);
//好多人先写这样,到下面强制类型转换,结果错误
//FARPROC FunAddr = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
PTHREAD_START_ROUTINE FunAddress = (PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");
HANDLE hThread = CreateRemoteThread(hProcess,
NULL,
0,
FunAddress,
DllAddress,
0,
NULL);
int a = GetLastError();
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
}
BOOL WINAPI FreeDll(DWORD ProcessId, char* DllFullPathName)
{
BOOL Result = FALSE;
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
HANDLE Snapshot = NULL;
MODULEENTRY32 hMod = { sizeof(hMod) };
__try
{
// 打开进程.
hProcess = OpenProcess(
PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION,
FALSE,
ProcessId
);
if (hProcess == NULL)
__leave;
// 取得FreeLibrary函数在Kernel32.dll中的地址.
PTHREAD_START_ROUTINE pfnThread =
(PTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandle(L"Kernel32.dll"), "FreeLibrary");
if (pfnThread == NULL)
__leave;
// 取得指定进程的所有模块映象.
Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);
if (Snapshot == NULL)
__leave;
// 取得所有模块列表中的指定的模块.
BOOL bMoreMods = Module32First(Snapshot, &hMod);
if (bMoreMods == FALSE)
__leave;
// 循环取得想要的模块.
for (; bMoreMods; bMoreMods = Module32Next(Snapshot, &hMod))
{
if ((wcscmp(hMod.szExePath, (WCHAR*)DllFullPathName) == 0) ||
(wcscmp(hMod.szModule, (WCHAR*)DllFullPathName) == 0)) {
break;
}
}
hThread = CreateRemoteThread(hProcess,
NULL,
0,
pfnThread,
hMod.modBaseAddr,
0,
NULL);
if (hThread == NULL)
__leave;
// 等待远程线程终止.
WaitForSingleObject(hThread, INFINITE);
Result = TRUE;
}
__finally
{
// 关闭句柄.
if (hThread != NULL)
CloseHandle(hThread);
if (Snapshot != NULL)
CloseHandle(Snapshot);
if (hProcess != NULL)
CloseHandle(hProcess);
}
return Result;
}
在主函数中分别调用了一下。win10下测试成功。
有三个需要注意的问题:
一是如果打开的是记事本,一定要分清楚32位和64位两个是不同的,64位在System32目录下,32位在SystemWow64目录下,而我们平时打开的是64位的,编译的程序却是x86,不匹配导致无法显示。补充说一下,win10下的计算器也是两个目录下各一个,但是用任务管理器查看的时候,发现都是64位,没有32位的,不知道怎么回事,我第一次注入计算器,结果失败了好长时间。
二是CreateRemoteThread的第四参数本来直接定义函数指针,最后强制类型转换,结果一直失败,调用,错误显示是拒绝访问,后来改为直接定义PTHREAD_START_ROUTINE,就OK了。
三是卸载的MessageBox框弹了好多次,不知道怎么解决,还希望大神指点。