+/*
+ * ia32rtools
+ * (C) notaz, 2013,2014
+ *
+ * This work is licensed under the terms of 3-clause BSD license.
+ * See COPYING file in the top-level directory.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
*raw_symtab_out = symt_all;
}
-static int handle_pad(uint8_t *d_obj, uint8_t *d_exe, int maxlen)
+static int try_align(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 }; // 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
+ static const uint8_t aligns[8][7] = {
+ { }, // [0] not used
+ { 0x90 }, // [1] nop
+ { 0x8b, 0xff }, // mov edi, edi
+ { 0x8d, 0x49, 0x00 }, // lea ecx, [ecx]
+ { 0x8d, 0x64, 0x24, 0x00 }, // lea
+ { 0x05, 0x00, 0x00, 0x00, 0x00 }, // add eax, 0
+ { 0x8d, 0x9b, 0x00, 0x00, 0x00, 0x00 },
+ { 0x8d, 0xa4, 0x24, 0x00, 0x00, 0x00, 0x00 },
+ };
+ int j = 0;
int len;
int i;
+ // check exe for common pad/align patterns
for (i = 0; i < maxlen; i++)
if (d_exe[i] != 0xcc)
break;
- for (len = i; len > 0; )
+ while (j < 8) {
+ for (j = 1; j < 8; j++) {
+ if (maxlen - i < j) {
+ j = 8;
+ break;
+ }
+ if (memcmp(&d_exe[i], aligns[j], j) == 0) {
+ i += j;
+ break;
+ }
+ }
+ }
+ if (i == 0)
+ return 0;
+
+ // now check the obj
+ for (j = 0, len = i; len > 0; )
{
i = len;
if (i > 7)
i = 7;
- switch (i) {
- #define CASE(x) \
- case sizeof(p ## x): \
- if (memcmp(d_obj, p ## x, sizeof(p ## x))) \
- return 0; \
- memset(d_obj, 0xcc, sizeof(p ## x)); \
+ if (memcmp(d_obj, aligns[i], i) != 0)
break;
- CASE(7)
- CASE(6)
- CASE(5)
- CASE(4)
- CASE(3)
- CASE(2)
- CASE(1)
- default:
- printf("%s: unhandled len: %d\n", __func__, len);
- return 0;
- #undef CASE
- }
+
+ memcpy(d_obj, d_exe, i);
+ j += i;
len -= i;
d_obj += i;
+ d_exe += i;
}
- return 1;
+ return j;
}
struct equiv_opcode {
signed char len;
signed char ofs;
- short cmp_rm;
+ unsigned short cmp_rm:1;
+ unsigned short simple:1;
uint8_t v_masm[8];
uint8_t v_masm_mask[8];
uint8_t v_msvc[8];
uint8_t v_msvc_mask[8];
} equiv_ops[] = {
// cmp $0x11,%ax
- { 4, -1, 0,
+ { 4, -1, 0, 0,
{ 0x66,0x83,0xf8,0x03 }, { 0xff,0xff,0xff,0x00 },
{ 0x66,0x3d,0x03,0x00 }, { 0xff,0xff,0x00,0xff }, },
// lea -0x1(%ebx,%eax,1),%esi // op mod/rm sib offs
// mov, test, imm grp 1
- { 3, -2, 1,
+ { 3, -2, 1, 0,
{ 0x8d,0x74,0x03 }, { 0xf0,0x07,0xc0 },
{ 0x8d,0x74,0x18 }, { 0xf0,0x07,0xc0 }, },
// movzbl 0x58f24a(%eax,%ecx,1),%eax
- { 4, -3, 1,
+ { 4, -3, 1, 0,
{ 0x0f,0xb6,0x84,0x08 }, { 0xff,0xff,0x07,0xc0 },
{ 0x0f,0xb6,0x84,0x01 }, { 0xff,0xff,0x07,0xc0 }, },
// inc/dec
- { 3, -2, 1,
+ { 3, -2, 1, 0,
{ 0xfe,0x4c,0x03 }, { 0xfe,0xff,0xc0 },
{ 0xfe,0x4c,0x18 }, { 0xfe,0xff,0xc0 }, },
// cmp
- { 3, -2, 1,
+ { 3, -2, 1, 0,
{ 0x38,0x0c,0x0c }, { 0xff,0xff,0xc0 },
{ 0x38,0x0c,0x30 }, { 0xff,0xff,0xc0 }, },
// test %dl,%bl
- { 2, -1, 1,
+ { 2, -1, 1, 0,
{ 0x84,0xd3 }, { 0xfe,0xc0 },
{ 0x84,0xda }, { 0xfe,0xc0 }, },
// cmp r,r/m vs rm/r
- { 2, 0, 1,
+ { 2, 0, 1, 0,
{ 0x3a,0xca }, { 0xff,0xc0 },
{ 0x38,0xd1 }, { 0xff,0xc0 }, },
// rep + 66 prefix
- { 2, 0, 0,
+ { 2, 0, 0, 0,
{ 0xf3,0x66 }, { 0xfe,0xff },
{ 0x66,0xf3 }, { 0xff,0xfe }, },
// fadd st, st(0) vs st(0), st
- { 2, 0, 0,
+ { 2, 0, 0, 0,
{ 0xd8,0xc0 }, { 0xff,0xf7 },
{ 0xdc,0xc0 }, { 0xff,0xf7 }, },
+ // [esp] vs [esp+0]
+ { 4, -1, 0, 0,
+ { 0x00,0x04,0x24,0x90 }, { 0x00,0xc7,0xff,0xff },
+ { 0x00,0x44,0x24,0x00 }, { 0x00,0xc7,0xff,0xff }, },
+ { 5, -1, 0, 0,
+ { 0x00,0x04,0x24,0x00,0x90 }, { 0x00,0xc7,0xff,0x00,0xff },
+ { 0x00,0x44,0x24,0x00,0x00 }, { 0x00,0xc7,0xff,0xff,0x00 }, },
+ { 8, -1, 0, 0,
+ { 0x00,0x04,0x24,0x00,0x00,0x00,0x00,0x90 }, { 0x00,0xc7,0xff,0x00,0x00,0x00,0x00,0xff },
+ { 0x00,0x44,0x24,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0xc7,0xff,0xff,0x00,0x00,0x00,0x00 }, },
+
+ // various align insns/fillups
+ { 2, -1, 0, 0,
+ { 0x8b,0xff }, { 0xff,0xff },
+ { 0x8b,0xc0 }, { 0xff,0xff }, },
+ { 2, 0, 0, 1,
+ { 0x00,0x00 }, { 0x00,0x00 },
+ { 0x8b,0xc0 }, { 0xff,0xff }, },
+ { 3, 0, 0, 1,
+ { 0x00,0x00,0x00 }, { 0x50,0x00,0x00 },
+ { 0x2e,0x8b,0xc0 }, { 0xff,0xff,0xff }, },
// broad filters (may take too much..)
// testb $0x4,0x1d(%esi,%eax,1)
// movb, push, ..
- { 3, -2, 1,
+ { 3, -2, 1, 0,
{ 0xf6,0x44,0x06 }, { 0x00,0x07,0xc0 },
{ 0xf6,0x44,0x30 }, { 0x00,0x07,0xc0 }, },
};
op->v_msvc_mask, len))
continue;
+ if (op->simple)
+ return len + ofs;
+
jo = je = 0;
d_obj += ofs;
d_exe += ofs;
break;
if ((jo == len && je != len) || (jo != len && je == len)) {
- printf("invalid equiv_ops\n");
+ printf("invalid equiv_op #%td\n", op - equiv_ops);
return -1;
}
if (jo == len)
- return len + ofs - 1; // matched
+ return len + ofs; // matched
// var byte
vo = d_obj[jo] & ~op->v_masm_mask[jo];
FILE *f_obj, *f_exe;
SCNHDR tmphdr;
long sztext_cmn;
+ int do_cmp = 1;
int retval = 1;
+ int bad = 0;
int left;
+ int arg;
int ret;
int i;
- if (argc != 3) {
- printf("usage:\n%s <a_obj> <exe>\n", argv[0]);
+ for (arg = 1; arg < argc; arg++) {
+ if (!strcmp(argv[arg], "-n"))
+ do_cmp = 0;
+ else
+ break;
+ }
+
+ if (argc != arg + 2) {
+ printf("usage:\n%s [-n] <a_obj> <exe>\n", argv[0]);
return 1;
}
- f_obj = fopen(argv[1], "r+b");
+ f_obj = fopen(argv[arg++], "r+b");
if (f_obj == NULL) {
fprintf(stderr, "%s: ", argv[1]);
perror("");
return 1;
}
- f_exe = fopen(argv[2], "r");
+ f_exe = fopen(argv[arg++], "r");
if (f_exe == NULL) {
fprintf(stderr, "%s: ", argv[2]);
perror("");
}
}
+ if (do_cmp)
for (i = 0; i < sztext_cmn; i++)
{
- if (s_text_obj.data[i] == s_text_exe.data[i])
+ if (s_text_obj.data[i] == s_text_exe.data[i]) {
+ bad = 0;
continue;
+ }
left = sztext_cmn - i;
- if (s_text_exe.data[i] == 0xcc) { // padding
- if (handle_pad(s_text_obj.data + i,
- s_text_exe.data + i, left))
- continue;
+ ret = try_align(s_text_obj.data + i, s_text_exe.data + i, left);
+ if (ret > 0) {
+ i += ret - 1;
+ continue;
}
ret = check_equiv(s_text_obj.data + i, s_text_exe.data + i, left);
if (ret >= 0) {
- i += ret;
+ i += ret - 1;
continue;
}
printf("%x: %02x vs %02x\n", base + i,
s_text_obj.data[i], s_text_exe.data[i]);
- goto out;
+ if (bad)
+ goto out;
+
+ bad = 1;
}
// fill removed funcs with 'int3'