首页
社区
课程
招聘
[原创]BattlEye内核驱动检测模块深入分析
发表于: 2022-7-4 23:47 37743

[原创]BattlEye内核驱动检测模块深入分析

2022-7-4 23:47
37743

BattlEye总共分为以下4个部分:

本次分析的是BEDaisy,也就是BE内核驱动中的各种检测。

BE内核驱动中包含着很多种检测,在发现检测到异常情况时首先会记录到一个内部的链表中,然后当BEClient对BE内核驱动发起特定长度的读请求时,BE内核驱动会将链表内的数据发送给BEClient,BEClient再将其发送给BEServer。

半个月前写过一个简易的绕过BE内核驱动的程序,原理就是阻断这一过程,具体原理请看我的上一篇文章:https://bbs.pediy.com/thread-273334-1.htm

下面的内容主要分为三个部分,第一个是上传部分,主要是讲解BEClient给BE内核驱动发送的各种检测相关的数据;第二个是检测部分,重点讲述BE内核驱动中的各种检测第三个部分是对于这些检测的总结。BE内核驱动中还包含一些其他的内容,比如数据包加解密算法、设备UID算法等,这些内容都不涉及“检测”,因此在本文中不进行分析。

BEClient通过对BE驱动调用Write方法,也就是对应驱动的IRP_MJ_WRITE方式进行上传。上传的内容主要是一些黑名单特征,这些特征应该是从服务器下发的,因此可以在不重新编译驱动的情况下,动态调整检测的特征。

以类似数组的形式紧密排列,由于检测数据不定长,因此每个数据包是动态长度的,依靠包头记录的数据包长度确定下一个数据包的位置。

检测分为两类:

如果report list 0中存在数据包,则会挨个检测是否有匹配的特征,如果存在则直接原封上报异常数据。(由于并没有人写入report list 0,因此怀疑该检测暂未开启)

report list 0 数据结构如下:

通过IrpWrite上传的数据包如下:

g_PatternBlackList是存储着32个PatternBlackListItem的数组,具体数量记录在g_PatternBlackListSize中

在检测线程启动时,会向g_PatternBlackList添加一个9字节长度的硬编码的特征(看起来像是有关ROP的一些特征?不太清楚。)

对应amd64汇编

该检测针对的是进程、线程的前置、后置回调,注册表回调,映像加载回调,对这些函数的头部64个字节进行特征检测。

数据包格式同上一个特征,检测的对象为系统调用函数的头部64字节。

上传的内容为一个给定偏移量的字节序列,在后续步骤中(见report type 18)会使用上传的特征对BE驱动自身的重点代码进行检查,检查BE驱动是否被篡改。

该特征用于定位Dxgkrnl某个内部的未导出函数,在后续步骤(见report type 22),BE将会Hook该函数,并对该函数的地址范围进行检查。

该类型的数据包仅是为了触发InfinityHook检测(见report type 23),不传输数据。

该部分内容较多,总共有30多种检测。大多数的检测都具有标号,只有当检测结果异常时才会记录,并传输给处在应用层的BEClient,然后再由其发送给BE的服务器。所有具有标号的检测如下,除此之外还有少量处在IRP_MJ_READ的handler中的没有标号的检测(例如:获取设备UID,虚拟机检测等)。

在接收到应用程序上传的数据后会开始检测。BE会对自身的驱动的关键部位进行检查,检查是否被篡改。如果出现异常则会上报。

数据包结构:

BE会对通过MmGetSystemRoutineAddress获得的系统函数进行完整性检测,会检测此时调用MmGetSystemRoutineAddress获得的地址与以前获得的地址是否相同,会检测系统函数头部是否存在hook,如果存在hook则会追踪连续的无条件跳转,直到最终的hook函数,并上报该hook函数的特征上报。

总共分为4类异常:

除此之外,如果判定正常,仍会将信息临时记录在report list 2中,方便在后续过程中检查是否存在黑名单特征。

数据包结构:

会试图通过多种手段遍历系统线程(通过SystemProcessInformation获得线程信息、通过枚举TID尝试得到线程对象),如果遍历过程中检测到隐藏进程/线程(找不到系统进程或系统进程的SystemProcessInformation中找不到当前线程),则会在全局变量中进行记录。

