某某市信息科技学业水平测试软件打开加载失败逆向分析(笔记)

引言:笔者在工作过程中,用户上报某某市信息科技学业水平测试软件在云电脑上打开初始化的情况下出现了加载和绑定机器失败的问题。一般情况下,在实体机上用户进行登录后,用户的账号信息跟主机的机器码进行绑定然后保存到配置文件,等下次再次登录的时候就可以不用再次输入用户账户信息的情况下完成自动登录。但是用户反馈在我们的云电脑上出现了无法完成自动登录的情况。

解决过程:

用dbgx64.exe对该软件进行逆向调试分析(这里过程复杂,不具体罗列),发现该软件是用vb写的程序,并最后调试并发现该软件获取机器序列号的函数,该软件是通过DeviceIoControl这个Api来获取机器的序列号的,通过hook该Api发现该软件会调用三次DeviceIoControl这个api来获取机器码。到底要hook哪一次的调用呢。

通过在网上找到vb程序写的获取机器码的相关代码(代码放在后面的附录里面)。通过vb6.0对改代码进行调试,发现该代码基本就是该软件获取机器码的方式:

并发现,在云桌面上每次通过DeviceIoCtrol获取的机器码都是不一样的,而在实体机上发现,该Api调用会返回失败,但为什么在实体机软件能运行正常呢,这里猜测是软件在获取机器码失败的情况会通过固定算法自动生成一个ID的方式来替代本机的机器码,而在云主机上由于每次调用DeviceIoCtrol都能调用成功,但是获取的机器码不一样导致校验失败。

这里通过Hook DeviceIoCtrol并根据特定的ID进行返回失败操作来达到目的。可以通过CFF对软件进行修改导入表的方式来完成软件对自己插件的自动依赖和加载,但同时考虑到软件软件的升级,所以这里不建议直接给软件程序打补丁,而是通过对软件依赖的msvbvm60.dll进行打补丁,这样哪怕软件完成了升级也不会导致因为软件文件升级而导致补丁加载失效:

