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
];
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: