2 * Copyright (C) 2010 gonzoj
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/ptrace.h>
26 #include "elf_utils.h"
27 #include "proc_utils.h"
28 #include "ptrace_utils.h"
34 char *module_to_load
= NULL
;
38 char *libc_path
= NULL
;
40 Elf32_Off malloc_off
= 0;
41 Elf32_Off free_off
= 0;
42 Elf32_Off dlopen_off
= 0;
43 Elf32_Off dlclose_off
= 0;
46 resolve_symbol_generic(vaddr_t base
, const char *symbol
, vaddr_t
*resolved
)
48 if (elf_is_valid(base
))
51 if (elf_read_ehdr(base
, ehdr
))
53 if (ehdr
.e_type
== ET_DYN
)
55 vaddr_t phdr_table
= base
+ ehdr
.e_phoff
;
57 for (i
= 0; i
< ehdr
.e_phnum
* ehdr
.e_phentsize
; i
61 if (elf_read_phdr(phdr_table
+ i
, phdr
))
63 if (phdr
.p_type
== PT_DYNAMIC
)
65 vaddr_t dyn_section
= base
+ phdr
.p_offset
;
66 Elf32_Off dyn_off
= 0;
67 vaddr_t symtab
= 0, strtab
= 0;
72 if (!elf_read_dyn(dyn_section
+ dyn_off
, dyn
))
76 dyn_off
+= sizeof(Elf32_Dyn
);
77 if (dyn
.d_tag
== DT_SYMTAB
)
80 = ((vaddr_t
) dyn
.d_un
.d_ptr
< base
) ? base
82 : (vaddr_t
) dyn
.d_un
.d_ptr
;
84 else if (dyn
.d_tag
== DT_STRTAB
)
87 = ((vaddr_t
) dyn
.d_un
.d_ptr
< base
) ? base
89 : (vaddr_t
) dyn
.d_un
.d_ptr
;
91 else if (dyn
.d_tag
== DT_HASH
)
93 vaddr_t hash
= ((vaddr_t
) dyn
.d_un
.d_ptr
94 < base
) ? base
+ dyn
.d_un
.d_ptr
95 : (vaddr_t
) dyn
.d_un
.d_ptr
;
96 if (!elf_read(hash
+ sizeof(Elf32_Word
),
97 &nchain
, sizeof(Elf32_Word
)))
103 while (dyn
.d_tag
!= DT_NULL
&& !(symtab
&& strtab
105 if (symtab
&& strtab
&& nchain
)
108 for (j
= 0; j
< nchain
* sizeof(Elf32_Sym
); j
109 += sizeof(Elf32_Sym
))
112 if (elf_read_sym(symtab
+ j
, sym
))
114 if (sym
.st_name
!= 0)
116 char *sym_name
= elf_read_string(
117 strtab
+ sym
.st_name
);
120 if (strcmp(symbol
, sym_name
) == 0)
123 = ((vaddr_t
) sym
.st_value
126 : (vaddr_t
) sym
.st_value
;
144 resolve_symbol_dumb(const char *object
, const char *symbol
, vaddr_t
*resolved
)
146 char *cmd
= (char *) malloc(strlen("readelf -s ") + strlen(object
) + strlen(
147 " | grep ") + strlen(symbol
) + 1);
150 printf("err: %s\n", strerror(errno
));
153 sprintf(cmd
, "readelf -s %s | grep %s", object
, symbol
);
154 FILE *output
= popen(cmd
, "r");
157 printf("err: %s\n", strerror(errno
));
162 while ((line
= read_line(output
)))
164 if (strstr(line
, "GLOBAL"))
168 char *tmp
= strtok(NULL
, " ");
171 sscanf(tmp
, "%x", &off
);
177 char *sym
= strtok(NULL
, "@");
180 if (strcmp(symbol
, sym
) == 0)
183 if (proc_get_object_base(object
, &base
))
185 *resolved
= base
+ off
;
201 load_module(const char *module
, vaddr_t patch
, vaddr_t sym__libc_dlopen_mode
,
202 vaddr_t sym_malloc
, vaddr_t sym_free
)
206 struct user_regs_struct regs_backup
;
207 struct user_regs_struct regs
;
209 if (ptrace(PTRACE_GETREGS
, pid
, NULL
, ®s_backup
) == -1)
211 printf("err: %s\n", strerror(errno
));
214 memcpy(®s
, ®s_backup
, sizeof(struct user_regs_struct
));
217 size_t patch_size
= ALIGN_SIZE(call_malloc_STUB_size
)
218 + ALIGN_SIZE(call_free_STUB_size
)
219 + ALIGN_SIZE(call_libc_dlopen_mode_STUB_size
);
220 if ((patch_backup
= ptrace_read(patch
, patch_size
)) == NULL
)
222 printf("err: could not backup original code\n");
225 vaddr_t free_stub
= patch
+ ALIGN_SIZE(call_malloc_STUB_size
);
226 vaddr_t libc_dlopen_mode_stub
= free_stub
+ ALIGN_SIZE(call_free_STUB_size
);
227 if (!ptrace_write(patch
, call_malloc_STUB
, call_malloc_STUB_size
))
229 printf("err: could not patch in malloc stub\n");
232 if (!ptrace_write(free_stub
, call_free_STUB
, call_free_STUB_size
))
234 printf("err: could not patch in free stub\n");
237 if (!ptrace_write(libc_dlopen_mode_stub
, call_libc_dlopen_mode_STUB
,
238 call_libc_dlopen_mode_STUB_size
))
240 printf("err: could not patch in __libc_dlopen_mode stub\n");
244 regs
.eax
= (long) sym_malloc
;
245 regs
.ecx
= (long) ALIGN_SIZE(strlen(module
) + 1);
246 vaddr_t module_string
= ptrace_call(patch
, ®s
);
247 if (module_string
== NULL
)
249 printf("err: allocating memory for module name failed\n");
252 if (!ptrace_write(module_string
, (void *) module
, strlen(module
) + 1))
254 printf("err: failed to write module name\n");
258 regs
.eax
= (long) sym__libc_dlopen_mode
;
259 regs
.ecx
= (long) RTLD_LAZY
| 0x80000000;
260 regs
.edx
= (long) module_string
;
261 success
= (long) ptrace_call(libc_dlopen_mode_stub
, ®s
);
263 cleanup
: regs
.eax
= (long) sym_free
;
264 regs
.ecx
= (long) module_string
;
265 ptrace_call(free_stub
, ®s
);
267 backup
: if (!ptrace_write(patch
, patch_backup
, patch_size
))
269 printf("err: failed to restore original code\n");
272 if (ptrace(PTRACE_SETREGS
, pid
, NULL
, ®s_backup
) == -1)
274 printf("err: %s\n", strerror(errno
));
282 unload_module(const char *module
, vaddr_t patch
, vaddr_t sym__libc_dlclose
,
283 vaddr_t sym__libc_dlopen_mode
, vaddr_t sym_malloc
, vaddr_t sym_free
)
285 struct user_regs_struct regs_backup
;
286 struct user_regs_struct regs
;
288 if (ptrace(PTRACE_GETREGS
, pid
, NULL
, ®s_backup
) == -1)
290 printf("err: %s\n", strerror(errno
));
293 memcpy(®s
, ®s_backup
, sizeof(struct user_regs_struct
));
296 size_t patch_size
= ALIGN_SIZE(call_malloc_STUB_size
)
297 + ALIGN_SIZE(call_free_STUB_size
)
298 + ALIGN_SIZE(call_libc_dlopen_mode_STUB_size
)
299 + ALIGN_SIZE(call_libc_dlclose_STUB_size
);
300 if ((patch_backup
= ptrace_read(patch
, patch_size
)) == NULL
)
302 printf("err: could not backup original code\n");
305 vaddr_t free_stub
= patch
+ ALIGN_SIZE(call_malloc_STUB_size
);
306 vaddr_t libc_dlopen_mode_stub
= free_stub
+ ALIGN_SIZE(call_free_STUB_size
);
307 vaddr_t libc_dlclose_stub
= libc_dlopen_mode_stub
308 + ALIGN_SIZE(call_libc_dlopen_mode_STUB_size
);
309 if (!ptrace_write(patch
, call_malloc_STUB
, call_malloc_STUB_size
))
311 printf("err: could not patch in malloc stub\n");
314 if (!ptrace_write(free_stub
, call_free_STUB
, call_free_STUB_size
))
316 printf("err: could not patch in free stub\n");
319 if (!ptrace_write(libc_dlopen_mode_stub
, call_libc_dlopen_mode_STUB
,
320 call_libc_dlopen_mode_STUB_size
))
322 printf("err: could not patch in __libc_dlopen_mode stub\n");
325 if (!ptrace_write(libc_dlclose_stub
, call_libc_dlclose_STUB
,
326 call_libc_dlclose_STUB_size
))
328 printf("err: could not patch in __libc_dlclose stub\n");
332 regs
.eax
= (long) sym_malloc
;
333 regs
.ecx
= (long) ALIGN_SIZE(strlen(module
) + 1);
334 vaddr_t module_string
= ptrace_call(patch
, ®s
);
335 if (module_string
== NULL
)
337 printf("err: could not allocate memory for module name\n");
340 if (!ptrace_write(module_string
, (void *) module
, strlen(module
) + 1))
342 printf("err: failed to write module name\n");
346 regs
.eax
= (long) sym__libc_dlopen_mode
;
347 regs
.ecx
= (long) RTLD_LAZY
| 0x80000000;
348 regs
.edx
= (long) module_string
;
349 void *handle
= ptrace_call(libc_dlopen_mode_stub
, ®s
);
352 printf("err: could not get a handle for %s\n", module
);
358 while (proc_get_object_base(module
, &base
))
360 regs
.eax
= (long) sym__libc_dlclose
;
361 regs
.ecx
= (long) handle
;
362 if (ptrace_call(libc_dlclose_stub
, ®s
))
364 printf("err: __libc_dlclose returned with error\n");
370 cleanup
: regs
.eax
= (long) sym_free
;
371 regs
.ecx
= (long) module_string
;
372 ptrace_call(free_stub
, ®s
);
374 backup
: if (!ptrace_write(patch
, patch_backup
, patch_size
))
378 if (ptrace(PTRACE_SETREGS
, pid
, NULL
, ®s_backup
) == -1)
380 printf("err: %s\n", strerror(errno
));
388 parse_arguments(int argc
, char **argv
)
390 struct option long_options
[] =
392 { "libc", required_argument
, 0, 'a' },
393 { "malloc", required_argument
, 0, 'b' },
394 { "free", required_argument
, 0, 'c' },
395 { "dlopen", required_argument
, 0, 'd' },
396 { "dlclose", required_argument
, 0, 'e' },
398 while (optind
< argc
)
401 int result
= getopt_long(argc
, argv
, "hiu", long_options
, &index
);
409 libc_path
= (char *) malloc(strlen(optarg
) + 1);
410 if (libc_path
== NULL
)
412 printf("err: %s\n", strerror(errno
));
415 strcpy(libc_path
, optarg
);
418 if (!sscanf(optarg
, "%lx", (long unsigned *) &malloc_off
))
424 if (!sscanf(optarg
, "%lx", (long unsigned *) &free_off
))
430 if (!sscanf(optarg
, "%lx", (long unsigned *) &dlopen_off
))
436 if (!sscanf(optarg
, "%lx", (long unsigned *) &dlclose_off
))
448 printf("err: unknown parameter\n");
451 printf("err: missing argument\n");
455 if (argc
- optind
< 2)
459 if (!sscanf(argv
[optind
++], "%i", &pid
))
463 module_to_load
= (char *) malloc(strlen(argv
[optind
]) + 1);
464 strcpy(module_to_load
, argv
[optind
++]);
473 printf(" surgeon [OPTION]... PID MODULE\n");
475 printf(" OPTIONS:\n");
476 printf(" -h display usage\n");
477 printf(" -i inject MODULE into process PID (default)\n");
478 printf(" -u unload MODULE from process PID\n");
479 printf(" --libc=PATH set location of libc to PATH\n");
480 printf(" --malloc=OFFSET set offset for symbol malloc to OFFSET\n");
481 printf(" --free=OFFSET set offset for symbol free to OFFSET\n");
483 " --dlopen=OFFSET set offset for symbol __libc_dlopen_mode to OFFSET\n");
485 " --dlclose=OFFSET set offset for symbol __libc_dlclose to OFFSET\n");
490 main(int argc
, char **argv
)
492 if (!parse_arguments(argc
, argv
))
498 if (ptrace(PTRACE_ATTACH
, pid
, NULL
, NULL
) == -1)
500 printf("err: could not attach to process %i (%s)\n", pid
, strerror(errno
));
504 vaddr_t libc_base
= 0, patch
= 0, p_malloc
= 0, p_free
= 0, p_dlopen
= 0,
509 proc_get_object_base(libc_path
, &libc_base
);
513 proc_get_object_base("libc-", &libc_base
);
518 if (libc_path
== NULL
)
520 libc_path
= proc_get_object_path(libc_base
);
524 p_malloc
= libc_base
+ malloc_off
;
526 else if (!resolve_symbol_generic(libc_base
, "malloc", &p_malloc
))
530 resolve_symbol_dumb(libc_path
, "malloc", &p_malloc
);
535 p_free
= libc_base
+ free_off
;
537 else if (!resolve_symbol_generic(libc_base
, "free", &p_free
))
541 resolve_symbol_dumb(libc_path
, "free", &p_free
);
546 p_dlopen
= libc_base
+ dlopen_off
;
548 else if (!resolve_symbol_generic(libc_base
, "__libc_dlopen_mode",
553 resolve_symbol_dumb(libc_path
, "__libc_dlopen_mode", &p_dlopen
);
556 if (dlclose_off
&& action
== 'u')
558 p_dlclose
= libc_base
+ dlclose_off
;
560 else if (!resolve_symbol_generic(libc_base
, "__libc_dlclose", &p_dlclose
)
565 resolve_symbol_dumb(libc_path
, "__libc_dlclose", &p_dlclose
);
572 while (proc_iterate_addrspace(&addr
))
576 resolve_symbol_generic(addr
, "malloc", &p_malloc
);
580 resolve_symbol_generic(addr
, "free", &p_free
);
584 resolve_symbol_generic(addr
, "__libc_dlopen_mode", &p_dlopen
);
586 if (action
== 'u' && !p_dlclose
)
588 resolve_symbol_generic(addr
, "__libc_dlclose", &p_dlclose
);
593 char *bin
= proc_get_executable();
596 proc_get_object_base(bin
, &patch
);
599 if (!(patch
&& p_malloc
&& p_free
&& p_dlopen
&& (action
== 'i' || p_dlclose
)))
601 printf("err: could not resolve all necessary symbols\n");
602 ptrace(PTRACE_DETACH
, pid
, NULL
, NULL
);
611 printf("injecting module %s into process %i\n", module_to_load
, pid
);
613 = load_module(module_to_load
, patch
, p_dlopen
, p_malloc
, p_free
);
616 printf("err: failed to load module %s\n", module_to_load
);
620 printf("successfully injected module %s\n", module_to_load
);
624 printf("unloading module %s from process %i\n", module_to_load
, pid
);
625 success
= unload_module(module_to_load
, patch
, p_dlclose
, p_dlopen
,
629 printf("err: failed to unload module %s\n", module_to_load
);
633 printf("successfully unloaded module %s\n", module_to_load
);
639 ptrace(PTRACE_DETACH
, pid
, NULL
, NULL
);
644 ptrace(PTRACE_DETACH
, pid
, NULL
, NULL
);