驱动无模块注入dll

news2024/12/25 15:41:16

文章目录

      • 实现效果
      • 三环无模块注入的方案
      • 反射型dll注入方式的改进
      • 零环无模块注入方案
      • petoshellcode
      • 无模块注入流程
      • 实现代码
      • Xenos注入方案研究
        • IT_MMap注入
        • IT_Thread注入
        • IT_Apc注入
      • 火绒的注入思路

实现效果

在这里插入图片描述

可以看到dll已经成功执行,但是在内存区域里面并没有我们的模块,并且在模块列表里面,也没有我们的dll模块

三环无模块注入的方案

实际上无模块注入的方案在三环也可以完成,这种技术叫反射型dll注入。实现的原理就是在dll内部实现了一个loader函数代替LoadLibrary,然后把这个函数导出直接调用。

BlackBone里面已经封装好了相关的接口,直接调用就可以了

//隐藏注入dll 进程名 dll路径 适配32位和64位
void HideInject(const std::wstring& processName, const std::wstring& dllPath)
{
	vector<DWORD> vecPid = Process::EnumByName(processName);

	if (vecPid.empty())
	{
		MessageBoxA(0, "不存在目标进程", "提示", 0);
		return;
	}

	//首先要拿到目标进程的信息
	Process proc;
	proc.Attach(vecPid.front());

	//确保LdrInitializeProcess被调用
	proc.EnsureInit();

	//将PE文件映射到目标进程 1.PE文件路径 flags(手动映射导入函数) 回调函数
	auto image = proc.mmap().MapImage(dllPath, ManualImports, &MapCallback2);

	printf("ImageBase:%llx\n", image);

	//获取导出函数地址s
	auto g_loadDataPtr = proc.modules().GetExport(image.result(), "g_LoadData");

	//调用导出函数
	auto g_loadData = proc.memory().Read<DllLoadData>(g_loadDataPtr->procAddress);
	
}

我们把这个函数调用来看一下效果

HideInject(L"WeChat.exe", L"C:\\Users\\Administrator\\Desktop\\Test.dll");

实现效果如下:

在这里插入图片描述

在VAD树里可以看到这块内存在分配时的属性是可读可写可执行,而当前的内存属性是可读,说明BlackBone还是做了一些防护措施的,在dllmain执行完成后,把内存属性修改为了只读。

在这里插入图片描述

在枚举模块的位置已经找不到我们注入的dll了。

反射型dll注入方式的改进

事实上这种注入方式已经很隐蔽了,查探不到模块,但是依然还有两个问题,第一是内存区域指向的位置有PE头,第二是在申请时的内存属性为可执行。

那么我们可以针对这种方式进行改进:

  1. 在dll入口函数执行完成之后,把PE头抹掉
  2. 在申请内存时候,只申请可读可写的内存
  3. 在调用dllmain前,将属性修改为可执行
  4. 在执行完dllmain之后,将属性修改为只读

完成这些操作之后,在VAD树的分配时内存属性就会变成读写,当前的内存属性就会变成只读,再把PE头抹掉,就实现了三环的无模块注入了。

各位有需要可以参考这个思路进行自行魔改。

零环无模块注入方案

接下来再来说零环的无模块注入方案,零环的无模块注入方案首先要用到一个项目,将我们的dll文件转成shellcode

petoshellcode

pe转shellcode的原理就是在完整的dll外层套上一个用shellcode的加载器,然后由这个加载器把我们的dll跑起来。

https://github.com/monoxgas/sRDI

这里需要用到一个开源项目叫sRDI,做红队相关的同学应该比较眼熟了。

在这里插入图片描述

这个项目里面实现了一个加载dll的函数,使用shellcode的方式编写的,与位置无关,编译完成之后,可以直接把二进制扣出来用。

在这里插入图片描述

里面也有一个调用示例。我们需要修改下这个函数,把参数的部分去掉,就可以使用这个loader来加载任意一个dll了。

无模块注入流程

接着就可以开始实现驱动层的无模块注入了,流程如下:

  1. 将要注入的dll提取成硬编码存存放到char数组里
  2. 附加目标进程,申请一块不可执行的内存,用来存放硬编码的dll
  3. 用隐藏可执行内存的方式,申请一块可执行的内存,用来存放dllLoader
  4. 修改dllLoader内的dll入口函数地址
  5. 附加到目标进程,并创建线程执行dllLoder
  6. 等待线程执行完成,释放内存

实现代码

实现代码如下:


NTSTATUS Inject(HANDLE pid, char * shellcode, SIZE_T shellcodeSize)
{
	PEPROCESS Process = NULL;
	NTSTATUS status = PsLookupProcessByProcessId(pid, &Process);
	KAPC_STATE kApcState = {0};

	if (!NT_SUCCESS(status))
	{
		return status;
	}

	if (PsGetProcessExitStatus(Process) != STATUS_PENDING)
	{
		ObDereferenceObject(Process);
		return NULL;
	}

	PUCHAR kfileDll = ExAllocatePool(PagedPool, shellcodeSize);
	memcpy(kfileDll, shellcode, shellcodeSize);

	BOOLEAN isuFileAllocatedll = FALSE;
	BOOLEAN isuShellcode = FALSE;
	BOOLEAN isuimageDll = FALSE;

	PUCHAR ufileDll = NULL;
	PUCHAR uShellcode = NULL;
	SIZE_T uShellcodeSize = 0;
	PUCHAR uImage = NULL;
	SIZE_T uImageSize = 0;

	KeStackAttachProcess(Process, &kApcState);
	do 
	{
		//这里填充的是dll
		ufileDll = AllocateMemoryNotExecute(pid, shellcodeSize);

		if (!ufileDll)
		{
			break;
		}
		
		memcpy(ufileDll, kfileDll, shellcodeSize);

		isuFileAllocatedll = TRUE;


		//这里填充的是dllLoader
		uShellcode = AllocateMemory(pid, sizeof(MemLoadShellcode_x64));

		if (!uShellcode)
		{
			break;
		}

		isuShellcode = TRUE;

		memcpy(uShellcode, MemLoadShellcode_x64, sizeof(MemLoadShellcode_x64));

		PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ufileDll;
		PIMAGE_NT_HEADERS pNts = (PIMAGE_NT_HEADERS)(ufileDll + pDos->e_lfanew);
		uImageSize = pNts->OptionalHeader.SizeOfImage;

		//申请内存 存放展开后的dll
		uImage = AllocateMemory(pid, uImageSize);

		DbgPrint("Base:%llx\n", uImage);

		if (!uImage)
		{
			break;
		}

		//替换shellcode里面的dll地址 mov rax,uImage
		uShellcode[0x50f] = 0x90;
		uShellcode[0x510] = 0x48;
		uShellcode[0x511] = 0xb8;
		*(PULONG64)&uShellcode[0x512] = (ULONG64)uImage;

		
		//附加到目标进程 然后创建线程去跑dllLoader
		PETHREAD thread = NULL;
		if (CreateRemoteThreadByProcess(pid, uShellcode, ufileDll, &thread))
		{
			KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);
			memset(uImage, 0, PAGE_SIZE);
		}
		else 
		{
			isuimageDll = TRUE;
		}
	} while (0);


	//释放内存
	if (isuFileAllocatedll)
	{
		FreeMemory(pid, ufileDll, shellcodeSize);
	}

	if (isuShellcode)
	{
		FreeMemory(pid, uShellcode, uShellcodeSize);
	}

	if (isuimageDll)
	{
		FreeMemory(pid, uImage, uImageSize);
	}

	KeUnstackDetachProcess(&kApcState);

	ExFreePool(kfileDll);

	return status;
}

到这里所有的步骤就已经完成了,之前没研究过的时候总听人说驱动无模块注入,以为有多厉害,其实就是把三环的dlltoshellcode搬到了零环,再改掉分页属性,既隐藏掉了模块,也隐藏了可执行内存属性。

Xenos注入方案研究

既然都研究到这了,就索性把各路大神的注入姿势都研究一下。

https://github.com/DarthTon/Xenos

这个注入工具是一位大佬推荐给我的,说里面有几个比较牛逼的内核注入姿势,不过现在应该被各大游戏公司给杀了个遍。

具体什么原理当时也没看,现在回过头来瞅瞅。

在这里插入图片描述

我拿到了一份汉化版,居然还带BlackBone的驱动,驱动代码估计也是直接引用的。

在这里插入图片描述

里面有三种内核注入方式

在这里插入图片描述

找到这个枚举,然后分别查看引用,就能知道三种注入方案的原理了

在这里插入图片描述

都是调用的同一个函数

在这里插入图片描述

里面都是调用的BlackBone的接口,看来研究内核这个项目是绕不开了。

在这里插入图片描述

最终都是来到了这个函数,里面确实有三种注入的姿势。不得不说他这个注入写的确实好,考虑到的比较全。关保护,抹PE头,判断进程位数等等。自己写的话估计要踩很多坑,才能到他的代码健壮度。

不过这个Xenos的注入工具确实是太水了,调个接口都能拿1.5Kstar,还被传的牛逼哄哄的。。。。这我就不理解了

总结一下这个函数的三种注入方式:

IT_MMap注入

