I'm trying to load PCI config space data into python for evaluation, but am running into an issue with using a c_unit32 for BAR0. I've managed to simplify the issue / script to show c_uint16 behaving as I expect, but the c_uint32 failing. Bar0 must be a c_unit32 as in the actual script, the Bar0 is decoded as a separate struct which uses bits 0-13 for various fields, then bits 14:31 for the lower BAR.
In the script, data is loaded from /sys/pci/bus/devices/x/config, so comes back as a string of hex characters, this is emulated in the example by loading a smaller string to represent only a few of the fields
Expected:
Input string: "86802010f6710000"
VendorID : 0x8086
DeviceID : 0x1020
Bar0 : 0x71f60000
Actual:
Input string: "86802010f6710000"
VendorID : 0x8086
DeviceID : 0x1020
Bar0 : 0x71f6
The VendorID and DeviceID fields are correctly swapped. I presume the "0000" is being byte swapped and being put infront of the f671, and the f671 is then byte swapped to be 71f6. The leading 00s are then eliminated creating "0x71f6". This is confirmed if I use "f6710100" which becomes 0x171f6.
How can I ensure when I use the c_uint32 that it is correctly interpreted as 0x71f60000?
Code:
from ctypes import *
class PCICfg(Structure):
_pack_ = 1
_fields_ = [
("VendorID", c_uint16),
("DeviceID", c_uint16),
("Bar0", c_uint32),
]
class PCIUnion(Union):
_pack_ = 1
_fields_ = [
("ConfigSpace", PCICfg),
("Bytes", c_ubyte * sizeof(PCICfg))
]
def from_str(self, input):
print("Input String: ", input)
hex_data = bytearray.fromhex(input)
for x in range(0, len(hex_data)):
self.Bytes[x] = hex_data[x]
if __name__ == '__main__':
cfg = PCIUnion()
cfg.from_str("86802010f6710100")
print("VID: %s" % hex(cfg.ConfigSpace.VendorID))
print("DID: %s" % hex(cfg.ConfigSpace.DeviceID))
print("BA0: %s" % hex(cfg.ConfigSpace.Bar0))
What you are seeing is the correct little-endian 32-bit result of your input, but if your input is really a hex representation of little-endian 16-bit words, then treat it that way:
from ctypes import *
from binascii import unhexlify
class PCICfg(Structure):
_pack_ = 1
_fields_ = [("VendorID", c_uint16),
("DeviceID", c_uint16),
("Bar0Hi", c_uint16),
("Bar0Lo", c_uint16)]
class PCIUnion(Union):
_pack_ = 1
_fields_ = [("ConfigSpace", PCICfg),
("Bytes", c_ubyte * sizeof(PCICfg))]
def from_str(self, inp):
print("Input String: ", inp)
self.Bytes[:] = unhexlify(inp)
if __name__ == '__main__':
cfg = PCIUnion()
cfg.from_str("86802010f6710100")
print("VID: {:#04x}".format(cfg.ConfigSpace.VendorID))
print("DID: {:#04x}".format(cfg.ConfigSpace.DeviceID))
print("BA0: {:#04x}{:04x}".format(cfg.ConfigSpace.Bar0Hi,cfg.ConfigSpace.Bar0Lo))
Input String: 86802010f6710100
VID: 0x8086
DID: 0x1020
BA0: 0x71f60001
Related
I am trying to get the SendInput function from user32.dll to work in python using ctypes.I am a noob but from what I read from the docs you have to create the structs the function requires in python and then pass it to the function.
import ctypes
import keyboard
from ctypes import *
lib = windll.user32
KEYEVENTF_SCANCODE = 0x8
KEYEVENTF_KEYUP = 0x2
SPACEBAR = 57 # 0x39
INPUT_KEYBOARD = 1
class KEYBDINPUT(Structure):
_fields_ = [('wVk' , c_ushort) , ('wScan' , c_ushort)
, ('dwFlags' , c_ulong) , ('time' , c_ulong) , ('dwExtraInfo' , c_ulong)]
class INPUT(Structure):
_fields_ = [('type' , c_ulong) ,('ki' , KEYBDINPUT)]
lib.SendInput.restype = c_uint
lib.SendInput.argtypes = [c_uint , INPUT , c_int]
keybdinput_obj = KEYBDINPUT(0 , SPACEBAR , KEYEVENTF_SCANCODE , 0 , 0)
input_obj = INPUT(INPUT_KEYBOARD , keybdinput_obj)
keyboard.wait('u')
lib.SendInput(1 , byref(input_obj) , sizeof(INPUT))
keybdinput_obj = KEYBDINPUT(0 , SPACEBAR , KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP , 0 , 0)
input_obj = INPUT(INPUT_KEYBOARD , keybdinput_obj)
lib.SendInput(1 , byref(input_obj) , sizeof(INPUT))
In the microsoft docs at which I guided myself from the INPUT struct had an union but i figured if I would only need the KEYBDINPUT then it's the same thing as if i had an union.
https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-input
https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-keybdinput
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput
I pretty much got stuck because i can't see what's going wrong here so I am asking for help.The program is supposed to send a space after i press 'u' on the keyboard (this was for debugging purposes) and i do it this way because i want it to send as a scancode instead of a virtual keypress.
So if there is another way in python with with which you can send scancodes , that'll work and I would appreciate it a lot .
Define the whole union, or at least MOUSEINPUT, which is the largest member of the union. You can test that your definition is the correct size by print(sizeof(INPUT)) and it should agree with printing the size of an INPUT structure in a C program. I got size 28 for 32-bit and 40 for 64-bit C structure.
Also, your second parameter to SendInput is POINTER(INPUT), not INPUT, and ULONG_PTR is not necessarily c_ulong because it depends on running 32-bit or 64-bit Python.
Here's a tested example:
import ctypes
from ctypes import *
from ctypes import wintypes as w
KEYEVENTF_SCANCODE = 0x8
KEYEVENTF_UNICODE = 0x4
KEYEVENTF_KEYUP = 0x2
SPACE = 0x39
INPUT_KEYBOARD = 1
# not defined by wintypes
ULONG_PTR = c_ulong if sizeof(c_void_p) == 4 else c_ulonglong
class KEYBDINPUT(Structure):
_fields_ = [('wVk' ,w.WORD),
('wScan',w.WORD),
('dwFlags',w.DWORD),
('time',w.DWORD),
('dwExtraInfo',ULONG_PTR)]
class MOUSEINPUT(Structure):
_fields_ = [('dx' ,w.LONG),
('dy',w.LONG),
('mouseData',w.DWORD),
('dwFlags',w.DWORD),
('time',w.DWORD),
('dwExtraInfo',ULONG_PTR)]
class HARDWAREINPUT(Structure):
_fields_ = [('uMsg' ,w.DWORD),
('wParamL',w.WORD),
('wParamH',w.WORD)]
class DUMMYUNIONNAME(Union):
_fields_ = [('mi',MOUSEINPUT),
('ki',KEYBDINPUT),
('hi',HARDWAREINPUT)]
class INPUT(Structure):
_anonymous_ = ['u']
_fields_ = [('type',w.DWORD),
('u',DUMMYUNIONNAME)]
print(sizeof(INPUT))
lib = WinDLL('user32')
lib.SendInput.argtypes = w.UINT,POINTER(INPUT),c_int
lib.SendInput.restype = w.UINT
def send_scancode(code):
i = INPUT()
i.type = INPUT_KEYBOARD
i.ki = KEYBDINPUT(0,code,KEYEVENTF_SCANCODE,0,0)
lib.SendInput(1,byref(i),sizeof(INPUT))
i.ki.dwFlags |= KEYEVENTF_KEYUP
lib.SendInput(1,byref(i),sizeof(INPUT))
def send_unicode(s):
i = INPUT()
i.type = INPUT_KEYBOARD
for c in s:
i.ki = KEYBDINPUT(0,ord(c),KEYEVENTF_UNICODE,0,0)
lib.SendInput(1,byref(i),sizeof(INPUT))
i.ki.dwFlags |= KEYEVENTF_KEYUP
lib.SendInput(1,byref(i),sizeof(INPUT))
send_scancode(SPACE)
send_unicode('The quick brown fox jumped over the lazy dog')
Output on terminal running 64-bit Python 3.6:
C:\>example
40
C:\> The quick brown fox jumped over the lazy dog
I've got some troubles with using "GetExtendedTcpTable". When I tried to run my script, i've got message like this:
AssertionError: [Error 0] The operation completed successfully
Rarely script working normally, I dont understand this message, Operation completed, what`s wrong?
This is code, i tried to execute:
from ctypes import *
from ctypes.wintypes import *
from socket import inet_aton, inet_ntoa, htons
AF_INET = 2
TCP_TABLE_BASIC_LISTENER = 0
TCP_TABLE_BASIC_CONNECTIONS = 1
TCP_TABLE_BASIC_ALL = 2
TCP_TABLE_OWNER_PID_LISTENER = 3
TCP_TABLE_OWNER_PID_CONNECTIONS = 4
TCP_TABLE_OWNER_PID_ALL = 5
TCP_TABLE_OWNER_MODULE_LISTENER = 6
TCP_TABLE_OWNER_MODULE_CONNECTIONS = 7
TCP_TABLE_OWNER_MODULE_ALL = 8
# for storing socket info python style.
class socket_info:
State = None
LocalAddr = None
LocalPort = None
RemoteAddr = None
RemotePort = None
def __init__ (self, **kwargs):
for key, word in kwargs.items():
setattr(self, key, word)
def formatip (ip):
ip = inet_aton (str(ip))
return inet_ntoa (ip[::-1])
states = {
1 : "TCP_STATE_CLOSED",
2 : "TCP_STATE_LISTEN",
3 : "TCP_STATE_SYN_SENT",
4 : "TCP_STATE_SYN_RCVD",
5 : "TCP_STATE_ESTAB",
6 : "TCP_STATE_FIN_WAIT",
7 : "TCP_STATE_FIN_WAIT2",
8 : "TCP_STATE_CLOSE_WAIT",
9 : "TCP_STATE_CLOSING",
10 : "TCP_STATE_LAST_ACK",
11 : "TCP_STATE_TIME_WAIT",
12 : "TCP_STATE_DELETE_TCB",
"TCP_STATE_CLOSED" : 1,
"TCP_STATE_LISTEN" : 2,
"TCP_STATE_SYN_SENT" : 3,
"TCP_STATE_SYN_RCVD" : 4,
"TCP_STATE_ESTAB" : 5,
"TCP_STATE_FIN_WAIT" : 6,
"TCP_STATE_FIN_WAIT2" : 7,
"TCP_STATE_CLOSE_WAIT" : 8,
"TCP_STATE_CLOSING" : 9,
"TCP_STATE_LAST_ACK" :10,
"TCP_STATE_TIME_WAIT" : 11,
"TCP_STATE_DELETE_TCB" : 12 }
class MIB_TCPROW_OWNER_PID(Structure):
_fields_ = [
("dwState", DWORD),
("dwLocalAddr", DWORD),
("dwLocalPort", DWORD),
("dwRemoteAddr", DWORD),
("dwRemotePort", DWORD),
("dwOwningPid", DWORD)
]
class MIB_TCPTABLE_OWNER_PID(Structure):
_fields_ = [
("dwNumEntries", DWORD),
("MIB_TCPROW_OWNER_PID", MIB_TCPROW_OWNER_PID * 100)
]
def GetExtendedTcpTable (vip=AF_INET):
table = MIB_TCPTABLE_OWNER_PID ()
so = sizeof (table)
size = DWORD (so)
order = c_int(1)
failure= windll.iphlpapi.GetExtendedTcpTable (
byref (table),
addressof (size),
order,
vip,
TCP_TABLE_OWNER_PID_ALL,
0 )
assert not failure, WinError (GetLastError ())
pytables = []
tables = table.MIB_TCPROW_OWNER_PID
for index in range(table.dwNumEntries):
table = tables [index]
pytables.append (
socket_info (
State=states.get (table.dwState, "UNKNOWN_STATE_%s" %(str(table.dwState))),
LocalAddr=formatip (table.dwLocalAddr),
LocalPort=htons(table.dwLocalPort),
RemoteAddr=formatip (table.dwRemoteAddr),
RemotePort=htons(table.dwRemotePort),
OwningPid = int (table.dwOwningPid)
)
)
return pytables
def GetTcpTableForPid (pid):
tables = GetExtendedTcpTable ()
for table in tables:
if table.OwningPid == pid: return table
raise "Cannot find tcp table for pid %s" %pid
dict_process = {}
pid_set =set()
pid_list = []
tcp_info_list = []
tcp_info = GetExtendedTcpTable()
for item in tcp_info:
LocalAddr = item.LocalAddr
LocalPort = item.LocalPort
RemoteAddr = item.RemoteAddr
RemotePort = item.RemotePort
OwningPid = item.OwningPid
print('local Addr: '+ LocalAddr,'local port: '+ str(LocalPort),'remote Addr: ' + RemoteAddr, 'Remote Port: ' + str(RemotePort), OwningPid)
The script is run from time to time. It can run for 5 minutes and then don't work about an hour with this stupid mistake. How to get around it?
I really dont know, what's with it. Please, help me, what i do wrong?
I use python 3.2 on Win7 SP1 x64
Thank you a lot!
You shouldn't use addressof(size). That returns a Python integer which will be cast as a 32-bit C int. Use byref(size) to create a pointer, which will be a 64-bit value if you're using 64-bit Python.
GetExtendedTcpTable doesn't call SetLastError. It returns a DWORD with one of the following codes:
NO_ERROR = 0
ERROR_INVALID_PARAMETER = 87
ERROR_INSUFFICIENT_BUFFER = 122
The pdwSize argument has the required size if the buffer was too small. One option here is to start with a length 0 array; then resize the struct; and finally cast the array to the correct size:
class MIB_TCPTABLE_OWNER_PID(Structure):
_fields_ = [
("dwNumEntries", DWORD),
("MIB_TCPROW_OWNER_PID", MIB_TCPROW_OWNER_PID * 0),
]
_GetExtendedTcpTable = windll.iphlpapi.GetExtendedTcpTable
def GetExtendedTcpTable(vip=AF_INET):
table = MIB_TCPTABLE_OWNER_PID()
size = DWORD()
order = 1
failure = _GetExtendedTcpTable(
byref(table),
byref(size),
order,
vip,
TCP_TABLE_OWNER_PID_ALL,
0)
if failure == ERROR_INSUFFICIENT_BUFFER:
resize(table, size.value)
memset(byref(table), 0, sizeof(table))
failure = _GetExtendedTcpTable(
byref(table),
byref(size),
order,
vip,
TCP_TABLE_OWNER_PID_ALL,
0)
if failure:
raise WinError(failure)
ptr_type = POINTER(MIB_TCPROW_OWNER_PID * table.dwNumEntries)
tables = cast(table.MIB_TCPROW_OWNER_PID, ptr_type)[0]
pytables = []
for table in tables:
# rest unchanged
Regarding the Win32 LastError value, in general you shouldn't rely on GetLastError in Python. You don't know if you're seeing an old error code from a previous call or if an intervening call modified the LastError value. If you're checking a single API call that uses LastError, then it should be OK to check GetLastError immediately afterward if the call failed. But more generally you may need to load the DLL with use_last_error=True:
iphlpapi = WinDLL('iphlpapi', use_last_error=True)
Function pointers created from this WinDLL instance will save LastError to thread local storage immediately after the call returns. Calling get_last_error returns the saved error code. Beforehand you can call set_last_error(0) to have 0 swapped in to LastError before the function is called.
I have a binary file with a known format/structure.
How do I read all the binary data in to an array of the structure?
Something like (in pseudo code)
bytes = read_file(filename)
struct = {'int','int','float','byte[255]'}
data = read_as_struct(bytes, struct)
data[1]
>>> 10,11,10.1,Arr[255]
My solution so far is:
data = []
fmt = '=iiiii256i'
fmt_s = '=iiiii'
fmt_spec = '256i'
struct_size = struct.calcsize(fmt)
for i in range(struct_size, len(bytes)-struct_size, struct_size):
dat1= list(struct.unpack(fmt_s, bytes[i-struct_size:i-1024]))
dat2= list(struct.unpack(fmt_spec, bytes[i-1024:i]))
dat1.append(dat2)
data.append(dat1)
Actually it looks like you're trying to read a list (or array) of structures from the file. The idiomatic way to do this in Python is use the struct module and call struct.unpack() in a loop—either a fixed number of times if you know the number of them in advance, or until end-of-file is reached—and store the results in a list. Here's an example of the latter:
import struct
struct_fmt = '=5if255s' # int[5], float, byte[255]
struct_len = struct.calcsize(struct_fmt)
struct_unpack = struct.Struct(struct_fmt).unpack_from
results = []
with open(filename, "rb") as f:
while True:
data = f.read(struct_len)
if not data: break
s = struct_unpack(data)
results.append(s)
The same results can be also obtained slightly more concisely using a list comprehension along with a short generator function helper (i.e. read_chunks() below):
def read_chunks(f, length):
while True:
data = f.read(length)
if not data: break
yield data
with open(filename, "rb") as f:
results = [struct_unpack(chunk) for chunk in read_chunks(f, struct_len)]
Update
You don't, in fact, need to explicitly define a helper function as shown above because you can use Python's built-in iter() function to dynamically create the needed iterator object in the list comprehension itself like so:
from functools import partial
with open(filename, "rb") as f:
results = [struct_unpack(chunk) for chunk in iter(partial(f.read, struct_len), b'')]
Use the struct module; you need to define the types in a string format documented with that library:
struct.unpack('=HHf255s', bytes)
The above example expects native byte-order, two unsigned shorts, a float and a string of 255 characters.
To loop over an already fully read bytes string, I'd use itertools; there is a handy grouper recipe that I've adapted here:
from itertools import izip_longest, imap
from struct import unpack, calcsize
fmt_s = '=5i'
fmt_spec = '=256i'
size_s = calcsize(fmt_s)
size = size_s + calcsize(fmt_spec)
def chunked(iterable, n, fillvalue=''):
args = [iter(iterable)] * n
return imap(''.join, izip_longest(*args, fillvalue=fillvalue))
data = [unpack(fmt_s, section[:size_s]) + (unpack(fmt_spec, section[size_s:]),)
for section in chunked(bytes, size)]
This produces tuples rather than lists, but it's easy enough to adjust if you have to:
data = [list(unpack(fmt_s, section[:size_s])) + [list(unpack(fmt_spec, section[size_s:]))]
for section in chunked(bytes, size)]
Add comments
import struct
First just read the binary into an array
mbr = file('mbrcontent', 'rb').read()
So you can just fetch some piece of the the array
partition_table = mbr[446:510]
and then unpack it as an integer
signature = struct.unpack('<H', mbr[510:512])[0]
a more complex example
little_endian = (signature == 0xaa55) # should be True
print "Little endian:", little_endian
PART_FMT = (little_endian and '<' or '>') + (
"B" # status (0x80 = bootable (active), 0x00 = non-bootable)
# CHS of first block
"B" # Head
"B" # Sector is in bits 5; bits 9 of cylinder are in bits 7-6
"B" # bits 7-0 of cylinder
"B" # partition type
# CHS of last block
"B" # Head
"B" # Sector is in bits 5; bits 9 of cylinder are in bits 7-6
"B" # bits 7-0 of cylinder
"L" # LBA of first sector in the partition
"L" # number of blocks in partition, in little-endian format
)
PART_SIZE = 16
fmt_size = struct.calcsize(PART_FMT)
# sanity check expectations
assert fmt_size == PART_SIZE, "Partition format string is %i bytes, not %i" % (fmt_size, PART_SIZE)
def cyl_sector(sector_cyl, cylinder7_0):
sector = sector_cyl & 0x1F # bits 5-0
# bits 7-6 of sector_cyl contain bits 9-8 of the cylinder
cyl_high = (sector_cyl >> 5) & 0x03
cyl = (cyl_high << 8) | cylinder7_0
return sector, cyl
#I have corrected the indentation, but the change is refused because less than 6 characters, so I am adding this useful comment.
for partition in range(4):
print "Partition #%i" % partition,
offset = PART_SIZE * partition
(status, start_head, start_sector_cyl, start_cyl7_0, part_type, end_head, end_sector_cyl, end_cyl7_0,
lba, blocks ) = struct.unpack( PART_FMT,partition_table[offset:offset + PART_SIZE])
if status == 0x80:
print "Bootable",
elif status:
print "Unknown status [%s]" % hex(status),
print "Type=0x%x" % part_type
start = (start_head,) + cyl_sector(start_sector_cyl, start_cyl7_0)
end = (end_head,) + cyl_sector(end_sector_cyl, end_cyl7_0)
print " (Start: Heads:%i\tCyl:%i\tSect:%i)" % start
print " (End: Heads:%i\tCyl:%i\tSect:%i)" % end
print " LBA:", lba
print " Blocks:", blocks
import os, re
import functools
import ctypes
from ctypes import string_at, byref, sizeof, cast, POINTER, pointer, create_string_buffer, memmove
import numpy as np
import pandas as pd
class _StructBase(ctypes.Structure):
__type__ = 0
_fields_ = []
#classmethod
def Offsetof(cls, field):
pattern = '(?P<field>\w+)\[(?P<idx>\d+)\]'
mat = re.match(pattern, field)
if mat:
fields = dict(cls.Fields())
f = mat.groupdict()['field']
idx = mat.groupdict()['idx']
return cls.Offsetof(f) + int(idx) * ctypes.sizeof(fields[field])
else:
return getattr(cls, field).offset
#classmethod
def DType(cls):
map = {
ctypes.c_byte: np.byte,
ctypes.c_ubyte: np.ubyte,
ctypes.c_char: np.ubyte,
ctypes.c_int8: np.int8,
ctypes.c_int16: np.int16,
ctypes.c_int32: np.int32,
ctypes.c_int64: np.int64,
ctypes.c_uint8: np.uint8,
ctypes.c_uint16: np.uint16,
ctypes.c_uint32: np.uint32,
ctypes.c_uint64: np.uint64,
ctypes.c_float: np.float32,
ctypes.c_double: np.float64,
}
res = []
for k, v in cls.Fields():
if hasattr(v, '_length_'):
if v._type_ != ctypes.c_char:
for i in range(v._length):
res.append((k, map[v], cls.Offsetof(k)))
else:
res.append((k, 'S%d' % v._length_, cls.Offsetof(k)))
else:
res.append((k, map[v], cls.Offsetof(k)))
res = pd.DataFrame(res, columns=['name', 'format', 'offset'])
return np.dtype({
'names': res['name'],
'formats': res['format'],
'offsets': res['offset'],
})
#classmethod
def Attr(cls):
fields = cls._fields_
res = []
for attr, tp in fields:
if str(tp).find('_Array_') > 0 and str(tp).find('char_Array_') < 0:
for i in range(tp._length_):
res.append((attr + '[%s]' % str(i), tp._type_))
else:
res.append((attr, tp))
return res
#classmethod
def Fields(cls, notype=False):
res = [cls.Attr()]
cur_cls = cls
while True:
cur_cls = cur_cls.__bases__[0]
if cur_cls == ctypes.Structure:
break
res.append(cur_cls.Attr())
if notype:
return [k for k, v in functools.reduce(list.__add__, reversed(res), [])]
else:
return functools.reduce(list.__add__, reversed(res), [])
#classmethod
def size(cls):
return sizeof(cls)
#classmethod
def from_struct_binary(cls, path, max_count=2 ** 32, decode=True):
print(os.path.getsize(path), cls.size())
assert os.path.getsize(path) % cls.size() == 0
size = os.path.getsize(path) // cls.size()
size = min(size, max_count)
index = range(size)
array = np.fromfile(path, dtype=cls.DType(), count=size)
df = pd.DataFrame(array, index=index)
for attr, tp in eval(str(cls.DType())):
if re.match('S\d+', tp) is not None and decode:
try:
df[attr] = df[attr].map(lambda x: x.decode("utf-8"))
except:
df[attr] = df[attr].map(lambda x: x.decode("gbk"))
return df
class StructBase(_StructBase):
_fields_ = [
('Type', ctypes.c_uint32),
]
class IndexStruct(StructBase):
_fields_ = [
('Seq', ctypes.c_uint32),
('ExID', ctypes.c_char * 8),
('SecID', ctypes.c_char * 8),
('SecName', ctypes.c_char * 16),
('SourceID', ctypes.c_int32),
('Time', ctypes.c_uint32),
('PreClose', ctypes.c_uint32),
('Open', ctypes.c_uint32),
('High', ctypes.c_uint32),
('Low', ctypes.c_uint32),
('Match', ctypes.c_uint32),
]
df = IndexStruct.from_struct_binary('your path')
print(df)
I'm working on a captive portal projet on Windows. I've written this piece of code (similar to this) :
from ctypes import wintypes
import ctypes
WlanApi = ctypes.windll.wlanapi
hClientHandle = wintypes.HANDLE()
phClientHandle = ctypes.pointer(hClientHandle)
dwNegotiatedVersion = wintypes.DWORD()
pdwNegotiatedVersion = ctypes.pointer(dwNegotiatedVersion)
dwClientVersion = wintypes.DWORD()
dwClientVersion.value = 2L
rc = WlanApi.WlanOpenHandle(dwClientVersion, None, pdwNegotiatedVersion, phClientHandle)
print rc
class GUID(ctypes.Structure):
_fields_ = [("Data1", wintypes.DWORD),
("Data2", wintypes.WORD),
("Data3", wintypes.WORD),
("Data4", wintypes.BYTE * 8)]
class WLAN_INTERFACE_INFO (ctypes.Structure):
_fields_ = [('InterfaceGuid', GUID),
('strInterfaceDescription', wintypes.WCHAR * 256),
('isState', wintypes.????)]
class WLAN_INTERFACE_INFO_LIST(ctypes.Structure):
_fields_ = [('dwNumberOfItems', wintypes.DWORD),
('dwIndex', wintypes.DWORD),
('InterfaceInfo', WLAN_INTERFACE_INFO * 10)]
IfList = WLAN_INTERFACE_INFO_LIST()
pIfList = ctypes.pointer(IfList)
rc = WlanApi.WlanEnumInterfaces(hClientHandle, None, pIfList)
print rc
print "Num Entries: %s" % IfList.dwNumberOfItems
I can't find how to structure "WLAN_INTERFACE_STATE enumeration" and when I try with a WCHAR array or anything else, this script return my 6000000 wireless interfaces !!!
Can somebody help me?
It's just an integer, there is no structure 0 = Not ready, 1 = connected etc.
Hmm it starts to make sense,as most of these structs have a corresponding pointer.
According to the boys at PInvoke
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct WLAN_INTERFACE_INFO
{
/// GUID->_GUID
public Guid InterfaceGuid;
/// WCHAR[256]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string strInterfaceDescription;
/// WLAN_INTERFACE_STATE->_WLAN_INTERFACE_STATE
public WLAN_INTERFACE_STATE isState;
}
Where WLAN_INTERFACE_STATE is
public enum WLAN_INTERFACE_STATE
{
wlan_interface_state_not_ready = 0,
...
// 1 to 6
...
wlan_interface_state_authenticating = 7,
}
PInvoke on WLAN...
I have the below arrays on C how can i interpert them to ctypes datatypes inside structre
struct a {
BYTE a[30];
CHAR b[256];
};
should i interpert a fixed array as the datatype * the size i want like the below and if yes how can i
call this structure as a parameter to fun that takes instance from this structure
class a(structure) :
_fields_ = [ ("a",c_bytes*30 ),
("b",c_char*256 ),]
You're on the right track. You're probably just missing the byref() function. Assuming the function you want to call is named *print_struct*, do the following:
from ctypes import *
class MyStruct(Structure):
_fields_ = [('a',c_byte*30), ('b',c_char*256)]
s = MyStruct() # Allocates a new instance of the structure from Python
s.a[5] = 10 # Use as normal
d = CDLL('yourdll.so')
d.print_struct( byref(s) ) # byref() passes a pointer rather than passing by copy
This should work:
from ctypes import Structure, c_bytes, c_char
class A(Structure):
_fields_ = [("a", c_bytes*30), ("b", c_char*256)]
Then you can simply access the fields of the structure using the dot operator:
>>> my_a = A()
>>> my_a.a[4] = 127
>>> my_a.a[4]
127
>>> my_a.b = "test string"
>>> my_a.b
'test string'
>>> my_a.b[2]
's'
You can also pass the structure directly to an arbitrary Python function:
def my_func(a):
print "a[0] + a[1] = %d" % (a.a[0] + a.a[1], )
print "Length of b = %d" % len(a.b)
>>> my_a = A()
>>> my_a.a[0:2] = 19, 23
>>> my_a.b = "test"
>>> my_func(my_a)
a[0] + a[1] = 42
Length of b = 4