职业IT人-IT人生活圈

 找回密码
 成为会员
搜索
查看: 1375|回复: 2

获取系统特征码的方法整理

[复制链接]
zlyuanna 发表于 2007-4-26 20:02 | 显示全部楼层 |阅读模式
BYTE szSystemInfo[4096]; // 在程序执行完毕后,此处存储取得的系统特征码
UINT uSystemInfoLen = 0; // 在程序执行完毕后,此处存储取得的系统特征码的长度

// 网卡 MAC 地址,注意: MAC 地址是可以在注册表中修改的
CODE:
{
  UINT uErrorCode = 0;
  IP_ADAPTER_INFO iai;
  ULONG uSize = 0;
  DWORD dwResult = GetAdaptersInfo( &iai, &uSize );
  if( dwResult == ERROR_BUFFER_OVERFLOW )
  {
    IP_ADAPTER_INFO* piai = ( IP_ADAPTER_INFO* )HeapAlloc( GetProcessHeap( ), 0, uSize );
    if( piai != NULL )
    {
     dwResult = GetAdaptersInfo( piai, &uSize );
     if( ERROR_SUCCESS == dwResult )
     {
      IP_ADAPTER_INFO* piai2 = piai;
      while( piai2 != NULL && ( uSystemInfoLen + piai2->AddressLength ) < 4096U )
      {
        CopyMemory( szSystemInfo + uSystemInfoLen, piai2->Address, piai2->AddressLength );
        uSystemInfoLen += piai2->AddressLength;
        piai2 = piai2->Next;         
      }
     }
     else
     {
      uErrorCode = 0xF0000000U + dwResult;
     }
     VERIFY( HeapFree( GetProcessHeap( ), 0, piai ) );
    }
    else
    {
     return FALSE;
    }
  }
  else
  {
    uErrorCode = 0xE0000000U + dwResult;
  }
  if( uErrorCode != 0U )
  {
    return FALSE;
  }
}
[Copy to clipboard]


// 硬盘序列号,注意:有的硬盘没有序列号
CODE:
{
  OSVERSIONINFO ovi = { 0 };
  ovi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
  GetVersionEx( &ovi );
  
  if( ovi.dwPlatformId != VER_PLATFORM_WIN32_NT )
  {
    // Only Windows 2000, Windows XP, Windows Server 2003...
    return FALSE;
  }
  else
  {
    if( !WinNTHDSerialNumAsPhysicalRead( szSystemInfo, &uSystemInfoLen, 1024 ) )
    {
     WinNTHDSerialNumAsScsiRead( szSystemInfo, &uSystemInfoLen, 1024 );
    }
  }
}
[Copy to clipboard]


// CPU ID
CODE:
{
  BOOL bException = FALSE;
  BYTE szCpu[16] = { 0 };
  UINT uCpuID  = 0U;

  __try
  {
    _asm
    {
     mov eax, 0
     cpuid
     mov dword ptr szCpu[0], ebx
     mov dword ptr szCpu[4], edx
     mov dword ptr szCpu[8], ecx
     mov eax, 1
     cpuid
     mov uCpuID, edx
    }
  }
  __except( EXCEPTION_EXECUTE_HANDLER )
  {
    bException = TRUE;
  }
  
  if( !bException )
  {
    CopyMemory( szSystemInfo + uSystemInfoLen, &uCpuID, sizeof( UINT ) );
    uSystemInfoLen += sizeof( UINT );

    uCpuID = strlen( ( char* )szCpu );
    CopyMemory( szSystemInfo + uSystemInfoLen, szCpu, uCpuID );
    uSystemInfoLen += uCpuID;
  }
}
[Copy to clipboard]


