注意: 使用机器码注入获取的.不知道其他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; }