欢迎进入Allbet官网。Allbet官网开放Allbet登录网址、Allbet开户、Allbet代理开户、Allbet电脑客户端、Allbet手机版下载等业务。

首页科技正文

电银付(dianyinzhifu.com):剖析Windows Defender驱动程序:WdFilter(Part 4)

admin2021-03-19213系统安全

剖析Windows Defender驱动程序:WdFilter(Part 1)

剖析Windows Defender驱动程序:WdFilter(Part 2)

剖析Windows Defender驱动程序:WdFilter(Part 3)

在前两篇文章中,我们已经先容了WdFilter若何通过ImageLoad回调例程处置内存中的映像加载。另外我们还先容了若何在两个差别的线程建立回调例程中检查新线程,以及若何将新闻同步和异步发送到MsMpEng。现在,我们将重点关注以下内容:

1.历程和桌面处置操作回调;

2.驱动程序信息和验证

历程和桌面处置回调

首先,若何完成工具回调的初始化。该历程在MpObInitialize内部启动,此函数将动态获取两个函数的地址:

1.ObRegisterCallbacks(指针保存在MpData-> pObRegisterCallbacks中);

2.ObUnRegisterCallbacks(指针保存在MpData-> pObUnRegisterCallbacks中);

若是两个函数指针都被检索到,它将继续挪用MpObAddCallback。 MpObAddCallback的主要事情是现实注册回调并在out参数中返回注册句柄,然后将其保存在MpData-> ObRegistrationHandle中。

为了注册工具回调,必须向ObRegisterCallbacks提供OB_CALLBACK_REGISTRATION结构。除其他事项外,此结构还包罗一个OB_OPERATION_REGISTRATION数组,它将以以下这种方式初始化:

OB_CALLBACK_REGISTRATION    ObCbRegistration = {}     
OB_OPERATION_REGISTRATION   OperationRegistration[2] = {}
 
OperationRegistration[0].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
OperationRegistration[0].ObjectType = PsProcessType;
OperationRegistration[0].PreOperation = MpObPreOperationCallback;
 
if (MpData->OsVersionMask & OsVersionWin10) {
    OperationRegistration[0].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
    OperationRegistration[0].ObjectType = ExDesktopObjectType;
    OperationRegistration[0].PreOperation = MpObPreOperationCallback;
    ObCbRegistration.OperationRegistrationCount = 2;
} else {
    ObCbRegistration.OperationRegistrationCount = 1;
}
 
ObCbRegistration.OperationRegistration = OperationRegistration;

在前面的伪代码中,我们可以看到若何将两个条目(在Windows 10中)添加到数组中,这两个操作都注册相同的PreOperation而没有PostOperation,也都注册以处置建立和复制。现在,我们将专注于PreOperation函数MpObPreOperationCallback。

要领会更多关于所有这些结构和其他内容,我强烈推荐你阅读这篇文章。

MpObPreOperationCallback

正如我们在此回调之前所看到的,PsProcessType和ExDesktopObjectType都注册了回调,因此很明显,例程需要一种方式来区分哪个工具触发了回调。由于这是PreOperation例程,因此必须将其原型界说为POB_PRE_OPERATION_CALLBACK,这意味着它的第二个参数将是OB_PRE_OPERATION_INFORMATION结构,该结构包罗具有ObjectType的字段,该值可用于领会触发回调的工具的类型。因此,此函数的唯一事情就是将OperationInformation重定向到每种工具类型的准确函数。

MpObHandleOpenDesktopCallback

这是处置有关桌面工具的操作的函数,主要是充当通知员的作用。它将吸收OB_PRE_OPERATION_INFORMATION作为参数,它要做的第一件事是从当前历程获取ProcessCtx。此时,ProcessCtx->ProcessRules将被检查将被检查,以查看是否设置了我建立的DoNotNotifyDesktopHandlesOp(0x8)值。若是未设置该值,则将从OB_PRE_OPERATION_INFORMATION中检索目的工具。使用此工具,代码将继续在函数ObQueryNameString中获取其名称。然后,凭据工具名称的长度分配AsyncMessageData结构,并响应地填充它。union TypeOfMessage将包罗以下结构:

typedef struct _ObDesktopHandleMessage
{
  AuxPidCreationTime Process;
  INT ThreadId;
  INT SessionId;
  BYTE Operation;
  BYTE KernelHandleFlag;
  INT DesiredAccess; // https://docs.microsoft.com/en-us/windows/win32/winstation/desktop-security-and-access-rights
  WCHAR *ObjectName;
} ObDesktopHandleMessage, *PObDesktopHandleMessage;