如果检测到启动地址不在加载模块地址范围内的系统线程(模块地址范围会在LoadImageNotify中以链表的形式记录),则会上报异常数据。猜测是用来检测kdmapper等工具加载的模块。

数据包结构:

向所有系统线程插入APC,调用RtlWalkFrameChain获得调用者列表,依次检查各个内核空间调用者的地址是否在模块范围内,是否存在黑名单中的特征,是否存在多次跳转(>=5)、int3、nop等异常情况,如果存在则直接上报异常数据,如果判断正常则会添加到report list 0,待进一步进行黑名单检查。

数据包结构:

会检测进程、线程的前置、后置回调,注册表回调,映像加载回调,检测是否存在一下几种hook,最多检测头部64字节:

(注:不会多次追踪跳转,只会追踪1次,感觉设计不太合理)

当检测到hook时才会上报异常数据,结构如下:

检测回调地址是否在某个内核模块的范围内,如果不在任何一个模块的地址范围内,则上报异常。

数据包结构:

所有进程、线程的前置、后置回调,注册表回调,映像加载回调都会记录到report list 1,待进一步检测黑名单特征。

数据包结构:

检测是否有应用程序引用"\\device\\PhysicalMemory"对象,如果存在则上报异常数据。

检测的逻辑如下:

首先遍历所有进程,使用MmUnmapViewOfSection解除掉"\\device\\PhysicalMemory"的映射,然后再查看"\\device\\PhysicalMemory" Section对象内部的ControlArea中的NumberOfUserReferences是否为0,如果非0则说明仍存在应用程序对物理内存的引用,因此判定异常,上报异常数据。(用于检测某种手动创建的"\\device\\PhysicalMemory"对象?)

数据包结构:

首先置一个标志位为0,然后尝试获得游戏进程句柄,如果回调工作正常,则会将标志位置为1,否则标志位仍为0,从而达到检测回调是否被通过某些手段摘除,无法正常工作。

如果回调无法正常工作,则会上报一次异常数据(不会重复上报)。

数据包结构:

在BE内核模块加载时检查所有系统模块的派遣函数是否都是自己本模块内的函数或者是系统模块(ntoskrnl)的函数。

在运行中会检查自身的MJ_IRP_CREATE、MJ_IRP_CLOSE、MJ_IRP_READ、MJ_IRP_WRITE对应的派遣函数是否被修改,如果被修改则会上传到异常链表,否则不会有额外操作。

数据包结构:

该函数在线程回调函数中被调用,该函数会检测PsLookupThreadByThreadId是否被hook,检测的hook类型仅是FF 25 jmp,即 jmp [addr] 类型的hook。该函数最多追踪2次jmp,如果出现hook则会上传到异常链表。

(会对封包从1到45字节做异或0x7F的加密操作,第一个字节PacketType不进行加密,不知道为什么要这么做)

数据包结构:

\\FileSystem\\Filters\\FltMgrMsg对象涉及到Filter通信,其中有过滤通信的回调函数,因此BE对其进行了检测。

可以参考该文章:https://www.amossys.fr/fr/ressources/blog-technique/filter-communication-ports/

其中有3个callback会被检测:

检测回调地址是否在某个内核模块的范围内,如果不在任何一个模块的地址范围内,则上报异常。

数据包结构:

对3个回调函数做hook检查,方式同回调hook检测(report type 6),仅report type不同。

在检测到hook时会上报异常数据,结构如下:

首先BE会先Hook该函数,然后在Hook函数中对原始函数进行模块范围检测,目前该检测还不完善,并且在卸载驱动时也没有对该私有链表进行清理,因此怀疑该检测未开启。如果检测到该函数地址不在任何一个模块内,则会上报异常数据。

为了避免重复上报,该检测使用report list 6记录每个异常上报数据。

数据包结构:

首先检测系统是否可以进行infinity hook,如果可能进行了infinity hook,则会检测WmipLoggerContext中每一项的GetCpuClock函数地址,如果该函数地址在模块地址范围内,并且该地址所在节的权限为executable + non-paged(从磁盘读取PE文件进行解析),则判定为正常,否则判定为异常,会上报异常数据。

