解析 IRtlFile

179 篇文章 0 订阅
86 篇文章 0 订阅

解析 IRtlFile

要使用对象,需要创建实例,即 NewInstance.Allocate(),大体有三步:
1、分配空间
2、构造对象
3、初始化

一、实例化
//----- (0000000180067820) ----------------------------------------------------
__int64 __fastcall Windows::Rtl::CRtlRefCountedObjectBase<
Windows::Rtl::SystemImplementation::CFile,
Windows::Rtl::IRtlFile,
Windows::Rtl::IRtlSystemObject,
Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface,
Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface>::CreateInstance<
Windows::Rtl::SystemImplementation::CreateFileSource,
Windows::Rtl::IRtlFile>(
struct Windows::Rtl::SystemImplementation::CreateFileSource *a1, 
Windows::Rtl::SystemImplementation::CFile **a2)
{

  v2 = a1;
  v3 = a2;
// 1、分配空间
  LODWORD(v4) = operator new(96i64);
// 2、构造对象
  if ( v4 )
    v5 = Windows::Rtl::SystemImplementation::CFile::CFile(v4);
  else
    v5 = 0i64
// 3、初始化     
  v6 = Windows::Rtl::SystemImplementation::CFile::Initialize(v5, v2);
  *v3 = v5;
  return 0i64;
}

二、构造对象,即 CFile::CFile
1、+0 为 Windows::Rtl::SystemImplementation::CFile::`vftable 地址
          Windows::Rtl::CRtlRefCountedObjectBase
2、+2 为 Windows::Rtl::SystemImplementation::CFile::`vftable 地址
          Windows::Rtl::SystemImplementation::CSystemObject
3、+1 为标志位,1
4、+3 4 5 6 8 9 10 11 清零
5、如果设置了全局变量 g_pTrackTypeDescription,进行记录。

//----- (0000000180067EE8) ----------------------------------------------------
Windows::Rtl::SystemImplementation::CFile *__fastcall Windows::Rtl::SystemImplementation::CFile::CFile(
Windows::Rtl::SystemImplementation::CFile *this)
{

  v1 = Windows::Rtl::g_pTrackTypeDescription;
  v2 = this;
// 这两种写法,有什么不一样?
// 如果一样,为什么要写两次;如果不一样,在同一个字段同写两次,后面的肯定会覆盖前面的。
  *(_QWORD *)this = Windows::Rtl::CRtlRefCountedObjectBase<
Windows::Rtl::SystemImplementation::CFile,
Windows::Rtl::IRtlFile,
Windows::Rtl::IRtlSystemObject,
Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface,
Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface>::`vftable';
  *(_QWORD *)this = Windows::Rtl::SystemImplementation::CFile::`vftable'{for `Windows::Rtl::CRtlRefCountedObjectBase<
Windows::Rtl::SystemImplementation::CFile,
Windows::Rtl::IRtlFile,
Windows::Rtl::IRtlSystemObject,
Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface,
Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface>'};

  *((_QWORD *)this + 2) = &Windows::Rtl::SystemImplementation::CSystemObject::`vftable';
  *((_QWORD *)this + 2) = &Windows::Rtl::SystemImplementation::CFile::`vftable'{for `Windows::Rtl::SystemImplementation::CSystemObject'};

  *((_DWORD *)this + 2) = 1;

  *((_QWORD *)this + 3) = 0i64;
  *((_QWORD *)this + 4) = 0i64;
  *((_QWORD *)this + 5) = 0i64;
  *((_QWORD *)this + 6) = 0i64;
  *((_QWORD *)v2 + 8) = 0i64;
  *((_QWORD *)v2 + 9) = 0i64;
  *((_QWORD *)v2 + 10) = 0i64;
  *((_QWORD *)v2 + 11) = 0i64;

// 根据全局变量 g_pTrackTypeDescription,记录对象构造过程。
  if ( v1 )
  {
    v3 = *(void (__fastcall **)(struct Windows::Rtl::CRtlTrackTypeDescription *, const char *, signed __int64))(*(_QWORD *)v1 + 16i64);
    _guard_check_icall_fptr(*(_QWORD *)(*(_QWORD *)v1 + 16i64));
    v3(v1, "CFile", 13i64);
  }
  result = v2;
  return result;
}



