Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.56/34: Рейтинг темы: голосов - 34, средняя оценка - 4.56
182 / 33 / 3
Регистрация: 28.05.2015
Сообщений: 148

Серийный номер железа или как ещё привязать к компьютеру?

31.01.2017, 12:50. Показов 7462. Ответов 28
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
При помощи VB6 как сделать привязку программы? По SN материнки, процессора, жёсткого диска, сетевой карты и т.д.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
31.01.2017, 12:50
Ответы с готовыми решениями:

Как в реестре или при помощи cmd посмотреть серийный номер материнской платы ?
Добрый день! Может кто сказать, как в реестре посмотреть серийный номер материнской платы или как при помощи cmd посмотреть на удаленной...

Серийный номер процессора или жесткого диска или материнки
Парни, помогите пожалуйста, очень нужен пример на delphi 7 как считать серийный номер ПРОЦЕССОРА или МАТЕРИНСКОЙ ПЛАТЫ или ЖЕСТКОГО ДИСКА...

Серийный номер материнской платы или винчестера
Здравствуйте! Как узнать серийный номер материнской платы или винчестера под lubuntu 15.04? Спасибо

28
 Аватар для dr_Morro
195 / 115 / 30
Регистрация: 05.08.2013
Сообщений: 491
31.01.2017, 13:23
тык
или ТЫК
Или ещё ТЫК
0
Заблокирован
31.01.2017, 13:32
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
SN ... жёсткого диска
Visual Basic
1
MsgBox CreateObject("Scripting.FileSystemObject").GetDrive("C:").SerialNumber, , "SN Drive C:"
0
31.01.2017, 13:34

Не по теме:

Shersh, Я намекаю про поиск по форуму...

0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
31.01.2017, 13:36
Лучший ответ Сообщение было отмечено CharlyChaplin как решение

Решение

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Private Function GetMACAddress( _
                 ByRef bData() As Byte) As Boolean
    Dim bAdapterInfo()  As Byte
    Dim lRet            As Long
    Dim lSize           As Long
    Dim bMACAddress()   As Byte
    Dim lMACAddresSize  As Long
    
    ' // Get MAC address
    lSize = &H288
    ReDim bAdapterInfo(lSize - 1)
 
    lRet = GetAdaptersInfo(bAdapterInfo(0), lSize)
    
    If lRet = ERROR_BUFFER_OVERFLOW Then
    
        ReDim bAdapterInfo(lSize - 1)
        lRet = GetAdaptersInfo(bAdapterInfo(0), lSize)
        
    End If
 
    If lRet = 0 Then
        
        GetMem4 bAdapterInfo(&H190), lMACAddresSize
        
        If lMACAddresSize > 0 Then
            
            ReDim bData(lMACAddresSize - 1)
            memcpy bData(0), bAdapterInfo(&H194), lMACAddresSize
            
            GetMACAddress = True
            
        End If
        
    End If
    
