예제 #1
0
	def readLazyBind(self, offset: int) -> typing.Tuple[int, int, bytes]:
		"""
			Reads the OPCODE_SET_SEGMENT_AND_OFFSET_ULEB and 
			OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM from the
			lazy bind info at the given offset.
		"""

		dyldInfo = self.machoFile.getLoadCommand((MachO.LoadCommands.LC_DYLD_INFO, MachO.LoadCommands.LC_DYLD_INFO_ONLY))
		lazyBindData = dyldInfo.lazy_bindData

		segIndex = None
		segOff = None
		flags = None

		# assume that OPCODE_SET_SEGMENT_AND_OFFSET_ULEB comes first
		# and then OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
		while offset < dyldInfo.lazy_bind_size:
			imm = lazyBindData[offset] & MachO.Bind.BIND_IMMEDIATE_MASK
			opcode = lazyBindData[offset] & MachO.Bind.BIND_OPCODE_MASK
			offset += 1

			if opcode == MachO.Bind.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
				segIndex = imm

				segOff, ulebLen = Uleb128.readUleb128(lazyBindData, offset)
				offset += ulebLen
			elif opcode == MachO.Bind.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
				flagsEnd = lazyBindData.index(b"\x00", offset) + 1
				flags = lazyBindData[offset:flagsEnd]
				break
		
		if segIndex is None or segOff is None or flags is None:
			raise Exception("Incorrect parsing")

		return (segIndex, segOff, flags)
예제 #2
0
	def processNode(self, exportOff: int, cumStrHead: int) -> None:
		"""Recursively process a node.

		Parameters
		----------
			exportOff : int
				The offset in the export data to the node.
			cumStrHead : int
				The end of the string in the cumulative string,
				not including the null byte.

		Raises
		------
			Exception
				raises "Export off beyond export length" if the
				exportOff is beyond the length of the export data.
		"""

		if exportOff >= len(self.exports):
			raise Exception("Export off beyond export length")

		# read the entry
		entryReadHead = exportOff

		terminalSize, ulebSize = Uleb128.readUleb128(self.exports, entryReadHead)
		entryReadHead += ulebSize

		if terminalSize != 0:
			entry = TrieEntry()
			entry.nodeOffset = exportOff

			currentStrEnd = self.cumulativeStr.index(b"\x00") + 1
			entry.name = bytes(self.cumulativeStr[0:currentStrEnd])

			entry.flags, ulebSize = Uleb128.readUleb128(self.exports, entryReadHead)
			entryReadHead += ulebSize

			if entry.flags & Export.EXPORT_SYMBOL_FLAGS_REEXPORT:
				entry.address = 0

				entry.other, ulebSize = Uleb128.readUleb128(self.exports, entryReadHead)
				entryReadHead += ulebSize

				importNameEnd = self.exports.index(b"\x00", entryReadHead) + 1
				entry.importName = bytes(self.exports[entryReadHead:importNameEnd])
			else:
				entry.address, ulebSize = Uleb128.readUleb128(self.exports, entryReadHead)
				entryReadHead += ulebSize

				entry.importName = None

				if entry.flags & Export.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER:
					entry.other, ulebSize = Uleb128.readUleb128(self.exports, entryReadHead)
					entryReadHead += ulebSize
				else:
					entry.other = 0
			
			self.entries.append(entry)

		# process children
		childrenCount = int(self.exports[exportOff + terminalSize + 1])
		childrenReadHead = exportOff + terminalSize + 2

		for _ in range(0, childrenCount):
			# read the extra chars
			edgeStrEnd = self.exports.index(b"\x00", childrenReadHead) + 1
			edgeStr = self.exports[childrenReadHead:edgeStrEnd]
			childrenReadHead += len(edgeStr)

			self.cumulativeStr[cumStrHead:] = edgeStr

			# process child
			childNodeOff, ulebSize = Uleb128.readUleb128(self.exports, childrenReadHead)
			childrenReadHead += ulebSize
			
			self.processNode(childNodeOff, cumStrHead + (len(edgeStr) - 1))
		pass
    def rebasePage(self, pageOffset: int, firstRebaseOffset: int,
                   segment: MachO.segment_command_64) -> None:
        """
			processes the rebase infomation in a page

			### parameters
			pageOffset: int
				
				The file offset of the page.

			firstRebaseOffset: int

				The offset from the start of the page to the first
				rebase location.
			
			segment: segment_command_64

				The segment to rebase.
			
		"""

        segmentIndex = self.machoFile.loadCommands.index(segment)

        deltaMask = self.slideInfo.delta_mask
        valueMask = ~deltaMask
        valueAdd = self.slideInfo.value_add

        # basically __builtin_ctzll(deltaMask) - 2;
        deltaShift = "{0:b}".format(deltaMask)
        deltaShift = len(deltaShift) - len(deltaShift.rstrip("0"))
        deltaShift = deltaShift - 2

        delta = 1

        rebaseOffset = firstRebaseOffset
        while delta != 0:
            realLoc = pageOffset + rebaseOffset

            self.dyldFile.file.seek(realLoc)

            rawValueBytes = self.dyldFile.file.read(8)
            rawValue = struct.unpack("<Q", rawValueBytes)[0]

            delta = (rawValue & deltaMask) >> deltaShift
            value = rawValue & valueMask
            if value:
                value += valueAdd

            # if the location is within the segment, adjust the data
            if realLoc >= segment.fileoff and realLoc < (segment.fileoff +
                                                         segment.filesize):
                self.slideLocation(realLoc, value, segment)

                # add a rebase entry
                self.rebaseInfo.append(
                    MachO.Rebase.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
                    | segmentIndex)
                self.rebaseInfo += Uleb128.encodeUleb128(realLoc -
                                                         segment.fileoff)
                self.rebaseInfo.append(
                    MachO.Rebase.REBASE_OPCODE_DO_REBASE_IMM_TIMES | 0x1)

            rebaseOffset += delta