为了避免重复上报,该检测使用report list 5记录每个异常上报数据用于去重。

数据包结构:

遍历内核中加载的所有模块,对其进行检测,但是会跳过以下几个模块。

在处理win32k模块时,由于win32k模块的内存只在csrss中进行了映射,因此需要附加到csrss后再进行检查。

由于该检测模块较为混乱,因此逆向分析的不是很清楚,怀疑是在寻找模块中一些int 3、hook的指令,并将指令所在的页面上传到异常链表。

其中对dxgkrnl.sys有特殊检测,怀疑是在检测gdi hook,原文链接:https://secret.club/2019/10/18/kernel_gdi_hook.html

数据包结构:

通过解析各个模块的内存中的PE结构,检查是否存在某个IAT项的函数地址不在任何一个模块范围内,如果是则会上报异常数据。

数据包结构:

通过遍历\\Device目录,得到所有Device类型的对象,然后遍历\\Driver和\\FileSystem目录,得到所有Driver对象,对每个Device对象找到其内部存储的Driver指针,然后逐一匹配刚才遍历得到的Driver对象,如果没有任何一个Driver对象与其匹配,则判定该Device对应的驱动被隐藏了,会上报异常数据。

数据包结构:

通过I/O指令遍历PCI设备树,寻找具有指定特征的PCI设备,怀疑是检测DMA作弊工具。如果找到具有指定特征的PCI设备,则会上报异常数据。

PCI设备检测实现参考源码:https://gitlab.freedesktop.org/xorg/lib/libpciaccess/-/blob/master/src/x86_pci.c

UC上也有人提到过该检测:https://www.unknowncheats.me/forum/anti-cheat-bypass/304545-detecting-dma-hardware-cheats-12.html

(注意:在第二种上报类型中,Info中的Dev貌似被BE的开发者误写成了Bus,导致记录了两次Bus而没有记录Dev,笑)

数据包结构:

gDxgkInterface和gDxgkWin32kEngInterface是存储在Win32k中的两张函数表,作用类似于SSDT,IChooseYou曾将其用于无模块驱动的通信,https://www.unknowncheats.me/forum/anti-cheat-bypass/335585-communicating-mapped-driver-using.html,故BE对其进行检测。

由于win32k仅在csrss模块的地址空间中进行了映射,因此在检测时需要附加到csrss进程。

对gDxgkInterface 表中的绝大部分函数进行地址范围检测(跳过前两个函数),检测其地址是否在win32k模块范围内。

数据包结构:

对上述函数进行hook检测,检测方式同回调Hook检测(report type 6),仅report type不同。FunctionType值为函数在表中的下标。

对gDxgkWin32kEngInterface表中的所有函数进行地址范围检测,检测其地址是否在win32k模块范围内。

数据包结构:

对上述函数进行hook检测,检测方式同回调Hook检测(report type 6),仅report type不同。FunctionType值为函数在表中的下标。

该表未导出,因此BE通过特征码定位的方式获得该表,通过BRUSHOBJ_hGetColorTransform函数进行定位,在该函数中搜索如下特征码,addr1即为ext_ms_win_core_win32k_full_export_l1:

对该表中的函数逐个检测地址,查看其是否在win32k和win32kfull模块的范围内,如果不在则会上报异常数据。

数据包结构:

DxgCoreInterface是Dxgkrnl模块中的一张函数表。可能曾被用作无模块通信/绘制,或者仅是预防性检查。

对DxgCoreInterface表中的所有函数进行地址范围检测,检测其地址是否在win32k模块范围内。

数据包结构:

对上述函数进行hook检测,检测方式同回调Hook检测(report type 6),仅report type不同。

这是https://www.unknowncheats.me/forum/anti-cheat-bypass/335585-communicating-mapped-driver-using.html这篇文章中提到的另一种通信方式,具体的实现方式是hook HalDispatchTable中的函数,因此BE对该表进行检测。除此之外,BE还发现HalPrivateDispatchTable也可以被hook,因此又额外加入了对该表的检测。