End Function
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Private Function GetCPUIDInfo( _
                 ByRef bData() As Byte) As Boolean
    Dim pCode       As Long
    Dim types()     As Integer
    Dim list()      As Long
    Dim param()     As Variant
    
    pCode = VirtualAlloc(0&, &H1000, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
    If pCode = 0 Then Exit Function
    
    GetMem8 -842598367924536.4653@, ByVal pCode
    GetMem8 -857273203654571.5132@, ByVal pCode + 8
    GetMem8 88933012021608.5599@, ByVal pCode + &H10
    GetMem8 3762050.5183@, ByVal pCode + &H18
    
    ReDim bData(&H20 - 1)
    ReDim types(1)
    ReDim list(1)
    ReDim param(1)
    
    param(0) = VarPtr(bData(0)):    param(1) = 0&
    types(0) = vbLong:              types(1) = vbLong
    list(0) = VarPtr(param(0)):     list(1) = VarPtr(param(1))
    
    DispCallFunc 0, pCode, CC_STDCALL, vbEmpty, 2, types(0), list(0), Null
    
    param(0) = VarPtr(bData(&H10)): param(1) = 1&
    
    DispCallFunc 0, pCode, CC_STDCALL, vbEmpty, 2, types(0), list(0), Null
    
    VirtualFree pCode, 0, MEM_RELEASE
    
    GetCPUIDInfo = True
    
End Function
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
Private Function GetHDDInfo( _
                 ByRef bData() As Byte) As Boolean
    Dim guidDiskInterface   As Guid
    Dim hSet                As Long
    Dim tInterfaceData      As SP_DEVICE_INTERFACE_DATA
    Dim lDeviceIndex        As Long
    Dim lRequiredSize       As Long
    Dim pDataDetail         As Long
    Dim hDisk               As Long
    Dim tDiskNumber         As STORAGE_DEVICE_NUMBER
    Dim bLocalData()        As Byte
    Dim lSize               As Long
    Dim lLocalSize          As Long
    Dim lIndex              As Long
    
    ' // GUID_DEVINTERFACE_DISK {53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
    With guidDiskInterface
    
        .Data1 = &H53F56307
        .Data2 = &HB6BF
        .Data3 = &H11D0
        .Data4(0) = &H94
        .Data4(1) = &HF2
        .Data4(2) = &H0
        .Data4(3) = &HA0
        .Data4(4) = &HC9
        .Data4(5) = &H1E
        .Data4(6) = &HFB
        .Data4(7) = &H8B
        
    End With
    
    hSet = SetupDiGetClassDevs(guidDiskInterface, 0&, 0&, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
    If hSet = INVALID_HANDLE_VALUE Then Exit Function
    
    tInterfaceData.cbSize = Len(tInterfaceData)
    
    Do While SetupDiEnumDeviceInterfaces(hSet, ByVal 0&, guidDiskInterface, lDeviceIndex, tInterfaceData)
    
        SetupDiGetDeviceInterfaceDetail hSet, tInterfaceData, ByVal 0&, _
                                        0, lRequiredSize, ByVal 0&
        If Err.LastDllError <> ERROR_INSUFFICIENT_BUFFER Then GoTo continue
        
        If pDataDetail Then HeapFree GetProcessHeap(), HEAP_NO_SERIALIZE, pDataDetail
        
        pDataDetail = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE, lRequiredSize)
        If pDataDetail = 0 Then GoTo continue
        
        GetMem4 6&, ByVal pDataDetail   ' // sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)
        
        If SetupDiGetDeviceInterfaceDetail(hSet, tInterfaceData, ByVal pDataDetail, _
                        lRequiredSize, 0, ByVal 0&) = 0 Then GoTo continue
        
        If hDisk <> INVALID_HANDLE_VALUE And hDisk <> 0 Then CloseHandle (hDisk)
        
        hDisk = CreateFile(pDataDetail + 4, GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, _
                            ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
        If hDisk = INVALID_HANDLE_VALUE Then GoTo continue
        
        If DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, ByVal 0&, 0, tDiskNumber, _
                            Len(tDiskNumber), 0, ByVal 0&) = 0 Then GoTo continue
                            
        If Not GetPhysicalDriveInfo(tDiskNumber.DeviceNumber, bLocalData()) Then GoTo continue
        
        lLocalSize = SafeArrayElementsCount(Not Not bLocalData)
        
        If lLocalSize > 0 Then
            
            ReDim Preserve bData(lIndex + 31)
 
            HashData bLocalData(0), lLocalSize, bData(lIndex), 32
            
            lIndex = lIndex + 32
            
        End If
        
continue:
        
        lDeviceIndex = lDeviceIndex + 1
        
    Loop
 
    If hDisk <> INVALID_HANDLE_VALUE And hDisk <> 0 Then CloseHandle (hDisk)
    If pDataDetail Then HeapFree GetProcessHeap(), HEAP_NO_SERIALIZE, pDataDetail
    If hSet <> INVALID_HANDLE_VALUE Then SetupDiDestroyDeviceInfoList (hSet)
    
    GetHDDInfo = True
    
End Function
 
Private Function GetPhysicalDriveInfo( _
                 ByVal lDeviceIndex As Long, _
                 ByRef bData() As Byte) As Boolean
    Dim sDevicePath     As String
    Dim hDevice         As Long
    Dim tProp           As STORAGE_PROPERTY_QUERY
    Dim tHeader         As STORAGE_DESCRIPTOR_HEADER
    Dim pOutBuffer      As Long
    Dim lOffset         As Long
    Dim lLength         As Long
    Dim bPropSerial()   As Byte
    Dim bPropVendor()   As Byte
    Dim bPropModel()    As Byte
    Dim bSmartSerial()  As Byte
    Dim bSmartModel()   As Byte
    Dim pArray          As Long
    
    sDevicePath = "\\.\PhysicalDrive" & CStr(lDeviceIndex)
    
    hDevice = CreateFile(StrPtr(sDevicePath), GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or _
                         FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
    If hDevice = INVALID_HANDLE_VALUE Then Exit Function
    
    tProp.PropertyId = StorageDeviceProperty
    tProp.QueryType = PropertyStandardQuery
    
    If DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, tProp, LenB(tProp), tHeader, _
                        Len(tHeader), 0, ByVal 0&) = 0 Then GoTo CleanUp
                        
    pOutBuffer = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE, tHeader.Size)
    If pOutBuffer = 0 Then GoTo CleanUp
    
    If DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, tProp, LenB(tProp), ByVal pOutBuffer, _
                        tHeader.Size, 0&, ByVal 0&) = 0 Then GoTo SMART_METHOD
                                        
    GetMem4 ByVal pOutBuffer + &H18, lOffset
    
    If lOffset Then
    
        lLength = lstrlenA(ByVal pOutBuffer + lOffset)
        If lLength > 0 Then
            
            ReDim bPropSerial(lLength - 1)
            memcpy bPropSerial(0), ByVal pOutBuffer + lOffset, lLength
 
        End If
 
    End If
    
    GetMem4 ByVal pOutBuffer + &HC, lOffset
    
    If lOffset Then
    
        lLength = lstrlenA(ByVal pOutBuffer + lOffset)
        If lLength > 0 Then
            
            ReDim bPropVendor(lLength - 1)
            memcpy bPropVendor(0), ByVal pOutBuffer + lOffset, lLength
 
        End If
 
    End If
    
    GetMem4 ByVal pOutBuffer + &H10, lOffset
    
    If lOffset Then
    
        lLength = lstrlenA(ByVal pOutBuffer + lOffset)
        If lLength > 0 Then
            
            ReDim bPropModel(lLength - 1)
            memcpy bPropModel(0), ByVal pOutBuffer + lOffset, lLength
 
        End If
 
    End If
    
SMART_METHOD:
 
    Dim tCmdIn          As SENDCMDINPARAMS
    Dim tCmdOut         As SENDCMDOUTPARAMS
    Dim tSmartVersion   As GETVERSIONOUTPARAMS
    Dim lIndex          As Long
    
    If DeviceIoControl(hDevice, SMART_GET_VERSION, ByVal 0&, 0, tSmartVersion, _
                       Len(tSmartVersion), 0, 0) = 0 Then GoTo COLLECT_INFO
                     
    tCmdIn.cBufferSize = 512
    tCmdIn.irDriveRegs.bCommandReg = ID_CMD
    
    If DeviceIoControl(hDevice, SMART_RCV_DRIVE_DATA, tCmdIn, LenB(tCmdIn), _
                       tCmdOut, LenB(tCmdOut), 0, ByVal 0&) = 0 Then GoTo COLLECT_INFO
                       
    ReDim bSmartSerial(19)
    ReDim bSmartModel(39)
    
    memcpy bSmartSerial(0), tCmdOut.bBuffer(&H14), 20
    memcpy bSmartModel(0), tCmdOut.bBuffer(&H36), 40
    
COLLECT_INFO:
    
    lLength = SafeArrayElementsCount(Not Not bPropSerial) + _
              SafeArrayElementsCount(Not Not bPropModel) + _
              SafeArrayElementsCount(Not Not bPropVendor) + _
              SafeArrayElementsCount(Not Not bSmartSerial) + _
              SafeArrayElementsCount(Not Not bSmartModel) + 5 * 2
              
    ReDim bData(lLength - 1)
    lOffset = 0
    
    For lIndex = 0 To 4
        
        Select Case lIndex
        Case 0: pArray = Not Not bPropSerial
        Case 1: pArray = Not Not bPropVendor
        Case 2: pArray = Not Not bPropModel
        Case 3: pArray = Not Not bSmartSerial
        Case 4: pArray = Not Not bSmartModel
        End Select
        
        lLength = SafeArrayElementsCount(pArray)
        
        If lLength Then
            
            Select Case lIndex
            Case 0: pArray = VarPtr(bPropSerial(0))
            Case 1: pArray = VarPtr(bPropVendor(0))
            Case 2: pArray = VarPtr(bPropModel(0))
            Case 3: pArray = VarPtr(bSmartSerial(0))
            Case 4: pArray = VarPtr(bSmartModel(0))
            End Select
            
            memcpy bData(lOffset), ByVal pArray, lLength
            lOffset = lOffset + lLength
            
        End If
        
        bData(lOffset) = 13
        bData(lOffset + 1) = 10
        
        lOffset = lOffset + 2
            
    Next
 
    GetPhysicalDriveInfo = True
    
CleanUp:
 
    If pOutBuffer Then HeapFree GetProcessHeap(), HEAP_NO_SERIALIZE, pOutBuffer
    CloseHandle hDevice
    
End Function
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Private Function GetComputerInfo( _
                 ByRef bData() As Byte) As Boolean
    Dim lLength As Long
    
    lLength = MAX_COMPUTERNAME_LENGTH + 1
    
    ReDim bData(lLength - 1)
    
    GetComputerName bData(0), lLength
    
    If lLength > 0 Then
    
        ReDim Preserve bData(lLength - 1)
        GetComputerInfo = True
        
    Else
        Erase bData
    End If
 
