【VC++积累】之五、进程注入技术

摘要:
因此,如果进程A想要查看或修改进程B的地址空间的内容,它必须深入其地址空间。因为DLL可以加载到任何进程中,所以DLL应该是进程注入的主角,也就是说,一些核心代码应该用DLL编写。

注入:就是把我的代码,添加到已经远行的远程进程的方法;

在WinNT以后的系列操作系统中,每个进程都有自己的4GB私有进程地址空间,彼此互不相关。

如 :   进程A中的一个地址,比如:0x12345678,到了进程B中的相同地方,存的东西完全不一样,或者说不可预料。

           所以说如果进程A想要看看或者修改进程B地址空间中的内容,就必须深入到其地址空间中,因为DLL是可以被加载到任何进程当中的,所以在进程注入中,DLL应该是主角,也就是说一些核心的代码都应该放在DLL中编写。

来看一下步骤:

1、找到远程进程的processid
2、全权打开它
3、在远程进程中申请一块内存,大小为你要写入的东东的大小
4、在这个申请好的内存里面写入你要注入的东西
5、创建一个远程线程来运行这个内存
6、关闭进程


主要用到的API函数:

OpenProcess(...) //获取已知进程的句柄;

  HANDLE OpenProcess(
  DWORD dwDesiredAccess, //渴望得到的访问权限(标志)
  BOOL bInheritHandle, // 是否继承句柄
  DWORD dwProcessId// 进程标示符
  );
VirtualAllocEx(...) //在进程中申请空间;
  LPVOID VirtualAllocEx(
  HANDLE hProcess,//申请内存所在的进程句柄
  LPVOID lpAddress,//保留页面的内存地址
  SIZE_T dwSize,//想分配的内存的大小,字节为单位,    实际分配的内存的大小是页内存大小的整数倍
  DWORD flAllocationType,//
  DWORD flProtect//
  );
WriteProcessMemory(...) //向进程中写入东西;
  BOOL WriteProcessMemory(
  HANDLE hProcess,
  LPVOID lpBaseAddress,//要写的内存首地址,写之前需检查目标地址是否可用
  LPVOID lpBuffer,//指向要写的数据的指针
  DWORD nSize,//要写入的字节数
  LPDWORD lpNumberOfBytesWritten//
  );
GetProcAddress(...) //取得函数在DLL中的地址;
  FARPROC GetProcAddress(
  HMODULE hModule, // DLL模块句柄
  LPCSTR lpProcName // 函数名
  );
CreateRemoteThread(...) //在其他进程中创建新线程;
HANDLE WINAPI CreateRemoteThread( 
__in HANDLE hProcess, 
__in LPSECURITY_ATTRIBUTES lpThreadAttributes, //指定了线程的安全属性
__in SIZE_T dwStackSize, //线程初始大小,以字节为单位,如果该值设为0,那么使用系统默认大小
__in LPTHREAD_START_ROUTINE lpStartAddress, //在远程进程的地址空间中,该线程的线程函数的起始地址.
__in LPVOID lpParameter, //  传给线程函数的参数
__in DWORD dwCreationFlags,// 线程创建的标志
__out LPDWORD lpThreadId //ID
);
CloseHandle(...) //关闭句柄;


下面看一下封装好的函数:

//szModule是dll的地址,  dwID是进程的ID
BOOL insertdll(LPCTSTR szModule, DWORD dwID)
{
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwID);
	if(!hProcess)
		return FALSE;

	//dll 路径
	int nByte = (_tcslen(szModule) + 1) * sizeof(TCHAR);
	//alloc memory
	LPVOID pAddr = VirtualAllocEx(hProcess, NULL, nByte, MEM_COMMIT, PAGE_READWRITE);
	//write to process
	if(!pAddr || !WriteProcessMemory(hProcess, pAddr, szModule, nByte, NULL))
		return FALSE;

#ifdef _UNICODE
	PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(_T("Kernel32")), "LoadLibraryW");
#else
	PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_TOUTINE)GetProcAddress(GetModuleHandle(_T("Kernel32")), "LoadLibraryA");
#endif

	if(!pfnStartAddr)
		return FALSE;
	DWORD dwThreadID = 0;
	//在其他进程中创建线程
	HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, pfnStartAddr, pAddr, 0, &dwThreadID);
	if(!hRemoteThread)
		return FALSE;

	CloseHandle(hRemoteThread);
	CloseHandle(hProcess);
	return TRUE;
}


有的时候你没有足够的权限是不能对进程进行注入的,你必须提权,这里要用到这几个API函数:

