Skip to content

Commit 684fde1

Browse files
j4ckp0t85manio
authored andcommitted
mitm/video_in_motion: completion
The previous option worked only in some scenarios / for some HUs. This commit adds additional conditions. Code is AI-generated using the Opus 4.6 model. Closes: #66
1 parent f9b30ce commit 684fde1

1 file changed

Lines changed: 116 additions & 5 deletions

File tree

src/mitm.rs

Lines changed: 116 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,15 +331,86 @@ pub async fn pkt_modify_hook(
331331
SENSOR_MESSAGE_BATCH => {
332332
if let Ok(mut msg) = SensorBatch::parse_from_bytes(data) {
333333
if cfg.video_in_motion {
334+
// === DRIVING STATUS: must be UNRESTRICTED (0) ===
335+
// This is the primary flag AA checks. Value is a bitmask:
336+
// 0 = unrestricted, 1 = no video, 2 = no keyboard, etc.
337+
if !msg.driving_status_data.is_empty() {
338+
msg.driving_status_data[0].set_status(0);
339+
}
340+
341+
// === GEAR: force PARK ===
334342
if !msg.gear_data.is_empty() {
335-
// forcing gear
336343
msg.gear_data[0].set_gear(GEAR_PARK);
337344
}
338-
if !msg.driving_status_data.is_empty() {
339-
// forcing status to 0 value
340-
msg.driving_status_data[0].set_status(0);
345+
346+
// === PARKING BRAKE: engaged ===
347+
// Modern AA cross-checks parking brake with gear/speed.
348+
if !msg.parking_brake_data.is_empty() {
349+
msg.parking_brake_data[0].set_parking_brake(true);
350+
}
351+
352+
// === VEHICLE SPEED: zero ===
353+
// SpeedData.speed_e3 is speed in m/s * 1000. Zero = stopped.
354+
if !msg.speed_data.is_empty() {
355+
msg.speed_data[0].set_speed_e3(0);
356+
// Also ensure cruise control is disengaged
357+
msg.speed_data[0].set_cruise_engaged(false);
358+
}
359+
360+
// === GPS/LOCATION: zero speed, keep position ===
361+
// LocationData.speed_e3 is GPS-derived speed.
362+
// Modern AA compares this against SpeedData for consistency.
363+
if !msg.location_data.is_empty() {
364+
msg.location_data[0].set_speed_e3(0);
365+
// Zero bearing = not turning
366+
msg.location_data[0].set_bearing_e6(0);
341367
}
342-
// regenerating payload data
368+
369+
// === ACCELEROMETER: gravity only (stationary) ===
370+
// A parked car only feels gravity on Z axis (~9810 mm/s²).
371+
// Any X/Y acceleration implies movement/turning.
372+
if !msg.accelerometer_data.is_empty() {
373+
msg.accelerometer_data[0].set_acceleration_x_e3(0);
374+
msg.accelerometer_data[0].set_acceleration_y_e3(0);
375+
msg.accelerometer_data[0].set_acceleration_z_e3(9810);
376+
}
377+
378+
// === GYROSCOPE: zero rotation ===
379+
// Any rotation speed implies the vehicle is turning.
380+
if !msg.gyroscope_data.is_empty() {
381+
msg.gyroscope_data[0].set_rotation_speed_x_e3(0);
382+
msg.gyroscope_data[0].set_rotation_speed_y_e3(0);
383+
msg.gyroscope_data[0].set_rotation_speed_z_e3(0);
384+
}
385+
386+
// === DEAD RECKONING: zero wheel speed + steering ===
387+
// Wheel speed ticks and steering angle are used by Toyota
388+
// and other modern HUs as independent motion verification.
389+
if !msg.dead_reckoning_data.is_empty() {
390+
msg.dead_reckoning_data[0].set_steering_angle_e1(0);
391+
msg.dead_reckoning_data[0].wheel_speed_e3.clear();
392+
// Push four zero values for the four wheels
393+
msg.dead_reckoning_data[0].wheel_speed_e3.push(0);
394+
msg.dead_reckoning_data[0].wheel_speed_e3.push(0);
395+
msg.dead_reckoning_data[0].wheel_speed_e3.push(0);
396+
msg.dead_reckoning_data[0].wheel_speed_e3.push(0);
397+
}
398+
399+
// === COMPASS: freeze bearing ===
400+
// Changing compass bearing implies turning/moving.
401+
if !msg.compass_data.is_empty() {
402+
msg.compass_data[0].set_pitch_e6(0);
403+
msg.compass_data[0].set_roll_e6(0);
404+
}
405+
406+
// === RPM: idle engine ===
407+
// High RPM with zero speed is suspicious on some HUs.
408+
// ~700 RPM idle is realistic for a parked car.
409+
if !msg.rpm_data.is_empty() {
410+
msg.rpm_data[0].set_rpm_e3(700_000);
411+
}
412+
413+
// Regenerate payload with ALL spoofed fields
343414
pkt.payload = msg.write_to_bytes()?;
344415
pkt.payload.insert(0, (message_id >> 8) as u8);
345416
pkt.payload.insert(1, (message_id & 0xff) as u8);
@@ -587,6 +658,46 @@ pub async fn pkt_modify_hook(
587658
}
588659
}
589660

661+
// video_in_motion: strip motion-related sensors from SDR capabilities
662+
// and downgrade location_characterization so AA cannot cross-validate
663+
if cfg.video_in_motion {
664+
if let Some(svc) = msg
665+
.services
666+
.iter_mut()
667+
.find(|svc| !svc.sensor_source_service.sensors.is_empty())
668+
{
669+
// Remove sensor types that reveal vehicle motion.
670+
// Keep DRIVING_STATUS, GEAR, PARKING_BRAKE, LOCATION (we spoof those)
671+
// but remove the ones that are harder to spoof consistently per-HU.
672+
let sensors_to_strip = [
673+
SENSOR_ACCELEROMETER_DATA,
674+
SENSOR_GYROSCOPE_DATA,
675+
SENSOR_DEAD_RECKONING_DATA,
676+
SENSOR_SPEED,
677+
];
678+
svc.sensor_source_service
679+
.as_mut()
680+
.unwrap()
681+
.sensors
682+
.retain(|s| !sensors_to_strip.contains(&s.sensor_type()));
683+
684+
// Reset location_characterization to RAW_GPS_ONLY (256).
685+
// This tells AA the HU does NOT fuse wheel speed, gyroscope,
686+
// accelerometer, or dead reckoning into position fixes, so AA
687+
// will not expect those signals for cross-validation.
688+
svc.sensor_source_service
689+
.as_mut()
690+
.unwrap()
691+
.set_location_characterization(256); // RAW_GPS_ONLY
692+
693+
info!(
694+
"{} <yellow>{:?}</> video_in_motion: stripped motion sensors from SDR, location_characterization=RAW_GPS_ONLY",
695+
get_name(proxy_type),
696+
control.unwrap(),
697+
);
698+
}
699+
}
700+
590701
// enabling developer mode
591702
if cfg.developer_mode {
592703
msg.set_make(DHU_MAKE.into());

0 commit comments

Comments
 (0)