对HalDispatchTable 表中的所有函数进行地址范围检测,检测其地址是否在ntoskrnl、hal等系统模块范围内。

数据包结构:

对上述函数进行hook检测,检测方式同回调Hook检测(report type 6),仅report type不同。FunctionType值为函数在表中的下标。

对HalPrivateDispatchTable 表中的所有函数进行地址范围检测,检测其地址是否在ntoskrnl、hal等系统模块范围内。

数据包结构:

对上述函数进行hook检测,检测方式同回调Hook检测(report type 6),仅report type不同。FunctionType值为函数在表中的下标。

在BE加载时,会对系统内的所有模块进行扫描,对每个驱动的每个派遣函数进行扫描,检测是否存在hook。

只会检测头部64个字节以内的hook(仅以下两种形式),并且只会跟踪一次跳转,不会跟踪多次跳转。

数据包结构:

尝试打开\\Driver,\\FileSystem目录下的Driver对象,如果通过ObOpenObjectByName打开失败,则会上报异常数据。

数据包结构:

通过线程创建回调监视游戏内创建线程的操作,如果线程启动地址不在任何一个游戏模块内,则判定为异常,上报异常数据。猜测该检测主要用来检测DLL注入。

数据包结构:

附件是逆向后的文件,感兴趣的可以看一看这些检测具体是怎么实现的。如果发现我哪里分析的有问题,欢迎指出错误。

 
 
 
 
struct AbnormalListItem {
    // because nobody writes to report list 0, so some parts of the structure is unknown
    BYTE Unknown[10];
    BYTE Content[64];
};
struct AbnormalListItem {
    // because nobody writes to report list 0, so some parts of the structure is unknown
    BYTE Unknown[10];
    BYTE Content[64];
};
struct UploadPatternBlackListItemType0 {
    // -1 means no specified match offset, it will try every possible offset
    // not -1 means a specified offset, it will just try the offset
    BYTE MatchOffset;
    // if the length <= 32, it will be copied to the g_PatternBlackList
    BYTE PatternLength;
    // length depends on PatternLength
    BYTE Content[0];
};
struct UploadPatternBlackListItemType0 {
    // -1 means no specified match offset, it will try every possible offset
    // not -1 means a specified offset, it will just try the offset
    BYTE MatchOffset;
    // if the length <= 32, it will be copied to the g_PatternBlackList
    BYTE PatternLength;
    // length depends on PatternLength
    BYTE Content[0];
};
struct PatternBlackListItemType0 {
    // pattern in black list up to 32 bytes
    BYTE Pattern[32];
    // length up to 32
    ULONG Length;
};
struct PatternBlackListItemType0 {
    // pattern in black list up to 32 bytes
    BYTE Pattern[32];
    // length up to 32
    ULONG Length;
};
48 81 C4 80 01 00 00 5F C3
48 81 C4 80 01 00 00 5F C3
add rsp, 180h
pop rdi
ret
add rsp, 180h
pop rdi
ret
struct UploadPatternBlackListItemType1or2 {
    // -1 means universal pattern, this check will be applied to each callback
    // not -1 means this check only works on a specific callback
    BYTE FunctionType;
    // -1 means no specified match offset, it will try every possible offset
    // not -1 means a specified offset, it will just try the offset
    BYTE MatchOffset;
    // length of the pattern
    BYTE PatternLength;
    // length depends on PatternLength
    BYTE Content[0];
};
struct UploadPatternBlackListItemType1or2 {
    // -1 means universal pattern, this check will be applied to each callback
    // not -1 means this check only works on a specific callback
    BYTE FunctionType;
    // -1 means no specified match offset, it will try every possible offset
    // not -1 means a specified offset, it will just try the offset
    BYTE MatchOffset;
    // length of the pattern
    BYTE PatternLength;
    // length depends on PatternLength
    BYTE Content[0];
};
struct UploadSelfIntegrityCheck {
    // if it is true, it means use stored driver memory range
    // if it is false, it means use driver memory range read from driver object
    BOOLEAN UseStoredDriverInfo;
    // offset to the driver module
    ULONG Offset;
    // unknown, has an impact on the reporting policy
    // if the flag is true, then normal means upload, abnormal means don't upload
    // maybe use to detect some kind of attack?
    BOOLEAN FlipReportPolicy;
    // compare size, up to 64 bytes
    ULONG CompareSize;
    // content of normal data, length depends on CompareSize
    BYTE Content[0];
};
struct UploadSelfIntegrityCheck {
    // if it is true, it means use stored driver memory range
    // if it is false, it means use driver memory range read from driver object
    BOOLEAN UseStoredDriverInfo;
    // offset to the driver module
    ULONG Offset;
    // unknown, has an impact on the reporting policy
    // if the flag is true, then normal means upload, abnormal means don't upload
    // maybe use to detect some kind of attack?
    BOOLEAN FlipReportPolicy;
    // compare size, up to 64 bytes
    ULONG CompareSize;
    // content of normal data, length depends on CompareSize
    BYTE Content[0];
};
struct UploadDxgkrnlInternalFunctionRangeCheck {
    // length = upload packet length - 1
    BYTE Pattern[0];
    // how far is the function address from the pattern matching address
    BYTE Offset;
}
struct UploadDxgkrnlInternalFunctionRangeCheck {
    // length = upload packet length - 1
    BYTE Pattern[0];
    // how far is the function address from the pattern matching address
    BYTE Offset;
}
 
