-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathunpack.c
146 lines (116 loc) · 3.83 KB
/
unpack.c
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
#include "dr_api.h"
#include "hashtable.h"
#include "drmgr.h"
#include <string.h>
#define LOG(level, fmt, ...) \
do {\
dr_log(NULL, LOG_ALL, (level), "%s:%d:unpack:" fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
} while (0)
#define DEBUG(fmt, ...) LOG(3, "D: " fmt, ##__VA_ARGS__)
#define INFO(fmt, ...) LOG(2, "I: " fmt, ##__VA_ARGS__)
#define WARN(fmt, ...) LOG(1, "W: " fmt, ##__VA_ARGS__)
#define ERROR(fmt, ...) LOG(0, "E: " fmt, ##__VA_ARGS__)
#define INITIAL_MEM_SIZE (32)
static hashtable_t g_ht_data;
static void dump_memory(const void *p_data, size_t size, const app_pc target) {
file_t dump = INVALID_FILE;
int ret;
ssize_t written = -1;
char dumpfname[256];
ret = dr_snprintf(dumpfname, sizeof(dumpfname), "dump.%p.%p", target, p_data);
if (0 > ret || sizeof(dumpfname) <= ret) {
ERROR("failed to generate dump name (%d)", ret);
return;
}
dump = dr_open_file(dumpfname, DR_FILE_WRITE_OVERWRITE);
if (INVALID_FILE == dump) {
ERROR("opening file for dump failed");
return;
}
while (0 < size) {
written = dr_write_file(dump, p_data, size);
if (0 >= ret) {
ERROR("writing dump file failed");
break;
}
p_data += written;
size -= written;
}
dr_close_file(dump);
return;
}
static void free_mem_INITIAL_MEM_SIZE(void *ptr) {
dr_global_free(ptr, INITIAL_MEM_SIZE);
}
static bool should_dump(const dr_mem_info_t *info) {
bool ret = true;
void *prev = NULL;
void *data = NULL;
data = dr_global_alloc(INITIAL_MEM_SIZE);
DR_ASSERT(data);
if (false == dr_safe_read(info->base_pc, INITIAL_MEM_SIZE, data, NULL)) {
ret = false;
free_mem_INITIAL_MEM_SIZE(data);
goto exit;
}
prev = hashtable_add_replace(&g_ht_data, info->base_pc, data);
if (NULL == prev) {
ret = true;
goto exit;
}
if (0 == memcmp(prev, data, INITIAL_MEM_SIZE)) {
ret = false;
}
exit:
if (prev) { free_mem_INITIAL_MEM_SIZE(prev); }
return ret;
}
static void check_target(app_pc pc, app_pc target) {
//TODO: locking?
dr_mem_info_t info = {0};
if (false == dr_query_memory_ex(target, &info)) {
WARN("cant query memory %p, going to call it????", target);
return;
}
if (!(info.prot & DR_MEMPROT_WRITE) && (info.type & DR_MEMTYPE_IMAGE)) {
//seems legit, no write permissions and mapped binary
return;
}
if (!should_dump(&info)) {
DEBUG("fishy but already dumped...");
return;
}
INFO("found fishy behavior in %p, dumping", target);
dump_memory(info.base_pc, info.size, target);
}
static dr_emit_flags_t
event_bb_insert(void *drcontext, void *tag, instrlist_t *bb,
instr_t *instr, bool for_trace, bool translating,
void *user_data) {
if (NULL == instr_get_app_pc(instr)) {
return DR_EMIT_DEFAULT;
}
if (!instr_is_call_indirect(instr) && !instr_is_mbr(instr)) {
return DR_EMIT_DEFAULT;
}
DEBUG("instrumeting %p", instr_get_app_pc(instr));
dr_insert_mbr_instrumentation(drcontext, bb, instr, check_target,
SPILL_SLOT_1);
return DR_EMIT_DEFAULT;
}
static void event_exit(void) {
INFO("finised");
hashtable_delete(&g_ht_data);
drmgr_exit();
}
DR_EXPORT void dr_init(client_id_t id) {
/* Specify priority relative to other instrumentation operations: */
drmgr_priority_t priority = {sizeof(priority), "unpack", NULL, NULL, 0};
INFO("starting");
drmgr_init();
hashtable_init_ex(&g_ht_data, 4, HASH_INTPTR, false, false,
free_mem_INITIAL_MEM_SIZE, NULL, NULL);
dr_register_exit_event(event_exit);
DR_ASSERT(drmgr_register_bb_instrumentation_event(NULL,
event_bb_insert, &priority));
}