三、初始化

初始化时使用结构:Windows::Rtl::SystemImplementation::CreateFileSource

CFile 对象是继承自 CSystemObject,因此,初始化也分成两步,第一步先初始化 CFile,第二步再初始化 CSystemObject。
另外,前面在构造对象时,一部分别用了 this,另一部分使用了 v2,是否也是因为两个对象所造成的?


//----- (101098B8) --------------------------------------------------------
int __thiscall Windows::Rtl::SystemImplementation::CFile::Initialize(
  Windows::Rtl::SystemImplementation::CFile *this, 
  const struct Windows::Rtl::SystemImplementation::CreateFileSource *a2)
{
  Windows::Rtl::SystemImplementation::CFile *v2; // edi@1

  v2 = this;

// +8 是 IRtlFileSystemProvider 的地址
  v3 = Windows::Rtl::IRtlObject::CreateRequiredInterface<
         Windows::Rtl::SystemImplementation::IRtlFileSystemProvider>(
           *(void **)a2,
           (int *)this + 8);

// +3 是 IRtlObjectProvider 的地址
  v3 = Windows::Rtl::IRtlObject::CreateRequiredInterface<
        Windows::Rtl::SystemImplementation::IRtlObjectProvider>(
          *(void **)a2,
          (int *)v2 + 3);

// 把 CreateFileSource 中的 Name 复制到来
// +5 ==> +9
  v4 = RtlDuplicateLUnicodeString((int)a2 + 20, (int)v2 + 36);

  v3 = v4;
// 初始化 CSystemObject
// +2 是 CSystemObject 的地址
  v3 = Windows::Rtl::SystemImplementation::CSystemObject::Initialize(
         (Windows::Rtl::SystemImplementation::CFile *)((char *)v2 + 8),
         a2);
  if ( v3 < 0 )
    return v3;
  return 0;
}



int __thiscall Windows::WCP::Implementation::CAllocationPool::Allocate<
  Windows::Auto<Windows::Rtl::IRtlFile >>(
    Windows::WCP::Implementation::CAllocationPool *this, 
    int a2)
{
  _DWORD *v2; // eax@1

  *(_DWORD *)a2 = 0;
  v2 = Windows::WCP::Implementation::CAllocationPool::Allocate(
         this,
         4u,  
         Windows::Auto<Windows::Rtl::IRtlSystemIsolationLayer *>::~Auto<Windows::Rtl::IRtlSystemIsolationLayer *>);
  if ( v2 )
  {
    *v2 = 0;
    *(_DWORD *)a2 = v2;
  }
  return *(_DWORD *)a2;
}


void *__thiscall Windows::WCP::Implementation::CAllocationPool::Allocate(
  Windows::WCP::Implementation::CAllocationPool *this, 
  unsigned __int32 a2, void (__fastcall *a3)(void *))
{
  BUCL::CDequeBase *v3; // edi@1

  v3 = this;
  if ( a2 < 0xFFFFFFEF )
  {
    v5 = RtlAllocateHeap(*(HANDLE *)(__readfsdword(48) + 24), 0, a2 + 16);
// 前面的 IRtlFile,这里是 4,说明 IRtlFile 有 5 个字段
    v7 = v5;
    if ( v5 )
    {  // 把前 3 个字段清空
      v5[2] = 0;
      *v5 = 0;
      v5[1] = 0;
    }
    else
    {
      v7 = 0;
    }
    if ( v7 )
    {  // 这里也是清空的动作,v3 即 this,可以是不同的类型,比如 IRtlFile
      v7[3] = a3;
      BUCL::CDequeBase::InsertBefore(v3, v3, (struct BUCL::CDequeLinkage *)v7, v6);
      result = v7 + 4;  // 把返回结果增加 1 个字段
    }
    else
    {
      result = 0;
    }
  }
  else
  {
    result = 0;
  }
  return result;
}