填满整个AsyncMessageData后,将使用MpAsyncSendNotification发送通知。这差不多就是关于这个回调的所有内容了,正如我在这一节更先说的它主要作为一个通知工具。

电银付(dianyinzhifu.com):剖析Windows Defender驱动程序:WdFilter(Part 4) 系统安全 第1张

MpObHandleOpenProcessCallback

这个函数将处置关于历程句柄的操作,为了让这个回调启动它的操作,万万不要设置符号MpData->UnsetObAndRegCallback,这样当前历程就不会是MsMpEng,而且句柄不能是KernelHandle。若是这些条件都获得知足,则代码将继续为当前历程和目的历程获取ProcessCtx,当前历程是试图获取目的历程句柄的历程。从现在更先,应用差别的规则这就要取决于历程所请求的接见类型。若是该历程正在请求以下任何一种接见:

1.PROCESS_VM_WRITE:写入目的历程的地址空间;

2.PROCESS_VM_OPERATION:修改目的历程的地址空间;

3.PROCESS_CREATE_THREAD:在目的历程的上下文中建立一个新线程;

然后,回调将继续检查是否允许将代码从当前历程注入目的历程,为此,它使用了两个函数。BOOLEAN MpAllowCodeInjection(PProcessCtx CurrentProcess,PProcessCtx TargetProcess)此函数将检查CurrentProcess的ProcessFlags是否与以下任何值匹配:

ExcludedProcess - 0x1
MpServiceSidProcess - 0x10
FriendlyProcess - 0x20
SvchostProcess - 0x100

若是没有标志匹配,则它将从TargetProcess获得值ProcessCtx-> CodeInjectionTargetMask,并从CurrentProcess获得值ProcessCtx-> CodeInjectionRequestMask,它将继续处置这两个值,以确定是否允许注入。下面的伪代码展示了这个函数的行为。

processFlags = CurrentProcess->ProcessFlags;
 
if (processFlags & ExcludedProcess || processFlags & MpServiceSidProcess ||
    processFlags & FriendlyProcess || processFlags & SvchostProcess) {
      return TRUE;
}
targetMask = TargetProcess->CodeInjectionTargetMask;
requestMask = CurrentProcess->CodeInjectionRequestMask;
 
if (!targetMask || requestMask == -1 || targetMask & requestMask) {
  return TRUE
} 
MpLogPrintfW(L"[Mini-filter] Injection into process %u from process %u is BLOCKED.",
    TargetProcess->ProcessId,
    CurrentProcess->ProcessId);
return FALSE;

若是此函数返回FALSE,则将修改DesiredAccess,以删除触发此检查的权限。

若是我们运行的是Windows 10 build 16000或更高版本,则将基于Windows Defender主机入侵和防御系统(HIPS)规则举行另一项检查。

老实说,我对Windows Defender HIPS知之甚少,而且在互联网上找不到关于它的太多信息。因此,我不知道是否有添加或检查系统上正在运行的HIPS规则的方式。

在MpAllowAccessBasedOnHipsRule中检查用于句柄建立的HIPS规则,除此之外,此函数将接受以下参数:

HipsRule - @r8
ProcessRule - @r9
TargetRule - @rsp+20

而且该函数将基本上检查作为参数提供的规则是否与响应的ProcessRules相对照,对HipsRule凭据当前的历程规则举行相对照,现实行为可以在以下伪代码中看到:

allowedFlag = FALSE;
allowedOrBlocked = L"BLOCKED";
targetRules = TargetProcess->ProcessRules; 
processRules = CurrentProcess->ProcessRules;
 
if (!(processRules & HipsRule) || targetRules & TargetHipsRule || processRules & ProcessRule) {
      allowedOrBlocked = L"ALLOWED";
      status = TRUE;
}
 
MpLogPrintfW(
    L"[Mini-filter] Applying HipsRule 0x%x: Access from process %u to target %u is '%ls'",
    HipsRule,
    CurrentProcess->ProcessId,
    TargetProcess->ProcessId,
    allowedOrBlocked);
 
return allowedFlag;

对于PROCESS_VM_WRITE,PROCESS_VM_OPERATION和PROCESS_CREATE_THREAD,将以下值作为参数传递给此函数:

