mirror of
https://github.com/Lekensteyn/lglaf.git
synced 2024-11-14 19:35:41 -05:00
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'
This commit is contained in:
parent
eed04da13f
commit
8f35f2f5b5
2 changed files with 154 additions and 18 deletions
62
protocol.md
62
protocol.md
|
@ -34,12 +34,26 @@ error code and the original request header as body.
|
|||
|
||||
## Commands
|
||||
|
||||
### OPEN - Open
|
||||
Arguments: none
|
||||
Request body: at most 276 (0x114) bytes (?)
|
||||
### OPEN - Open File
|
||||
Opens a file path.
|
||||
|
||||
### CLSE - Close
|
||||
Arguments: none
|
||||
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:
|
||||
|
@ -53,19 +67,28 @@ Arguments:
|
|||
Note: `CTRL(RSET)` with no body is sent by the `Send_Command.exe` utility for
|
||||
the `LEAVE` command.
|
||||
|
||||
### WRTE - Write
|
||||
Arguments:
|
||||
- arg1: ?
|
||||
- arg2: ?
|
||||
### WRTE - Write File
|
||||
Writes to a file descriptor.
|
||||
|
||||
### READ - Read
|
||||
Arguments:
|
||||
- arg1: ?
|
||||
- arg2: ?
|
||||
- arg3: ?
|
||||
Response body: present.
|
||||
- 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).
|
||||
|
||||
(Arguments probably encode read offset, length)
|
||||
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:
|
||||
|
@ -83,11 +106,14 @@ see standard error, use variables and globbing, use a command such as:
|
|||
|
||||
sh -c "$@" -- eval 2>&1 echo $PATH
|
||||
|
||||
### INFO - Get Info
|
||||
### INFO
|
||||
Arguments:
|
||||
- arg1: action (`GPRO` - Get Properties, `SPRO` - Set Properties)
|
||||
Request body: fixed size 2824 (0xb08)
|
||||
Response body: present for `GPRO`
|
||||
Request body: must begin with two bytes (`08 0b`).
|
||||
Response body: 2824 (0xb08) bytes of binary info.
|
||||
|
||||
See [scripts/parse-props.py](scripts/parse-props.py) for the structure of the
|
||||
property body.
|
||||
|
||||
### UNLK - Unlock
|
||||
Arguments: none
|
||||
|
|
110
scripts/parse-props.py
Executable file
110
scripts/parse-props.py
Executable file
|
@ -0,0 +1,110 @@
|
|||
#!/usr/bin/env python
|
||||
# Parse property file.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# lglaf.py -c '!INFO GPRO \x08\x0b' > props.bin
|
||||
# scripts/parse-props.py props.bin
|
||||
|
||||
import argparse, sys, struct
|
||||
|
||||
def stringify(resp):
|
||||
if not isinstance(resp, str):
|
||||
try: resp = resp.decode('ascii')
|
||||
except: pass
|
||||
return resp
|
||||
|
||||
def get_str(data, shadow, offset):
|
||||
resp = b''
|
||||
#while True:
|
||||
while offset < len(data):
|
||||
b = data[offset:offset+1]
|
||||
shadow[offset] = 's'
|
||||
if b == b'\0':
|
||||
break
|
||||
resp += b
|
||||
offset += 1
|
||||
return stringify(resp)
|
||||
|
||||
def get_chr(data, shadow, offset):
|
||||
b = data[offset:offset+1]
|
||||
shadow[offset] = 'c'
|
||||
return stringify(b)
|
||||
|
||||
def get_int(data, shadow, offset):
|
||||
d = struct.unpack_from('<I', data, offset)[0]
|
||||
for off in range(offset, offset+4):
|
||||
shadow[off] = 'd'
|
||||
return d
|
||||
|
||||
# Description of the contents
|
||||
keys = [
|
||||
(0x3f9, get_str, "download cable"),
|
||||
(0x42b, get_int, "battery level"),
|
||||
(0x010, get_chr, "download type"),
|
||||
(0x021, get_int, "download speed"),
|
||||
(0x403, get_str, "usb version"),
|
||||
(0x417, get_str, "hardware revision"),
|
||||
(0x029, get_str, "download sw version"),
|
||||
(0x14f, get_str, "device sw version"),
|
||||
(0x42f, get_chr, "secure device"),
|
||||
(0x4e8, get_str, "laf sw version"),
|
||||
(0x24f, get_str, "device factory version"),
|
||||
(0x528, get_str, "device factory out version"),
|
||||
(0x3db, get_str, "pid"),
|
||||
(0x3c7, get_str, "imei"),
|
||||
(0x131, get_str, "model name"),
|
||||
(0x430, get_str, "device build type"),
|
||||
(0x43a, get_str, "chipset platform"),
|
||||
(0x44e, get_str, "target_operator"),
|
||||
(0x462, get_str, "target_country"),
|
||||
(0x4fc, get_int, "ap_factory_reset_status"),
|
||||
(0x500, get_int, "cp_factory_reset_status"),
|
||||
(0x504, get_int, "isDownloadNotFinish"),
|
||||
(0x508, get_int, "qem"),
|
||||
(0x628, get_str, "cupss swfv"),
|
||||
(0x728, get_int, "is one binary dual plan"),
|
||||
(0x72c, get_int, "memory size"),
|
||||
(0x730, get_str, "memory_id"),
|
||||
(0x39f, get_str, "bootloader_ver"),
|
||||
]
|
||||
|
||||
def debug_other(data, shadow):
|
||||
for offset, shadow_type in enumerate(shadow):
|
||||
data_byte = data[offset:offset+1]
|
||||
if not shadow_type and data_byte != b'\0':
|
||||
print("Unprocessed byte at 0x%03x: %r" % (offset, data_byte))
|
||||
shadow[offset] = '*'
|
||||
|
||||
def print_shadow(shadow):
|
||||
for offset in range(0, len(shadow), 32):
|
||||
line1 = ''.join(c or '.' for c in shadow[offset:offset+16])
|
||||
line2 = ''.join(c or '.' for c in shadow[offset+16:offset+32])
|
||||
print("%03x: %-16s %-16s" % (offset, line1, line2))
|
||||
|
||||
def parse_data(data):
|
||||
assert data[0:2] == b'\x08\x0b'
|
||||
assert len(data) == 0xb08
|
||||
|
||||
# Set to non-None when processed
|
||||
shadow = [None] * len(data)
|
||||
for offset, getter, description in keys:
|
||||
resp = getter(data, shadow, offset)
|
||||
print("%-26s = %r" % (description, resp))
|
||||
|
||||
return data, shadow
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--debug", action='store_true')
|
||||
parser.add_argument("file", help="2824 byte properties dump file")
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
data = open(args.file, "rb").read()
|
||||
data, shadow = parse_data(data)
|
||||
if args.debug:
|
||||
debug_other(data, shadow)
|
||||
print_shadow(shadow)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue