当前位置: 首页 > news >正文

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

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



解决过程:

用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

相关文章:

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

引言&#xff1a;笔者在工作过程中&#xff0c;用户上报某某市信息科技学业水平测试软件在云电脑上打开初始化的情况下出现了加载和绑定机器失败的问题。一般情况下&#xff0c;在实体机上用户进行登录后&#xff0c;用户的账号信息跟主机的机器码进行绑定然后保存到配置文件&a…...

vue3+antd 实现点击按钮弹出对话框

格式1&#xff1a;确认对话框 按钮&#xff1a; 点击按钮之后&#xff1a; 完整代码&#xff1a; <template><div><a-button click"showConfirm">Confirm</a-button></div> </template> <script setup> import {Mod…...

Python一些可能用的到的函数系列130 UCS-Time Brick

说明 UCS对象是基于GFGoLite进行封装&#xff0c;且侧重于实现UCS规范。 内容 1 函数 我发现pydantic真是一个特别好用的东西&#xff0c;可以确保在数据传递时的可靠&#xff0c;以及对某个数据模型的描述。 以下&#xff0c;UCS给出了id、time相关的brick映射&#xff0…...

Java实现布隆过滤器的几种方式

布隆过滤器应用场景: 为预防大量黑客故意发起非法的时间查询请求,造成缓存击穿,建议采用布隆过滤器的方法解决。布隆过滤器通过一个很长的二进制向量和一系列随机映射函数(哈希函数)来记录与识别某个数据是否在一个集合中。如果数据不在集合中,能被识别出来,不需要到数…...

最新整理的机器人相关数据合集(1993-2022年不等 具体看数据类型)

机器人安装数据是指记录全球或特定区域内工业机器人新安装数量的信息&#xff0c;这一数据由国际机器人联合会(IFR)等权威机构定期发布。这些数据不仅揭示了机器人技术的市场需求趋势&#xff0c;还反映了各国和地区自动化水平及产业升级的步伐。例如&#xff0c;数据显示中国在…...

Python打开Excel文档并读取数据

Python 版本 目前 Python 3 版本为主流版本&#xff0c;这里测试的版本是&#xff1a;Python 3.10.5。 常用库说明 Python 操作 Excel 的常用库有&#xff1a;xlrd、xlwt、xlutils、openpyxl、pandas。这里主要说明下 Excel 文档 .xls 格式和 .xlsx 格式的文档打开和读取。 …...

算法day03 桶排序 数据结构分类 时间复杂度 异或运算

学数据结构之前 必看_哔哩哔哩_bilibili 1.认识复杂度和简单排序算法_哔哩哔哩_bilibili 桶排序&#xff08;Bucket sort&#xff09;------时间复杂度为O(n)的排序方法&#xff08;一&#xff09;_多桶排序时间复杂度-CSDN博客 桶排序 测试场景&#xff1a;数组中有10000个随…...

k8s学习之cobra命令库学习

1.前言 打开k8s代码的时候&#xff0c;我发现基本上那几个核心服务都是使用cobra库作为命令行处理的能力。因此&#xff0c;为了对代码之后的代码学习的有比较深入的理解&#xff0c;因此先基于这个库写个demo&#xff0c;加深对这个库的一些理解吧 2.cobra库的基本简介 Git…...

Spring框架的学习SpringMVC(1)

1.什么是MVC (1)MVC其实就是软件架构的一种设计模式&#xff0c;它将软件的系统分为&#xff0c;&#xff08;视图&#xff0c;模型&#xff0c;控制器&#xff09;三个部分 1.1View(视图) 视图也就是&#xff0c;在浏览器显示的那一个部分&#xff0c;是后端数据的呈现 1.…...

赋值运算符重载和const成员函数和 const函数

文章目录 1.运算符重载(1)(2)运算符重载的语法&#xff1a;(3)运算符重载的注意事项&#xff1a;(4)前置和后置重载区别 2.const成员函数3.取地址及const取地址操作符重载4.总结 1.运算符重载 (1) 我们知道内置类型(整形&#xff0c;字符型&#xff0c;浮点型…)可以进行一系…...

