forked from advanced-microcode-patching/shiva
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathshiva_target.c
157 lines (143 loc) · 4.52 KB
/
shiva_target.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
146
147
148
149
150
151
152
153
154
155
156
/*
* This source file contains code that tweak, alter, read and write
* to the memory space of the executable target program.
*/
#include "shiva.h"
bool
shiva_target_has_prelinking(struct shiva_ctx *ctx)
{
uint32_t magic = *(uint32_t *)&ctx->elfobj.mem[EI_PAD];
struct elf_section shdr;
if (magic != (uint32_t)SHIVA_SIGNATURE)
return false;
if (elf_section_by_name(&ctx->elfobj, ".shiva.xref", &shdr) == true &&
elf_section_by_name(&ctx->elfobj, ".shiva.branch", &shdr) == true) {
ctx->prelink_flags |= SHIVA_PRELINK_F_CFG_ENABLED;
}
return true;
}
/*
* Will copy a string from src address of binary.
* Copies up to 4095 bytes of a string, leaving 1 byte for NULL terminator.
*/
bool
shiva_target_copy_string(struct shiva_ctx *ctx, char *dst, const char *src, size_t *len_out)
{
elfobj_t *elfobj = &ctx->elfobj;
int i;
uint64_t byte;
bool res;
char *d = dst;
for (i = 0 ;; i++) {
res = elf_read_address(elfobj, (uint64_t)src + i, &byte, ELF_BYTE);
if (res == false) {
fprintf(stderr, "elf_read_address() failed at %lx\n", (uint64_t)src + i);
return false;
}
*(d++) = byte;
if (i >= PATH_MAX - 1)
break;
if (byte == 0)
break;
}
*len_out = i - 1;
return true;
}
/*
* Copies no more than PATH_MAX bytes into buf.
*/
bool
shiva_target_get_module_path(struct shiva_ctx *ctx, char *buf)
{
uint64_t search_addr, basename_addr;
char tmp[PATH_MAX];
size_t len, o_len;
bool res;
if (shiva_target_dynamic_get(ctx, SHIVA_DT_SEARCH, &search_addr) == false) {
fprintf(stderr, "shiva_target_dynamic_get(%p, SHIVA_DT_SEARCH, ...) failed\n",
ctx);
return false;
}
if (shiva_target_dynamic_get(ctx, SHIVA_DT_NEEDED, &basename_addr) == false) {
fprintf(stderr, "shiva_target_dynamic_get(%p, SHIVA_DT_NEEDED, ...) failed\n",
ctx);
return false;
}
res = shiva_target_copy_string(ctx, tmp, (const char *)search_addr, &len);
if (res == false) {
fprintf(stderr, "shiva_target_copy_string() failed at %#lx\n", (uint64_t)search_addr);
return false;
}
o_len = len;
if (tmp[len] != '/' && len < 4095) {
tmp[len + 1] = '/';
len += 1;
}
res = shiva_target_copy_string(ctx, &tmp[len + 1], (const char *)basename_addr, &len);
if (res == false) {
fprintf(stderr, "shiva_target_copy_string() failed at %#lx\n", (uint64_t)basename_addr);
return false;
}
if (len + o_len >= PATH_MAX - 1) {
fprintf(stderr, "path len (%zu) exceeds PATH_MAX - 1\n", len + o_len);
return false;
}
strcpy(buf, tmp);
return true;
}
/*
* This function modifies the "live" dynamic segment in memory. It will modify
* the first dynamic tag found of type 'tag' and change it to 'value'.
*/
bool
shiva_target_dynamic_set(struct shiva_ctx *ctx, uint64_t tag, uint64_t value)
{
int i;
uint64_t phdr_vaddr = ctx->ulexec.base_vaddr + elf_phoff(&ctx->elfobj);
Elf64_Phdr *phdr = (Elf64_Phdr *)phdr_vaddr;
Elf64_Dyn *dyn = NULL;
for (i = 0; i < elf_segment_count(&ctx->elfobj); i++) {
if (phdr[i].p_type != PT_DYNAMIC)
continue;
dyn = (Elf64_Dyn *)((uint64_t)(phdr[i].p_vaddr + ctx->ulexec.base_vaddr));
break;
}
if (dyn == NULL) {
fprintf(stderr, "shiva_target_dynamic_tag() failed, dyn == NULL\n");
return false;
}
for (i = 0; dyn[i].d_tag != DT_NULL; i++) {
if (dyn[i].d_tag == tag) {
shiva_debug("Set dynamic tag %d: %#lx\n", dyn[i].d_tag, value);
dyn[i].d_un.d_val = value;
return true;
}
}
return false;
}
bool
shiva_target_dynamic_get(struct shiva_ctx *ctx, uint64_t tag, uint64_t *out)
{
int i;
uint64_t phdr_vaddr = ctx->ulexec.base_vaddr + elf_phoff(&ctx->elfobj);
Elf64_Phdr *phdr = (Elf64_Phdr *)phdr_vaddr;
Elf64_Dyn *dyn = NULL;
for (i = 0; i < elf_segment_count(&ctx->elfobj); i++) {
if (phdr[i].p_type != PT_DYNAMIC)
continue;
dyn = (Elf64_Dyn *)((uint64_t)(phdr[i].p_vaddr + ctx->ulexec.base_vaddr));
break;
}
if (dyn == NULL) {
fprintf(stderr, "shiva_target_dynamic_tag() failed, dyn == NULL\n");
return false;
}
for (i = 0; dyn[i].d_tag != DT_NULL; i++) {
if (dyn[i].d_tag == tag) {
shiva_debug("Get dynamic tag %d: %#lx\n", dyn[i].d_tag, dyn[i].d_un.d_val);
*out = dyn[i].d_un.d_val;
return true;
}
}
return false;
}