内存写入注入
如果进程A本身就给了其他进程申请和写入空间的权限,那我只要将模块复制到指定进程A的空间里面,再利用远程线程或者hook也就能让我们的模块在进程A运行,这就是内存写入注入
思路
只要我进程A允许进程B有写入操作就可以实现注入。这样实现了隐藏模块的注入
拓展:若是不允许别的进程有写入操作,但应该也会允许系统进程有写入操作,只要我将注入功能注入到系统进程里面,让系统进程对进程A进行内存写入注入就可以了。相当于内存写入注入+伪装合法软件注入
步骤
1、内存写入:
- 获取当前模块句柄,得到SizeOfImage的大小和Image Base
- 在当前空间申请空间存放自身代码
- 打开要注入的进程A
- 在远程进程A中申请空间,大小为SizeOfImage
- 对本身进程B中的代码进行重定位
- 得到本身进程B中要在进程A中运行的函数的地址,重定位后的地址
- 将重定位修正后的数据 通过WriteProcessMemory写入远程进程的内存空间中
- 通过CreateRemoteThread开线程,线程函数地址为Entry重定位后的地址
- 释放当前空间申请的内存
2、模块入口函数执行
- 根据重定位信息,修复IAT表。
- 因为被注入的进程可能没有自己进程的一些系统函数,所以注入模块的第一步便是修复IAT表
- 可能两个有些系统dll没有预装到指定位置,所以修复
- 海哥说不是所有dll都能正确加载到相同的位置
- 执行其他功能
- 通过全局变量来结束这个函数
为什么不用修复IAT表也可以注入成功,我想:
只要我注入进的代码这里用的函数都是被注入进程dll里面有的应该就可以不用修复,因为两个常见系统dll(user32、kernel32)都会抢占到相同的内存地址 。正因为抢占到了相同位置,所以并不需要修复IAT表。但我注入进的代码用到其他 位置不相同的dll了就需要修复IAT表了
还有调用系统函数是间接call,这样可能会想就算重定位修复了IAT的地址如:FF [4123] 变成了 FF[5123],但IAT表里面的内容没有跟着移动到新的地址,所以FF[5123]里面是空的。这样想恰恰是错误的,我们复制是根据ImageBase整体复制的,内容并没有改变,IAT表的内容也会从[4123]复制到[5123],也正是这样,我们才需要修复间接Call,让它从4123变成5123
实例
说明:XP和Win10上都可以运行,没有修复IAT表。
错误点:卸载注入时有错误,能通过内存写入改变全局变量来结束远程线程,但远程释放空间会让程序崩溃
#include <stdio.h>
#include <iostream>
#include < windows.h>
#define PID 13912
#define RELOCATION 5
using namespace std;
//得到Image_base SizeOfImage EntryPoint
DWORD GetSizeOfImage(IN LPVOID FileBuffer, OUT DWORD& ImageBase, OUT DWORD& EntryPoint)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)FileBuffer;
PIMAGE_FILE_HEADER pFile = (PIMAGE_FILE_HEADER)((DWORD)FileBuffer + pDos->e_lfanew + 0x4);
PIMAGE_OPTIONAL_HEADER32 pOption = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFile + IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)pOption + pFile->SizeOfOptionalHeader);
ImageBase = pOption->ImageBase;
EntryPoint = pOption->AddressOfEntryPoint;
//防止ImageSize不准,靠最后一个节来得到ImageSize
DWORD Last_idex = pFile->NumberOfSections - 1;
DWORD real_ImageSize = pSection[Last_idex].VirtualAddress + pSection[Last_idex].SizeOfRawData;
return real_ImageSize;
}
//修复重定位表
void FixRelocation(IN LPVOID Buffer, IN DWORD FixImageBase)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)Buffer;
if (pDos->e_magic != IMAGE_DOS_SIGNATURE || *(PDWORD)((DWORD)pDos + pDos->e_lfanew) != IMAGE_NT_SIGNATURE)
{
cout << "NOT MZ" << endl;
return;
}
PIMAGE_FILE_HEADER pFile = (PIMAGE_FILE_HEADER)((DWORD)pDos + pDos->e_lfanew + 4);
PIMAGE_OPTIONAL_HEADER32 pOptionalFile = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFile + IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_BASE_RELOCATION pRelocation = (PIMAGE_BASE_RELOCATION)((DWORD)Buffer + pOptionalFile->DataDirectory[5].VirtualAddress);
//保存原本值 更改ImageBase
DWORD Imagebase = pOptionalFile->ImageBase;
pOptionalFile->ImageBase = FixImageBase;
//修复重定位表
PWORD pDataAddr = (PWORD)((DWORD)pRelocation + 8);
DWORD Block = pRelocation->SizeOfBlock;
DWORD VitualAddr = pRelocation->VirtualAddress;
PDWORD Replace = NULL;
DWORD Rva = 0;
while (Block != 0 && VitualAddr != 0)
{
for (DWORD i = 0; i < (Block - 8) / 2; i++)
{
// 高四位值为3 代表的是需要修改的数据
if ((*(pDataAddr + i) & 0xF000) == 0x3000)
{
Rva = (*(pDataAddr + i) & 0x0FFF) + VitualAddr;
Replace = (PDWORD)((DWORD)Buffer + Rva);
*Replace = *Replace - Imagebase + FixImageBase;
}
}
pRelocation = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocation + Block);
Block = pRelocation->SizeOfBlock;
VitualAddr = pRelocation->VirtualAddress;
pDataAddr = (PWORD)((DWORD)pRelocation + 8);
}
}
//全局变量,用于控远程线程函数
DWORD ExitCode = 0;
//要执行的函数 线程函数格式
DWORD WINAPI Entry(LPVOID lpParameter)
{
//程序代码
while(1)
{
Sleep(2000);
MessageBox(NULL, L"执行的函数", L"注入", MB_OK);
if (ExitCode)
{
ExitThread(1);
return 0;
}
}
return 0;
}
int main()
{
cout << "注入中...." << endl;
//获取当前模块句柄
HANDLE hCurrentProcess = NULL;
hCurrentProcess = ::GetModuleHandle(NULL);
if (hCurrentProcess == NULL)
{
cout << "获取当前模块句柄失败" << endl;
return 0;
}
//得到自己的SizeOfImage和ImageBase
DWORD EntryPoint = 0;
DWORD ImageBase = 0;
DWORD SizeOfImage = GetSizeOfImage((LPVOID)(DWORD)hCurrentProcess, ImageBase, EntryPoint);
//当前空间申请空间存放自身代码
LPVOID pszBuffer = malloc(SizeOfImage);
if (pszBuffer == NULL)
{
cout << "申请空间失败" << endl;
return 0;
}
ZeroMemory(pszBuffer, SizeOfImage);
//空间存放自身代码
memcpy(pszBuffer, (LPVOID)ImageBase, SizeOfImage);
//获取要注入的进程A句柄
HANDLE hProcess = NULL;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, PID);
if (hProcess == NULL)
{
cout << "获取进程A句柄失败" << endl;
return 0;
}
//在远程进程A中申请空间
LPVOID pszProBuffer = NULL;
pszProBuffer = VirtualAllocEx(hProcess, NULL, SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pszProBuffer == NULL)
{
cout << "远程进程A中申请空间失败" << endl;
return 0;
}
//修复重定位表
FixRelocation(pszBuffer, (DWORD)pszProBuffer);
//写入远程进程空间
DWORD WriteSize = 0;
if (!WriteProcessMemory(hProcess, pszProBuffer, pszBuffer, SizeOfImage, &WriteSize))
{
cout << "写入远程进程失败" << endl;
return 0;
}
//创建远程线程
坑点 给的线程函数地址需要是重定位后的
DWORD dwProcOffset = (DWORD)Entry - (DWORD)ImageBase + (DWORD)pszProBuffer;
坑点
HANDLE hThread = NULL;
hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)dwProcOffset, NULL, 0, 0);
//释放本身内存
free(pszBuffer);
//释放
system("pause");
DWORD CodeAddr = (DWORD)&ExitCode - (DWORD)ImageBase + (DWORD)pszProBuffer;
DWORD Code = 1;
DWORD size;
if (!WriteProcessMemory(hProcess, (LPVOID)CodeAddr, (LPVOID)&Code, 4, &size))
{
cout << "写入远程进程失败" << endl;
return 0;
}
//远程释放会崩
//VirtualFreeEx(hProcess,pszProBuffer,SizeOfImage,MEM_DECOMMIT);
return 0;
}
注入成功图,在win10上测试: