dart_vm_injector 1.0.0 copy "dart_vm_injector: ^1.0.0" to clipboard
dart_vm_injector: ^1.0.0 copied to clipboard

Ultra-pro Dart package for injecting and evaluating expressions in live Dart VM isolates via VM Service (WebSocket/JSON-RPC), designed for advanced debugging, live inspection, hot-patching, and securi [...]

dart_vm_injector πŸ”¬ #

pub package Dart SDK License: MIT style: lints

⚠️ Security Warning
This package opens a direct, unrestricted channel to the live Dart VM heap β€” including all in-memory secrets (passwords, API tokens, private keys, PII).
Use only with explicit authorisation on systems you own or are permitted to inspect.


Inject and evaluate arbitrary Dart expressions inside live, running Dart VM Isolates without stopping, restarting, or modifying the target application.

Powered by the official Dart VM Service Protocol (WebSocket + JSON-RPC 2.0).


✨ Features #

Feature Description
πŸ”Œ Connect WebSocket connection to any live Dart VM
πŸ” Discover List all running Isolates with full metadata
πŸ’‰ Inject Evaluate any valid Dart expression in a live Isolate
πŸ‘οΈ Watch Continuous polling streams for any variable or expression
πŸ“‘ Stream Subscribe to VM stdout / stderr / events in real-time
πŸ”­ Inspect Deep heap inspection via getObject / getInstances
πŸ›‘οΈ Type-safe Strongly-typed API with meaningful exception hierarchy
πŸ“Š Stats Per-session latency and injection counters

⚠️ Requirements #

This package works only with JIT-compiled Dart programs running with the --enable-vm-service flag.

Scenario Works?
dart run your_app.dart βœ…
dart run --enable-vm-service your_app.dart βœ…
dart run --observe your_app.dart βœ…
Flutter debug mode βœ…
Flutter profile mode βœ…
dart compile exe your_app.dart (AOT) ❌
Flutter release mode ❌

πŸš€ Quick Start #

1. Add to pubspec.yaml #

dependencies:
  dart_vm_injector: ^1.0.0

2. Start your target app with VM Service enabled #

dart run --enable-vm-service your_app.dart

You will see:

The Dart VM service is listening on http://127.0.0.1:8181/FmMJoBzneFU=/

3. Inject an expression #

import 'package:dart_vm_injector/dart_vm_injector.dart';

void main() async {
  // One-shot injection β€” connects, evaluates, disconnects
  final result = await VmInjector.inject(
    3495637284,                  // isolate number from startup output
    'userService.currentUser?.email ?? "none"',
    token: 'FmMJoBzneFU',        // from the VM service URL
  );

  print(result.valueAsString);   // admin@example.com
  print(result.latency);         // Duration(milliseconds: 12)
}

πŸ“– API Reference #

One-shot static methods #

// Inject into a specific Isolate and disconnect immediately
final r = await VmInjector.inject(isolateNumber, expression, token: '...');

// Inject into the main Isolate (auto-detected)
final r = await VmInjector.injectMain(expression, token: '...');

Persistent session #

// Open a reusable session
final injector = await VmInjector.connect(
  host: '127.0.0.1',
  port: 8181,
  token: 'YourToken',
);

try {
  // List Isolates
  final isolates = await injector.listIsolates();

  // Evaluate expressions
  final r = await injector.evaluateInIsolate(12345, '2 + 2');
  final r = await injector.evaluateInMainIsolate('"hello"');
  final r = await injector.evaluateInNamedIsolate('worker', 'queue.length');

  // Evaluate in a paused stack frame
  final r = await injector.evaluateInFrame(12345, 0, 'localVar');

  // Watch a variable (continuous polling stream)
  await for (final e in injector.watch(12345, 'requestCount', interval: 1.seconds)) {
    print('requestCount = ${e.value}');
  }

  // Live VM streams
  injector.stdout.listen(print);
  injector.stderr.listen(print);
  injector.vmEvents.listen((e) => print(e.kind));

  // Deep object inspection
  final obj = await injector.getObject(12345, result.instanceId!);
  final instances = await injector.getInstances(12345, 'objects/class/42');

  // Lifecycle control
  await injector.pauseIsolate(12345);
  await injector.resumeIsolate(12345);

  // Statistics
  print(injector.stats);
} finally {
  await injector.dispose();
}