// BIOS 编号,支持 AMI, AWARD, PHOENIX
CODE:
{
  SIZE_T ssize;

  LARGE_INTEGER so;
  so.LowPart=0x000f0000;
  so.HighPart=0x00000000;
  ssize=0xffff;
  wchar_t strPH[30]=L\"\\\\device\\\\physicalmemory\";

  DWORD ba=0;

  UNICODE_STRING struniph;
  struniph.Buffer=strPH;
  struniph.Length=0x2c;
  struniph.MaximumLength =0x2e;

  OBJECT_ATTRIBUTES obj_ar;
  obj_ar.Attributes =64;
  obj_ar.Length =24;
  obj_ar.ObjectName=&struniph;
  obj_ar.RootDirectory=0;
  obj_ar.SecurityDescriptor=0;
  obj_ar.SecurityQualityOfService =0;

  HMODULE hinstLib = LoadLibrary(\"ntdll.dll\");
  ZWOS ZWopenS=(ZWOS)GetProcAddress(hinstLib,\"ZwOpenSection\");
  ZWMV ZWmapV=(ZWMV)GetProcAddress(hinstLib,\"ZwMapViewOfSection\");
  ZWUMV ZWunmapV=(ZWUMV)GetProcAddress(hinstLib,\"ZwUnmapViewOfSection\");
  
  //调用函数,对物理内存进行映射
  HANDLE hSection;
  if( 0 == ZWopenS(&hSection,4,&obj_ar) &&
    0 == ZWmapV(
    ( HANDLE )hSection,  //打开Section时得到的句柄
    ( HANDLE )0xFFFFFFFF, //将要映射进程的句柄,
    &ba,       //映射的基址
    0,
    0xFFFF,      //分配的大小
    &so,       //物理内存的地址
    &ssize,      //指向读取内存块大小的指针
    1,       //子进程的可继承性设定
    0,       //分配类型
    2        //保护类型
    ) )
  //执行后会在当前进程的空间开辟一段64k的空间,并把f000:0000到f000:ffff处的内容映射到这里
  //映射的基址由ba返回,如果映射不再有用,应该用ZwUnmapViewOfSection断开映射
  {
    BYTE* pBiosSerial = ( BYTE* )ba;
    UINT uBiosSerialLen = FindAwardBios( &pBiosSerial );
    if( uBiosSerialLen == 0U )
    {
     uBiosSerialLen = FindAmiBios( &pBiosSerial );
     if( uBiosSerialLen == 0U )
     {
      uBiosSerialLen = FindPhoenixBios( &pBiosSerial );
     }
    }
    if( uBiosSerialLen != 0U )
    {
     CopyMemory( szSystemInfo + uSystemInfoLen, pBiosSerial, uBiosSerialLen );
     uSystemInfoLen += uBiosSerialLen;
    }
    ZWunmapV( ( HANDLE )0xFFFFFFFF, ( void* )ba );
  }
}
[Copy to clipboard]



以下是其中用到的某些结构及函数的定义:

CODE:
define FILE_DEVICE_SCSI     0x0000001b
#define IOCTL_SCSI_MINIPORT_IDENTIFY ( ( FILE_DEVICE_SCSI << 16 ) + 0x0501 )

#define IOCTL_SCSI_MINIPORT 0x0004D008 // see NTDDSCSI.H for definition

#define IDENTIFY_BUFFER_SIZE 512
#define SENDIDLENGTH ( sizeof( SENDCMDOUTPARAMS ) + IDENTIFY_BUFFER_SIZE )

#define IDE_ATAPI_IDENTIFY 0xA1 // Returns ID sector for ATAPI.
#define IDE_ATA_IDENTIFY  0xEC // Returns ID sector for ATA.
#define DFP_RECEIVE_DRIVE_DATA  0x0007c088

typedef struct _IDSECTOR
{
USHORT wGenConfig;
USHORT wNumCyls;
USHORT wReserved;
USHORT wNumHeads;
USHORT wBytesPerTrack;
USHORT wBytesPerSector;
USHORT wSectorsPerTrack;
USHORT wVendorUnique[3];
CHAR  sSerialNumber[20];
USHORT wBufferType;
USHORT wBufferSize;
USHORT wECCSize;
CHAR  sFirmwareRev[8];
CHAR  sModelNumber[40];
USHORT wMoreVendorUnique;
USHORT wDoubleWordIO;
USHORT wCapabilities;
USHORT wReserved1;
USHORT wPIOTiming;
USHORT wDMATiming;
USHORT wBS;
USHORT wNumCurrentCyls;
USHORT wNumCurrentHeads;
USHORT wNumCurrentSectorsPerTrack;
ULONG  ulCurrentSectorCapacity;
USHORT wMultSectorStuff;
ULONG  ulTotalAddressableSectors;
USHORT wSingleWordDMA;
USHORT wMultiWordDMA;
BYTE  bReserved[128];
} IDSECTOR, *PIDSECTOR;

typedef struct _DRIVERSTATUS
{
BYTE bDriverError; // Error code from driver, or 0 if no error.
BYTE bIDEStatus;  // Contents of IDE Error register.
// Only valid when bDriverError is SMART_IDE_ERROR.
BYTE bReserved[2]; // Reserved for future expansion.
DWORD dwReserved[2]; // Reserved for future expansion.
} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;

typedef struct _SENDCMDOUTPARAMS
{
DWORD    cBufferSize;  // Size of bBuffer in bytes
DRIVERSTATUS DriverStatus; // Driver status structure.
BYTE    bBuffer[1];  // Buffer of arbitrary length in which to store the data read from the                   // drive.
} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;

typedef struct _SRB_IO_CONTROL
{
ULONG HeaderLength;
UCHAR Signature[8];
ULONG Timeout;
ULONG ControlCode;
ULONG ReturnCode;
ULONG Length;
} SRB_IO_CONTROL, *PSRB_IO_CONTROL;

typedef struct _IDEREGS
{
BYTE bFeaturesReg;   // Used for specifying SMART \"commands\".
BYTE bSectorCountReg;  // IDE sector count register
BYTE bSectorNumberReg;  // IDE sector number register
BYTE bCylLowReg;    // IDE low order cylinder value
BYTE bCylHighReg;   // IDE high order cylinder value
BYTE bDriveHeadReg;   // IDE drive/head register
BYTE bCommandReg;   // Actual IDE command.
BYTE bReserved;    // reserved for future use. Must be zero.
} IDEREGS, *PIDEREGS, *LPIDEREGS;

typedef struct _SENDCMDINPARAMS
{
DWORD  cBufferSize;  // Buffer size in bytes
IDEREGS  irDriveRegs;  // Structure with drive register values.
BYTE bDriveNumber;   // Physical drive number to send
// command to (0,1,2,3).
BYTE bReserved[3];   // Reserved for future expansion.
DWORD  dwReserved[4]; // For future use.
BYTE   bBuffer[1];  // Input buffer.
} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;

typedef struct _GETVERSIONOUTPARAMS
{
BYTE bVersion;   // Binary driver version.
BYTE bRevision;  // Binary driver revision.
BYTE bReserved;  // Not used.
BYTE bIDEDeviceMap; // Bit map of IDE devices.
DWORD fCapabilities; // Bit mask of driver capabilities.
DWORD dwReserved[4]; // For future use.
} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;

//////////////////////////////////////////////////////////////////////

//结构定义
typedef struct _UNICODE_STRING
{
USHORT Length;//长度
USHORT MaximumLength;//最大长度
PWSTR Buffer;//缓存指针
} UNICODE_STRING,*PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length;//长度 18h
HANDLE RootDirectory;// 00000000
PUNICODE_STRING ObjectName;//指向对象名的指针
ULONG Attributes;//对象属性00000040h
PVOID SecurityDescriptor;   // Points to type SECURITY_DESCRIPTOR,0
PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE,0
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;

//函数指针变量类型
typedef DWORD (__stdcall *ZWOS )( PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES);
typedef DWORD (__stdcall *ZWMV )( HANDLE,HANDLE,PVOID,ULONG,ULONG,PLARGE_INTEGER,PSIZE_T,DWORD,ULONG,ULONG);
typedef DWORD (__stdcall *ZWUMV )( HANDLE,PVOID);


BOOL WinNTHDSerialNumAsScsiRead( BYTE* dwSerial, UINT* puSerialLen, UINT uMaxSerialLen )
{
BOOL bInfoLoaded = FALSE;

for( int iController = 0; iController < 2; ++ iController )
{
  HANDLE hScsiDriveIOCTL = 0;
  char  szDriveName[256];
  
  // Try to get a handle to PhysicalDrive IOCTL, report failure
  // and exit if can&#39;t.
  sprintf( szDriveName, \"\\\\\\\\.\\\\Scsi%d:\", iController );

  // Windows NT, Windows 2000, any rights should do
  hScsiDriveIOCTL = CreateFile( szDriveName,
    GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    OPEN_EXISTING, 0, NULL);

  // if (hScsiDriveIOCTL == INVALID_HANDLE_VALUE)
  //  printf (\"Unable to open SCSI controller %d, error code: 0x%lX\\n\",
  //     controller, GetLastError ());
  
  if( hScsiDriveIOCTL != INVALID_HANDLE_VALUE )
  {
    int iDrive = 0;
    for( iDrive = 0; iDrive < 2; ++ iDrive )
    {
     char szBuffer[sizeof( SRB_IO_CONTROL ) + SENDIDLENGTH] = { 0 };

     SRB_IO_CONTROL* p = ( SRB_IO_CONTROL* )szBuffer;
     SENDCMDINPARAMS* pin = ( SENDCMDINPARAMS* )( szBuffer + sizeof( SRB_IO_CONTROL ) );
     DWORD dwResult;

     p->HeaderLength = sizeof( SRB_IO_CONTROL );
     p->Timeout = 10000;
     p->Length = SENDIDLENGTH;
     p->ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
     strncpy( ( char* )p->Signature, \"SCSIDISK\", 8 );

     pin->irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
     pin->bDriveNumber = iDrive;
     
     if( DeviceIoControl( hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,
      szBuffer,
      sizeof( SRB_IO_CONTROL ) + sizeof( SENDCMDINPARAMS ) - 1,
      szBuffer,
      sizeof( SRB_IO_CONTROL ) + SENDIDLENGTH,
      &dwResult, NULL ) )
     {
      SENDCMDOUTPARAMS* pOut = ( SENDCMDOUTPARAMS* )( szBuffer + sizeof( SRB_IO_CONTROL ) );
      IDSECTOR* pId = ( IDSECTOR* )( pOut->bBuffer );
      if( pId->sModelNumber[0] )
      {
        if( * puSerialLen + 20U <= uMaxSerialLen )
        {
         // 序列号
         CopyMemory( dwSerial + * puSerialLen, ( ( USHORT* )pId ) + 10, 20 );

         // Cut off the trailing blanks
         for( UINT i = 20; i != 0U && &#39; &#39; == dwSerial[* puSerialLen + i - 1]; -- i )
         {}
         * puSerialLen += i;

         // 型号
         CopyMemory( dwSerial + * puSerialLen, ( ( USHORT* )pId ) + 27, 40 );
         // Cut off the trailing blanks
         for( i = 40; i != 0U && &#39; &#39; == dwSerial[* puSerialLen + i - 1]; -- i )
         {}
         * puSerialLen += i;

         bInfoLoaded = TRUE;
        }
        else
        {
         ::CloseHandle( hScsiDriveIOCTL );
         return bInfoLoaded;
        }
      }
     }
    }
    ::CloseHandle( hScsiDriveIOCTL );
  }
}
return bInfoLoaded;
}

BOOL DoIdentify( HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP,
     PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum,
     PDWORD lpcbBytesReturned )
{
// Set up data structures for IDENTIFY command.
pSCIP->cBufferSize       = IDENTIFY_BUFFER_SIZE;
pSCIP->irDriveRegs.bFeaturesReg  = 0;
pSCIP->irDriveRegs.bSectorCountReg = 1;
pSCIP->irDriveRegs.bSectorNumberReg = 1;
pSCIP->irDriveRegs.bCylLowReg   = 0;
pSCIP->irDriveRegs.bCylHighReg   = 0;

// calc the drive number.
pSCIP->irDriveRegs.bDriveHeadReg = 0xA0 | ( ( bDriveNum & 1 ) << 4 );

// The command can either be IDE identify or ATAPI identify.
pSCIP->irDriveRegs.bCommandReg = bIDCmd;
pSCIP->bDriveNumber = bDriveNum;
pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;

return DeviceIoControl( hPhysicalDriveIOCTL, DFP_RECEIVE_DRIVE_DATA,
  ( LPVOID ) pSCIP,
  sizeof( SENDCMDINPARAMS ) - 1,
  ( LPVOID ) pSCOP,
  sizeof( SENDCMDOUTPARAMS ) + IDENTIFY_BUFFER_SIZE - 1,
  lpcbBytesReturned, NULL );
}

BOOL WinNTHDSerialNumAsPhysicalRead( BYTE* dwSerial, UINT* puSerialLen, UINT uMaxSerialLen )
{
#define DFP_GET_VERSION    0x00074080
BOOL bInfoLoaded = FALSE;

for( UINT uDrive = 0; uDrive < 4; ++ uDrive )
{
  HANDLE hPhysicalDriveIOCTL = 0;

  // Try to get a handle to PhysicalDrive IOCTL, report failure
  // and exit if can&#39;t.
  char szDriveName [256];
  sprintf( szDriveName, \"\\\\\\\\.\\\\PhysicalDrive%d\", uDrive );

  // Windows NT, Windows 2000, must have admin rights
  hPhysicalDriveIOCTL = CreateFile( szDriveName,
    GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    OPEN_EXISTING, 0, NULL);

  if( hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE )
  {
    GETVERSIONOUTPARAMS VersionParams = { 0 };
    DWORD      cbBytesReturned = 0;

    // Get the version, etc of PhysicalDrive IOCTL
    if( DeviceIoControl( hPhysicalDriveIOCTL, DFP_GET_VERSION,
     NULL,
     0,
     &VersionParams,
     sizeof( GETVERSIONOUTPARAMS ),
     &cbBytesReturned, NULL ) )
    {
     // If there is a IDE device at number \"i\" issue commands
     // to the device
     if( VersionParams.bIDEDeviceMap != 0 )
     {
      BYTE     bIDCmd = 0;  // IDE or ATAPI IDENTIFY cmd
      SENDCMDINPARAMS scip = { 0 };

      // Now, get the ID sector for all IDE devices in the system.
      // If the device is ATAPI use the IDE_ATAPI_IDENTIFY command,
      // otherwise use the IDE_ATA_IDENTIFY command
      bIDCmd = ( VersionParams.bIDEDeviceMap >> uDrive & 0x10 ) ? IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;
      BYTE IdOutCmd[sizeof( SENDCMDOUTPARAMS ) + IDENTIFY_BUFFER_SIZE - 1] = { 0 };

      if( DoIdentify( hPhysicalDriveIOCTL,
        &scip,
        ( PSENDCMDOUTPARAMS )&IdOutCmd,
        ( BYTE )bIDCmd,
        ( BYTE )uDrive,
        &cbBytesReturned ) )
      {
        if( * puSerialLen + 20U <= uMaxSerialLen )
        {
         CopyMemory( dwSerial + * puSerialLen, ( ( USHORT* )( ( ( PSENDCMDOUTPARAMS )IdOutCmd )->bBuffer ) ) + 10, 20 ); // 序列号

         // Cut off the trailing blanks
         for( UINT i = 20; i != 0U && &#39; &#39; == dwSerial[* puSerialLen + i - 1]; -- i ) {}
         * puSerialLen += i;

         CopyMemory( dwSerial + * puSerialLen, ( ( USHORT* )( ( ( PSENDCMDOUTPARAMS )IdOutCmd )->bBuffer ) ) + 27, 40 ); // 型号

         // Cut off the trailing blanks
         for( i = 40; i != 0U && &#39; &#39; == dwSerial[* puSerialLen + i - 1]; -- i ) {}
         * puSerialLen += i;

         bInfoLoaded = TRUE;
        }
        else
        {
         ::CloseHandle( hPhysicalDriveIOCTL );
         return bInfoLoaded;
        }
      }
     }
    }
    CloseHandle( hPhysicalDriveIOCTL );
  }
}
return bInfoLoaded;
}

UINT FindAwardBios( BYTE** ppBiosAddr )
{
BYTE* pBiosAddr = * ppBiosAddr + 0xEC71;

BYTE szBiosData[128];
CopyMemory( szBiosData, pBiosAddr, 127 );
szBiosData[127] = 0;

int iLen = lstrlen( ( char* )szBiosData );
if( iLen > 0 && iLen < 128 )
{
  //AWard:    07/08/2002-i845G-ITE8712-JF69VD0CC-00
  //Phoenix-Award: 03/12/2002-sis645-p4s333
  if( szBiosData[2] == &#39;/&#39; && szBiosData[5] == &#39;/&#39; )
  {
    BYTE* p = szBiosData;
    while( * p )
    {
     if( * p < &#39; &#39; || * p >= 127 )
     {
      break;
     }
     ++ p;
    }
    if( * p == 0 )
    {
     * ppBiosAddr = pBiosAddr;
     return ( UINT )iLen;
    }
  }
}
return 0;
}

UINT FindAmiBios( BYTE** ppBiosAddr )
{
BYTE* pBiosAddr = * ppBiosAddr + 0xF478;

BYTE szBiosData[128];
CopyMemory( szBiosData, pBiosAddr, 127 );
szBiosData[127] = 0;

int iLen = lstrlen( ( char* )szBiosData );
if( iLen > 0 && iLen < 128 )
{
  // Example: \"AMI: 51-2300-000000-00101111-030199-\"
  if( szBiosData[2] == &#39;-&#39; && szBiosData[7] == &#39;-&#39; )
  {
    BYTE* p = szBiosData;
    while( * p )
    {
     if( * p < &#39; &#39; || * p >= 127 )
     {
      break;
     }
     ++ p;
    }
    if( * p == 0 )
    {
     * ppBiosAddr = pBiosAddr;
     return ( UINT )iLen;
    }
  }
}
return 0;
}

UINT FindPhoenixBios( BYTE** ppBiosAddr )
{
UINT uOffset[3] = { 0x6577, 0x7196, 0x7550 };
for( UINT i = 0; i < 3; ++ i )
{
  BYTE* pBiosAddr = * ppBiosAddr + uOffset;

  BYTE szBiosData[128];
  CopyMemory( szBiosData, pBiosAddr, 127 );
  szBiosData[127] = 0;

  int iLen = lstrlen( ( char* )szBiosData );
  if( iLen > 0 && iLen < 128 )
  {
    // Example: Phoenix \"NITELT0.86B.0044.P11.9910111055\"
    if( szBiosData[7] == &#39;.&#39; && szBiosData[11] == &#39;.&#39; )
    {
     BYTE* p = szBiosData;
     while( * p )
     {
      if( * p < &#39; &#39; || * p >= 127 )
      {
        break;
      }
      ++ p;
     }
     if( * p == 0 )
     {
      * ppBiosAddr = pBiosAddr;
      return ( UINT )iLen;
     }
    }
  }
}
return 0;
}
爱车车 发表于 2011-7-17 10:02 | 显示全部楼层
都看了,这帖子有意思。
秋秋 发表于 2011-7-26 10:19 | 显示全部楼层
看你快沉底了~~~~~~
您需要登录后才可以回帖 登录 | 成为会员

本版积分规则

QQ|手机版|小黑屋|网站帮助|职业IT人-IT人生活圈 ( 粤ICP备12053935号-1 )|网站地图
本站文章版权归原发布者及原出处所有。内容为作者个人观点,并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是信息平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽造成漏登,请及时联系我们,我们将根据著作权人的要求立即更正或者删除有关内容。

GMT+8, 2024-5-4 00:58 , Processed in 0.139805 second(s), 20 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表