struct PacketSelfIntegrityCheck {
    // 18 is self integrity check
    BYTE PacketType;
    // if it is true, it means use stored driver memory range
    // if it is false, it means use driver memory range read from driver object
    BOOLEAN UseStoredDriverInfo;
    // offset to the driver module
    ULONG Offset;
    // content of checked address, 64 bytes
    BYTE Content[64];
};
struct PacketSelfIntegrityCheck {
    // 18 is self integrity check
    BYTE PacketType;
    // if it is true, it means use stored driver memory range
    // if it is false, it means use driver memory range read from driver object
    BOOLEAN UseStoredDriverInfo;
    // offset to the driver module
    ULONG Offset;
    // content of checked address, 64 bytes
    BYTE Content[64];
};
 
 
struct PacketSyscallIntegrityCheck {
    // 9 is syscall integrity check
    BYTE PacketType;
    // each syscall function has an index
    BYTE FuncIndex;
    // -1: fine
    // 0: function pointer modification
    // 1: address out of module range
    // 2: after jump, address out of range
    // 3: int3 trap, may be under debugging
    BYTE ErrorType;
    // after useless jump instructions, the function body's address
    PVOID Address;
    // dump 64 bytes
    BYTE Content[64];
};
struct PacketSyscallIntegrityCheck {
    // 9 is syscall integrity check
    BYTE PacketType;
    // each syscall function has an index
    BYTE FuncIndex;
    // -1: fine
    // 0: function pointer modification
    // 1: address out of module range
    // 2: after jump, address out of range
    // 3: int3 trap, may be under debugging
    BYTE ErrorType;
    // after useless jump instructions, the function body's address
    PVOID Address;
    // dump 64 bytes
    BYTE Content[64];
};
 
 
struct PacketSystemThreadStartAddressCheck {
    // 1 is system thread start address check
    BYTE PacketType;
    // start address read from SYSTEM_PROCESS_INFORMATION structure
    PVOID StartAddress;
    // dump 64 bytes from start address
    BYTE Content[64];
    // thread running time
    // from thread creation to now
    LARGE_INTEGER RunningTime;
    // CountdonwId = SystemProcessInformation->NumberOfThreads - AbnormalThreadIndex - 1
    // counting thread indexes from back to front
    // making the ID generic
    USHORT CountdownId;
    // thread create time
    // between process creation and thread creation
    LARGE_INTEGER CreateTime;
};
struct PacketSystemThreadStartAddressCheck {
    // 1 is system thread start address check
    BYTE PacketType;
    // start address read from SYSTEM_PROCESS_INFORMATION structure
    PVOID StartAddress;
    // dump 64 bytes from start address
    BYTE Content[64];
    // thread running time
    // from thread creation to now
    LARGE_INTEGER RunningTime;
    // CountdonwId = SystemProcessInformation->NumberOfThreads - AbnormalThreadIndex - 1
    // counting thread indexes from back to front
    // making the ID generic
    USHORT CountdownId;
    // thread create time
    // between process creation and thread creation
    LARGE_INTEGER CreateTime;
};
 