附录代码:
static BOOL(WINAPI* OrgDeviceIoControl)(HANDLE       hDevice,DWORD        dwIoControlCode,LPVOID       lpInBuffer,DWORD        nInBufferSize,LPVOID       lpOutBuffer,DWORD        nOutBufferSize,LPDWORD      lpBytesReturned,LPOVERLAPPED lpOverlapped
) = DeviceIoControl;BOOL WINAPI NewDeviceIoControl(HANDLE       hDevice,DWORD        dwIoControlCode,LPVOID       lpInBuffer,DWORD        nInBufferSize,LPVOID       lpOutBuffer,DWORD        nOutBufferSize,LPDWORD      lpBytesReturned,LPOVERLAPPED lpOverlapped
)
{BOOL bRet = OrgDeviceIoControl(hDevice,dwIoControlCode,lpInBuffer,nInBufferSize,lpOutBuffer,nOutBufferSize,lpBytesReturned,lpOverlapped);//IOCTL_DISK_GET_DRIVE_GEOMETRY;/* if (0x74080 == dwIoControlCode || 0x7C084 == dwIoControlCode || dwIoControlCode == 0x7C088){bRet = FALSE;return FALSE;} */if (dwIoControlCode == 0x7C088){bRet = FALSE;OutputDebugString(L"DeviceIoCtrol Code is 0x7C088, process it!");SENDCMDOUTPARAMS out;int outparamsize = sizeof(out);memcpy(&out, lpOutBuffer, sizeof(out));IDSECTOR idsector;memcpy(&idsector, &out.bBuffer[0], sizeof(idsector));char* pcNumber = idsector.sModelNumber;__int64 pNumber = (__int64)pcNumber;__int64 pFirmware = (__int64)idsector.sFirmwareRev;__int64 pSerNum = (__int64)idsector.sSerialNumber;WCHAR szBuf[350] = { 0 };wsprintf(szBuf, L" sModelNumber 1:0x%p  0x%02X %02X %02X %02X %02X %02X %02X %02X \n"L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n",pcNumber, *(char*)(pNumber+0), *(char*)(pNumber + 1), *(char*)(pNumber + 2), *(char*)(pNumber + 3), *(char*)(pNumber + 4), *(char*)(pNumber + 5), *(char*)(pNumber + 6), *(char*)(pNumber + 7),*(char*)(pNumber + 8), *(char*)(pNumber + 9), *(char*)(pNumber + 10), *(char*)(pNumber + 11), *(char*)(pNumber + 12), *(char*)(pNumber + 13), *(char*)(pNumber + 14), *(char*)(pNumber + 15),*(char*)(pNumber + 16), *(char*)(pNumber + 17), *(char*)(pNumber + 18), *(char*)(pNumber + 19), *(char*)(pNumber + 20), *(char*)(pNumber + 21), *(char*)(pNumber + 22), *(char*)(pNumber + 23),*(char*)(pNumber + 24), *(char*)(pNumber + 25), *(char*)(pNumber + 26), *(char*)(pNumber + 27), *(char*)(pNumber + 28), *(char*)(pNumber + 29), *(char*)(pNumber + 30), *(char*)(pNumber + 31),*(char*)(pNumber + 32), *(char*)(pNumber + 33), *(char*)(pNumber + 34), *(char*)(pNumber + 35), *(char*)(pNumber + 36), *(char*)(pNumber + 37), *(char*)(pNumber + 38), *(char*)(pNumber + 39));OutputDebugStringW(szBuf);wsprintf(szBuf, L" sFirmwareRev 2:0x%p  0x%02X %02X %02X %02X %02X %02X %02X %02X \n",pFirmware, *(char*)(pFirmware + 0), *(char*)(pFirmware + 1), *(char*)(pFirmware + 2), *(char*)(pFirmware + 3), *(char*)(pFirmware + 4), *(char*)(pFirmware + 5), *(char*)(pFirmware + 6), *(char*)(pFirmware + 7));OutputDebugStringW(szBuf);wsprintf(szBuf, L"sSerialNumber 3:0x%p  0x%02X %02X %02X %02X %02X %02X %02X %02X \n"L"0x%02X %02X %02X %02X %02X %02X %02X %02X \n"L"0x%02X %02X %02X %02X \n",pSerNum, *(char*)(pSerNum + 0), *(char*)(pSerNum + 1), *(char*)(pSerNum + 2), *(char*)(pSerNum + 3), *(char*)(pSerNum + 4), *(char*)(pSerNum + 5), *(char*)(pSerNum + 6), *(char*)(pSerNum + 7),*(char*)(pSerNum + 8), *(char*)(pSerNum + 9), *(char*)(pSerNum + 10), *(char*)(pSerNum + 11), *(char*)(pSerNum + 12), *(char*)(pSerNum + 13), *(char*)(pSerNum + 14), *(char*)(pSerNum + 15),*(char*)(pSerNum + 16), *(char*)(pSerNum + 17), *(char*)(pSerNum + 18), *(char*)(pSerNum + 19));OutputDebugStringW(szBuf);}return bRet;
}bool Hook()
{// 相关的初始化信息DetourTransactionBegin();// 更新线程信息 DetourUpdateThread(GetCurrentThread());DetourAttach(&(PVOID&)OrgDeviceIoControl, NewDeviceIoControl);//    org_vbaStrCmp = (_vbaStrCmp)GetProcAddress(LoadLibraryA("msvbvm60.dll"), "__vbaStrCmp");//int iRet2 = DetourAttach(&(PVOID&)org_vbaStrCmp, new_vbaStrCmp);return NO_ERROR == DetourTransactionCommit();
}// 卸载Hook
bool UnHoo()
{DetourTransactionBegin();DetourUpdateThread(GetCurrentThread());return NO_ERROR == DetourTransactionCommit();
}

C#获取机器码的相关代码:

