内存免杀--

news2025/1/6 13:58:07

通过分析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.coloradmin.cn/o/1277276.html

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

相关文章

vue中使用echarts实现省市地图绘制,根据数据在地图上显示柱状图信息,增加涟漪特效动画效果

一、实现效果 使用echarts实现省市地图绘制根据数据在地图显示柱状图根据数据显示数据,涟漪效果 二、实现方法 1、安装echarts插件 npm install echarts --save2、获取省市json数据 https://datav.aliyun.com/portal/school/atlas/area_selector 通过 阿里旗下…

振南技术干货集:各大平台串口调试软件大赏(6)

注解目录 (串口的重要性不言而喻。为什么很多平台把串口称为 tty,比如 Linux、MacOS 等等,振南告诉你。) 1、各平台上的串口调试软件 1.1Windows 1.1.1 STCISP (感谢 STC 姚老板设计出 STCISP 这个软件。&#xf…

安科瑞ASCP200系列 DS 型电气防火限流式保护器 充电桩配套用限流式保护 -安科瑞 蒋静

1 概述 电气防火限流式保护器可有效克服传统断路器、空气开关和监控设备存在的短路电流大、切断短路电流 时间长、短路时产生的电弧火花大,以及使用寿命短等弊端,发生短路故障时,能以微秒级速度快速限制短 路电流以实现灭弧保护&#xff0…

Python 重要数据类型

目录 列表 序列操作 列表内置方法 列表推到式 字典 声明字典 字典基本操作 列表内置方法 字典进阶使用 字典生成式 附录 列表 在实际开发中,经常需要将一组(不只一个)数据存储起来,以便后边的代码使用。列表就是这样的…

python之logo编程

Logo标志是一种视觉符号,代表着一个品牌、企业或组织的形象。它通常采用图形、字母或字形来代表一个公司或品牌,起到对徽标拥有公司的识别和推广的作用。Logo的设计需要考虑多种因素,例如颜色搭配、字体选择和构图等,以创造出独特…

C#中GDI+图形图像绘制(直线、矩形、圆、椭圆、圆弧、扇形、多边形)

目录 一、直线 二、矩形 三、椭圆 四、圆 五、圆弧 六、扇形 七、多边形 八、示例源码 一、直线 调用Graphics类中的DrawLine()方法,结合Pen对象可以绘制直线。DrawLine()方法有以下两种构造函数。 第一种用于绘制一条连接两个Point结构的线。当参数pt1的值…

Spring---更简单的存储和读取对象

文章目录 存储Bean对象配置扫描路径添加注解存储Bean对象使用类注解为什么需要五个类注解呢?Bean命名规则 使用方法注解重命名Bean 读取Bean对象属性注入Setter注入构造方法注入注入多个相同类型的BeanAutowired vs Resource 存储Bean对象 配置扫描路径 注&#xf…

计算机网络TCP篇①

目录 一、TCP 基本信息 1.1、TCP 的头格式 1.2、什么是 TCP 1.3、什么是 TCP 连接 1.4、TCP 与 UDP 的区别 1.2、TCP 连接建立 1.2.1、TCP 三次握手的过程 1.2.2、为什么是三次握手?不是两次?四次?(这个问题真是典中典&am…

python自动化第二篇——合并ppt

简述 python合并ppt的方法有很多,但网上常说的python-pptx的方法,我用不了,这里我用了一个python-office的库。但又两个缺点,第一个生成的文档在你的用户名下的文档里,第二个是名字随机。 import office import os im…

2023_Spark_实验二十四:SparkStreaming读取Kafka数据源:使用Direct方式

SparkStreaming读取Kafka数据源:使用Direct方式 一、前提工作 安装了zookeeper 安装了Kafka 实验环境:kafka zookeeper spark 实验流程 二、实验内容 实验要求:实现的从kafka读取实现wordcount程序 启动zookeeper zk.sh start# zk.sh…

西南科技大学模拟电子技术实验三(BJT单管共射放大电路测试)预习报告

一、计算/设计过程 说明:本实验是验证性实验,计算预测验证结果。是设计性实验一定要从系统指标计算出元件参数过程,越详细越好。用公式输入法完成相关公式内容,不得贴手写图片。(注意:从抽象公式直接得出结果,不得分,页数可根据内容调整) 二、画出并填写实验指导书上…

数据结构 - 堆:TOP-K问题

问题描述 TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大 比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等 对于Top-K问题,能想到的最简单直接的方式就是排序,但是&…

使用drawio图表,在团队中,做计划,设计和跟踪项目

使用drawio图表,在团队中,做计划,设计和跟踪项目 drawio是一款强大的图表绘制软件,支持在线云端版本以及windows, macOS, linux安装版。 如果想在线直接使用,则直接输入网址draw.io或者使用drawon(桌案), drawon.cn内部…

六、三台主机免密登录和时钟同步

目录 1、免密登录 1.1 为什么要免密登录 1.2 免密 SSH 登录的原理

Sass 同时导出JavaScript 和 CSS变量

Sass 官网 安装插件 注意 sass-loader 版本没设太高,否则会报错 Syntax Error: TypeError: this.getOptions is not a function npm i sass sass-loader10 -D创建 Sass 文件 variables.module.scss。注意这里是 module.scss: 否则报错 Cant find st…

安卓小程序与编译抓包

APK小程序渗透测试 查找bp的证书 在浏览器中打开bp代理,然后在网页中搜索hppps://burp 点击高级——接受风险并继续 拿到证书 将浏览器信任证书 打开设置 搜索证书——查看证书 点击导入——导入证书 证书验证成功后,访问网页(吾爱破解&a…

linux上编写进度条

目录 一、预备的两个小知识1、缓冲区2、回车与换行 二、倒计时程序三、编写入门的进度条四、编写一个正式的五、模拟实现和下载速度相关的进度条 一、预备的两个小知识 1、缓冲区 首先认识一下缓冲区:先写一个.c文件如下: 我们执行一下这个程序时&…

windows ce Remote Process Explorer定位程序崩溃地址

windows ce Remote Process Explorer定位程序崩溃地址 一:下载地址二:使用1)找到程序基准地址2) 定位程序异常位置 一:下载地址 链接:https://pan.baidu.com/s/1fQVBpputtRmynqa95DaPrg 提取码:cx65 二&a…

hdlbits系列verilog解答(真值表)-50

文章目录 一、问题描述二、verilog源码三、仿真结果一、问题描述 本节我们学习用真值表来描述组合逻辑的行为,通过真值表我们将组合逻辑的每一种输入和输出对应值都罗列出来。 对于一个N个输入的布尔函数,理论上有2的N次方输入组合。下表是一个3输入的例子。 假设现在我们来…

Vue---Echarts

项目需要用echarts来做数据展示,现记录vue3引入并使用echarts的过程。 1. 使用步骤 安装 ECharts:使用 npm 或 yarn 等包管理工具安装 ECharts。 npm install echarts 在 Vue 组件中引入 ECharts:在需要使用图表的 Vue 组件中,引入…