驱动开发:内核实现进程汇编与反汇编

news2024/11/25 20:52:57

在笔者上一篇文章《驱动开发:内核MDL读写进程内存》简单介绍了如何通过MDL映射的方式实现进程读写操作,本章将通过如上案例实现远程进程反汇编功能,此类功能也是ARK工具中最常见的功能之一,通常此类功能的实现分为两部分,内核部分只负责读写字节集,应用层部分则配合反汇编引擎对字节集进行解码,此处我们将运用capstone引擎实现这个功能。

首先是实现驱动部分,驱动程序的实现是一成不变的,仅仅只是做一个读写功能即可,完整的代码如下所示;

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntifs.h>
#include <windef.h>

#define READ_PROCESS_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ALL_ACCESS)
#define WRITE_PROCESS_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ALL_ACCESS)

#define DEVICENAME L"\\Device\\ReadWriteDevice"
#define SYMBOLNAME L"\\??\\ReadWriteSymbolName"

typedef struct
{
	DWORD pid;       // 进程PID
	UINT64 address;  // 读写地址
	DWORD size;      // 读写长度
	BYTE* data;      // 读写数据集
}ProcessData;

// MDL读取封装
BOOLEAN ReadProcessMemory(ProcessData* ProcessData)
{
	BOOLEAN bRet = TRUE;
	PEPROCESS process = NULL;

	// 将PID转为EProcess
	PsLookupProcessByProcessId(ProcessData->pid, &process);
	if (process == NULL)
	{
		return FALSE;
	}

	BYTE* GetProcessData = NULL;
	__try
	{
		// 分配堆空间 NonPagedPool 非分页内存
		GetProcessData = ExAllocatePool(NonPagedPool, ProcessData->size);
	}
	__except (1)
	{
		return FALSE;
	}

	KAPC_STATE stack = { 0 };
	// 附加到进程
	KeStackAttachProcess(process, &stack);

	__try
	{
		// 检查进程内存是否可读取
		ProbeForRead(ProcessData->address, ProcessData->size, 1);

		// 完成拷贝
		RtlCopyMemory(GetProcessData, ProcessData->address, ProcessData->size);
	}
	__except (1)
	{
		bRet = FALSE;
	}

	// 关闭引用
	ObDereferenceObject(process);

	// 解除附加
	KeUnstackDetachProcess(&stack);

	// 拷贝数据
	RtlCopyMemory(ProcessData->data, GetProcessData, ProcessData->size);

	// 释放堆
	ExFreePool(GetProcessData);
	return bRet;
}

// MDL写入封装
BOOLEAN WriteProcessMemory(ProcessData* ProcessData)
{
	BOOLEAN bRet = TRUE;
	PEPROCESS process = NULL;

	// 将PID转为EProcess
	PsLookupProcessByProcessId(ProcessData->pid, &process);
	if (process == NULL)
	{
		return FALSE;
	}

	BYTE* GetProcessData = NULL;
	__try
	{
		// 分配堆
		GetProcessData = ExAllocatePool(NonPagedPool, ProcessData->size);
	}
	__except (1)
	{
		return FALSE;
	}

	// 循环写出
	for (int i = 0; i < ProcessData->size; i++)
	{
		GetProcessData[i] = ProcessData->data[i];
	}

	KAPC_STATE stack = { 0 };

	// 附加进程
	KeStackAttachProcess(process, &stack);

	// 分配MDL对象
	PMDL mdl = IoAllocateMdl(ProcessData->address, ProcessData->size, 0, 0, NULL);
	if (mdl == NULL)
	{
		return FALSE;
	}

	MmBuildMdlForNonPagedPool(mdl);

	BYTE* ChangeProcessData = NULL;

	__try
	{
		// 锁定地址
		ChangeProcessData = MmMapLockedPages(mdl, KernelMode);

		// 开始拷贝
		RtlCopyMemory(ChangeProcessData, GetProcessData, ProcessData->size);
	}
	__except (1)
	{
		bRet = FALSE;
		goto END;
	}

	// 结束释放MDL关闭引用取消附加
END:
	IoFreeMdl(mdl);
	ExFreePool(GetProcessData);
	KeUnstackDetachProcess(&stack);
	ObDereferenceObject(process);

	return bRet;
}

