From 3443df8b41f959cceddd0cbc4d9ce32129d1a4d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 14 Mar 2023 15:17:27 +0100 Subject: code --- Makefile | 6 ++ analyze-gz.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ui.c | 167 +++++++++++++++++++++++++++++++++++ 3 files changed, 453 insertions(+) create mode 100644 Makefile create mode 100644 analyze-gz.c create mode 100644 ui.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1221184 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +CFLAGS = -Wall -std=c11 -ggdb +LDLIBS = -lncurses + +analyze-gc: analyze-gz.c + +ui: ui.c diff --git a/analyze-gz.c b/analyze-gz.c new file mode 100644 index 0000000..a0c6d40 --- /dev/null +++ b/analyze-gz.c @@ -0,0 +1,280 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include + +#define ID1 31 +#define ID2 139 + +enum compression_method { + DEFLATE = 8, +}; + +enum flag { + FTEXT = 1 << 0, + FHCRC = 1 << 1, + FEXTRA = 1 << 2, + FNAME = 1 << 3, + FCOMMENT = 1 << 4, +}; + +enum operating_system { + FAT = 0, + AMIGA, + VMS, + UNIX, + CMS, + ATARI_TOS, + HPFS, + MACINTOSH, + Z_SYSTEM, + CP_M, + TOPS20, + NTFS, + QDOS, + ACORN_RISCOS, +}; + +const char *os_str(enum operating_system os) { + switch (os) { + case FAT: return "FAT filesystem (MS-DOS, OS/2, NT/Win32)"; + case AMIGA: return "Amiga"; + case VMS: return "VMS (or OpenVMS)"; + case UNIX: return "Unix"; + case CMS: return "VM/CMS"; + case ATARI_TOS: return "Atari TOS"; + case HPFS: return "HPFS filesystem (OS/2, NT)"; + case MACINTOSH: return "Macintosh"; + case Z_SYSTEM: return "Z-System"; + case CP_M: return "CP/M"; + case TOPS20: return "TOPS-20"; + case NTFS: return "NTFS filesystem (NT)"; + case QDOS: return "QDOS"; + case ACORN_RISCOS: return "Acorn RISCOS"; + default: return "unknown"; + } +} + +struct member { + uint8_t id1, id2, cm, flg; + uint32_t mtime; + uint8_t xfl, os; +} __attribute__((packed)); + + +enum color { + BLACK = 0, + RED, + GREEN, + YELLOW, + BLUE, + PURPLE, + CYAN, + WHITE, +}; + + +struct segment { + enum color c; + size_t len; + uint8_t *data; +}; + +enum color next_color(void) { + static uint8_t cc = 0; + cc += 1; + cc %= 6; + return cc + 1; +} + +void color_put(enum color c) { + printf("\x1b[0;3%im", c); +} + +void color_reset(void) { + printf("\x1b[m"); +} + +#define LINELEN 0x8 +struct segment line_segments[LINELEN]; +size_t file_idx = 0; +size_t line_idx = 0; +size_t current_segment = 0; + +void cleanup_line(void) { + for (int i = 0; i < current_segment; i++) { + free(line_segments[i].data); + } +} + +void put_byte(uint8_t byte) { + static bool flip = 0; + printf("%02x", byte); + flip = !flip; + if (! flip) { + printf(" "); + } +} + +void flush_line() { + printf("%06lx: ", file_idx); + file_idx += LINELEN; + for (int i = 0; i < current_segment; i++) { + color_put(line_segments[i].c); + for (int b = 0; b < line_segments[i].len; b++) { + put_byte(line_segments[i].data[b]); + } + color_reset(); + } + for (int i = 0; i < current_segment; i++) { + color_put(line_segments[i].c); + for (int b = 0; b < line_segments[i].len; b++) { + uint8_t ch = line_segments[i].data[b]; + if (isprint(ch)) { + printf("%c", ch); + } else { + printf("."); + } + } + color_reset(); + } + printf("\n"); +} + +void add_segment(struct segment segment) { + line_segments[current_segment++] = segment; + line_idx += segment.len; + if (line_idx == LINELEN) { + flush_line(); + cleanup_line(); + current_segment = 0; + line_idx = 0; + } +} + +/* + * Buf MUST be a malloc:ed buffer, which is invalidated on this call. + */ +void write_chunk(uint8_t *buf, size_t len) { + if (line_idx + len >= LINELEN) { + enum color c = next_color(); + size_t len1 = LINELEN - line_idx, + len2 = len - len1; + uint8_t *buf1 = malloc(len1), + *buf2 = malloc(len2); + memcpy(buf1, buf, len1); + memcpy(buf2, buf + len1, len2); + free(buf); + struct segment + seg1 = { + .c = c, + .len = len1, + .data = buf1, + }, + seg2 = { + .c = c, + .len = len2, + .data = buf2, + }; + add_segment(seg1); + add_segment(seg2); + } else { + struct segment seg = { + .c = next_color(), + .len = len, + .data = buf, + }; + add_segment(seg); + } +} + +void write_chunk_s(uint8_t *buf, size_t len) { + assert (len >= 0); + uint8_t *true_buf = malloc(len); + memcpy(true_buf, buf, len); + write_chunk(true_buf, len); +} + +int main(int argc, char *argv[]) { + if (argc == 1) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + FILE *f = fopen(argv[1], "rb"); + size_t len; + + struct member header; + uint8_t *extra_fields = NULL; + uint16_t crc16 = 0; + char *filename = NULL; + char *file_comment = NULL; + + len = fread(&header, sizeof(header), 1, f); + + if (len != 1) { + fprintf(stderr, "Unexpected end of header\n"); + return 1; + } + + write_chunk_s((uint8_t[2]) {header.id1, header.id2}, 2); + write_chunk_s(&header.cm, 1); + write_chunk_s(&header.flg, 1); + { + size_t s = sizeof(header.mtime); + uint8_t *buf = malloc(s); + memcpy(buf, &header.mtime, s); + write_chunk(buf, s); + } + write_chunk_s(&header.xfl, 1); + write_chunk_s(&header.os, 1); + + if (header.flg & FEXTRA) { + uint16_t xlen; + len = fread(&xlen, sizeof(xlen), 1, f); + { + uint8_t *buf = malloc(len); + memcpy(buf, &xlen, len); + write_chunk(buf, len); + } + extra_fields = malloc(xlen); + len = fread(extra_fields, 1, xlen, f); + write_chunk(extra_fields, xlen); + } + + if (header.flg & FNAME) { + size_t n; + len = getdelim(&filename, &n, '\0', f); + write_chunk((uint8_t*) filename, n); + } + + if (header.flg & FCOMMENT) { + size_t n; + len = getdelim(&file_comment, &n, '\0', f); + write_chunk((uint8_t*) file_comment, n); + } + + if (header.flg & FHCRC) { + len = fread(&crc16, sizeof(crc16), 1, f); + { + uint8_t *buf = malloc(len); + memcpy(buf, &crc16, len); + write_chunk(buf, len); + } + } + +// cleanup: + if (extra_fields) free(extra_fields); + if (filename) free(filename); + if (file_comment) free(file_comment); + flush_line(); + cleanup_line(); + + printf("\n"); + + +} diff --git a/ui.c b/ui.c new file mode 100644 index 0000000..f114a41 --- /dev/null +++ b/ui.c @@ -0,0 +1,167 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LINE_LEN 0x10 + +// int screen_height, screen_width; + +struct screen { + WINDOW *lineno, *hex, *chr; + int top_address; + void *mem; + size_t mem_len; + int hx, hy; +} screen = { + .hx = -1, .hy = -1, +}; + +void draw_lines() { + for (int y = 0; y < LINES; y++) { + mvwprintw(screen.lineno, y, 0, "%08x:", screen.top_address + y * LINE_LEN); + wrefresh(screen.lineno); + } +} + +void draw_hex() { + for (int y = 0; y < LINES; y++) { + for (int x = 0; x < LINE_LEN; x++) { + if (screen.hy == y && screen.hx == x) { + wattron(screen.hex, A_REVERSE); + } + mvwprintw(screen.hex, y, x * 2 + (x/2), "%02x", + 0xFF & ((char*) screen.mem)[screen.top_address + y * LINE_LEN + x]); + if (screen.hy == y && screen.hx == x) { + wattroff(screen.hex, A_REVERSE); + } + } + wrefresh(screen.hex); + } +} + +void draw_chr() { + for (int y = 0; y < LINES; y++) { + for (int x = 0; x < LINE_LEN; x++) { + if (screen.hy == y && screen.hx == x) { + wattron(screen.chr, A_REVERSE); + } + char c = ((char*) screen.mem)[screen.top_address + y * LINE_LEN + x]; + mvwprintw(screen.chr, y, x, "%c", isprint(c) ? c : '.'); + if (screen.hy == y && screen.hx == x) { + wattroff(screen.chr, A_REVERSE); + } + } + wrefresh(screen.chr); + } +} + +void draw_screen() { + + draw_lines(); + draw_hex(); + draw_chr(); + /* TODO end at end of file */ +} + +int main() { + + /* Terminal supporting mouse movements */ + setenv("TERM", "xterm-1003", true); + + initscr(); + clear(); + noecho(); + cbreak(); + curs_set(0); + + start_color(); + + // getmaxyx(stdscr, screen_height, screen_width); + + keypad(stdscr, true); + + screen.lineno = newwin(0, 10, 0, 0); + screen.hex = newwin(0, (int) ceil(LINE_LEN * 2.5), 0, 10); + screen.chr = newwin(0, LINE_LEN, 0, 10 + (int) ceil(LINE_LEN * 2.5)); + + int fd = open("payload.gz", O_RDONLY); + struct stat statbuf; + if (fstat(fd, &statbuf) == -1) { + goto end; + } + screen.mem_len = statbuf.st_size; + screen.mem = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + + mousemask(ALL_MOUSE_EVENTS|REPORT_MOUSE_POSITION, NULL); + + refresh(); + + draw_screen(); + + int ch; + MEVENT event; + while (1) { + ch = wgetch(stdscr); + switch (ch) { + case KEY_MOUSE: + wmove(stdscr, 0, 0); + switch (getmouse(&event)) { + case OK: + if (event.bstate & BUTTON4_PRESSED) { + screen.top_address -= LINE_LEN; + } + if (event.bstate & BUTTON5_PRESSED) { + screen.top_address += LINE_LEN; + } + + if (event.x >= 10 && event.x < 10 + (int) ceil(LINE_LEN * 2.5)) { + screen.hx = (int) ((event.x - 10) / 2.5); + screen.hy = event.y; + } else if (event.x >= 10 + (int) ceil(LINE_LEN * 2.5) && event.x < (int) ceil(LINE_LEN * 2.5) + 10 + LINE_LEN) { + screen.hx = event.x - (10 + (int) ceil(LINE_LEN * 2.5)); + screen.hy = event.y; + } else { + screen.hx = -1; + screen.hy = -1; + } + + draw_screen(); + break; + case ERR: + // wprintw(win, "err"); + break; + } + draw_screen(); + refresh(); + break; + case KEY_RESIZE: + wresize(screen.lineno, LINES, 0); + wresize(screen.hex, LINES, 0); + wresize(screen.chr, LINES, 0); + draw_screen(); + mvprintw(0, 0, "%ix%i", COLS, LINES); + refresh(); + break; + case KEY_ENTER: + goto end; + } + } + +end: + munmap(screen.mem, 0); + delwin(screen.lineno); + delwin(screen.hex); + delwin(screen.chr); + endwin(); + return 0; +} -- cgit v1.2.3