πŸ”¬ How It Works #

Your code            dart_vm_injector        Dart VM (JIT)
─────────────────────────────────────────────────────────────
VmInjector.inject()
  β”‚
  β”œβ”€β–Ί WebSocket handshake ─────────────────► VM Service (port 8181)
  β”‚                                              β”‚
  β”œβ”€β–Ί getVM() JSON-RPC ────────────────────────► β”‚ list isolates
  β”‚   ◄─────────────────── IsolateRef[] ──────────
  β”‚                                              β”‚
  β”œβ”€β–Ί getIsolate(id) ──────────────────────────► β”‚ get root library
  β”‚   ◄─────────────────── Isolate{rootLib} ──────
  β”‚                                              β”‚
  β”œβ”€β–Ί evaluate(isolateId, libId, expr) ────────► β”‚
  β”‚                                         JIT compiler
  β”‚                                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                                         β”‚ parse expr      β”‚
  β”‚                                         β”‚ β†’ AST           β”‚
  β”‚                                         β”‚ β†’ kernel IR     β”‚
  β”‚                                         β”‚ β†’ bytecode      β”‚
  β”‚                                         β”‚ execute in heap β”‚
  β”‚                                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  β”‚   ◄──────────── InstanceRef{valueAsString} ───
  β”‚
  └─► InjectionResult{valueAsString, valueKind, instanceId}

The evaluate RPC is implemented by the incremental Dart compiler embedded in every JIT runtime. It compiles the expression in the scope of a specific Library, executes the resulting bytecode on the target Isolate's thread, and returns an InstanceRef β€” a reference to the live heap object.


🧭 Finding the Isolate Number #

The Isolate number is the numeric portion of the Isolate ID (isolates/XXXXXXXXXX).

final injector = await VmInjector.connect(host: 'localhost', port: 8181, token: '...');
final isolates = await injector.listIsolates();
for (final iso in isolates) {
  print('${iso.number}  ${iso.name}');  // 3495637284  main
}

Method 2 β€” Observatory UI #

Open http://127.0.0.1:8181/FmMJoBzneFU=/ in a browser β†’ Isolates tab.

Method 3 β€” dart:developer #

import 'dart:developer' as dev;

void main() {
  print(dev.Service.getIsolateID(Isolate.current));
  // prints: isolates/3495637284
}

πŸ”’ Security Model #

What the VM Service exposes #

Capability Risk
Read any live variable πŸ”΄ High β€” secrets, tokens, PII
Write any live variable πŸ”΄ High β€” bypass auth, corrupt state
Call any function πŸ”΄ High β€” arbitrary side effects
Trigger GC 🟑 Medium β€” service disruption
Kill Isolate πŸ”΄ High β€” DoS
Read call stacks 🟑 Medium β€” logic exposure

Defence in depth #

  1. Never run --enable-vm-service on public-facing production servers.
  2. Restrict the VM Service port with firewall rules (iptables, ufw, security groups).
  3. Never use --disable-service-auth-codes β€” the random token is your only layer of protection.
  4. Audit all injections β€” log every expression evaluated in a tamper-proof audit trail.
  5. Prefer --observe (profile mode) over debug when you need live inspection β€” it is slightly faster.
  6. Use TLS tunnelling (e.g. SSH port-forward) when connecting to remote VMs.

πŸ—‚οΈ Package Structure #