struct PacketSystemThreadStartAddressCheck {
    // 14 is system thread stack check
    BYTE PacketType;
    // bad caller index in the RtlWalkFrameChain result
    BYTE CallerIndex;
    // bad caller's return address
    PVOID Address;
    // 64 bytes of caller's content
    BYTE Content[64];
    // notice: only 32 bits
    // which thread has the bad caller
    ULONG ThreadId;
    // image name length
    BYTE ImageNameLength;
    // image name buffer
    // length depends on the ImageNameLength
    BYTE ImageName[0];
    // low 32 bits of StartAddress, always upload
    ULONG LowStartAddress;
    // may be null if the StartAddress is invalid
    PVOID StartAddress;
    // may be null if the StartAddress is invalid
    HANDLE ProcessId;
    // thread running time
    // from thread creation to now
    LARGE_INTEGER RunningTime;
    // CountdonwId = SystemProcessInformation->NumberOfThreads - AbnormalThreadIndex - 1
    // counting thread indexes from back to front
    // making the ID generic
    USHORT CountdownId;
    // thread create time
    // between process creation and thread creation
    LARGE_INTEGER CreateTime;
    // track the E9 jumps after the return address up to 60 bytes,
    // record up to 10 addresses
    BYTE FollowAddressCount;
    // size depends on the FollowAddressCount
    PVOID FollowAddressArr[0];
};
struct PacketSystemThreadStartAddressCheck {
    // 14 is system thread stack check
    BYTE PacketType;
    // bad caller index in the RtlWalkFrameChain result
    BYTE CallerIndex;
    // bad caller's return address
    PVOID Address;
    // 64 bytes of caller's content
    BYTE Content[64];
    // notice: only 32 bits
    // which thread has the bad caller
    ULONG ThreadId;
    // image name length
    BYTE ImageNameLength;
    // image name buffer
    // length depends on the ImageNameLength
    BYTE ImageName[0];
    // low 32 bits of StartAddress, always upload
    ULONG LowStartAddress;
    // may be null if the StartAddress is invalid
    PVOID StartAddress;
    // may be null if the StartAddress is invalid
    HANDLE ProcessId;
    // thread running time
    // from thread creation to now
    LARGE_INTEGER RunningTime;
    // CountdonwId = SystemProcessInformation->NumberOfThreads - AbnormalThreadIndex - 1
    // counting thread indexes from back to front
    // making the ID generic
    USHORT CountdownId;
    // thread create time
    // between process creation and thread creation
    LARGE_INTEGER CreateTime;
    // track the E9 jumps after the return address up to 60 bytes,
    // record up to 10 addresses
    BYTE FollowAddressCount;
    // size depends on the FollowAddressCount
    PVOID FollowAddressArr[0];
};
 
struct PacketCallbackHookCheck {
    // 6 is callback hook check
    BYTE PacketType;
    // function type:
    // 0: process callback
    // 1: thread callback
    // 2: register callback
    // 3: image notify callback
    BYTE FunctionType;
    // hooked offset to the callback function begin
    BYTE HookOffset;
    // absolute hooked address
    PVOID HookAddress;
    // dump 16 bytes of callback head
    BTYE CallbackHeadContent[16];
    // where to jump
    PVOID JumpAddress;
    // content of address after the jump
    BYTE HookContent[64];
    // up to 260 bytes, no terminator
    CHAR ModulePath[0];
};
struct PacketCallbackHookCheck {
    // 6 is callback hook check
    BYTE PacketType;
    // function type:
    // 0: process callback
    // 1: thread callback
    // 2: register callback
    // 3: image notify callback
    BYTE FunctionType;
    // hooked offset to the callback function begin
    BYTE HookOffset;
    // absolute hooked address
    PVOID HookAddress;
    // dump 16 bytes of callback head
    BTYE CallbackHeadContent[16];
    // where to jump
    PVOID JumpAddress;
    // content of address after the jump
    BYTE HookContent[64];
    // up to 260 bytes, no terminator
    CHAR ModulePath[0];
};
 
