├── screenshot.png ├── .gitattributes ├── a.c ├── WMA09308.TMP ├── b.c ├── .gitignore ├── README.md ├── LICENSE ├── Makefile ├── lxedit.c ├── fixups.c ├── pages.c ├── objects.c ├── lx.c ├── info.c ├── lxlib.c └── lx.h /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetmorecode/lxedit/HEAD/screenshot.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /a.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main (int ac, char **av) { 4 | printf("A\n"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /WMA09308.TMP: -------------------------------------------------------------------------------- 1 | name lxedit.exe 2 | system dos32a 3 | file { 4 | ..\pdcurses\dos\pdcurses.lib 5 | lxedit.obj lx.obj objects.obj pages.obj fixups.obj info.obj 6 | } 7 | option quiet 8 | -------------------------------------------------------------------------------- /b.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // We want this in the data object so a fixup is created 4 | // that we can overwrite 5 | char run_game_dummy[] = "\xc3"; 6 | 7 | int main (int ac, char **av) { 8 | // Print some banner and wait for input 9 | printf("F1 Manager Professional Megapack 2022\nPress any key to continue.."); 10 | getchar(); 11 | 12 | // Start the game 13 | void(*f)() = (void(*)())run_game_dummy; 14 | f(); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | *.sym 54 | *.txt 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LX/LE executable editor for DOS (WIP) 2 | 3 | ![lxedit](screenshot.png) 4 | 5 | ## Features 6 | 7 | * View LX/LE exeuctables (headers, objects, pages, fixups) 8 | * Change base address, permission or order of objects (WIP) 9 | * Merge objects from multiple executables into one exe (WIP) 10 | * Manually add and edit fixups (like "hooking" places) (WIP) 11 | * Edit page data with inline hex editor (WIP) 12 | 13 | ## Usage 14 | 15 | * Run `lxedit file1.exe file2.exe ...` 16 | * Arrow keys to navigate `up`, `down`, `left` and `right` 17 | * `e` to edit data 18 | * `m` to merge objects 19 | * `w` to write changes to a new exe file 20 | * `q` to exit 21 | 22 | ## Development (in dosbox) 23 | * Install open watcom 24 | * Install pdcurses 25 | * Run wmake -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 yetmorecode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CURSES=..\pdcurses 2 | 3 | lxedit.exe: lxlib.obj objects.obj pages.obj fixups.obj info.obj lxedit.obj 4 | wlink @<< 5 | name $@ 6 | system dos32a 7 | file { 8 | $CURSES\dos\pdcurses.lib 9 | $< 10 | } 11 | option quiet 12 | << 13 | 14 | a.exe: a.obj 15 | wlink @<< 16 | name $@ 17 | system dos32a 18 | file { 19 | $< 20 | } 21 | option quiet 22 | << 23 | b.exe: b.obj 24 | wlink @<< 25 | name $@ 26 | system stub32ac 27 | debug all 28 | file { 29 | $< 30 | } 31 | << 32 | lxedit.obj: lxedit.c lx.h 33 | wpp386 -zq -bt=dos32a $< -i=$CURSES 34 | lxlib.obj: lxlib.c lx.h 35 | wpp386 -zq -bt=dos32a $< -i=$CURSES 36 | objects.obj: objects.c lx.h 37 | wpp386 -zq -bt=dos32a $< -i=$CURSES 38 | pages.obj: pages.c lx.h 39 | wpp386 -zq -bt=dos32a $< -i=$CURSES 40 | fixups.obj: fixups.c lx.h 41 | wpp386 -zq -bt=dos32a $< -i=$CURSES 42 | info.obj: info.c lx.h 43 | wpp386 -zq -bt=dos32a $< -i=$CURSES 44 | a.obj: a.c 45 | wpp386 -zq -bt=dos32a $< -i=$CURSES 46 | b.obj: b.c 47 | wpp386 -d2 -zq -bt=dos32a $< -i=$CURSES 48 | 49 | clean: .SYMBOLIC 50 | del *.obj 51 | del lxedit.exe 52 | del a.exe 53 | del b.exe 54 | -------------------------------------------------------------------------------- /lxedit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "lx.h" 10 | 11 | lxedit *lx; 12 | 13 | lxedit_window *objects_window = objects_window_create(); 14 | lxedit_window *pages_window = pages_window_create(); 15 | lxedit_window *fixups_window = fixups_window_create(); 16 | lxedit_window *info_window = info_window_create(); 17 | 18 | void refresh_windows() { 19 | lx->layout->active_window->refresh(); 20 | wrefresh(lx->layout->header); 21 | wrefresh(lx->layout->status); 22 | } 23 | 24 | void goodbye() { 25 | wclear(lx->layout->header); 26 | wclear(lx->layout->tree); 27 | wclear(lx->layout->status); 28 | mvwprintw(lx->layout->header, 0, 0, "Thanks for using " TITLE); 29 | WINDOW *del = newwin(lx->layout->screen_height-1, lx->layout->screen_width, 1, 0); 30 | refresh_windows(); 31 | wrefresh(del); 32 | curs_set(1); 33 | } 34 | 35 | int main (int ac, char **av) { 36 | initscr(); 37 | keypad(stdscr, TRUE); 38 | noecho(); 39 | curs_set(0); 40 | start_color(); 41 | refresh(); 42 | 43 | init_pair(COLOR_HEADER, COLOR_WHITE, COLOR_RED); 44 | init_pair(COLOR_STATUS, COLOR_WHITE, COLOR_RED); 45 | init_pair(COLOR_TREE, COLOR_WHITE, COLOR_BLACK); 46 | 47 | lx = (lxedit*)malloc(sizeof(lxedit)); 48 | lx->layout = (lxedit_layout*)malloc(sizeof(lxedit_layout)); 49 | lxedit_layout *layout = lx->layout; 50 | getmaxyx(stdscr, 51 | layout->screen_height, 52 | layout->screen_width); 53 | 54 | layout->active_object = -1; 55 | layout->header = newwin(1, layout->screen_width, 0, 0); 56 | wbkgd(layout->header, COLOR_PAIR(COLOR_HEADER)); 57 | mvwprintw(layout->header, 0, layout->screen_width/2 - strlen(TITLE)/2, TITLE); 58 | 59 | 60 | layout->status = newwin(1, layout->screen_width, layout->screen_height - 1, 0); 61 | layout->tree = newwin(layout->screen_height - 2, layout->screen_width, 1, 0); 62 | wbkgd(layout->status, COLOR_PAIR(COLOR_STATUS)); 63 | 64 | lx->executables = (exe**)malloc((ac-1)*sizeof(exe*)); 65 | lx->num_executables = ac-1; 66 | for (int i = 1; i < ac; i++) { 67 | lx->executables[i-1] = (exe *)lx_load(av[i]); 68 | } 69 | 70 | layout->active_exe = 0; 71 | static int left_count = 0; 72 | layout->active_window = objects_window; 73 | while (1) { 74 | refresh_windows(); 75 | int ch = getch(); 76 | if (ch == KEY_LEFT) { 77 | left_count++; 78 | } else { 79 | left_count = 0; 80 | } 81 | if (ch == 'q' || (ch == KEY_LEFT && left_count > 1)) { 82 | if (layout->active_window == objects_window) { 83 | goodbye(); 84 | return 0; 85 | } 86 | } 87 | lxedit_window *next = (lxedit_window*)layout->active_window->input(ch); 88 | if (next) { 89 | layout->active_window = next; 90 | left_count = 0; 91 | } 92 | } 93 | curs_set(1); 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /fixups.c: -------------------------------------------------------------------------------- 1 | #include "lx.h" 2 | #include 3 | 4 | void fixups_refresh() { 5 | lxedit_layout *l = lx->layout; 6 | int row = 0; 7 | exe *exe = lx->executables[l->active_exe]; 8 | object_record *r = exe->object_records + l->active_object; 9 | 10 | for (int i = 0; i < exe->fixup_count[l->active_page-1]; i++) { 11 | if (i < l->scroll_fixup) { 12 | continue; 13 | } 14 | if (l->active_fixup == i) { 15 | wattron(l->tree, A_BOLD); 16 | } 17 | lx_fixup *f = exe->fixups[l->active_page-1][i]; 18 | int col = 40; 19 | switch(f->type & OSF_SOURCE_MASK) { 20 | case 0: 21 | mvwprintw(l->tree, row, col, "%s", "byte"); 22 | break; 23 | case 1: 24 | mvwprintw(l->tree, row, col, "%s","u1"); 25 | break; 26 | case 2: 27 | mvwprintw(l->tree, row, col, "%s","seg"); 28 | break; 29 | case 3: 30 | mvwprintw(l->tree, row, col, "%s","32bit ptr"); 31 | break; 32 | case 4: 33 | mvwprintw(l->tree, row, col, "%s","u4"); 34 | break; 35 | case 5: 36 | mvwprintw(l->tree, row, col, "%s","16bit off"); 37 | break; 38 | case 6: 39 | mvwprintw(l->tree, row, col, "%s","16:32bit ptr"); 40 | break; 41 | case 7: 42 | mvwprintw(l->tree, row, col, "%s","32bit off"); 43 | break; 44 | case 8: 45 | mvwprintw(l->tree, row, col, "%s","32bit rel"); 46 | break; 47 | 48 | } 49 | col = 16; 50 | switch (f->flags & OSF_TARGET_MASK) { 51 | case OSF_TARGET_INTERNAL: 52 | { 53 | mvwprintw(l->tree, row, col, "-> %08x (%x:%06x)", 54 | exe->object_records[f->object-1].addr + f->target_off, 55 | f->object, 56 | f->target_off); 57 | 58 | 59 | unsigned char buf[6] = "\x00\x00\x00\x00\x00"; 60 | lx_read(exe, f->object, f->target_off, buf, sizeof(buf)-1); 61 | for (int i=0; i < sizeof(buf)-1; i++) { 62 | mvwprintw(l->tree, row, 53 + i*3, "%02x ", buf[i]); 63 | mvwprintw(l->tree, row, 53 + sizeof(buf)*3 - 2 + i, "%c ", isalpha(buf[i]) ? buf[i] : '.'); 64 | } 65 | } 66 | break; 67 | case OSF_TARGET_EXT_ORD: 68 | mvwprintw(l->tree, row, col, "%s", "import by ord"); 69 | break; 70 | case OSF_TARGET_EXT_NAME: 71 | mvwprintw(l->tree, row, col, "%s", "import by name"); 72 | break; 73 | case OSF_TARGET_INT_VIA_ENTRY: 74 | mvwprintw(l->tree, row, col, "%s", "ref via entry"); 75 | break; 76 | 77 | } 78 | mvwprintw(l->tree, row, 6, "@%08x", r->addr + (l->active_page - r->mapidx)*exe->lx.page_size + f->src_off); 79 | mvwprintw(l->tree, row++, 0, "%04d", i+1); 80 | wattroff(l->tree, A_BOLD); 81 | } 82 | wrefresh(l->tree); 83 | 84 | wclear(l->status); 85 | mvwprintw(l->status, 0, 0, "%s > Object #%d > Page #%d (%x - %x)", 86 | lx->executables[l->active_exe]->name, 87 | l->active_object+1, 88 | l->active_page, 89 | r->addr + (l->active_page - r->mapidx)*exe->lx.page_size, 90 | r->addr + (l->active_page - r->mapidx+1)*exe->lx.page_size); 91 | wrefresh(l->status); 92 | } 93 | 94 | void *fixups_input(int ch) { 95 | exe *exe = lx->executables[lx->layout->active_exe]; 96 | lxedit_layout *l = lx->layout; 97 | switch(ch) { 98 | case KEY_LEFT: 99 | case 'q': 100 | return pages_window; 101 | case KEY_DOWN: 102 | if (l->active_fixup == exe->fixup_count[l->active_page-1]-1) { 103 | l->active_fixup = 0; 104 | l->scroll_fixup = 0; 105 | } else { 106 | l->active_fixup++; 107 | } 108 | if (l->active_fixup - l->scroll_fixup > l->screen_height - 3) { 109 | l->scroll_fixup++; 110 | } 111 | break; 112 | case KEY_UP: 113 | if (l->active_fixup == 0) { 114 | l->active_fixup = exe->fixup_count[l->active_page-1]-1; 115 | l->scroll_fixup = l->active_fixup - (l->screen_height - 3); 116 | } else { 117 | l->active_fixup--; 118 | } 119 | if (l->active_fixup < l->scroll_fixup) { 120 | l->scroll_fixup--; 121 | } 122 | break; 123 | case 'e': 124 | { 125 | char buf[20]; 126 | int r = l->active_fixup - l->scroll_fixup + 1; 127 | WINDOW *input = newwin(1, sizeof(buf)-1, r, 19); 128 | wbkgd(input, COLOR_PAIR(COLOR_HEADER)); 129 | echo(); 130 | wrefresh(input); 131 | wgetnstr(input, buf, sizeof(buf)-1); 132 | uint16_t obj; 133 | uint32_t target; 134 | sscanf(buf, "%d:%x", &obj, &target); 135 | lx_fixup *f = exe->fixups[l->active_page-1][l->active_fixup]; 136 | f->object = obj; 137 | f->target_off = target; 138 | noecho(); 139 | delwin(input); 140 | wclear(l->tree); 141 | } 142 | break; 143 | 144 | } 145 | return NULL; 146 | } 147 | 148 | lxedit_window *fixups_window_create() { 149 | static lxedit_window win; 150 | win.refresh = &fixups_refresh; 151 | win.input = &fixups_input; 152 | return &win; 153 | } 154 | -------------------------------------------------------------------------------- /pages.c: -------------------------------------------------------------------------------- 1 | #include "lx.h" 2 | 3 | void pages_refresh() { 4 | lxedit_layout *layout = lx->layout; 5 | wclear(layout->tree); 6 | int row = 1; 7 | exe *exe = lx->executables[layout->active_exe]; 8 | object_record *r = &exe->object_records[layout->active_object]; 9 | for (int i = 0; i < r->mapsize; i++) { 10 | int page = r->mapidx + i; 11 | if (page < layout->scroll_page) { 12 | continue; 13 | } 14 | if (page == layout->active_page) { 15 | wattron(layout->tree, A_BOLD); 16 | } 17 | if (exe->lx.signature == OSF_FLAT_SIGNATURE) { 18 | // LE 19 | le_map_entry *lemap = (le_map_entry*)(&exe->object_map[page-1]); 20 | int page_num = lemap->page_num[2] + (lemap->page_num[1] << 8) + (lemap->page_num[0] << 16); 21 | mvwprintw(layout->tree, row, 10, "~%d", page_num); 22 | mvwprintw(layout->tree, row, 28, "%06x - %06x", 23 | exe->lx.page_off + (page_num-1) * exe->lx.page_size, 24 | exe->lx.page_off + page_num * exe->lx.page_size); 25 | switch (lemap->flags) { 26 | case PAGE_VALID: 27 | mvwprintw(layout->tree, row, 16, "valid"); 28 | break; 29 | case PAGE_ITERATED: 30 | mvwprintw(layout->tree, row, 16, "iter"); 31 | break; 32 | case PAGE_INVALID: 33 | mvwprintw(layout->tree, row, 16, "inval"); 34 | break; 35 | case PAGE_ZEROED: 36 | mvwprintw(layout->tree, row, 16, "zero"); 37 | break; 38 | case PAGE_RANGE: 39 | mvwprintw(layout->tree, row, 16, "range"); 40 | break; 41 | default: 42 | mvwprintw(layout->tree, row, 16, "%x", lemap->flags); 43 | break; 44 | } 45 | mvwprintw(layout->tree, row, 44, "%08x - %08x", 46 | r->addr + i * exe->lx.page_size, 47 | r->addr + (i+1) * exe->lx.page_size, 48 | exe->lx.page_size); 49 | } else { 50 | // LX 51 | lx_map_entry *lxmap = (lx_map_entry*)(&exe->object_map[page-1]); 52 | int offset = lxmap->page_offset; 53 | int size = lxmap->data_size; 54 | int flags = lxmap->flags; 55 | mvwprintw(layout->tree, row, 16, "%x", size); 56 | mvwprintw(layout->tree, row, 22, "%04x", flags); 57 | mvwprintw(layout->tree, row, 29, "%06x - %06x", 58 | exe->lx.page_off + offset, 59 | exe->lx.page_off + offset + size); 60 | mvwprintw(layout->tree, row, 46, "%08x - %08x", 61 | r->addr + offset, 62 | r->addr + offset + size); 63 | } 64 | mvwprintw(layout->tree, row, 73, "%d", exe->fixup_count[page-1]); 65 | mvwprintw(layout->tree, row++, 0, "Page #%d", page); 66 | wattroff(layout->tree, A_BOLD); 67 | } 68 | wrefresh(layout->tree); 69 | WINDOW *tree_head = newwin(1, layout->screen_width, 1, 0); 70 | wbkgd(tree_head, COLOR_PAIR(COLOR_STATUS)); 71 | mvwprintw(tree_head, 0, 0, "Logical#"); 72 | mvwprintw(tree_head, 0, 10, "Phy#"); 73 | mvwprintw(tree_head, 0, 16, "Size"); 74 | mvwprintw(tree_head, 0, 22, "Flags"); 75 | mvwprintw(tree_head, 0, 29, "File Offset"); 76 | mvwprintw(tree_head, 0, 46, "Memory"); 77 | mvwprintw(tree_head, 0, 73, "Fixups"); 78 | wrefresh(tree_head); 79 | delwin(tree_head); 80 | wclear(layout->status); 81 | mvwprintw(layout->status, 0, 0, 82 | "%s > Object #%d (%d pages)", 83 | exe->name, layout->active_object+1, r->mapsize); 84 | wrefresh(layout->status); 85 | 86 | return; 87 | } 88 | 89 | void *pages_input(int ch) { 90 | lxedit_layout *layout = lx->layout; 91 | exe *exe = lx->executables[layout->active_exe]; 92 | object_record *r = &exe->object_records[layout->active_object]; 93 | switch (ch) { 94 | case KEY_LEFT: 95 | case 'q': 96 | wclear(layout->tree); 97 | return objects_window; 98 | case KEY_RIGHT: 99 | wclear(layout->tree); 100 | wclear(layout->status); 101 | layout->active_fixup = 0; 102 | layout->scroll_fixup = 0; 103 | return fixups_window; 104 | case KEY_DOWN: 105 | if (layout->active_page == r->mapidx + r->mapsize - 1) { 106 | layout->active_page = r->mapidx; 107 | layout->scroll_page = r->mapidx; 108 | } else { 109 | layout->active_page++; 110 | } 111 | if (layout->active_page - layout->scroll_page >= layout->screen_height - 3) { 112 | layout->scroll_page++; 113 | } 114 | break; 115 | case KEY_UP: 116 | if (layout->active_page == r->mapidx) { 117 | layout->active_page = r->mapidx + r->mapsize - 1; 118 | layout->scroll_page = layout->active_page - layout->screen_height + 4; 119 | } else { 120 | layout->active_page--; 121 | } 122 | if (layout->active_page - layout->scroll_page < 0) { 123 | layout->scroll_page--; 124 | } 125 | break; 126 | } 127 | return NULL; 128 | } 129 | 130 | lxedit_window *pages_window_create() { 131 | static lxedit_window window; 132 | window.input = &pages_input; 133 | window.refresh = &pages_refresh; 134 | return &window; 135 | } 136 | -------------------------------------------------------------------------------- /objects.c: -------------------------------------------------------------------------------- 1 | #include "lx.h" 2 | #include 3 | #include 4 | #include 5 | 6 | void *objects_input(int ch) { 7 | lxedit_layout *layout = lx->layout; 8 | switch (ch) { 9 | case KEY_RIGHT: 10 | case 10: 11 | if (layout->active_object != -1) { 12 | exe *exe = lx->executables[layout->active_exe]; 13 | object_record *r = &exe->object_records[layout->active_object]; 14 | layout->active_page = r->mapidx; 15 | layout->scroll_page = r->mapidx; 16 | return pages_window; 17 | } else { 18 | return info_window; 19 | } 20 | break; 21 | case KEY_UP: 22 | if (layout->active_object == 0) { 23 | // go to parent exe 24 | layout->active_object = -1; 25 | } else if (layout->active_object == -1) { 26 | // goto next exe last object 27 | if (layout->active_exe == 0) { 28 | layout->active_exe = lx->num_executables-1; 29 | } else { 30 | layout->active_exe--; 31 | } 32 | layout->active_object = lx->executables[layout->active_exe]->lx.num_objects-1; 33 | } else { 34 | layout->active_object--; 35 | } 36 | break; 37 | case KEY_DOWN: 38 | if (layout->active_object == -1) { 39 | layout->active_object = 0; 40 | } else { 41 | if (layout->active_object >= lx->executables[layout->active_exe]->lx.num_objects-1) { 42 | // goto next exe 43 | layout->active_object = -1; 44 | if (layout->active_exe == lx->num_executables - 1){ 45 | layout->active_exe = 0; 46 | } else { 47 | layout->active_exe++; 48 | } 49 | } else { 50 | // goto next object 51 | layout->active_object++; 52 | } 53 | } 54 | break; 55 | case 'm': 56 | { 57 | exe **new_executables = (exe **)malloc(sizeof(exe*)); 58 | exe *e = lx->executables[0]; 59 | for (int i=1; i < lx->num_executables; i++) { 60 | e = lx_merge(e, lx->executables[i], layout->active_exe == i); 61 | } 62 | new_executables[0] = e; 63 | lx_save(e); 64 | lx->executables = new_executables; 65 | lx->num_executables = 1; 66 | layout->active_exe = 0; 67 | } 68 | break; 69 | case 's': 70 | lx_save(lx->executables[layout->active_exe]); 71 | break; 72 | default: 73 | break; 74 | } 75 | return NULL; 76 | } 77 | 78 | void objects_refresh() { 79 | int row = 0; 80 | lxedit_layout *layout = lx->layout; 81 | exe *exe, *active_exe; 82 | active_exe = lx->executables[layout->active_exe]; 83 | werase(layout->tree); 84 | for (int j = 0; j < lx->num_executables; j++) { 85 | exe = lx->executables[j]; 86 | if (j == layout->active_exe && layout->active_object == -1) { 87 | wattron(layout->tree, A_BOLD); 88 | } 89 | mvwprintw(layout->tree, row, 0, "%s", exe->name); 90 | mvwprintw(layout->tree, row++, 51, "%d pages", exe->lx.num_pages); 91 | wattroff(layout->tree, A_BOLD); 92 | for (int i = 0; i < exe->lx.num_objects; i++) { 93 | if (j == layout->active_exe && layout->active_object == i) { 94 | wattron(layout->tree, A_BOLD); 95 | } 96 | object_record *r = &exe->object_records[i]; 97 | mvwprintw(layout->tree, row, INDENT, "Object #%d", i); 98 | mvwprintw(layout->tree, row, 13, "%s%s%s", 99 | r->flags & OBJ_READABLE ? "r" : "-", 100 | r->flags & OBJ_WRITEABLE ? "w" : "-", 101 | r->flags & OBJ_EXECUTABLE ? "x" : "-"); 102 | mvwprintw(layout->tree, row, 51, "%3d - %3d (%d)", r->mapidx, r->mapidx + r->mapsize - 1, r->mapsize); 103 | mvwprintw(layout->tree, row++, 18, "%08x - %08x [%7x]", r->addr, r->addr + r->size, r->size); 104 | wattroff(layout->tree, A_BOLD); 105 | } 106 | row++; 107 | } 108 | wrefresh(layout->tree); 109 | exe = lx->executables[layout->active_exe]; 110 | char *shortname = exe->name + strlen(exe->name)-1; 111 | while (*shortname && *shortname != '\\') { 112 | shortname--; 113 | } 114 | werase(layout->status); 115 | if (exe->stat) { 116 | mvwprintw(layout->status, 0, 0, "%s | %.1f%s | fixups: %dkb | pages: %dkb", 117 | *shortname == '\\' ? shortname+1 : shortname, 118 | exe->stat->st_size > 1024*1024 ? 1.0*exe->stat->st_size/1024/1024: 1.0*exe->stat->st_size/1024, 119 | exe->stat->st_size > 1024*1024 ? "mb" : "kb", 120 | exe->fixup_map[exe->lx.num_pages] / 1024, 121 | (exe->lx.page_size * (exe->lx.num_pages-1) + exe->lx.l.last_page)/1024); 122 | } else { 123 | mvwprintw(layout->status, 0, 0, "%s | fixups: %dkb | pages: %dkb", 124 | *shortname == '\\' ? shortname+1 : shortname, 125 | exe->fixup_map[exe->lx.num_pages] / 1024, 126 | (exe->lx.page_size * (exe->lx.num_pages-1) + exe->lx.l.last_page)/1024); 127 | 128 | } 129 | wrefresh(layout->status); 130 | } 131 | 132 | lxedit_window *objects_window_create() { 133 | static lxedit_window window; 134 | window.refresh = &objects_refresh; 135 | window.input = &objects_input; 136 | return &window; 137 | } 138 | -------------------------------------------------------------------------------- /lx.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "lx.h" 5 | 6 | int lx_fixup_parse(char *begin, lx_fixup *f) { 7 | static lx_fixup tmp; 8 | char *start = begin; 9 | if (f == NULL) { 10 | f = &tmp; 11 | } 12 | f->type = *begin++; 13 | f->flags = *begin++; 14 | if (f->type & OSF_SFLAG_LIST) { 15 | f->src_off = *begin++; 16 | } else { 17 | f->src_off = *(short *)begin; 18 | begin += 2; 19 | } 20 | if (f->flags & OSF_TFLAG_OBJ_MOD_16BIT) { 21 | f->object = *(short *)begin; 22 | begin += 2; 23 | } else { 24 | f->object = *begin++; 25 | } 26 | if ((f->flags & OSF_TARGET_MASK) == OSF_TARGET_INTERNAL) { 27 | if ((f->type & OSF_SOURCE_MASK) == OSF_SOURCE_SEG) { 28 | // no target 29 | } else if (f->flags & OSF_TFLAG_OFF_32BIT) { 30 | f->target_off = *(int *)begin; 31 | begin += 4; 32 | } else { 33 | f->target_off = *(short *)begin; 34 | begin += 2; 35 | } 36 | } else if ((f->flags & OSF_TARGET_MASK) == OSF_TARGET_EXT_ORD) { 37 | if (f->flags & OSF_TFLAG_OBJ_MOD_16BIT) { 38 | f->mod_ord = *(short *)begin; 39 | begin += 2; 40 | } else { 41 | f->mod_ord = *begin++; 42 | } 43 | if (f->flags & OSF_TFLAG_ORDINAL_8BIT) { 44 | f->imp_ord = *begin++; 45 | } else if (f->flags & OSF_TFLAG_OFF_32BIT) { 46 | f->imp_ord = *(int*)begin; 47 | begin += 4; 48 | } else { 49 | f->imp_ord = *(short*)begin; 50 | begin += 2; 51 | } 52 | if (f->flags & OSF_TFLAG_ADDITIVE_VAL) { 53 | f->additive = *(int*)begin; 54 | begin += 4; 55 | } 56 | } else if ((f->flags & OSF_TARGET_MASK) == OSF_TARGET_EXT_NAME) { 57 | if (f->flags & OSF_TFLAG_OBJ_MOD_16BIT) { 58 | f->mod_ord = *(short *)begin; 59 | begin += 2; 60 | } else { 61 | f->mod_ord = *begin++; 62 | } 63 | if (f->flags & OSF_TFLAG_OFF_32BIT) { 64 | f->name_off = *(int*)begin; 65 | begin += 4; 66 | } else { 67 | f->name_off = *(short*)begin; 68 | begin += 2; 69 | 70 | } 71 | if (f->flags & OSF_TFLAG_ADDITIVE_VAL) { 72 | f->additive = *(int*)begin; 73 | begin += 4; 74 | } 75 | } else { 76 | if (f->flags & OSF_TFLAG_OBJ_MOD_16BIT) { 77 | f->mod_ord = *(short *)begin; 78 | begin += 2; 79 | } else { 80 | f->mod_ord = *begin++; 81 | } 82 | if (f->flags & OSF_TFLAG_ADDITIVE_VAL) { 83 | f->additive = *(int*)begin; 84 | begin += 4; 85 | } 86 | } 87 | if (f->type & OSF_SFLAG_LIST) { 88 | begin += 2*f->src_off; 89 | } 90 | return begin - start; 91 | } 92 | 93 | int lx_fixup_length(char *begin) { 94 | return lx_fixup_parse(begin, NULL); 95 | } 96 | 97 | exe *lx_load_executable(char *name) { 98 | exe *e; 99 | e = (exe *)malloc(sizeof(exe)); 100 | char *cwd = getcwd(NULL, 0); 101 | char *filename = (char*)malloc(strlen(cwd) + strlen(name) + 2); 102 | sprintf(filename, "%s\\%s", cwd, name); 103 | e->name = filename; 104 | FILE *file = fopen(filename, "rb"); 105 | if (file == NULL) { 106 | return NULL; 107 | } 108 | 109 | // Stat file 110 | e->stat = (struct stat*)malloc(sizeof(*e->stat)); 111 | stat(filename, e->stat); 112 | 113 | // Read MZ header 114 | int r = fread(&e->mz, sizeof(e->mz), 1, file); 115 | if (r != 1) { 116 | return NULL; 117 | } 118 | if (e->mz.e_magic != 0x5a4d) { 119 | curs_set(1); 120 | return NULL; 121 | } 122 | 123 | // Read MZ relocations and code 124 | int code_size = e->mz.e_lfanew - sizeof(e->mz); 125 | if (code_size <= 0) { 126 | return NULL; 127 | } 128 | e->mz_code = (uint8_t*)malloc(code_size); 129 | r = fread(e->mz_code, code_size, 1, file); 130 | if (r != 1) { 131 | return NULL; 132 | } 133 | 134 | // Read LX header 135 | r = fread(&e->lx, sizeof(e->lx), 1, file); 136 | if (r != 1) { 137 | return NULL; 138 | } 139 | 140 | // Read object records 141 | e->object_records = (object_record *)malloc(e->lx.num_objects * sizeof(object_record)); 142 | fseek(file, e->mz.e_lfanew + e->lx.objtab_off, SEEK_SET); 143 | fread(e->object_records, sizeof(object_record), e->lx.num_objects, file); 144 | 145 | // Read object page map 146 | e->object_map = (map_entry *)malloc(e->lx.num_pages * sizeof(map_entry)); 147 | fseek(file, e->mz.e_lfanew + e->lx.objmap_off, SEEK_SET); 148 | for (int i = 0; i < e->lx.num_pages; i++) { 149 | if (e->lx.signature == OSF_FLAT_SIGNATURE) { 150 | // LE 151 | fread(e->object_map + i, sizeof(le_map_entry), 1, file); 152 | } else { 153 | // LX 154 | fread(e->object_map + i, sizeof(lx_map_entry), 1, file); 155 | } 156 | } 157 | 158 | // Read name table 159 | long pos = e->lx.resname_off; 160 | lx_name *head = NULL; 161 | while (pos < e->lx.entry_off) { 162 | uint8_t l = 0; 163 | fread(&l, 1, 1, file); 164 | if (l > 0) { 165 | lx_name *n = (lx_name *)malloc(sizeof(lx_name)); 166 | n->length = l; 167 | n->name = (char *)malloc(l+1); 168 | fread(n->name, l, 1, file); 169 | n->name[l] = 0; 170 | fread(&n->ordinal, sizeof(n->ordinal), 1, file); 171 | if (head) { 172 | n->next = head; 173 | n->prev = head->prev; 174 | head->prev->next = n; 175 | head->prev = n; 176 | } else { 177 | head = n; 178 | head->prev = n; 179 | head->next = n; 180 | } 181 | pos += sizeof(uint8_t) + l + sizeof(uint16_t); 182 | } else { 183 | pos++; 184 | break; 185 | } 186 | } 187 | e->names = head; 188 | // Read entry table 189 | 190 | // Read fixup page table 191 | e->fixup_map = (uint32_t *)malloc(sizeof(uint32_t)*(e->lx.num_pages+1)); 192 | fseek(file, e->mz.e_lfanew + e->lx.fixpage_off, SEEK_SET); 193 | fread(e->fixup_map, sizeof(uint32_t), e->lx.num_pages+1, file); 194 | 195 | // Read fixup records 196 | e->fixup_count = (int*)malloc(sizeof(int) * e->lx.num_pages); 197 | e->fixups = (lx_fixup ***)malloc(sizeof(void*) * e->lx.num_pages); 198 | char *fixup_data = (char*)malloc(e->lx.fixup_size); 199 | fseek(file, e->mz.e_lfanew + e->lx.fixrec_off, SEEK_SET); 200 | fread(fixup_data, e->lx.fixup_size - sizeof(int)*(e->lx.num_pages+1), 1, file); 201 | for (int i = 0; i < e->lx.num_pages; i++) { 202 | // Read fixups for page 203 | char *begin = fixup_data + e->fixup_map[i]; 204 | char *end = fixup_data + e->fixup_map[i+1]; 205 | e->fixup_count[i] = 0; 206 | while (begin < end) { 207 | begin += lx_fixup_length(begin); 208 | e->fixup_count[i]++; 209 | } 210 | e->fixups[i] = (lx_fixup**)malloc(e->fixup_count[i] * sizeof(lx_fixup*)); 211 | begin = fixup_data + e->fixup_map[i]; 212 | int j = 0; 213 | while (begin < end) { 214 | lx_fixup *f = (lx_fixup*)malloc(sizeof(lx_fixup)); 215 | memset(f, 0, sizeof(lx_fixup)); 216 | begin += lx_fixup_parse(begin, f); 217 | e->fixups[i][j++] = f; 218 | } 219 | } 220 | 221 | // Read pages 222 | e->pages = (uint8_t **)malloc(sizeof(uint8_t *) * e->lx.num_pages); 223 | for (int i=0; i < e->lx.num_pages; i++) { 224 | // TODO support LX 225 | int size = e->lx.page_size; 226 | if (i == e->lx.num_pages - 1) { 227 | size = e->lx.l.last_page; 228 | } 229 | e->pages[i] = (uint8_t*)malloc(size); 230 | fseek(file, e->lx.page_off + i*e->lx.page_size, SEEK_SET); 231 | fread(e->pages[i], size, 1, file); 232 | } 233 | return e; 234 | } 235 | 236 | -------------------------------------------------------------------------------- /info.c: -------------------------------------------------------------------------------- 1 | #include "lx.h" 2 | 3 | void info_refresh() { 4 | lxedit_layout *l = lx->layout; 5 | wclear(l->tree); 6 | int row = 0; 7 | exe *exe = lx->executables[lx->layout->active_exe]; 8 | mvwprintw(l->tree, row++, 0, "%s", exe->name); 9 | mvwprintw(l->tree, row, 0, "%6x - %6x", 0, sizeof(exe->mz)); 10 | mvwprintw(l->tree, row++, 16, "MZ header"); 11 | mvwprintw(l->tree, row, 0, "%6x - %6x", sizeof(exe->mz), exe->mz.e_cparhdr*16); 12 | mvwprintw(l->tree, row++, 16, "MZ relocations"); 13 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_cparhdr*16, (exe->mz.e_cp-1)*512 + exe->mz.e_cblp); 14 | mvwprintw(l->tree, row++, 16, "MZ code"); 15 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew, exe->mz.e_lfanew + sizeof(exe->lx)); 16 | mvwprintw(l->tree, row++, 16, "LX header"); 17 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + sizeof(exe->lx), exe->mz.e_lfanew + sizeof(exe->lx) + exe->lx.loader_size); 18 | mvwprintw(l->tree, row++, 16, "LX loader"); 19 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + exe->lx.objtab_off, exe->mz.e_lfanew + exe->lx.objtab_off + exe->lx.num_objects*sizeof(object_record)); 20 | mvwprintw(l->tree, row++, 18, "object table"); 21 | mvwprintw(l->tree, row, 0, "%6x - %6x", 22 | exe->mz.e_lfanew + exe->lx.objmap_off, 23 | exe->mz.e_lfanew + exe->lx.objmap_off + 24 | exe->lx.num_pages * (exe->lx.signature == OSF_FLAT_SIGNATURE ? sizeof(le_map_entry) : sizeof(lx_map_entry))); 25 | mvwprintw(l->tree, row++, 18, "page table"); 26 | if (exe->lx.num_rsrcs) { 27 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + exe->lx.rsrc_off, exe->mz.e_lfanew + exe->lx.rsrc_off + 16*exe->lx.num_rsrcs); 28 | mvwprintw(l->tree, row++, 18, "resource table"); 29 | } 30 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + exe->lx.resname_off, exe->mz.e_lfanew + exe->lx.entry_off); 31 | mvwprintw(l->tree, row++, 18, "name table"); 32 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + exe->lx.entry_off, exe->mz.e_lfanew + exe->lx.entry_off + 1); 33 | mvwprintw(l->tree, row++, 18, "entry table"); 34 | if (exe->lx.cksum_off) { 35 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + exe->lx.cksum_off, exe->mz.e_lfanew + exe->lx.cksum_off); 36 | mvwprintw(l->tree, row++, 18, "checksum table"); 37 | } 38 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + exe->lx.fixpage_off, exe->mz.e_lfanew + exe->lx.fixpage_off + (exe->lx.num_pages+1)*4); 39 | mvwprintw(l->tree, row++, 18, "fixup table"); 40 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + exe->lx.fixrec_off, exe->mz.e_lfanew + exe->lx.impmod_off); 41 | mvwprintw(l->tree, row++, 18, "fixup records"); 42 | if (exe->lx.impproc_off > exe->lx.impmod_off) { 43 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + exe->lx.impmod_off, exe->mz.e_lfanew + exe->lx.impproc_off); 44 | mvwprintw(l->tree, row++, 18, "import mods"); 45 | } 46 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->mz.e_lfanew + exe->lx.impproc_off, exe->mz.e_lfanew + exe->lx.fixpage_off + exe->lx.fixup_size); 47 | mvwprintw(l->tree, row++, 18, "import proc"); 48 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->lx.page_off, exe->lx.page_off + (exe->lx.num_pages-1)*exe->lx.page_size + exe->lx.l.last_page); 49 | mvwprintw(l->tree, row++, 16, "LX pages"); 50 | if (exe->lx.debug_off) { 51 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->lx.debug_off, exe->lx.debug_off + sizeof(*exe->debug_header)); 52 | mvwprintw(l->tree, row++, 16, "WATCOM debug"); 53 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->lx.debug_off + exe->debug_header->e_shoff, exe->lx.debug_off + exe->debug_header->e_shoff + (exe->debug_header->e_shentsize * exe->debug_header->e_shnum)); 54 | mvwprintw(l->tree, row++, 16, " section headers"); 55 | for (int i=0; i < exe->debug_header->e_shnum; i++) { 56 | char *strtab = (char*)exe->debug_data[exe->debug_header->e_shstrndx]; 57 | if (exe->debug_sections[i].sh_type == 0) { 58 | continue; 59 | } 60 | mvwprintw(l->tree, row, 0, "%6x - %6x", exe->lx.debug_off + exe->debug_sections[i].sh_offset, exe->lx.debug_off + exe->debug_sections[i].sh_offset + exe->debug_sections[i].sh_size); 61 | mvwprintw(l->tree, row++, 16, " %s", strtab + exe->debug_sections[i].sh_name); 62 | } 63 | } 64 | if (exe->stat != NULL) { 65 | mvwprintw(l->tree, row, 0, " %6x", exe->stat->st_size); 66 | mvwprintw(l->tree, row++, 16, "EOF"); 67 | } 68 | 69 | int col2 = l->screen_width / 4 * 2 - 6; 70 | row = 0; 71 | mvwprintw(l->tree, row++, col2, "signature: %c%c", exe->lx.signature & 0xff, (exe->lx.signature >> 8) & 0xff); 72 | mvwprintw(l->tree, row++, col2, "order (b/w): %02x/%02x", exe->lx.byte_order, exe->lx.word_order); 73 | mvwprintw(l->tree, row++, col2, "level: %08x", exe->lx.level); 74 | mvwprintw(l->tree, row++, col2, "cpu/os: %x/%x", exe->lx.cpu_type, exe->lx.os_type); 75 | mvwprintw(l->tree, row++, col2, "version: %08x", exe->lx.version); 76 | mvwprintw(l->tree, row++, col2, "flags: %08x", exe->lx.flags); 77 | mvwprintw(l->tree, row++, col2, "num_objects: %x (%d)", exe->lx.num_objects, exe->lx.num_objects); 78 | mvwprintw(l->tree, row++, col2, "eip: %x:%08x", exe->lx.start_obj, exe->lx.eip); 79 | mvwprintw(l->tree, row++, col2, "esp: %x:%08x", exe->lx.stack_obj, exe->lx.esp); 80 | mvwprintw(l->tree, row++, col2, "autodataobj: %x", exe->lx.autodata_obj); 81 | mvwprintw(l->tree, row++, col2, "num_pages: %x (%d)", exe->lx.num_pages, exe->lx.num_pages); 82 | mvwprintw(l->tree, row++, col2, "page_size: %x (%d)", exe->lx.page_size, exe->lx.page_size); 83 | mvwprintw(l->tree, row++, col2, "page_shift: %d", exe->lx.l.page_shift); 84 | mvwprintw(l->tree, row++, col2, "debug_len: %x", exe->lx.debug_len); 85 | mvwprintw(l->tree, row++, col2, "num_rsrcs: %x (%d)", exe->lx.num_rsrcs, exe->lx.num_rsrcs); 86 | mvwprintw(l->tree, row++, col2, "num_moddirs: %x (%d)", exe->lx.num_moddirs, exe->lx.num_moddirs); 87 | mvwprintw(l->tree, row++, col2, "num_impmods: %x (%d)", exe->lx.num_impmods, exe->lx.num_impmods); 88 | mvwprintw(l->tree, row++, col2, "num_preload: %x (%d)", exe->lx.num_preload, exe->lx.num_preload); 89 | mvwprintw(l->tree, row++, col2, "nonres_size: %x (%d)", exe->lx.nonres_size, exe->lx.nonres_size); 90 | mvwprintw(l->tree, row++, col2, "inst_preloa: %x (%d)", exe->lx.num_inst_preload, exe->lx.num_inst_preload); 91 | mvwprintw(l->tree, row++, col2, "inst_demand: %x (%d)", exe->lx.num_inst_demand, exe->lx.num_inst_demand); 92 | mvwprintw(l->tree, row++, col2, "heapsize: %x", exe->lx.heapsize); 93 | mvwprintw(l->tree, row++, col2, "stacksize: %x", exe->lx.stacksize); 94 | 95 | int col3 = l->screen_width / 4 * 3; 96 | row = 0; 97 | mvwprintw(l->tree, row++, col3, "magic: %c%c", exe->mz.e_magic & 0xff, (exe->mz.e_magic >> 8) & 0xff); 98 | mvwprintw(l->tree, row++, col3, "cplp: %04x", exe->mz.e_cblp); 99 | mvwprintw(l->tree, row++, col3, "cp: %04x", exe->mz.e_cp); 100 | mvwprintw(l->tree, row++, col3, "crlc: %04x", exe->mz.e_crlc); 101 | mvwprintw(l->tree, row++, col3, "cparhdr: %04x (%x)", exe->mz.e_cparhdr, exe->mz.e_cparhdr*16); 102 | mvwprintw(l->tree, row++, col3, "minalloc: %04x", exe->mz.e_minalloc); 103 | mvwprintw(l->tree, row++, col3, "maxalloc: %04x", exe->mz.e_maxalloc); 104 | mvwprintw(l->tree, row++, col3, "ss:sp %04x:%04x", exe->mz.e_ss, exe->mz.e_sp); 105 | mvwprintw(l->tree, row++, col3, "csum: %04x", exe->mz.e_csum); 106 | mvwprintw(l->tree, row++, col3, "cs:ip %04x:%04x", exe->mz.e_cs, exe->mz.e_ip); 107 | mvwprintw(l->tree, row++, col3, "lfarlc: %04x", exe->mz.e_lfarlc); 108 | mvwprintw(l->tree, row++, col3, "ovno: %04x", exe->mz.e_ovno); 109 | mvwprintw(l->tree, row++, col3, "res: %04x%04x", exe->mz.e_res[0], exe->mz.e_res[1]); 110 | mvwprintw(l->tree, row++, col3, " %04x%04x", exe->mz.e_res[2], exe->mz.e_res[3]); 111 | mvwprintw(l->tree, row++, col3, "oemid: %04x", exe->mz.e_oemid); 112 | mvwprintw(l->tree, row++, col3, "oeminfo: %04x", exe->mz.e_oeminfo); 113 | mvwprintw(l->tree, row++, col3, "res2: %04x%04x", exe->mz.e_res2[0], exe->mz.e_res2[1]); 114 | mvwprintw(l->tree, row++, col3, " %04x%04x", exe->mz.e_res2[2], exe->mz.e_res2[3]); 115 | mvwprintw(l->tree, row++, col3, " %04x%04x", exe->mz.e_res2[4], exe->mz.e_res2[5]); 116 | mvwprintw(l->tree, row++, col3, " %04x%04x", exe->mz.e_res2[6], exe->mz.e_res2[7]); 117 | mvwprintw(l->tree, row++, col3, " %04x%04x", exe->mz.e_res2[8], exe->mz.e_res2[9]); 118 | mvwprintw(l->tree, row++, col3, "lfanew: %08x", exe->mz.e_lfanew); 119 | wrefresh(l->tree); 120 | } 121 | 122 | void *info_input(int ch) { 123 | switch(ch) { 124 | case KEY_LEFT: 125 | case 'q': 126 | wclear(lx->layout->tree); 127 | return objects_window; 128 | } 129 | return NULL; 130 | } 131 | 132 | lxedit_window *info_window_create() { 133 | static lxedit_window win; 134 | win.input = &info_input; 135 | win.refresh = &info_refresh; 136 | return &win; 137 | } 138 | -------------------------------------------------------------------------------- /lxlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "lx.h" 5 | 6 | void lx_read(exe *e, uint16_t object, uint32_t offset, unsigned char *buf, int length) { 7 | long page_idx = (e->object_records[object-1].mapidx-1) + (offset / e->lx.page_size); 8 | long page_off = offset % e->lx.page_size; 9 | memcpy(buf, e->pages[page_idx] + page_off, length); 10 | return; 11 | } 12 | 13 | int lx_fixup_write(char *begin, lx_fixup *f) { 14 | char *start = begin; 15 | *begin = f->type; 16 | begin++; 17 | *begin = f->flags; 18 | begin++; 19 | if (f->type & OSF_SFLAG_LIST) { 20 | *begin = f->src_off & 0xff; 21 | begin++; 22 | } else { 23 | *(short *)begin = f->src_off; 24 | begin += 2; 25 | } 26 | if (f->flags & OSF_TFLAG_OBJ_MOD_16BIT) { 27 | *(short *)begin = f->object; 28 | begin += 2; 29 | } else { 30 | *begin = f->object & 0xff; 31 | begin++; 32 | } 33 | if ((f->flags & OSF_TARGET_MASK) == OSF_TARGET_INTERNAL) { 34 | if ((f->type & OSF_SOURCE_MASK) == OSF_SOURCE_SEG) { 35 | // no target 36 | } else if (f->flags & OSF_TFLAG_OFF_32BIT) { 37 | *(int *)begin = f->target_off; 38 | begin += 4; 39 | } else { 40 | *(short *)begin = f->target_off & 0xffff; 41 | begin += 2; 42 | } 43 | } 44 | // TODO external fixups 45 | // TODO source list 46 | return begin - start; 47 | } 48 | 49 | int lx_fixup_parse(char *begin, lx_fixup *f) { 50 | static lx_fixup tmp; 51 | char *start = begin; 52 | if (f == NULL) { 53 | f = &tmp; 54 | } 55 | f->type = *begin++; 56 | f->flags = *begin++; 57 | if (f->type & OSF_SFLAG_LIST) { 58 | f->src_off = *begin++; 59 | } else { 60 | f->src_off = *(short *)begin; 61 | begin += 2; 62 | } 63 | if (f->flags & OSF_TFLAG_OBJ_MOD_16BIT) { 64 | f->object = *(short *)begin; 65 | begin += 2; 66 | } else { 67 | f->object = *begin++; 68 | } 69 | if ((f->flags & OSF_TARGET_MASK) == OSF_TARGET_INTERNAL) { 70 | if ((f->type & OSF_SOURCE_MASK) == OSF_SOURCE_SEG) { 71 | // no target 72 | } else if (f->flags & OSF_TFLAG_OFF_32BIT) { 73 | f->target_off = *(int *)begin; 74 | begin += 4; 75 | } else { 76 | f->target_off = *(short *)begin; 77 | begin += 2; 78 | } 79 | } else if ((f->flags & OSF_TARGET_MASK) == OSF_TARGET_EXT_ORD) { 80 | if (f->flags & OSF_TFLAG_OBJ_MOD_16BIT) { 81 | f->mod_ord = *(short *)begin; 82 | begin += 2; 83 | } else { 84 | f->mod_ord = *begin++; 85 | } 86 | if (f->flags & OSF_TFLAG_ORDINAL_8BIT) { 87 | f->imp_ord = *begin++; 88 | } else if (f->flags & OSF_TFLAG_OFF_32BIT) { 89 | f->imp_ord = *(int*)begin; 90 | begin += 4; 91 | } else { 92 | f->imp_ord = *(short*)begin; 93 | begin += 2; 94 | } 95 | if (f->flags & OSF_TFLAG_ADDITIVE_VAL) { 96 | f->additive = *(int*)begin; 97 | begin += 4; 98 | } 99 | } else if ((f->flags & OSF_TARGET_MASK) == OSF_TARGET_EXT_NAME) { 100 | if (f->flags & OSF_TFLAG_OBJ_MOD_16BIT) { 101 | f->mod_ord = *(short *)begin; 102 | begin += 2; 103 | } else { 104 | f->mod_ord = *begin++; 105 | } 106 | if (f->flags & OSF_TFLAG_OFF_32BIT) { 107 | f->name_off = *(int*)begin; 108 | begin += 4; 109 | } else { 110 | f->name_off = *(short*)begin; 111 | begin += 2; 112 | 113 | } 114 | if (f->flags & OSF_TFLAG_ADDITIVE_VAL) { 115 | f->additive = *(int*)begin; 116 | begin += 4; 117 | } 118 | } else { 119 | if (f->flags & OSF_TFLAG_OBJ_MOD_16BIT) { 120 | f->mod_ord = *(short *)begin; 121 | begin += 2; 122 | } else { 123 | f->mod_ord = *begin++; 124 | } 125 | if (f->flags & OSF_TFLAG_ADDITIVE_VAL) { 126 | f->additive = *(int*)begin; 127 | begin += 4; 128 | } 129 | } 130 | if (f->type & OSF_SFLAG_LIST) { 131 | begin += 2*f->src_off; 132 | } 133 | return begin - start; 134 | } 135 | 136 | int lx_fixup_length(char *begin) { 137 | return lx_fixup_parse(begin, NULL); 138 | } 139 | 140 | exe *lx_load(char *name) { 141 | exe *e = (exe *)malloc(sizeof(exe)); 142 | memset(e, 0, sizeof(exe)); 143 | char *cwd = getcwd(NULL, 0); 144 | char *filename = (char*)malloc(strlen(cwd) + strlen(name) + 2); 145 | sprintf(filename, "%s\\%s", cwd, name); 146 | e->name = filename; 147 | FILE *file = fopen(filename, "rb"); 148 | if (file == NULL) { 149 | return NULL; 150 | } 151 | 152 | // Stat file 153 | e->stat = (struct stat*)malloc(sizeof(*e->stat)); 154 | stat(filename, e->stat); 155 | 156 | // Read MZ header 157 | int r = fread(&e->mz, sizeof(e->mz), 1, file); 158 | if (r != 1) { 159 | return NULL; 160 | } 161 | if (e->mz.e_magic != 0x5a4d) { 162 | curs_set(1); 163 | return NULL; 164 | } 165 | 166 | // Read MZ relocations and code 167 | int code_size = e->mz.e_lfanew - sizeof(e->mz); 168 | if (code_size <= 0) { 169 | return NULL; 170 | } 171 | e->mz_code = (uint8_t*)malloc(code_size); 172 | r = fread(e->mz_code, code_size, 1, file); 173 | if (r != 1) { 174 | return NULL; 175 | } 176 | 177 | // Read LX header 178 | r = fread(&e->lx, sizeof(e->lx), 1, file); 179 | if (r != 1) { 180 | return NULL; 181 | } 182 | 183 | // Read object records 184 | e->object_records = (object_record *)malloc(e->lx.num_objects * sizeof(object_record)); 185 | fseek(file, e->mz.e_lfanew + e->lx.objtab_off, SEEK_SET); 186 | fread(e->object_records, sizeof(object_record), e->lx.num_objects, file); 187 | 188 | // Read object page map 189 | e->object_map = (map_entry *)malloc(e->lx.num_pages * sizeof(map_entry)); 190 | fseek(file, e->mz.e_lfanew + e->lx.objmap_off, SEEK_SET); 191 | for (int i = 0; i < e->lx.num_pages; i++) { 192 | if (e->lx.signature == OSF_FLAT_SIGNATURE) { 193 | // LE 194 | fread(e->object_map + i, sizeof(le_map_entry), 1, file); 195 | } else { 196 | // LX 197 | fread(e->object_map + i, sizeof(lx_map_entry), 1, file); 198 | } 199 | } 200 | 201 | // Read name table 202 | long pos = e->lx.resname_off; 203 | lx_name *head = NULL; 204 | while (pos < e->lx.entry_off) { 205 | uint8_t l = 0; 206 | fread(&l, 1, 1, file); 207 | if (l > 0) { 208 | lx_name *n = (lx_name *)malloc(sizeof(lx_name)); 209 | n->length = l; 210 | n->name = (char *)malloc(l+1); 211 | fread(n->name, l, 1, file); 212 | n->name[l] = 0; 213 | fread(&n->ordinal, sizeof(n->ordinal), 1, file); 214 | if (head) { 215 | n->next = head; 216 | n->prev = head->prev; 217 | head->prev->next = n; 218 | head->prev = n; 219 | } else { 220 | head = n; 221 | head->prev = n; 222 | head->next = n; 223 | } 224 | pos += sizeof(uint8_t) + l + sizeof(uint16_t); 225 | } else { 226 | pos++; 227 | break; 228 | } 229 | } 230 | e->names = head; 231 | // Read entry table 232 | 233 | // Read fixup page table 234 | e->fixup_map = (uint32_t *)malloc(sizeof(uint32_t)*(e->lx.num_pages+1)); 235 | fseek(file, e->mz.e_lfanew + e->lx.fixpage_off, SEEK_SET); 236 | fread(e->fixup_map, sizeof(uint32_t), e->lx.num_pages+1, file); 237 | 238 | // Read fixup records 239 | e->fixup_count = (int*)malloc(sizeof(int) * e->lx.num_pages); 240 | e->fixups = (lx_fixup ***)malloc(sizeof(void*) * e->lx.num_pages); 241 | char *fixup_data = (char*)malloc(e->lx.fixup_size); 242 | fseek(file, e->mz.e_lfanew + e->lx.fixrec_off, SEEK_SET); 243 | fread(fixup_data, e->lx.fixup_size - sizeof(int)*(e->lx.num_pages+1), 1, file); 244 | for (int i = 0; i < e->lx.num_pages; i++) { 245 | // Read fixups for page 246 | char *begin = fixup_data + e->fixup_map[i]; 247 | char *end = fixup_data + e->fixup_map[i+1]; 248 | e->fixup_count[i] = 0; 249 | while (begin < end) { 250 | begin += lx_fixup_length(begin); 251 | e->fixup_count[i]++; 252 | } 253 | e->fixups[i] = (lx_fixup**)malloc(e->fixup_count[i] * sizeof(lx_fixup*)); 254 | begin = fixup_data + e->fixup_map[i]; 255 | int j = 0; 256 | while (begin < end) { 257 | lx_fixup *f = (lx_fixup*)malloc(sizeof(lx_fixup)); 258 | memset(f, 0, sizeof(lx_fixup)); 259 | begin += lx_fixup_parse(begin, f); 260 | e->fixups[i][j++] = f; 261 | } 262 | } 263 | 264 | // Read pages 265 | e->pages = (uint8_t **)malloc(sizeof(uint8_t *) * e->lx.num_pages); 266 | for (int i=0; i < e->lx.num_pages; i++) { 267 | // TODO support LX 268 | int size = e->lx.page_size; 269 | if (i == e->lx.num_pages - 1) { 270 | size = e->lx.l.last_page; 271 | } 272 | e->pages[i] = (uint8_t*)malloc(size); 273 | fseek(file, e->lx.page_off + i*e->lx.page_size, SEEK_SET); 274 | fread(e->pages[i], size, 1, file); 275 | } 276 | 277 | // Read watcom debug 278 | if (e->lx.debug_off && e->lx.debug_len) { 279 | fseek(file, e->lx.debug_off, SEEK_SET); 280 | e->debug_header = (Elf32_Ehdr *)malloc(sizeof(Elf32_Ehdr)); 281 | fread(e->debug_header, sizeof(Elf32_Ehdr), 1, file); 282 | // TODO validate Elf 283 | fseek(file, e->lx.debug_off + e->debug_header->e_shoff, SEEK_SET); 284 | e->debug_sections = (Elf32_Shdr*)malloc(e->debug_header->e_shnum * sizeof(Elf32_Shdr)); 285 | fread(e->debug_sections, sizeof(Elf32_Shdr), e->debug_header->e_shnum, file); 286 | e->debug_data = (uint8_t**)malloc(sizeof(uint8_t*)*e->debug_header->e_shnum); 287 | for (int i=0; i < e->debug_header->e_shnum; i++) { 288 | Elf32_Shdr *s = &e->debug_sections[i]; 289 | e->debug_data[i] = (uint8_t*)malloc(s->sh_size); 290 | fseek(file, e->lx.debug_off + s->sh_offset, SEEK_SET); 291 | fread(e->debug_data[i], s->sh_size, 1, file); 292 | } 293 | } 294 | return e; 295 | } 296 | 297 | void lx_save(exe *e) { 298 | FILE *file = fopen(e->name, "wb"); 299 | // Write MZ header 300 | fwrite(&e->mz, sizeof(e->mz), 1, file); 301 | // Write MZ code 302 | fwrite(e->mz_code, e->mz.e_lfanew - sizeof(e->mz), 1, file); 303 | // Write LX header 304 | fwrite(&e->lx, sizeof(e->lx), 1, file); 305 | // Write object map 306 | fwrite(e->object_records, sizeof(object_record), e->lx.num_objects, file); 307 | // Write page map 308 | for (int i=0; i < e->lx.num_pages; i++) { 309 | fwrite(e->object_map + i, sizeof(le_map_entry), 1, file); 310 | } 311 | // Write name table 312 | // Write entry table 313 | lx_name *n = e->names; 314 | do { 315 | fwrite(&n->length, sizeof(uint8_t), 1, file); 316 | fwrite(n->name, n->length, 1, file); 317 | fwrite(&n->ordinal, sizeof(uint16_t), 1, file); 318 | n = n->next; 319 | } while (n != e->names); 320 | uint8_t end = 0; 321 | // End of name table 322 | fwrite(&end, sizeof(end), 1, file); 323 | // End of entry table (empty) 324 | fwrite(&end, sizeof(end), 1, file); 325 | 326 | // Write fixup map 327 | fwrite(e->fixup_map, sizeof(uint32_t), e->lx.num_pages + 1, file); 328 | 329 | // Write fixup records 330 | char *buf = (char *)malloc(e->lx.fixup_size); 331 | char *begin = buf; 332 | for (int i=0; i < e->lx.num_pages; i++) { 333 | for (int j=0; j < e->fixup_count[i]; j++) { 334 | begin += lx_fixup_write(begin, e->fixups[i][j]); 335 | } 336 | } 337 | fwrite(buf, begin - buf, 1, file); 338 | 339 | // import table 340 | fwrite(&end, sizeof(end), 1, file); 341 | 342 | // Write pages 343 | fseek(file, e->lx.page_off, SEEK_SET); 344 | for (int i=0; i < e->lx.num_pages-1; i++) { 345 | fwrite(e->pages[i], e->lx.page_size, 1, file); 346 | } 347 | fwrite(e->pages[e->lx.num_pages-1], e->lx.l.last_page, 1, file); 348 | 349 | fclose(file); 350 | } 351 | 352 | exe *lx_merge(exe *to, exe *from, bool use_entry) { 353 | exe *n; 354 | n = (exe *)malloc(sizeof(exe)); 355 | n->stat = NULL; 356 | // Set new name 357 | char *cwd = getcwd(NULL, 0); 358 | char *shortname = to->name + strlen(to->name) - 1; 359 | while (*shortname && *shortname != '\\') { 360 | shortname--; 361 | } 362 | n->name = (char*)malloc(strlen(cwd) + strlen(shortname) + 10); 363 | sprintf(n->name, "%s%s", cwd, shortname); 364 | 365 | // Copy MZ and LE headers from first exe 366 | memcpy(&n->mz, &to->mz, sizeof(n->mz)); 367 | memcpy(&n->lx, &to->lx, sizeof(n->lx)); 368 | n->mz_code = to->mz_code; 369 | 370 | // Copy Objects 371 | n->object_records = (object_record *)malloc(sizeof(object_record) * (to->lx.num_objects + from->lx.num_objects)); 372 | n->lx.num_objects = to->lx.num_objects + from->lx.num_objects; 373 | int object_shift = to->lx.num_objects; 374 | if (use_entry) { 375 | n->lx.start_obj = from->lx.start_obj + object_shift; 376 | //n->lx.stack_obj = from->lx.stack_obj + object_shift; 377 | //n->lx.autodata_obj = from->lx.autodata_obj + object_shift; 378 | n->lx.eip = from->lx.eip; 379 | //n->lx.esp = from->lx.esp; 380 | } 381 | // Copy objects from first exe 382 | memcpy(n->object_records, to->object_records, sizeof(object_record) * to->lx.num_objects); 383 | // Copy objects from second exe 384 | memcpy(n->object_records + to->lx.num_objects, from->object_records, sizeof(object_record) *from->lx.num_objects); 385 | uint32_t vbase_shift = to->object_records[to->lx.num_objects-1].addr + to->object_records[to->lx.num_objects-1].size; 386 | vbase_shift = (vbase_shift / from->object_records[0].addr) * from->object_records[0].addr; 387 | // Shift pages in second exe objects 388 | int page_shift = to->lx.num_pages; 389 | for (int i=0; i < from->lx.num_objects; i++) { 390 | n->object_records[to->lx.num_objects + i].addr += vbase_shift; 391 | n->object_records[to->lx.num_objects + i].mapidx += page_shift; 392 | } 393 | 394 | // Pages 395 | n->lx.num_pages = to->lx.num_pages + from->lx.num_pages; 396 | n->lx.l.last_page = from->lx.l.last_page; 397 | // Shift LX by added object records 398 | int lx_shift = from->lx.num_objects * sizeof(object_record); 399 | 400 | // Copy page table (object map) 401 | n->lx.objmap_off += lx_shift; 402 | n->object_map = (map_entry *)malloc(n->lx.num_pages * sizeof(map_entry)); 403 | for (int i=0; i < to->lx.num_pages; i++) { 404 | memcpy(n->object_map + i, to->object_map + i, sizeof(map_entry)); 405 | } 406 | for (int i=0; i < from->lx.num_pages; i++) { 407 | memcpy(n->object_map + i + page_shift, from->object_map + i, sizeof(map_entry)); 408 | map_entry *e = n->object_map + i + page_shift; 409 | le_map_entry *le = (le_map_entry *)e; 410 | int page_num = le->page_num[2] + (le->page_num[1] << 8) + (le->page_num[0] << 16); 411 | page_num += page_shift; 412 | le->page_num[2] = page_num & 0xff; 413 | le->page_num[1] = (page_num & 0xff00) >> 8; 414 | le->page_num[0] = (page_num & 0xff0000) >> 16; 415 | } 416 | // Shift LX by added page records 417 | lx_shift += from->lx.num_pages * sizeof(le_map_entry); 418 | 419 | n->lx.resname_off += lx_shift; 420 | n->names = to->names; 421 | // TODO: merge entries 422 | n->lx.entry_off += lx_shift; 423 | n->lx.fixpage_off += lx_shift; 424 | 425 | // Copy fixup page table 426 | n->fixup_map = (uint32_t *)malloc(sizeof(uint32_t) * (n->lx.num_pages+1)); 427 | memcpy(n->fixup_map, to->fixup_map, sizeof(uint32_t) * (to->lx.num_pages + 1)); 428 | memcpy(n->fixup_map + page_shift + 1, from->fixup_map + 1, sizeof(uint32_t) * from->lx.num_pages); 429 | for (int i=1; i < from->lx.num_pages + 1; i++) { 430 | uint32_t old_off = from->fixup_map[i] - from->fixup_map[0]; 431 | n->fixup_map[page_shift + i] = old_off + n->fixup_map[page_shift]; 432 | } 433 | n->fixup_count = (int *)malloc(sizeof(int) * n->lx.num_pages); 434 | memcpy(n->fixup_count, to->fixup_count, to->lx.num_pages * sizeof(int)); 435 | memcpy(n->fixup_count + page_shift, from->fixup_count, from->lx.num_pages * sizeof(int)); 436 | // Shift LX by added fixup table 437 | lx_shift += from->lx.num_pages * sizeof(uint32_t); 438 | n->lx.fixup_size += from->lx.num_pages * sizeof(uint32_t); 439 | n->lx.fixrec_off += lx_shift; 440 | 441 | // Copy (parsed) fixup records 442 | n->fixups = (lx_fixup ***)malloc(sizeof(lx_fixup **) * n->lx.num_pages); 443 | for (int i=0; i < to->lx.num_pages; i++) { 444 | n->fixups[i] = (lx_fixup **)malloc(sizeof(lx_fixup *) * to->fixup_count[i]); 445 | memcpy(n->fixups[i], to->fixups[i], sizeof(lx_fixup *) * to->fixup_count[i]); 446 | } 447 | for (int i=0; i < from->lx.num_pages; i++) { 448 | n->fixups[page_shift + i] = (lx_fixup **)malloc(sizeof(lx_fixup *) * from->fixup_count[i]); 449 | memcpy(n->fixups[page_shift + i], from->fixups[i], sizeof(lx_fixup *) * from->fixup_count[i]); 450 | for (int j=0; j < from->fixup_count[i]; j++) { 451 | lx_fixup *f= n->fixups[page_shift + i][j]; 452 | // Shift fixup object numbers 453 | if (f->object > 0) { 454 | f->object += object_shift; 455 | } 456 | if (f->mod_ord > 0) { 457 | f->mod_ord += object_shift; 458 | } 459 | if (f->imp_ord > 0) { 460 | f->imp_ord += object_shift; 461 | } 462 | } 463 | } 464 | 465 | // Shift LX by added fixup records 466 | lx_shift += from->lx.impmod_off - from->lx.fixrec_off; 467 | n->lx.fixup_size += from->lx.impmod_off - from->lx.fixrec_off; 468 | n->lx.impmod_off += lx_shift; 469 | n->lx.impproc_off += lx_shift; 470 | n->lx.page_off += lx_shift; 471 | 472 | // Copy pages 473 | n->pages = (uint8_t **)malloc(sizeof(uint8_t*) * n->lx.num_pages); 474 | memcpy(n->pages, to->pages, sizeof(uint8_t*) * (to->lx.num_pages-1)); 475 | uint8_t *page = (uint8_t*)malloc(n->lx.page_size); 476 | memset(page, 0, n->lx.page_size); 477 | memcpy(page, to->pages[to->lx.num_pages-1], to->lx.l.last_page); 478 | n->pages[to->lx.num_pages-1] = page; 479 | memcpy(n->pages + page_shift, from->pages, sizeof(uint8_t*) * from->lx.num_pages); 480 | 481 | return n; 482 | } 483 | 484 | -------------------------------------------------------------------------------- /lx.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __LX_H 3 | #define __LX_H 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define TITLE "lxedit - https://github.com/yetmorecode/lxedit" 10 | #define COLOR_HEADER 1 11 | #define COLOR_STATUS 2 12 | #define COLOR_TREE 3 13 | #define COLOR_TREE_HEADER 4 14 | #define INDENT 1 15 | 16 | typedef unsigned short USHORT; 17 | typedef long LONG; 18 | 19 | typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header 20 | USHORT e_magic; // Magic number 21 | USHORT e_cblp; // Bytes on last page of file 22 | USHORT e_cp; // Pages in file 23 | USHORT e_crlc; // Relocations 24 | USHORT e_cparhdr; // Size of header in paragraphs 25 | USHORT e_minalloc; // Minimum extra paragraphs needed 26 | USHORT e_maxalloc; // Maximum extra paragraphs needed 27 | USHORT e_ss; // Initial (relative) SS value 28 | USHORT e_sp; // Initial SP value 29 | USHORT e_csum; // Checksum 30 | USHORT e_ip; // Initial IP value 31 | USHORT e_cs; // Initial (relative) CS value 32 | USHORT e_lfarlc; // File address of relocation table 33 | USHORT e_ovno; // Overlay number 34 | USHORT e_res[4]; 35 | USHORT e_oemid; // OEM identifier (for e_oeminfo) 36 | USHORT e_oeminfo; // OEM information; e_oemid specific 37 | USHORT e_res2[10]; 38 | LONG e_lfanew; // File address of new exe header 39 | } IMAGE_DOS_HEADER; 40 | 41 | 42 | #define OSF_FLAT_RESERVED 20 43 | 44 | typedef unsigned char unsigned_8; 45 | typedef unsigned short unsigned_16; 46 | typedef unsigned int unsigned_32; 47 | 48 | typedef struct os2_flat_header { 49 | unsigned_16 signature; 50 | unsigned_8 byte_order; /* the byte ordering of the .exe */ 51 | unsigned_8 word_order; /* the word ordering of the .exe */ 52 | unsigned_32 level; /* the exe format level */ 53 | unsigned_16 cpu_type; /* the cpu type */ 54 | unsigned_16 os_type; /* the operating system type */ 55 | unsigned_32 version; /* .exe version */ 56 | unsigned_32 flags; /* .exe flags */ 57 | unsigned_32 num_pages; /* # of pages in .exe */ 58 | unsigned_32 start_obj; /* starting object number */ 59 | unsigned_32 eip; /* starting value of eip */ 60 | unsigned_32 stack_obj; /* object # for stack pointer */ 61 | unsigned_32 esp; /* starting value of esp */ 62 | unsigned_32 page_size; /* .exe page size */ 63 | union { 64 | unsigned_32 last_page; /* size of last page - LE */ 65 | unsigned_32 page_shift; /* left shift for page offsets - LX */ 66 | } l; 67 | unsigned_32 fixup_size; /* fixup section size */ 68 | unsigned_32 fixup_cksum; /* fixup section checksum */ 69 | unsigned_32 loader_size; /* loader section size */ 70 | unsigned_32 loader_cksum; /* loader section checksum */ 71 | unsigned_32 objtab_off; /* object table offset */ 72 | unsigned_32 num_objects; /* number of objects in .exe */ 73 | unsigned_32 objmap_off; /* object page map offset */ 74 | unsigned_32 idmap_off; /* iterated data map offset */ 75 | unsigned_32 rsrc_off; /* offset of resource table */ 76 | unsigned_32 num_rsrcs; /* number of resource entries */ 77 | unsigned_32 resname_off; /* offset of resident names table */ 78 | unsigned_32 entry_off; /* offset of entry table */ 79 | unsigned_32 moddir_off; /* offset of module directives table */ 80 | unsigned_32 num_moddirs; /* number of module directives */ 81 | unsigned_32 fixpage_off; /* offset of fixup page table */ 82 | unsigned_32 fixrec_off; /* offset of fixup record table */ 83 | unsigned_32 impmod_off; /* offset of import module name table */ 84 | unsigned_32 num_impmods; /* # of entries in import mod name tbl */ 85 | unsigned_32 impproc_off; /* offset of import procedure name table */ 86 | unsigned_32 cksum_off; /* offset of per-page checksum table */ 87 | unsigned_32 page_off; /* offset of enumerated data pages */ 88 | unsigned_32 num_preload; /* number of preload pages */ 89 | unsigned_32 nonres_off; /* offset of non-resident names table */ 90 | unsigned_32 nonres_size; /* size of non-resident names table */ 91 | unsigned_32 nonres_cksum; /* non-resident name table checksum */ 92 | unsigned_32 autodata_obj; /* object # of autodata segment */ 93 | unsigned_32 debug_off; /* offset of the debugging information */ 94 | unsigned_32 debug_len; /* length of the debugging info */ 95 | unsigned_32 num_inst_preload; /* # of instance pages in preload sect*/ 96 | unsigned_32 num_inst_demand; /*# instance pages in demand load sect*/ 97 | unsigned_32 heapsize; /* size of heap - for 16-bit apps */ 98 | unsigned_32 stacksize; /* size of stack OS/2 only */ 99 | union { /* pad to 196 bytes. */ 100 | unsigned_8 reserved[ OSF_FLAT_RESERVED ]; 101 | struct { 102 | unsigned_8 reserved1[ 8 ]; /* +0xB0 */ 103 | unsigned_32 winresoff; /* +0xB8 Windows VxD version info resource offset */ 104 | unsigned_32 winreslen; /* +0xBC Windows VxD version info resource lenght */ 105 | unsigned_16 device_ID; /* +0xC0 Windows VxD device ID */ 106 | unsigned_16 DDK_version; /* +0xC2 Windows VxD DDK version (0x030A) */ 107 | } vxd; 108 | } r; 109 | } os2_flat_header; 110 | 111 | #define OSF_DEF_PAGE_SIZE 4096 112 | #define OSF_FLAT_SIGNATURE 0x454C // 'LE' 113 | #define OSF_FLAT_LX_SIGNATURE 0x584C // 'LX' 114 | #define OSF_386_BYTE_ORDER 0 115 | #define OSF_386_WORD_ORDER 0 116 | #define OSF_EXE_LEVEL 0 117 | 118 | #define OSF_CPU_286 1 119 | #define OSF_CPU_386 2 120 | #define OSF_CPU_486 3 121 | 122 | #define OSF_OS_LEVEL 1 // OS/2 123 | #define OSF_WIN386_LEVEL 4 // Windows 386 (VxD) 124 | 125 | /****************************************************************************** 126 | * 127 | * The flags field low order word goes as follows: 128 | * 129 | * x x x x x x x x x x x x x x x x 130 | * | | | | | | | | | 131 | * | | | | | | | | +-> single data flag 132 | * | | | | | | | +-----> if DLL, per-process 133 | * | | | | | | | initialization 134 | * | | | | | | +--------------> no internal fixups. 135 | * | | | | | +----------------> no external fixups. 136 | * | | +-+-+---------------------------> PM compatibility flags 137 | * | +------------------------------------------> errors during link 138 | * | (not executable) 139 | * +----------------------------------------------> 1=DLL, 0=program file 140 | * 141 | * The flags field high order word goes as follows: 142 | * 143 | * x x x x x x x x x x x x x x x x 144 | * | | | 145 | * | | +-> prot. mem. lib. mod 146 | * | +---> device driver. 147 | * +--------------------------------------------> DLL per-proc termination 148 | *****************************************************************************/ 149 | 150 | #define OSF_SINGLE_DATA 0x0001 151 | #define OSF_INIT_INSTANCE 0x0004 152 | #define OSF_INTERNAL_FIXUPS_DONE 0x0010 153 | #define OSF_EXTERNAL_FIXUPS_DONE 0x0020 154 | #define OSF_NOT_PM_COMPATIBLE 0x0100 155 | #define OSF_PM_COMPATIBLE 0x0200 156 | #define OSF_PM_APP 0x0300 157 | #define OSF_LINK_ERROR 0x2000 158 | #define OSF_IS_DLL 0x8000 159 | #define OSF_IS_PROT_DLL 0x00010000UL 160 | #define OSF_DEVICE_DRIVER 0x00020000UL 161 | #define OSF_PHYS_DEVICE 0x00020000UL 162 | #define OSF_VIRT_DEVICE 0x00028000UL 163 | #define OSF_TERM_INSTANCE 0x40000000UL 164 | 165 | #define VXD_DEVICE_DRIVER_3x 0x00008020UL 166 | #define VXD_DEVICE_DRIVER_STATIC 0x00028000UL 167 | #define VXD_DEVICE_DRIVER_DYNAMIC 0x00038000UL 168 | 169 | typedef struct object_record { 170 | unsigned_32 size; /* object virtual size */ 171 | unsigned_32 addr; /* base virtual address */ 172 | unsigned_32 flags; 173 | unsigned_32 mapidx; /* page map index */ 174 | unsigned_32 mapsize; /* number of entries in page map */ 175 | unsigned_32 reserved; 176 | } object_record; 177 | 178 | /****************************************************************************** 179 | * 180 | * The flags field low order word is used as follows: 181 | * 182 | * x x x x x x x x x x x x x x x x 183 | * | | | | | | | | | | | | | | | 184 | * | | | | | | | | | | | | | | +-> readable object 185 | * | | | | | | | | | | | | | +---> writeable object 186 | * | | | | | | | | | | | | +-----> executable object 187 | * | | | | | | | | | | | +-------> resource object 188 | * | | | | | | | | | | +--------------> discardable object 189 | * | | | | | | | | | +----------------> sharable object 190 | * | | | | | | | | +------------------> object has preload pages 191 | * | | | | | | | +--------------------> object has invalid pages 192 | * | | | | | | +---------------------------> permanent and swappable 193 | * | | | | | +-----------------------------> permanent and resident 194 | * | | | | +-------------------------------> perm. and long lockable 195 | * | | | | 196 | * | | | +----------------------------------------> 16:16 alias required 197 | * | | +------------------------------------------> big/default bit setting 198 | * | +--------------------------------------------> conforming for code 199 | * +----------------------------------------------> object io privilege level 200 | * 201 | * The flags field high order word is used as follows: 202 | * 203 | * x x x x x x x x x x x x x x x x 204 | * 205 | *****************************************************************************/ 206 | 207 | #define OBJ_READABLE 0x0001 208 | #define OBJ_WRITEABLE 0x0002 209 | #define OBJ_EXECUTABLE 0x0004 210 | #define OBJ_RESOURCE 0x0008 211 | #define OBJ_DISCARDABLE 0x0010 212 | #define OBJ_SHARABLE 0x0020 213 | #define OBJ_HAS_PRELOAD 0x0040 214 | #define OBJ_HAS_INVALID 0x0080 215 | #define OBJ_PERM_SWAPPABLE 0x0100 /* LE */ 216 | #define OBJ_HAS_ZERO_FILL 0x0100 /* LX */ 217 | #define OBJ_PERM_RESIDENT 0x0200 218 | #define OBJ_PERM_CONTIGUOUS 0x0300 /* LX */ 219 | #define OBJ_PERM_LOCKABLE 0x0400 220 | #define OBJ_ALIAS_REQUIRED 0x1000 221 | #define OBJ_BIG 0x2000 222 | #define OBJ_CONFORMING 0x4000 223 | #define OBJ_IOPL 0x8000 224 | 225 | typedef struct le_map_entry { /* LE */ 226 | unsigned_8 page_num[3]; /* 24-bit page number in .exe file */ 227 | unsigned_8 flags; 228 | } le_map_entry; 229 | 230 | typedef struct lx_map_entry { /* LX */ 231 | unsigned_32 page_offset; /* offset from Preload page start 232 | shifted by page_shift in hdr */ 233 | unsigned_16 data_size; /* # bytes in this page */ 234 | unsigned_16 flags; 235 | } lx_map_entry; 236 | 237 | typedef union { 238 | le_map_entry le; 239 | lx_map_entry lx; 240 | } map_entry; 241 | 242 | #define PAGE_VALID 0 243 | #define PAGE_ITERATED 1 244 | #define PAGE_INVALID 2 245 | #define PAGE_ZEROED 3 246 | #define PAGE_RANGE 4 247 | 248 | 249 | typedef struct flat_bundle_prefix { 250 | unsigned_8 b32_cnt; 251 | unsigned_8 b32_type; 252 | unsigned_16 b32_obj; 253 | } flat_bundle_prefix; 254 | 255 | typedef struct flat_null_prefix { 256 | unsigned_8 b32_cnt; 257 | unsigned_8 b32_type; 258 | } flat_null_prefix; 259 | 260 | /* values for the b32_type field */ 261 | enum bundle_types { 262 | FLT_BNDL_EMPTY = 0, 263 | FLT_BNDL_ENTRY16, 264 | FLT_BNDL_GATE16, 265 | FLT_BNDL_ENTRY32, 266 | FLT_BNDL_ENTRYFWD 267 | }; 268 | 269 | typedef struct flat_bundle_entry32 { 270 | unsigned_8 e32_flags; /* flag bits are same as in OS/2 1.x */ 271 | unsigned_32 e32_offset; 272 | } flat_bundle_entry32; 273 | 274 | typedef struct flat_bundle_gate16 { 275 | unsigned_8 e32_flags; /* flag bits are same as in OS/2 1.x */ 276 | unsigned_16 offset; 277 | unsigned_16 callgate; 278 | } flat_bundle_gate16; 279 | 280 | /* 281 | * other, unused bundle types are: 282 | */ 283 | 284 | typedef struct flat_bundle_entry16 { 285 | unsigned_8 e32_flags; /* flag bits are same as in OS/2 1.x */ 286 | unsigned_16 e32_offset; 287 | } flat_bundle_entry16; 288 | 289 | typedef struct flat_bundle_entryfwd { 290 | unsigned_8 e32_flags; /* flag bits are same as in OS/2 1.x */ 291 | unsigned_16 modord; 292 | unsigned_32 value; 293 | } flat_bundle_entryfwd; 294 | 295 | typedef struct flat_res_table { 296 | unsigned_16 type_id; 297 | unsigned_16 name_id; 298 | unsigned_32 res_size; 299 | unsigned_16 object; 300 | unsigned_32 offset; 301 | } flat_res_table; 302 | 303 | /* fixup record source flags */ 304 | 305 | #define OSF_SOURCE_MASK 0x0F 306 | #define OSF_SOURCE_BYTE 0x00 307 | #define OSF_SOURCE_UNDEFINED1 0x01 308 | #define OSF_SOURCE_SEG 0x02 309 | #define OSF_SOURCE_PTR_32 0x03 310 | #define OSF_SOURCE_UNDEFINED4 0x04 311 | #define OSF_SOURCE_OFF_16 0x05 312 | #define OSF_SOURCE_PTR_48 0x06 313 | #define OSF_SOURCE_OFF_32 0x07 314 | #define OSF_SOURCE_OFF_32_REL 0x08 315 | 316 | #define OSF_SFLAG_FIXUP_TO_ALIAS 0x10 317 | #define OSF_SFLAG_LIST 0x20 318 | 319 | /* fixup record target flags */ 320 | 321 | #define OSF_TARGET_MASK 0x03 322 | #define OSF_TARGET_INTERNAL 0x00 323 | #define OSF_TARGET_EXT_ORD 0x01 324 | #define OSF_TARGET_EXT_NAME 0x02 325 | #define OSF_TARGET_INT_VIA_ENTRY 0x03 326 | 327 | #define OSF_TFLAG_ADDITIVE_VAL 0x04 328 | #define OSF_TFLAG_INT_CHAIN 0x08 329 | #define OSF_TFLAG_OFF_32BIT 0x10 330 | #define OSF_TFLAG_ADD_32BIT 0x20 331 | #define OSF_TFLAG_OBJ_MOD_16BIT 0x40 332 | #define OSF_TFLAG_ORDINAL_8BIT 0x80 333 | 334 | // ELF debugging info 335 | /* Type for a 16-bit quantity. */ 336 | typedef uint16_t Elf32_Half; 337 | typedef uint16_t Elf64_Half; 338 | /* Types for signed and unsigned 32-bit quantities. */ 339 | typedef uint32_t Elf32_Word; 340 | typedef int32_t Elf32_Sword; 341 | typedef uint32_t Elf64_Word; 342 | typedef int32_t Elf64_Sword; 343 | /* Types for signed and unsigned 64-bit quantities. */ 344 | typedef uint64_t Elf32_Xword; 345 | typedef int64_t Elf32_Sxword; 346 | typedef uint64_t Elf64_Xword; 347 | typedef int64_t Elf64_Sxword; 348 | /* Type of addresses. */ 349 | typedef uint32_t Elf32_Addr; 350 | typedef uint64_t Elf64_Addr; 351 | /* Type of file offsets. */ 352 | typedef uint32_t Elf32_Off; 353 | typedef uint64_t Elf64_Off; 354 | /* Type for section indices, which are 16-bit quantities. */ 355 | typedef uint16_t Elf32_Section; 356 | typedef uint16_t Elf64_Section; 357 | /* Type for version symbol information. */ 358 | typedef Elf32_Half Elf32_Versym; 359 | typedef Elf64_Half Elf64_Versym; 360 | /* The ELF file header. This appears at the start of every ELF file. */ 361 | #define EI_NIDENT (16) 362 | typedef struct 363 | { 364 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ 365 | Elf32_Half e_type; /* Object file type */ 366 | Elf32_Half e_machine; /* Architecture */ 367 | Elf32_Word e_version; /* Object file version */ 368 | Elf32_Addr e_entry; /* Entry point virtual address */ 369 | Elf32_Off e_phoff; /* Program header table file offset */ 370 | Elf32_Off e_shoff; /* Section header table file offset */ 371 | Elf32_Word e_flags; /* Processor-specific flags */ 372 | Elf32_Half e_ehsize; /* ELF header size in bytes */ 373 | Elf32_Half e_phentsize; /* Program header table entry size */ 374 | Elf32_Half e_phnum; /* Program header table entry count */ 375 | Elf32_Half e_shentsize; /* Section header table entry size */ 376 | Elf32_Half e_shnum; /* Section header table entry count */ 377 | Elf32_Half e_shstrndx; /* Section header string table index */ 378 | } Elf32_Ehdr; 379 | 380 | typedef struct 381 | { 382 | Elf32_Word sh_name; /* Section name (string tbl index) */ 383 | Elf32_Word sh_type; /* Section type */ 384 | Elf32_Word sh_flags; /* Section flags */ 385 | Elf32_Addr sh_addr; /* Section virtual addr at execution */ 386 | Elf32_Off sh_offset; /* Section file offset */ 387 | Elf32_Word sh_size; /* Section size in bytes */ 388 | Elf32_Word sh_link; /* Link to another section */ 389 | Elf32_Word sh_info; /* Additional section information */ 390 | Elf32_Word sh_addralign; /* Section alignment */ 391 | Elf32_Word sh_entsize; /* Entry size if section holds table */ 392 | } Elf32_Shdr; 393 | 394 | 395 | typedef struct { 396 | // source type 397 | unsigned char type; 398 | // target flags 399 | unsigned char flags; 400 | // source offset or source list count 401 | unsigned short src_off; 402 | // internal fixup target data 403 | unsigned short object; 404 | unsigned long target_off; 405 | // external fixup target data 406 | unsigned short mod_ord; 407 | unsigned short imp_ord; 408 | unsigned long name_off; 409 | unsigned long additive; 410 | // source list 411 | unsigned short *source_list; 412 | } lx_fixup; 413 | 414 | typedef struct lx_name lx_name; 415 | struct lx_name { 416 | lx_name *prev; 417 | lx_name *next; 418 | uint8_t length; 419 | char *name; 420 | uint16_t ordinal; 421 | }; 422 | 423 | typedef struct exe exe; 424 | struct exe { 425 | exe *prev; 426 | exe *next; 427 | char *name; 428 | struct stat *stat; 429 | IMAGE_DOS_HEADER mz; 430 | uint8_t *mz_code; 431 | os2_flat_header lx; 432 | object_record *object_records; 433 | map_entry *object_map; 434 | lx_name *names; 435 | uint32_t *fixup_map; 436 | // by page and fixup index 437 | lx_fixup ***fixups; 438 | // by page 439 | int *fixup_count; 440 | uint8_t **pages; 441 | 442 | Elf32_Ehdr *debug_header; 443 | Elf32_Shdr *debug_sections; 444 | uint8_t **debug_data; 445 | }; 446 | 447 | int lx_fixup_parse(char *, lx_fixup *); 448 | int lx_fixup_write(char *, lx_fixup *); 449 | int lx_fixup_length(char *); 450 | exe *lx_load(char *); 451 | exe *lx_merge(exe *, exe *, bool); 452 | void lx_save(exe *); 453 | void lx_read(exe *, uint16_t, uint32_t, unsigned char *, int); 454 | 455 | typedef struct { 456 | WINDOW *win; 457 | void *(*input)(int key); 458 | void (*refresh)(); 459 | } lxedit_window; 460 | 461 | typedef struct { 462 | int screen_width; 463 | int screen_height; 464 | WINDOW *header; 465 | WINDOW *tree; 466 | WINDOW *tree_head; 467 | WINDOW *status; 468 | int active_exe; 469 | int active_object; 470 | int show_object; 471 | int active_page; 472 | int scroll_page; 473 | lxedit_window *active_window; 474 | int active_fixup; 475 | int scroll_fixup; 476 | 477 | } lxedit_layout; 478 | 479 | typedef struct { 480 | lxedit_layout *layout; 481 | int num_executables; 482 | exe **executables; 483 | } lxedit; 484 | 485 | extern lxedit *lx; 486 | extern lxedit_window *objects_window; 487 | extern lxedit_window *pages_window; 488 | extern lxedit_window *fixups_window; 489 | extern lxedit_window *info_window; 490 | 491 | lxedit_window *objects_window_create(void); 492 | lxedit_window *pages_window_create(void); 493 | lxedit_window *fixups_window_create(void); 494 | lxedit_window *info_window_create(void); 495 | 496 | 497 | 498 | 499 | #endif // __LX_H 500 | --------------------------------------------------------------------------------