End Function
5
182 / 33 / 3
Регистрация: 28.05.2015
Сообщений: 148
31.01.2017, 16:24  [ТС]
Иногда удивляюсь The trick. Такие вещи знает. Я тоже программирую: могу решить нужные задачи, продумать логику приложения, но как дело заходит о выудить что-то из ОС или поработать с памятью или API - проблема.
0
182 / 33 / 3
Регистрация: 28.05.2015
Сообщений: 148
06.02.2017, 07:12  [ТС]
Пытаюсь выполнить функцию GetCPUIDInfo. Почему выполнение VirtualAlloc выдаёт 0?
*** Форма: ***
Кликните здесь для просмотра всего текста
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Const MEM_COMMIT As Long = &H1000
Const MEM_RESERVE As Long = &H2000
Const PAGE_EXECUTE_READWRITE As Long = &H40
Const MEM_RELEASE As Long = &H8000
Const CC_STDCALL As Long = 4&
 
 
Private Function GetCPUIDInfo( _
                 ByRef bData() As Byte) As Boolean
    Dim pCode       As Long
    Dim types()     As Integer
    Dim list()      As Long
    Dim param()     As Variant
    
    pCode = VirtualAlloc(0&, &H1000, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
    If pCode = 0 Then MsgBox "Вылет": Exit Function
    
    GetMem8 -842598367924536.4653@, ByVal pCode
    GetMem8 -857273203654571.5132@, ByVal pCode + 8
    GetMem8 88933012021608.5599@, ByVal pCode + &H10
    GetMem8 3762050.5183@, ByVal pCode + &H18
    
    ReDim bData(&H20 - 1)
    ReDim types(1)
    ReDim list(1)
    ReDim param(1)
    
    param(0) = VarPtr(bData(0)):    param(1) = 0&
    types(0) = vbLong:              types(1) = vbLong
    list(0) = VarPtr(param(0)):     list(1) = VarPtr(param(1))
    
    DispCallFunc 0, pCode, CC_STDCALL, vbEmpty, 2, types(0), list(0), Null
    
    param(0) = VarPtr(bData(&H10)): param(1) = 1&
    
    DispCallFunc 0, pCode, CC_STDCALL, vbEmpty, 2, types(0), list(0), Null
    
    VirtualFree pCode, 0, MEM_RELEASE
    
    GetCPUIDInfo = True
    
End Function
 
Private Sub Form_Load()
   Dim bData() As Byte
   
   MsgBox GetCPUIDInfo(bData)
End Sub


*** Модуль ***
Кликните здесь для просмотра всего текста
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Public Declare Function VirtualAlloc Lib "kernel32.dll" ( _
    ByRef lpAddress As Any, _
    ByVal dwSize As Long, _
    ByVal flAllocationType As Long, _
    ByVal flProtect As Long) As Long
    
Public Declare Sub GetMem8 Lib "msvbvm60" (ByVal Addr As Long, RetVal As Long)
 
Public Declare Sub DispCallFunc Lib "oleaut32.dll" ( _
    ByRef pvInstance As Any, _
    ByVal oVft As Long, _
    ByVal cc As Integer, _
    ByVal vtReturn As Integer, _
    ByVal cActuals As Long, _
    ByRef prgvt As Integer, _
    ByRef prgpvarg As Variant, _
    ByRef pvargResult As Variant)
    
Public Declare Function VirtualFree Lib "kernel32.dll" ( _
    ByRef lpAddress As Any, _
    ByVal dwSize As Long, _
    ByVal dwFreeType As Long) As Long
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
06.02.2017, 08:42
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
ByRef lpAddress As Any
ByVal
1
182 / 33 / 3
Регистрация: 28.05.2015
Сообщений: 148
06.02.2017, 10:21  [ТС]
Поискал информацию про GetMem N. Если я правильно понял, то N это 1, 2, 4, 8 - это тоже самое как и ассемблерная команда mov с передачей 1, 2, 4, 8 байт в al, ax, eax регистры. Короче, передаваемые данные через N-разрядные регистры.

Я не совсем понимаю, какая разрядность у бейсиковского типа Long? Почему первый же GetMem не может передать 64-битное число в "лонговую" переменную pCode из-за переполнения?

Если я правильно понял, то инструкциями mov последовательно в память через каждые 8 байт ложатся 64-х разрядные числа. Что это за числа?
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
06.02.2017, 11:05
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Поискал информацию про GetMem N. Если я правильно понял, то N это 1, 2, 4, 8 - это тоже самое как и ассемблерная команда mov с передачей 1, 2, 4, 8 байт в al, ax, eax регистры. Короче, передаваемые данные через N-разрядные регистры.
GetMem принимает 2 адреса, откуда и куда копировать данные. 1,2,4,8 - размер. Это тоже самое что и RtlMoveMemory (CopyMemory), только быстрее.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Я не совсем понимаю, какая разрядность у бейсиковского типа Long? Почему первый же GetMem не может передать 64-битное число в "лонговую" переменную pCode из-за переполнения?
Long - 4 байта. В данном случае pCode - это адрес куда копировать 8 байтовые числа.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Если я правильно понял, то инструкциями mov последовательно в память через каждые 8 байт ложатся 64-х разрядные числа. Что это за числа?
Это асемблерный код:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CPU Disasm
Address                        Hex dump          Command                                  Comments
00500000                         53              PUSH EBX
00500001                         52              PUSH EDX
00500002                         57              PUSH EDI
00500003                         8B7CE4 10       MOV EDI,DWORD PTR SS:[ESP+10]
00500007                         8B44E4 14       MOV EAX,DWORD PTR SS:[ESP+14]
0050000B                         0FA2            CPUID
0050000D                         8907            MOV DWORD PTR DS:[EDI],EAX
0050000F                         895F 04         MOV DWORD PTR DS:[EDI+4],EBX
00500012                         894F 08         MOV DWORD PTR DS:[EDI+8],ECX
00500015                         8957 0C         MOV DWORD PTR DS:[EDI+0C],EDX
00500018                         5F              POP EDI
00500019                         5A              POP EDX
0050001A                         5B              POP EBX
0050001B                         C2 0800         RETN 8
1
182 / 33 / 3
Регистрация: 28.05.2015
Сообщений: 148
06.02.2017, 14:15  [ТС]
Я вас ещё не достал?
Всё же мне интересно, как работает функция GetCPUIDInfo и, в частности, вышеприведённый ассемблерный листинг. Хочется разобраться в программе, а не тупо копировать код. Немного покурил MSDN. Сорри за мой обывательский язык. Вот как я понимаю программу:

1. Сначала при помощи VirtualAlloc выделяем 4Кб памяти с правами "чтение/запись". Адрес, где начинается выделенное пространство, помещаем в "лонговую" переменную pCode.
2. Встроенной библиотечной функцией Getmem8, пачками(по 8 байт) передаём ассемблерный код в выделенную область памяти.
3. Потом производятся какие-то переопределения массивов и непонятный для меня код:
Visual Basic
1
2
3
    param(0) = VarPtr(bData(0)):    param(1) = 0&
    types(0) = vbLong:              types(1) = vbLong
    list(0) = VarPtr(param(0)):     list(1) = VarPtr(param(1))
4. Вызывается код, по адресу в pCode. Код рассматривается как функция с 2-мя параметрами.
5. В param(0) помещается &H10-ый элемент массива bData(), а в param(1) - единица.
6. Снова вызывается код по адресу в pCode.
7. Освобождаем использованную область памяти для операционной системы.

Также пытался разобраться в ассемблерном листинге:
Где после сохранения в стеке текущих значений регистров, в EDI и EAX заносим адреса из SS:[ESP+10] и SS:[ESP+14], соответственно. Я так понимаю, они выполняют роль аргументов для функции. Потом даётся непосредственная CPUID-инструкция. А далее результат выполнения оказывается в EAX, EBX, ECX и EDX, откуда мы и переносим их в сегмент данных. Ну и из стека данные возвращаем на место в свои регистры.
Если я правильно понимаю, цель ассемблерного листинга в том, что напрямую из VB нельзя обратиться к инструкции CPUID и приходится делать это с самого низа? Ещё вопрос, откуда взялись значения в SS:[ESP+10] и SS:[ESP+14]? Я имею ввиду, кто их туда поместил?

Также вопрос по-поводу 3-го пункта. Какие действия там производятся, зачем мы переопределили массивы и что означает запись: types(0) = vbLong и types(1) = vbLong?
DispCallFunc вызывается 2 раза, а параметры вызова одинаковы. Для чего вызывается она 2 раза?
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
06.02.2017, 20:50
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
1. Сначала при помощи VirtualAlloc выделяем 4Кб памяти с правами "чтение/запись". Адрес, где начинается выделенное пространство, помещаем в "лонговую" переменную pCode.
Да, только права чтение/запись/исполнение.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
2. Встроенной библиотечной функцией Getmem8, пачками(по 8 байт) передаём ассемблерный код в выделенную область памяти.
Да.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
3. Потом производятся какие-то переопределения массивов и непонятный для меня код:
Это подготавливаются данные для функции DispCallFunc которая используется для вызова кода по указателю.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
4. Вызывается код, по адресу в pCode. Код рассматривается как функция с 2-мя параметрами.
Да, первый параметр это адрес куда будут копироваться данные инструкции CPUID, второй - индекс для инструкции.
Массив param - это непосредственно параметры функции, types - типы параметров.
Первый вызов - передается первый элемент массива, функция заполняет 16 байт с индексом 0.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
5. В param(0) помещается &H10-ый элемент массива bData(), а в param(1) - единица.
6. Снова вызывается код по адресу в pCode.
Второй вызов - передается уже 16-й параметр с индексом 1.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Где после сохранения в стеке текущих значений регистров, в EDI и EAX заносим адреса из SS:[ESP+10] и SS:[ESP+14], соответственно.
ESP+14 - это второй аргумент функции, ESP+10 - первый. CPUID принимает входящий параметр в регистре EAX поэтому туда и копируем второй аргумент. EDI инструкция CPUID не изменяет, поэтому туда заносится первый аргумент. После CPUID мы просто копируем данные по адресу EDI (первый аргумент) с разным смещением.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Если я правильно понимаю, цель ассемблерного листинга в том, что напрямую из VB нельзя обратиться к инструкции CPUID и приходится делать это с самого низа?
Я бы заюзал свой инлайн ассемблер, но этот код я делал не для себя поэтому не использовал дополнительный Add-in для того чтобы код работал на любой IDE.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Ещё вопрос, откуда взялись значения в SS:[ESP+10] и SS:[ESP+14]? Я имею ввиду, кто их туда поместил?
Я . Это адреса аргументов. Вот смотри, если бы мы не сохраняли регистры в стеке push'ами, то адрес первого аргумента был бы ESP+4 (т.к. дополнительно ложится адрес возврата 4 байта), второго ESP+8, но мы сделали 3 push'а - 12 байт. 4 + 12 = 16 = 0x10.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Также вопрос по-поводу 3-го пункта. Какие действия там производятся, зачем мы переопределили массивы и что означает запись: types(0) = vbLong и types(1) = vbLong?
Функция DispCallFunc принимает не только параметры, но и их типы. Вместо этого можно применить любые другие методы вызова по указателю.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
DispCallFunc вызывается 2 раза, а параметры вызова одинаковы. Для чего вызывается она 2 раза?
На самом деле параметры разные, второй вызов принимает первым аргументом адрес 16 элемента и индекс = 1.
2
182 / 33 / 3
Регистрация: 28.05.2015
Сообщений: 148
09.02.2017, 10:36  [ТС]
Ещё вопрос:
Я не смог найти связи между
Visual Basic
1
2
3
4
    GetMem8 -842598367924536.4653@, ByVal pCode
    GetMem8 -857273203654571.5132@, ByVal pCode + 8
    GetMem8 88933012021608.5599@, ByVal pCode + &H10
    GetMem8 3762050.5183@, ByVal pCode + &H18
и

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
00500000                         53              PUSH EBX
00500001                         52              PUSH EDX
00500002                         57              PUSH EDI
00500003                         8B7CE4 10       MOV EDI,DWORD PTR SS:[ESP+10]
00500007                         8B44E4 14       MOV EAX,DWORD PTR SS:[ESP+14]
0050000B                         0FA2            CPUID
0050000D                         8907            MOV DWORD PTR DS:[EDI],EAX
0050000F                         895F 04         MOV DWORD PTR DS:[EDI+4],EBX
00500012                         894F 08         MOV DWORD PTR DS:[EDI+8],ECX
00500015                         8957 0C         MOV DWORD PTR DS:[EDI+0C],EDX
00500018                         5F              POP EDI
00500019                         5A              POP EDX
0050001A                         5B              POP EBX
0050001B                         C2 0800         RETN 8
То есть взяли код на асме в HEX-виде и перевели в целое число? Тогда первое размещаемое в памяти значение -842598367924536.4653@ в HEX-е должно быть что-то вроде FFFD 01A9 4797 6EC8, но в коде я не нашёл таких HEX-комбинаций. Или я не правильно понял суть? Кстати, а что означает символ @?

В вашем блоге про Inline-ассеблер вы написали:

"Бывают ситуации когда в VB нужно использовать ассемблер. Обычно для этого используют предварительно скомпилированный код размещенный в памяти и запускают его одним из миллиона способов. Очевидным недостатком этого метода является то, что любая модификация ассемблерного кода требует изменения в процедурах размещения кода в памяти. К тому же это является довольно медленной процедурой."

Правильно ли я понял, что недостаток выражается в том, что любых ошибках придётся заново компилировать код и брать шестнадцатеричные числа(например из отладчика) и вставлять их в проект Visual Basic? В нашем случае они были переведены в другую систему счисления? И я не совсем понимаю, что означает формулировка: "...требует изменения в процедурах размещения кода в памяти...". Изменения в каких процедурах например?
Почему я задал такой вопрос, потому как первая же операция Getmem у меня вызывает ошибку "Overflow". Так как код "заморожен", т.е. его не исправить в IDE, то придётся либо отдельно его компилировать заново и вставлять новый HEX в проект, либо использовать вашу разработку из блога про Inline-Ассеблер, что я и хочу сделать.
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
09.02.2017, 10:45
-842598367924536.4653@ - это Currency значение т.е. знаковое 64 битное число деленое не 1000, поэтому чтобы узнать hex значение умножаем на 1000 и смотрим Hex значение полученного числа -842598367924536465310=0x8B10E47C8B57525316.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Кстати, а что означает символ @?
Суффикс типа Currency.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Правильно ли я понял, что недостаток выражается в том, что любых ошибках придётся заново компилировать код и брать шестнадцатеричные числа(например из отладчика) и вставлять их в проект Visual Basic?
Да.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
В нашем случае они были переведены в другую систему счисления?
Да.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
И я не совсем понимаю, что означает формулировка: "...требует изменения в процедурах размещения кода в памяти...". Изменения в каких процедурах например?
Ну к примеру нужно будет вставить куда-нибудь в середину какой-нибудь inc eax, и все данные за ним сдвинутся, соответственно и коды изменятся.
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Почему я задал такой вопрос, потому как первая же операция Getmem у меня вызывает ошибку "Overflow".
Не должно быть такого, вероятно декларация неправильная:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
Private Declare Function GetMem1 Lib "msvbvm60" ( _
                         ByRef src As Any, _
                         ByRef dst As Any) As Long
Private Declare Function GetMem2 Lib "msvbvm60" ( _
                         ByRef src As Any, _
                         ByRef dst As Any) As Long
Private Declare Function GetMem4 Lib "msvbvm60" ( _
                         ByRef src As Any, _
                         ByRef dst As Any) As Long
Private Declare Function GetMem8 Lib "msvbvm60" ( _
                         ByRef src As Any, _
                         ByRef dst As Any) As Long
1
182 / 33 / 3
Регистрация: 28.05.2015
Сообщений: 148
09.02.2017, 12:41  [ТС]
Блин, получилось наконец! Я оказывается ещё и неправильную декларацию DispCallFunc сделал. Исправил. Всё работает.
Спасибо большое.
0
182 / 33 / 3
Регистрация: 28.05.2015
Сообщений: 148
13.02.2017, 12:12  [ТС]
Немного поэкспериментировал с программой.
Есть два компьютера с процессорами: Pentium D и Core i5. Запуск программы производился как из IDE, так и простым exe-файлом, который был скомпилирован как на Pentium D, так и на Core i5. Результаты находятся в байтовом массиве, но байты для удобства я вывел строкой в MsgBox. Итак:

Если запуск производится на Pentium D:
1.) в IDE, то 13 0 0 0 71 101 110 117 110 116 101 108 105 110 101 73 169 6 3 0 0 8 16 2 191 227 186 127 255 251 235 191
2.) exe, скомпилированном в Pentium D, то 13 0 0 0 71 101 110 117 110 116 101 108 105 110 101 73 169 6 3 0 0 8 16 2 191 227 186 127 255 251 235 191
3.) exe, скомпилированном в Core i5, то 13 0 0 0 71 101 110 117 110 116 101 108 105 110 101 73 169 6 3 0 0 8 16 0 191 227 186 127 255 251 235 191