把目标PE在内存中展开后,创建线程调用导出函数LdrLoadDll进行内存加载;跟反射型注入的MapImage很像,大概翻了一下代码还是有区别的,MapImage反射注入dll是在三环把PE展开,而IT_MMap 的注入方式则是在驱动层把dll手动展开,并且抹掉了PE头,不知道为啥反射注入不抹掉。。。搞不懂作者咋想的。

IT_Thread注入

原理就是附加目标进程后,起了一个线程去执行代码

IT_Apc注入

这个就更没什么说的了,就是APC注入。

三个方式对比还是第一个最优

在这里插入图片描述

也就是这个玩意,有机会把里面的Map注入方式的代码给抠出来自己拿来用。

火绒的注入思路

再来看看火绒早期的注入

https://gitee.com/DragonQuestHero/nahequdongzhurudll

在这里插入图片描述

他这里是注册了一个模块监控的回调,相当于现在可以监控任意一个进程的主模块,等这个主模块跑起来的时候,再注入dll

在这里插入图片描述

先搜一下原理,再来看代码

在这里插入图片描述

大概就是等到目标进程跑起来的时候,替换一下IAT,这样就能实现在进程启动的时候注入dll了。没写注释看的头疼。。。就这样吧。加上这一个一共就有五种驱动注入的姿势了,后面想怎么注就怎么注了。

驱动无模块注入完整源码:

https://download.csdn.net/download/qq_38474570/87263833?spm=1001.2014.3001.5501

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

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

相关文章

《野球少年》:投捕搭档·棒球联盟

中文名 野球少年 原版名称 バッテリー 别 名 棒球伙伴、Battery 动画制作 ZERO-G 类 型 青春、运动、棒球 剧情简介 身为一名投手&#xff0c;原田巧是位拥有着拔群棒球才能的少年。在初中入学时移居的山间城镇新田市&#xff0c;巧与接住自己全力投球的捕手永仓豪相遇了。…

13 个你应该知道的 Webpack 优化技巧

Webpack 是目前前端开发最重要的构建工具。无论是自己的日常开发&#xff0c;还是准备面试&#xff0c;都应该掌握一些关于 Webpack 的优化技巧。 在这篇文章中&#xff0c;我将从三个方面分享一些我常用的技巧&#xff1a; 提高优化速度 压缩打包文件的大小 改善用户体验。…

