首页
社区
课程
招聘
[原创]X64进程DLL注入获取模块句柄
发表于: 2019-9-3 19:29 9717

[原创]X64进程DLL注入获取模块句柄

2019-9-3 19:29
9717

注意: 使用机器码注入获取的.不知道其他CPU 获取是否有Bug
      思路:通过C++ X64平台写一个空的子程序 发布版本把优化禁用,
查看反汇编 如下:(注意:里面最好还需要添加一点东西免得禁用优化一样没有效果)
空的子程序
48 89 4C 24 08     mov         qword ptr [rsp+8],rcx  
48 83 EC 28          sub         rsp,28h  


48 83 C4 28          add         rsp,28h  
C3
注入代码都是内存地址,所以需要自己查看下64位汇编在C++反汇编中内存地址给寄存器赋值
通过查看反汇编代码得出一个公式.(不知道是不是正确的)
列如 下面汇编:
000000013FBC11AF   48 8B 05 6A 1E 00 00 mov         rax,qword ptr [pDllName (013FBC3020h)]  

48 8B 05  这是 Mov Rax 的机器码 
6A 1E 00 00  偏移地址
偏移算法  013FBC3020h- 000000013FBC11AF- 7=1E6A
内存地址-RIP-7=偏移地址
64位Call 计算Call 如果是引用IAT 表的话, 公式  IAT地址-RIP-6=偏移地址  不知道对不对,反正我在C++反汇编中
用这样公式能计算出偏移

64位Call 调用参数传入如下:
typedef __int64 (*Call)(__int64 rcx,__int64 rdx,__int 64 r8,__int64 r9,__int64 esp-20,__int64 esp-28,...)


卸载DLL的结构体只需要把_Rcx[1] =0x8d;改为  _Rcx[1]=0x8B;
就是一个是字符串变量,一个是int 变量 取值不一样
字符串变量 Lea            Int  Mov
函数体只需要把写入DLL路劲哪里改为写入模块句柄变量就好了

#pragma pack(push,1)
struct LoadLibrary64
{
	BYTE  _Begin[9]; //函数头部
	BYTE _Rcx[3];
	DWORD Address;
	BYTE _CallRax[1];
	DWORD LoadLibrayBase;
	BYTE _Rax_Mov_Ptr[3];
	DWORD SaveAddress;
	BYTE _End[5]; //函数结尾
	LoadLibrary64(PVOID pRip, PVOID nDllPathAddress, PVOID nLoadLibBase, PVOID nSaveAddress)
	{
                //初始函数头部
		_Begin[0] = 0x48, _Begin[1] = 0x89, _Begin[2] = 0x4C, _Begin[3] = 0x24, _Begin[4] = 0x08, _Begin[5] = 0x48, _Begin[6] = 0x83, _Begin[7] = 0xEC, _Begin[8] = 0x28;
              //Lea Rcx [xxxxxxxxx]
		_Rcx[0] = 0x48, _Rcx[1] = 0x8D, _Rcx[2] = 0x0d;
              //Call xxxxxx
		_CallRax[0] = 0xE8;
              //初始结尾
		_Rax_Mov_Ptr[0] = 0x48, _Rax_Mov_Ptr[1] = 0x89, _Rax_Mov_Ptr[2] = 0x05;
		_End[0] = 0x48, _End[1] = 0x83, _End[2] = 0xC4, _End[3] = 0x28, _End[4] = 0xC3;
                //定位RIP
		PVOID nPorPos = (unsigned char *)pRip + 9;
                //计算偏移 公式已经在上面写出来了
		DWORD nOffset = clacoffset(nPorPos, nDllPathAddress);
		Address = nOffset;
                //定位Rip
		nPorPos = (unsigned char*)nPorPos + 7;
                //Call 的公式还是和32位一样
		nOffset = jmpcall(nPorPos, nLoadLibBase);
		LoadLibrayBase = nOffset;
                //定位RIP
		nPorPos = (unsigned char*)nPorPos + 5;
                //写入保存地址
		nOffset = clacoffset(nPorPos, nSaveAddress);
		SaveAddress = nOffset;
	}
};



