内存免杀--

通过分析Ekko项目了解内存加密过程,这对对抗内存扫描来说很重要。

概述

Edr会扫描程序的内存空间,检测是否存在恶意软件,这种检测恶意软件的方式,应该和静态检测没什么区别,只不过一个扫描的对象是硬盘,一个是内存,应该都是基于特征码来检测的,为了绕过这种扫描我们可以对内存中的beacon进行加密,但这样的话就会出现问题,因为beacon被加密后是无法正常的运行的,因为代码被加密了。
#
我们提到过自己是不可以加密自己的,但是Ekko项目实现了自己加密自己的内存,这对对抗内存扫描很有帮助。

API理解

CreateEvent()创建或打开一个事件对象

SetEvent()设置对象状态已通知状态

CreateTimerQueue()创建计时器队列

CreateTimerQueueTimer()创建计时器队列计时器


BOOL CreateTimerQueueTimer([out]          PHANDLE             phNewTimer,[in, optional] HANDLE              TimerQueue,[in]           WAITORTIMERCALLBACK Callback,[in, optional] PVOID               Parameter,[in]           DWORD               DueTime,[in]           DWORD               Period,[in]           ULONG               Flags
);

phNewTimer接受计时器队列计时器的缓冲区

TimeQueue计时器队列句柄

CallBack回调函数,计时器过期时要执行的函数

Parameter回调函数的参数

DueTime过多长时间向计时器发信号

Period计时器的周期,如果为0就向计时器发信号

Flag标志,指定函数调用相关内容。

对于CreateTimerQueueTimer函数可以这样理解,它可以定时执行一个函数,应该是异步执行的。

WaitForSingleObject()等待某个对象的状态,如果状态为已通知就往下执行,或者等待超时也会往下执行,也可以设置一直等待

SystemFunction032()通过RC4加密方式加密内存

RtlCaptureContext()得到当前线程的CONTEXT结构

对于CONTEXT结构可以理解为:用于存储线程运行时寄存器的值,RIP,RSP......

NtContinue()对于这个函数确实不太理解,这里只需要知道给它传进去一个CONTEXT结构,就可以执行CONTEXT对应的代码,也就是可以控制程序执行流程。

Ekko代码阅读

一些不太重要的代码会跳过去

image.png

  hEvent = CreateEventW(0, 0, 0, 0);//创建一个未通知状态自动复位的事件hTimerQueue = CreateTimerQueue();//创建计时器队列NtContinue = GetProcAddress(GetModuleHandleA("Ntdll"), "NtContinue");//得到函数地址SysFunc032 = GetProcAddress(LoadLibraryA("Advapi32"), "SystemFunction032");ImageBase = GetModuleHandleA(NULL);//当前程序地址ImageSize = ((PIMAGE_NT_HEADERS)((DWORD64)ImageBase + ((PIMAGE_DOS_HEADER)ImageBase)->e_lfanew))->OptionalHeader.SizeOfImage;//大小

这段代码通过调用CreateTimerQueue创建了一个计时器队列接着,通过调用GetModuleHandleAGetProcAddress得到了NtContinueSystemFunction032函数的地址,接着又得到了当前程序的基地址和当前程序的大小

image.png

if (CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)RtlCaptureContext, &CtxThread, 0, 0, WT_EXECUTEINTIMERTHREAD))//调用RtlCaptureContext得到CONTEXT结构{WaitForSingleObject(hEvent, 0x32);//等待memcpy(&RopProtRW, &CtxThread, sizeof(CONTEXT));memcpy(&RopMemEnc, &CtxThread, sizeof(CONTEXT));memcpy(&RopDelay, &CtxThread, sizeof(CONTEXT));memcpy(&RopMemDec, &CtxThread, sizeof(CONTEXT));memcpy(&RopProtRX, &CtxThread, sizeof(CONTEXT));memcpy(&RopSetEvt, &CtxThread, sizeof(CONTEXT));

通过CreateTimerQueueTimer创建了一个计时器,在创建后会立刻调用(因为DueTimeperiod都是0)RtlCaptureContext函数得到当前线程的CONTEXT结构,接着使用得到的CONTEXT结构初始化了一些CONTEXT结构,为下面的调用做准备。

