struct my_symtab {
unsigned int addr;
- unsigned int fpos; // for patching
+ //unsigned int fpos; // for patching
+ unsigned int is_text:1;
char *name;
};
+struct my_sect_info {
+ long scnhdr_fofs;
+ long sect_fofs;
+ long reloc_fofs;
+ uint8_t *data;
+ long size;
+ RELOC *relocs;
+ long reloc_cnt;
+};
+
static int symt_cmp(const void *p1_, const void *p2_)
{
const struct my_symtab *p1 = p1_, *p2 = p2_;
}
void parse_headers(FILE *f, unsigned int *base_out,
- long *sect_ofs, uint8_t **sect_data, long *sect_sz,
- RELOC **relocs, long *reloc_cnt,
- struct my_symtab **symtab_out, long *sym_cnt)
+ struct my_sect_info *sect_i,
+ struct my_symtab **symtab_out, long *sym_cnt,
+ struct my_symtab **raw_symtab_out, long *raw_sym_cnt)
{
- struct my_symtab *symt_o = NULL;
+ struct my_symtab *symt_txt = NULL;
+ struct my_symtab *symt_all = NULL;
char *stringtab = NULL;
unsigned int base = 0;
int text_scnum = 0;
my_assert(ret, sizeof(opthdr));
my_assert(opthdr.magic, COFF_ZMAGIC);
- printf("text_start: %x\n", opthdr.text_start);
+ //printf("text_start: %x\n", opthdr.text_start);
if (hdr.f_opthdr > sizeof(opthdr)) {
ret = fread(&base, 1, sizeof(base), f);
my_assert(ret, sizeof(base));
- printf("base: %x\n", base);
+ //printf("base: %x\n", base);
}
ret = fseek(f, opthdr_pos + hdr.f_opthdr, SEEK_SET);
my_assert(ret, 0);
// note: assuming first non-empty one is .text ..
for (s = 0; s < hdr.f_nscns; s++) {
+ sect_i->scnhdr_fofs = ftell(f);
+
ret = fread(&scnhdr, 1, sizeof(scnhdr), f);
my_assert(ret, sizeof(scnhdr));
break;
}
}
+ my_assert(s < hdr.f_nscns, 1);
+#if 0
printf("f_nsyms: %x\n", hdr.f_nsyms);
printf("s_name: '%s'\n", scnhdr.s_name);
printf("s_vaddr: %x\n", scnhdr.s_vaddr);
//printf("s_scnptr: %x\n", scnhdr.s_scnptr);
printf("s_nreloc: %x\n", scnhdr.s_nreloc);
printf("--\n");
+#endif
ret = fseek(f, scnhdr.s_scnptr, SEEK_SET);
my_assert(ret, 0);
- *sect_data = malloc(scnhdr.s_size);
- my_assert_not(*sect_data, NULL);
- ret = fread(*sect_data, 1, scnhdr.s_size, f);
+ sect_i->data = malloc(scnhdr.s_size);
+ my_assert_not(sect_i->data, NULL);
+ ret = fread(sect_i->data, 1, scnhdr.s_size, f);
my_assert(ret, scnhdr.s_size);
- *sect_ofs = scnhdr.s_scnptr;
- *sect_sz = scnhdr.s_size;
+ sect_i->sect_fofs = scnhdr.s_scnptr;
+ sect_i->size = scnhdr.s_size;
// relocs
ret = fseek(f, scnhdr.s_relptr, SEEK_SET);
my_assert(ret, 0);
- reloc_size = scnhdr.s_nreloc * sizeof((*relocs)[0]);
- *relocs = malloc(reloc_size + 1);
- my_assert_not(*relocs, NULL);
- ret = fread(*relocs, 1, reloc_size, f);
+ reloc_size = scnhdr.s_nreloc * sizeof(sect_i->relocs[0]);
+ sect_i->relocs = malloc(reloc_size + 1);
+ my_assert_not(sect_i->relocs, NULL);
+ ret = fread(sect_i->relocs, 1, reloc_size, f);
my_assert(ret, reloc_size);
- *reloc_cnt = scnhdr.s_nreloc;
+ sect_i->reloc_cnt = scnhdr.s_nreloc;
+ sect_i->reloc_fofs = scnhdr.s_relptr;
+
+ if (base != 0 && base_out != NULL)
+ *base_out = base + scnhdr.s_vaddr;
+
+ if (symtab_out == NULL || sym_cnt == NULL)
+ return;
// symtab
if (hdr.f_nsyms != 0) {
symname[8] = 0;
- symt_o = malloc(hdr.f_nsyms * sizeof(symt_o[0]) + 1);
- my_assert_not(symt_o, NULL);
+ symt_txt = malloc(hdr.f_nsyms * sizeof(symt_txt[0]) + 1);
+ my_assert_not(symt_txt, NULL);
+ symt_all = malloc(hdr.f_nsyms * sizeof(symt_all[0]) + 1);
+ my_assert_not(symt_all, NULL);
ret = fseek(f, hdr.f_symptr
+ hdr.f_nsyms * sizeof(syment), SEEK_SET);
}
for (i = s = 0; i < hdr.f_nsyms; i++) {
- long pos = ftell(f);
+ //long pos = ftell(f);
ret = fread(&syment, 1, sizeof(syment), f);
my_assert(ret, sizeof(syment));
//printf("%3d %2d %08x '%s'\n", syment.e_sclass,
// syment.e_scnum, syment.e_value, symname);
- if (syment.e_scnum != text_scnum || syment.e_sclass != C_EXT)
- continue;
-
- symt_o[s].addr = syment.e_value;
- symt_o[s].fpos = pos;
+ symt_all[i].addr = syment.e_value;
+ //symt_all[i].fpos = pos;
if (syment.e.e.e_zeroes == 0)
- symt_o[s].name = stringtab + syment.e.e.e_offset;
+ symt_all[i].name = stringtab + syment.e.e.e_offset;
else
- symt_o[s].name = strdup(symname);
- s++;
+ symt_all[i].name = strdup(symname);
+
+ symt_all[i].is_text = (syment.e_scnum == text_scnum);
+ if (symt_all[i].is_text && syment.e_sclass == C_EXT) {
+ symt_txt[s] = symt_all[i];
+ s++;
+ }
if (syment.e_numaux) {
ret = fseek(f, syment.e_numaux * sizeof(syment),
}
}
- if (symt_o != NULL)
- qsort(symt_o, s, sizeof(symt_o[0]), symt_cmp);
+ if (symt_txt != NULL)
+ qsort(symt_txt, s, sizeof(symt_txt[0]), symt_cmp);
*sym_cnt = s;
- *symtab_out = symt_o;
-
- if (base != 0 && base_out != NULL)
- *base_out = base + scnhdr.s_vaddr;
+ *symtab_out = symt_txt;
+ *raw_sym_cnt = i;
+ *raw_symtab_out = symt_all;
}
static int handle_pad(uint8_t *d_obj, uint8_t *d_exe, int maxlen)
{
static const uint8_t p7[7] = { 0x8d, 0xa4, 0x24, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t p6[6] = { 0x8d, 0x9b, 0x00, 0x00, 0x00, 0x00 };
- static const uint8_t p5[5] = { 0x05, 0x00, 0x00, 0x00, 0x00 };
- static const uint8_t p4[4] = { 0x8d, 0x64, 0x24, 0x00 };
- static const uint8_t p3[3] = { 0x8d, 0x49, 0x00 };
- static const uint8_t p2[2] = { 0x8b, 0xff };
- static const uint8_t p1[1] = { 0x90 };
+ static const uint8_t p5[5] = { 0x05, 0x00, 0x00, 0x00, 0x00 }; // add eax, 0
+ static const uint8_t p4[4] = { 0x8d, 0x64, 0x24, 0x00 }; // lea
+ static const uint8_t p3[3] = { 0x8d, 0x49, 0x00 }; // lea ecx, [ecx]
+ static const uint8_t p2[2] = { 0x8b, 0xff }; // mov edi, edi
+ static const uint8_t p1[1] = { 0x90 }; // nop
int len;
int i;
return -1;
}
+static void fill_int3(unsigned char *d, int len)
+{
+ while (len-- > 0) {
+ if (d[0] == 0xcc && d[1] == 0xcc)
+ break;
+ *d++ = 0xcc;
+ }
+}
+
int main(int argc, char *argv[])
{
+ unsigned int base = 0, addr, end, sym, *t;
+ struct my_sect_info s_text_obj, s_text_exe;
+ struct my_symtab *raw_syms_obj = NULL;
+ struct my_symtab *syms_obj = NULL;
+ long sym_cnt_obj, raw_sym_cnt_obj;
FILE *f_obj, *f_exe;
- long text_ofs_obj, text_ofs_exe;
- long sztext_obj, sztext_exe, sztext_cmn;
- RELOC *relocs_obj, *relocs_exe;
- long reloc_cnt_obj, reloc_cnt_exe;
- struct my_symtab *syms_obj, *syms_exe;
- long sym_cnt_obj, sym_cnt_exe;
- uint8_t *d_obj, *d_exe;
- unsigned int base = 0;
+ SCNHDR tmphdr;
+ long sztext_cmn;
int retval = 1;
int left;
int ret;
f_obj = fopen(argv[1], "r+b");
if (f_obj == NULL) {
- fprintf(stderr, "%s", argv[1]);
+ fprintf(stderr, "%s: ", argv[1]);
perror("");
return 1;
}
f_exe = fopen(argv[2], "r");
if (f_exe == NULL) {
- fprintf(stderr, "%s", argv[2]);
+ fprintf(stderr, "%s: ", argv[2]);
perror("");
return 1;
}
- parse_headers(f_obj, NULL, &text_ofs_obj, &d_obj, &sztext_obj,
- &relocs_obj, &reloc_cnt_obj, &syms_obj, &sym_cnt_obj);
- parse_headers(f_exe, &base, &text_ofs_exe, &d_exe, &sztext_exe,
- &relocs_exe, &reloc_cnt_exe, &syms_exe, &sym_cnt_exe);
+ parse_headers(f_obj, NULL, &s_text_obj, &syms_obj, &sym_cnt_obj,
+ &raw_syms_obj, &raw_sym_cnt_obj);
+ parse_headers(f_exe, &base, &s_text_exe, NULL, NULL, NULL, NULL);
- sztext_cmn = sztext_obj;
- if (sztext_cmn > sztext_exe)
- sztext_cmn = sztext_exe;
+ sztext_cmn = s_text_obj.size;
+ if (sztext_cmn > s_text_exe.size)
+ sztext_cmn = s_text_exe.size;
if (sztext_cmn == 0) {
printf("bad .text size(s): %ld, %ld\n",
- sztext_obj, sztext_exe);
+ s_text_obj.size, s_text_exe.size);
return 1;
}
- for (i = 0; i < reloc_cnt_obj; i++)
+ for (i = 0; i < s_text_obj.reloc_cnt; i++)
{
- unsigned int a = relocs_obj[i].r_vaddr;
- //printf("%04x %08x\n", relocs_obj[i].r_type, a);
-
- switch (relocs_obj[i].r_type) {
- case 0x06:
- memset(d_obj + a, 0, 4);
- memset(d_exe + a, 0, 4);
+ unsigned int a = s_text_obj.relocs[i].r_vaddr;
+ //printf("%04x %08x\n", s_text_obj.relocs[i].r_type, a);
+
+ switch (s_text_obj.relocs[i].r_type) {
+ case 0x06: // RELOC_ADDR32
+ case 0x14: // RELOC_REL32
+ // must preserve stored val,
+ // so trash exe so that cmp passes
+ memcpy(s_text_exe.data + a, s_text_obj.data + a, 4);
break;
default:
- printf("unknown reloc %x @%08x\n",
- relocs_obj[i].r_type, base + a);
+ printf("unknown reloc %x @%08x/%08x\n",
+ s_text_obj.relocs[i].r_type, a, base + a);
return 1;
}
}
for (i = 0; i < sztext_cmn; i++)
{
- if (d_obj[i] == d_exe[i])
+ if (s_text_obj.data[i] == s_text_exe.data[i])
continue;
left = sztext_cmn - i;
- if (d_exe[i] == 0xcc) { // padding
- if (handle_pad(d_obj + i, d_exe + i, left))
+ if (s_text_exe.data[i] == 0xcc) { // padding
+ if (handle_pad(s_text_obj.data + i,
+ s_text_exe.data + i, left))
continue;
}
- ret = check_equiv(d_obj + i, d_exe + i, left);
+ ret = check_equiv(s_text_obj.data + i, s_text_exe.data + i, left);
if (ret >= 0) {
i += ret;
continue;
}
- printf("%x: %02x vs %02x\n", base + i, d_obj[i], d_exe[i]);
+ printf("%x: %02x vs %02x\n", base + i,
+ s_text_obj.data[i], s_text_exe.data[i]);
goto out;
}
+ // fill removed funcs with 'int3'
+ for (i = 0; i < sym_cnt_obj; i++) {
+ if (strncmp(syms_obj[i].name, "rm_", 3))
+ continue;
+
+ addr = syms_obj[i].addr;
+ end = (i < sym_cnt_obj - 1)
+ ? syms_obj[i + 1].addr : s_text_obj.size;
+ if (addr >= s_text_obj.size || end > s_text_obj.size) {
+ printf("addr OOR: %x-%x '%s'\n", addr, end,
+ syms_obj[i].name);
+ goto out;
+ }
+ fill_int3(s_text_obj.data + addr, end - addr);
+ }
+
+ // remove relocs
+ for (i = 0; i < s_text_obj.reloc_cnt; i++) {
+ addr = s_text_obj.relocs[i].r_vaddr;
+ sym = s_text_obj.relocs[i].r_symndx;
+ if (addr > s_text_obj.size - 4) {
+ printf("reloc addr OOR: %x\n", addr);
+ goto out;
+ }
+ if (sym >= raw_sym_cnt_obj) {
+ printf("reloc sym OOR: %d/%ld\n",
+ sym, raw_sym_cnt_obj);
+ goto out;
+ }
+#if 0
+ printf("r %08x -> %08x %s\n", base + addr,
+ raw_syms_obj[sym].addr,
+ raw_syms_obj[sym].name);
+#endif
+ t = (unsigned int *)(s_text_obj.data + addr);
+ if (t[0] == 0xcccccccc
+ || t[-1] == 0xcccccccc) { // jumptab of a func?
+ t[0] = 0xcccccccc;
+ memmove(&s_text_obj.relocs[i],
+ &s_text_obj.relocs[i + 1],
+ (s_text_obj.reloc_cnt - i - 1)
+ * sizeof(s_text_obj.relocs[0]));
+ i--;
+ s_text_obj.reloc_cnt--;
+ }
+#if 0
+ // note: branches/calls already linked,
+ // so only useful for dd refs
+ // XXX: rm'd because of switch tables
+ else if (raw_syms_obj[sym].is_text) {
+ unsigned int addr2 = raw_syms_obj[sym].addr;
+ if (s_text_obj.data[addr2] == 0xcc) {
+ printf("warning: reloc %08x -> %08x "
+ "points to rm'd target '%s'\n",
+ base + addr, base + addr2,
+ raw_syms_obj[sym].name);
+ }
+ }
+#endif
+ }
+
+ // patch .text
+ ret = fseek(f_obj, s_text_obj.sect_fofs, SEEK_SET);
+ my_assert(ret, 0);
+ ret = fwrite(s_text_obj.data, 1, s_text_obj.size, f_obj);
+ my_assert(ret, s_text_obj.size);
+
+ // patch relocs
+ ret = fseek(f_obj, s_text_obj.reloc_fofs, SEEK_SET);
+ my_assert(ret, 0);
+ ret = fwrite(s_text_obj.relocs, sizeof(s_text_obj.relocs[0]),
+ s_text_obj.reloc_cnt, f_obj);
+ my_assert(ret, s_text_obj.reloc_cnt);
+
+ ret = fseek(f_obj, s_text_obj.scnhdr_fofs, SEEK_SET);
+ my_assert(ret, 0);
+ ret = fread(&tmphdr, 1, sizeof(tmphdr), f_obj);
+ my_assert(ret, sizeof(tmphdr));
+
+ tmphdr.s_nreloc = s_text_obj.reloc_cnt;
+
+ ret = fseek(f_obj, s_text_obj.scnhdr_fofs, SEEK_SET);
+ my_assert(ret, 0);
+ ret = fwrite(&tmphdr, 1, sizeof(tmphdr), f_obj);
+ my_assert(ret, sizeof(tmphdr));
+
+ fclose(f_obj);
+ fclose(f_exe);
+
+ retval = 0;
out:
return retval;
}