Skip to content

Commit ca6e1a3

Browse files
committed
Initial commit: FileRedirect dylib for iOS game modding
0 parents  commit ca6e1a3

File tree

6 files changed

+815
-0
lines changed

6 files changed

+815
-0
lines changed

.github/workflows/build.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Build FileRedirect.dylib
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
# Allow manual trigger from the Actions tab
9+
workflow_dispatch:
10+
11+
jobs:
12+
build:
13+
runs-on: macos-14 # Apple Silicon runner (has Xcode 15+)
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Show Xcode version
20+
run: xcodebuild -version
21+
22+
- name: Show iOS SDK path
23+
run: xcrun --sdk iphoneos --show-sdk-path
24+
25+
- name: Build dylib
26+
run: make
27+
working-directory: .
28+
29+
- name: Verify output
30+
run: |
31+
ls -la FileRedirect.dylib
32+
file FileRedirect.dylib
33+
otool -l FileRedirect.dylib | head -40
34+
35+
- name: Upload dylib artifact
36+
uses: actions/upload-artifact@v4
37+
with:
38+
name: FileRedirect-dylib
39+
path: FileRedirect.dylib
40+
retention-days: 90

Makefile

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# FileRedirectDylib Makefile
2+
#
3+
# Build a dylib for iOS arm64 using Xcode's clang.
4+
# Requires macOS with Xcode (or Xcode Command Line Tools) + iOS SDK.
5+
#
6+
# Usage:
7+
# make — build FileRedirect.dylib
8+
# make clean — remove build artifacts
9+
#
10+
# If your iOS SDK path differs, override it:
11+
# make SDK=/path/to/iPhoneOS.sdk
12+
13+
# --- Configuration ---
14+
CC = xcrun -sdk iphoneos clang
15+
SDK ?= $(shell xcrun --sdk iphoneos --show-sdk-path)
16+
ARCH = arm64
17+
MIN_IOS = 12.0
18+
19+
TARGET = FileRedirect.dylib
20+
SOURCES = tweak.m fishhook.c
21+
OBJECTS = tweak.o fishhook.o
22+
23+
CFLAGS = -arch $(ARCH) \
24+
-isysroot $(SDK) \
25+
-miphoneos-version-min=$(MIN_IOS) \
26+
-fobjc-arc \
27+
-fmodules \
28+
-Wall
29+
30+
LDFLAGS = -arch $(ARCH) \
31+
-isysroot $(SDK) \
32+
-miphoneos-version-min=$(MIN_IOS) \
33+
-dynamiclib \
34+
-framework Foundation \
35+
-install_name @executable_path/$(TARGET)
36+
37+
# --- Targets ---
38+
39+
all: $(TARGET)
40+
41+
$(TARGET): $(OBJECTS)
42+
$(CC) $(LDFLAGS) -o $@ $^
43+
@echo "✅ Built $(TARGET) for iOS $(ARCH)"
44+
45+
tweak.o: tweak.m fishhook.h
46+
$(CC) $(CFLAGS) -c tweak.m -o tweak.o
47+
48+
fishhook.o: fishhook.c fishhook.h
49+
$(CC) $(CFLAGS) -c fishhook.c -o fishhook.o
50+
51+
clean:
52+
rm -f $(OBJECTS) $(TARGET)
53+
@echo "🧹 Cleaned build artifacts"
54+
55+
.PHONY: all clean