image.png

        //构造VirtualProtect函数的CONTEXT结构,此函数用于修改内存权限// VirtualProtect( ImageBase, ImageSize, PAGE_READWRITE, &OldProtect );RopProtRW.Rsp -= 8;RopProtRW.Rip = (DWORD64)VirtualProtect;RopProtRW.Rcx = (DWORD64)ImageBase;RopProtRW.Rdx = (DWORD64)ImageSize;RopProtRW.R8 = PAGE_READWRITE;RopProtRW.R9 = (DWORD64)&OldProtect;//构造SystemFunction032函数的CONTEXT结构,此函数用于加密内存// SystemFunction032( &Key, &Img );RopMemEnc.Rsp -= 8;RopMemEnc.Rip = (DWORD64)SysFunc032;RopMemEnc.Rcx = (DWORD64)&Img;RopMemEnc.Rdx = (DWORD64)&Key;//构造WaitForSingleObject函数的CONTEXT结构,此函数用于睡眠// WaitForSingleObject( hTargetHdl, SleepTime );RopDelay.Rsp -= 8;RopDelay.Rip = (DWORD64)WaitForSingleObject;RopDelay.Rcx = (DWORD64)NtCurrentProcess();RopDelay.Rdx = SleepTime;//构造SystemFunction032函数的CONTEXT结构,此函数用于解密内存// SystemFunction032( &Key, &Img );RopMemDec.Rsp -= 8;RopMemDec.Rip = (DWORD64)SysFunc032;RopMemDec.Rcx = (DWORD64)&Img;RopMemDec.Rdx = (DWORD64)&Key;//构造VirtualProtect函数的CONTEXT结构,此函数用于修改内存权限// VirtualProtect( ImageBase, ImageSize, PAGE_EXECUTE_READWRITE, &OldProtect );RopProtRX.Rsp -= 8;RopProtRX.Rip = (DWORD64)VirtualProtect;RopProtRX.Rcx = (DWORD64)ImageBase;RopProtRX.Rdx = (DWORD64)ImageSize;RopProtRX.R8 = PAGE_EXECUTE_READWRITE;RopProtRX.R9 = (DWORD64)&OldProtect;//构造SetEvent函数CONTEXT结构,设置对象为已通知状态// SetEvent( hEvent );RopSetEvt.Rsp -= 8;RopSetEvt.Rip = (DWORD64)SetEvent;RopSetEvt.Rcx = (DWORD64)hEvent;

这段代码为调用VirtualProtectSystemFunction032......做准备
主要通过给CONTEXT结构的成员赋值,来模拟对应函数的调用(当然这里不是真的调用)

image.png

    //等100毫秒向计时器发信号,通过NtContinue调用VirtualProtect取消内存可执行权限CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopProtRW, 100, 0, WT_EXECUTEINTIMERTHREAD);//等200毫秒向计时器发信号,通过NtContinue调用SystemFunction032加密内存CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopMemEnc, 200, 0, WT_EXECUTEINTIMERTHREAD);//等300毫秒向计时器发信号,通过NtContinue调用WaitForSingleObject进行睡眠CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopDelay, 300, 0, WT_EXECUTEINTIMERTHREAD);

这段代码负责加密,主要通过CreateTimerQueueTimer函数创建计时器,计时器在等待指定的毫秒后,调用回调函数(也就是调用NtContinue)而NtContinue则会根据我们传入的CONTEXT结构去执行对应的函数。

比如第一行,传入的是VirtualProtect函数的CONTEXT结构,那么NtContinue将会调用VirtualProtect

下面是调用流程,画的有点丑,师傅们见谅^ _^......

image.png
第二行就是调用SystemFunction032来对内存进行加密
第三行就是调用WaitForSingleObject来实现睡眠,SleepTime就是睡眠的时间

image.png
下面来看一下解密内存部分

 //等400毫秒向计时器发信号,通过NtContinue调用SystemFunction032解密内存CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopMemDec, 400, 0, WT_EXECUTEINTIMERTHREAD);//等500毫秒向计时器发信号,通过NtContinue调用VirtualProtect更改内存权限为可执行CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopProtRX, 500, 0, WT_EXECUTEINTIMERTHREAD);//等600毫秒向计时器发信号,通过NtContinue调用SetEvent设置对象为已通知状态CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopSetEvt, 600, 0, WT_EXECUTEINTIMERTHREAD);

第一行通过调用SystemFunction032来解密内存,第二行调用VirtualProtect设置内存权限为可读可写可执行,第三行调用SetEvent将事件对象设置为已通知状态。
内存加密部分执行流程

image.png

主要的代码已经介绍完了,下面来看一下效果。

