上一次做了个双进程保护。后来试着做了DLL远程注入。可行性倒是没问题。问题在于,最理想的进程是注入在explorer里面,但是在WIN7 64位的系统注入不了。getlasterror()返回5.拒绝访问。不知道要怎么去解决。

 

远程注入大致就几个步骤,首先。记得提升权限。

 

DWORD EnablePrivilege (PCSTR name)
{
	HANDLE hToken;
	BOOL rv;
	//设置结构
	TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
	// 查找权限值
	LookupPrivilegeValue (
		0,
		name,
		&priv.Privileges[0].Luid
		);
	// 打开本进程Token
	OpenProcessToken(
		GetCurrentProcess (),
		TOKEN_ADJUST_PRIVILEGES,
		&hToken
		);
	// 提权
	AdjustTokenPrivileges (
		hToken,
		FALSE,
		&priv,
		sizeof priv,
		0,
		0
		);
	// 返回值,错误信息,如果操作成功,则应为ERROR_SUCCESS,为O
	rv = GetLastError();
	// 关闭Token
	CloseHandle (hToken);
	return rv;
}


提升权限之后我们就可以开始注入了,先获取目标进程ID。之后再由ID来获得句柄。

 

BOOL GetProcessIdByName(LPSTR szProcessName, LPDWORD lpPID)
{
	// 变量及初始化
	STARTUPINFO st;
	PROCESS_INFORMATION pi;
	PROCESSENTRY32 ps;
	HANDLE hSnapshot;
	ZeroMemory(&st, sizeof(STARTUPINFO));
	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
	st.cb = sizeof(STARTUPINFO);
	ZeroMemory(&ps,sizeof(PROCESSENTRY32));
	ps.dwSize = sizeof(PROCESSENTRY32);
	// 遍历进程
	hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0);
	if(hSnapshot == INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}

	if(!Process32First(hSnapshot,&ps))
	{
		return FALSE;
	}
	do
	{
		// 比较进程名
		if(lstrcmpi(ps.szExeFile,"explorer.exe")==0)
		{
			// 找到了
			*lpPID = ps.th32ProcessID;
			CloseHandle(hSnapshot);
			return TRUE;
		}
	}
	while(Process32Next(hSnapshot,&ps));
	// 没有找到
	CloseHandle(hSnapshot);
	return FALSE;
}


 

上面这个函数就是由进程名而获取句柄咯。

之后就开始正式工作。你要在人家的进程里面运行线程加载DLL模块,总要给人家一个地方去放DLL的路径不是?不然都不知道在哪里,怎么去运行。所以要计算DLL路径名的字节数。

然后在开辟空间。开辟的空间比计算的字节数要大一。还有点要注意,DLL的路径最好是用绝对路径。总之我只用绝对路径才成功。

开辟空间的函数

  pszLibFileRemote = (PSTR)VirtualAllocEx(
   hProcess, //申请内存所在的进程句柄
   NULL, //保留页面的内存地址;一般用NULL自动分配
   cch, //欲分配的内存大小,字节单位;注意实际分 配的内存大小是页内存大小的整数倍
   MEM_COMMIT,
   PAGE_READWRITE
   );
开辟空间后,就把DLL路径写进去。
 
WriteProcessMemory(
   hProcess,//由OpenProcess返回的进程句柄。如参数传数据为 INVALID_HANDLE_VALUE 【即-1】目标进程为自身进程
   (PVOID)pszLibFileRemote, //要写的内存首地址.再写入之前,此函数将先检查目标地址是否可用,并能容纳待写入的数据。
   (PVOID)lpszLibName, //指向要写的DLL的路径的指针。
   cch, //要写入的字节数。
   NULL)
 
然后在目标进程中通过函数LoadLibraryA来加载我们的DLL。LoadLibraryA函数在Kerne132.dll里面。通过显示调用,获取真实地址,然后用函数CreateRemoteThread创建远程线程,调用DLL。
 CreateRemoteThread(
   hProcess, //目标进程句柄.
   NULL, //一个指向 SECURITY_ATTRIBUTES 结构的指针, 该结指定了线程的安全属性.
   0,//线程初始大小,以字节为单位,如果该值设为0,那么使用系统默认大小.
   pfnThreadRtn, //在远程进程的地址空间中,该线程的线程函数的起始地址.
   (PVOID)pszLibFileRemote, //传给线程函数的参数.
   0, //线程的创建标志.
   NULL
   )
 
