这几天一直在研究远程进程注入的问题,下面也是我个人学习心得写出来供大家参考指证,同时也有问题要请教大家.
终于写会了远程DLL的注入,远程DLL的注入其实是通过调用LoadLibrary函数来在远程进程中开启一个线程,因为LoadLibrary函数是在kernel32.dll里面,windows中每个进程在启动后都加裁了Kernel32.dll所以实现远程DLL注入很简单,它其实是调用的远程进程中kernel32.dll模块里面的函数,所以很好实现.虽然LoadLibrary函数已经在远程进程中只需要我们用一定的方法去调用就是了~但还有一个问题需要我们去解决,那就是LoadLibrar函数的参数,我们知道LoadLibrary已经在远程进程中了,但是LoadLibrary要用到的参数(也就是我们将要注入到远程进程中的DLL模块___DLL文件的完整路径名,如果不指明路径,一定要将该DLL放远程进程目录下或放入windows的系统目录下)并没有在远程进程中(准确的说是在远程进程的内存中),所以我们还需要一系列的工作将这个参数写入到远程进程的内存中去....下面具体说明
一.首先我们要做的事情是找到目标进程并打开它获取目标进程句柄(注:取得的目标进程一定要足够多的权限,以便我们后面的注入工作)
查找目标进程的方法很多,这里我们创建系统快照的方法,来获取目标进程(此方法的好处是可以查找到那些没有窗口的进程),现在我们来定义一个函数,用来获取目标进程的ID
DWORD FindTarget(LPCTSTR lpszProcess)//参数lpszProcess指明想要获取的目标进程的名字
{
DWORD dwRet = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );//创建一个系统快照
PROCESSENTRY32 pe32;//这里定义了一个PROCESSENTRY32结构,它用来保存进程信息
pe32.dwSize = sizeof( PROCESSENTRY32 );//结构大小
Process32First( hSnapshot, &pe32 );//获取系统快照中的第一个系统进程
do
{
if ( lstrcmpi( pe32.szExeFile, lpszProcess ) == 0 )//lstrcmpi函数用获取的进程名与指定的进程名进行比较
{
dwRet = pe32.th32ProcessID;//获取进程ID
break;
}
}
while ( Process32Next( hSnapshot, &pe32 ) );//循环
CloseHandle( hSnapshot );//关闭系统快照
return dwRet;//返回进程ID
}
然后是打开目标进程:
HADNLE hProcess=OpenProcess( PROCESS_TERMINATE|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_CREATE_THREAD, FALSE, dwProcessID);
注意:第一个参数.这里就是为了取得目标进程的操作权限而设的.最后一个参数是上面一个函数所获取的目标进程的ID,好了我们现在开始重要的准备注入了.
要想把DLL的名字(一个字符串)注入目标进程,我们先需要在目标进程中取得一块内存空间用来存放这个字符串,这里要用到两个重要的函数VirtualAllocEx()用来在目标进程中开劈一开内存空间然后是WriteProcessMemory()用来将本地进程中的内存数据拷贝到目标进程的内存中去.这也是一步很重要的工作.现在我们就来实现这一步.
DWORD dwSize;//将要在目标进程中开劈的空间的大小
dwSize = lstrlenA(lpszDll) + 1;//这个大小就等于DLL文件名字串的长度
//lpszDll指向DLL文件名
LPVOID lpBuf=VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE );
//如果上面调用成功lpBuf就指向了远程进程中所开劈出来的内存空间的首地址
//当然最好要写一些代码处理如果不成功的情况
DWORD dwWritten;
//它用来接收实际拷贝到目标进程的数据长度(如果不需要验证正确性可以不要)
WriteProcessMemory(hProcess, lpBuf, (LPVOID)lpszDll, dwSize, &dwWritten);
//下面写一些验证代码.........略
如果上面代码都成功执行后我们就可以调用CreateRemoteThread()在远程进程中开启LoadLibrary线程来载入我们自己的DLL了.
HINSTANCE Pkernel32=::GetModuleHandle("kernel32.dll");
//首先获取Kernel32.dll模块的名柄(因为LoadLibrary函数在kernel32.dll模块内
LPVOID pFunc=(LPTHREAD_START_ROUTINE)GetProcAddress(Pkernel32,"LoadLibraryA");
//然后从kernel32.dll里获取LoadLibrary函数的地址
最后就可以调用CreateRemoteThread()函数在目标进程中开启线程了~~~~~~~
HANDLE hThread;
hThread=CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE)pFunc,lpBuf,0,0);
WaitForSingleObject( hThread, INFINITE);//等待线程结束
最后等待线程执行完后,要进行释放目标进程中申请的内存等操作
VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );
CloseHandle( hThread );
CloseHandle( hProcess );
以上程序我在XP,VC6.0下运行成功
上面是远程注入DLL的方法.可是在网上看到有人向远程进程注入的不是DLL而是本地进程中的一个函数,也就是说他在用CreateRemoteThread()在远程进程开启线程时不是调用的kernel32.dll里面的LoadLibrary()而是调用的本地进程中的一个函数(准确的说不是本地进程内的)他首先将本地进程的函数用WriteProcessMemory写入到目标进程的内存中去然后再进行调用的。
终于写会了远程DLL的注入,远程DLL的注入其实是通过调用LoadLibrary函数来在远程进程中开启一个线程,因为LoadLibrary函数是在kernel32.dll里面,windows中每个进程在启动后都加裁了Kernel32.dll所以实现远程DLL注入很简单,它其实是调用的远程进程中kernel32.dll模块里面的函数,所以很好实现.虽然LoadLibrary函数已经在远程进程中只需要我们用一定的方法去调用就是了~但还有一个问题需要我们去解决,那就是LoadLibrar函数的参数,我们知道LoadLibrary已经在远程进程中了,但是LoadLibrary要用到的参数(也就是我们将要注入到远程进程中的DLL模块___DLL文件的完整路径名,如果不指明路径,一定要将该DLL放远程进程目录下或放入windows的系统目录下)并没有在远程进程中(准确的说是在远程进程的内存中),所以我们还需要一系列的工作将这个参数写入到远程进程的内存中去....下面具体说明
一.首先我们要做的事情是找到目标进程并打开它获取目标进程句柄(注:取得的目标进程一定要足够多的权限,以便我们后面的注入工作)
查找目标进程的方法很多,这里我们创建系统快照的方法,来获取目标进程(此方法的好处是可以查找到那些没有窗口的进程),现在我们来定义一个函数,用来获取目标进程的ID
DWORD FindTarget(LPCTSTR lpszProcess)//参数lpszProcess指明想要获取的目标进程的名字
{
DWORD dwRet = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );//创建一个系统快照
PROCESSENTRY32 pe32;//这里定义了一个PROCESSENTRY32结构,它用来保存进程信息
pe32.dwSize = sizeof( PROCESSENTRY32 );//结构大小
Process32First( hSnapshot, &pe32 );//获取系统快照中的第一个系统进程
do
{
if ( lstrcmpi( pe32.szExeFile, lpszProcess ) == 0 )//lstrcmpi函数用获取的进程名与指定的进程名进行比较
{
dwRet = pe32.th32ProcessID;//获取进程ID
break;
}
}
while ( Process32Next( hSnapshot, &pe32 ) );//循环
CloseHandle( hSnapshot );//关闭系统快照
return dwRet;//返回进程ID
}
然后是打开目标进程:
HADNLE hProcess=OpenProcess( PROCESS_TERMINATE|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_CREATE_THREAD, FALSE, dwProcessID);
注意:第一个参数.这里就是为了取得目标进程的操作权限而设的.最后一个参数是上面一个函数所获取的目标进程的ID,好了我们现在开始重要的准备注入了.
要想把DLL的名字(一个字符串)注入目标进程,我们先需要在目标进程中取得一块内存空间用来存放这个字符串,这里要用到两个重要的函数VirtualAllocEx()用来在目标进程中开劈一开内存空间然后是WriteProcessMemory()用来将本地进程中的内存数据拷贝到目标进程的内存中去.这也是一步很重要的工作.现在我们就来实现这一步.
DWORD dwSize;//将要在目标进程中开劈的空间的大小
dwSize = lstrlenA(lpszDll) + 1;//这个大小就等于DLL文件名字串的长度
//lpszDll指向DLL文件名
LPVOID lpBuf=VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE );
//如果上面调用成功lpBuf就指向了远程进程中所开劈出来的内存空间的首地址
//当然最好要写一些代码处理如果不成功的情况
DWORD dwWritten;
//它用来接收实际拷贝到目标进程的数据长度(如果不需要验证正确性可以不要)
WriteProcessMemory(hProcess, lpBuf, (LPVOID)lpszDll, dwSize, &dwWritten);
//下面写一些验证代码.........略
如果上面代码都成功执行后我们就可以调用CreateRemoteThread()在远程进程中开启LoadLibrary线程来载入我们自己的DLL了.
HINSTANCE Pkernel32=::GetModuleHandle("kernel32.dll");
//首先获取Kernel32.dll模块的名柄(因为LoadLibrary函数在kernel32.dll模块内
LPVOID pFunc=(LPTHREAD_START_ROUTINE)GetProcAddress(Pkernel32,"LoadLibraryA");
//然后从kernel32.dll里获取LoadLibrary函数的地址
最后就可以调用CreateRemoteThread()函数在目标进程中开启线程了~~~~~~~
HANDLE hThread;
hThread=CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE)pFunc,lpBuf,0,0);
WaitForSingleObject( hThread, INFINITE);//等待线程结束
最后等待线程执行完后,要进行释放目标进程中申请的内存等操作
VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );
CloseHandle( hThread );
CloseHandle( hProcess );
#include <windows.h>
#include <psapi.h>
#include <string>
#include <iostream>
#pragma comment(lib, "Psapi.lib")
//提升进程访问权限
void enableDebugPriv()
{
HANDLE hToken;
LUID sedebugnamue;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return;
if (!LookupPrivilegue(NULL, SE_DEBUG_NAME, &sedebugnamue)) {
CloseHandle(hToken);
return;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnamue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
CloseHandle(hToken);
}
//根据进程名称取得进程ID,如果有多个运行实例则返回第一个枚举出来的进程ID
DWORD getSpecifiedProcessId(const char* pszProcessName)
{
DWORD processId[1024], cbNeeded, dwProcessesCount;
HANDLE hProcess;
HMODULE hMod;
char szProcessName[MAX_PATH] = "UnknownProcess";
DWORD dwArrayInBytes = sizeof(processId)*sizeof(DWORD);
if (!EnumProcesses(processId, dwArrayInBytes, &cbNeeded))
return 0;
//计算数组中的元素个数
dwProcessesCount = cbNeeded / sizeof(DWORD);
enableDebugPriv();
for (UINT i = 0; i < dwProcessesCount; i++) {
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId[i]);
if (!hProcess) {
continue;
} else {
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName));
if (!_stricmp(szProcessName, pszProcessName)) {
CloseHandle(hProcess);
return processId[i];
}
}
}
}
CloseHandle(hProcess);
return 0;
}
int main(int argc, char* argv[])
{
std::cout << "please input the name of target process !" << std::endl;
//等待输入进程名称
std::string strProcessName;
std::cin >> strProcessName;
//在这里为了简单起见,使用了绝对路径
char szDllPath[MAX_PATH] = "D://test.dll";
char szFileName[MAX_PATH] = "D://test.dll";
//提升进程访问权限
enableDebugPriv();
if (strProcessName.empty()) {
MessageBox(NULL, "The target process name is invalid !", "Notice", MB_ICONSTOP);
return -1;
}
//根据进程名称得到进程ID
DWORD dwTargetProcessId = getSpecifiedProcessId(strProcessName.c_str());
HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwTargetProcessId);
if (!hTargetProcess) {
MessageBox(NULL, "Open target process failed !", "Notice", MB_ICONSTOP);
return -1;
}
//计算DLL文件名称所占的存储空间
int memorySize = (strlen(szDllPath) + 1) * sizeof(char);
//在目标进程中开辟存储空间,用来存放DLL的文件名称
char* pszFileNameRemote = (char*)VirtualAllocEx(hTargetProcess,
0, memorySize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!pszFileNameRemote) {
MessageBox(NULL, "Alloc dll name string in target process failed !", "Notice", MB_ICONSTOP);
return -1;
}
//将DLL的文件名写入目标进程地址空间
if (!WriteProcessMemory(hTargetProcess, pszFileNameRemote,
(LPVOID)szFileName, memorySize, NULL)) {
MessageBox(NULL, "Write dll name string to target process failed !",
"Notice", MB_ICONSTOP);
return -1;
}
PTHREAD_START_ROUTINE pfnStartAddr =
(PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
HANDLE hRemoteThread = CreateRemoteThread(hTargetProcess,
NULL, 0, pfnStartAddr, pszFileNameRemote, 0, NULL);
WaitForSingleObject(hRemoteThread, INFINITE);
VirtualFreeEx(hTargetProcess, 0, memorySize, NULL);
if (hRemoteThread)
CloseHandle(hTargetProcess);
return 0;
}
以上程序我在XP,VC6.0下运行成功
上面是远程注入DLL的方法.可是在网上看到有人向远程进程注入的不是DLL而是本地进程中的一个函数,也就是说他在用CreateRemoteThread()在远程进程开启线程时不是调用的kernel32.dll里面的LoadLibrary()而是调用的本地进程中的一个函数(准确的说不是本地进程内的)他首先将本地进程的函数用WriteProcessMemory写入到目标进程的内存中去然后再进行调用的。