HipsRule => AllowCodeInjectionHIPSRule-0x8000
ProcessRule => AllowedToInjectCode-0x10000
TargetRule => AllowIncomingCodeInjection-0x80000

再次进入回调,另有另一组接见权限将触发检查,可以在以下列表中看到它们:

SYNCHRONIZE:使用wait函数来守候历程终止;

PROCESS_TERMINATE:使用TerminateProcess终止历程;

PROCESS_SUSPEND_RESUME:暂停或恢复历程;

PROCESS_QUERY_LIMITED_INFORMATION:检索有关流程的某些信息;

在本文示例中,回调将检查当前历程的值ProcessCtx->ProcessProtection,以检查类型是否为PsProtectedTypeNone,署名者是否小于PsProtectedSignerAntimalware。与前一个例子一样,在这个例子中也有HIPS规则,在这个例子中,传递给函数MpAllowAccessBasedOnHipsRule的参数如下:

,

电银付

电银付(dianyinzhifu.com)是官方网上推广平台。在线自动销售电银付激活码、电银付POS机。提供电银付安装教程、电银付使用教程、电银付APP使用教程、电银付APP安装教程、电银付APP下载等技术支持。面对全国推广电银付加盟、电银付大盟主、电银付小盟主业务。

,
HipsRule => QuerySuspendResumeHIPSRule-0x800000
ProcessRule => AllowedToQuerySuspendResume-0x1000000
TargetRule => AllowQuerySuspendResume-0x2000000

若是这些检查失败,那么DesiredAccess将响应地举行调整。

最后,此回调将继续发送异步通知。该通知将在MpObSendOpenProcessBMNotification内部建立并发送,我们已经在上面看到了几个类似的函数,它将建立一个AsyncMessageData,其中TypeOfMessage将变为ObProcessHandleMessage,该结构具有以下界说:

typedef struct _ObProcessHandleMessage
{
  AuxPidCreationTime Process;
  AuxPidCreationTime TargetProcess;
  INT SessionId;
  INT FinalDesiredAccess;
  INT FileNameLen;
  INT FileNameOffset;
  INT TargeFileNameLen;
  INT TargeFileNameOffset;
  BYTE CodeInjectionHIPS[16];           // Needs investigation
  BYTE QuerySuspendResumeHIPSRule[16];  // Needs investigation
  INT Unk;
  MP_OB_NOTIFICATION_REASON NotificationReason;
} ObProcessHandleMessage, * PObProcessHandleMessage;
 
typedef enum MP_OB_NOTIFICATION_REASON
{
  // Default notification set to 0x0
  DesiredAccessModified = 0x1,
  AllowCodeInjectionHIPSTrigger = 0x2,
  QuerySuspendResumeHIPSTrigger = 0x4,
  SameDesiredAccesAndAllowCodeInjectionHIPSTrigger = 0x8,
  SameDesiredAccessAndQuerySuspendResumeHIPSTrigger = 0x10,
}

一旦这个结构被分配和填充,通知将添加到AsyncNotificationsList中,以供事情线程处置。

电银付(dianyinzhifu.com):剖析Windows Defender驱动程序:WdFilter(Part 4) 系统安全 第2张

回到主函数中,在发送通知之后,在完成该函数之前需要举行最后一项检查,若是目的历程是MpServiceSidProcess,而当前历程既不是MpServiceSidProcess也不是FriendlyProcess,,然后下面的接见权限将被删除。

if (!(TargetProcess->ProcessFlags & MpServiceSidProcess)) {
 
  if (!(CurrentProcess->ProcessFlags & MpServiceSidProcess) && 
      !(CurrentProcess->ProcessFlags & FriendlyProcess)) {
 
    ObOpParameters->CreateHandleInformation.DesiredAccess &= 
        ~(PROCESS_VM_WRITE|PROCESS_VM_OPERATION|PROCESS_CREATE_THREAD|PROCESS_TERMINATE);
  }
 
  goto ReleaseProcessCtx;
}

有关流程安全性和接见权限的更多信息,请点此参阅。

驱动程序信息和验证

此历程中涉及的第一个函数是MpInitializeDriverInfo,它是在DriverEntry内部举行挪用的。我们已经在第一篇文章中提到了此函数,现在我们将看到有关此函数以及与驱动程序信息和验证相关的其他函数的更多详细信息。进入现实函数,主要是它将分配以下结构:

