Reverse Engineering the USB protocol of the EOL'd ACTIONPRO X7 camera to configure the WiFi access point settings and time synchronization via PC.
Go to file
jpk bdf0e8bd50 Updated research documentation 2021-08-10 15:55:58 +02:00
.gitignore Initial commit 2021-08-10 15:21:40 +02:00
Makefile Initial commit 2021-08-10 15:21:40 +02:00
README.md Updated research documentation 2021-08-10 15:55:58 +02:00
config.def.h Initial commit 2021-08-10 15:21:40 +02:00
config.mk Initial commit 2021-08-10 15:21:40 +02:00
main.c Initial commit 2021-08-10 15:21:40 +02:00

README.md

ACTIONPRO X7

Research

Hardware

  • SOC: Ambarella, A7L-B1-RH, A1402, N6T96-AN8, 1N1
  • WiFi: Atheros AR6103G-BM2D, P0BV68.2BE5, P0BV68.2B, 1441
  • Flash: ATO, 1440N, MST5F08G16G, NH-2106, 5FGHG46V17W

Research: File/Drive Access by Action Manager 1.3

Opening Drive/Device:

CreateFile():
Desired Access:	Generic Read/Write
Disposition:	Open
Options:	Synchronous IO Non-Alert, Non-Directory File
Attributes:	n/a
ShareMode:	Read, Write
AllocationSize:	n/a
OpenResult:	Opened

Sending Command: Windows Application sends IOCTL_SCSI_PASS_THROUGH with DeviceIoControl().

Research: Access Point

After connecting to the access point (AP), it is possible to connect to the camera via telnet.

  • Host: 192.168.42.1
  • Username: root
  • Password: no password required
$ telnet 192.168.42.1
Trying 192.168.42.1...
Connected to 192.168.42.1.
Escape character is '^]'.

buildroot login: root
# uname -a
Linux buildroot 2.6.38.8 #1 PREEMPT Mon Dec 15 21:04:04 KST 2014 armv6l GNU/Linux
# ps
PID   USER     TIME   COMMAND
    1 root       0:02 init
    2 root       0:00 [kthreadd]
    3 root       0:00 [ksoftirqd/0]
    4 root       0:00 [kworker/0:0]
    5 root       0:00 [kworker/u:0]
    6 root       0:00 [khelper]
  351 root       0:00 [sync_supers]
  353 root       0:00 [bdi-default]
  355 root       0:00 [kblockd]
  356 root       0:00 [ipc_bh 0]
  357 root       0:00 [ipc_bh 1]
  448 root       0:00 [kworker/u:2]
  452 root       0:00 [rpciod]
  453 root       0:01 [kworker/0:1]
  462 root       0:00 [kswapd0]
  463 root       0:00 [fsnotify_mark]
  464 root       0:00 [aio]
  465 root       0:00 [nfsiod]
  468 root       0:00 [crypto]
  512 root       0:00 [mtdblock0]
  519 root       0:00 [mtdblock1]
  524 root       0:00 [mtdblock2]
  529 root       0:00 [mtdblock3]
  534 root       0:00 [mtdblock4]
  539 root       0:00 [mtdblock5]
  544 root       0:00 [mtdblock6]
  549 root       0:00 [mtdblock7]
  554 root       0:00 [mtdblock8]
  559 root       0:00 [mtdblock9]
  564 root       0:00 [mtdblock10]
  569 root       0:00 [mtdblock11]
  574 root       0:00 [mtdblock12]
  579 root       0:00 [mtdblock13]
  584 root       0:00 [mtdblock14]
  593 root       0:00 [ubi_bgt0d]
  597 root       0:00 [mmcqd/0]
  604 root       0:00 [lkvfs_bh 0]
  609 root       0:00 {rcS} /bin/sh /etc/init.d/rcS
  617 root       0:00 [ubifs_bgt0_1]
  636 dbus       0:00 dbus-daemon --system
  648 root       0:00 {S50service} /bin/sh /etc/init.d/S50service start
  656 root       0:06 vffs /tmp/fuse_a -l a -C 1 -o big_writes -s
  659 root       0:00 vffs /tmp/fuse_d -l d -C 1 -o big_writes -s
  662 root       0:00 vffs /tmp/fuse -l f -s
  674 root       0:00 ombra
  677 root       0:00 dvf2web --daemon
  678 root       0:00 /usr/bin/AmbaStreamSVC
  680 root       0:00 amba_mq_handler
  683 root       0:00 network_message_daemon
  691 root       0:00 /usr/bin/lu_lnxfio_stream
  703 root       0:15 [AR6K Async]
  711 root       0:18 [ksdioirqd/mmc1]
  780 nobody     0:00 dnsmasq --nodns -5 -K -R -n --dhcp-range=192.168.42.2,192.168.42.6,infinite
  814 root       0:05 hostapd -B /tmp/hostapd.conf
  829 root       0:00 telnetd
  842 root       0:00 cherokee-worker -a -C /etc/cherokee.conf -j -s -d
  848 root       0:00 cgiBridge
  854 root       0:00 remote_ctrl
 1493 root       0:00 -sh
 1498 root       0:00 ps