创建接口
//----- (000000018006B3E0) ----------------------------------------------------
__int64 __fastcall Windows::Rtl::CRtlRefCountedObjectBase<
  Windows::Rtl::SystemImplementation::CFile,
  Windows::Rtl::IRtlFile,
  Windows::Rtl::IRtlSystemObject,
  Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface,
  Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface>::
CreateInterface(
  __int64 a1, 
  __int64 a2, 
  int (__fastcall ****a3)(_QWORD))
{

  v3 = 0;
  v12 = C00000E5;
  v4 = a3;
  v5 = a2;
  v6 = a1;
// a2 - IID
// 38218435_079f_49e9_bb3f_149cb22b88cd - 所有的接口都有这个 IID,可能是 System
// 144aa3c6_22ad_4666_91ee_064d0aa0179e - 这个接口和 CIniFile 有
// e42c887e_3ed6_4087_a172_d346ab63a13a - 有四个

// a3 - pObject
  if ( a3 )
  {
    Windows::AutoPointerBase<Windows::Cdf::Rtl::IRtlCdfUlongTableEnumerator *,Windows::Auto<Windows::Cdf::Rtl::IRtlCdfUlongTableEnumerator *>>::Close(a3);
    if ( *(_QWORD *)v5 == *(_QWORD *)&GUID_38218435_079f_49e9_bb3f_149cb22b88cd.Data1
      && *(_QWORD *)(v5 + 8) == *(_QWORD *)&GUID_38218435_079f_49e9_bb3f_149cb22b88cd.Data4[0]
      || *(_QWORD *)v5 == *(_QWORD *)&GUID_144aa3c6_22ad_4666_91ee_064d0aa0179e.Data1
      && *(_QWORD *)(v5 + 8) == *(_QWORD *)&GUID_144aa3c6_22ad_4666_91ee_064d0aa0179e.Data4[0]
      || *(_QWORD *)v5 == *(_QWORD *)&GUID_e42c887e_3ed6_4087_a172_d346ab63a13a.Data1
      && *(_QWORD *)(v5 + 8) == *(_QWORD *)&GUID_e42c887e_3ed6_4087_a172_d346ab63a13a.Data4[0] )
    {
      _InterlockedIncrement((volatile signed __int32 *)(v6 + 8));
      *v4 = v6;
    }
  }
// 出错
  return (unsigned int)v3;

// 32 位的更直观
  if ( a3 )
  {
    Windows::AutoPointerBase<Windows::Cdf::Rtl::IRtlCdfStringTableEnumerator *,Windows::Auto<Windows::Cdf::Rtl::IRtlCdfStringTableEnumerator *>>::Close(a3);
    if ( IsEqualGUID(a2, (int)&_GUID_38218435_079f_49e9_bb3f_149cb22b88cd)
      || IsEqualGUID(v6, (int)&_GUID_144aa3c6_22ad_4666_91ee_064d0aa0179e)
      || IsEqualGUID(v7, (int)&_GUID_e42c887e_3ed6_4087_a172_d346ab63a13a) )
    {
      _InterlockedIncrement((volatile signed __int32 *)v3 + 1);
      *(_DWORD *)a3 = v3;
    }
    result = 0;
  }

}


析构函数

//----- (0000000180068C40) ----------------------------------------------------
void *__fastcall Windows::Rtl::CRtlRefCountedObjectBase<
Windows::Rtl::SystemImplementation::CFile,
Windows::Rtl::IRtlFile,
Windows::Rtl::IRtlSystemObject,
Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface,
Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface>::
`vector deleting destructor'(void *a1, char a2)
{
  void *v2; // rbx@1

  v2 = a1;
  *(_QWORD *)a1 = Windows::Rtl::IRtlObject::`vftable';
  if ( a2 & 1 )
    operator delete(a1);
  return v2;
}

 
示例 GetName