typedef struct _MP_DRIVERS_INFO
{
  INT Status;
  BYTE Reserved[8];
  INT ElamSignaturesMajorVer;
  INT ElamSignatureMinorVer;
  LIST_ENTRY LoadedDriversList;
  PSLIST_ENTRY ElamRegistryEntries;
  LIST_ENTRY BootProcessList;
  PCALLBACK_OBJECT CallbackObject;
  PVOID BootDriverCallbackRegistration;
  FAST_MUTEX DriversInfoFastMutex;
  INT TotalDriverEntriesLenght;
  NTSTATUS (__fastcall *pSeRegisterImageVerificationCallback)(SE_IMAGE_TYPE, SE_IMAGE_VERIFICATION_CALLBACK_TYPE, PSE_IMAGE_VERIFICATION_CALLBACK_FUNCTION, PVOID, SE_IMAGE_VERIFICATION_CALLBACK_TOKEN, PVOID *);
  VOID (__fastcall *pSeUnregisterImageVerificationCallback)(PVOID);
  PVOID ImageVerificationCbHandle;
  INT RuntimeDriversCount;
  INT RuntimeDriversArrayLenght;
  PVOID RuntimeDriversArray;
  LIST_ENTRY RuntimeDriversList;
  INT64 field_C8;
} MP_DRIVERS_INFO, *PMP_DRIVERS_INFO

在初始化结构的某些字段之后,该函数将获得回调工具\ Callback \ WdEbNotificationCallback的句柄,然后它将继续将MpBootDriverCallback注册为回调函数,将注册句柄保存在结构成员BootDriverCallbackRegistration中。

MpAddDriverInfo和MpAddBootProcessEntry

在启动驱动程序回调之前,我想注释一下列表项LoadedDriversList和BootProcessList是若何被填充的。在LoadedDriversList中,数据将链接到在Image-Load回调中执行的MpAddDriverInfo中,而BootProcessList则被填充在MpAddBootProcessEntry中,MpAddBootProcessEntry是在Process-Creation回调中挪用的。

正如我适才所说,只要加载的映像是SystemModeImage,就将从Image-Load回调中挪用MpAddDriverInfo。该函数将吸收IMAGE_INFO和完整映像名称作为参数,而且主要它将为结构MP_DRIVER_INFO分配内存

typedef struct _MP_DRIVER_INFO
{
  LIST_ENTRY DriverInfoList;
  UNICODE_STRING ImageName;
  UNICODE_STRING DriverRegistryPath;
  UNICODE_STRING CertPublisher;
  UNICODE_STRING CertIssuer;
  PVOID ImageHash;
  INT ImageHashAlgorithm;
  INT ImageHashLength;
  PVOID CertThumbprint;
  INT ThumbprintHashAlgorithm;
  INT CertificateThumbprintLength;
  PVOID ImageBase;
  INT64 ImageSize;
  INT ImageFlags;
  INT DriverClassification;
  INT ModuleEntryEnd;
} MP_DRIVER_INFO, *PMP_DRIVER_INFO;

它将填充ImageSize、ImageBase和ImageName,然后将这个新条目链接到MP_DRIVERS_INFO->LoadedDriversList。

电银付(dianyinzhifu.com):剖析Windows Defender驱动程序:WdFilter(Part 4) 系统安全 第3张

对于MpAddBootProcessEntry而言,此函数是在历程建立历程中挪用的,,它执行前50个加载的历程(Counter保留在全局变量BootProcessCounter中)。函数原型如下所示:

VOID
MpAddBootProcessEntry(
  HANDLE  ProcessId,
  HANDLE  ParentProcessId,
  PCUNICODE_STRING  ImageFileName,
  PCUNICODE_STRING  CmdLine
)

同样,如前所述,该函数的主要目的是分配和初始化该结构,在本文的示例中,该结构为MP_BOOT_PROCESS,其界说如下:

typedef struct _MP_BOOT_PROCESS
{
  LIST_ENTRY BootProcessList;
  HANDLE ProcessId;
  HANDLE ParentProcessId;
  UNICODE_STRING ImageFileName;
  UNICODE_STRING CommandLine;
  INT SomeFlag;   // Set to 3
} MP_BOOT_PROCESS, *PMP_BOOT_PROCESS;

初始化条目后,将其链接到列表MP_DRIVERS_INFO->BootProcessList中。

