🇬🇧 English Documentation | 🇸🇦 التوثيق باللغة العربية
Captured directly on Android 15 (TECNO CL8, MT6896) via ADB. 3D GL rendering, music, sound effects, physics, and gameplay fully restored.
This repository is structured as an exhaustive, peer-verifiable forensic dossier for reverse engineering, binary preservation, and reproducibility:
snailmail/
├── 📁 original/ # Original 2011 APK forensics
│ ├── APK_METADATA.md # Package identity, SDK configuration, MD5/SHA1/SHA256
│ ├── CERTIFICATE_INFO.txt # Sandlot Games CEO certificate dump (RSA 1024-bit)
│ ├── APK_FILE_TREE.txt # Exact zip header records, CRC32, compressed sizes
│ └── HASHES_ORIGINAL.sha256 # SHA-256 checksums of every single component
├── 📁 analysis/ # Failure analysis & runtime diagnostics
│ ├── logcat/ # Raw crash logs (VerifyError, SIGABRT, OpenFeint NPE)
│ ├── readelf/ # llvm-readelf headers, DT_NEEDED, DT_TEXTREL diffs
│ ├── disassembly/ # Side-by-side assembly diffs of JNIDatInit & OpenFeint
│ └── jni_art_deepdive.md # Dalvik vs ART reference table failure mechanics
├── 📁 patches/ # Exact byte-level diffs
│ ├── manifest_binary.diff.md # AXML binary chunk modifications
│ ├── jni_opcode.diff.md # 1-byte opcode surgery (0x5c -> 0x58: DeleteGlobalRef)
│ └── openfeint_stubs.diff.md # Minimal ARM assembly stubs for dead network calls
├── 📁 verification/ # Device and runtime proofs
│ ├── DEVICE_COMPATIBILITY.md # Android 14/15, MediaTek Dimensity 8200, 32-bit execution
│ └── SUSTAINED_RUN_LOGS.txt # Continuous 60 FPS process monitoring log
├── 📁 reproducibility/ # Complete reproducibility matrix
│ ├── COMPONENT_HASHES_MATRIX.md # PRE/POST HASH MATRIX FOR ALL 237 COMPONENTS
│ ├── checksums_manifest.json # Machine-readable JSON with all file checksums
│ └── REPRODUCE.md # Step-by-step reproduction guide
└── 📁 screenshots/ # Gameplay proof captured on live Android 15 device
├── gameplay_1.png
└── gameplay_2.png
Tip
View the Complete Pre/Post Hash Matrix: Check reproducibility/COMPONENT_HASHES_MATRIX.md to verify that 233 out of 237 files (98.3%) are 100% bit-for-bit identical to the 2011 release.
All credit, copyright, and intellectual property for Snail Mail belong to Sandlot Games (and its successors).
Originally released for PC in 2004 and ported to Android in 2011, Snail Mail is a timeless nostalgic classic. Its fast-paced galactic tracks, catchy music, vibrant graphics, and the iconic protagonist Turbo the snail brought joy to millions of players worldwide.
This restoration project was undertaken strictly for historical preservation, educational research, and reverse engineering study. It demonstrates how classic native Android games from the early Dalvik/Froyo era can be revived on cutting-edge 64/32-bit Android 14 & 15 runtimes without source code access and without altering any original game assets.
In this restoration, no game assets were modified, recompressed, or altered in any way:
- 3D Models, Textures, and Level Data (
assets/asm.mp3):- Exact File Size:
8,188,993bytes - SHA-256 Hash:
59740ec3a2cd1f7e9ff250e3c6128ffff922193925e3d0316db22a4118861b6a - Stored completely uncompressed (
ZIP_STORED/ 0% compression) with 4-byte alignment, exactly as required by the native archive loader.
- Exact File Size:
- Audio & Sound Effects: All 171
.ogg,.mp3, and.wavaudio files remain byte-identical to the 2011 release. - Bytecode Integrity: The original Dalvik executable
classes.dexremains 100% untouched to preserve class verifier integrity.
When installing the original 2011 APK on Android 14/15, multiple modern OS security layers and runtime differences prevented it from running:
Original APK (2011)
│
❌ Blocked by OS ▼ [INSTALL_FAILED_DEPRECATED_SDK_VERSION]
Fix: Binary AXML patch (minSdkVersion = 28)
│
❌ Rejected Signature ▼ [INSTALL_PARSE_FAILED_NO_CERTIFICATES]
Fix: Modern RSA-2048 / SHA-256 APK signing
│
❌ Crash on dlopen() ▼ [library "libstdc++.so" not found]
Fix: In-place DT_NEEDED rewrite: libstdc++.so -> libc.so
│
❌ Linker Security ▼ [DT_TEXTREL is not allowed]
Fix: DT_TEXTREL -> DT_NULL & .rel.dyn nullification
│
❌ SIGABRT on JNIDatInit▼ ['Attempt to delete global reference as local JNI reference']
Fix: 1-byte opcode patch in libsnailmail.so (0x5c -> 0x58: DeleteGlobalRef)
│
❌ NullPointerException ▼ [OpenFeintInternal.getCurrentUser() on null object]
Fix: ARM assembly stubs in libsnailmail.so for dead OpenFeint C++ functions
│
🎮 Snail Mail running smoothly on Android 15!
- Issue: Android 14+ blocks installing apps with
targetSdkVersion < 23orminSdkVersion < 23(INSTALL_FAILED_DEPRECATED_SDK_VERSION). - Fix: Directly modified the binary AndroidManifest.xml (AXML) in-place: set
minSdkVersionattribute to28and cleanly removed the obsolete<application android:name="...">attribute.
- Issue: The 2011 APK was signed with RSA 1024-bit and SHA-1, which modern Android package managers strictly reject.
- Fix: Resigned the package using RSA 2048-bit with SHA-256 and aligned zip entries.
- Issue: Early Android NDK binaries linked against
libstdc++.so. On Android 7.0+, Google isolated linker namespaces and deprecatedlibstdc++.so, causing:java.lang.UnsatisfiedLinkError: dlopen failed: library "libstdc++.so" not found. - Fix: The only symbols imported were
_Znwj(operator new) and__cxa_guard_*, which already exist inside standardlibc.so. TheDT_NEEDEDentry forlibstdc++.sowas redirected in-place tolibc.sowith zero byte displacement.
- Issue: Android 6.0+ prohibits text relocations (
DT_TEXTREL) in shared libraries for security reasons. - Fix: Neutralized the
DT_TEXTRELtag toDT_NULLand cleared the 12 text relocation entries in.rel.dynthat belonged to unused unwind tables.
- Issue: In
Java_com_sandlotgames_snailmail_SnailMailActivity_JNIDatInit, the C++ code creates a global reference tojava.io.FileDescriptorusingNewGlobalRef(offset0x54), but at function exit it cleans it up usingDeleteLocalRef(offset0x5c):While old Dalvik (2010) silently ignored this mismatch, modern Android ART strictly verifies reference types in0x1543c: ldr pc, [r3, #0x5c] ; (*env)->DeleteLocalRef(env, global_ref)LocalReferenceTable::Remove(void*)and aborts immediately withSIGABRT:Abort message: 'Attempt to delete global reference reference as local JNI reference' - Fix: Changed the offset from
0x5cto0x58inlibsnailmail.so(armeabi-v7aat0x1543c,armeabiat0x15d30):This 1-byte opcode patch calls the correct0x1543c: ldr pc, [r3, #0x58] ; (*env)->DeleteGlobalRef(env, global_ref)DeleteGlobalRefmethod, perfectly satisfying ART's strict reference tracker!
-
Issue: The game called OpenFeint social gaming network APIs. OpenFeint was discontinued in December 2012. Calling
JAVAOpenFeintLastLoggedInUserIDresulted in a fatalNullPointerExceptioninside the OpenGL rendering thread (GLThread). -
Fix: Patched the 7 C++ OpenFeint wrapper functions with minimal native ARM assembly stubs:
_Z21JAVAOpenFeintIsOnlinev:mov r0, #0; bx lr(Reports offline)_Z27JAVAOpenFeintIsUserLoggedInv:mov r0, #0; bx lr(Reports not logged in)_Z31JAVAOpenFeintLastLoggedInUserIDPci:strb r1, [r0]; mov r0, #0; bx lr(Returns empty user ID"")_Z17JAVAOpenFeintOpenv,_Z19JAVAOpenFeintSubmitPcii,_Z19JAVAOpenFeintUnlockPci:bx lr(No-op)
This tells the native game engine that it is in offline mode, causing it to immediately fall back to its robust local profile and local save systems without ever querying network servers.
- Download the modern APK from this repository:
- SnailMail_DirectPlay.apk (13.2 MB)
- Install via ADB:
Or transfer the APK to your phone and install it using your preferred file manager (enable "Install unknown apps" if prompted).
adb install -r SnailMail_DirectPlay.apk
- Launch Snail Mail and enjoy!
To reproduce the patch from the original 2011 APK:
# Prerequisites: Python 3.8+, JDK (jarsigner)
python patch_snailmail.pyDon't just take our word for it — run the automated verification tool to independently validate all 23 scientific checkpoints across both ABIs, memory alignment, cryptographic signatures, and asset preservation:
python verification.py================================================================================
SNAIL MAIL (2011) - SCIENTIFIC REPRODUCIBILITY VERIFICATION
================================================================================
[SUITE 1] ORIGINAL ASSET INTEGRITY (ZERO ASSET MODIFICATION)
[PASS] assets/asm.mp3 SHA-256 bit-for-bit match (59740ec3a2cd1f7e...)
[PASS] assets/asm.mp3 exact size match (8,188,993 bytes)
[PASS] All 170 audio tracks (.ogg/.mp3/.wav) 100% bit-identical (170 files verified)
[SUITE 2] DALVIK BYTECODE VERIFIER INTEGRITY
[PASS] classes.dex SHA-256 bit-for-bit identical to 2011 (b430e061e63dba68...)
[PASS] classes.dex exact size match (397,560 bytes)
[PASS] Zero Dalvik instruction tampering (prevents ART VerifyError)
[SUITE 3] ELF SHARED LIBRARY SURGERY (libsnailmail.so)
[PASS] [armeabi-v7a] File size exact match (0-byte shift) (670,897 bytes)
[PASS] [armeabi-v7a] JNI DeleteLocalRef -> DeleteGlobalRef opcode fix (@ 0x1543c: 0x5c -> 0x58)
[PASS] [armeabi-v7a] OpenFeint C++ offline stubs injected
[PASS] [armeabi-v7a] Linker namespace libstdc++.so redirected to libc.so
[PASS] [armeabi] File size exact match (0-byte shift) (707,235 bytes)
[PASS] [armeabi] JNI DeleteLocalRef -> DeleteGlobalRef opcode fix (@ 0x15d30: 0x5c -> 0x58)
[PASS] [armeabi] OpenFeint C++ offline stubs injected
[PASS] [armeabi] Linker namespace libstdc++.so redirected to libc.so
[SUITE 4] ANDROIDMANIFEST.XML BINARY COMPATIBILITY
[PASS] minSdkVersion upgraded to 28 (Android 9+) (bypasses Android 14/15 deprecation)
[PASS] Obsolete OpenFeint SnailMailApplication cleanly removed
[SUITE 5] APK STORAGE & MEMORY ALIGNMENT (ZIPALIGN)
[PASS] assets/asm.mp3 stored uncompressed (ZIP_STORED) for mmap/openFd
[PASS] assets/asm.mp3 4-byte memory aligned
[PASS] lib/**/*.so 4096-byte page aligned (Android 15 requirement)
[SUITE 6] CRYPTOGRAPHIC SIGNATURE SCHEME
[PASS] Valid APK signature block present (META-INF/*.SF, *.RSA)
[PASS] Official Android SDK apksigner verification (Scheme v2/v3) (Android 14/15 Verified)
[SUITE 7] GLOBAL PRESERVATION RATIO (BIT-FOR-BIT ACCURACY)
[PASS] 233 / 236 files (98.73%) are 100% bit-for-bit identical to 2011 release
[PASS] Only 3 components surgically patched for modern OS compatibility (Manifest, v7a .so, armeabi .so)
================================================================================
VERDICT: ALL 23/23 VERIFICATION CHECKS PASSED (100% SCIENTIFIC COMPLIANCE)
================================================================================
Note
Transparency Note regarding snailmail_modern.jks:
The keystore snailmail_modern.jks (password: snailmail123) is deliberately included in this repository. It is a public, disposable test keystore created solely for deterministic reproducibility so that anyone building the project produces an APK signed with the exact same test certificate, allowing seamless installation, testing, and updates without signature mismatch warnings.
The script will read com.sandlotgames.snailmail.apk, verify the assets hash, apply the binary patches with zero-byte displacement, align entries, and output SnailMail_DirectPlay.apk.
كافة حقوق الملكية الفكرية، وحقوق النشر، والرسوميات، والأصوات الخاصة بلعبة Snail Mail تعود بالكامل للشركة المطورة الأصلية Sandlot Games.
صدرت اللعبة لأول مرة على أجهزة الكمبيوتر عام 2004، ثم نُقلت إلى نظام أندرويد عام 2011. تميزت اللعبة بمساراتها الفضائية المليئة بالحماس، وموسيقاها الإلكترونية الأيقونية، وشخصية الحلزون الفضائي (Turbo).
هذا العمل يهدف بشكل أساسي إلى الحفظ التاريخي للبرمجيات الكلاسيكية والتوثيق التعليمي والهندسة العكسية، لإثبات إمكانية إحياء ألعاب أندرويد الكلاسيكية المبنية في عصر أندرويد 2.2 لتعمل مباشرة على أحدث أنظمة أندرويد (أندرويد 14 و15) دون الحاجة للشيفرة المصدرية، ودون المساس بأي من أصول اللعبة الأصلية.
أحد أهم شروط هذا المشروع كان عدم التعديل على أي ملف من ملفات اللعبة الأصلية أو إعادة ضغطها:
- أرشيف المراحل والمجسمات ثلاثية الأبعاد (
assets/asm.mp3):- حجم الملف الأصلي:
8,188,993بايت. - بصمة التشفير (SHA-256):
59740ec3a2cd1f7e9ff250e3c6128ffff922193925e3d0316db22a4118861b6a. - مخزن بنسبة ضغط
0%(بدون ضغط) ومحاذاة 4 بايت لمطابقة ذاكرة المحرك.
- حجم الملف الأصلي:
- الأصوات والموسيقى: جميع الملفات الصوتية الـ 171 ملفاً (بصيغ OGG و MP3 و WAV) مطابقة للأصل بالبايت.
- كود دالفيك (
classes.dex): لم يتم التعديل على تعليمات بايتكود دالفيك لتجنب أي رفض من فاحص الأمان (ART Verifier).
- المشكلة: يمنع نظام أندرويد 14/15 تثبيت التطبيقات التي تستهدف إصدارات قديمة (
INSTALL_FAILED_DEPRECATED_SDK_VERSION). - الحل: تم تعديل ملف
AndroidManifest.xmlالثنائي مباشرة دون فك الحزمة إلى Smali: رفع قيمةminSdkVersionإلى28، وإزالة السمة القديمة<application android:name="...">.
- المشكلة: كانت الحزمة الأصلية موقّعة بخوارزمية قديمة (RSA 1024-bit و SHA-1) يرفضها أندرويد الحديث لأسباب أمنية.
- الحل: إعادة توقيع الحزمة بشهادة حديثة RSA 2048-bit مع بصمة SHA-256.
- المشكلة: مكتبة المحرك
libsnailmail.soكانت تطلبlibstdc++.soالتي حذفتها جوجل من أندرويد 7.0 وما بعده، مما كان يفجر خطأUnsatisfiedLinkError: dlopen failed: library "libstdc++.so" not found. - الحل: تم فحص الرموز المطلوبة، وتبين أنها تقتصر على
operator newوguardوهي متوفرة داخلlibc.soالقياسية؛ فتم استبدال اسم المكتبة المطلوبة في ترويسة ELF الثنائية بدون تغيير في حجم الملف.
- المشكلة: أندرويد 6.0 وما بعده يحظر تحميل المكتبات التي تحتوي على Text Relocations.
- الحل: تحييد راية
DT_TEXTRELإلىDT_NULL، وتصفير إدخالات الـ relocations الـ 12 غير المستخدمة في جداول الـ Unwind.
- المشكلة: في كود C++ الأصلي الخاص بقراءة ملف المراحل
JNIDatInit: قام المطور بإنشاء مرجع عام لكلاس واصف الملفNewGlobalRef(إزاحة0x54)، ولكنه عند مسحه استدعى بالخطأDeleteLocalRef(إزاحة0x5c):نظام دالفيك القديم عام 2010 كان يتساهل مع هذا الخطأ، أما نظام تشغيل أندرويد الحديث ART فيفحص نوع المرجع بدقة بالغة، وعند مسح مرجع عام كمرجع محلي يُسقط النظام اللعبة فوراً برسالة:0x1543c: ldr pc, [r3, #0x5c] ; (*env)->DeleteLocalRef(env, global_ref)Abort message: 'Attempt to delete global reference reference as local JNI reference' - الحل: تم تعديل بايت واحد فقط في تعليمة المعالج من
0x5cإلى0x58لاستدعاء دالةDeleteGlobalRefالصحيحة، ليتطابق نوع المرجع مع جدول ART وتعمل الدالة بسلام!
-
المشكلة: عند تشغيل المحرك ثلاثي الأبعاد، كان يستدعي دالة فحص معرّف اللاعب
JAVAOpenFeintLastLoggedInUserIDالتي تفجر استثناءNullPointerExceptionفي خيط الرسوميات لأن خوادم الشبكة مغلقة نهائياً منذ ديسمبر 2012. -
الحل: تم حقن دوال بديلة قصيرة جداً (Stubs) بلغة تجميع ARM:
- دالة
IsOnlineترجع دائماً0(غير متصل). - دالة
IsUserLoggedInترجع دائماً0(غير مسجل). - دالة
LastLoggedInUserIDتضع قيمة خالية""وتعود فوراً.
بهذا الإجراء يدرك محرك اللعبة تلقائياً أنه في وضع اللعب الفردي دون اتصال، فيفتح شاشة اللعبة فوراً ويعتمد على ملف الحفظ المحلي بالكامل.
- دالة
- حمّل ملف التطبيق الجاهز مباشرة من هذا المستودع:
- SnailMail_DirectPlay.apk (بحجم 13.2 ميجابايت).
- ثبته عبر سطر الأوامر ADB:
أو انسخه إلى هاتفك وثبته عبر أي مدير ملفات (مع السماح بتثبيت التطبيقات من مصادر غير معروفة).
adb install -r SnailMail_DirectPlay.apk
- استمتع برحلتك الفضائية مع الحلزون السريع! 🐌✨
إذا أردت إعادة توليد الحزمة وتطبيق الإصلاحات بنفسك:
# المتطلبات: Python 3.8+ و JDK (أداة jarsigner)
python patch_snailmail.pyيقوم السكربت بفحص بصمة ملفات الأصول الأصلية للتأكد من عدم المساس بها، ثم يطبق التعديلات الثنائية الدقيقة ويخرج حزمة جاهزة وموقعة تلقائياً.
This repository is strictly for preservation and educational purposes. All assets, trademarks, and game code belong to Sandlot Games. If you are a copyright holder and have questions or concerns, please open an issue in this repository.

