Skip to content

Commit fa7ef5f

Browse files
committedFeb 21, 2019
Improve enumerateLoadedClasses() to handle Swift classes
1 parent 01b5b2c commit fa7ef5f

File tree

4 files changed

+130
-30
lines changed

4 files changed

+130
-30
lines changed
 

‎index.js

+26-7
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,9 @@ function Runtime() {
15961596
}
15971597

15981598
function enumerateLoadedClasses(...args) {
1599+
const allModules = new ModuleMap();
1600+
let unfiltered = false;
1601+
15991602
let callbacks;
16001603
let modules;
16011604
if (args.length === 1) {
@@ -1606,25 +1609,41 @@ function Runtime() {
16061609
const options = args[0];
16071610
modules = options.ownedBy;
16081611
}
1609-
if (modules === undefined)
1610-
modules = new ModuleMap();
1612+
if (modules === undefined) {
1613+
modules = allModules;
1614+
unfiltered = true;
1615+
}
16111616

16121617
const readPointer = Memory.readPointer.bind(Memory);
16131618
const readUtf8String = Memory.readUtf8String.bind(Memory);
16141619
const classGetName = api.class_getName;
1615-
const findPath = modules.findPath.bind(modules);
16161620
const onMatch = callbacks.onMatch.bind(callbacks);
1621+
const swiftNominalTypeDescriptorOffset = ((pointerSize === 8) ? 8 : 11) * pointerSize;
16171622

16181623
const numClasses = api.objc_getClassList(NULL, 0);
16191624
const classHandles = Memory.alloc(numClasses * pointerSize);
16201625
api.objc_getClassList(classHandles, numClasses);
16211626

16221627
for (let i = 0; i !== numClasses; i++) {
1623-
const handle = readPointer(classHandles.add(i * pointerSize));
1624-
const rawName = classGetName(handle);
1625-
const modulePath = findPath(rawName);
1628+
const classHandle = readPointer(classHandles.add(i * pointerSize));
1629+
1630+
const rawName = classGetName(classHandle);
1631+
let name = null;
1632+
1633+
let modulePath = modules.findPath(rawName);
1634+
const possiblySwift = (modulePath === null) && (unfiltered || allModules.findPath(rawName) === null);
1635+
if (possiblySwift) {
1636+
name = readUtf8String(rawName);
1637+
const probablySwift = name.indexOf('.') !== -1;
1638+
if (probablySwift) {
1639+
const nominalTypeDescriptor = Memory.readPointer(classHandle.add(swiftNominalTypeDescriptorOffset));
1640+
modulePath = modules.findPath(nominalTypeDescriptor);
1641+
}
1642+
}
1643+
16261644
if (modulePath !== null) {
1627-
const name = readUtf8String(rawName);
1645+
if (name === null)
1646+
name = readUtf8String(rawName);
16281647
onMatch(name, modulePath);
16291648
}
16301649
}

‎test/Makefile

+80-23
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,43 @@
1+
RUNNER_ARGS ?=
2+
13
IOS_HOST = iphone
24
IOS_ARCH = arm64
35
IOS_PREFIX = /usr/local/opt/frida-objc-tests-$(IOS_ARCH)
46

57
frida_version := 12.3.3
68

79
cflags := -Wall -pipe -Os -g
8-
ldflags := -Wl,-framework,Foundation -lfrida-gumjs -lresolv -Wl,-dead_strip
10+
ldflags := -Wl,-framework,Foundation -lfrida-gumjs -lresolv -Wl,-dead_strip
11+
toolchain := $(shell dirname $(shell dirname $(shell dirname $(shell xcrun --toolchain XcodeDefault -f swift))))
912

1013
macos_cc := $(shell xcrun --sdk macosx -f clang)
11-
macos_sysroot := $(shell xcrun --sdk macosx --show-sdk-path)
12-
macos_cflags := -isysroot "$(macos_sysroot)" -arch x86_64 -mmacosx-version-min=10.9 $(cflags) -DHAVE_MACOS
13-
macos_ldflags := $(ldflags)
14+
macos_swift := $(shell xcrun --sdk macosx -f swift)
15+
macos_sdk := $(shell xcrun --sdk macosx --show-sdk-path)
16+
macos_cflags := -isysroot "$(macos_sdk)" -arch x86_64 $(cflags) -DHAVE_MACOS
17+
macos_runtimedir := $(toolchain)/usr/lib/swift/macosx
18+
macos_ldflags := "-L$(macos_runtimedir)" -lswiftObjectiveC "-Wl,-rpath,$(macos_runtimedir)" $(ldflags)
1419

1520
ios_cc := $(shell xcrun --sdk iphoneos -f clang)
16-
ios_sysroot := $(shell xcrun --sdk iphoneos --show-sdk-path)
17-
ios_cflags := -isysroot "$(ios_sysroot)" -arch $(IOS_ARCH) -miphoneos-version-min=7.0 $(cflags) -DHAVE_IOS
18-
ios_ldflags := $(ldflags)
21+
ios_swift := $(shell xcrun --sdk iphoneos -f swift)
22+
ios_sdk := $(shell xcrun --sdk iphoneos --show-sdk-path)
23+
ios_cflags := -isysroot "$(ios_sdk)" -arch $(IOS_ARCH) -miphoneos-version-min=7.0 $(cflags) -DHAVE_IOS
24+
ios_runtimedir := $(toolchain)/usr/lib/swift/iphoneos
25+
ios_ldflags := "-L$(ios_runtimedir)" -lswiftObjectiveC "-Wl,-rpath,$(IOS_PREFIX)" $(ldflags)
1926
ios_codesign := $(shell xcrun --sdk iphoneos -f codesign)
20-
21-
sources := runner.m basics.m
22-
headers := fixture.m
27+
ios_swift_libraries := \
28+
$(ios_runtimedir)/libswiftCore.dylib \
29+
$(ios_runtimedir)/libswiftCoreFoundation.dylib \
30+
$(ios_runtimedir)/libswiftCoreGraphics.dylib \
31+
$(ios_runtimedir)/libswiftDarwin.dylib \
32+
$(ios_runtimedir)/libswiftDispatch.dylib \
33+
$(ios_runtimedir)/libswiftFoundation.dylib \
34+
$(ios_runtimedir)/libswiftObjectiveC.dylib \
35+
$(ios_runtimedir)/libswiftSwiftOnoneSupport.dylib \
36+
$(NULL)
37+
38+
objc_sources := runner.m basics.m
39+
objc_headers := fixture.m
40+
swift_sources := taylor.swift
2341

2442
js_sources := ../index.js
2543

@@ -32,38 +50,77 @@ build-macos: build/macos-x86_64/runner
3250
build-ios: build/ios-$(IOS_ARCH)/runner
3351

3452
run-macos: build/macos-x86_64/runner build/frida-objc.js
35-
$<
36-
run-ios: build/ios-$(IOS_ARCH)/runner build/frida-objc.js
37-
ssh $(IOS_HOST) "rm -rf $(IOS_PREFIX); mkdir -p $(IOS_PREFIX)"
38-
scp $^ "$(IOS_HOST):$(IOS_PREFIX)/"
39-
ssh $(IOS_HOST) "$(IOS_PREFIX)/runner"
53+
$< $(RUNNER_ARGS)
54+
run-ios: build/ios-$(IOS_ARCH)/runner build/frida-objc.js build/ios-$(IOS_ARCH)/.swift-runtime-stamp
55+
cd build/ios-$(IOS_ARCH)/ && rsync -rLz runner ../frida-objc.js *.dylib "$(IOS_HOST):$(IOS_PREFIX)/"
56+
ssh $(IOS_HOST) "$(IOS_PREFIX)/runner $(RUNNER_ARGS)"
4057

4158
watch-macos: build/macos-x86_64/runner build/frida-objc.js
4259
npm run watch &
4360
./node_modules/.bin/chokidar \
4461
build/frida-objc.js \
45-
-c 'build/macos-x86_64/runner'
62+
-c 'build/macos-x86_64/runner $(RUNNER_ARGS)'
4663
watch-ios: build/ios-$(IOS_ARCH)/runner build/frida-objc.js
4764
npm run watch &
4865
./node_modules/.bin/chokidar \
4966
build/frida-objc.js \
5067
-c 'scp build/frida-objc.js "$(IOS_HOST):$(IOS_PREFIX)/" \
51-
&& ssh $(IOS_HOST) "$(IOS_PREFIX)/runner"'
68+
&& ssh $(IOS_HOST) "$(IOS_PREFIX)/runner $(RUNNER_ARGS)"'
5269

53-
build/macos-x86_64/runner: $(sources) $(headers) build/macos-x86_64/libfrida-gumjs.a
54-
"$(macos_cc)" $(macos_cflags) \
55-
$(sources) \
70+
build/macos-x86_64/runner: $(objc_sources) $(objc_headers) build/macos-x86_64/taylor.o build/macos-x86_64/libfrida-gumjs.a
71+
"$(macos_cc)" \
72+
$(macos_cflags) \
73+
$(objc_sources) \
74+
build/macos-x86_64/taylor.o \
5675
-o $@ \
5776
-Ibuild/macos-x86_64 -Lbuild/macos-x86_64 \
5877
$(macos_ldflags)
59-
build/ios-$(IOS_ARCH)/runner: $(sources) $(headers) runner.xcent build/ios-$(IOS_ARCH)/libfrida-gumjs.a
60-
"$(ios_cc)" $(ios_cflags) \
61-
$(sources) \
78+
build/ios-$(IOS_ARCH)/runner: $(objc_sources) $(objc_headers) build/ios-$(IOS_ARCH)/taylor.o runner.xcent build/ios-$(IOS_ARCH)/libfrida-gumjs.a
79+
"$(ios_cc)" \
80+
$(ios_cflags) \
81+
$(objc_sources) \
82+
build/ios-$(IOS_ARCH)/taylor.o \
6283
-o $@ \
6384
-Ibuild/ios-$(IOS_ARCH) -Lbuild/ios-$(IOS_ARCH) \
6485
$(ios_ldflags)
6586
"$(ios_codesign)" -f -s "$$IOS_CERTID" --entitlements runner.xcent $@
6687

88+
build/macos-x86_64/taylor.o: taylor.swift
89+
@mkdir -p $(@D)
90+
"$(macos_swift)" \
91+
-frontend \
92+
-c \
93+
-primary-file taylor.swift \
94+
-sdk "$(macos_sdk)" \
95+
-module-name FridaObjCTests \
96+
-emit-module-path build/macos-x86_64/FridaObjCTests.swiftmodule \
97+
-emit-objc-header-path build/macos-x86_64/taylor.h \
98+
-enable-testing \
99+
-enable-objc-interop \
100+
-parse-as-library \
101+
-o $@
102+
build/ios-$(IOS_ARCH)/taylor.o: taylor.swift
103+
@mkdir -p $(@D)
104+
"$(ios_swift)" \
105+
-frontend \
106+
-c \
107+
-primary-file taylor.swift \
108+
-target $(IOS_ARCH)-apple-ios7.0-iphoneos \
109+
-sdk "$(ios_sdk)" \
110+
-module-name FridaObjCTests \
111+
-emit-module-path build/ios-$(IOS_ARCH)/FridaObjCTests.swiftmodule \
112+
-emit-objc-header-path build/ios-$(IOS_ARCH)/taylor.h \
113+
-enable-testing \
114+
-enable-objc-interop \
115+
-parse-as-library \
116+
-o $@
117+
118+
build/ios-$(IOS_ARCH)/.swift-runtime-stamp: $(ios_swift_libraries)
119+
@mkdir -p $(@D)
120+
cp $^ $(@D)
121+
"$(ios_codesign)" -f -s "$$IOS_CERTID" $(@D)/*.dylib
122+
@touch $@
123+
67124
build/%/libfrida-gumjs.a:
68125
@mkdir -p $(@D)
69126
curl -Ls https://github.com/frida/frida/releases/download/$(frida_version)/frida-gumjs-devkit-$(frida_version)-$*.tar.xz | tar -xJf - -C $(@D)

‎test/basics.m

+11
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
TESTGROUP_BEGIN ("EnumerateLoadedClasses")
4848
TESTENTRY (classes_can_be_enumerated_without_filtering)
4949
TESTENTRY (classes_can_be_enumerated_with_filtering)
50+
TESTENTRY (swift_classes_can_be_enumerated)
5051
TESTGROUP_END ()
5152

5253
TESTENTRY (existing_instances_can_be_discovered)
@@ -829,6 +830,16 @@ @implementation FridaTest4
829830
EXPECT_NO_MESSAGES ();
830831
}
831832

833+
TESTCASE (swift_classes_can_be_enumerated)
834+
{
835+
COMPILE_AND_LOAD_SCRIPT (
836+
"var classes = ObjC.enumerateLoadedClassesSync();"
837+
"var runnerPath = Process.enumerateModulesSync()[0].path;"
838+
"send(classes[runnerPath].indexOf('FridaObjCTests.Taylor') !== -1)");
839+
EXPECT_SEND_MESSAGE_WITH ("true");
840+
EXPECT_NO_MESSAGES ();
841+
}
842+
832843
TESTCASE (existing_instances_can_be_discovered)
833844
{
834845
if (!g_test_slow ())

‎test/taylor.swift

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Foundation
2+
3+
public class Taylor: NSObject {
4+
@objc public var mood: String
5+
6+
public override init() {
7+
self.mood = "creative"
8+
}
9+
10+
public func saySomething() -> String {
11+
return "I am feeling \(mood)"
12+
}
13+
}

0 commit comments

Comments
 (0)
Please sign in to comment.