电银付(dianyinzhifu.com):剖析Windows Defender驱动程序:WdFilter(Part 4) 系统安全 第4张

MpBootDriverCallback

既然知道了若何填充这两个列表项,我们将更先研究初始化时代注册的回调函数。正如我在有关Windows Defender ELAM的文章中已经注释的那样,当在ELAM驱动程序的启动驱动程序回调函数中将BDCB_CALLBACK_TYPE设置为BdCbStatusUpdate而且映像信息的BDCB_CLASSIFICATION设置为BdCbClassificationKnownBadImage时,将通知该回调。若是知足了这些条件,则将以Argument1作为指向主要WdBoot结构MP_EB_GLOBALS的指针并将Argument2设置为常数0x28的指针来通知回调。

因此,进入MpBootDriverCallback,首先要做的是对Argument1和Argument2举行完整性检查。对于Argument2,它将检查是否即是0x28,而对于Argument1,它将检查结构的Magic是否为0xEB01。若是两项检查都准确,则它将继续遍历WdBoot建立的驱动程序列表,而且对于每个驱动程序,它将挪用MpCopyDriverEntry,它会将驱动程序条目数据复制到MP_DRIVER_INFO结构中,然后将其链接到MP_DRIVERS_INFO-> LoadedDriversList。

接下来,我会形貌一个我无法触发的路径/用例,但其中会有一些预测的身分,对此我表示歉意。之所以会这样,我以为这与ELAM驱动程序可以使用注册表回调或指导驱动程序回调来监控和验证设置数据有关,至少在我的研究中,我只看到了第二种情形。更多信息,请点此。

复制完每个条目后,将遍历SLIST_ENTRY ElamRegistryEntries,对于每个条目,它将挪用MpCopyElamRegistryEntry。此函数基本上会将条目复制到名为MP_ELAM_REGISTRY_ENTRY的结构中,并将此结构插入到单链接列表MP_DRIVERS_INFO-> ElamRegistryEntries中,这可能与ELAM注册表设置单元条目有关,MP_ELAM_REGISTRY_ENTRY sizeof为0x40,其中包罗两个UNICODE_STRINGS,但我无法提供更多有关此的信息。

最后,将另外两个值从MP_EB_GLOBALS复制到MP_DRIVERS_INFO。这些值为ElamSignaturesMajorVer和ElamSignatureMinorVer。以上就是这个函数要做的所有事情,总而言之,它主要将来自MP_EB_GLOBALS的信息(即由ELAM驱动程序获得的信息)复制到MP_DRIVERS_INFO结构中。

MpSetImageVerificationCallback

这是在初始化时代执行的最后一个函数,此函数的目的主要是注册一个映像验证回调,为此,它将动态检索两个函数指针:

SeRegisterImageVerificationCallback
SeUnregisterImageVerificationCallback

这两个函数都驻留在内核中,而且它们基本上根据其名称举行操作。 SeRegisterImageVerificationCallback有一些检查,可以在以下伪代码上看到:

NTSTATUS 
SeRegisterImageVerificationCallback(
  SE_IMAGE_TYPE ImageType, 
  SE_IMAGE_VERIFICATION_CALLBACK_TYPE CallbackType, 
  PSE_IMAGE_VERIFICATION_CALLBACK_FUNCTION CallbackFunction, 
  PVOID CallbackContext, 
  SE_IMAGE_VERIFICATION_CALLBACK_TOKEN CallbackToken, 
  PVOID * RegistrationHandle
)
{
  if (ImageType != SeImageTypeDriver || CallbackType || CallbackToken) {
    // CallbackType should be SeImageVerificationCallbackInformational which is 0
    return STATUS_INVALID_PARAMETER;
  }
  
  PVOID registrationHandle = 
        ExRegisterCallback(ExCbSeImageVerificationDriverInfo, 
                          CallbackFunction, 
                          CallbackContext);
 
  if (registrationHandle) {
    *RegistrationHandle = registrationHandle;
  }
}

返回MpSetImageVerificationCallback,除了将函数MpImageVerificationCallback注册为映像验证回调例程外,它还将分配巨细为0x800的池,这样RuntimeDriversArray将驻留在该池中。

MpImageVerificationCallback

这个回调将从内核内的SepImageVerificationCallbackWorker中获得通知,执行此回调时的挪用客栈如下所示:

电银付(dianyinzhifu.com):剖析Windows Defender驱动程序:WdFilter(Part 4) 系统安全 第5张

