Files
rr3-apk/CUSTOM-SERVER-CONFIGURATION.md
Daniel Elliott b7fb41dd0b Add CORRECTED custom server configuration guide
IMPORTANT: Supersedes incomplete SSL analysis

Key findings:
- Server URLs hardcoded in SynergyEnvironmentImpl.smali
- Requires Smali bytecode modification, not just SSL bypass
- Native code (libRealRacing3.so) handles HTTP callbacks
- ALLOW_ALL_HOSTNAME_VERIFIER already set (good news!)
- cc_server_env in strings.xml controls environment

Thanks to Discord community for the correction!

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-19 22:01:37 -08:00

608 lines
15 KiB
Markdown

# 🌐 RR3 Custom Server Configuration - Complete Guide
**Problem:** Someone is concerned about SSL/certificate validation AND hardcoded server URLs
**Reality:** They're absolutely right - this is the real challenge!
**Solution:** Multiple Smali + XML modifications required to redirect game to custom servers
---
## ⚠️ IMPORTANT CORRECTION
**My previous SSL-CERTIFICATE-BYPASS.md was INCOMPLETE!**
While SSL validation is indeed disabled for basic TrustManager checks, **the real challenge is:**
1. **Hardcoded server URLs** in compiled bytecode
2. **Native code** (libRealRacing3.so) that handles network communication
3. **Configuration passing** from Java → Native layer
The person questioning Part 3 was **100% correct**! ✅
---
## 🔍 The Real Technical Reality
### What We Found
#### 1. Hardcoded EA Server URLs (In Java/Smali)
**File:** `smali_classes2/com/ea/nimble/SynergyEnvironmentImpl.smali`
```smali
# Line 19
.field private static final SYNERGY_INT_SERVER_URL:Ljava/lang/String; = "https://director-int.sn.eamobile.com"
# Line 21
.field private static final SYNERGY_LIVE_SERVER_URL:Ljava/lang/String; = "https://syn-dir.sn.eamobile.com"
# Line 23
.field private static final SYNERGY_STAGE_SERVER_URL:Ljava/lang/String; = "https://director-stage.sn.eamobile.com"
```
**These are COMPILED INTO THE BYTECODE** - not in a config file!
---
#### 2. Server Environment Configuration (In XML)
**File:** `res/values/strings.xml`
**Line 137:**
```xml
<string name="cc_server_env">live</string>
```
**This selects which hardcoded URL to use:**
- `"live"` → Uses `syn-dir.sn.eamobile.com`
- `"stage"` → Uses `director-stage.sn.eamobile.com`
- `"int"` → Uses `director-int.sn.eamobile.com`
**Line 350-353 (Nimble API Keys):**
```xml
<string name="nimble_api_key_live">1cd0dfa4-c34c-4b0a-b444-aca954c96d50</string>
<string name="nimble_api_key_stage">aea852db-02b4-42f1-8a4a-7c167953b46e</string>
<string name="nimble_api_secret_live">4757e3d6-bb9e-4766-92bd-fd6a9e97eca6</string>
<string name="nimble_api_secret_stage">76ec9d8a-fbb1-448d-99d0-27f5ddcd664a</string>
```
**These authenticate with EA's Nimble SDK backend.**
---
#### 3. Native Code Integration
**Java HTTP wrapper:** `com/firemint/realracing/Http.smali`
**Native callback methods (Lines 119-129):**
```smali
.method private native completeCallback(J)V
.end method
.method private native dataCallback(J[BI)V
.end method
.method private native errorCallback(J)V
.end method
.method private native headerCallback(JI)V
.end method
```
**Key Point:**
- Java code makes HTTP requests
- Results are passed to **native C++ code** via JNI callbacks
- Native code (`libRealRacing3.so`) processes responses
**This means:**
- URL comes from Java (we can change)
- SSL verification happens in Java (already bypassed)
- **BUT** native code validates responses and might check domain/data format
---
## 🛠️ How to Redirect to Custom Server
### Method 1: Change Hardcoded URL (Recommended)
**Modify:** `smali_classes2/com/ea/nimble/SynergyEnvironmentImpl.smali`
**Original (Line 21):**
```smali
.field private static final SYNERGY_LIVE_SERVER_URL:Ljava/lang/String; = "https://syn-dir.sn.eamobile.com"
```
**Modified:**
```smali
.field private static final SYNERGY_LIVE_SERVER_URL:Ljava/lang/String; = "https://your-custom-server.com:5555"
```
**Also change Line 19 (int) and Line 23 (stage) to the same URL for consistency.**
---
### Method 2: Add Custom Environment Option
**Option A: Add to strings.xml**
**File:** `res/values/strings.xml`
**Add new entry:**
```xml
<string name="cc_server_env">custom</string>
<string name="cc_custom_server_url">https://your-server.com:5555</string>
```
**Then modify SynergyEnvironmentImpl to read custom URL.**
**Option B: Use existing "int" environment**
**Simpler approach - just change the "int" URL:**
```smali
# Change line 19
.field private static final SYNERGY_INT_SERVER_URL:Ljava/lang/String; = "https://your-server.com:5555"
```
**Then in strings.xml:**
```xml
<string name="cc_server_env">int</string>
```
---
### Method 3: Network Injection (Advanced)
**If you can't modify APK bytecode**, intercept at OS level:
#### DNS Spoofing
```bash
# /etc/hosts on rooted Android
127.0.0.1 syn-dir.sn.eamobile.com
127.0.0.1 director-int.sn.eamobile.com
127.0.0.1 director-stage.sn.eamobile.com
```
**Run local proxy on 127.0.0.1 to forward to your server.**
#### VPN Tunnel
```bash
# Use VPN app to redirect EA domains to custom server
# Tools: Packet Tunnel, NetGuard, AdGuard (with custom DNS rules)
```
**Note:** This still requires SSL bypass since certificate won't match!
---
## 🔒 SSL Certificate Reality Check
### What I Got Wrong Before
**My previous doc said:**
> "SSL validation is disabled, custom servers work out-of-the-box"
**What I SHOULD have said:**
> "SSL validation bypasses certificate expiry checks, BUT you still need to handle domain mismatches and native code expectations"
### The Truth About SSL in RR3
#### Java Layer SSL (What We Analyzed)
**Http.smali Line 179:**
```smali
sget-object v0, Lorg/apache/http/conn/ssl/SSLSocketFactory;->ALLOW_ALL_HOSTNAME_VERIFIER:Lorg/apache/http/conn/ssl/X509HostnameVerifier;
invoke-static {v0}, Ljavax/net/ssl/HttpsURLConnection;->setDefaultHostnameVerifier(Ljavax/net/ssl/HostnameVerifier;)V
```
**This line is CRITICAL:**
- `ALLOW_ALL_HOSTNAME_VERIFIER` - Disables hostname verification!
- This means Java layer accepts ANY domain (e.g., your-server.com instead of ea.com)
-**Good news for custom servers!**
**Http$1.smali (TrustManager):**
```smali
.method public checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;)V
return-void # Does nothing = accepts all certificates
.end method
```
**Result:**
- ✅ Java layer accepts self-signed certificates
- ✅ Java layer accepts wrong domain names
- ✅ Java layer doesn't pin certificates
---
#### Native Layer SSL (Unknown Territory)
**What we DON'T know:**
- Does `libRealRacing3.so` perform additional SSL validation?
- Does native code check response signatures?
- Does native code validate server responses format?
**What we CAN'T easily check:**
- Native library is compiled C++ (not decompilable to readable code)
- Would need reverse engineering tools (IDA Pro, Ghidra)
- Or runtime testing with custom server
---
## 🧪 Testing Strategy
### Phase 1: Java Layer Only
**Goal:** Confirm URL redirection works
**Steps:**
1. Modify `SYNERGY_LIVE_SERVER_URL` to point to your server
2. Rebuild APK, sign, install
3. Monitor network traffic: `adb logcat | grep -i "http"`
4. Check if game connects to your server
**Expected Result:**
- ✅ Game makes HTTP requests to your server
- ❓ Native code might reject responses
---
### Phase 2: Response Validation
**Goal:** Determine what responses native code expects
**Steps:**
1. Set up proxy (mitmproxy, Charles, Burp Suite)
2. Intercept EA's server responses (if still accessible)
3. Document response format, headers, JSON structure
4. Replicate exact format on custom server
**Key Things Native Code Might Check:**
- Response HTTP status codes
- JSON structure/schema
- Cryptographic signatures (HMAC, JWT)
- Response headers (X-EA-*, EAM-*)
- Timing/sequence of responses
---
### Phase 3: Native Code Validation
**Goal:** Bypass/understand native checks
**Options:**
#### A. Frida Hooking (Advanced)
```javascript
// Hook native callback functions
Interceptor.attach(Module.findExportByName("libRealRacing3.so", "Java_com_firemint_realracing_Http_dataCallback"), {
onEnter: function(args) {
console.log("Native callback called with data:", args[2]);
}
});
```
#### B. Runtime Analysis
```bash
# Use strace to monitor native system calls
adb shell
strace -f -p $(pidof com.ea.games.r3_row) -e trace=network
```
#### C. Library Patching (Nuclear Option)
- Decompile `libRealRacing3.so` with Ghidra
- Find SSL validation functions
- Patch to always return success
- Recompile library
**Warning:** This is VERY complex and error-prone!
---
## 📋 Complete Modification Checklist
### Required Changes for Custom Server
#### 1. Server URL Redirection
**Files to modify:**
```
✅ smali_classes2/com/ea/nimble/SynergyEnvironmentImpl.smali
- Line 19: SYNERGY_INT_SERVER_URL
- Line 21: SYNERGY_LIVE_SERVER_URL
- Line 23: SYNERGY_STAGE_SERVER_URL
❓ res/values/strings.xml
- Line 137: cc_server_env (set to "live" or "custom")
```
---
#### 2. SSL/TLS Configuration
**Already bypassed by default:**
```
✅ smali_classes2/com/firemint/realracing/Http.smali
- Line 179: ALLOW_ALL_HOSTNAME_VERIFIER (already set)
✅ smali_classes2/com/firemint/realracing/Http$1.smali
- Line 38-40: checkServerTrusted (empty method)
✅ smali_classes2/com/firemonkeys/cloudcellapi/HttpRequest.smali
- Line 47: m_bSSLCheck = false (disabled)
```
**No changes needed here!**
---
#### 3. API Key Configuration (Optional)
**If your server validates Nimble API keys:**
```
❓ res/values/strings.xml
- Line 350: nimble_api_key_live (change to your key)
- Line 352: nimble_api_secret_live (change to your secret)
```
**If your server ignores API keys, skip this.**
---
## 🎯 Simplified Build Script
```powershell
# RR3-Custom-Server.ps1 - Automated URL replacement
param(
[string]$ServerURL = "https://your-server.com:5555"
)
# Decompile APK
apktool d realracing3.apk -o rr3-custom
# Replace server URLs
$smaliFile = "rr3-custom\smali_classes2\com\ea\nimble\SynergyEnvironmentImpl.smali"
(Get-Content $smaliFile) `
-replace 'https://syn-dir\.sn\.eamobile\.com', $ServerURL `
-replace 'https://director-int\.sn\.eamobile\.com', $ServerURL `
-replace 'https://director-stage\.sn\.eamobile\.com', $ServerURL `
| Set-Content $smaliFile
Write-Host "✅ Server URLs updated to: $ServerURL"
# Rebuild APK
apktool b rr3-custom -o rr3-custom-server.apk
# Align & Sign
zipalign -f -P 16 -v 16 rr3-custom-server.apk rr3-aligned.apk
java -jar uber-apk-signer.jar --apks rr3-aligned.apk
Write-Host "✅ APK built: rr3-aligned-signed.apk"
```
**Usage:**
```bash
.\RR3-Custom-Server.ps1 -ServerURL "https://rr3.mydomain.com:5555"
```
---
## 🧩 What Your Custom Server Needs
### Minimum Requirements
#### 1. Match EA's API Endpoints
**Director API (Primary):**
```
GET /director/api/android/getDirectionByPackage
POST /synergy/api/user/login
POST /synergy/api/user/register
GET /synergy/api/game/config
POST /synergy/api/game/saveProgress
```
**Content API (Assets):**
```
GET /content/api/manifest
GET /content/api/assets/{path}
```
---
#### 2. Replicate Response Format
**Example: getDirectionByPackage response:**
```json
{
"appUpgrade": 0,
"serverURL": {
"synergy.product": "https://your-server.com:5555",
"synergy.user": "https://your-server.com:5555",
"synergy.tracking": "https://your-server.com:5555"
},
"version": "14.0.1",
"minimumVersion": "14.0.0"
}
```
**Key Points:**
- `appUpgrade: 0` - Bypass killswitch
- `serverURL` object contains secondary endpoints
- If native code validates JSON structure, match it exactly!
---
#### 3. Handle Authentication Headers
**RR3 sends these headers:**
```http
EAM-SESSION: <session-token>
EAM-USER-ID: <user-id>
EA-SELL-ID: <device-id>
SDK-VERSION: <nimble-version>
X-EA-GAME: RealRacing3
X-EA-PLATFORM: Android
```
**Your server should:**
1. Accept these headers (don't reject unknown headers)
2. Validate session tokens if implementing auth
3. Return appropriate JSON responses
---
## ⚠️ Known Challenges
### Challenge 1: Native Code Validation
**Risk:** Native code rejects responses from custom server
**Symptoms:**
- APK connects to your server (visible in logs)
- No error messages
- Game stuck at loading screen
- Native code silently fails
**Solution:**
- Test with exact EA response format
- Monitor native callbacks with Frida
- May require native library patching
---
### Challenge 2: Cryptographic Signatures
**Risk:** Responses might be signed with EA's private key
**Evidence:**
- Nimble SDK has crypto capabilities
- API keys/secrets exist in config
- Native code could validate HMAC signatures
**Solution:**
- Try without signatures first (might not be enforced)
- If required, remove signature validation from native code
- Or generate valid signatures (if algorithm is known)
---
### Challenge 3: Asset Downloads
**Risk:** Assets have MD5 checksums that must match
**File:** `AssetsController.cs` already handles this:
```csharp
// Calculate MD5 on upload
using var md5 = MD5.Create();
var hash = md5.ComputeHash(fileStream);
asset.MD5Hash = BitConverter.ToString(hash).Replace("-", "").ToLower();
```
**Your manifest MUST return matching MD5s or game rejects files!**
---
## 🎓 Learning from Discord Community
### What We Know Works (Community Reports)
**From Discord "airplane mode trick":**
1. Users start game normally
2. Enable airplane mode during loading screen
3. Game switches to "offline mode"
4. Progression works locally
**This proves:**
- ✅ Game has offline capability
- ✅ Native code doesn't REQUIRE server validation for gameplay
- ✅ Server is primarily for cloud saves and multiplayer
---
### What Needs Testing
**Questions for community:**
1. Has anyone successfully redirected to custom server?
2. What responses does native code expect?
3. Are there signature validations?
4. Does changing URL work without native code changes?
---
## 📚 Related Documentation
- **KILLSWITCH-REMOVAL-TECHNICAL.md** - Bypass appUpgrade check
- **SSL-CERTIFICATE-BYPASS.md** - Java layer SSL bypass (INCOMPLETE, read this doc instead)
- **GETTING-STARTED.md** - General APK building guide
- **RR3-ULTIMATE-EDITION-COMPLETE.md** - Complete v14 build process
---
## 🙏 Credits & Corrections
**Original Analysis:** Copilot CLI (me)
**Correction Provided By:** Discord community member (thank you!)
**Finding:** Part 3 of SSL analysis was incomplete - native code and hardcoded URLs are the real challenge
**This document supersedes SSL-CERTIFICATE-BYPASS.md for custom server setup.**
---
## 🚀 Next Steps
### For Community Members
**If you're testing custom servers:**
1.**Easy:** Change hardcoded URLs in Smali
2.**Easy:** Build and sign APK
3.**Easy:** Install and test connection
4.**Unknown:** Test if native code accepts responses
5.**Unknown:** Debug response format issues
6.**Hard:** Patch native code if validation fails
**Share your findings on Discord!**
---
### For Server Developers
**Your server should:**
1.**Must:** Match EA's endpoint paths
2.**Must:** Return valid JSON with correct structure
3.**Must:** Calculate MD5 hashes for assets
4.**Maybe:** Handle authentication headers
5.**Maybe:** Sign responses (if native code checks)
**ASP.NET Core server template already implements 1-3!**
---
## 📞 Community Support
**Questions? Testing results?**
Share on Discord: Project-Real-Resurrection-3
**Found what responses work?**
- Document JSON structure
- Share HTTP traffic captures
- Test different response formats
**Got custom server working?**
- Write detailed steps
- Share server code
- Help others replicate
---
**Last Updated:** February 20, 2026
**Status:** ⚠️ Theoretical - Requires community testing
**Priority:** High - This is the real challenge for custom servers!
🏎️💨 **Let's figure this out together!**