注入代码都是和32大同小异如下:
BOOL CPicture::InjectDll(WCHAR *pDllName, DWORD nPid)
{
	BOOL bRet = FALSE;
        //提权
	if (!AdJustPr()) return bRet;

	//打开进程
	HANDLE hProcess = nullptr, hThread = nullptr;
	PVOID pAddress = nullptr, pStartAddress = nullptr, pSaveAddress = nullptr, pLoadAddress = nullptr;
	CString strCode;
	CHAR cBuf[64] = { 0 };
	do
	{
		hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, false, nPid);
		if (!hProcess)
		{
			Printf("打开进程失败,请确认是否是管理员权限运行!!!");
			break;
		}
		pAddress = ::VirtualAllocEx(hProcess, NULL, 1024 * 4, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		if (!pAddress)
		{
			Printf("远程申请内存失败!");
			break;
		}
		//这里执行地址
		pStartAddress = (DWORD *)pAddress + 200;
		//保存地址
		pSaveAddress = (DWORD*)pAddress + 512;
		//取得DLL路径
		
		//DLL路径
		if (!WriteProcessMemory(hProcess, pAddress, pDllName, sizeof(WCHAR)* (wcslen(pDllName) + 1), 0))
		{
			Printf("写入内存失败!!!!");
			break;
		}
		//LoadLibarayW
		pLoadAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"Kernel32"), "LoadLibraryW");

		//初始写入数据
		LoadLibrary64 Code(pStartAddress, pAddress, pLoadAddress,pSaveAddress);
		
		//写入执行地址
		if (!WriteProcessMemory(hProcess, pStartAddress, &Code, sizeof(LoadLibrary64), NULL))
		{
			Printf("写入内存失败!!!!");
			break;
		}
		hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pStartAddress, NULL, 0, NULL);
		if (!hThread)
		{
			Printf("执行失败!!!!");
			break;
		}

		WaitForSingleObject(hThread, INFINITE);
		DWORD dwCode;
		GetExitCodeThread(hThread, &dwCode);
		if (!ReadProcessMemory(hProcess, pSaveAddress, &m_hModule, sizeof(INT64), NULL))
		{
			Printf("读取模块句柄失败");
			break;
		}
		if (dwCode == -1)
		{
			Printf("注入失败......");
			break;
		}
		_i64toa_s(m_hModule, cBuf, 64, 16);
		strCode=L"注入成功:模块句柄为:";
		strCode += cBuf;
		Printf(strCode);
		bRet = TRUE;

	} while (false);
	if (pAddress)
		::VirtualFreeEx(hProcess, pAddress, 1024 * 4, MEM_RELEASE);
	if (hProcess)
		CloseHandle(hProcess);
	if (hThread)
		CloseHandle(hThread);
	return bRet;
}


注意: 使用机器码注入获取的.不知道其他CPU 获取是否有Bug
      思路:通过C++ X64平台写一个空的子程序 发布版本把优化禁用,
查看反汇编 如下:(注意:里面最好还需要添加一点东西免得禁用优化一样没有效果)
空的子程序
48 89 4C 24 08     mov         qword ptr [rsp+8],rcx  
48 83 EC 28          sub         rsp,28h  


48 83 C4 28          add         rsp,28h  
C3
注入代码都是内存地址,所以需要自己查看下64位汇编在C++反汇编中内存地址给寄存器赋值
空的子程序
48 89 4C 24 08     mov         qword ptr [rsp+8],rcx  
48 83 EC 28          sub         rsp,28h  


48 83 C4 28          add         rsp,28h  
C3
注入代码都是内存地址,所以需要自己查看下64位汇编在C++反汇编中内存地址给寄存器赋值
空的子程序
48 89 4C 24 08     mov         qword ptr [rsp+8],rcx  
48 83 EC 28          sub         rsp,28h  


48 83 C4 28          add         rsp,28h  
C3
注入代码都是内存地址,所以需要自己查看下64位汇编在C++反汇编中内存地址给寄存器赋值
通过查看反汇编代码得出一个公式.(不知道是不是正确的)
列如 下面汇编:
000000013FBC11AF   48 8B 05 6A 1E 00 00 mov         rax,qword ptr [pDllName (013FBC3020h)]  
000000013FBC11AF   48 8B 05 6A 1E 00 00 mov         rax,qword ptr [pDllName (013FBC3020h)]  

48 8B 05  这是 Mov Rax 的机器码 
6A 1E 00 00  偏移地址
偏移算法  013FBC3020h- 000000013FBC11AF- 7=1E6A
内存地址-RIP-7=偏移地址
64位Call 计算Call 如果是引用IAT 表的话, 公式  IAT地址-RIP-6=偏移地址  不知道对不对,反正我在C++反汇编中
用这样公式能计算出偏移

64位Call 调用参数传入如下:
typedef __int64 (*Call)(__int64 rcx,__int64 rdx,__int 64 r8,__int64 r9,__int64 esp-20,__int64 esp-28,...)


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 2
支持
分享
最新回复 (3)
雪    币: 12252
活跃值: (4998)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2

多谢楼主分享,学习了
2019-9-3 19:31
0
雪    币: 27069
活跃值: (62999)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
3
好文,但是我好想给你调个格式啊 来自小编的强迫症
2019-9-6 14:39
0
雪    币: 43
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
可以,受教了
2019-10-4 18:08
0
游客
登录 | 注册 方可回帖
返回
//