VSCode设置字体大小

方法1&#xff1a;Ctrl 和 Ctrl -&#xff0c;可以控制整个VSCode界面的整体缩放&#xff0c;但是不会调整字体大小 方法2&#xff1a;该方法只能设置编辑器界面的字号&#xff0c;无法改变窗口界面的字号。 &#xff08;1&#xff09;点开左下角如下图标&#xff0c;进入…...

Excel中按列的首行字母顺序,重新排列(VBA脚本)

排序前 要求对4列数据按照第一行abcd的顺序排列 VB脚本如下&#xff1a; 要使用这个脚本&#xff0c;请按照以下步骤操作&#xff1a; 打开Excel&#xff0c;然后按下 Alt F11 打开VBA编辑器。在VBA编辑器中&#xff0c;选择“插入” > “模块”&#xff0c;在打开的模块…...

多线程爬虫技术详解

&#x1f380;引言❤❤ 在当今信息爆炸的时代&#xff0c;网络爬虫&#xff08;Web Crawler&#xff09;作为一种自动获取网页内容的程序&#xff0c;已经成为数据挖掘和信息检索不可或缺的工具。多线程爬虫作为提高爬虫效率的重要手段&#xff0c;通过并行处理技术大幅度提升…...

项目一单机安装基于LNMP结构的WordPress网站 web与数据库服务分离

网站的类型&#xff1a; Jave:LNMT PHP:LNMP Python: LNMU 项目部署&#xff1a; 1.项目的类型&#xff08;项目的开发语言&#xff09; 2.项目运营平台的技术选择 3.尽快让项目运行起来 all in one部署 4. 架构的优化 配置ansible管理环境 配置nginx 配置数据库服务…...

vue事件处理v-on或@

事件处理v-on或 我们可以使用v-on指令&#xff08;简写&#xff09;来监听DOM事件&#xff0c;并在事件触发时执行对应的Javascript。用法&#xff1a;v-on:click"methodName"或click"hander" 事件处理器的值可以是&#xff1a; 内敛事件处理器&#xff1…...

使用OpenCV与PySide(PyQt)的视觉检测小项目练习

OpenCV 提供了丰富的图像处理和计算机视觉功能&#xff0c;可以实现各种复杂的图像处理任务&#xff0c;如目标检测、人脸识别、图像分割等。 PyQt(或PySide)是一个创建GUI应用程序的工具包&#xff0c;它是Python编程语言和Qt库的成功融合。Qt库是最强大的GUI库之一。Qt的快速…...

通信协议_C#实现自定义ModbusRTU主站

背景知识&#xff1a;modbus协议介绍 相关工具 mbslave:充当从站。虚拟串口工具:虚拟出一对串口。VS2022。 实现过程以及Demo 打开虚拟串口工具: 打开mbslave: 此处从站连接COM1口。 Demo实现 创建DLL库&#xff0c;创建ModbusRTU类,进行实现&#xff1a; using Syste…...

【C语言】 —— 编译和链接

【C语言】 —— 编译和链接 一、编译环境和运行环境二、翻译环境2.1、 预处理2.2、 编译&#xff08;1&#xff09;词法分析&#xff08;2&#xff09;语法分析&#xff08;3&#xff09;语义分析 2.3、 汇编2.4、链接 三、运行环境 一、编译环境和运行环境 平时我们说写 C语言…...

DNS正向解析与反向解析实验

正向解析 安装bind软件 [rootlocalhost ~]# dnf install bind bind-utils -y修改主配置文件/etc/named.conf [rootlocalhost ~]# vim /etc/named.conf重启DNS服务&#xff08;named&#xff09; [rootlocalhost ~]# systemctl restart named编辑数据配置文件。在/var/named…...

机器学习简介--NLP(二)

