lglaf/protocol.md
Peter Wu 8f35f2f5b5 More protocol details, add property parser
Example output for parse-props.py:

    download cable             = 'USER'
    battery level              = 100
    download type              = ' '
    download speed             = 0
    usb version                = ' '
    hardware revision          = 'rev_10'
    download sw version        = ' '
    device sw version          = 'D85520t'
    secure device              = 'S'
    laf sw version             = '1.1'
    device factory version     = 'LGD855AT-00-V20t-EUR-XX-AUG-18-2015-16G+0'
    device factory out version = 'LGD855AT-00-V20t-GLOBAL-COM-AUG-18-2015-16G+0'
    pid                        = 'YE01S151002002500'
    imei                       = (redacted)
    model name                 = 'LG-D855'
    device build type          = 'U'
    chipset platform           = 'msm8974'
    target_operator            = 'GLOBAL'
    target_country             = 'COM'
    ap_factory_reset_status    = 3
    cp_factory_reset_status    = 0
    isDownloadNotFinish        = 0
    qem                        = 0
    cupss swfv                 = 'A1439892730-M1439892730-C1439940554-U1439940554-0'
    is one binary dual plan    = 0
    memory size                = 30777344
    memory_id                  = 'SDW16G\n'
    bootloader_ver             = 'MiniOS 3.0'
2015-12-25 15:16:42 +01:00

4.5 KiB

LG LAF Protocol

This document is a reverse-engineered protocol description for "LG LAG", the download mode offered by various LG models. It is based on analysis on the Send_Command.exe utility and LGD855_20140526_LGFLASHv160.dll file and a USB trace using Wireshark and usbmon on Linux. Some commands were found in the /sbin/lafd binary.

Overview

LAF is a simple request/response protocol operating over USB. The USB details are described at the end of the document, the messages are described below.

Each message consists of a header, followed by an optional body. The header contains 32-bit DWORDs, integers are encoded in little-endian form:

| Offset (hex) | Offset (dec) | Type | Description | ----:| --:| --- | 0x00 | 0 | char[4] | Command | 0x04 | 4 | var | Argument 1 | 0x08 | 8 | var | Argument 2 | 0x0c | 12 | var | Argument 3 | 0x10 | 16 | var | Argument 4 (not encountered) | 0x14 | 20 | int | Body length | 0x18 | 24 | int | CRC-16 | 0x1c | 28 | char[4] | Bit-wise invertion of command at offset 0

Arguments can be integers or character sequences depending on the command.

The CRC field is the CRC-16-CCITT calculation (LSB-first) over the header and the body with zeroes in place of CRC.

Each request is followed by a response with a matching command field. If an error occurs, the response contains command is FAIL with argument 1 being the error code and the original request header as body.

Commands

OPEN - Open File

Opens a file path.

Arguments:

  • arg1 (response): DWORD file descriptor. Request body: NUL-terminated file path that should be opened for reading or an empty string to open /dev/block/mmcblk0 in read/write mode. (at most 276 (0x114) bytes?)

Non-existing files result in FAIL with error code 0x80000001.

CLSE - Close File

Closes a file descriptor which was returned by the OPEN command.

Arguments:

  • arg1: DWORD file descriptor (same in request and response).

Note: this allows you to close any file descriptor that are in use by the lafd process, not just the one returned by OPEN. You can discover the current file descriptors via ls -l /proc/$pid/fd where $pid is found by ps | grep lafd.

HELO - Hello

Arguments:

  • arg1: DWORD Protocol Version (\1\0\0\1) (resp must match req.)
  • arg2 (response): Minimum Protocol Version (\0\0\x80\0 was observed)

CTRL - Control

Arguments:

  • arg1: "RSET" or "ONRS"

Note: CTRL(RSET) with no body is sent by the Send_Command.exe utility for the LEAVE command.

WRTE - Write File

Writes to a file descriptor.

Arguments:

  • arg1: file descriptor (must be open for writing!)
  • arg2: offset in blocks (multiple of 512 bytes). Request body: the data to be written. Can be of any size (including 1 or 513).

Note: writing to a file descriptor which was opened for reading results in FAIL with code 0x82000002. This command is likely used for writing to partitions.

READ - Read File

Reads from a file descriptor.

Arguments:

  • arg1: file descriptor
  • arg2: offset in blocks (multiple of 512 bytes).
  • arg3: requested length in bytes. Response body: data in file at given offset and requested length.

Note: be sure not to read past the end of the file (512 * offset + length), this will hang the communication, requiring a reset (pull out battery)!

ERSE - Erase

Arguments:

  • arg1: ?
  • arg2: ?
  • arg3: ?

EXEC - Execute Command

Arguments: none Request body: NUL-terminated command. Response body: standard output of the command.

The command is probably split on space and then passes to execve. In order to see standard error, use variables and globbing, use a command such as:

sh -c "$@" -- eval 2>&1 echo $PATH

INFO

Arguments:

  • arg1: action (GPRO - Get Properties, SPRO - Set Properties) Request body: must begin with two bytes (08 0b). Response body: 2824 (0xb08) bytes of binary info.

See scripts/parse-props.py for the structure of the property body.

UNLK - Unlock

Arguments: none

RSVD - Reserved

Arguments: none

IOCT

Unknown.

MISC

Unknown.

KILO

Unknown.

DIFF

Unknown.

USB layer

The LG Windows driver (via LGMobileDriver_WHQL_Ver_4.0.3.exe) exposes two serial ports, LGANDNETMDM0 and LGANDNETDIAG1. The LGANDNETDIAG1 port is used for LAF.

The LG G3 (D855) has Vendor ID 0x1004 and Product ID 0x633e.

There is only one configuration descriptor and LAF uses bulk transfers over endpoints 5 (for input from the device) and endpoint 3 (for output to the device).

For other descriptors, see info/lsusb.txt.