dart_vm_injector/
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ dart_vm_injector.dart          ← Barrel export
β”‚   └── src/
β”‚       β”œβ”€β”€ vm_injector.dart           ← VmInjector β€” main class
β”‚       β”œβ”€β”€ vm_connection.dart         ← WebSocket connection management
β”‚       β”œβ”€β”€ isolate_resolver.dart      ← Isolate discovery & resolution
β”‚       β”œβ”€β”€ expression_evaluator.dart  ← evaluate / evaluateInFrame / invoke
β”‚       β”œβ”€β”€ result_parser.dart         ← InstanceRef β†’ InjectionResult
β”‚       β”œβ”€β”€ stream_listener.dart       ← Live VM event streams
β”‚       β”œβ”€β”€ models/
β”‚       β”‚   β”œβ”€β”€ injection_result.dart
β”‚       β”‚   β”œβ”€β”€ isolate_info.dart
β”‚       β”‚   β”œβ”€β”€ vm_connection_config.dart
β”‚       β”‚   β”œβ”€β”€ vm_connection_stats.dart
β”‚       β”‚   └── watch_event.dart
β”‚       β”œβ”€β”€ exceptions/
β”‚       β”‚   β”œβ”€β”€ vm_connection_exception.dart
β”‚       β”‚   β”œβ”€β”€ isolate_not_found_exception.dart
β”‚       β”‚   β”œβ”€β”€ injection_failed_exception.dart
β”‚       β”‚   β”œβ”€β”€ aot_mode_exception.dart
β”‚       β”‚   └── vm_timeout_exception.dart
β”‚       └── utils/
β”‚           β”œβ”€β”€ logger.dart
β”‚           └── websocket_helper.dart
β”œβ”€β”€ example/
β”‚   β”œβ”€β”€ basic_inject.dart
β”‚   β”œβ”€β”€ list_isolates.dart
β”‚   β”œβ”€β”€ watch_variable.dart
β”‚   β”œβ”€β”€ listen_stdout.dart
β”‚   β”œβ”€β”€ advanced_inspect.dart
β”‚   └── server_example/
β”‚       β”œβ”€β”€ target_server.dart         ← Shelf server to inject into
β”‚       └── injector_client.dart       ← Client that injects into it
└── test/
    β”œβ”€β”€ models_test.dart
    β”œβ”€β”€ exceptions_test.dart
    β”œβ”€β”€ result_parser_test.dart
    └── websocket_helper_test.dart

πŸ”§ VM Service RPC Reference #

RPC Used by Risk
getVM listIsolates() Low
getIsolate All evaluate calls Low
evaluate evaluateInIsolate() Very High
evaluateInFrame evaluateInFrame() Very High
invoke ExpressionEvaluator.invokeMethod() High
getObject getObject() Medium
getInstances getInstances() High
streamListen stdout, stderr, events Low
streamCancel dispose() Low
pause pauseIsolate() High
resume resumeIsolate() High
getVersion Connection setup Low

πŸ§‘β€πŸ’» Legitimate Use Cases #

  • βœ… IDE plugin development β€” power live variable inspection panels.
  • βœ… Custom debuggers β€” build domain-specific debuggers for Dart servers.
  • βœ… Staging environment inspection β€” debug issues without deploying new code.
  • βœ… Developer tooling β€” CLI tools for Dart server introspection.
  • βœ… Authorised penetration testing β€” assess VM Service exposure on client systems.
  • βœ… Hot-patch tooling β€” apply emergency in-memory patches in JIT environments.
  • βœ… Forensics β€” post-incident memory inspection on isolated, authorised systems.

❌ Out of Scope #

  • ❌ Unauthorized access to any system.
  • ❌ Production systems without explicit operator consent.
  • ❌ AOT-compiled Flutter release or standalone binaries.
  • ❌ Exfiltrating user data.

πŸ“œ License #

MIT Β© 2026 β€” See LICENSE.

0
likes
130
points
27
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Ultra-pro Dart package for injecting and evaluating expressions in live Dart VM isolates via VM Service (WebSocket/JSON-RPC), designed for advanced debugging, live inspection, hot-patching, and security research.

Repository (GitHub)
View/report issues

Topics

#dart #vm #debugging #introspection #injection

License

MIT (license)

Dependencies

async, meta, retry, vm_service, web_socket_channel

More

Packages that depend on dart_vm_injector