机器学习简介 机器学习简介机器学习例子机器学习分类有监督学习有监督学习的应用 无监督学习 机器学习常见概念数据集k折交叉验证过拟合欠拟合评价指标 机器学习简介 机器学习例子 问题&#xff1a; 2&#xff0c;4&#xff0c;6&#xff0c;8&#xff0c;&#xff1f;&#…...

Winform中使用HttpClient实现调用http的post接口并设置传参content-type为application/json示例

场景 Winform中怎样使用HttpClient调用http的get和post接口并将接口返回json数据解析为实体类&#xff1a; Winform中怎样使用HttpClient调用http的get和post接口并将接口返回json数据解析为实体类_winform解析json-CSDN博客 上面使用HttpClient调用post接口时使用的HttpCon…...

【RAG探索第3讲】LlamaIndex的API调用与本地部署实战

原文链接&#xff1a;【RAG探索第3讲】LlamaIndex的API调用与本地部署实战 今天是2024年7月5日&#xff0c;星期五&#xff0c;天气晴&#xff0c;北京。 RAG的文章也看不少了&#xff0c;今天给大家带来一个llamaindex的实战。分为两个部分&#xff0c;调用ChatGLM的API来用l…...

C# —— 日期对象

DateTime 时间类 存储时间对象 可以获取当前时间 DateTime now DateTime.Now;// 获取当前时间 Console.WriteLine("年:" now.Year);//2023 Console.WriteLine("月:" now.Month);//9 Console.WriteLine("日:" now.Day);//12 Console.WriteLi…...

【MySQL04】【 redo 日志】

文章目录 一、前言二、redo 日志1. redo 日志格式2. Mini-Transaction2.1 以组的形式写入 redo 日志2.2 Mini-Transaction &#xff08;MTR&#xff09;概念 3. redo 日志写入过程3.1 redo 日志缓冲区3.3 redo 日志写入 log buffer 4. redo 日志文件4.1 redo 日志刷盘机制4.2 r…...

Android线性布局的概念与属性

线性布局(LinearLayout)是Android中最简单的布局方式&#xff0c;线性布局方式会使得所有在其内部的控件或子布局按一条水平或垂直的线排列。如图所示&#xff0c;图a是纵向线性布局示意图&#xff0c;图b是横向线性布局示意图。 a&#xff09;纵向线性布局示意图 …...

java反射介绍

Java反射API允许你在运行时检查和修改程序的行为。这意味着你可以动态地创建对象、查看类的字段、方法和构造函数&#xff0c;甚至调用它们。这是一个强大的特性&#xff0c;但也应该谨慎使用&#xff0c;因为它可以破坏封装性。 以下是使用Java反射的一些常见用途&#xff1a;…...

Spring中@Transactional的实现和原理

这篇文章写的很详细了&#xff0c;引自脚本之家 Java中SpringBoot的Transactional原理_java_脚本之家...

华为仓颉可以取代 Java 吗?

大家好&#xff0c;我是君哥。 在最近的华为开发者大会上&#xff0c;华为亮相了仓颉编程语言&#xff0c;这是华为历经 5 年&#xff0c;投入大量研发成本沉淀的一门编程语言。 1 仓颉简介 按照官方报告&#xff0c;仓颉编程语言是一款面向全场景智能的新一代编程语言&#…...

性能测试相关理解(一)

根据学习全栈测试博主的课程做的笔记 一、说明 若未特别说明&#xff0c;涉及术语都是jmeter来说&#xff0c;线程数&#xff0c;就是jmeter线程组中的线程数 二、软件性能是什么 1、用户关注&#xff1a;响应时间 2、业务/产品关注&#xff1a;响应时间、支持多少并发数、…...

缓存-分布式锁-原理和基本使用

分布式锁原理和使用 自旋 public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {Boolean b redisTemplate.opsForValue().setIfAbsent(Lock, Lock, Duration.ofMinutes(1));if (!b) {int i 10;while (i > 0) {Object result redisTe…...