至于怎么去获得DLL路径。
 int num;
 string x(szPath);
 num = x.length();
 x.replace(num - strlen("remote.exe"),num,"远程DLL.dll");
    LPTSTR lp=const_cast<char*>(x.c_str());
其中remote.exe就是本进程名,远程DLL.dll就是我们的dll名。这样只要DLL和本身进程在一个目录。就能正确读取。
 
 
BOOL LoadRometeDll(DWORD dwProcessId, LPTSTR lpszLibName)
{
	BOOL   bResult          = FALSE; 
	HANDLE hProcess         = NULL;
	HANDLE hThread          = NULL;
	PSTR   pszLibFileRemote = NULL;
	DWORD  cch;
	PTHREAD_START_ROUTINE pfnThreadRtn;

	__try 
	{
		// 获得想要注入代码的进程的句柄.
		hProcess = OpenProcess(
			PROCESS_ALL_ACCESS, 
			FALSE, 
			dwProcessId
			);

		if (hProcess == NULL)
			__leave;

		// 计算DLL路径名需要的字节数.
		cch = 1 + lstrlen(lpszLibName);

		// 在远程线程中为路径名分配空间.
		pszLibFileRemote = (PSTR)VirtualAllocEx(
			hProcess, //申请内存所在的进程句柄
			NULL, //保留页面的内存地址;一般用NULL自动分配 
			cch, //欲分配的内存大小,字节单位;注意实际分 配的内存大小是页内存大小的整数倍 
			MEM_COMMIT, 
			PAGE_READWRITE
			);

		if (pszLibFileRemote == NULL) 
			__leave;

		// 将DLL的路径名复制到远程进程的内存空间.
		if (!WriteProcessMemory(
			hProcess,//由OpenProcess返回的进程句柄。如参数传数据为 INVALID_HANDLE_VALUE 【即-1】目标进程为自身进程 
			(PVOID)pszLibFileRemote, //要写的内存首地址.再写入之前,此函数将先检查目标地址是否可用,并能容纳待写入的数据。
			(PVOID)lpszLibName, //指向要写的DLL的路径的指针。
			cch, //要写入的字节数。
			NULL)) 
			__leave;

		// 获得LoadLibraryA在Kernel32.dll中的真正地址. 
		pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(
			GetModuleHandle(TEXT("Kernel32")), TEXT("LoadLibraryA"));

		if (pfnThreadRtn == NULL) 
			__leave;

		// 创建远程线程,并通过远程线程调用用户的DLL文件. 
		hThread = CreateRemoteThread(
			hProcess, //目标进程句柄. 
			NULL, //一个指向 SECURITY_ATTRIBUTES 结构的指针, 该结指定了线程的安全属性.
			0,//线程初始大小,以字节为单位,如果该值设为0,那么使用系统默认大小.
			pfnThreadRtn, //在远程进程的地址空间中,该线程的线程函数的起始地址.
			(PVOID)pszLibFileRemote, //传给线程函数的参数.
			0, //线程的创建标志.
			NULL
			);
		
		if (hThread == NULL) 
		{
					int a = GetLastError();
					cout<<"error = "<<a<<endl;
			__leave;
		}

		// 等待远程线程终止.
		WaitForSingleObject(hThread, INFINITE);
		bResult = TRUE; 
	}
	__finally 
	{ 
		// 关闭句柄. 
		if (pszLibFileRemote != NULL) 
			VirtualFreeEx(hProcess, (PVOID)pszLibFileRemote, 0, MEM_RELEASE);
		if (hThread  != NULL) 
			CloseHandle(hThread);
		if (hProcess != NULL) 
			CloseHandle(hProcess);
	}
	return bResult;
}

这是效果图。。可是看出,对话框是由QQ弹出。
DLL代码就不贴了。主要DLL里面要写线程,不要直接写函数。否则注入的进程直接会挂掉。
 
 
本文代码参考自《精通Windows.API-函数、接口、编程实例》
 
posted on 2014-05-16 19:59  zkkkkkky  阅读(169)  评论(0编辑  收藏  举报