[附源码]Python计算机毕业设计SSM基于框架的动漫设计(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

MarkDown语法浅析(基础语法)

本篇学习笔记简述MarkDown基础语法。掌握了“MarkDown基本语法简单HTML5标签”的综合运用&#xff0c;就可以把CSDN博文搞得美美哒✌ (本文获得CSDN质量评分【92】)【学习的细节是欢悦的历程】Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经…

SpringMVC笔记

文章目录一、SpringMVC简介1、什么是MVC2、什么是SpringMVC3、SpringMVC的特点二、HelloWorld1、开发环境2、创建maven工程a>添加web模块b>打包方式&#xff1a;warc>引入依赖3、配置web.xmla>默认配置方式b>扩展配置方式4、创建请求控制器5、创建springMVC的配…

Android开发中的服务发现技术

我们的日常开发中充满了InterfaceRegistry这种模式的代码&#xff0c;其中&#xff1a; Interface为定义的服务接口&#xff0c;可能是业务功能服务也可能是日志服务、数据解析服务、特定功能引擎等各种抽象层&#xff08;abstract layer&#xff09;&#xff1b;Registry为特…

线性表→顺序表→链表 逐个击破

一. 线性表 1. 前言 线性表&#xff0c;全名为线性存储结构。使用线性表存储数据的方式可以这样理解&#xff0c;即 “ 把所有(一对一逻辑关系的)数据用一根线儿串起来&#xff0c;再存储到物理空间中 ”。这根线有两种串联形式&#xff0c;如下图&#xff0c;即顺序存储(集中…

【收藏级】MySQL基本操作的所有内容(常看常新)

文章目录前言一、ER模型二、数据类型三、字段命名规范四、数据库创建与管理4.1、创建数据库4.2、删除数据库4.3、列出数据库4.4、备份数据库4.5、还原数据库4.6、使用某个数据库五、数据表创建与管理5.1、创建表、结构5.2、查看表结构5.3、查看数据表5.4、复制表结构5.5、复制表…

m基于PSO粒子群算法的重采样算法仿真,对比随机重采样,多项式重采样,分层重采样,系统重采样,残差重采样,MSV重采样

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 重采样的主要方法有随机重采样,多项式重采样,分层重采样,系统重采样,残差重采样,MSV重采样等。 a.随机采样是一种利用分层统计思想设计出来的&#xff0c;将空间均匀划分&#xff0c;粒子打点后…

Lecture6:激活函数、权值初始化、数据预处理、批量归一化、超参数选择

目录 1.最小梯度下降&#xff08;Mini-batch SGD&#xff09; 2.激活函数 2.1 sigmoid 2.2 tanh 2.3 ReLU 2.4 Leaky ReLU 2.5 ELU 2.6 最大输出神经元 2.7 建议 3.数据预处理 4. 如何初始化网络的权值 5. 批量归一化 6.超参数的选择 1.最小梯度下降&#xf…

Flowable定时器与实时流程图

1. 定时器 1.1. 流程定义定时激活 在之前松哥给小伙伴们介绍流程定义的时候&#xff0c;流程都是定义好之后立马就激活了&#xff0c;其实在流程定义的这个过程中&#xff0c;我们还可以设置一个激活时间&#xff0c;也就是流程定义好之后&#xff0c;并不会立马激活&#xf…

Java一些面试题(简单向)

以下全部简单化回答(本人新手,很多都是直接百度粘贴收集得来的,如有不对请留下正确答案,谢谢) (问题来源https://www.bilibili.com/video/BV1XL4y1t7LL/?spm_id_from333.337.search-card.all.click&vd_source3cf72bb393b8cc11b96c6d4bfbcbd890) 1.重写 重载的区别 重写(ov…

dubbo3.0使用

dubbo3.0使用 介绍 官方网址&#xff1a;https://dubbo.apache.org/ 本文基于springCloud依赖的方式演示相关示例&#xff1a;https://github.com/alibaba/spring-cloud-alibaba/wiki/Dubbo-Spring-Cloud dubbo示例项目&#xff1a;https://github.com/apache/dubbo-sample…

9 内中断

内中断 任何一个通用的CPU&#xff0c;比如8086 &#xff0c;都具备一种能力&#xff0c;可以在执行完当前正在执行的指令之后&#xff0c;检测到从CPU 外部发送过来的或内部产生的一种特殊信息&#xff0c;并且可以立即对所接收到的信息进行处理。这种特殊的信息&#xff0c;…

S7-200SMART高速脉冲输出的使用方法和示例

S7-200SMART高速脉冲输出的使用方法和示例 S7-200SMART PLC内部集成了高速脉冲发生器,不同的CPU型号,高速脉冲发生器的数量不同。 具体型号可参考下图: 注意:要输出高速脉冲的话,必须选择ST晶体管型号的PLC,SR继电器型的不支持。 S7-200SMART PLC能产生2种类型的高速脉冲…

【瑞吉外卖】公共字段填充

&#x1f341;博客主页&#xff1a;&#x1f449;不会压弯的小飞侠 ✨欢迎关注&#xff1a;&#x1f449;点赞&#x1f44d;收藏⭐留言✒ ✨系列专栏&#xff1a;&#x1f449;瑞吉外卖 ✨欢迎加入社区&#xff1a; &#x1f449;不会压弯的小飞侠 ✨人生格言&#xff1a;知足上…

激光雷达标定(坐标系转换)

文章目录1. 旋转矩阵2. 平移矩阵3. 坐标系的转换4. 坐标转换代码1. 旋转矩阵 由于激光雷达获取的点云数据的坐标是相对于激光雷达坐标系的&#xff0c;为了使车最终得到的点云数据坐标是在车坐标系下的&#xff0c;我们需要对点云中每一个点的坐标进行坐标转换。首先是需要对坐…

Docker笔记--创建容器、退出容器、查看容器、进入容器、停止容器、启动容器、删除容器、查看容器详细信息

目录 1--docker run创建容器 2--exit退出容器 3--docker ps查看容器 4--docker exec进入容器 5--docker stop停止容器 6--docker start启动容器 7--docker rm删除容器 8--docker inspect查看容器详细信息 1--docker run创建容器 sudo docker run -it --nametest redis…

Python 可迭代对象(Iterable)、迭代器(Iterator)与生成器(generator)之间的相互关系

1、迭代 通过重复执行的代码处理相似的数据集的过程&#xff0c;并且本次迭代的处理数据要依赖上一次的结果继续往下做&#xff0c;上一次产生的结果为下一次产生结果的初始状态&#xff0c;如果中途有任何停顿&#xff0c;都不能算是迭代。 # 非迭代例子 n 0 while n < …

SSM如何

目录 1、整合Mybatis 1.1.新建项目 1.2.添加pom依赖 1.3.application.yml 1.4.generatorConfig.xml 1.5.设置逆向生成 1.6.编写controller层 1.7.测试 2、整合 Mybatis-plus 2.1Mybatis-plus简介 2.2.创建项目 2.3.添加pom依赖 2.4.application.yml 2.5.MPGenerator 2.6.生成…