Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
248 lines (190 sloc) 8.99 KB
# Legilimency - Memory Analysis Framework for iOS
# --------------------------------------
#
# Written and maintained by Gal Beniamini <laginimaineb@google.com>
#
# Copyright 2017 Google Inc. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from defs import *
import struct
#The offset of the "rxd" field in the dma_info structure
RXD_OFFSET = 64
#The offset of the "nrxd" field in the dma_info structure
NRXD_OFFSET = 108
#The size of a 64-bit RX descriptor in the DMA descriptor chain
RX_DESC_SIZE = 16
#The offset of the rings_info_ptr field in the PCIe shared structure
RINGS_INFO_PTR_OFFSET = 12 * DWORD_SIZE
#The offset of the flow ring instance array in the PCIe object
FLOW_RINGS_OFFSET = 1328
#The size of a ring_mem entry in the ringmem array
RING_MEM_ENTRY_SIZE = 16
#The number of D2H/H2D rings (not including flow rings!)
NUM_RINGS = 5
#The number of D2H rings (not including flow rings!)
NUM_D2H_RINGS = 3
#The indices of each of the generic H2D/D2H rings (not including flow rings)
H2D_MSGRING_CONTROL_SUBMIT = 0
H2D_MSGRING_RXPOST_SUBMIT = 1
D2H_MSGRING_CONTROL_COMPLETE = 2
D2H_MSGRING_TX_COMPLETE = 3
D2H_MSGRING_RX_COMPLETE = 4
#The offsets of the AppleBCMWLANPCIeSubmissionRing instances for each H2D ring in the PCIe object
H2D_RING_OFFSETS = {H2D_MSGRING_CONTROL_SUBMIT : 1232,
H2D_MSGRING_RXPOST_SUBMIT : 1272}
#The offsets of the AppleBCMWLANPCIeCompletionRing instances for each D2H ring in the PCIe object
D2H_RING_OFFSETS = {D2H_MSGRING_CONTROL_COMPLETE : 1240,
D2H_MSGRING_TX_COMPLETE : 1288,
D2H_MSGRING_RX_COMPLETE : 1280}
#The types of indices present
H2D_WRITE = 0
H2D_READ = 1
D2H_WRITE = 2
D2H_READ = 3
#The hostaddr offsets for each type of index provided, within rings_info structure
INDEX_HOSTADDR_OFFSETS = {H2D_WRITE : 5 * DWORD_SIZE,
H2D_READ : 7 * DWORD_SIZE,
D2H_WRITE : 9 * DWORD_SIZE,
D2H_READ : 11 * DWORD_SIZE}
class BCMHostDongleInterface(object):
"""
This class allows inspection of the H2D/D2H communication between the BCM chip and the host.
"""
def __init__(self, bcmclient):
"""
Creates a new instance, using the underlying BCMClient to communicate with the Wi-Fi SoC.
"""
self.bcmclient = bcmclient
self.client = bcmclient.client
def dump_rx_descriptors(self, dma_object_addr):
"""
Dumps each RXD in the given DMA object.
"""
rxd = self.bcmclient.fw_read32(dma_object_addr + RXD_OFFSET)
nrxd = struct.unpack("<HH", struct.pack("<I", self.bcmclient.fw_read32(dma_object_addr + NRXD_OFFSET)))[0]
print "rxd: %X" % rxd
print "nrxd: %X" % nrxd
for i in range(0, nrxd):
print "desc[%d] : 0x%016X" % (i, self.bcmclient.fw_read64(rxd + RX_DESC_SIZE*i + QWORD_SIZE))
def get_pciedev_shared_t_addr(self):
"""
Returns the address of the pciedev_shared_t structure.
"""
return self.bcmclient.fw_read32(self.bcmclient.ram_offset + self.bcmclient.ram_size - DWORD_SIZE)
def dump_pcie_rings(self):
"""
Dumps the information about each of the PCIe rings.
"""
pciedev_shared_t_addr = self.bcmclient.fw_read32(self.bcmclient.ram_offset + self.bcmclient.ram_size - DWORD_SIZE)
rings_info_ptr = self.bcmclient.fw_read32(pciedev_shared_t_addr + RINGS_INFO_PTR_OFFSET)
ringmem_ptr = self.bcmclient.fw_read32(rings_info_ptr)
print "rings_info_ptr: %X" % rings_info_ptr
print "pciedev_shared_t_addr: 0x%08X" % pciedev_shared_t_addr
print "ringmem_ptr: %X" % ringmem_ptr
for i in range(0, NUM_RINGS):
ring_mem_entry = self.bcmclient.fw_read(ringmem_ptr + i * RING_MEM_ENTRY_SIZE)
(_, _, _, max_items, len_items, ringaddr) = struct.unpack("<HBBHHQ", ring_mem_entry)
ringaddr_ptr = ringmem_ptr + (i + 1) * RING_MEM_ENTRY_SIZE - QWORD_SIZE
ringaddr = self.bcmclient.fw_read64(ringaddr_ptr)
print "ring : %d" % i
print "max_items: %d, len_items: %d" % (max_items, len_items)
print "ringaddr_ptr: %X, ringaddr: %X " % (ringaddr_ptr, ringaddr)
def get_index_hostaddr(self, index_type):
"""
Returns the hostaddr (IO-Space address) of the index type provided
"""
pciedev_shared_t_addr = self.bcmclient.fw_read32(self.bcmclient.ram_offset + self.bcmclient.ram_size - DWORD_SIZE)
rings_info_ptr = self.bcmclient.fw_read32(pciedev_shared_t_addr + RINGS_INFO_PTR_OFFSET)
return self.bcmclient.fw_read32(rings_info_ptr + INDEX_HOSTADDR_OFFSETS[index_type])
def get_h2d_w_idx_hostaddr(self):
"""
Returns the address of the h2d_w_idx_hostaddr field in the rings_info_ptr
"""
return self.get_index_hostaddr(H2D_WRITE)
def get_h2d_r_idx_hostaddr(self):
"""
Returns the address of the h2d_r_idx_hostaddr field in the rings_info_ptr
"""
return self.get_index_hostaddr(H2D_READ)
def get_d2h_w_idx_hostaddr(self):
"""
Returns the address of the d2h_w_idx_hostaddr field in the rings_info_ptr
"""
return self.get_index_hostaddr(D2H_WRITE)
def get_d2h_r_idx_hostaddr(self):
"""
Returns the address of the d2h_r_idx_hostaddr field in the rings_info_ptr
"""
return self.get_index_hostaddr(D2H_READ)
def get_ring_instance(ring_index):
"""
Returns the ring instance for the corresponding ring index
"""
pcie_obj = self.bcmclient.get_pcie_obj()
if ring_index in H2D_RING_OFFSETS:
clazz = AppleBCMWLANPCIeSubmissionRing
off = H2D_RING_OFFSETS[ring_index]
elif ring_index in D2H_RING_OFFSETS:
clazz = AppleBCMWLANPCIeCompletionRing
off = D2H_RING_OFFSETS[ring_index]
else:
raise Exception("Invalid ring index: %d" % ring_index)
return clazz(self.client, self.client.read(pcie_obj + off), ring_index)
def get_h2d_msgring_control_submit_ring(self):
"""
Returns the AppleBCMWLANPCIeSubmissionRing instance for ring #0 (H2D_MSGRING_CONTROL_SUBMIT)
"""
return self.get_ring_instance(H2D_MSGRING_CONTROL_SUBMIT)
def get_h2d_msgring_rxpost_submit_ring(self):
"""
Returns the AppleBCMWLANPCIeSubmissionRing instance for ring #1 (H2D_MSGRING_RXPOST_SUBMIT)
"""
return self.get_ring_instance(H2D_MSGRING_RXPOST_SUBMIT)
def get_d2h_msgring_control_complete_ring(self):
"""
Returns the AppleBCMWLANPCIeCompletionRing instance for ring #2 (D2H_MSGRING_CONTROL_COMPLETE)
"""
return self.get_ring_instance(D2H_MSGRING_CONTROL_SUBMIT)
def get_d2h_msgring_tx_complete_ring(self):
"""
Returns the AppleBCMWLANPCIeCompletionRing instance for ring #3 (D2H_MSGRING_TX_COMPLETE)
"""
return self.get_ring_instance(D2H_MSGRING_TX_COMPLETE)
def get_d2h_msgring_rx_complete_ring(self):
"""
Returns the AppleBCMWLANPCIeCompletionRing instance for ring #4 (D2H_MSGRING_RX_COMPLETE)
"""
return self.get_ring_instance(D2H_MSGRING_RX_COMPLETE)
def get_flow_ring(self, flow_id):
"""
Returns the flow ring corresponding to the given flow ID
"""
pcie_obj = self.bcmclient.get_pcie_obj()
obj_addr = self.client.read64(pcie_obj + flow_id * QWORD_SIZE + FLOW_RINGS_OFFSET)
if obj_addr == 0:
return None
return AppleBCMWLANPCIeSubmissionRing(self.client, obj_addr, flow_id + NUM_D2H_RINGS)
def dump_submission_and_completion_rings(self):
"""
Dumps information about the submission and completion rings
"""
compl_rings = [self.get_d2h_msgring_control_complete_ring(),
self.get_d2h_msgring_tx_complete_ring(),
self.get_d2h_msgring_rx_complete_ring()]
subm_rings = [self.get_h2d_msgring_control_submit_ring(),
self.get_h2d_msgring_rxpost_submit_ring()]
for ring in (subm_rings + compl_rings):
print "Ring ID: %d" % ring.get_ring_id()
print "Ring Base Address: %016X" % ring.get_base_address()
print "Ring Element Size: %d" % ring.get_element_size()
print "Ring Index Pointer %016X" % ring.get_index_pointer()
You can’t perform that action at this time.