前言
该技术是指通过在【目标进程】中创建一个【远程线程】来达到注入的目的。
创建的【远程线程】函数为LoadLibrary, 线程函数的参数为DLL名字, 想要做的工作在DLL中编写。
示意图如下:
相关API
1、创建远程线程
//该函数除了第一个参数为目标进程句柄外
//其他参数均和CreateThread一样
HANDLE hThread = CreateRemoteThread(
__in HANDLE hProcess, //目标进程句柄
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize, //线程栈初始预定空间=Max(/STACK, dwStackSize, 初始调拨大小=(dwStackSize == 0? /STACK, dwStackSize)
__in LPTHREAD_START_ROUTINE lpStartAddress, //线程函数
__in_opt LPVOID lpParameter, //线程函数参数
__in DWORD dwCreationFlags, //标志
__out_opt LPDWORD lpThreadId //线程ID
)
失败返回NULL
2、根据进程ID获取进程句柄,并且传入相应权限标志,自定义函数
//根据进程ID获取进程句柄
HANDLE GetProcessHandle(DWORD deProcessID)
{
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION //查询进程句柄
| PROCESS_VM_OPERATION //PROCESS_VM_WRITE + PROCESS_VM_READ + x
| PROCESS_CREATE_THREAD //创建线程
| PROCESS_VM_WRITE, //WriteProcessMemory
FALSE, //不继承
deProcessID //进程句柄
);
return hProcess;
}
3、获得LoadLibrary函数地址
由于LoadLibrary是个宏,而非实际的函数,因此需要使用GetProcAddress并传入LoadLibraryW 或 LoadLibraryA来获取真实地址
4、从目标进程申请内存
当把Dll名字作为线程函数LoadLibraryW(A)的参数传给他时,由于此时的线程是运行在其他进程地址空间中的,因此当把本地进程中的字符串指针传给CreateRemoteThread函数时会引起访问违例,因此需要从目标进程地址空间中申请内存,并将本地Dll名字符串写入远程进程,然后使用远程进程中的地址作为CreateRemoteThread函数的参数。
//该函数除了第一个参数为进程句柄外
//其他参数和VirtualAlloc一样
LPVOID WINAPI VirtualAllocEx(
__in HANDLE hProcess, //进程句柄
__in_opt LPVOID lpAddress, //地址,为NULL自动找一个合适的地址
__in SIZE_T dwSize, //内存块大小,单位为字节
__in DWORD flAllocationType, //分配类型,预定或调拨
__in DWORD flProtect //保护属性
);
5、往远程进程中写输入, 即把本地DLL名字字符串 写入 远程进程地址空间中
BOOL WINAPI WriteProcessMemory(
__in HANDLE hProcess, //进程句柄
__in LPVOID lpBaseAddress, //写入地址
__in LPCVOID lpBuffer, //源缓冲区
__in SIZE_T nSize, //缓冲区大小,单位为字节
__out SIZE_T *lpNumberOfBytesWritten //实际写入的字节数
);
No code you say a XX
本demo的作用是将一个DLL注入一个窗口标题为"Endl"的目标进程,该DLL的作用是在DLL_PROCESS_ATTACH中ExitProcess,即强制退出目标进程。
开发进程代码
//根据进程ID获取进程句柄
HANDLE GetProcessHandle(DWORD deProcessID)
{
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION //查询进程句柄
| PROCESS_VM_OPERATION //PROCESS_VM_WRITE + PROCESS_VM_READ + x
| PROCESS_CREATE_THREAD //创建线程
| PROCESS_VM_WRITE, //WriteProcessMemory
FALSE, //不继承
deProcessID //进程句柄
);
return hProcess;
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwErrCode = 0;
//获取进程ID
//HWND hWnd = FindWindow(NULL, _T("计算器"));
HWND hWnd = FindWindow(NULL, _T("Endl"));
DWORD dwProcessID = 0;
GetWindowThreadProcessId(hWnd, &dwProcessID);
HANDLE hDestProcess = GetProcessHandle(dwProcessID);
if(NULL == hDestProcess)
{
cerr<<"打开进程句柄失败"<<endl;
return 0;
}
//获取KERNER32.DLL 模块句柄
HMODULE hModule = GetModuleHandle(_T("kernel32.dll"));
if(NULL == hModule)
{
cerr<<"获取kernel32.dll句柄失败"<<endl;
return -1;
}
//线程函数,kernerl32.dll被映射到所有进程内相同的地址
LPTHREAD_START_ROUTINE lpThreadStartRoutine =
(LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryW");
if(NULL == lpThreadStartRoutine)
{
cerr<<"获取LoadLibraryW地址失败"<<endl;
return -2;
}
//从目标进程内申请堆内存
LPVOID lpMemory = VirtualAllocEx(
hDestProcess, NULL, MAX_PATH, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if(NULL == lpMemory)
{
cerr<<"申请目标进程内存失败"<<endl;
return -3;
}
//注入DLL
LPCTSTR lpDLLName = _T("DLLForRemoteThread.dll");
//把DLL名字写入目标进程
BOOL bWriteMemory = WriteProcessMemory(
hDestProcess, lpMemory, lpDLLName, (_tcslen(lpDLLName) + 1) * sizeof(lpDLLName[0]), NULL);
if(FALSE == bWriteMemory)
{
cerr<<"WriteProcessMemory失败"<<endl;
dwErrCode = GetLastError();
VirtualFreeEx(hModule, lpMemory, 0, MEM_RELEASE | MEM_DECOMMIT);
return -4;
}
//创建远程线程
HANDLE hThread = CreateRemoteThread(
hDestProcess,
NULL,
0,
lpThreadStartRoutine,
lpMemory,
0,
NULL);
if (NULL == hThread || INVALID_HANDLE_VALUE == hThread)
{
cerr<<"创建远程线程CreateRomoteThread失败"<<endl;
VirtualFreeEx(hModule, lpMemory, 0, MEM_RELEASE | MEM_DECOMMIT);
return -5;
}
VirtualFreeEx(hModule, lpMemory, 0, MEM_RELEASE | MEM_DECOMMIT);
return 0;
}
待注入DLL代码
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
#if defined _DEBUG
OutputDebugString(TEXT("\r\n*************DLL_PROCESS_ATTACH*************"));
#endif
ExitProcess(1);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}