Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various Changes #32

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
package lol.fairplay.ghidraapple.analysis.objectivec

import ghidra.program.model.data.ArrayDataType
import ghidra.program.model.data.BooleanDataType
import ghidra.program.model.data.CategoryPath
import ghidra.program.model.data.CharDataType
import ghidra.program.model.data.DataType
import ghidra.program.model.data.DoubleDataType
import ghidra.program.model.data.FloatDataType
import ghidra.program.model.data.IntegerDataType
import ghidra.program.model.data.LongDataType
import ghidra.program.model.data.LongDoubleDataType
import ghidra.program.model.data.LongLongDataType
import ghidra.program.model.data.PointerDataType
import ghidra.program.model.data.ShortDataType
import ghidra.program.model.data.StructureDataType
import ghidra.program.model.data.UnionDataType
import ghidra.program.model.data.UnsignedCharDataType
import ghidra.program.model.data.UnsignedIntegerDataType
import ghidra.program.model.data.UnsignedLongDataType
import ghidra.program.model.data.UnsignedLongLongDataType
import ghidra.program.model.data.UnsignedShortDataType
import ghidra.program.model.data.VoidDataType
import ghidra.program.model.data.*
import ghidra.program.model.listing.Program
import lol.fairplay.ghidraapple.core.objc.encodings.TypeNode
import lol.fairplay.ghidraapple.core.objc.encodings.TypeNodeVisitor

import java.security.SecureRandom