通知回调后,首先要做的就是挪用MpAllocateDriverInfoEx来分配和初始化一个MP_DRIVER_INFO_EX。

typedef struct _MP_DRIVER_INFO_EX
{
  USHORT Magic;   // Set to 0xDA18
  USHORT Size;    // Sizeof 0xB0
  _QWORD WdFilterFlag;
  PVOID SameIndexList;
  _QWORD IndexHash;
  MP_DRIVER_INFO DriverInfo;
} MP_DRIVER_INFO_EX, *PMP_DRIVER_INFO_EX;

若是你还记得我写的有关WdBoot的内容,那这就是我在那篇文章中命名为MODULE_ENTRY的结构。同样,该结构似乎是MP_DRIVER_INFO的扩展版本,这让人想起IMAGE_INFO_EX和IMAGE_INFO,不外在本文的示例中可不是一个指针,而是包罗的整个结构。

现在,代码的作用将与我在关于WdBoot的文章中所注释的作用基本相同。将使用相同算法盘算IndexHash:

WCHAR  upper;
 _QWORD IndexHash =  0x4CB2F;
 while(*DriverInfo.ImageName.Buffer) {
     upper = RtlUpcaseUnicodeChar(*DriverInfo.ImageName.Buffer);
     IndexHash = HIBYTE(upper) + 0x25 * (upper + 0x25 * IndexHash);
     DriverInfo.ImageName.Buffer++;
 }

然后使用这个IndexHash,使用以下算法在RuntimeDriversArray中获得一个索引:

DWROD size = (MpDriversInfo.RuntimeDriversArray >> 5) - 1;
_QWORD tmp = IndexHash & (-1 << (MpDriversInfo.RuntimeDriversArray & 0x1F))
_QWORD idx = (0x25 * (BYTE6(tmp) + 0x25 * (BYTE5(tmp) + 
              0x25 * (BYTE4(tmp) + 0x25 * (BYTE3(tmp) + 
              0x25 * (BYTE2(tmp) + 0x25 * (BYTE1(tmp) + 
              0x25 * (BYTE(tmp) + 0xB15DCB))))))) + HIBYTE(tmp)) & size;

详细历程,请参阅WdBoot这篇文章,以更好地领会所有这些疯狂行为的执行历程。

最后,驱动程序将链接到MpDriversInfo.RuntimeDriversList。

电银付(dianyinzhifu.com):剖析Windows Defender驱动程序:WdFilter(Part 4) 系统安全 第6张

我们所看到的有关驱动程序信息的所有内容都将在一个函数中发挥作用,该作用将在另一篇名为MpQueryLoadedDrivers的文章中看到。这个函数可以由MsMpEng触发,以获得MP_DRIVERS_INFO数据的副本。

本文翻译自:https://n4r1b.netlify.com/posts/2020/03/dissecting-the-windows-defender-driver-wdfilter-part-3/如若转载,请注明原文地址

网友评论

5条评论
  • 2021-01-01 00:18:35

    电银付官网(dianyinzhifu.com)是官方网上推广平台。在线自动销售电银付激活码、电银付POS机。提供电银付安装教程、电银付使用教程、电银付APP使用教程、电银付APP安装教程、电银付APP下载等技术支持。面对全国推广电银付加盟、电银付大盟主、电银付小盟主业务。贼精彩,想看下一节

  • 2021-01-03 00:02:57

    而福建队这边王哲林上半场竞赛显示异常的拼命,6投4中砍下10分2篮板1抢断2盖帽,在防守端完全是拼尽了全力。徐铭智今天是他们的一大惊喜,获得8分2篮板2助攻,陈林坚粉丝大军助威

  • 2021-01-22 00:11:52

    欢迎进入allbet欧博官网(www.ALLbetgame.us)。allbet欧博官网开放ALLBET欧博真人客户端、Allbet代理网页版、Allbet会员网页版、Allbet会员注册、Allbet代理开户、Allbet电脑客户端下载、Allbet手机版下载等业务。近日最爱

  • 2021-03-19 00:07:18

    皇冠新现金网www.huangguan.us是一个提供皇冠代理APP下载、皇冠会员APP下载、皇冠体育最新登录线路、新2皇冠网址的的体育平台。新皇冠体育官网是多年来值得广大客户信赖的平台,我们期待您的到来!简直精彩

最新评论