首页 网络安全 安全学院 查看内容

红队攻防之基础免杀(上)

2022-11-27 15:19 1651 0

摘要: 引言本文主要介绍“反射型dll注入”及“柔性加载”技术。反射型dll注入为什么需要反射型dll注入常规的dll注入代码如下:int main(int argc, char *argv) { HANDLE processHandle; PVOID remoteBuffer; wchar_t dllPa ...
关键词: 内存 调用 dll 使用 shellcode 注入 NULL 函数 我们 写入

引言

本文主要介绍“反射型dll注入”及“柔性加载”技术。

反射型dll注入

为什么需要反射型dll注入

常规的dll注入代码如下:

int main(int argc, char *argv[]) {
HANDLE processHandle;
PVOID remoteBuffer;
wchar_t dllPath[] = TEXT("C:\\experiments\\evilm64.dll");

printf("Injecting DLL to PID: %i\n", atoi(argv[1]));
processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof dllPath, MEM_COMMIT, PAGE_READWRITE);        
WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)dllPath, sizeof dllPath, NULL);
PTHREAD_START_ROUTINE threatStartRoutineAddress = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
CreateRemoteThread(processHandle, NULL, 0, threatStartRoutineAddress, remoteBuffer, 0, NULL);
CloseHandle(processHandle); 

return 0;
}

主要做了几件事情:

  1. 从磁盘读取dll到wchar_t数组
  2. 将该payload数组写入目标内存
  3. 在目标内存中找到LoadLibraryW函数
  4. 通过CreateRemoteThread调用LoadLibraryW函数,参数为dll在内存中的地址。

这样的操作模式有几个很高危的点。首先,从磁盘读取dll需要考虑dll的静态免杀,对此我们可以直接写在装载器中并加密。

其次,在目标内存中找到LoadLibraryW函数,需要GetProcAddress LoadLibraryW,这种调用属于很有特征的调用模式,容易被AV/EDR归类。对此我们的解决措施就是接下来要提及的反射型dll注入技术。

最后,CreateRemoteThread进行远程线程注入 行为本身就很高危,同时参数是LoadLibraryW的地址,一眼malware。

对此我们优化调用,不再使用CreateRemoteThread进而使用创建新进程的方式结合反射型dll注入技术改变dll注入技术的调用模式。

实现思路

早期的dll注入实现原理:

上图比较清楚的写了反射型dll注入的原理,1,2,3步由A向B线程写入dll。第四步调用B线程中的embedded bootstrapper code。最后通过bootstrapper shellcode调用dll的导出函数reflective loader。

reflective loader实际上是一个自己实现的LoadLibraryW函数,从内存中找到我们写入的dll并修复使其成为可以被正常使用的pe文件,最后调用DLLmain实现我们的恶意功能。

我们的具体实现和上面早期的思路有所区别,首先我们不使用远程进程/线程注入的方式,其次我们不需要bootstrapper shellcode这个部分,我们可以直接在加载器部分算出reflective loader在内存中的地址,直接调用即可。

【一一帮助安全学习,所有资源关注我,私信回复“资料”获取一一】
①网络安全学习路线
②20份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥网络安全必备书籍
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析

具体实现

加载器部分

首先shellcode使用AES解密,这部分添加了一些c的代码加密

后来发现原本项目的release目录下有python的加密脚本:

解密载入内存后,使用GetReflectiveLoaderOffset计算出ReflectLoader函数的偏移:

最后创建线程调用ReflectLoader函数。

dll部分

ReflectiveLoader一共做了5件事:

一、 解析加载DLL所需kernel32.dll WINAPI的地址(例如VirtualAlloc, LoadLibraryA等),
通过关键函数的hash在内存中搜索,函数hash:

遍历内存进行搜索:

二、 将DLL及其相应的节写入内存中:

三、 建立DLL导入表,以便DLL可以调用ntdll.dll和kernel32.dll WINAPI

四、 修复重定位表:

五、 调用DLL的入口点:

最终我们的恶意代码位于dllmain中,项目还是采用加载shellcode的方式上线cs。

柔性加载

限制使用具有RWX标记的内存,cs在4+可以直接进行相关配置。

推荐配置:

set startrwx        "false";
set userwx          "false";
set cleanup         "true";
set stomppe         "true";
set obfuscate       "true";
set sleep_mask      "true";
set smartinject     "true";

牛刀小试

360

使用base64+xor混淆shellcode:

成功bypass:

火绒

和上述方法相同:

definder

加强shellcode的混淆:

std::string rest2_reference = "xxx@@";
std::string rest3_reference = replace(rest2_reference, "@@", "==");

依旧报毒,但是类型发生改变了,说明静态的混淆有效果:

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部