Если запуск производится на Core i5:
1.) в IDE, то 6 0 0 0 71 101 110 117 110 116 101 108 105 110 101 73 98 15 0 0 0 8 2 1 61 228 0 0 255 251 235 191
2.) exe, скомпилированном на Core i5, то 6 0 0 0 71 101 110 117 110 116 101 108 105 110 101 73 98 15 0 0 0 8 2 1 61 228 0 0 255 251 235 191
3.) exe, скомпилированном на Pentium D, то 6 0 0 0 71 101 110 117 110 116 101 108 105 110 101 73 98 15 0 0 0 8 2 1 61 228 0 0 255 251 235 191

То есть, отличие в одном байте, когда компиляция идёт на процессоре старой модели, то при запуске готового exe на новой модели байты разнятся.
Но если компилировать exe на новой модели, то результаты будут одинаковы что на новой, что на старой модели CPU.
Также я заметил, что иногда 24-й байт изменяется то на 1, то на 0, то на 2 - если просто запускать несколько раз exe.
Иногда первый байт меняется на 6, 3 или 13.
Тогда возникает вопрос, можно ли привязываться к компьютеру, если ID не постоянен, хотя определённые его части, всё-таки, не изменчивы.

Добавлено через 31 минуту
Вопрос ещё осложняется тем, что мне важна именно неизменчивость данных. В моём приложении я беру CPUID, превращаю его в подобный вышеприведённый строчный вид, только без пробелов, беру из него хеш SHA-256, и часть этого хеша является ключом к зашифрованным данным, которые шифруются криптостойким алгоритмом.
А теперь представьте себе, если вдруг изменится хотя бы одно значение в CPUID. Пользователь просто потеряет свои данные. Это будет катастрофа.(( Поэтому, прежде чем вшивать туда код по выуживанию CPUID, я должен убедиться, что данные не меняются. Но они почему-то меняются. Даже если брать часть CPUID, типа Genuenintel, то ведь он у многих есть, нужен именно уникальный идентификатор.

Добавлено через 1 час 48 минут
Теперь про серийник жёсткого диска. Когда разбирал код, не смог найти описание функции SaveArrayElementsCount. Ну да ладно. Поискал по форуму и здесь нашёл ваш же пост по такой же теме. Тот код работает и показывает серийник именно жёсткого диска. Этот серийник я проверил в программе Everest - всё верно. Но проблема в том, что он не показывается на WinXP, т.к. desc.SerialNumberOffset выдаёт смещение, но в buffer по нему стоят нули. В принципе, вы так и написали в комментарии: "Если он представлен конвертируем его из HEX в строку" На Win7 прекрасно работает. В чём может быть проблема?
1. Необходимо сначала узнать на каком логическом диске запущено моё приложение. 2. затем узнать какому физическому диску сопоставлена буква логического диска 3. и потом уже сверить серийный номер физического диска с заданным. Если верен, то программа запустится.

Добавлено через 4 часа 30 минут
Решил проблему самостоятельно. Помимо HDD Serial, также смог определить Model Number и Firmware Revision. Код работает как на Win7, так и на WinXP. Сверил с показаниями Everest - всё верно.

Но с CPUID я так и не разобрался.
0
39 / 39 / 8
Регистрация: 15.08.2014
Сообщений: 634
14.07.2017, 15:05
Добрый

Добавлено через 44 секунды
Добрый день!
Вам не трудно выложить финальный листинг проекта..
Желательно в архивчике...

Заранее спасибо
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
14.07.2017, 23:39
CharlyChaplin, кинь оба EXE. На разных ядрах может быть разный результат.
0
182 / 33 / 3
Регистрация: 28.05.2015
Сообщений: 148
15.07.2017, 07:32  [ТС]
Определение CPUID (часть кода принадлежит Анатолию):

****** форма(без контролов) ******
Кликните здесь для просмотра всего текста
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Const MEM_COMMIT As Long = &H1000
Const MEM_RESERVE As Long = &H2000
Const PAGE_EXECUTE_READWRITE As Long = &H40
Const MEM_RELEASE As Long = &H8000
Const CC_STDCALL As Long = 4&
 
 
Private Function GetCPUIDInfo( _
                 ByRef bData() As Byte) As Boolean
    Dim pCode       As Long
    Dim types()     As Integer
    Dim list()      As Long
    Dim param()     As Variant
    
    pCode = VirtualAlloc(0&, &H1000, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
    If pCode = 0 Then MsgBox "Вылет": Exit Function
    
    GetMem8 -842598367924536.4653@, ByVal pCode
    GetMem8 -857273203654571.5132@, ByVal pCode + 8
    GetMem8 88933012021608.5599@, ByVal pCode + &H10
    GetMem8 3762050.5183@, ByVal pCode + &H18
    
    ReDim bData(&H20 - 1)
    ReDim types(1)
    ReDim list(1)
    ReDim param(1)
    
    param(0) = VarPtr(bData(0)):    param(1) = 0&
    types(0) = vbLong:              types(1) = vbLong
    list(0) = VarPtr(param(0)):     list(1) = VarPtr(param(1))
    
    DispCallFunc 0, pCode, CC_STDCALL, vbEmpty, 2, types(0), list(0), Null
    
    param(0) = VarPtr(bData(&H10)): param(1) = 1&
    
    DispCallFunc 0, pCode, CC_STDCALL, vbEmpty, 2, types(0), list(0), Null
    
    VirtualFree pCode, 0, MEM_RELEASE
    
    
    GetCPUIDInfo = True
    
End Function
 
Private Sub Form_Load()
   Dim bData() As Byte
   
   Call GetCPUIDInfo(bData)
   MsgBox IsString(bData)
   End
End Sub
 
Function IsString(ByRef bData() As Byte) As String
   Dim i As Integer
   For i = LBound(bData) To UBound(bData)
      IsString = IsString & Trim$(Str$(bData(i))) & " "
   Next i
End Function

****** модуль ******
Кликните здесь для просмотра всего текста
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Public Declare Function VirtualAlloc Lib "kernel32.dll" ( _
    ByVal lpAddress As Any, _
    ByVal dwSize As Long, _
    ByVal flAllocationType As Long, _
    ByVal flProtect As Long) As Long
    
Public Declare Function GetMem8 Lib "msvbvm60" ( _
                         ByRef src As Any, _
                         ByRef dst As Any) As Long
 
Public Declare Function DispCallFunc Lib "oleaut32.dll" ( _
    ByVal pvInstance As Long, _
    ByVal oVft As Long, _
    ByVal cc As Long, _
    ByVal vtReturn As VbVarType, _
    ByVal cActuals As Long, _
    prgvt As Any, _
    prgpvarg As Any, _
    ByRef pvargResult As Variant) As Long
    
Public Declare Function VirtualFree Lib "kernel32.dll" ( _
    ByRef lpAddress As Any, _
    ByVal dwSize As Long, _
    ByVal dwFreeType As Long) As Long


Готовый проект + *.exe находится во Вложении.

Второй EXE-файл смогу скинуть только в понедельник, т.к. Pentium D находится на работе.
Вложения
Тип файла: 7z GetCPUID.7z (5.5 Кб, 18 просмотров)
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
15.07.2017, 09:02
Цитата Сообщение от CharlyChaplin Посмотреть сообщение
Даже если брать часть CPUID, типа Genuenintel, то ведь он у многих есть, нужен именно уникальный идентификатор.
CPUID не предоставляет никаких уникальных идентификаторов. Их там просто нет.
На двух компьютерах с одинаковыми моделями процессоров и одинаковыми настройками BIOS
данные, полученные из CPUID, будут полностью идентичными. Поддержку серийных номеров
из CPUID убрали еще много лет назад. Так что привязываться к CPUID - это ошибочная идея,
она хорошо работать не будет. Уж лучше использовать серийные номера HDD и MAC...
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
15.07.2017, 09:02
Помогаю со студенческими работами здесь

Как привязать программу к компьютеру? (Сделать что-то наподобие лицензии)
Здравствуйте! Изучаю с++ builder, и возникла идея попробовать сделать привязку программы к одному компьютеру. Думал сделать на базе...

Как восстановить серийный номер seomonitor ???
Как восстановить серийный номер seomonitor ??? На одном ноуте стоит лицензионная прога seomonitor . Сам ключ потерял...Как взять ключ...

Как узнать Серийный номер диска?
Как узнать серийный номер диска (например компакта)

Как прочесть серийный номер процессора?
Привет всем! Имеется-ли серийный или какой-нибудь еще номер у процесса или других устройств компьютера? и как эти номера прочесть и VB?

Как вывести серийный номер батареи
Здесь нашел как вывести серийный номер батареи:http://msdn.microsoft.com/en-us/library/aa372698.aspx Но, при нажатии на Button1 в Label1...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru