windows机制初探
2023-4-26 14:41:9 Author: 红队蓝军(查看原文) 阅读量:13 收藏

Windows内存管理

EPROCESS结构体:在内核中表示一个进程

VAD树

二叉树,存储进程在内核层申请的虚拟内存信息

(x86 EPROCESS+0x11c) (x64 EPROCESS+0x7d8)指向VadRoot(VAD树)

可以看到两种内存:Private(私有内存)、 Mapped(映射内存)

私有内存

通过VirtualAlloc、VirtualAllocEx等申请(malloc、new是在用户层申请虚拟内存,所以不是)

独享物理页,可读可写可执行的 Private 会被杀软重点关注

映射内存

通过 CreateFileMapping 等映射

可能与其他进程共享物理页,可以防止多个进程访问DLL时死锁

操作系统通过 VirtualAlloc 预先分配好的一大块内存

malloc和new的调用链: malloc -> _nh_malloc_dbg -> _heap_alloc_dbg -> _heap_alloc_base -> HeapAlloc new -> _nh_malloc -> _nh_malloc_dbg -> _heap_alloc_dbg -> _heap_alloc_base -> HeapAllocHeapAlloc的作用就是在堆里分一些出来

SystemCall 系统调用(x86)

用户层地址0-7开头,内核层8-f

用户层(x86 0x7ffe0000 可读)和内核层(x86 0xffdf0000 可读可写)分别有一个KUSER_SHARED_DATA结构体(用于共享数据,指向同一物理页)

操作系统在系统启动时在 KUSER_SHARED_DATA+0x300 写入 KiFastSystemCallKiIntSystemCall

快速调用:sysenter/sysexit(返回用户层),ntdll 中的 KiFastSystemCall 函数

中断门(老版本):int 0x2E,ntdll 中的 KiIntSystemCall 函数

通过汇编判断支持的方式:

; 将CPU的信息存入寄存器
mov eax,0x1
cpuid

之后edx的SEP位(从右向左从0开始数第11位)为1则支持快速调用,为0则支持中断门

进入内核后,CS由3变为0(0环权限)、SS也改变权限、换栈,然后找SSDT表(系统服务描述符表,KSERVICE_TABLE_DESCRIPTOR结构体,存储真正函数实现的地址)

两个SSDT表(结构相同):

KeServiceDescriptorTable 主要处理 kernel32,在ntoskrnl.exe是导出的

KeServiceDescriptorTableShadow 主要处理 user32、gdi32,没有被Windows导出

双机调试看结构:

kd> dd KeServiceDescriptorTable
80553fa0  80502b8c 00000000 0000011c 80503000
...

一行是一个KSYSTEM_SERVICE_TABLE结构体

参数1指向当前内核函数地址(位于所有内核函数地址的数组中)

参数2指向当前内核函数使用次数的地址(位于所有内核函数使用次数的数组中)

参数3代表所有内核函数个数(284)

参数4代表当前内核函数参数个数(0x18/0x4=0x6)

kd> db 80503000
80503000  18 20 2c 2c 40 2c 40 44-0c 08 18 18 08 04 04 0c
...

用Ollydbg找函数在SSDT表中的调用号

底部Command(bp 函数名),下断点

直到跟进Call ntdll,看到调用号(0x7A)ntdll.ZwOpenProcess mov eax,0x7A偏移到函数

kd> dd 80502b8c + 7A*4
80502d74  805c2296 805e49fc 805e4660 805a0722
...
kd> u 805c2296
nt!NtOpenProcess:
805c2296 68c4000000      push    0C4h
805c229b 68a8aa4d80      push    offset nt!FsRtlLegalAnsiCharacterArray+0x2008 (804daaa8)
805c22a0 e86b6cf7ff      call    nt!wctomb+0x45 (80538f10)
805c22a5 33f6            xor     esi,esi
805c22a7 8975d4          mov     dword ptr [ebp-2Ch],esi
805c22aa 33c0            xor     eax,eax
805c22ac 8d7dd8          lea     edi,[ebp-28h]
805c22af ab              stos    dword ptr es:[edi]
3.驱动(x86)

驱动程序(.sys):让内核兼容不同硬件,在加载时会在注册表注册服务

每个进程有4GB内存空间:低2GB是独立的,高2GB位于内核层是公共的

DRIVER_OBJECT结构体代表驱动程序(一种内核模块)

DRIVER_OBJECT+0x10 为 DriverSize(驱动大小)

DRIVER_OBJECT+0x1c 为 DriverName(驱动名称)

DRIVER_OBJECT+0x14 为 DriverSection(指向LDR_DATA_TABLE_ENTRY结构体)

LDR_DATA_TABLE_ENTRY+0x0 为 InLoadOrderLinks结构体(LIST_ENTRY双向链表结构体,可以遍历内核模块)

LDR_DATA_TABLE_ENTRY+0x18 为 DllBase(当前模块首地址)

LDR_DATA_TABLE_ENTRY+0x20 为 SizeOfImage(当前模块大小)

LDR_DATA_TABLE_ENTRY+0x24 为 FullDllName(驱动文件完整路径)

遍历模块输出信息,例:

#include <ntddk.h>

typedef struct _LDR_DATA_TABLE_ENTRY {
    LIST_ENTRY InLoadOrderLinks;
    LIST_ENTRY InMemoryOrderLinks;
    LIST_ENTRY InInitializationOrderLinks;
    PVOID DllBase;
    PVOID EntryPoint;
    UINT32 SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    UINT32 Flags;
    UINT16 LoadCount;
    UINT16 TlsIndex;
    LIST_ENTRY HashLinks;
    PVOID SectionPointer;
    UINT32 CheckSum;
    UINT32 TimeDateStamp;
    PVOID LoadedImports;
    PVOID EntryPointActivationContext;
    PVOID PatchInformation;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;

VOID DriverUnload(PDRIVER_OBJECT driver) // 卸载驱动时调用
    DbgPrint("Unload\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) // 加载驱动时调用
    DbgPrint("驱动地址:%x\n注册表路径:%wZ", driver, reg_path);

    PLDR_DATA_TABLE_ENTRY phead = (PLDR_DATA_TABLE_ENTRY)(driver->DriverSection); // 头节点
    PLDR_DATA_TABLE_ENTRY pcur = phead; // 当前节点

    do {
        pcur = (PLDR_DATA_TABLE_ENTRY)(pcur->InLoadOrderLinks.Flink);
        DbgPrint("DllBase:%p,SizeOfImage:%08X,BaseDllName:%wZ\n", pcur->DllBase, pcur->SizeOfImage, &(pcur->BaseDllName));
    } while (phead != pcur);

    driver->DriverUnload = DriverUnload; // 指定卸载函数
    return STATUS_SUCCESS;
}

EDR回调监控

1.x86:用jmp进行hook

2.x64:在0环通过回调函数,挂驱动(.sys)来实现监控

系统会随机对内存和快照进行比对,导致用jmp进行hook可能触发PG(Patch Guard)导致蓝屏

微软提供了CmRegisterCallback回调函数来监控注册表操作

本文为免杀三期学员笔记:https://www.cnblogs.com/LeiyNeKo/articles/17201218.html

课程链接如下

第四期免杀课程


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NDY2MTQ1OQ==&mid=2247508435&idx=1&sn=13996abb395502c0e09d5a20506dab35&chksm=ce671b6ff9109279da0377eaae6b5106e5972fc26db74d2418be91da7902c5d2eb6a34cbaeb4#rd
如有侵权请联系:admin#unsafe.sh