OpenProcessToken  获得进程访问令牌句柄

 BOOL OpenProcessToken(
  __in HANDLE ProcessHandle, //要修改访问权限的进程句柄
  __in DWORD DesiredAccess, //指定你要进行的操作类型
  __out PHANDLE TokenHandle //返回的访问令牌指针
  );

AdjustTokenPrivileges对这个访问令牌进行修改

  BOOL AdjustTokenPrivileges(
  HANDLE TokenHandle, // handle to token访问令牌的句柄
  BOOL DisableAllPrivileges, // disabling option  决定所有权
  PTOKEN_PRIVILEGES NewState, // privilege information指明要修改的权限
  DWORD BufferLength, // size of buffer  结构的长度
  PTOKEN_PRIVILEGES PreviousState, // original state buffer  存放修改前访问权限的信息
  PDWORD ReturnLength // required buffer size
  );

LookupPrivilegevalue   获取本地唯一的标识
 BOOL LookupPrivilegevalue(
  LPCTSTR lpSystemName, // system name
  LPCTSTR lpName, // privilege name
  PLUID lpLuid // locally unique identifier
  );

看一下封装好的函数:
BOOL EnablePrivilege(LPCTSTR lpszPrivilegeName, BOOL bEnable)
{
	HANDLE hToken = NULL;
	TOKEN_PRIVILEGES tp;
	LUID luid;

	if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken))
		return FALSE;
	if(!LookupPrivilegeValue(NULL, lpszPrivilegeName, &luid))
		return FALSE;

	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	tp.Privileges[0].Attributes = (bEnable)?SE_PRIVILEGE_ENABLED : 0;

	AdjustTokenPrivileges(hToken, FALSE, &tp, NULL, NULL, NULL);
	CloseHandle(hToken);
	return (GetLastError() == ERROR_SUCCESS);
}


本文讲的是利用远程进程来注入DLL,  
DLL注入技术还有: 用注册表来注入DLL,      用windows钩子来注入DLL,     用木马DLL来注入DLL,   
                                用CreateProces来注入代码    用木马DLL 来注入DLL
这些在后续的文章中还会讲到。


2012/10/8
jofranks 于南昌

免责声明:文章转载自《【VC++积累】之五、进程注入技术》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇java中年月日的加减法,年月的加减法使用【转】弹出USB大容量存储设备时出问题的解决方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Creckme_bjanes.1

先说一下总结:这个crackme,有一个小坑,并且它的判断循环特别的长。 首先我们先说说这个坑: 004036DC . 50 push eax ; /String = " 3" 004036DD . FF15 08104000 call dword ptr...

SetupDi系列函数

SetupDiClassGuidsFromName WINSETUPAPI BOOL SetupDiClassGuidsFromNameA( PCSTR ClassName, LPGUID ClassGuidList, DWORD ClassGuidListSize, PDWORD RequiredSize ); SetupDiClassGuidsF...

超全!iOS 面试题汇总

作者:Job_Yang 之前看了很多面试题,感觉要不是不够就是过于冗余,于是我将网上的一些面试题进行了删减和重排,现在分享给大家。(题目来源于网络,侵删) 1. Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么? 答: Object-c的类不可以多重继承;可以实现多个接口,通过实现多...

C#跨线程修改控件——从MSIL和汇编看Invoke, 多线程, 事件与事件委托

相信大家刚开始写winform的时候都遇到过这样的问题,当跨线程修改控件属性时会遇到如下的异常: 线程间操作无效: 从不是创建控件"progressBar1"的线程访问它。 这是相应的产生上述异常的代码: 1 #region Auto-Generated Properties 2 3 // DelegateDemo - Director.cs...

Java多线程6:synchronized锁定类方法、volatile关键字及其他

同步静态方法 synchronized还可以应用在静态方法上,如果这么写,则代表的是对当前.java文件对应的Class类加锁。看一下例子,注意一下printC()并不是一个静态方法: public classThreadDomain25 { public synchronized static voidprintA() {...

WPF 同一窗口内的多线程 UI(VisualTarget)

WPF 的 UI 逻辑只在同一个线程中,这是学习 WPF 开发中大家几乎都会学习到的经验。如果希望做不同线程的 UI,大家也会想到使用另一个窗口来实现,让每个窗口拥有自己的 UI 线程。然而,就不能让同一个窗口内部使用多个 UI 线程吗? 答案其实是——可以的!使用 VisualTarget 即可。 阅读本文将收获一份对 VisualTarget 的解读以...