README.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# FileRedirectDylib
2+
3+
A dylib for iOS that hooks file-access functions so games like **Bully** or **GTA San Andreas** transparently load modded files from `Documents/disk/` instead of the app bundle.
4+
5+
## How It Works
6+
7+
On non-jailbroken iOS the `.app` bundle is **read-only**. This dylib doesn't try to write into it. Instead it:
8+
9+
1. Hooks C functions: `fopen`, `open`, `stat`, `access`
10+
2. Swizzles ObjC methods: `NSBundle -pathForResource:ofType:`, `NSFileManager -contentsAtPath:`
11+
3. When the game requests a file from its `.app` bundle, the hook checks if a replacement exists at `Documents/disk/<same relative path>`
12+
4. If yes → returns the modded file. If no → falls through to the original.
13+
14+
## File Structure
15+
16+
```
17+
FileRedirectDylib/
18+
├── .github/
19+
│ └── workflows/
20+
│ └── build.yml ← GitHub Actions CI (builds on free macOS runner)
21+
├── tweak.m ← Main hook/swizzle logic
22+
├── fishhook.h ← Facebook fishhook header
23+
├── fishhook.c ← Facebook fishhook implementation
24+
├── Makefile ← Build script
25+
└── README.md ← This file
26+
```
27+
28+
## Building — No Mac Required (GitHub Actions)
29+
30+
You do NOT need a Mac. GitHub gives you a free macOS build machine.
31+
32+
### Step-by-step:
33+
34+
1. **Create a GitHub account** if you don't have one: https://github.com
35+
2. **Create a new repository** (e.g. `FileRedirectDylib`)
36+
3. **Upload all files** from this folder to the repo, keeping the folder structure
37+
(make sure `.github/workflows/build.yml` is included)
38+
4. **Push / commit** — the build runs automatically
39+
5. Go to the **Actions** tab in your repo
40+
6. Click the latest workflow run → click **FileRedirect-dylib** under "Artifacts"
41+
7. **Download the zip** — it contains `FileRedirect.dylib` ready to inject
42+
43+
You can also trigger a build manually: Actions tab → "Build FileRedirect.dylib" → "Run workflow".
44+
45+
### Alternative: Build locally on macOS
46+
47+
If you do have access to a Mac:
48+
49+
```bash
50+
cd FileRedirectDylib
51+
make
52+
```
53+
54+
This produces `FileRedirect.dylib` targeting iOS arm64 (min iOS 12.0).
55+
56+
**Requirements:**
57+
- macOS with Xcode or Xcode Command Line Tools
58+
- iOS SDK (included with Xcode)
59+
60+
## Injecting into an IPA
61+
62+
### Option A: Using insert_dylib
63+
64+
```bash
65+
# 1. Unzip the IPA
66+
mkdir payload && cd payload
67+
unzip ../GameName.ipa
68+
69+
# 2. Copy dylib into the .app
70+
cp FileRedirect.dylib Payload/GameName.app/
71+
72+
# 3. Inject the load command
73+
insert_dylib --strip-codesig --inplace \
74+
@executable_path/FileRedirect.dylib \
75+
Payload/GameName.app/GameName
76+
77+
# 4. Re-zip as IPA
78+
zip -r ../GameName-modded.ipa Payload/
79+
```
80+
81+
### Option B: Using optool
82+
83+
```bash
84+
optool install -c load -p @executable_path/FileRedirect.dylib \
85+
-t Payload/GameName.app/GameName
86+
```
87+
88+
## Re-signing & Sideloading
89+
90+
After injection, the IPA needs to be re-signed:
91+
92+
- **iOS App Signer** (macOS GUI) — easiest option
93+
- **ldid**`ldid -S Payload/GameName.app/GameName`
94+
- **codesign**`codesign -f -s "Apple Development: you@email.com" Payload/GameName.app`
95+
96+
Then sideload with:
97+
- **AltStore** / **Sideloadly** / **TrollStore** (if available)
98+
99+
## Using Mods
100+
101+
1. Install the modded IPA on your device
102+
2. Open a file manager (e.g. Files app, or via iTunes File Sharing)
103+
3. Navigate to the app's `Documents/` folder
104+
4. Create a `disk/` subfolder if it doesn't exist (the dylib also auto-creates it)
105+
5. Place your modded files inside `disk/`, mirroring the `.app` bundle structure
106+
107+
### Example for GTA SA
108+
109+
If the original file is at:
110+
```
111+
GameName.app/texdb/gta3.txd
112+
```
113+
114+
Place your modded version at:
115+
```
116+
Documents/disk/texdb/gta3.txd
117+
```
118+
119+
The dylib will intercept the read and serve your file instead.
120+
121+
## Debugging
122+
123+
The dylib logs all redirected file accesses to the device console. View them with:
124+
125+
```bash
126+
# Via Xcode → Window → Devices and Simulators → Open Console
127+
# Or via idevicesyslog:
128+
idevicesyslog | grep "FileRedirect"
129+
```
130+
131+
Look for lines like:
132+
```
133+
[FileRedirect] fopen: /var/containers/.../MyApp.app/data/file.dat -> /var/containers/.../Documents/disk/data/file.dat
134+
```
135+
136+
To disable logging in production, set `REDIRECT_LOG_ENABLED` to `0` in `tweak.m`.
137+
138+
## Notes
139+
140+
- This works on **non-jailbroken** iOS via sideloading
141+
- The `.app` bundle is never modified at runtime — all redirection is in-memory
142+
- If a file is NOT in `Documents/disk/`, the original bundle file is used (no breakage)
143+
- Compatible with **Bully**, **GTA San Andreas**, **GTA III**, **GTA Vice City**, **Max Payne**, and other Rockstar iOS ports

0 commit comments

Comments
 (0)