├── Makefile ├── README.md ├── ldscript ├── lib.h ├── main.c ├── mb7220 ├── boot.log ├── mb7220-5.7.1.9.fidb └── mb7220-serial-enabled.bin ├── measure.c └── upload.py /Makefile: -------------------------------------------------------------------------------- 1 | TCPREFIX=mips-linux- 2 | CC=$(TCPREFIX)gcc 3 | OBJCOPY=$(TCPREFIX)objcopy 4 | LDSCRIPT=./ldscript 5 | CFLAGS=-march=mips32 -mabi=eabi -mno-abicalls -fno-builtin -nostdlib -nodefaultlibs -nostartfiles -T $(LDSCRIPT) 6 | 7 | default: bin 8 | 9 | elf: measure.c 10 | $(CC) measure.c -o $@ $(CFLAGS) 11 | 12 | bin: elf 13 | $(OBJCOPY) -O binary -j .text -j .data -j .rodata $< $@ 14 | 15 | 16 | .PHONY: clean 17 | 18 | clean: 19 | rm -f elf bin 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BCM3383 (MB7220) Reverse Engineering 2 | 3 | Miscellaneous RE experiments on MB7220 (version 7220-5.7.1.9) 4 | -------------------------------------------------------------------------------- /ldscript: -------------------------------------------------------------------------------- 1 | memset = 0x80522d7c; 2 | memcpy = 0x80004f30; 3 | malloc = 0x80596998; 4 | printf = 0x8052b178; 5 | sleep_ms = 0x80411254; 6 | socket = 0x80332fd0; 7 | bind = 0x800ae7bc; 8 | listen = 0x80412ed4; 9 | accept = 0x80413118; 10 | send = 0x80413240; 11 | recv = 0x804134bc; 12 | new_addr = 0x8013df20; 13 | addr_cpy = 0x800186b4; 14 | write_tuner_reg = 0x8002dd94; 15 | read_tuner_reg = 0x8002dfb4; 16 | write_lna_reg = 0x80405dd4; 17 | read_lna_reg = 0x80406044; 18 | get_channel_dpm = 0x80075734; 19 | sample_bandpower = 0x800816f8; 20 | set_channel_freq = 0x80073a98; 21 | timer_start = 0x8005d79c; 22 | timer_stop = 0x8005d81c; 23 | 24 | SECTIONS 25 | { 26 | . = 0x80810000; 27 | .text : { *(.text) } 28 | .data : { *(.data) } 29 | .rodata : { *(.rodata) } 30 | } 31 | -------------------------------------------------------------------------------- /lib.h: -------------------------------------------------------------------------------- 1 | /* constants */ 2 | #define NULL (void*) 0 3 | 4 | #define AF_INET 0x02 5 | #define AF_INET6 0x1C 6 | 7 | 8 | /* structs */ 9 | 10 | typedef struct sock_addr_s { 11 | unsigned int _pad1; 12 | unsigned int _pad2; 13 | unsigned int addr; 14 | unsigned int _pad4; 15 | unsigned int _pad5; 16 | unsigned int _pad6; 17 | unsigned int _pad7; 18 | unsigned int _pad8; 19 | } sock_addr_t; 20 | 21 | 22 | 23 | /* stdlib functions */ 24 | void* memset(void* buf, int c, unsigned int n); 25 | void* memcpy(void* dst, const void* src, int n); 26 | void* malloc(unsigned int size); 27 | int printf(char* str, ...); 28 | void sleep_ms(unsigned int); 29 | 30 | 31 | /* network functions */ 32 | 33 | /* Create a new socket with IP protocol ip_proto on IP stack number ip_stack 34 | * _a and _b are unknown, use 1 and 6 respectively for IPv4 TCP. 35 | * Returns NULL on failure and pointer to socket handle on success. 36 | */ 37 | void* socket(int ip_proto, int _a, int _b, int ip_stack); 38 | 39 | /* Bind the valid socket handle to the given address and port. 40 | * Returns 0 on success. 41 | */ 42 | int bind(void* handle, void* addr, int port); 43 | 44 | /* Listen for a TCP connection on the bound socket. 45 | * Arg _a is unknown, probably backlog like posix listen(). Use 1. 46 | * Returns 0 on success. 47 | */ 48 | int listen(void* handle, int _a); 49 | 50 | /* Accept a connection on a listening socket. 51 | * Args _a and _b are unknown, use 0 and 0 respectively. 52 | * Returns a pointer to a new socket handle on success or NULL on failure. 53 | */ 54 | void* accept(void* handle, int _a, int _b); 55 | 56 | /* Send len bytes of data at the buffer buf on the connection handle. 57 | * Arg _a is unknown, use 0. 58 | * Returns the number of bytes send on success. 59 | */ 60 | int send(void* handle, char* buf, int len, int _a); 61 | 62 | /* Read up to len bytes of data from the connection handle into buffer buf. 63 | * Arg _a is unknown, use 0. 64 | * Returns the number of bytes read on success. 65 | */ 66 | int recv(void* handle, char* buf, int len, int _a); 67 | 68 | int new_addr(int a); 69 | int addr_cpy(int dst, int src); 70 | 71 | 72 | 73 | /* transceiver functions */ 74 | 75 | /* Write the given value to the given LNA register. 76 | */ 77 | void write_lna_reg(unsigned int reg, unsigned int val); 78 | 79 | /* Read the given LNA register. 80 | * Returns the value read. 81 | */ 82 | unsigned int read_lna_reg(unsigned int reg); 83 | 84 | /* Write a value to the given tuner register. 85 | * buf is a pointer to a 64 byte buffer 86 | * The value to write must be set in buf at offset reg. 87 | * reg is the register number/offset in buf to start from 88 | * size is the number of bytes to write 89 | * _a is unknown? 90 | */ 91 | int write_tuner_reg(void* buf, unsigned int reg, unsigned int size, unsigned int _a); 92 | 93 | /* Read size bytes into buf from the tuner register reg. 94 | */ 95 | void read_tuner_reg(int reg, void* buf, unsigned int size); 96 | 97 | /* Return/print the downstream power measurement (DPM) for the given channel. 98 | */ 99 | int get_channel_dpm(int channel); 100 | 101 | /* Sample the bandpower between start_freq and stop_freq using points points 102 | * per FFT and writing the result to the buffer out. 103 | * samples is the number of 8 byte samples to be written to buffer sample_buf 104 | */ 105 | int sample_bandpower(unsigned int start_freq, unsigned int stop_freq, int points, int* out, int samples, void* sample_buf); 106 | 107 | /* Set the given channel to the given freqency in Hz. 108 | * Arg _a unknown, use 0 or 1. 109 | */ 110 | int set_channel_freq(unsigned int freq, int channel, int _a); 111 | 112 | 113 | 114 | /* misc functions */ 115 | 116 | /* Not actually its primary purpose but it prints the elapsed time in 117 | * microseconds. 118 | */ 119 | void timer_start(int* t); 120 | void timer_stop(int* t); 121 | 122 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int __start(void) 4 | { 5 | void* sock; 6 | void* conn; 7 | int addr[5] = {0}; 8 | int n; 9 | char* buf = malloc(512); 10 | memset(buf, 0, 512); 11 | 12 | if (NULL == (sock = socket(2, 1, 6, 2))) 13 | return -1; 14 | //printf("sock %x\n", sock); 15 | 16 | addr[2] = 0xc0a86401; // set ip address 17 | //printf("addr: 0x%x\n", addr); 18 | if (0 != bind(sock, addr, 1338)) 19 | return -2; 20 | 21 | if (0 != listen(sock, 1)) 22 | return -3; 23 | 24 | if (NULL == (conn = accept(sock, 0, 0))) 25 | return -4; 26 | 27 | n = recv(conn, buf, 511, 0); 28 | if (n <= 0) 29 | return -5; 30 | 31 | printf("%s\n", buf); 32 | 33 | char resp[] = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: 5\r\n\r\nHello"; 34 | n = send(conn, resp, sizeof(resp), 0); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /mb7220/boot.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdw/bcm3383-reverse-engineering/e661112a5959d38379a4bf442c1f00bc4f3eba73/mb7220/boot.log -------------------------------------------------------------------------------- /mb7220/mb7220-5.7.1.9.fidb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdw/bcm3383-reverse-engineering/e661112a5959d38379a4bf442c1f00bc4f3eba73/mb7220/mb7220-5.7.1.9.fidb -------------------------------------------------------------------------------- /mb7220/mb7220-serial-enabled.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdw/bcm3383-reverse-engineering/e661112a5959d38379a4bf442c1f00bc4f3eba73/mb7220/mb7220-serial-enabled.bin -------------------------------------------------------------------------------- /measure.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #define SAMPLES 10000 4 | #define FREQ 96000000 5 | #define BW 7500000 /* Assuming because it uses 7.5Mhz bins? */ 6 | #define HALFBW 3750000 7 | 8 | int __start(void) 9 | { 10 | int bandpower[4]; 11 | int* buf = (int*) malloc(SAMPLES*8); 12 | if(!buf) 13 | return -1; 14 | 15 | /* RAM is mapped to addresses 0x80000000 and 0xA0000000 16 | * The latter is not cached and we get mostly zeros if we use 17 | * the 0x80000000 address even though the function looks to be 18 | * converting it interally too. So pass a 0xA0000000 address 19 | */ 20 | buf = (int*)((int)buf | 0x20000000); 21 | memset(buf, 0, SAMPLES*8); 22 | 23 | printf("buffer: 0x%x\n", buf); 24 | 25 | /* The last argument is the buffer to use for samples used to 26 | * calculate the FFT. 2nd to last arg is the number of 8 byte 27 | * samples. The samples are passed to a function that pulls 28 | * out the first and second 32-bit words separately. These 29 | * values are positive and negative integers centered around 0. 30 | * Seems logical that it is I/Q data? 31 | */ 32 | sample_bandpower(FREQ-HALFBW, FREQ+HALFBW, 128, (void*)&bandpower, SAMPLES, buf); 33 | 34 | void* sock; 35 | void* conn; 36 | sock_addr_t sa = {0}; 37 | int n = 1; 38 | 39 | if (NULL == (sock = socket(AF_INET, 1, 6, 2))) 40 | return -1; 41 | 42 | sa.addr = 0xc0a86401; // set ip address to 192.168.100.1 43 | if (0 != bind(sock, &sa, 1337)) 44 | return -2; 45 | 46 | if (0 != listen(sock, 1)) 47 | return -3; 48 | 49 | if (NULL == (conn = accept(sock, 0, 0))) 50 | return -4; 51 | 52 | int remaining = SAMPLES*8; 53 | int chunk_size = 1024; 54 | int chunk_sent = 0; 55 | char* start = (char*)buf; 56 | while (remaining > 0) { 57 | chunk_sent = 0; 58 | if (remaining < chunk_size) 59 | chunk_size = remaining; 60 | 61 | while (chunk_sent < chunk_size && n > 0) { 62 | n = send(conn, start, chunk_size - chunk_sent, 0); 63 | chunk_sent += n; 64 | start += n; 65 | } 66 | if (n <= 0) { 67 | printf("error sending: %d\n", n); 68 | return n; 69 | } 70 | remaining -= chunk_size; 71 | } 72 | printf("sent %d bytes total\n", SAMPLES*8 - remaining); 73 | return (int)buf; 74 | } 75 | -------------------------------------------------------------------------------- /upload.py: -------------------------------------------------------------------------------- 1 | import telnetlib 2 | 3 | HOST = '192.168.100.1' 4 | USER = b'technician' 5 | PASS = b'abcd' 6 | 7 | DEST = 0x80810000 8 | FILE = './bin' 9 | 10 | def main(): 11 | t = telnetlib.Telnet(HOST) 12 | get(t, b'Login:') 13 | t.write(USER + b'\r\n') 14 | get(t, b'Password:') 15 | t.write(PASS + b'\r\n') 16 | if b'Console' in get(t, b'>'): 17 | authenticate(t) 18 | 19 | t.write(b'cd ..\r\n') 20 | stop_scan(t) 21 | 22 | upload_file(t, FILE, DEST) 23 | 24 | # execute function at start address 25 | #t.write(b'call func -r -a ' + bytes(hex(DEST), 'utf-8') + b'\r\n') 26 | #get(t, b'>') 27 | 28 | 29 | # get/print output up to stop 30 | def get(t, stop): 31 | output = t.read_until(stop) 32 | print(output.decode('latin-1')) 33 | return output 34 | 35 | # get full permissions 36 | def authenticate(t): 37 | t.write(b'su\r\n') 38 | get(t, b':') 39 | t.write(b'brcm\r\n') 40 | get(t, b'>') 41 | 42 | # delete task that floods output 43 | def stop_scan(t): 44 | t.write(b'cd cm_hal\r\n') 45 | get(t, b'>') 46 | t.write(b'scan_stop\r\n') 47 | get(t, b'>') 48 | t.write(b'cd ..\r\n') 49 | get(t, b'>') 50 | 51 | # write file to RAM 52 | def upload_file(t, filename, address): 53 | with open(filename, 'rb') as f: 54 | payload = f.read() 55 | 56 | dest = address 57 | for off in range(0, len(payload), 4): 58 | addr = hex(dest + off) 59 | val = payload[off:off+4].hex() 60 | cmd = bytes(f'write_memory -s 4 {addr} 0x{val}\r\n', 'utf-8') 61 | t.write(cmd) 62 | print(t.read_until(b'>')) 63 | 64 | 65 | if __name__ == '__main__': 66 | main() 67 | --------------------------------------------------------------------------------