内存写入注入

内存写入注入

如果进程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上测试:
在这里插入图片描述

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值