fun getRandomHexString(length: Int): String {
Expand Down Expand Up @@ -57,22 +36,33 @@ class GhidraTypeBuilder(val program: Program) : TypeNodeVisitor {
return GhidraTypeBuilder(program)
}

fun tryResolveDefinedStruct(name: String): DataType? {
fun getGAType(name: String): DataType? {
val category = CategoryPath("/GA_OBJC")
return program.dataTypeManager.getDataType(category, name)
}

fun tryResolveStructPtr(name: String): DataType? {
return PointerDataType(tryResolveDefinedStruct(name) ?: return null)
fun createUnionDT(name: String): DataType {
val category = CategoryPath("/GA_OBJC")
return program.dataTypeManager.addDataType(UnionDataType(category, name), null)
}

fun createStructureDT(name: String): DataType {
val category = CategoryPath("/GA_OBJC")
return program.dataTypeManager.addDataType(StructureDataType(category, name, 0), null)
}

override fun visitStruct(struct: TypeNode.Struct) {
val name = (struct.name ?: "anon__${getRandomHexString(6)}").let{
if (it.isEmpty()) "anon__${getRandomHexString(6)}" else it
}

val ghidraStruct = (tryResolveDefinedStruct(name) ?: StructureDataType(name, 0)) as StructureDataType
var ghidraStruct = getGAType(name) as Structure?
if (ghidraStruct != null) {
result = ghidraStruct
return
}

ghidraStruct = createStructureDT(name) as Structure
if (struct.fields == null) {
result = ghidraStruct
return
Expand Down Expand Up @@ -104,8 +94,8 @@ class GhidraTypeBuilder(val program: Program) : TypeNodeVisitor {
return
}

val resolved = tryResolveStructPtr(obj.name)
result = resolved ?: idType
val objDT = getGAType(obj.name) ?: createStructureDT(obj.name)
result = PointerDataType(objDT, 8)
}

override fun visitUnion(union: TypeNode.Union) {
Expand All @@ -114,8 +104,13 @@ class GhidraTypeBuilder(val program: Program) : TypeNodeVisitor {
if (it.isEmpty()) "anon__${getRandomHexString(6)}" else it
}

val ghidraUnion = UnionDataType(name)
var ghidraUnion = getGAType(name)
if (ghidraUnion != null) {
result = ghidraUnion
return
}

ghidraUnion = createUnionDT(name) as Union
if (union.fields == null) {
result = ghidraUnion
return
Expand Down Expand Up @@ -149,8 +144,9 @@ class GhidraTypeBuilder(val program: Program) : TypeNodeVisitor {
'C' -> UnsignedCharDataType.dataType
's' -> ShortDataType.dataType
'S' -> UnsignedShortDataType.dataType
'i' -> IntegerDataType.dataType
'I' -> UnsignedIntegerDataType.dataType
// 'i' -> IntegerDataType.dataType
// 'I' -> UnsignedIntegerDataType.dataType
'i', 'I' -> Undefined4DataType.dataType
'l' -> LongDataType.dataType
'L' -> UnsignedLongDataType.dataType
'q' -> LongLongDataType.dataType
Expand All @@ -160,7 +156,7 @@ class GhidraTypeBuilder(val program: Program) : TypeNodeVisitor {
'v' -> VoidDataType.dataType
'B' -> BooleanDataType.dataType
'D' -> LongDoubleDataType.dataType
'*' -> PointerDataType(CharDataType.dataType)
'*' -> PointerDataType(CharDataType.dataType, 8)
else -> throw Exception("Unknown primitive type: ${primitive.type}")
}
}
Expand All @@ -169,7 +165,7 @@ class GhidraTypeBuilder(val program: Program) : TypeNodeVisitor {
val visitor = extend()
pointer.pointee.accept(visitor)

result = PointerDataType(visitor.getResult())
result = PointerDataType(visitor.getResult(), 8)
}

override fun visitBitfield(bitfield: TypeNode.Bitfield) {
Expand All @@ -181,7 +177,7 @@ class GhidraTypeBuilder(val program: Program) : TypeNodeVisitor {
}

override fun visitFunctionPointer(fnPtr: TypeNode.FunctionPointer) {
result = PointerDataType(VoidDataType.dataType)
result = PointerDataType(VoidDataType.dataType, 8)
}

override fun visitSelector(fnPtr: TypeNode.Selector) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class TypeResolver(val program: Program) {
return builder.getResult()
}

fun tryResolveStructPtr(name: String): DataType? {
fun tryResolveDefinedStructPtr(name: String): DataType? {
return PointerDataType(tryResolveDefinedStruct(name) ?: return null)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ class StructureParsing(val program: Program) {
name = dat[0].deref<String>(),
attributes = encoding.attributes,
type = encoding.type,
backingIvar = encoding.backingIvar
customGetter = encoding.customGetter,
customSetter = encoding.customSetter,
backingIvar = encoding.backingIvar,
)
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import lol.fairplay.ghidraapple.analysis.objectivec.TypeResolver
import lol.fairplay.ghidraapple.analysis.objectivec.modelling.StructureParsing
import lol.fairplay.ghidraapple.analysis.utilities.address
import lol.fairplay.ghidraapple.analysis.utilities.idealClassStructures
import lol.fairplay.ghidraapple.core.objc.encodings.PropertyAttribute
import lol.fairplay.ghidraapple.core.objc.modelling.OCClass
import lol.fairplay.ghidraapple.core.objc.modelling.OCProtocol

class OCClassPropertiesAnalyzer : AbstractAnalyzer(NAME, DESCRIPTION, AnalyzerType.FUNCTION_ANALYZER) {

Expand All @@ -32,7 +34,11 @@ class OCClassPropertiesAnalyzer : AbstractAnalyzer(NAME, DESCRIPTION, AnalyzerTy

override fun canAnalyze(program: Program): Boolean {
this.program = program
return program.memory.getBlock("__objc_classlist") != null

program.memory.getBlock("__objc_classlist") ?: return false
program.memory.getBlock("__objc_protolist") ?: return false

return true
}

override fun added(program: Program, set: AddressSetView, monitor: TaskMonitor, log: MessageLog): Boolean {
Expand Down Expand Up @@ -76,14 +82,18 @@ class OCClassPropertiesAnalyzer : AbstractAnalyzer(NAME, DESCRIPTION, AnalyzerTy

monitor.message = "Analyzing properties: ${klass.name}"
Msg.info(this, "Analyzing properties for ${klass.name}")
val properties = klass.getCollapsedProperties() ?: continue
val properties = klass.resolvedProperties() ?: continue
val methodMapping = klass.baseMethods?.associateBy { it.name } ?: continue

properties.forEach { property ->
val methodGetter = methodMapping[property.name] ?: return@forEach
println("Property: ${property.name}")
if (property.parent != klass) {
Msg.error(this, "Unsupported property: ${property.name} is not from the current class")
return@forEach
}

val setterName = "set${property.name[0].uppercase()}${property.name.substring(1)}:"
val methodSetter = methodMapping[setterName] ?: return@forEach
val getterName = property.customGetter ?: property.name
val methodGetter = methodMapping[getterName] ?: return@forEach

val propertyDataType = runCatching {
val parsed = property.type?.first ?: return@runCatching null
Expand All @@ -93,10 +103,15 @@ class OCClassPropertiesAnalyzer : AbstractAnalyzer(NAME, DESCRIPTION, AnalyzerTy
}.getOrNull() ?: return@forEach

val fnGetter = program.functionManager.getFunctionAt(program.address(methodGetter.implAddress!!.toLong()))
val fnSetter = program.functionManager.getFunctionAt(program.address(methodSetter.implAddress!!.toLong()))

fnGetter.setReturnType(propertyDataType, SourceType.ANALYSIS)
fnSetter.getParameter(2).setDataType(propertyDataType, SourceType.ANALYSIS)

if (!property.attributes.contains(PropertyAttribute.READ_ONLY)) {
val setterName = property.customSetter ?: "set${property.name[0].uppercase()}${property.name.substring(1)}:"
val methodSetter = methodMapping[setterName]!!
val fnSetter = program.functionManager.getFunctionAt(program.address(methodSetter.implAddress!!.toLong()))
fnSetter.getParameter(2).setDataType(propertyDataType, SourceType.ANALYSIS)
}

}
}
}
Expand Down
Loading
Loading