1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
|
/*
* This is a simple program demonstrating the libx86emu usage.
*
* It lets you load a binary blob at some address and run the emulation.The
* emulation trace is logged to the console to show what it is doing.
*/
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <x86emu.h>
void help(void);
void flush_log(x86emu_t *emu, char *buf, unsigned size);
x86emu_t *emu_new(void);
int emu_init(x86emu_t *emu, char *file);
void emu_run(char *file);
struct option options[] = {
{ "help", 0, NULL, 'h' },
{ "load", 1, NULL, 'l' },
{ "start", 1, NULL, 's' },
{ "max", 1, NULL, 'm' },
{ "32", 0, NULL, 1001 },
{ }
};
struct {
struct {
unsigned segment;
unsigned offset;
} start;
unsigned load;
unsigned max_instructions;
unsigned bits_32:1;
char *file;
} opt;
/*
* Parse options, then run emulation.
*/
int main(int argc, char **argv)
{
int i;
char *str;
opt.start.segment = 0;
opt.start.offset = opt.load = 0x7c00;
opt.max_instructions = 10000000;
opterr = 0;
while((i = getopt_long(argc, argv, "hm:l:s:", options, NULL)) != -1) {
switch(i) {
case 'm':
opt.max_instructions = strtoul(optarg, NULL, 0);
break;
case 'l':
opt.load = strtoul(optarg, NULL, 0);
break;
case 's':
opt.start.offset = strtoul(optarg, &str, 0);
if(*str == ':') {
opt.start.segment = opt.start.offset;
opt.start.offset = strtoul(str + 1, NULL, 0);
}
break;
case 1001:
opt.bits_32 = 1;
break;
default:
help();
return i == 'h' ? 0 : 1;
}
}
if(argc == optind + 1) {
opt.file = argv[optind];
}
else {
help();
return 1;
}
emu_run(opt.file);
return 0;
}
/*
* Display short usage message.
*/
void help()
{
printf(
"Usage: x86emu-demo [OPTIONS] FILE\n"
"\n"
"Load FILE and run x86 emulation.\n"
"\n"
"Options:\n"
" -l, --load ADDRESS Load FILE at ADDRESS into memory (default 0x7c00).\n"
" -s, --start ADDRESS Start emulation at ADDRESS (default 0:0x7c00).\n"
" ADDRESS may contain a colon (':') to separate segment and\n"
" offset values. Without colon, segment 0 is assumed.\n"
" -m, --max N Stop after emulating N instructions.\n"
" --32 Start in 32-bit mode (default 16-bit mode).\n"
" -h, --help Show this text\n"
);
}
/*
* Write emulation log to console.
*/
void flush_log(x86emu_t *emu, char *buf, unsigned size)
{
if(!buf || !size) return;
fwrite(buf, size, 1, stdout);
}
/*
* Create new emulation object.
*/
x86emu_t *emu_new()
{
x86emu_t *emu = x86emu_new(X86EMU_PERM_R | X86EMU_PERM_W | X86EMU_PERM_X, 0);
/* log buf size of 1000000 is purely arbitrary */
x86emu_set_log(emu, 1000000, flush_log);
emu->log.trace = X86EMU_TRACE_DEFAULT;
return emu;
}
/*
* Setup registers and memory.
*/
int emu_init(x86emu_t *emu, char *file)
{
FILE *f;
unsigned addr;
int i;
addr = opt.load;
x86emu_set_seg_register(emu, emu->x86.R_CS_SEL, opt.start.segment);
emu->x86.R_EIP = opt.start.offset;
if(opt.bits_32) {
/* set default data/address size to 32 bit */
emu->x86.R_CS_ACC |= (1 << 10);
/* maximize descriptor limits */
emu->x86.R_CS_LIMIT =
emu->x86.R_DS_LIMIT =
emu->x86.R_ES_LIMIT =
emu->x86.R_FS_LIMIT =
emu->x86.R_GS_LIMIT =
emu->x86.R_SS_LIMIT = ~0;
}
if(!(f = fopen(file, "r"))) return 0;
while((i = fgetc(f)) != EOF) {
x86emu_write_byte(emu, addr++, i);
}
fclose(f);
return 1;
}
/*
* Run emulation.
*/
void emu_run(char *file)
{
x86emu_t *emu = emu_new();
unsigned flags = X86EMU_RUN_MAX_INSTR | X86EMU_RUN_NO_EXEC | X86EMU_RUN_NO_CODE | X86EMU_RUN_LOOP;
int ok = 0;
if(!file) return;
ok = emu_init(emu, file);
if(ok) {
printf("*** running %s ***\n\n", file);
x86emu_dump(emu, X86EMU_DUMP_MEM | X86EMU_DUMP_ASCII);
x86emu_reset_access_stats(emu);
emu->max_instr = opt.max_instructions;
x86emu_run(emu, flags);
x86emu_dump(emu, X86EMU_DUMP_DEFAULT | X86EMU_DUMP_ACC_MEM);
x86emu_clear_log(emu, 1);
}
x86emu_done(emu);
}
|