-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdw-disassembly.h
128 lines (102 loc) · 4.54 KB
/
dw-disassembly.h
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
#ifndef DW_DISASSEMBLY_H
#define DW_DISASSEMBLY_H
#include <ucontext.h>
#include <stdbool.h>
#include <stddef.h>
#include <unistd.h>
#include <stdint.h>
#include <libpatch/patch.h>
// The instruction table contains all the information about the instructions that
// access tainted pointers. This is in order to untaint the pointers, emulate the
// access and retaint the pointers. The structure is not opaque for now because
// it is accessed from a few files. More abstraction is likely in the future,
// especially when multiple architectures will be supported.
#define MAX_MEM_ARG 3
#define MAX_REG_ARG 6
#define MAX_MOD_REG 6
enum dw_strategies {DW_PATCH_TRAP=0, DW_PATCH_JUMP};
struct insn_table;
typedef struct insn_table instruction_table;
// x86_64 instructions can have several memory arguments.
// Each can contain a tainted pointer. Normally, the base register
// is tainted but sometimes the index register is tainted instead.
// On some instructions with two memory arguments, it may happen that
// both are tainted. Sometimes only one is tainted but not always the same.
// Thus, the detection of which argument is tainted must be dynamic.
struct memory_arg {
// Those fields are extracted directly from the Capstone library
// The base and index are set to X86_REG_INVALID if not used
uintptr_t scale;
uintptr_t displacement;
int base;
int index;
unsigned length;
unsigned access;
// If the same register as the base or index is also a register
// argument, base_access or index_access will be non zero and set
// to CS_AC_READ / CS_AC_WRITE, and some care is needed when
// untainting and retainting that register.
unsigned base_access, index_access;
// When the unprotect handler is called, if the base or index register
// is tainted, this taint is saved, otherwise the field is set to zero.
// It will be used to retaint the register in the reprotect handler,
// and to detect if the tainted register, base or index, changes
// between different executions of that instruction.
uintptr_t base_taint, index_taint;
// When a register is untainted before its value is read from or written to memory,
// because it is at the same time a base pointer and register argument,
// we need to fix the value at that address in the unprotect handler.
// We thus save the address and the value.
uintptr_t saved_address, saved_value;
};
struct reg_arg {
unsigned reg;
unsigned length;
unsigned access;
};
struct insn_entry {
struct memory_arg arg_m[MAX_MEM_ARG];
struct reg_arg arg_r[MAX_REG_ARG];
unsigned nb_arg_m;
unsigned nb_arg_r;
bool repeat;
bool post_handler;
uintptr_t insn;
uintptr_t next_insn;
uintptr_t olx_buffer;
unsigned hit_count;
char disasm_insn[64];
unsigned strategy;
unsigned insn_length;
unsigned gregs_read_count;
unsigned gregs_write_count;
unsigned gregs_read[MAX_MOD_REG]; // test
unsigned gregs_written[MAX_MOD_REG]; // test
};
// For now the instruction table cannot be expanded after initialization
instruction_table*
dw_init_instruction_table(size_t size);
// Free the instruction table. Difficult to be sure that no tainted pointer remains.
void dw_fini_instruction_table(instruction_table *table);
// Check if an entry already exists for that instruction address
struct insn_entry*
dw_get_instruction_entry(instruction_table *table, uintptr_t fault);
// Create a new entry for that instruction address
struct insn_entry*
dw_create_instruction_entry(instruction_table *table, uintptr_t fault, uintptr_t *next, ucontext_t *uctx);
// Initialize libpatch
void dw_patch_init();
typedef void (*dw_patch_probe)(struct patch_exec_context *ctx, uint8_t post_or_ret);
// Patch the instruction described by that entry and have
// the specified handler called before and after that instruction
bool dw_instruction_entry_patch(struct insn_entry *entry, enum dw_strategies strategy, dw_patch_probe patch_handler);
// A potentially tainted pointer is accessed, unprotect it before the access
void dw_unprotect_context(struct patch_exec_context *ctx);
// A potentially tainted pointer was accessed, reprotect it after the access
void dw_reprotect_context(struct patch_exec_context *ctx);
// List all the instructions in the table along with their statistics
void dw_print_instruction_entries(instruction_table *table, int fd);
// Activate or deactivate extensive checking in tainting/untainting handler
void dw_set_check_handling(bool f);
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif /* DW_DISASSEMBLY_H */