struct PacketCallbackRangeCheck {
    // 7 is callback range check
    BYTE PacketType;
    // function type:
    // 0: process callback
    // 1: thread callback
    // 2: register callback
    // 3: image notify callback
    BYTE FunctionType;
    // address of the function
    PVOID Address;
    // 64 bytes content of the callback
    BYTE Content[64];
};
struct PacketCallbackRangeCheck {
    // 7 is callback range check
    BYTE PacketType;
    // function type:
    // 0: process callback
    // 1: thread callback
    // 2: register callback
    // 3: image notify callback
    BYTE FunctionType;
    // address of the function
    PVOID Address;
    // 64 bytes content of the callback
    BYTE Content[64];
};
 
struct PacketCallbackCheck {
    // 17 is callback check
    BYTE PacketType;
    // function type:
    // 0: process callback
    // 1: thread callback
    // 2: register callback
    // 3: image notify callback
    BYTE FunctionType;
    // address of the callback
    PVOID Address;
    // 64 bytes content of the callback
    BYTE Content[64];
    // module path if exists, no terminator
    CHAR ModulePath[0];
};
struct PacketCallbackCheck {
    // 17 is callback check
    BYTE PacketType;
    // function type:
    // 0: process callback
    // 1: thread callback
    // 2: register callback
    // 3: image notify callback
    BYTE FunctionType;
    // address of the callback
    PVOID Address;
    // 64 bytes content of the callback
    BYTE Content[64];
    // module path if exists, no terminator
    CHAR ModulePath[0];
};
 
 
 