VERSION 5.00
Begin VB.Form Form1 Caption         =   "Form1"ClientHeight    =   3015ClientLeft      =   120ClientTop       =   465ClientWidth     =   4560LinkTopic       =   "Form1"ScaleHeight     =   3015ScaleWidth      =   4560StartUpPosition =   3  '窗口缺省Begin VB.CommandButton Command1 Caption         =   "Command1"Height          =   855Left            =   1080TabIndex        =   0Top             =   600Width           =   1335End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False'============================================
'模块功能:取得硬盘的信息
'编    程:来自互联网,阿勇修改
'更新日期:2005/7/8
'调用方法:
'   GetDiskVolume() 取得逻辑盘的序列号
'   GetHardDiskInfo() 取得物理盘的型号或序列号
'============================================Private Const MAX_IDE_DRIVES As Long = 4
Private Const READ_ATTRIBUTE_BUFFER_SIZE As Long = 512
Private Const IDENTIFY_BUFFER_SIZE As Long = 512
Private Const READ_THRESHOLD_BUFFER_SIZE As Long = 512
Private Const DFP_GET_VERSION As Long = &H74080
Private Const DFP_SEND_DRIVE_COMMAND As Long = &H7C084
Private Const DFP_RECEIVE_DRIVE_DATA As Long = &H7C088Private Type GETVERSIONOUTPARAMSbVersion As Byte       ' Binary driver version.bRevision As Byte      ' Binary driver revision.bReserved As Byte      ' Not used.bIDEDeviceMap As Byte  ' Bit map of IDE devices.fCapabilities As Long  ' Bit mask of driver capabilities.dwReserved(3) As Long  ' For future use.
End TypePrivate Const CAP_IDE_ID_FUNCTION As Long = 1               ' ATA ID command supported
Private Const CAP_IDE_ATAPI_ID As Long = 2                  ' ATAPI ID command supported
Private Const CAP_IDE_EXECUTE_SMART_FUNCTION As Long = 4    ' SMART commannds supportedPrivate Type IDEREGSbFeaturesReg As Byte       ' Used for specifying SMART "commands".bSectorCountReg As Byte    ' IDE sector count registerbSectorNumberReg As Byte   ' IDE sector number registerbCylLowReg As Byte         ' IDE low order cylinder valuebCylHighReg As Byte        ' IDE high order cylinder valuebDriveHeadReg As Byte      ' IDE drive/head registerbCommandReg As Byte        ' Actual IDE command.bReserved As Byte          ' reserved for future use.  Must be zero.
End TypePrivate Type SENDCMDINPARAMScBufferSize As Long        ' Buffer size in bytesirDriveRegs As IDEREGS     ' Structure with drive register values.bDriveNumber As Byte       ' Physical drive number to send' command to (0,1,2,3).bReserved(2) As Byte       ' Reserved for future expansion.dwReserved(3) As Long      ' For future use.bBuffer(0) As Byte         ' Input buffer.
End TypePrivate Const IDE_ATAPI_ID As Long = &HA1  ' Returns ID sector for ATAPI.
Private Const IDE_ID_FUNCTION As Long = &HEC  ' Returns ID sector for ATA.
Private Const IDE_EXECUTE_SMART_FUNCTION As Long = &HB0  ' Performs SMART cmd.
Private Const SMART_CYL_LOW As Long = &H4F
Private Const SMART_CYL_HI As Long = &HC2Private Type DRIVERSTATUSbDriverError As Byte       ' Error code from driver,bIDEStatus As Byte         ' Contents of IDE Error register.bReserved(1) As Byte       ' Reserved for future expansion.dwReserved(1) As Long      ' Reserved for future expansion.
End TypePrivate Const SMART_NO_ERROR As Long = 0  ' No error
Private Const SMART_IDE_ERROR As Long = 1  ' Error from IDE controller
Private Const SMART_INVALID_FLAG As Long = 2  ' Invalid command flag
Private Const SMART_INVALID_COMMAND As Long = 3  ' Invalid command byte
Private Const SMART_INVALID_BUFFER As Long = 4  ' Bad buffer (null, invalid addr..)
Private Const SMART_INVALID_DRIVE As Long = 5  ' Drive number not valid
Private Const SMART_INVALID_IOCTL As Long = 6   ' Invalid IOCTL
Private Const SMART_ERROR_NO_MEM As Long = 7  ' Could not lock user's buffer
Private Const SMART_INVALID_REGISTER As Long = 8  ' Some IDE Register not valid
Private Const SMART_NOT_SUPPORTED As Long = 9  ' Invalid cmd flag set
Private Const SMART_NO_IDE_DEVICE As Long = 10 ' Cmd issued to device not presentPrivate Type SENDCMDOUTPARAMScBufferSize As Long        ' Size of bBuffer in bytesdrvStatus As DRIVERSTATUS  ' Driver status structure.bBuffer(0) As Byte         ' Buffer of arbitrary length in which to store the data read from the                                          ' drive.
End TypePrivate Const SMART_READ_ATTRIBUTE_VALUES As Long = &HD0    ' ATA4: Renamed
Private Const SMART_READ_ATTRIBUTE_THRESHOLDS As Long = &HD1    ' Obsoleted in ATA4!
Private Const SMART_ENABLE_DISABLE_ATTRIBUTE_AUTOSAVE As Long = &HD2
Private Const SMART_SAVE_ATTRIBUTE_VALUES As Long = &HD3
Private Const SMART_EXECUTE_OFFLINE_IMMEDIATE As Long = &HD4    ' ATA4
Private Const SMART_ENABLE_SMART_OPERATIONS As Long = &HD8
Private Const SMART_DISABLE_SMART_OPERATIONS As Long = &HD9
Private Const SMART_RETURN_SMART_STATUS As Long = &HDAPrivate Type DRIVEATTRIBUTEbAttrID As Byte        ' Identifies which attributewStatusFlags As Integer    ' see bit definitions belowbAttrValue As Byte     ' Current normalized valuebWorstValue As Byte    ' How bad has it ever been?bRawValue(5) As Byte   ' Un-normalized valuebReserved As Byte      ' ...
End TypePrivate Type ATTRTHRESHOLDbAttrID As Byte            ' Identifies which attributebWarrantyThreshold As Byte ' Triggering valuebReserved(9) As Byte      ' ...
End TypePrivate Type IDSECTORwGenConfig As IntegerwNumCyls As IntegerwReserved As IntegerwNumHeads As IntegerwBytesPerTrack As IntegerwBytesPerSector As IntegerwSectorsPerTrack As IntegerwVendorUnique(2) As IntegersSerialNumber(19) As BytewBufferType As IntegerwBufferSize As IntegerwECCSize As IntegersFirmwareRev(7) As BytesModelNumber(39) As BytewMoreVendorUnique As IntegerwDoubleWordIO As IntegerwCapabilities As IntegerwReserved1 As IntegerwPIOTiming As IntegerwDMATiming As IntegerwBS As IntegerwNumCurrentCyls As IntegerwNumCurrentHeads As IntegerwNumCurrentSectorsPerTrack As IntegerulCurrentSectorCapacity(3) As Byte    '这里只能用byte,因为VB没有无符号的LONG型变量wMultSectorStuff As IntegerulTotalAddressableSectors(3) As Byte   '这里只能用byte,因为VB没有无符号的LONG型变量wSingleWordDMA As IntegerwMultiWordDMA As IntegerbReserved(127) As Byte
End TypePrivate Const ATTR_INVALID As Long = 0
Private Const ATTR_READ_ERROR_RATE As Long = 1
Private Const ATTR_THROUGHPUT_PERF As Long = 2
Private Const ATTR_SPIN_UP_TIME As Long = 3
Private Const ATTR_START_STOP_COUNT As Long = 4
Private Const ATTR_REALLOC_SECTOR_COUNT As Long = 5
Private Const ATTR_READ_CHANNEL_MARGIN As Long = 6
Private Const ATTR_SEEK_ERROR_RATE As Long = 7
Private Const ATTR_SEEK_TIME_PERF As Long = 8
Private Const ATTR_POWER_ON_HRS_COUNT As Long = 9
Private Const ATTR_SPIN_RETRY_COUNT As Long = 10
Private Const ATTR_CALIBRATION_RETRY_COUNT As Long = 11
Private Const ATTR_POWER_CYCLE_COUNT As Long = 12Private Const PRE_FAILURE_WARRANTY As Long = &H1
Private Const ON_LINE_COLLECTION As Long = &H2
Private Const PERFORMANCE_ATTRIBUTE As Long = &H4
Private Const ERROR_RATE_ATTRIBUTE As Long = &H8
Private Const EVENT_COUNT_ATTRIBUTE As Long = &H10
Private Const SELF_PRESERVING_ATTRIBUTE As Long = &H20Private Const NUM_ATTRIBUTE_STRUCTS As Long = 30
Private Const INVALID_HANDLE_VALUE As Long = -1Private Const VER_PLATFORM_WIN32s As Long = 0
Private Const VER_PLATFORM_WIN32_WINDOWS As Long = 1
Private Const VER_PLATFORM_WIN32_NT As Long = 2Private Type OSVERSIONINFOdwOSVersionInfoSize As LongdwMajorVersion As LongdwMinorVersion As LongdwBuildNumber As LongdwPlatformId As LongszCSDVersion As String * 128      '  Maintenance string for PSS usage
End TypePrivate Const CREATE_NEW As Long = 1
Private Const GENERIC_READ As Long = &H80000000
Private Const GENERIC_WRITE As Long = &H40000000
Private Const FILE_SHARE_READ As Long = &H1
Private Const FILE_SHARE_WRITE As Long = &H2
Private Const OPEN_EXISTING  As Long = 3Private m_DiskInfo As IDSECTORPrivate Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function DeviceIoControl Lib "kernel32" (ByVal hDevice As Long, ByVal dwIoControlCode As Long, lpInBuffer As Any, ByVal nInBufferSize As Long, lpOutBuffer As Any, ByVal nOutBufferSize As Long, lpBytesReturned As Long, ByVal lpOverlapped As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)Private Declare Function GetVolumeInformation Lib "kernel32" Alias "GetVolumeInformationA" (ByVal lpRootPathName As String, ByVal lpVolumeNameBuffer As String, ByVal nVolumeNameSize As Long, lpVolumeSerialNumber As Long, lpMaximumComponentLength As Long, lpFileSystemFlags As Long, ByVal lpFileSystemNameBuffer As String, ByVal nFileSystemNameSize As Long) As Long'信息类型枚举
Enum eumInfoTypehdmodelsn = 0hdOnlyModel = 1hdOnlySN = 2
End Enum'磁盘通道枚举
Enum eumDiskNohdPrimaryMaster = 0hdPrimarySlave = 1hdSecondaryMaster = 2hdSecondarySlave = 3
End Enum'取得逻辑盘序列号(非唯一)
Function GetDiskVolume(Optional ByVal strDiskName = "C") As StringDim TempStr1 As String * 256, TempStr2 As String * 256Dim TempLon1 As Long, TempLon2 As Long, GetVal As LongDim tmpVol As StringCall GetVolumeInformation(strDiskName & ":/", TempStr1, 256, GetVal, TempLon1, TempLon2, TempStr2, 256)If GetVal = 0 ThentmpVol = ""ElsetmpVol = Hex(GetVal)tmpVol = String(8 - Len(tmpVol), "0") & tmpVoltmpVol = Left(tmpVol, 4) & "-" & Right(tmpVol, 4)End IfGetDiskVolume = tmpVol
End Function'取得硬盘信息:型号/物理系列号(唯一)
Function GetHardDiskInfo(Optional ByVal numDisk As eumDiskNo = hdPrimaryMaster, Optional ByVal numType As eumInfoType = hdOnlySN) As StringIf GetDiskInfo(numDisk) = 1 ThenDim pSerialNumber As String, pModelNumber As StringpSerialNumber = StrConv(m_DiskInfo.sSerialNumber, vbUnicode)pModelNumber = StrConv(m_DiskInfo.sModelNumber, vbUnicode)Select Case numTypeCase hdOnlyModel  '仅型号GetHardDiskInfo = Trim(pModelNumber)Case hdOnlySN  '仅系列号GetHardDiskInfo = Trim(pSerialNumber)Case Else   '型号,系列号GetHardDiskInfo = Trim(pModelNumber) & "," & Trim(pSerialNumber)End SelectEnd IfEnd FunctionPrivate Function OpenSMART(ByVal nDrive As Byte) As LongDim hSMARTIOCTL As LongDim hd As StringDim VersionInfo As OSVERSIONINFOhSMARTIOCTL = INVALID_HANDLE_VALUEVersionInfo.dwOSVersionInfoSize = Len(VersionInfo)GetVersionEx VersionInfoSelect Case VersionInfo.dwPlatformIdCase VER_PLATFORM_WIN32sOpenSMART = hSMARTIOCTLCase VER_PLATFORM_WIN32_WINDOWShSMARTIOCTL = CreateFile("//./SMARTVSD", 0, 0, 0, CREATE_NEW, 0, 0)Case VER_PLATFORM_WIN32_NTIf nDrive < MAX_IDE_DRIVES Thenhd = "//./PhysicalDrive" & nDrivehSMARTIOCTL = CreateFile(hd, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)End IfEnd SelectOpenSMART = hSMARTIOCTLEnd FunctionPrivate Function DoIDENTIFY(ByVal hSMARTIOCTL As Long, pSCIP As SENDCMDINPARAMS, pSCOP() As Byte, ByVal bIDCmd As Byte, ByVal bDriveNum As Byte, lpcbBytesReturned As Long) As BooleanpSCIP.cBufferSize = IDENTIFY_BUFFER_SIZEpSCIP.irDriveRegs.bFeaturesReg = 0pSCIP.irDriveRegs.bSectorCountReg = 1pSCIP.irDriveRegs.bSectorNumberReg = 1pSCIP.irDriveRegs.bCylLowReg = 0pSCIP.irDriveRegs.bCylHighReg = 0pSCIP.irDriveRegs.bDriveHeadReg = &HA0 Or ((bDriveNum And 1) * 2 ^ 4)'pSCIP.irDriveRegs.bCommandReg = bIDCmdpSCIP.bDriveNumber = bDriveNumpSCIP.cBufferSize = IDENTIFY_BUFFER_SIZEDoIDENTIFY = CBool(DeviceIoControl(hSMARTIOCTL, DFP_RECEIVE_DRIVE_DATA, _pSCIP, 32, _pSCOP(0), 528, _lpcbBytesReturned, 0))End FunctionPrivate Function DoEnableSMART(ByVal hSMARTIOCTL As Long, pSCIP As SENDCMDINPARAMS, pSCOP As SENDCMDOUTPARAMS, ByVal bDriveNum As Byte, lpcbBytesReturned As Long) As BooleanpSCIP.cBufferSize = 0pSCIP.irDriveRegs.bFeaturesReg = SMART_ENABLE_SMART_OPERATIONSpSCIP.irDriveRegs.bSectorCountReg = 1pSCIP.irDriveRegs.bSectorNumberReg = 1pSCIP.irDriveRegs.bCylLowReg = SMART_CYL_LOWpSCIP.irDriveRegs.bCylHighReg = SMART_CYL_HIpSCIP.irDriveRegs.bDriveHeadReg = &HA0 Or ((bDriveNum And 1) * 2 ^ 4)pSCIP.irDriveRegs.bCommandReg = IDE_EXECUTE_SMART_FUNCTIONpSCIP.bDriveNumber = bDriveNumDoEnableSMART = CBool(DeviceIoControl(hSMARTIOCTL, DFP_SEND_DRIVE_COMMAND, _pSCIP, LenB(pSCIP) - 1, _pSCOP, LenB(pSCOP) - 1, _lpcbBytesReturned, 0))End Function'---------------------------------------------------------------------
'---------------------------------------------------------------------
Private Sub ChangeByteOrder(szString() As Byte, ByVal uscStrSize As Integer)Dim i As IntegerDim bTemp As ByteFor i = 0 To uscStrSize - 1 Step 2bTemp = szString(i)szString(i) = szString(i + 1)szString(i + 1) = bTempNext iEnd SubPrivate Sub DisplayIdInfo(pids As IDSECTOR, pSCIP As SENDCMDINPARAMS, ByVal bIDCmd As Byte, ByVal bDfpDriveMap As Byte, ByVal bDriveNum As Byte)ChangeByteOrder pids.sModelNumber, UBound(pids.sModelNumber) + 1ChangeByteOrder pids.sFirmwareRev, UBound(pids.sFirmwareRev) + 1ChangeByteOrder pids.sSerialNumber, UBound(pids.sSerialNumber) + 1End SubPublic Function GetDiskInfo(ByVal nDrive As Byte) As LongDim hSMARTIOCTL As LongDim cbBytesReturned As LongDim VersionParams As GETVERSIONOUTPARAMSDim scip As SENDCMDINPARAMSDim scop() As ByteDim OutCmd As SENDCMDOUTPARAMSDim bDfpDriveMap As ByteDim bIDCmd As Byte                    ' IDE or ATAPI IDENTIFY cmdDim uDisk As IDSECTORm_DiskInfo = uDiskhSMARTIOCTL = OpenSMART(nDrive)If hSMARTIOCTL <> INVALID_HANDLE_VALUE ThenCall DeviceIoControl(hSMARTIOCTL, DFP_GET_VERSION, ByVal 0, 0, VersionParams, Len(VersionParams), cbBytesReturned, 0)If Not (VersionParams.bIDEDeviceMap / 2 ^ nDrive And &H10) ThenIf DoEnableSMART(hSMARTIOCTL, scip, OutCmd, nDrive, cbBytesReturned) ThenbDfpDriveMap = bDfpDriveMap Or 2 ^ nDriveEnd IfEnd IfbIDCmd = IIf((VersionParams.bIDEDeviceMap / 2 ^ nDrive And &H10), IDE_ATAPI_ID, IDE_ID_FUNCTION)ReDim scop(LenB(OutCmd) + IDENTIFY_BUFFER_SIZE - 1) As ByteIf DoIDENTIFY(hSMARTIOCTL, scip, scop, bIDCmd, nDrive, cbBytesReturned) ThenCopyMemory m_DiskInfo, scop(LenB(OutCmd) - 4), LenB(m_DiskInfo)Call DisplayIdInfo(m_DiskInfo, scip, bIDCmd, bDfpDriveMap, nDrive)CloseHandle hSMARTIOCTLGetDiskInfo = 1Exit Function '>---> BottomEnd IfCloseHandle hSMARTIOCTLGetDiskInfo = 0Else 'NOT HSMARTIOCTL...GetDiskInfo = -1End IfEnd FunctionPrivate Sub Command1_Click()result = MsgBox("你喜欢蓝色吗?", 3, "选择一个选项")GetDiskInfo (0)End Sub

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/864907.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Echarts-散点图