效果

睡眠前

image.png
睡眠后

image.png
因为作者水平有限,文章中难免会出现错误和不足之处,如果有哪些不好的地方希望各位师傅斧正。

参考

https://github.com/Cracked5pider/Ekko Ekko项目地址

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MidJourney笔记(6)-Niji模式

Niji模式 回顾一下,在讲解settings命令时,我们可以看到一个Niji字眼。 而且是在Midjourney V4之后才有的,那Niji到底是什么? Niji是MidJourney中用于绘制二次元/动漫风格的模型,那Niji的V4和V5有什么区别呢?

如何本地搭建个人hMailServer邮件服务并实现远程发送邮件

文章目录 前言1. 安装hMailServer2. 设置hMailServer3. 客户端安装添加账号4. 测试发送邮件5. 安装cpolar6. 创建公网地址7. 测试远程发送邮件8. 固定连接公网地址9. 测试固定远程地址发送邮件 前言 hMailServer 是一个邮件服务器,通过它我们可以搭建自己的邮件服务,通过cpola…

excel表格在线编辑(开源版)

文章目录 前言一、Luckysheetvue3vite 例子如有启发,可点赞收藏哟~ 前言 本文记录好用的开源在线表格 具体如图显示 另外记录下更名后的univer~,如下图(有兴趣可自行详细了解) univer 在线思维导图 一、Luckysheet 参考git…

vue使用elementui的el-menu的折叠菜单collapse

由于我的是在el-menu所在组件外面的兄弟组件设置是否折叠的控制,我用事件总线bus进行是否折叠传递 参数说明类型可选值默认值collapse是否水平折叠收起菜单(仅在 mode 为 vertical 时可用)boolean—falsebackground-color菜单的背景色&#…

Linux常用命令——awk命令

在线Linux命令查询工具 awk 文本和数据进行处理的编程语言 补充说明 awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能…

springCache——jetcache缓存

文章目录 jetcache远程、本地缓存方案jetcache方法注解使用方式 jetcache远程、本地缓存方案 <dependency><groupId>com.alicp.jetcache</groupId><artifactId>jetcache-starter-redis</artifactId><version>2.6.4</version></de…

mysql服务日志打印,时区不对的问题

查资料发现 原来日志的时区和服务器的时区不是一个参数控制的 log_timestamps 单独控制日志的时区 show global variables like log_timestamps;看到默认的是UTC&#xff0c;只需要修改为和系统一致就行 #数据库中直接修改 set global log_timestampsSYSTEM;#配置文件my.cn…

vue循环v-for遍历图表

循环遍历图表 index.vue主页面 <view v-if"powerPage"><view v-for"(item, index) in powerDetailsData.addMap" :key"index"><PowerEChartsCity:echartData"powerDetailsData.addMap[index]"></PowerEChartsC…

力扣 790. 多米诺和托米诺平铺(一维dp)

题目描述&#xff1a; 有两种形状的瓷砖&#xff1a;一种是 2 x 1 的多米诺形&#xff0c;另一种是形如 "L" 的托米诺形。两种形状都可以旋转。 给定整数 n &#xff0c;返回可以平铺 2 x n 的面板的方法的数量。返回对 109 7 取模 的值。 平铺指的是每个正方形都…

JavaScript WebAPI(三)(详解)

这次介绍一下webAPI中的一些知识&#xff1a; 回调函数 回调函数是指 如果将函数A做为参数传递给函数B时&#xff0c;我们称函数A为回调函数 例如&#xff1a; // 立即执行函数中传递的函数是一个回调函数 (function(){ console.log("我是回调函数") })(); // …

服务器数据恢复—服务器断电导致XenServer数据文件丢失的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌720服务器搭配该品牌某型号RAID卡&#xff0c;使用4块STAT硬盘组建了一组RAID10阵列。服务器上部署XenServer虚拟化平台&#xff0c;系统盘 数据盘两个虚拟机磁盘。虚拟机上安装的是Windows Server操作系统&#xff0c;作为Web服务器使用…

STM32内部温度传感器使用方法详解

STM32内部温度传感器使用方法详解 前言 STM32内部集成了一个片上温度传感器&#xff0c;可以用来测量MCU及周围的温度。测量范围&#xff1a;-40~125&#xff0c;精度1.5℃。虽然精度不高&#xff0c;但在某些应用场景下是够了的&#xff0c;相比于外部接入传感器&#xff0c…