//----- (10109770) --------------------------------------------------------
Windows::Rtl::SystemImplementation::CFile::GetName(unsigned long,class Windows::Auto<struct _LUNICODE_STRING> *)
int __userpurge Windows::Rtl::SystemImplementation::CFile::GetName@<eax>(
  struct Windows::WCP::Rtl::_RTL_TRACING_FACILITY *a1@<edx>, 
  int a2@<ecx>, 
  char *a3@<edi>, 
  char a4, // 0 - error; 2 - a2 copy to a5;
  int a5)
{

  v20 = 0;
  v5 = a2;
  v17 = C00000E5;
  v21 = 0;
  v19 = 1;
  if ( (unsigned __int8)Windows::WCP::Rtl::CEnterExitTracer<Windows::ErrorHandling::COM::CSimpleHResultCarryingFrame,6>::ShouldArm(
                          (Windows::WCP::Rtl *)&Facility_SIL,
                          a1) )
    Windows::WCP::Rtl::CEnterExitTracer<Windows::ErrorHandling::Rtl::CSimpleNtStatusCarryingFrame,7>::Arm(
      &v18,
      (int)&v17,
      v6,
      v5,
      (int)"Windows::Rtl::SystemImplementation::CFile::GetName",
      v6);
  if ( a4 & 2 )
  {
    v7 = RtlDuplicateLUnicodeString(v5 + 36, a5);
    if ( v7 >= 0 )
    {
      v8 = *(_DWORD *)a5;
      if ( *(_DWORD *)a5 > 2u && *(_WORD *)(*(_DWORD *)(a5 + 8) + 2 * (v8 >> 1) - 2) == 92 )
        *(_DWORD *)a5 = v8 - 2;
LABEL_8:
      v21 = 1;
      Windows::ErrorHandling::Rtl::CBaseFrame<Windows::ErrorHandling::Rtl::CVoidRaiseFrame>::SetCanonicalSuccess(&v17);
      v9 = v17;
      Windows::WCP::Rtl::CEnterExitTracer<Windows::ErrorHandling::Rtl::CSimpleNtStatusCarryingFrame,7>::~CEnterExitTracer<Windows::ErrorHandling::Rtl::CSimpleNtStatusCarryingFrame,7>(
        (int)&v18,
        (int)a3);
      return v9;
    }
  }
  else
  {
    if ( !(a4 & 1) )
      goto LABEL_8;
    v11 = v5 + 36;
    v12 = *(_DWORD *)v11;
    v11 += 4;
    v13 = *(_DWORD *)v11;
    v14 = *(_DWORD *)(v11 + 4);
    a3 = &v15;
    if ( v12 > 2 && *(_WORD *)(v14 + 2 * (v12 >> 1) - 2) == 92 )
      v12 -= 2;
    v7 = RtlSplitLUnicodeString(2, (int)&v12, 0, 0, 0x5Cu, (int)&v16, (int)&v15);
    if ( v7 >= 0 )
    {
      v7 = RtlDuplicateLUnicodeString((int)&v15, a5);
      if ( v7 >= 0 )
        goto LABEL_8;
    }
  }
  v17 = v7;
  Windows::WCP::Rtl::CEnterExitTracer<Windows::ErrorHandling::Rtl::CSimpleNtStatusCarryingFrame,7>::~CEnterExitTracer<Windows::ErrorHandling::Rtl::CSimpleNtStatusCarryingFrame,7>(
    (int)&v18,
    (int)a3);
  return v17;
}


示例