1.案例1 1.1代码 option = {xAxis: {scale: true,splitLine: {show: false},axisLabel: {show: true,textStyle: {color: white, //更改坐标轴文字颜色}}},yAxis: {show:false,scale: true,splitLine: {show: true,lineStyle: {type: dashed,}},axisLabel: {show: true ,tex…

毛概客观题题库

第一章毛泽东思想及其历史地位 一、单选题 2.1917年&#xff08; &#xff09;的胜利开辟了世界无产阶级社会主义革命的新时代&#xff0c;也给中国送来了马克思列宁主义.... A.俄国十月革命 B.五四运动 C.中国共产党建立 D.中华人民共和国建立 4.标志着毛泽东思想开始萌…

第十四届蓝桥杯省赛C++B组E题【接龙数列】题解(AC)

需求分析 题目要求最少删掉多少个数后&#xff0c;使得数列变为接龙数列。 相当于题目要求求出数组中的最长接龙子序列。 题目分析 对于一个数能不能放到接龙数列中&#xff0c;只关系到这个数的第一位和最后一位&#xff0c;所以我们可以先对数组进行预处理&#xff0c;将…

C++初学者指南-3.自定义类型(第一部分)-析构函数

C初学者指南-3.自定义类型(第一部分)-析构函数 文章目录 C初学者指南-3.自定义类型(第一部分)-析构函数特殊的成员函数用户定义的构造函数和析构函数RAII示例&#xff1a;资源处理示例&#xff1a;RAII记录零规则 特殊的成员函数 T::T()默认构造函数当创建新的 T 对象时运行。…

电脑录音方法:电脑怎么录音?5招轻松搞定录音!

想要从麦克风或系统音频录制电脑声音吗&#xff1f;这是一项简单的任务。本文将为您介绍5种最佳且最简单的方法&#xff0c;包括使用Windows系统自带的录音工具来录制电脑音频&#xff0c;在线音频录音软件和专业的第三方电脑录音软件。这些工具都能够很好地帮助您完成电脑怎么…

在树莓派上安装中文输入法

在树莓派上安装中文输入法&#xff0c;可以使用 fcitx 输入法框架&#xff0c;它支持多种中文输入法&#xff0c;如拼音、五笔等。以下是详细步骤&#xff1a; 1. 更新系统 首先&#xff0c;确保你的系统是最新的&#xff1a; sudo apt update sudo apt upgrade2. 安装 fcit…

江苏高防IP对网络安全有何作用?

网络科技在快速发展的过程中&#xff0c;网络安全问题也日益增加&#xff0c;许多网站行业和服务器会受到DDOS攻击和CC攻击等多种恶意的网络攻击&#xff0c;这些攻击给企业带来了巨大的经济损失&#xff0c;同时也导致服务器出现瘫痪和网站无法正常运行的情况&#xff0c;为了…

一款十六进制编辑器,你的瑞士军刀!!【送源码】

软件介绍 ImHex是一款功能强大的十六进制编辑器&#xff0c;专为逆向工程师、程序员以及夜间工作的用户设计。它不仅提供了基础的二进制数据编辑功能&#xff0c;还集成了一系列高级特性&#xff0c;使其成为分析和修改二进制文件的理想工具。 功能特点 专为逆向工程、编程和夜…

verilog实现PID控制

1 原理讲解 距离上一次说PID算法的事情过去蛮久了&#xff0c;今天又重新看了看PID的代码&#xff0c;其实还是存在一些不合理的地方。 整理归纳了一下原理&#xff0c;位置式和增量式的变化。 2 工程实现 timescale 1ns / 1psmodule pid_controller(input clk,input r…

075、Python 关于异常处理try-except语句的使用

在实际应用中&#xff0c;比如涉及文件读写、网络通信时&#xff0c;会因为文件不存在、权限不够、网络异常等原因引发异常&#xff0c;或者对数据库连接、查询、更新等操作&#xff0c;会因为连接超时、语法错误、唯一约束冲突等引发异常。 在Java或C#等语言中我们使用try-ca…

【ARM系列】GIC600AE功能安全

GIC600AE在原GIC600版本基础上增加了FuSa功能&#xff0c;所增加的FuSa特性都集成在GIC600外围&#xff0c;不会改变原GIC600的功能。 GIC600AE主要安全机制分布图&#xff1a; GIC-600AE包含以下FuSa安全机制&#xff1a; lockstep logic protection 通过添加duplication l…

C++ 类与对象(中)

C 类与对象&#xff08;中&#xff09; 1. 类的6个默认成员函数2. 构造函数2.1 概念2.2 特性 3.析构函数3.1 概念3.2 特性 4. 拷贝构造函数4.1 概念4.2 特征 5.赋值运算符重载5.1 运算符重载5.2 赋值运算符重载 1. 类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c…

数据库操作-DML和DQL

DML DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进行增、删、改操作。 添加数据&#xff08;INSERT&#xff09; 1.指定字段添加数据&#xff1a; insert into 表名 ( 字段名 1, 字段名 2) values ( 值 1, 值 2); 2…

【面试题】TLS和SSL协议的区别

TLS&#xff08;Transport Layer Security&#xff09;和SSL&#xff08;Secure Sockets Layer&#xff09;协议都是用于在网络上建立安全通信连接的协议&#xff0c;但它们在多个方面存在区别。以下是TLS和SSL协议之间区别的详细分析&#xff1a; 1. 发展历程与标准化 SSL&a…

Qt | 2D 时钟设计

01、重点内容公布 Qt | windows Qt6.5.3安卓环境搭建成功版(保姆级教程)VS2022 配置Qt编译环境 | winows安装Qt5.14.2 | VS2017和Qt5配置成功指南

企业本地大模型用Ollama+Open WebUI+Stable Diffusion可视化问答及画图

最近在尝试搭建公司内部用户的大模型&#xff0c;可视化回答&#xff0c;并让它能画图出来&#xff0c; 主要包括四块&#xff1a; Ollama 管理和下载各个模型的工具Open WebUI 友好的对话界面Stable Diffusion 绘图工具Docker 部署在容器里&#xff0c;提高效率 以上运行环境…

高薪程序员必修课-Spring中如果核心线程数为0,线程池会如何执行

目录 前言 线程池的原理 核心线程数为0的情况 示例代码 示例解释 运行示例 示例运行分析 总结 前言 在Spring&#xff08;以及底层的Java Executor 框架&#xff09;中&#xff0c;如果线程池的核心线程数设置为0&#xff0c;线程池的行为将受到影响。了解这种情况下线程…

python库 - json

文章目录 主要功能常用函数1. json.dumps()2. json.loads()3. json.dump()4. json.load() 自定义序列化和反序列化自定义序列化自定义反序列化 json 是 Python 标准库中的一个模块&#xff0c;用于处理 JSON&#xff08;JavaScript Object Notation&#xff09;数据格式。JSON …

17-Pandas缺失值处理

Python Pandas缺失值处理 在一些数据分析业务中&#xff0c;数据缺失是我们经常遇见的问题&#xff0c;缺失值会导致数据质量的下降&#xff0c;从而影响模型预测的准确性&#xff0c;这对于机器学习和数据挖掘影响尤为严重。因此妥善的处理缺失值能够使模型预测更为准确和有效…

20240627构造专题

写在前面&#xff1a;出场即巅峰&#xff08;明日模拟赛RP&#xff09; 一.何为构造 就是通过对一道题题面的分析可以发现某种规律&#xff08;类似于不完全归纳法&#xff09;&#xff0c;然后发掘本质&#xff0c;就可以很快的解题&#xff0c;但是显然我还没有掌握 二.一…