Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


d5bdfb8e557a30c55eeea769eb324de778cbc66a
[palacios.git] / palacios / src / gears / ext_code_inject.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2011, Kyle C. Hale <kh@u.norhtwestern.edu>
11  * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Kyle C. Hale <kh@u.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <palacios/vmm.h>
22 #include <palacios/vm_guest.h>
23 #include <palacios/vm_guest_mem.h>
24 #include <palacios/vmm_intr.h>
25 #include <palacios/vmm_extensions.h>
26 #include <palacios/vmm_decoder.h>
27 #include <palacios/vmm_types.h>
28 #include <palacios/vmm_hypercall.h>
29 #include <palacios/vmcb.h>
30
31 #include <gears/code_inject.h> 
32 #include <gears/execve_hook.h>
33 #include <gears/sw_intr.h>
34
35 #include "elf.h"
36
37 struct v3_code_injects code_injects;
38
39 static char mmap_code[] =   "\xb8\xc0\x00\x00\x00\x31\xdb\xb9"
40                             "\x00\x00\x10\x00\xba\x01\x00\x00"
41                             "\x00\xbd\x02\x00\x00\x00\x09\xea"
42                             "\xbd\x04\x00\x00\x00\x09\xea\xbe"
43                             "\x02\x00\x00\x00\xbd\x20\x00\x00"
44                             "\x00\x09\xee\xbf\xff\xff\xff\xff"
45                             "\x31\xed\xcd\x80\x89\xc3\xb9\x00"
46                             "\x00\x10\x00\xc7\x00\xef\xbe\xad"
47                             "\xde\x05\x00\x10\x00\x00\x81\xe9"
48                             "\x00\x10\x00\x00\x75\xed\xb8\x00"
49                             "\xf0\x00\x00\x0f\x01\xd9";
50
51 static char munmap_code[] = "\xb8\x5b\x00\x00\x00\xb9\x00\x00"
52                             "\x10\x00\xcd\x80\x89\xc3\xb8\x03"
53                             "\xf0\x00\x00\x0f\x01\xd9";
54
55 static char vmmcall_code[] = "\x48\xc7\xc0\x02\xf0\x00\x00\x0f"
56                              "\x01\xd9";
57
58 static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
59
60
61 /*
62  * the presence of this is kind of a hack, and exists because
63  * when one of the below hypercall handlers is invoked, we don't
64  * have an elegant way of deciding which inject queue (normal or exec-hooked)
65  * to pull the first element from, so we have this place marker
66  *
67  * This could be ugly with more than one core...
68  */
69 static struct v3_code_inject_info * current_inject;
70
71
72 static int free_code_inject (struct v3_vm_info * vm, struct v3_code_inject_info * inject) {
73     list_del(&(inject->inject_node));
74     V3_Free(inject);
75     return 0;
76 }
77
78
79 /* 
80  * helper function to save a chunk of code in an inject object's state and
81  * overwrite it with something else (mostly for injecting hypercalls)
82  */
83 static int v3_plant_code (struct guest_info * core, struct v3_code_inject_info * inject,
84                           char * hva, char * code, uint_t size) {
85     int i;
86
87     // first back up old code
88     inject->old_code = (char*)V3_Malloc(size);
89     for (i = 0; i < size; i++)
90         inject->old_code[i] = *(hva + i);
91
92     // overwrite
93     for (i = 0; i < size; i++)
94         *(hva + i) = *(code + i);
95
96     return 0;
97 }
98
99
100 static int v3_restore_pre_mmap_state (struct guest_info * core, struct v3_code_inject_info * inject) {
101     int ret;
102     addr_t rip_hva, mmap_gva;
103
104     if ((mmap_gva = (addr_t)core->vm_regs.rbx) < 0) {
105         PrintError("Error running mmap in guest: v3_restore_pre_mmap_state\n");
106         return -1;
107     }
108
109     inject->code_region_gva = mmap_gva;
110
111         ret = v3_gva_to_hva(core, 
112                                                 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
113                                                 &rip_hva);
114     if (ret == -1) {
115                 PrintError("Error translating RIP address: v3_restore_pre_mmap_state\n");
116                 return -1;
117     }
118
119     // restore the code overwritten by mmap code
120     memcpy((void*)rip_hva, (void*)inject->old_code, MMAP_SIZE);
121     V3_Free(inject->old_code);
122
123     v3_do_static_inject(core, inject, MMAP_COMPLETE, mmap_gva);
124     return 0;
125 }
126
127
128 static int v3_restore_pre_inject_state (struct guest_info * core, struct v3_code_inject_info * inject) {
129     int ret;
130     addr_t rip_hva;
131
132     // restore original register state at int 80
133     memcpy(&core->vm_regs, &inject->regs, sizeof(struct v3_gprs));
134     memcpy(&core->ctrl_regs, &inject->ctrl_regs, sizeof(struct v3_ctrl_regs));
135
136         ret = v3_gva_to_hva(core, 
137                                                 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
138                                                 &rip_hva);
139     if (ret == -1) {
140                 PrintError("Error translating RIP address: v3_pre_inject_state\n");
141                 return -1;
142     }
143
144     // increment original rip by 2 to skip the int 80
145     core->rip = inject->rip + 2;
146     return 0;
147 }
148
149
150 /* 
151  * This function completes stage 1 of the inject. It is invoked when code to
152  * mmap space for the real code has been injected and has completed. This mmap
153  * code will hypercall back into Placios, getting us here.
154  */
155 static int mmap_init_handler (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
156     struct v3_code_inject_info * inject = current_inject;
157     v3_restore_pre_mmap_state(core, inject);
158     return 0;
159 }
160
161
162 /* 
163  * This function is stage 3 of the injection process. It is invoked when the injected code 
164  * has run to completeion and run a hypercall at its tail to get back into the
165  * VMM. After this, it only remains to unmap the space we injected it into (the
166  * 4th and final stage)
167  */
168 static int inject_code_finish (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
169     struct v3_code_inject_info * inject = current_inject;
170     addr_t hva;
171
172     // is the original int 80 page still paged in?
173     if (v3_gva_to_hva(core, 
174                         get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
175                         &hva) == -1) {
176         PrintError("No mapping in shadow page table: inject_code_finish\n");
177         return -1;
178     }
179
180     inject->old_code = V3_Malloc(MUNMAP_SIZE);
181     if (!inject->old_code) {
182         PrintError("Problem mallocing old code segment\n");
183         return -1;
184     }
185
186     // save old code and overwrite with munmap
187     v3_plant_code(core, inject, (char*)hva, munmap_code, MUNMAP_SIZE);
188
189     // set rbx with gva of code region
190     core->vm_regs.rbx = inject->code_region_gva;
191
192     // set rip back
193     core->rip = inject->rip;
194     return 0;
195 }
196
197
198 //
199 // this is 4th and final stage of the code injection process. It is invoked after code
200 // has been injected to run the munmap system call on our previosuly allocated
201 // memory chunk. It results in the clean
202 // up and removal of the current inject's structures and state, and its
203 // removal from any injection queues
204 // 
205 static int munmap_finish (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
206     struct v3_code_inject_info * inject = current_inject;
207     int i = 0;
208     addr_t hva;
209
210     if (core->vm_regs.rbx < 0) {
211         PrintError("Problem munmapping injected code\n");
212         return -1;
213     }
214
215     if (v3_gva_to_hva(core, 
216                         get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
217                         &hva) == -1) {
218         PrintError("No mapping in shadow page table: inject_code_finish\n");
219         return -1;
220     }
221
222     for (i = 0; i < MUNMAP_SIZE; i++) 
223         *(char*)(hva + i) = *(char*)(inject->old_code + i);
224
225     V3_Free(inject->old_code);
226
227     v3_restore_pre_inject_state(core, inject);
228
229     // clean up
230     v3_remove_code_inject(core->vm_info, inject);
231     current_inject = NULL;
232     
233     // raise the original int 80 again, causing an exec
234     return v3_raise_swintr(core, SW_INTR_SYSCALL_VEC);
235 }
236
237
238 /* 
239  * This function is comprises stage 2 of the injection process. Here, the
240  * injected code is copied one page at a time. Each time a new page must be
241  * copied, Palacios injects a page fault for it to bring it into the guest and
242  * host page tables. The fault address will be somewhere in our previously
243  * mmap'd region, but we will jump back to the same RIP every time, which
244  * contains the hypercall that invokes this function.
245  */
246 static int mmap_pf_handler (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
247     struct v3_code_inject_info * inject = current_inject;
248     pf_error_t err;
249     int i, offset = core->vm_regs.rbx;
250     addr_t hva, gva = core->vm_regs.rcx;
251     memset((void*)&err, 0, sizeof(pf_error_t));
252
253     // was page fault handled by guest kernel?
254         if (v3_gva_to_hva(core, 
255                                                 get_addr_linear(core, gva, &(core->segments.ds)),
256                                                 &hva) == -1) {
257         PrintError("No mapping in shadow page table: mmap_pf_handler\n");
258         return -1;
259     }
260     
261     if (offset >= inject->code_size) {
262         core->rip = gva - offset + inject->func_offset;
263
264         // restore registers (here, really just for sane ebp/esp)
265         memcpy(&core->vm_regs, &inject->regs, sizeof(struct v3_gprs));
266         memcpy(&core->ctrl_regs, &inject->ctrl_regs, sizeof(struct v3_ctrl_regs));
267
268         if (v3_gva_to_hva(core, 
269                             get_addr_linear(core, inject->rip, &(core->segments.cs)),
270                             &hva) == -1) {
271             PrintError("No mapping for old RIP in shadow page table: mmap_pf_handler: %p\n", (void*)inject->rip);
272             return -1;
273         }
274
275         // restore the hypercall with original int 80 code
276         for (i = 0; i < VMMCALL_SIZE; i++) 
277             *(char*)(hva + i) = *(char*)(inject->old_code + i);
278
279         V3_Free(inject->old_code);
280
281         if (v3_gva_to_hva(core, 
282                             get_addr_linear(core, core->rip, &(core->segments.cs)),
283                             &hva) == -1) {
284             PrintError("No mapping for new RIP in shadow page table: mmap_pf_handler: %p\n", (void*)core->rip);
285             return -1;
286         }
287
288         return 0;
289     }
290
291     // copy the next page of code
292     for (i = 0; i < PAGE_SIZE; i++) 
293         *(char*)(hva + i) = *(char*)(inject->code + offset + i);
294
295
296     core->vm_regs.rbx += PAGE_SIZE;
297     core->vm_regs.rcx += PAGE_SIZE;
298
299     // to account for rip being incremented by hcall handler
300     core->rip -= VMMCALL_SIZE;
301
302     // inject the page fault for next page
303     err.user = 1;
304     err.write = 1;
305     v3_inject_guest_pf(core, gva + PAGE_SIZE, err);
306
307     return 0;
308 }
309
310
311 static int init_code_inject (struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) {
312     struct v3_code_injects * injects = &code_injects;
313     INIT_LIST_HEAD(&(injects->code_inject_list));
314     INIT_LIST_HEAD(&(injects->hooked_code_injects));
315
316     injects->active = 1;
317
318     current_inject = NULL;
319
320     v3_register_hypercall(vm, 0xf000, mmap_init_handler, NULL);
321     v3_register_hypercall(vm, 0xf001, inject_code_finish, NULL);
322     v3_register_hypercall(vm, 0xf002, mmap_pf_handler, NULL);
323     v3_register_hypercall(vm, 0xf003, munmap_finish, NULL);
324     return 0;
325 }
326
327
328 static int deinit_code_inject (struct v3_vm_info * vm, void * priv_data) {
329     struct v3_code_injects * injects = &code_injects;
330     struct v3_code_inject_info * inject = NULL;
331     struct v3_code_inject_info * tmp = NULL;
332
333     list_for_each_entry_safe(inject, tmp, &(injects->code_inject_list), inject_node) {
334         free_code_inject(vm, inject); 
335     }
336
337     list_for_each_entry_safe(inject, tmp, &(injects->hooked_code_injects), inject_node) {
338         free_code_inject(vm, inject); 
339     }
340
341     v3_remove_hypercall(vm, 0xf000);
342     v3_remove_hypercall(vm, 0xf001);
343     v3_remove_hypercall(vm, 0xf002);
344     v3_remove_hypercall(vm, 0xf003);
345     return 0;
346 }
347
348
349
350
351 /* KCH currently unused */
352 /* this dynamic linking stuff will eventually be moved out of this file... */
353 static addr_t v3_get_dyn_entry (struct guest_info * core, addr_t elf_gva, addr_t elf_hva, 
354                                     int section_code) {
355     ElfW(Ehdr) *ehdr;
356     ElfW(Phdr) *phdr, *phdr_cursor;
357     ElfW(Dyn) *dyn = NULL;
358     int i, j, num_dyn;
359     addr_t hva;
360
361     ehdr = (ElfW(Ehdr)*)elf_hva;
362     phdr = (ElfW(Phdr)*)(elf_hva + ehdr->e_phoff);
363     phdr_cursor = phdr;
364
365     //PrintDebug("num phdrs: %d\n", ehdr->e_phnum);
366     for (i = 0; i < ehdr->e_phnum; i++, phdr_cursor++) {
367         if (phdr_cursor->p_type == PT_DYNAMIC) {
368             num_dyn = phdr_cursor->p_filesz / sizeof(ElfW(Dyn));
369             dyn = (ElfW(Dyn)*)(elf_hva + phdr_cursor->p_offset);
370
371             // make sure this addr is paged in 
372             if (v3_gva_to_gpa(core, elf_gva + phdr_cursor->p_offset, &hva) == -1) {
373                 PrintError("Dynamic segment isn't paged in\n");
374                 return 0;
375             }
376
377             for (j = 0; j < num_dyn; j++, dyn++) {
378                 if (dyn->d_tag == section_code) {
379                     switch (section_code) {
380                         case DT_STRSZ:
381                         case DT_SYMENT:
382                         case DT_PLTREL:
383                             return (addr_t)dyn->d_un.d_val;
384                         default:
385                             return (addr_t)dyn->d_un.d_ptr;
386                     }
387                 }
388             }
389             break;
390         }
391     }
392     return 0;
393 }
394
395
396 static int v3_do_resolve (struct guest_info * core, addr_t elf_gva, addr_t elf_hva) {
397
398     addr_t got_gva, symtab_gva, strtab_gva;
399
400     if ((got_gva = v3_get_dyn_entry(core, elf_gva, elf_hva, DT_PLTGOT)) == 0) {
401         PrintError("Problem getting at PLTGOT in v3_do_resolve\n");
402         return -1;
403     }
404
405
406     if ((strtab_gva = v3_get_dyn_entry(core, elf_gva, elf_hva, DT_STRTAB)) == 0) {
407         PrintError("Problem getting at PLTGOT in v3_do_resolve\n");
408         return -1;
409     }
410
411     if ((symtab_gva = v3_get_dyn_entry(core, elf_gva, elf_hva, DT_SYMTAB)) == 0) {
412         PrintError("Problem getting at PLTGOT in v3_do_resolve\n");
413         return -1;
414     }
415
416
417     PrintDebug("Got gva: %p\n", (void*)got_gva);
418     PrintDebug("Symtab gva: %p\n", (void*)symtab_gva);
419     PrintDebug("Strtab gva: %p\n", (void*)strtab_gva);
420     return 0;
421 }
422
423 static int v3_do_cont (struct guest_info * core, struct v3_code_inject_info * inject,  addr_t check) {
424
425     addr_t hva;
426     pf_error_t err_code;
427     int ret;
428
429     ret = v3_gva_to_gpa(core, check, &hva);
430
431     // page fault wasn't handled by kernel??
432     if (ret == -1) {
433         PrintError("ERROR: no mapping in guest page table!\n");
434         return -1;
435     }
436
437         ret = v3_gva_to_hva(core, 
438                                                 get_addr_linear(core, check, &(core->segments.cs)),
439                                                 &hva);
440
441     // this should never happen...
442         if (ret == -1) {
443         PrintError("ERROR: no mapping in shadow page table\n");
444         return -1;
445         }
446     
447     if (strncmp(elf_magic, (char*)hva, ELF_MAG_SIZE) != 0) {
448
449         check -= PAGE_SIZE;
450         inject->cont->check_addr = check;
451         inject->cont->cont_func = v3_do_cont;
452
453         memset((void*)&err_code, 0, sizeof(pf_error_t));
454         err_code.user = 1;
455
456         if (v3_inject_guest_pf(core, check, err_code) < 0) {
457             PrintError("Problem injecting pf\n");
458             return -1;
459         }
460
461         return E_NEED_PF;
462     }
463
464     PrintDebug("Found ELF!\n");
465     V3_Free(inject->cont);
466     inject->cont = NULL;
467     return v3_do_resolve(core, check, hva);
468 }
469  
470
471 /*
472  * mmap_state: 0 = no inject space in procces yet
473  *             1 = code segment space mmap'd, still need data
474  *             2 = code & data segments mmap'd, ready to inject real code
475  *
476  */
477 //
478 // return  E_NEED_PF up the call stack to signal page fault injection
479 // (so rip doesn't get incremented and sw_intr doesn't get injected
480 //
481 int v3_do_inject (struct guest_info * core, struct v3_code_inject_info * inject, int mmap_state) {
482         addr_t rip_hva, elf_hva, elf_gva;
483         int ret = 0, i = 0;
484     pf_error_t err_code;
485
486     memset((void*)&err_code, 0, sizeof(pf_error_t));
487         
488         ret = v3_gva_to_hva(core, 
489                                                 get_addr_linear(core, (addr_t)core->rip, &(core->segments.cs)),
490                                                 &rip_hva);
491         if (ret == -1) {
492                 PrintError("Error translating RIP address in v3_do_inject\n");
493                 return -1;
494         }
495
496     elf_gva = (addr_t)(core->rip & 0xfffffffffffff000);
497
498     for (i = 0; i < PAGES_BACK; i++, elf_gva -= PAGE_SIZE) {
499     
500         ret = v3_gva_to_hva(core, 
501                             get_addr_linear(core, elf_gva, &(core->segments.cs)),
502                             &elf_hva);
503
504         // need to page in
505         if (ret == -1) {
506
507             PrintDebug("Found a page we need to fault in\n");
508             inject->cont = (struct v3_cont *)V3_Malloc(sizeof(struct v3_cont));
509             ret = v3_gva_to_gpa(core, elf_gva, &elf_hva);
510
511             if (ret == -1) {
512                 PrintDebug("no mapping in guest page table\n");
513             }
514
515             inject->cont->check_addr = elf_gva;
516             inject->cont->cont_func = v3_do_cont;
517             err_code.user = 1;
518
519             PrintDebug("Injecting pf for addr: %p\n", (void*) elf_gva);
520
521             if (v3_inject_guest_pf(core, elf_gva, err_code) < 0) {
522                 PrintError("Problem injecting pf\n");
523                 return -1;
524             }
525
526             return E_NEED_PF;
527         }
528
529         if (strncmp(elf_magic, (char*)elf_hva, ELF_MAG_SIZE) == 0) {
530             PrintDebug("Found elf_magic!\n");
531             break;
532         }
533
534     }
535
536
537     V3_Free(inject->cont);
538     inject->cont = NULL;
539     return v3_do_resolve(core, elf_gva, elf_hva);
540
541     PrintDebug("Planting code\n");
542     v3_plant_code(core, inject, (char*)rip_hva, mmap_code, MMAP_SIZE);
543
544     PrintDebug("Saving register context\n");
545     PrintDebug("First 8 bytes 0x%lx\n", *(long*)rip_hva);
546     /* may need to save v3_ctrl registers too... */
547     memcpy(&inject->regs, &core->vm_regs, sizeof(struct v3_gprs));
548     inject->rip = core->rip;
549
550     /* jump to injected code */
551     PrintDebug("Jumping to injected code\n");
552         return 0;
553 }
554
555
556 /*
557  * mmap_state: NO_MMAP = no inject space mmap'd in procces yet
558  *             MMAP_COMPLETE = mmap complete, time to do real inject
559  *
560  */
561 int v3_do_static_inject (struct guest_info * core, struct v3_code_inject_info * inject,
562                          int mmap_state, addr_t region_gva) {
563         addr_t rip_hva;
564         int ret;
565
566         
567         ret = v3_gva_to_hva(core, 
568                                                 get_addr_linear(core, (addr_t)core->rip, &(core->segments.cs)),
569                                                 &rip_hva);
570         if (ret == -1) {
571                 PrintError("Error translating RIP address: v3_do_static_inject\n");
572                 return -1;
573         }
574
575     switch (mmap_state) { 
576         case NO_MMAP: 
577         {
578             // inject mmap code
579             v3_plant_code(core, inject, (char*)rip_hva, mmap_code, MMAP_SIZE);
580
581             // save registers (gprs and ctrl regs, and rip)
582             memcpy(&inject->regs, &core->vm_regs, sizeof(struct v3_gprs));
583             memcpy(&inject->ctrl_regs, &core->ctrl_regs, sizeof(struct v3_ctrl_regs));
584             inject->rip = core->rip;
585
586             // jump to mmap code, and squash original swintr
587             return E_NEED_PF;
588         }
589         case MMAP_COMPLETE:
590         {
591             pf_error_t err_code;
592             memset((void*)&err_code, 0, sizeof(pf_error_t));
593
594             ret = v3_gva_to_hva(core, 
595                                 get_addr_linear(core, (addr_t)inject->rip, &(core->segments.cs)),
596                                 &rip_hva);
597             if (ret == -1) {
598                 PrintError("Error translating RIP address: v3_do_static_inject\n");
599                 return -1;
600             }
601
602             // inject hypercall code
603             v3_plant_code(core, inject, (char*)rip_hva, vmmcall_code, VMMCALL_SIZE);
604
605             /* store current copy offset in rbx, fault gva in rcx */
606             core->vm_regs.rbx = 0;
607             core->vm_regs.rcx = region_gva;
608
609             err_code.user = 1;
610             err_code.write = 1;
611
612             // inject the first page fault for the code block
613             if (v3_inject_guest_pf(core, region_gva, err_code) < 0) {
614                 PrintError("Problem injecting page fault in v3_do_static_inject\n");
615                 return -1;
616             }
617
618             // returning here will run hypercall 0xf002
619             // This will get us back in v3_mmap_pf_handler
620             core->rip = inject->rip;
621             return 0;
622         }
623         default:
624             PrintError("Invalid mmap state\n");
625             return -1;
626     }
627         return 0;
628 }
629
630
631 /*
632  * This function is invoked in one of two ways:
633  * 1. A syscall has been intercepted and we've popped off the next pending
634  * inject
635  * 2. An exec has been intercepted and we've popped off the next hooked inject
636  *
637  */
638 int v3_handle_guest_inject (struct guest_info * core, void * priv_data) {
639     struct v3_code_inject_info * inject = (struct v3_code_inject_info *)priv_data;
640
641     /* eventually this should turn into a mutex lock */
642     if (current_inject) {
643         PrintError("An inject is already in progress\n");
644         return -1;
645     } else {
646         current_inject = inject;
647         inject->in_progress = 1;
648     }
649
650     if (!inject->is_dyn) {
651         return v3_do_static_inject(core, inject, 0, (addr_t)NULL);
652     } else {
653         if (inject->cont) 
654            return inject->cont->cont_func(core, inject, inject->cont->check_addr);
655         else 
656            return v3_do_inject(core, inject, 0);
657     }
658
659     return 0;
660 }
661
662
663 int v3_insert_code_inject (void * ginfo, void * code, int size, 
664                            char * bin_file, int is_dyn, int is_exec_hooked, int func_offset) {
665     struct v3_code_injects * injects = &code_injects;
666     struct v3_vm_info * vm = (struct v3_vm_info *)ginfo;
667     struct v3_code_inject_info * inject;
668
669     if (!injects->active) {
670         PrintError("Code injection has not been initialized\n");
671         return -1;
672     }
673
674     inject = V3_Malloc(sizeof(struct v3_code_inject_info));
675     if (!inject) {
676         PrintError("Error allocating inject info in v3_insert_code_inject\n");
677         return -1;
678     }
679
680     memset(inject, 0, sizeof(struct v3_code_inject_info));
681
682     inject->code = code;
683     inject->code_size = size;
684     inject->is_dyn = is_dyn;
685     inject->func_offset = func_offset;
686     inject->bin_file = bin_file;
687     inject->is_exec_hooked = is_exec_hooked;
688
689     if (is_exec_hooked) {
690         v3_hook_executable(vm, bin_file, v3_handle_guest_inject, (void*)inject);
691         list_add_tail(&(inject->inject_node), &(injects->hooked_code_injects));
692     } else {
693         list_add_tail(&(inject->inject_node), &(injects->code_inject_list));
694     }
695
696     return 0;
697 }
698
699
700 int v3_remove_code_inject (struct v3_vm_info * vm, struct v3_code_inject_info * inject) {
701
702     PrintDebug("Removing and freeing code inject\n");
703     if (inject->is_exec_hooked) {
704         if (v3_unhook_executable(vm, inject->bin_file) < 0) {
705             PrintError("Problem unhooking executable in v3_remove_code_inject\n");
706             return -1;
707         }
708     }
709
710     free_code_inject(vm, inject);
711     return 0;
712 }
713
714
715 static struct v3_extension_impl code_inject_impl = {
716         .name = "code_inject",
717         .init = init_code_inject,
718         .deinit = deinit_code_inject,
719         .core_init = NULL,
720         .core_deinit = NULL,
721         .on_entry = NULL,
722         .on_exit = NULL
723 };
724 register_extension(&code_inject_impl);
725