NTSTATUS DriverIrpCtl(PDEVICE_OBJECT device, PIRP pirp)
{
	PIO_STACK_LOCATION stack;
	stack = IoGetCurrentIrpStackLocation(pirp);
	ProcessData* ProcessData;

	switch (stack->MajorFunction)
	{

	case IRP_MJ_CREATE:
	{
		break;
	}

	case IRP_MJ_CLOSE:
	{
		break;
	}

	case IRP_MJ_DEVICE_CONTROL:
	{
		// 获取应用层传值
		ProcessData = pirp->AssociatedIrp.SystemBuffer;

		DbgPrint("进程ID: %d | 读写地址: %p | 读写长度: %d \n", ProcessData->pid, ProcessData->address, ProcessData->size);

		switch (stack->Parameters.DeviceIoControl.IoControlCode)
		{
		// 读取函数
		case READ_PROCESS_CODE:
		{
			ReadProcessMemory(ProcessData);
			break;
		}
		// 写入函数
		case WRITE_PROCESS_CODE:
		{
			WriteProcessMemory(ProcessData);
			break;
		}

		}

		pirp->IoStatus.Information = sizeof(ProcessData);
		break;
	}

	}

	pirp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(pirp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
	if (driver->DeviceObject)
	{
		UNICODE_STRING SymbolName;
		RtlInitUnicodeString(&SymbolName, SYMBOLNAME);

		// 删除符号链接
		IoDeleteSymbolicLink(&SymbolName);
		IoDeleteDevice(driver->DeviceObject);
	}
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	NTSTATUS status = STATUS_SUCCESS;
	PDEVICE_OBJECT device = NULL;
	UNICODE_STRING DeviceName;

	DbgPrint("[LyShark] hello lyshark.com \n");

	// 初始化设备名
	RtlInitUnicodeString(&DeviceName, DEVICENAME);

	// 创建设备
	status = IoCreateDevice(Driver, sizeof(Driver->DriverExtension), &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &device);
	if (status == STATUS_SUCCESS)
	{
		UNICODE_STRING SymbolName;
		RtlInitUnicodeString(&SymbolName, SYMBOLNAME);

		// 创建符号链接
		status = IoCreateSymbolicLink(&SymbolName, &DeviceName);

		// 失败则删除设备
		if (status != STATUS_SUCCESS)
		{
			IoDeleteDevice(device);
		}
	}

	// 派遣函数初始化
	Driver->MajorFunction[IRP_MJ_CREATE] = DriverIrpCtl;
	Driver->MajorFunction[IRP_MJ_CLOSE] = DriverIrpCtl;
	Driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIrpCtl;

	// 卸载驱动
	Driver->DriverUnload = UnDriver;

	return STATUS_SUCCESS;
}

上方的驱动程序很简单关键部分已经做好了备注,此类驱动换汤不换药没啥难度,接下来才是本节课的重点,让我们开始了解一下Capstone这款反汇编引擎吧,Capstone是一个轻量级的多平台、多架构的反汇编框架。Capstone旨在成为安全社区中二进制分析和反汇编的终极反汇编引擎,该引擎支持多种平台的反汇编,非常推荐使用。

  • 反汇编引擎下载地址:https://cdn.lyshark.com/sdk/capstone_msvc12.zip

这款反汇编引擎如果你想要使用它则第一步就是调用cs_open()官方对其的解释是打开一个句柄,这个打开功能其中的参数如下所示;

  • 参数1:指定模式 CS_ARCH_X86 表示为Windows平台
  • 参数2:执行位数 CS_MODE_32为32位模式,CS_MODE_64为64位
  • 参数3:打开后保存的句柄&dasm_handle

第二步也是最重要的一步,调用cs_disasm()反汇编函数,该函数的解释如下所示;

  • 参数1:指定dasm_handle反汇编句柄
  • 参数2:指定你要反汇编的数据集或者是一个缓冲区
  • 参数3:指定你要反汇编的长度 64
  • 参数4:输出的内存地址起始位置 0x401000
  • 参数5:默认填充为0
  • 参数6:用于输出数据的一个指针

这两个函数如果能搞明白,那么如下反汇编完整代码也就可以理解了。

#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <iostream>
#include <inttypes.h>
#include <capstone/capstone.h>

#pragma comment(lib,"capstone64.lib")

#define READ_PROCESS_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ALL_ACCESS)
#define WRITE_PROCESS_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ALL_ACCESS)

typedef struct
{
	DWORD pid;
	UINT64 address;
	DWORD size;
	BYTE* data;
}ProcessData;

int main(int argc, char* argv[])
{
	// 连接到驱动
	HANDLE handle = CreateFileA("\\??\\ReadWriteSymbolName", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	ProcessData data;
	DWORD dwSize = 0;

	// 指定需要读写的进程
	data.pid = 6932;
	data.address = 0x401000;
	data.size = 64;

	// 读取机器码到BYTE字节数组
	data.data = new BYTE[data.size];
	DeviceIoControl(handle, READ_PROCESS_CODE, &data, sizeof(data), &data, sizeof(data), &dwSize, NULL);
	for (int i = 0; i < data.size; i++)
	{
		printf("0x%02X ", data.data[i]);
	}

	printf("\n");

	// 开始反汇编
	csh dasm_handle;
	cs_insn *insn;
	size_t count;

	// 打开句柄
	if (cs_open(CS_ARCH_X86, CS_MODE_32, &dasm_handle) != CS_ERR_OK)
	{
		return 0;
	}

	// 反汇编代码
	count = cs_disasm(dasm_handle, (unsigned char *)data.data, data.size, data.address, 0, &insn);

	if (count > 0)
	{
		size_t index;
		for (index = 0; index < count; index++)
		{
			/*
			for (int x = 0; x < insn[index].size; x++)
			{
				printf("机器码: %d -> %02X \n", x, insn[index].bytes[x]);
			}
			*/

			printf("地址: 0x%"PRIx64" | 长度: %d 反汇编: %s %s \n", insn[index].address, insn[index].size, insn[index].mnemonic, insn[index].op_str);
		}
		cs_free(insn, count);
	}
	cs_close(&dasm_handle);

	getchar();
	CloseHandle(handle);
	return 0;
}

通过驱动加载工具加载WinDDK.sys然后在运行本程序,你会看到正确的输出结果,反汇编当前位置处向下64字节。

说完了反汇编接着就需要讲解如何对内存进行汇编操作了,汇编引擎这里采用了XEDParse该引擎小巧简洁,著名的x64dbg就是在运用本引擎进行汇编替换的,本引擎的使用非常简单,只需要向XEDParseAssemble()函数传入一个规范的结构体即可完成转换,完整代码如下所示。

  • 汇编引擎下载地址:https://cdn.lyshark.com/sdk/XEDParse.zip
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <iostream>

extern "C"
{
#include "D:/XEDParse/XEDParse.h"
#pragma comment(lib, "D:/XEDParse/XEDParse_x64.lib")
}

using namespace std;

#define READ_PROCESS_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ALL_ACCESS)
#define WRITE_PROCESS_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ALL_ACCESS)

typedef struct
{
	DWORD pid;
	UINT64 address;
	DWORD size;
	BYTE* data;
}ProcessData;

int main(int argc, char* argv[])
{
	// 连接到驱动
	HANDLE handle = CreateFileA("\\??\\ReadWriteSymbolName", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	ProcessData data;
	DWORD dwSize = 0;

	// 指定需要读写的进程
	data.pid = 6932;
	data.address = 0x401000;
	data.size = 0;

	XEDPARSE xed = { 0 };
	xed.x64 = FALSE;

	// 输入一条汇编指令并转换
	scanf_s("%llx", &xed.cip);
	gets_s(xed.instr, XEDPARSE_MAXBUFSIZE);
	if (XEDPARSE_OK != XEDParseAssemble(&xed))
	{
		printf("指令错误: %s\n", xed.error);
	}

	// 生成堆
	data.data = new BYTE[xed.dest_size];

	// 设置长度
	data.size = xed.dest_size;

	for (size_t i = 0; i < xed.dest_size; i++)
	{
		// 替换到堆中
		printf("%02X ", xed.dest[i]);
		data.data[i] = xed.dest[i];
	}

	// 调用控制器,写入到远端内存
	DeviceIoControl(handle, WRITE_PROCESS_CODE, &data, sizeof(data), &data, sizeof(data), &dwSize, NULL);

	printf("[LyShark] 指令集已替换. \n");
	getchar();
	CloseHandle(handle);
	return 0;
}

通过驱动加载工具加载WinDDK.sys然后在运行本程序,你会看到正确的输出结果,可打开反内核工具验证是否改写成功。

打开反内核工具,并切换到观察是否写入了一条mov eax,1的指令集机器码,如下图已经完美写入。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/559520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WXSS 模板样式

WXSS WXSS&#xff08;WeiXin Style Sheets&#xff09;是一套样式语言&#xff0c;用来美化 WXML 的组件样式&#xff0c;类似于网页开发中的 CSS WXSS 和 CSS 的关系 WXSS 具有 CSS 大部分特性&#xff0c;同时&#xff0c;WXSS 还对 CSS 进行了扩充以及修改&#xff0c;以…

AJ-Report是一个完全开源,拖拽编辑的可视化设计工具

简介 AJ-Report是全开源的一个BI平台&#xff0c;酷炫大屏展示&#xff0c;能随时随地掌控业务动态&#xff0c;让每个决策都有数据支撑。     多数据源支持&#xff0c;内置mysql、elasticsearch、kudu驱动&#xff0c;支持自定义数据集省去数据接口开发&#xff0c;目前已支…

分布式应用之监控平台zabbix

1.监控系统的相关知识 1.1 监控系统运用的原因 当我们需要实时关注与其相关的各项指标是否正常&#xff0c;往往存在着很多的服务器、网络设备等硬件资源&#xff0c;如果我们想要能够更加方便的、集中的监控他们&#xff0c;zabix可以实现集中监控管理的应用程序 监控的初衷…

历届蓝桥杯青少年编程比赛 计算思维题真题解析【已更新3套 持续更新中】

一、计算思维组考试范围 计算思维组面向小学生&#xff08;7-12 岁&#xff0c;约 1-6 年级&#xff09;&#xff0c;通过设计多个角度的考核题目、层次科学的试卷组合、线上限时的考试形式&#xff0c;更加精确地考查学生的计算能力、反应能力、思维与分析能力&#xff0c;使…

【产品成长】产品专业化提升路径

产品专业化 产品专业化就是上山寻路。梳理一套作为产品经理的工作方法。 以图为例&#xff0c;做一个归纳。 第一&#xff1a;梳理自己的设计方法。就是拿到一个需求点之后&#xff0c;如何进行需求分析&#xff0c;如何还原业务情况&#xff0c;最终进行产品设计&#xff0c…

基于QEMU的RISC-V架构linux系统开发(三)——基于buildroot的最小根文件系统配置与编译

1.buildroot官网下载最新版本的buildroot。 https://buildroot.org/download.html 图1 下载最新版本的buildroot压缩包 2.拷贝buildroot软件包到工作目录&#xff0c;并解压buildroot。 图2 解压buildroot软件包 3.新建编译脚本build_risc-v.sh&#xff0c;使用buildroot自带的…

深度学习笔记之递归网络(五)递归神经网络的反向传播过程

机器学习笔记之递归网络——递归神经网络的反向传播过程 引言回顾&#xff1a;递归神经网络的前馈计算过程场景构建前馈计算描述 反向传播过程各参数的梯度计算各时刻损失函数梯度计算损失函数对各时刻神经元输出的梯度计算 Softmax \text{Softmax} Softmax回归的梯度计算关于 …

JAVA将xml数据转为实体类

使用 JAXB&#xff08;Java Architecture for XML Binding) 实现XML与Bean的相互转换 介绍 JAXB是一个业界的标准&#xff0c;是一项可以根据XML Schema产生Java类的技术。该过程中&#xff0c;JAXB也提供了将XML实例文档反向生成Java对象树的方法&#xff0c;并能将Java对象…

2023年7大人工智能技术趋势你有了解过嘛

人工智能 (AI) 已经接管世界&#xff0c;并且将在2023年继续向前发展。在2023年&#xff0c;它将完全实现自动化供应链、虚拟助手等多个产品与形态。 如今&#xff0c;世界正在经历一波人工智能驱动的全球经济转型浪潮。 当前之态势&#xff0c;人工智能 (AI) 技术几乎在每个领…

如何用Python进行屏幕录制?

文章目录 引言gpt3.5给出的代码更换截图函数——ImageGrab.grab禁用imshow解决递归现象摄像头录制代码后期需求 引言 关于屏幕录制这个功能需求&#xff0c;之前用过基于ffmpeg的Capture录屏软件&#xff0c;但是fps拉高以后会变得很卡&#xff0c;声音也同样出现卡顿。也自己…

cpu 内核 逻辑处理器的关系

6核CPU&#xff0c;12个逻辑处理器 一颗内核在一个时间片内只能执行一个内核线程&#xff1b;当物理CPU使用了超线程技术后&#xff0c;在CPU的一颗内核中&#xff0c;利用就是利用其中空闲的执行单元&#xff0c;模拟出另外一个核心&#xff08;并不是真正的物理运算核心&…

公司招人,面了一个5年经验不会自动化的测试人,他凭什么要18K?

在深圳这家金融公司也待了几年&#xff0c;被别人面试过也面试过别人&#xff0c;大大小小的事情也见识不少&#xff0c;今天又是团面的一天&#xff0c; 一百多个人都聚集在一起&#xff0c;因为公司最近在谈项目出来面试就2个人&#xff0c;无奈又被叫到面试房间。 整个过程…

【算法训练(day5)】前缀和与差分

目录 一.一维前缀 二.二维前缀和 三.一维差分 四.二维差分 一.一维前缀 1.前缀的作用 前缀用于在求一部分区间的和&#xff0c;比方说有一组数据a1,a2,a3,a4,我们想知道从第一个元素一直相加到最后一个元素的和或者是从第二个元素加到第三个元素&#xff0c;这种情况下就能…

docker部署elasticsearch:8.6.2, kibana,logstash 版本以及kibana的使用

文章目录 1、参考2、安装elasticsearch:8.6.22.1 创建网络2.2 创建无密码访问的elasticsearch服务2.3 访问验证2.4 建一个索引试试&#xff0c;此索引名为my-book&#xff0c;有六个字段2.5 用GET命令获取索引信息试试&#xff0c;如下&#xff0c;符合预期2.6 再试试批量导入一…

redis集群的架构、问题,附脑洞

本文首发自「慕课网」&#xff08;www.imooc.com&#xff09;&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"或慕课网公众号&#xff01; 作者&#xff1a;一凡 | 慕课网讲师 Redis 是一种开源&#xff08;BSD 许可&…

魔术表演-第14届蓝桥杯省赛Scratch中级组真题第1题

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第136讲。 魔术表演&#xff0c;本题是2023年5月7日举行的第14届蓝桥杯省赛Scratch图形化编程中级组真题第1题&#xf…

【arxiv】论文找 idea : 关于 OVD 的论文扫读(四)

文章目录 一、DetCLIPv2: Scalable Open-Vocabulary Object Detection Pre-training via Word-Region Alignment二、Prompt-Guided Transformers for End-to-End Open-Vocabulary Object Detection三、Bridging the Gap between Object and Image-level Representations for Op…

2023年京东618预售数据免费开放(往年618热门品类数据回顾)

2023年618京东平台整体的活动节奏分为五个时期&#xff1a; 第一时期为预售期&#xff1a;2023年5月23日晚8点-5月31日 第二时期为开门红&#xff1a;5月31日20点-6月3日 第三时期为场景期&#xff1a;6月4日-6月15日 第四时期为高潮期&#xff1a;6月15日20点-6月18日 第五…

前端HTML之基础扫盲

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 本篇文章将讲解HTML的基础&#xff0c;认识HTML的基本结构&#xff0c;学会使用常用的HTML标签&#xff0c;愿诸位喜欢 目录 文章目录 一、创建第一个HTML程序 二、HTML基本标签介绍 2.1 HT…

AAAI2024 The Thirty-Eighth Conference on Artificial Intelligence

Past Conferences For information about past AAAI Conferences, please consult the following pages. https://aaai.org/conference/aaai/ Future Conferences https://aaai.org/aaai-conference/ 2024 年 2 月在加拿大温哥华举行的第 38 届 AAAI 人工智能年度会议 The…