struct PacketPhysicalMemoryReferenceCheck {
    // 8 is physical memory reference check
    BYTE PacketType;
    // fields in struct _CONTROL_AREA
    ULONG64 NumberOfSectionReferences;
    ULONG64 NumberOfPfnReferences;
    ULONG64 NumberOfMappedViews;
    ULONG64 NumberOfUserReferences;
};
struct PacketPhysicalMemoryReferenceCheck {
    // 8 is physical memory reference check
    BYTE PacketType;
    // fields in struct _CONTROL_AREA
    ULONG64 NumberOfSectionReferences;
    ULONG64 NumberOfPfnReferences;
    ULONG64 NumberOfMappedViews;
    ULONG64 NumberOfUserReferences;
};
 
 
struct PacketProcessThreadCallbackFunctionalityCheck {
    // 2 is process thread callback functionality check
    BYTE PacketType;
    // probably always true
    BOOLEAN Abnormal;
};
struct PacketProcessThreadCallbackFunctionalityCheck {
    // 2 is process thread callback functionality check
    BYTE PacketType;
    // probably always true
    BOOLEAN Abnormal;
};
 
 
struct PacketDispatchFunctionIntegrityCheck {
    // 0 is dispatch function integrity check
    BYTE PacketType;
    // driver name
    // length = PacketLength - OtherFieldsLength
    CHAR DriverName[0];
    // major number
    BYTE MajorNumber;
    // hook function address
    PVOID Address;
    // 64 bytes of hook function
    BYTE Content[64];
};
struct PacketDispatchFunctionIntegrityCheck {
    // 0 is dispatch function integrity check
    BYTE PacketType;
    // driver name
    // length = PacketLength - OtherFieldsLength
    CHAR DriverName[0];
    // major number
    BYTE MajorNumber;
    // hook function address
    PVOID Address;
    // 64 bytes of hook function
    BYTE Content[64];
};
 
 
struct PacketPsLookupThreadByThreadIdHookCheck {
    // 4 is PsLookupThreadByThreadId hook check
    BYTE PacketType;
    // PsLookupThreadByThreadId address
    PVOID FunctionAddress;
    // FF 25 (4 bytes offset)
    ULONG JumpOffset1;
    // address after the first jump
    PVOID HookFunction1;
    // whether there is another jump
    BOOLEAN TwoJump;
    union {
        // no another jump
        // dump 16 bytes of the first hook function
        BYTE Content1[16];
        // have another jump
        struct {
            // record the second hook function
            PVOID HookFunction2;
            // dump 16 bytes of the second hook function
            BYTE Content2[16];
        };
    };
};
struct PacketPsLookupThreadByThreadIdHookCheck {
    // 4 is PsLookupThreadByThreadId hook check
    BYTE PacketType;
    // PsLookupThreadByThreadId address
    PVOID FunctionAddress;
    // FF 25 (4 bytes offset)
    ULONG JumpOffset1;
    // address after the first jump
    PVOID HookFunction1;
    // whether there is another jump
    BOOLEAN TwoJump;
    union {
        // no another jump
        // dump 16 bytes of the first hook function
        BYTE Content1[16];

[注意]APP应用上架合规检测服务,协助应用顺利上架!

上传的附件:
收藏
免费 34
支持
分享
打赏 + 100.00雪花
打赏次数 1 雪花 + 100.00
 
赞赏  Editor   +100.00 2022/07/18 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (24)
雪    币: 1025
活跃值: (633)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
五体投地了
2022-7-5 09:19
0
雪    币: 1213
活跃值: (4031)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
3
2022-7-5 10:15
0
雪    币: 3785
活跃值: (3947)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
感谢分享!
2022-7-5 10:25
0
雪    币: 914
活跃值: (2553)
能力值: ( LV5,RANK:68 )
在线值:
发帖
回帖
粉丝
5
2022-7-5 10:32
0
雪    币: 29
活跃值: (1719)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
老哥牛逼啊,花了不少时间分析的吧,拜读一下
2022-7-5 10:49
0
雪    币: 1634
活跃值: (3517)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
看雪我只服鬼哥··········
2022-7-5 11:09
0
雪    币: 5190
活跃值: (2971)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
这是真干货啊
2022-7-5 11:14
0
雪    币: 43
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
分析得十分全面,不错,学习了
2022-7-5 11:17
0
雪    币: 4794
活跃值: (4494)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
666赶紧下载啊哈哈哈
2022-7-5 11:22
0
雪    币: 576
活跃值: (1163)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
11
很刑
2022-7-5 11:25
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
牛逼!
2022-7-5 19:27
0
雪    币: 138
活跃值: (461)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
666
2022-7-5 21:08
0
雪    币: 5270
活跃值: (3505)
能力值: ( LV7,RANK:117 )
在线值:
发帖
回帖
粉丝
14
xiaomajia 老哥牛逼啊,花了不少时间分析的吧,拜读一下
花了两周搞出来的
2022-7-5 23:05
0
雪    币: 4641
活跃值: (163910)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
666
2022-7-6 14:33
0
雪    币: 141
活跃值: (7521)
能力值: ( LV9,RANK:335 )
在线值:
发帖
回帖
粉丝
16
猫猫震惊
2022-7-6 16:07
0
雪    币: 724
活跃值: (291)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
很厉害
2022-7-6 17:23
0
雪    币: 5046
活跃值: (4808)
能力值: ( LV10,RANK:171 )
在线值:
发帖
回帖
粉丝
18
感谢分享!!!
2022-7-7 08:29
0
雪    币: 1290
活跃值: (2332)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
19
感谢分享!!!
2022-7-7 15:32
0
雪    币: 962
活跃值: (9971)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
20
TQL five head 投地
2022-7-7 15:42
0
雪    币: 42
活跃值: (193)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21

b64:aHR0cDovLzEwNi4xMi4xMjkuMTI2L2J1aWxkP3Byb2plY3Q9bG9hZGVyLmNvcmUmdmVyc2lvbj0=

最后于 2022-7-14 17:14 被loveqiang编辑 ,原因:
2022-7-14 17:13
0
雪    币: 2065
活跃值: (500)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
22
讲的够全,但是不是最新
2022-7-18 18:27
0
雪    币: 1
活跃值: (461)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
膜拜大佬
2022-7-26 22:10
0
雪    币: 206
活跃值: (2036)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
哥哥 检测Vt呢,如果躲避 BE EAC 检测Vt
2022-9-17 18:34
0
雪    币: 1935
活跃值: (4185)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
感谢分享
2022-9-21 17:12
0
游客
登录 | 注册 方可回帖
返回
//