# mount
rootfs on / type rootfs (rw)
ubi0:linux on / type ubifs (ro,relatime)
devtmpfs on /dev type devtmpfs (rw,relatime,size=18668k,nr_inodes=4667,mode=755)
none on /dev type tmpfs (rw,relatime)
proc on /proc type proc (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,gid=5,mode=620)
tmpfs on /dev/shm type tmpfs (rw,relatime,mode=777)
tmpfs on /tmp type tmpfs (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
ubi0:pref on /pref type ubifs (rw,sync,relatime)
1 on /tmp/fuse_a type fuse.1 (rw,nosuid,nodev,relatime,user_id=0,group_id=0)
1 on /tmp/fuse_d type fuse.1 (rw,nosuid,nodev,relatime,user_id=0,group_id=0)
f on /tmp/fuse type fuse.f (rw,nosuid,nodev,relatime,user_id=0,group_id=0)
f on /var/www/shutter type fuse.f (rw,nosuid,nodev,relatime,user_id=0,group_id=0)
tmpfs on /var/www/live type tmpfs (rw,relatime)
1 on /var/www/pref type fuse.1 (rw,nosuid,nodev,relatime,user_id=0,group_id=0)
tmpfs on /var/www/mjpeg type tmpfs (rw,relatime)
# lsmod
ar6000 370159 0 - Live 0x7f000000
# ifconfig 
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:295 errors:0 dropped:0 overruns:0 frame:0
          TX packets:295 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:15356 (14.9 KiB)  TX bytes:15356 (14.9 KiB)

wlan0     Link encap:Ethernet  HWaddr 1C:4A:F7:00:6F:E4  
          inet addr:192.168.42.1  Bcast:192.168.42.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:38148 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3815 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:15639749 (14.9 MiB)  TX bytes:632131 (617.3 KiB)

# iwconfig 
lo        no wireless extensions.

wlan0     AR6000 802.11ng  ESSID:"X7APP"  Nickname:""
          NWID:off/any  Mode:Master  Frequency:2.462 GHz  
          Access Point: 1C:4A:F7:00:6F:E4   Bit Rate:52 Mb/s   Tx-Power=15 dBm   
          Sensitivity=0/3  
          RTS thr=0 B   Fragment thr=0 B   
          Encryption key:00   Security mode:open
          Power Management:on
          Link Quality:95  Signal level:0  Noise level:0
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

#

Research: Code Snippets using ioctl()

Trying to reproduce IOCTL_SCSI_PASS_THROUGH with Linux.

Code example #1:

#define DEF_TIMEOUT 5000 // 5 seconds
char cDiskName[] = "/dev/sg3";
int fd = open(cDiskName, O_RDWR);
if (fd < 0)
{
  printf("Open error: %s, errno=%d (%s)\n", cDiskName, errno, strerror(errno));
  return 1;
}

unsigned char turCmbBlk[] = {0x00, 0, 0, 0, 0, 0};
struct sg_io_hdr io_hdr;

unsigned char cIOBuffer[100];

// buffer initialization code omitted

memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(turCmbBlk);
io_hdr.mx_sb_len = sizeof(cIOBuffer);
io_hdr.dxfer_direction = SG_DXFER_NONE;
io_hdr.cmdp = turCmbBlk;
io_hdr.sbp = cIOBuffer;
io_hdr.timeout = DEF_TIMEOUT;
if (ioctl(fd, SG_IO, &io_hdr) < 0)
{
  printf("ioctl error: errno=%d (%s)\n", errno, strerror(errno));
}

// Code returned here without any errors but cIOBuffer remains unchanged.
#define BUFF_SIZE 100 // - Buffersize

#define DEF_TIMEOUT 5000 // 5 seconds
char cDiskName[] = "/dev/sg3";
int fd = open(cDiskName, O_RDWR);
if (fd < 0)
{
  printf("Open error: %s, errno=%d (%s)\n", cDiskName, errno, strerror(errno));
  return 1;
}

unsigned char turCmbBlk[] = {0x00, 0, 0, 0, 0, 0};
struct sg_io_hdr *p = (struct sg_io_hdr *) malloc(sizeof(struct sg_io_hdr)); // - dynamic memory allocation - free() required somewhere

unsigned char cIOBuffer[BUFF_SIZE];
unsigned char replyBuffer[BUFF_SIZE]; // - dxfer buffer

// buffer initialization code omitted

memset(p, 0, sizeof(struct sg_io_hdr));
p->interface_id = 'S';
p->cmd_len = sizeof(turCmbBlk);
p->mx_sb_len = BUFF_SIZE;
p->dxfer_direction = SG_DXFER_NONE;
p->cmdp = turCmbBlk;
p->sbp = cIOBuffer;
p->timeout = DEF_TIMEOUT;
p->flags = SG_FLAG_DIRECT_IO; // - Does this help?
p->dxferp = replyBuffer; // - Set dxferp buffer - (A)
p->dxfer_len = BUFF_SIZE; // - buffersize

if (ioctl(fd, SG_IO, p) < 0)
{
  printf("ioctl error: errno=%d (%s)\n", errno, strerror(errno));
}

// Code returned here without any errors but cIOBuffer remains unchanged.

Use for scsi/sg.h and ioctl.

Research: USB data transfer

Is it possible to just write to the usb interface instead?

USBPcap: Linux Host and Windows Guest

Identify the bus where the camera is connected to:

Bus 005 Device 017: ID 4255:1000 GoPro 9FF2 [Digital Photo Display]

Load usbmon to capture usb traffic with Wireshark:

modprobe usbmon

With Wireshark the usbmon<busid> (e.g. usbmon5) is selected as packet capture source.

After filtering the following filter rule will only display relevant packets:

(usb.device_address == 17 ) && (scsi.spc.opcode == 0xfd || scsi.spc.opcode == 0xfe || scsi.spc.opcode == 0xff)

Vendor specific commands:

  • 0xfd: set AP ssid
  • 0xfe: set AP passphrase
  • 0xff: syncronize time

Example packets:

0xfd:

0000   fd 00 58 37 41 50 50 00 00 00 00 00 00 00 00 00   ..X7APP.........

0xfe:

0000   fe 00 58 37 41 50 50 41 53 53 00 00 00 00 00 00   ..X7APPASS......

Synchrize time 0xff:

0000   ff 00 07 e5 08 0a 0b 24 00 00 00 00 00 00 00 00   .......$........

# 3 seconds later:
0000   ff 00 07 e5 08 0a 0b 24 03 00 00 00 00 00 00 00   .......$........

# 3 seconds later:
0000   ff 00 07 e5 08 0a 0b 24 06 00 00 00 00 00 00 00   .......$........