Swift runtime interop from Frida -- interact with iOS apps written in Swift, using Frida. (See frida-swift instead, if you're looking to script the Frida debugging session using Swift code you write.)
The functionality described below is mostly stable and working, but probably still has some bugs that need to be fixed (please report them!).
I'm mainly testing things on iOS 11.1.2 (64bit), and on iOS 9.3.5 (32bit). Other operating systems are not supported for now. Only apps using Swift 4.0.* are supported at the moment.
Clone the project, and install its dependencies:
git clone https://github.com/maltek/swift-frida.git cd swift-frida npm install
In your script, add this line:
const Swift = require('/path/to/swift-frida/');
Afterwards, compile your script with
frida-compile like this:
frida-compile -w -o /tmp/compiled.js your-script.js
To play around with the API interactively, you can load the compiled
loader.js into the REPL:
$ frida-compile -w -o /tmp/swift.js loader.js $ frida -U -n Foo -l /tmp/swift.js ____ / _ | Frida 12.2.14 - A world-class dynamic instrumentation toolkit | (_| | > _ | Commands: /_/ |_| help -> Displays the help system . . . . object? -> Display information about 'object' . . . . exit/quit -> Exit . . . . . . . . More info at http://www.frida.re/docs/home/ [iOS Device::Foo]-> Swift.available true
Right now, the following functions are available in the
Swift namespace, when the script is loaded:
availableAllows you to check if the current process uses Swift. Don't use any of the other functions here if this property is
isSwiftName(name)Takes a function/symbol name (like you can get from
Moduleobjects), and returns a boolean indicating whether it is a mangled Swift name or not.
demangle(name)Takes a mangled Swift name (like you can get from
Moduleobjects), and returns a demangled, human-readable String for it.
getMangled(name)The opposite of
demangle(name). Right now, this only works for names that were previously returned by
_apiThis is an object providing access to many low-level functions in the Swift runtime.
_typeFromCanonical(metadata)This function allows you to create a
Typeconstructor from a low-level
makeFunctionType(args, returnType, flags)Creates a new Swift
Typeconstructor for a function type.
argsshould be an array with the types of each argument,
flagsis an optional object with
makeTupleType(labels, innerTypes)Creates a new Swift
Typeconstructor for a tuple type.
innerTypesare arrays with the labels and types of the tuple elements. Use empty strings for unlabeled elements.
enumerateTypesSync(module)Searches for types defined in
module, or in all loaded modules if that parameter is
undefined. Returns a
Mapstoring information about all known Swift data types defined in the Swift program. The keys are the names of the data types (as strings), and the values are objects describing the type. These objects have a
toStringmethod returning the fully qualified name of the type, including generic bounds (if possible) and a string property
kindthat tells you which kind of type (e.g.
"Struct") it is. The
Typeproperty returns a
Typeconstructor for the meta type of the represented type. Depending on the kind of type, additional methods are available:
Kind available method Enum
enumCasesreturns an array with all defined cases, with their names, types, and attributes.
fieldsreturns an array with all fields of this class or struct, with names, offsets, types, and attributes.
tupleElementsreturns an array with the types and labels of the elements in the tuple.
returnTypereturns the return type of the function.
functionFlagsreturns an object telling you the calling convention and whether the function throws or not.
getArgumentsreturns an array with the type and flags (
inout) for every function argument.
ObjC.Objectdescribing this class.
Uninstantiated generic types (you can check this with the
isGenericmethod), do not have any of these methods available. You must call
withGenericParamsto get a fully concrete type.
For fully instantiated generic types or non-generic types, you can use these type objects as constructors -- you provide a pointer where a value of that type is stored, and get back an object that lets you interact with this variable. Note that this object only stays valid for as long as this pointer is valid and is not modified (except using methods directly on this object). Depending on the kind of type, the following properties exist:
Kind available property *
toString()returns a string with the debug representation of this variable
$pointerthe pointer where this value resides in memory
$typethe dynamic type of this value
$staticTypethe static type of this value
$destroy()destroys an owned Swift value. (On a best-effort basis this also happens when the object is garbage-collected.)
$assignWithCopy(other)assigns a copy of
otherto this variable.
othermust have a compatible type (this is not checked).
allocCopy()creates and returns an owned copy of this value. Use
$destroy()on the return value when you are done using it!
Function The object is a function that you can call. (Other properties are still available.) ObjCClassWrapper The object is an
ObjC.Object. See the documentation there. (None of the properties for Swift values are available.)
$isathe isa pointer. (Only for Existential types when they are class bound.)
$retainCountsthe number of references to this value. (Only for Existential types when they are class bound.)
$enumCase' the index of the active case of this enum, see$type.enumCases`.
$enumPayloadCopy()creates and returns an owned copy of the payload of this enum, or returns
undefinedif the active case has no payload. Use
$destroy()on the return value when you are done using it!
Class, Struct Getters and setters for every field (see
$type.fields()). When the field name collides with a property that exists on every JS object, or starts with a
$$as a name to access such a field.
$valueallows you to get/set the value in this variable. (Only for Existential types when they are not class bound.)
Tuple Getters and setters for every tuple element (see
$type.tupleElements(), by index or (when available) by label.
Returned values are normally the same kind of
But, again, this is completely unstable and might change at any time.
metadata.js is based on Apache-2.0 licensed Swift compiler source
code. Code in
runtime-api.js is based on wxWindows-3.1 licensed frida-objc
The compatible intersection of those licenses is LGPL-3.0 (or later) with wxWindows exceptions. So that's also the license terms under which we release the original code in this repository.