//----- (0000000180202DB0) ----------------------------------------------------
__int64 __fastcall Windows::Rtl::DeltaDecompressFile(
  Windows::Rtl *this, 
  struct Windows::Rtl::IRtlFile *a2, 
  __int64 a3, 
  struct Windows::Rtl::IRtlFile *a4, 
  struct Windows::Rtl::IRtlFile *a5)
{

// 总觉得这里的顺序不是太对,应该是两个输入文件,一个输出文件
// 即,a2 a3 是输入,a4 是输出
  v5 = a4;
  v6 = a3;
  v7 = a2;
  v8 = this;
  v9 = `anonymous namespace'::ValidateDeltaBufferCompressorInitialized();
  if ( v9 < 0 )
    return (unsigned int)v9;
  v15 = 0i64;
  *(_QWORD *)v14 = 0i64; // _LBLOB
  v16 = 0i64;
  v18 = 0i64;
  v17 = 0i64;  // _LBLOB
  v19 = 0i64;
  if ( v8
    && (v10 = *(int (__fastcall **)(Windows::Rtl *, _QWORD, unsigned __int32 *, _QWORD))(*(_QWORD *)v8 + 48i64),
        _guard_check_icall_fptr(*(_QWORD *)(*(_QWORD *)v8 + 48i64)),
        v9 = v10(v8, 0i64, v14, 0i64),
        v9 < 0)
// 读 a2 到 v14,
// +6 是读操作
    || (v11 = *(int (__fastcall **)(__int64, _QWORD, struct _LBLOB **, _QWORD))(*(_QWORD *)v6 + 48i64),
        _guard_check_icall_fptr(*(_QWORD *)(*(_QWORD *)v6 + 48i64)),
        v9 = v11(v6, 0i64, &v17, 0i64),
        v9 < 0) )
// 读 a3 到 v17
  {
LABEL_8:
    Windows::Rtl::AutoBlob<Windows::Auto<_LBLOB>>::Close((__int64)&v17);
    Windows::Rtl::AutoBlob<Windows::Auto<_LBLOB>>::Close((__int64)v14);
    return (unsigned int)v9;
  }
  v21 = 0i64;
  v20 = 0i64;
  v22 = 0i64;
  v9 = Windows::Rtl::DeltaDecompressBuffer(
         (Windows::Rtl *)3,
         (__int64)v14,
         v7,
         (__int64)&v17,
         (struct _LBLOB *)&v20,
         v18);
  if ( v9 < 0
    || (v12 = *(int (__fastcall **)(struct Windows::Rtl::IRtlFile *, _QWORD, __int64 *))(*(_QWORD *)v5 + 56i64),  
// a4,目标文件,这里是写文件,把 v20 写到 a4
// +7 是写操作
        _guard_check_icall_fptr(*(_QWORD *)(*(_QWORD *)v5 + 56i64)),
        v9 = v12(v5, 0i64, &v20),
        v9 < 0) )
  {
    Windows::Rtl::AutoDeltaBlob::Close((Windows::Rtl::AutoDeltaBlob *)&v20);
    goto LABEL_8;
  }
  Windows::Rtl::AutoDeltaBlob::Close((Windows::Rtl::AutoDeltaBlob *)&v20);
  Windows::Rtl::AutoBlob<Windows::Auto<_LBLOB>>::Close((__int64)&v17);
  Windows::Rtl::AutoBlob<Windows::Auto<_LBLOB>>::Close((__int64)v14);
  return 0i64;
}


示例  OpenFilesystemFile

//----- (0000000180086758) ----------------------------------------------------
__int64 __usercall Windows::Rtl::SystemImplementation::CSystemIsolationLayer::
OpenFilesystemFile@<rax>(
char a1@<dl>, 
__int64 a2@<rcx>, 
_DWORD *a3@<rbx>, 
unsigned int a4@<r8d>, 
const struct _LUNICODE_STRING *a5@<r9>)
{

  v5 = a3;
  v6 = a5;
  v7 = a1;
  v20 = a4;
  v8 = a2;
  v37 = C00000E5;
  if ( a3 )
    *a3 = 0;
  v25 = -1i64;
  v33 = 0i64;
  v34 = &v40;
  _mm_store_si128((__m128i *)&v23, 0i64);
  _mm_store_si128((__m128i *)&v24, 0i64);
  _mm_storeu_si128((__m128i *)&v38, 0i64);
  v32 = 48;
  _mm_storeu_si128((__m128i *)&v36, 0i64);
  v35 = 64;
  v9 = RtlInitUnicodeStringFromLUnicodeStringSafely(a5, &v40);
  if ( v9 < 0 )
    goto LABEL_24;
  v10 = *(_QWORD *)(v8 + 56);
  v11 = *(int (__fastcall **)(__int64, __int64 *))(*(_QWORD *)v10 + 24i64);
  _guard_check_icall_fptr(*(_QWORD *)(*(_QWORD *)v10 + 24i64));
  v9 = v11(v10, &v21);
  if ( v9 < 0 )
    goto LABEL_24;
  v12 = 0;
  if ( v7 & 1 )
    v12 = 2;
  if ( v7 & 2 )
    v12 |= 4u;
  if ( v7 & 8 )
    v12 |= 0x80u;
  if ( v7 & 0x10 )
    v12 |= 0x200u;
  if ( v7 & 0x20 )
    v12 |= 0x400u;
  v13 = v7 & 4;
  if ( v13 && vars30 & 2 )
  {
    Windows::ErrorHandling::Rtl::CBaseFrame<Windows::ErrorHandling::Rtl::CVoidRaiseFrame>::SetInvalidParameter(&v37);
    Windows::Rtl::SystemImplementation::CSilHandle::~CSilHandle((Windows::Rtl::SystemImplementation::CSilHandle *)&v38);
    v30 = 622;
    v28 = "base\\wcp\\sil\\systemisolationlayer.cpp";
    v29 = "Windows::Rtl::SystemImplementation::CSystemIsolationLayer::OpenFilesystemFile";
    v31 = "(ShareAccess & 0x00000002) == 0";
    Windows::ErrorHandling::Rtl::CBaseFrame<Windows::ErrorHandling::Rtl::CVoidRaiseFrame>::ReportErrorOrigination(
      &v37,
      (__int64)&v28);
    return v37;
  }
  v14 = *(_QWORD *)(v8 + 32);
  v15 = *(int (__fastcall **)(__int64, _QWORD, __int128 *, _QWORD))(*(_QWORD *)v14 + 72i64);
  _guard_check_icall_fptr(*(_QWORD *)(*(_QWORD *)v14 + 72i64));
  *(_QWORD *)&v23 = &v39;
  v22 = v21;
  LODWORD(v21) = 0;
  v9 = v15(v14, (unsigned int)v12, &v38, v20);
  if ( v9 < 0 )
  {
LABEL_24:
    Windows::Rtl::SystemImplementation::CSilHandle::~CSilHandle((Windows::Rtl::SystemImplementation::CSilHandle *)&v38);
    return (unsigned int)v9;
  }
  if ( v39 == 1 )
  {
    v17 = *((_QWORD *)v6 + 2);
    v25 = *((_QWORD *)&v38 + 1);
    *(_QWORD *)&v23 = *(_QWORD *)(v8 + 32);
    *((_QWORD *)&v23 + 1) = *(_QWORD *)(v8 + 40);
    *(_QWORD *)&v24 = *(_QWORD *)(v8 + 48);
    *((_QWORD *)&v24 + 1) = *(_QWORD *)(v8 + 56);
    v27 = v17;
    v26 = *(_OWORD *)v6;
    if ( v13 )
      v18 = Windows::Rtl::CRtlOneShotTypeDescriptionInit<Windows::Rtl::SystemImplementation::CIniFile>::CreateInstance<Windows::Rtl::SystemImplementation::CIniFile_IRtlIniFileTearoff,Windows::Rtl::SystemImplementation::CreateFileSource,Windows::Rtl::IRtlFile>(
              v16,
              (struct Windows::Rtl::OneShotTypeDescriptionRecord *)&v23,
              0i64);
    else
      v18 = Windows::Rtl::CRtlRefCountedObjectBase<Windows::Rtl::SystemImplementation::CFile,Windows::Rtl::IRtlFile,Windows::Rtl::IRtlSystemObject,Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface,Windows::Rtl::Detail::CRtlRefCountedObjectBaseNoInterface>::CreateInstance<Windows::Rtl::SystemImplementation::CreateFileSource,Windows::Rtl::IRtlFile>(
              (struct Windows::Rtl::SystemImplementation::CreateFileSource *)&v23,
              0i64);
    v9 = v18;
    if ( v18 < 0 )
      goto LABEL_24;
    if ( v5 )
      *v5 = 1;
  }
  else if ( v5 )
  {
    switch ( v39 )
    {
      case 3:
        *v5 = 2;
        break;
      case 4:
        *v5 = 3;
        break;
      case 9:
        *v5 = 4;
        break;
      case 11:
        *v5 = 5;
        break;
      case 12:
        *v5 = 6;
        break;
    }
  }
  Windows::Rtl::SystemImplementation::CSilHandle::~CSilHandle((Windows::Rtl::SystemImplementation::CSilHandle *)&v38);
  return 0i64;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值