Codebase list hotpatch / 2d1cd54
Imported Upstream version 0.2 Devon Kearns 11 years ago
26 changed file(s) with 4554 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Vikas Naresh Kumar <[email protected]>
1 Selective Intellect LLC <[email protected]>
0 ### hotpatch is a dll injection strategy
1 ### Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
2 ### All rights reserved.
3 ###
4 ### Redistribution and use in source and binary forms, with or without
5 ### modification, are permitted provided that the following conditions are met:
6 ###
7 ### * Redistributions of source code must retain the above copyright
8 ### notice, this list of conditions and the following disclaimer.
9 ###
10 ### * Redistributions in binary form must reproduce the above copyright
11 ### notice, this list of conditions and the following disclaimer in the
12 ### documentation and/or other materials provided with the distribution.
13 ###
14 ### * Neither the name of Selective Intellect LLC nor the
15 ### names of its contributors may be used to endorse or promote products
16 ### derived from this software without specific prior written permission.
17 ###
18 ### THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ### WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 ### DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22 ### DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 ### (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 ### LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ### ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 ### (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 ### SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 ###
29 cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
30
31 option(DEBUG "In Debug mode" ON)
32 option(USE_ASM "Use Assembler" OFF)
33 if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
34 set(DEBUG OFF)
35 endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
36
37 if (CMAKE_COMPILER_IS_GNUCC)
38 if (ARCH)
39 if (ARCH STREQUAL "x86_64")
40 message(STATUS "Compiling for ${ARCH} 64-bit")
41 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64")
42 set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -m64")
43 else (ARCH STREQUAL "x86_64")
44 message(STATUS "Compiling for ${ARCH} 32-bit")
45 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
46 set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -m32")
47 endif (ARCH STREQUAL "x86_64")
48 endif (ARCH)
49 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fPIC -pedantic -ansi -posix")
50 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -fno-inline")
51 set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
52 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fPIC -pedantic -ansi -posix")
53 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -fno-inline")
54 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
55 endif (CMAKE_COMPILER_IS_GNUCC)
56 include(CTest)
57 include(CheckFunctionExists)
58 include(CheckIncludeFile)
59 include(CheckIncludeFiles)
60 include(CheckSymbolExists)
61 include(CheckTypeSize)
62 if (WIN32 OR APPLE)
63 message(FATAL_ERROR "Windows or Mac OSX is not supported")
64 endif (WIN32 OR APPLE)
65 check_include_file("features.h" HOTPATCH_HAS_FEATURES_H)
66 check_include_file("errno.h" HOTPATCH_HAS_ERRNO_H)
67 check_include_file("stdio.h" HOTPATCH_HAS_STDIO_H)
68 check_include_file("stdlib.h" HOTPATCH_HAS_STDLIB_H)
69 check_include_file("string.h" HOTPATCH_HAS_STRING_H)
70 check_function_exists("strnlen" HOTPATCH_HAS_STRNLEN_FN)
71 check_function_exists("strtok_r" HOTPATCH_HAS_STRTOKR_FN)
72 check_include_file("stddef.h" HOTPATCH_HAS_STDDEF_H)
73 check_include_file("stdint.h" HOTPATCH_HAS_STDINT_H)
74 check_include_file("stdarg.h" HOTPATCH_HAS_STDARG_H)
75 check_include_file("stdbool.h" HOTPATCH_HAS_STDBOOL_H)
76 check_include_file("time.h" HOTPATCH_HAS_TIME_H)
77 check_include_file("sys/time.h" HOTPATCH_HAS_SYS_TIME_H)
78 check_include_file("sys/types.h" HOTPATCH_HAS_SYS_TYPES_H)
79 check_include_file("unistd.h" HOTPATCH_HAS_UNISTD_H)
80 check_include_file("assert.h" HOTPATCH_HAS_ASSERT_H)
81 check_include_file("limits.h" HOTPATCH_HAS_LIMITS_H)
82 if (UNIX AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
83 check_include_file("elf.h" HOTPATCH_HAS_LINUX_ELF_H)
84 check_include_file("dlfcn.h" HOTPATCH_HAS_LINUX_DLFCN_H)
85 if (HOTPATCH_HAS_LINUX_DLFCN_H)
86 set(HOTPATCH_OTHER_LIBS ${HOTPATCH_OTHER_LIBS} dl)
87 endif (HOTPATCH_HAS_LINUX_DLFCN_H)
88 check_include_file("link.h" HOTPATCH_HAS_LINUX_LINK_H)
89 check_include_file("pthread.h" HOTPATCH_HAS_LINUX_PTHREAD_H)
90 if (HOTPATCH_HAS_LINUX_PTHREAD_H)
91 set(HOTPATCH_OTHER_LIBS ${HOTPATCH_OTHER_LIBS} pthread)
92 endif (HOTPATCH_HAS_LINUX_PTHREAD_H)
93 check_include_file("setjmp.h" HOTPATCH_HAS_LINUX_SETJMP_H)
94 check_include_file("signal.h" HOTPATCH_HAS_LINUX_SIGNAL_H)
95 check_include_file("sys/ptrace.h" HOTPATCH_HAS_LINUX_SYS_PTRACE_H)
96 check_include_file("sys/wait.h" HOTPATCH_HAS_LINUX_SYS_WAIT_H)
97 check_include_file("sys/stat.h" HOTPATCH_HAS_LINUX_SYS_STAT_H)
98 check_include_file("fcntl.h" HOTPATCH_HAS_LINUX_FCNTL_H)
99 check_include_file("sys/syscall.h" HOTPATCH_HAS_LINUX_SYS_SYSCALL_H)
100 check_include_files("sys/types.h;sys/user.h" HOTPATCH_HAS_LINUX_SYS_USER_H)
101 check_function_exists("dl_iterate_phdr" HOTPATCH_HAS_LINUX_DLITERPHDR_FN)
102 check_type_size("void *" HOTPATCH_VOIDPTR_SIZE)
103 if (NOT HAVE_HOTPATCH_VOIDPTR_SIZE)
104 message(FATAL_ERROR "(void *) does not seem to be supported.")
105 endif (NOT HAVE_HOTPATCH_VOIDPTR_SIZE)
106 ## Find assemblers
107 if (USE_ASM)
108 include(FindPerl)
109 find_file(HOTPATCH_NASM nasm)
110 if (HOTPATCH_NASM MATCHES "-NOTFOUND")
111 message(STATUS "Found nasm - not found")
112 set(HOTPATCH_HAS_NASM 0)
113 else (HOTPATCH_NASM MATCHES "-NOTFOUND")
114 message(STATUS "Found nasm - ${HOTPATCH_NASM}")
115 set(HOTPATCH_HAS_NASM 1)
116 endif (HOTPATCH_NASM MATCHES "-NOTFOUND")
117 find_file(HOTPATCH_YASM yasm)
118 if (HOTPATCH_YASM MATCHES "-NOTFOUND")
119 message(STATUS "Found yasm - no")
120 set(HOTPATCH_HAS_YASM 1)
121 else (HOTPATCH_YASM MATCHES "-NOTFOUND")
122 message(STATUS "Found yasm - ${HOTPATCH_YASM}")
123 set(HOTPATCH_HAS_YASM 1)
124 endif (HOTPATCH_YASM MATCHES "-NOTFOUND")
125 if (HOTPATCH_HAS_NASM OR HOTPATCH_HAS_YASM)
126 if (HOTPATCH_HAS_NASM)
127 message(STATUS "Using nasm - yes")
128 message(STATUS "Using yasm - no")
129 set(HOTPATCH_ASM ${HOTPATCH_NASM} CACHE INTERNAL "" FORCE)
130 else (HOTPATCH_HAS_NASM)
131 message(STATUS "Using nasm - no")
132 message(STATUS "Using yasm - yes")
133 set(HOTPATCH_ASM ${HOTPATCH_YASM} CACHE INTERNAL "" FORCE)
134 endif (HOTPATCH_HAS_NASM)
135 else (HOTPATCH_HAS_NASM OR HOTPATCH_HAS_YASM)
136 message(FATAL_ERROR "Unable to find nasm or yasm."
137 " Please install nasm or yasm or both and make it available in the"
138 " PATH")
139 endif (HOTPATCH_HAS_NASM OR HOTPATCH_HAS_YASM)
140 set(HOTPATCH_USE_ASM 1)
141 endif (USE_ASM)
142 endif (UNIX AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
143
144 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
145 include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
146 add_subdirectory(include)
147 add_subdirectory(src)
148 add_subdirectory(test)
0 Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
1 All rights reserved.
2
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12
13 * Neither the name of Selective Intellect LLC nor the
14 names of its contributors may be used to endorse or promote products
15 derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0 HOTPATCH INSTALLATION
1 ======================
2
3 Pre-requisites:
4
5 1. CMake: You need to have cmake 2.6 or above installed.
6 2. Compilers: gcc is needed along with standard headers.
7 3. GNU Make: make is needed to build the code.
8
9
10 How to install:
11
12 Release build:
13
14 $ make
15 $ make test
16 $ make install
17
18 By default make will try to install in /usr/local. If you want your custom
19 directory then you can do the following:
20
21 $ make install PREFIX=/path/to/install
22
23 If you're on a 64-bit system and want to compile for 32-bit, you can do the
24 following:
25
26 $ make ARCH=i386
27 $ make test ARCH=i386
28 $ make install ARCH=i386
29
30 Debug build:
31
32 $ make debug
33 $ make testdebug
34 $ make installdebug
35
36 By default make will try to install in /usr/local. If you want your custom
37 directory then you can do the following:
38
39 $ make installdebug PREFIX=/path/to/install
40
41 If you're on a 64-bit system and want to compile for 32-bit, you can do the
42 following:
43
44 $ make debug ARCH=i386
45 $ make testdebug ARCH=i386
46 $ make installdebug ARCH=i386
0 ### hotpatch is a dll injection strategy
1 ### Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
2 ### All rights reserved.
3 ###
4 ### Redistribution and use in source and binary forms, with or without
5 ### modification, are permitted provided that the following conditions are met:
6 ###
7 ### * Redistributions of source code must retain the above copyright
8 ### notice, this list of conditions and the following disclaimer.
9 ###
10 ### * Redistributions in binary form must reproduce the above copyright
11 ### notice, this list of conditions and the following disclaimer in the
12 ### documentation and/or other materials provided with the distribution.
13 ###
14 ### * Neither the name of Selective Intellect LLC nor the
15 ### names of its contributors may be used to endorse or promote products
16 ### derived from this software without specific prior written permission.
17 ###
18 ### THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ### WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 ### DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22 ### DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 ### (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 ### LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ### ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 ### (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 ### SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 ###
29 CMAKE=$(shell which cmake)
30 CTEST=$(shell which ctest)
31 PREFIX?=/usr
32 ARCH=$(shell uname -m)
33
34 default: release
35 .PHONY: default
36
37 all: release debug
38 .PHONY: all
39
40 clean: cleanrelease
41 .PHONY: clean
42
43 test: testrelease
44 .PHONY: test
45
46 install: installrelease
47 .PHONY: install
48
49 release:
50 @mkdir -p Release
51 @cd Release && $(CMAKE) -DARCH=$(ARCH) -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$(PREFIX) ..
52 @cd Release && $(MAKE)
53 @echo "Release Build complete"
54 .PHONY: release
55
56 debug:
57 @mkdir -p Debug
58 @cd Debug && $(CMAKE) -DARCH=$(ARCH) -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$(PREFIX) ..
59 @cd Debug && $(MAKE)
60 @echo "Debug Build complete"
61 .PHONY: debug
62
63 cleanrelease:
64 @if test -d Release; then cd Release && $(MAKE) clean; fi
65 @if test -d Release; then cd Release && rm -f CMakeCache.txt; fi
66 @if test -d Release; then echo "Release Cleaning complete"; else echo "Nothing to clean"; fi
67 .PHONY: cleanrelease
68
69 cleandebug:
70 @if test -d Debug; then cd Debug && $(MAKE) clean; fi
71 @if test -d Debug; then cd Debug && rm -f CMakeCache.txt; fi
72 @if test -d Debug; then echo "Debug Cleaning complete"; else echo "Nothing to clean"; fi
73 .PHONY: cleandebug
74
75 testrelease: release
76 cd Release && $(CTEST)
77 .PHONY: testrelease
78
79 testdebug: debug
80 cd Debug && $(CTEST)
81 .PHONY: testdebug
82
83 installrelease: release
84 @cd Release && $(CMAKE) -DARCH=$(ARCH) -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$(PREFIX) ..
85 @cd Release && $(MAKE) install
86 @echo "Release installation complete"
87 .PHONY: installrelease
88
89 installdebug: debug
90 @cd Debug && $(CMAKE) -DARCH=$(ARCH) -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$(PREFIX) ..
91 @cd Debug && $(MAKE) install
92 @echo "Debug installation complete"
93 .PHONY: installdebug
94
0 Introduction to Hotpatch
1 =========================
2 Hotpatch is a library that can be used to dynamically load a shared library
3 (.so) file on Linux from one process into another already running process,
4 without affecting the execution of the target process. The API is a C API, but
5 also supported in C++.
6
7 The current version is 0.2.
8
9 The limitations, directions on how to use, and possible uses of hotpatch will be
10 explained in this document.
11
12 The main idea of hotpatch stems from the fact that in Linux, it is not easy to
13 load a library into another already running process. In Windows, there is an API
14 called CreateRemoteThread() that can load a library into another process very
15 easily with a couple of API calls. Hotpatch makes this functionality available
16 to Linux users and developers, with a single API call. Unlike other available
17 injection libraries, hotpatch restores the execution of the process to its
18 original state.
19
20 The user can do the following with hotpatch:
21 - load his/her own .so file into an already running process
22 - invoke a custom symbol/function in that .so file
23 - pass arguments to that function as long as it is serialized to the form of a
24 byte buffer and length of the buffer. This shall be explained more later.
25
26 Hotpatch is available as an API with a header file called "hotpatch.h" and a
27 .so file called "libhotpatch.so", and also a commandline application called
28 "hotpatcher" which can inject .so files into processes via the commandline
29 itself. Hotpatch also comes with a test .so called "libhotpatchtest.so"
30 which can be used via the commandline "hotpatcher" application to test out
31 the working of hotpatch on any system. The "libhotpatchtest.so" has a symbol
32 "mysym" that can be invoked, and it writes to the "/tmp/hotpatchtest.log" file
33 with the timestamp at which the .so file was injected and anything else.
34
35 Limitations
36 ============
37 NOTE: Currently if hotpatch is compiled in 64-bit mode, it can inject libraries
38 only in 64-bit processes, and if compiled in 32-bit mode can inject libraries
39 only in 32-bit processes. It cannot inject from a 64-bit to a 32-bit process or
40 from a 32-bit to a 64-bit process.
41
42 There are some limitations, the main being that the user can inject a library
43 .so file only in a process on which the user has privileges over. For example,
44 as the root user, hotpatch can inject libraries into any process, but as a
45 regular non-root user, hotpatch can inject libraries into only those processes
46 that hotpatch has access to, i.e. the user's processes and any other via sudo
47 privileges.
48
49 The other limitation is that if the user needs to compile his shared library
50 with the linker options "-fPIC -nostartfiles" so that hotpatch can reliably load
51 the .so file.
52
53 Another limitation is that injection for a particular .so file can happen only
54 once in the target process. Each library that is injected can be injected only
55 once into the target process.
56
57 Usage: API
58 ===========
59
60 The "hotpatch.h" header file needs to be included by the user. There are 3 main
61 API calls that matter. Each of them have to be called in the order as shown
62 below in the sample program.
63
64 - hotpatch_t *hotpatch_create(pid_t pid, int verbose);
65
66 This function takes a PID of the target process, and the verbosity level
67 (between 0 to 6), and returns an opaque object which contains further intimate
68 details about the process such as current library mappings, and locations of the
69 important functions needed for hotpatch to do its work.
70
71 - int hotpatch_inject_library(hotpatch_t *hp,
72 const char *sofile,
73 const char *symbol,
74 const unsigned char *data,
75 size_t datalen,
76 uintptr_t *out_addr,
77 uintptr_t *out_result);
78
79 This function takes the newly created hotpatch object, along with a path to the
80 shared library in the variable "sofile", the optional function "symbol" to invoke,
81 along with the serialized arguments to the function provided in "data" and
82 "datalen" which are also optional. The return address of where the library was
83 loaded is returned in "out_addr" and the return value of the invocation of
84 "symbol" is returned in "out_result". On success this returns 0 and on failure
85 returns -1.
86
87 The verbosity levels can be adjusted accordingly from 0 to 6 to see debugging
88 information for investigating errors.
89
90 The usefulness of the "data" and "datalen" parameters is extremely high. Suppose
91 the user has a custom function they want to invoke, and the arguments of the
92 function is a big struct or a class. The user can then write a wrapper function
93 that takes a serialized buffer of this struct/class along with the length of the
94 buffer and invoke that wrapper function. This wrapper function can then
95 deserialize this buffer into the struct/class as needed and call the actual
96 function that the user really wanted to invoke. This functionality is only
97 available by the API and not by the "hotpatcher" executable.
98
99 - void hotpatch_destroy(hotpatch_t *hp);
100
101 This function cleans up memory and resources used by the hotpatch opaque object.
102
103 Sample Program
104 ==============
105
106 #include <hotpatch.h>
107
108 int main(int argc, char **argv)
109 {
110 pid_t pid = argc > 1 ? atoi(argv[1]) : 0;
111 hotpatch_t *hp = hotpatch_create(pid, 1);
112 if (hp) {
113 unsigned char *data = (unsigned char *)"my custom serialized data";
114 size_t datalen = strlen((char *)data) + 1;
115 uintptr_t result1, result2;
116 hotpatch_inject_library(hp, "libhotpatchtest.so", "mysym",
117 data, datalen, &result1, &result2);
118 hotpatch_destroy(hp);
119 }
120 return 0;
121 }
122
123 Usage: Hotpatcher
124 ==================
125
126 The commandline "hotpatcher" can be executed with the "-h" option to see the
127 various options that are supported.
128
129 A sample execution of "hotpatcher" into the current running shell can be done as
130 below:
131
132 Let's say the library libhotpatchtest.so is in the current directory.
133
134 bash> ./hotpatcher -l ./libhotpatchtest.so -s mysym -v1 $$
135
136 On success the "/tmp/hotpatchtest.log" file can be checked if it has the
137 timestamp of the injection.
138
139 Uses of Hotpatch
140 =================
141 Most uses of hotpatch are related to custom modifications of processes for which
142 the users do not have source code available.
143
144 - System administrators can use hotpatch to inject their own custom libraries in
145 already running processes and change behavior as per requirement. Some such
146 behavior could be adding a library that creates a thread and heartbeats to a
147 monitoring system.
148
149 - Many software applications, that are not mission critical, are not built with
150 mechanisms to update their software without having to stop the application and
151 restarting it. Hotpatch can help modify applications to restart and do other
152 fancy tricks without losing the PID and the other states such as file handles of
153 the applications that might be very useful or too risky to let go.
154
155 - Users can inject a library and then set up RPC service calls for the target
156 application without changing any code.
157
158 - Users can inject a library and with import table modifications can instrument
159 the target application for things like profiling, reverse engineering and also
160 debugging. This is useful as it does not necessarily need the application to be
161 recompiled and performance numbers can be extracted. The code to do import table
162 modifications is currently outside the scope of hotpatch.
163
164 - Users can create threads in other processes and make them work like a cluster
165 of processes that they control.
166
167 - Users can modify another application and make it perform better by doing
168 tricks in the injected code.
169
170 License & Copyright
171 ===================
172
173 The license/copyright can be found in the COPYRIGHT document in the source code.
174
175 ==THE END==
0
1 [------------------------------------------------------------------------]
2 [-- Uninformed Research -- informative information for the uninformed. --]
3 [------------------------------------------------------------------------]
4 [-- Genre : Development --]
5 [-- Name : needle --]
6 [-- Desc : Linux x86 run-time process manipulation --]
7 [-- Url : http://www.uninformed.org/ --]
8 [-- Use : EVILNESS --]
9 [------------------------------------------------------------------------]
10 [-- Author : skape ([email protected]) --]
11 [-- Date : 01/19/2003 --]
12 [------------------------------------------------------------------------]
13
14 [-- Table of contents: --]
15
16 1) Overview
17 1.1) Topics
18 1.2) Techniques
19 1.3) Execution Diversion
20 2) Memory Allocation
21 3) Memory Management
22 4) Library Injection
23 5) Code Injection
24 5.1) Forking
25 5.2) Threading
26 5.3) Function Trampolines
27 6) Conclusion
28 7) References
29
30 [-- 1) Overview --]
31
32 So, you want to be evil and modify the image of an executing
33 process? Well, perhaps you've come to the right place. This
34 document deals strictly with some methodologies used to to
35 alter process images under Linux. If you're curious about how
36 to do something similar to the things listed in this document in
37 Windows, please read the ``References`` section.
38
39 [-- 1.1) Topics --]
40
41 The following concepts will be discussed in this document as they
42 relate to run-time process manipulation:
43
44 * Memory Allocation
45
46 The use of being able to allocate and deallocate memory in a
47 running process from another process has awesome power for
48 such scenarios as execution diversion (the act of diverting
49 a processes execution to your own code), data hiding (the act
50 of hiding data in a process image), and even, in some cases
51 allocating dynamic structures/strings for use within a process
52 for its normal execution. These aren't the only uses, but
53 they're all I could think of right now :). See the
54 ``Memory Allocation`` section for details.
55
56 * Memory Management
57
58 The ability to copy arbitrary memory from one process to another
59 at arbitrary addresses allows for flexible manipulation of
60 a given processes memory image. This can be applied to copy
61 strings, functions, integers, everything. See the ``Memory
62 Management`` section for details.
63
64 * Library Injection
65
66 The ability to inject arbitrary shared objects into a process
67 allows for getting at symbols that an executable would not
68 normally have as well as allowing an evil-doer such as yourself
69 to inject arbitrary PIC that can reference symbols in
70 an executable without getting in trouble. This alone is
71 extremely powerful. See the ``Library Injection`` section for
72 details.
73
74 * Code Injection
75
76 Well, when you get down to it, you just want to execute code
77 in a given process that you define and you want to control
78 when it gets executed. Lucky for you, this is possible AND
79 just as powerful as you'd hoped. This document will cover
80 three types of code injection:
81
82 1) Forking
83
84 The act of causing a process to create a child image
85 and execute arbitrary code.
86
87 2) Threading
88
89 The act of causing a process to create a thread
90 that executes an arbitrary function.
91
92 3) Function Trampolines
93
94 The act of causing a call to a given function to
95 'trampoline' to arbitrary code and then 'jump' back to
96 the original function.
97
98 [-- 1.2) Techniques --]
99
100 As of this document I'm aware of two plausible techniques for
101 altering the image of an executing process:
102
103 * ptrace
104
105 Likely the most obvious technique, the ptrace (process trace) API
106 allows for altering of memory, reading of memory, looking and
107 setting registers, as well as single-stepping through a process.
108 The application for these things as it pertains to this document
109 should be obvious. If not, or if you're curious, read the
110 ``References`` section for more details on ptrace.
111
112 * /proc/[pid]/mem
113
114 This technique is more limited in the amount of things it can
115 do but is by no means something that should be cast aside.
116 With the ability to read/write a given process's image, one
117 could easily modify the image to do ``Code Injection``. Doing
118 things like memory allocation, management, and library
119 injection via this method are quote a means harder but *NOT*
120 impossible. They would take a decent amount of hackery though.
121 (Theoretical, not proven yet, by me at least.)
122
123 [-- 1.3) Execution Diversion --]
124
125 In order to do most of the techniques in this document we need to
126 divert the execution of a running process to code that we control.
127 This presents a few problems off the bat. Where can we safely put
128 the code that we want executed? How could we possibly change the
129 course of execution? How do we restore execution once our code
130 has finished? Well, thankfully, there are answers to these
131 questions, and they're pretty easy to answer. Let's start with
132 the first one.
133
134 * Where can we safely put the code that we want executed?
135
136 Well to answer this question you need to have a slight
137 understanding of how the process is laid out and how the flow of
138 execution goes. The basic tools you need in your knowledge base
139 are that executables have symbols, symbols map to vma's that are
140 used to tell the vm where symbols should be located in memory.
141 This is used not only for functions, but also for global variables.
142 With that said, we can tell where code will be in an executable
143 based off processing the ELF image associated with the process.
144 Example:
145
146 root@rd-linux:~# objdump --syms ./ownme | grep main
147 08048450 g F .text 00000082 main
148
149 This tells us that main will be found at 0x08048450 when the
150 program is executing. But what good does this do us? A lot.
151 Considering the main function is the 'gateway' to normal code
152 execution, it's an excellent place to use as a dumping zone for
153 arbitrary code. There are some restrictions, however. The code
154 has some size restrictions. Here's the preamble and some code
155 from main in ./ownme:
156
157 root@rd-linux:~# objdump --section=.text \
158 --start-address=0x08048450 --stop-address=0x080484d4 \
159 -d ./ownme
160
161 ./ownme: file format elf32-i386
162
163 Disassembly of section .text:
164
165 08048450 <main>:
166 8048450: 55 push %ebp
167 8048451: 89 e5 mov %esp,%ebp
168 8048453: 83 ec 08 sub $0x8,%esp
169 8048456: 90 nop
170 8048457: 90 nop
171 8048458: 90 nop
172 ...
173 80484d0: c9 leave
174 80484d1: c3 ret
175
176 Granted, main isn't always the entry point, but it's easy to find
177 out what is by the e_entry attribute of the elf header. Now, the
178 reason I say main is a great place to use as a dump zone is because
179 it holds code that will _never be accessed again_. This is the key.
180 There are lots of other places you could use as a dumpzone. For
181 instance, if the application contains a large helper banner, you
182 could put code over the help banner considering the banner wont be
183 printed ever again once the program is executing. Use your
184 imagination, you'll think of lots more. 'main' is the most
185 generic method, since it's guaranteed in every application.
186
187 Well, now we know where we can safely put code to be executed, but
188 how do we actually execute it?
189
190 * How could we possibly change the course of execution?
191
192 In order to change the course of execution in a process you need
193 some working knowledge of ptrace and how the vm traverses an
194 executable. Assuming you have both, read on. On x86 there
195 is a vm register used to hold the vma of the NEXT instruction.
196 Once an instruction finishes, the vm processes the instruction
197 at eip (the vm register) and increments eip by the size of the
198 current instruction. There are some instructions, such as jmp
199 and call which are themselves execution diversion functions
200 that cause eip to be changed to the address specified in the
201 operand. We use this same principal when it comes to changing
202 our course of execution to what we want.
203
204 Now, let's say that we theoretically put some of our own code
205 at 0x08048450 (the address of main above) using the functionality
206 from the ``Memory Management`` section. In order to have
207 our code get executed (since it would normally never get executed)
208 we use ptrace's PTRACE_SETREGS and PTRACE_GETREGS functionality.
209 These two methods allow a third party process to obtain the
210 registers and set the registers of another process. These
211 registers include eip. In order to change the execution we
212 perform the following steps:
213
214 1) call PTRACE_GETREGS to obtain the 'current' set of
215 registers.
216
217 2) set eip in the returned set of registers to
218 0x08048450 (the address of our code).
219
220 3) call PTRACE_SETREGS with our modified structure.
221
222 4) continue the course of execution.
223
224 We've now successfully caused our code to be executed, but there's
225 a problem. We injected a small chunk of code that we wanted
226 to be run, but then we wanted the process to return to normal
227 execution. That brings us to the next question.
228
229 * How do we restore execution once our code has finished?
230
231 Glad you asked, because this is the most important part. In order
232 to restore execution we need a to modify our injected code just
233 a bit in order to make it easy for us to restore execution. We
234 do this by adding an instruction near the end:
235
236 int $0x3
237
238 This is on Linux (and Windows) to signal an exception or breakpoint
239 to the active debugger. In the case of Linux, it sends a SIGTRAP,
240 which, if the process is being traced will be caught by wait().
241
242 Okay, so we've modified our code and let's say it looks something
243 like this:
244
245 nop
246 nop
247 nop
248 nop
249 nop
250 nop
251
252 mov $0x1, %eax
253 int $0x3
254 nop
255
256 The code is setup with a 6 byte nop pad at the top to make our
257 changing of eip more cleaner (and safer) due to the way the vm
258 reacts to our execution diversion. The movement of 1 into
259 eax is just an example of our arbitrary code. The int $0x3
260 alerts our attached debugger (ptrace) and the nop is for padding
261 so we can see when we hit the end of our code.
262
263 Okay, that's a lot of stuff. Let's walk through our modified
264 process of execution now. This assumes you've already injected
265 your code at main (0x08048450):
266
267 1) call PTRACE_GETREGS to obtain the 'current' set of
268 registers
269
270 2) save these registers in another structure. This is used
271 for restoration.
272
273 3) set eip in the returned set of registers to
274 0x08048450 (the address of our code).
275
276 4) call PTRACE_SETREGS with the modified structure.
277
278 5) continue execution, but watch for signals with the wait()
279 function. If the wait function returns a signal
280 that is a stop signal:
281
282 a) call PTRACE_GETREGS and get the current set of registers
283
284 b) if eip is equal to the size of your injected code - 1
285 (the location of the nop at the end), you know you've
286 reached the end of your code. go to step 6 at this
287 point.
288
289 c) otherwise, continue executing.
290
291 6) at this point your code has finished. call PTRACE_SETREGS
292 with the saved structure from step 2 and you're finished.
293 you've successfully diverted and reverted execution.
294
295 That was a mouthful, but it's very important that it's understood.
296 All of the topics in this document emplore this underlying
297 logic to perform their actions. Each one has a 'stub' assembly
298 function that gets injected into a process at main to be executed.
299 This code is meant to be small due to the fact that there are
300 potential size issues.
301
302 Oh, and another thing, you have full control over every register
303 in this scenario because the registers are restored with
304 PTRACE_SETREGS before the 'normal' execution continues.
305
306 [-- 2) Memory allocation --]
307
308 Memory allocation is one of the key features in this documented
309 as all of the sub topics in Execution Diversion are dependant
310 on its functionailty. Memory allocation allows for dynamic
311 memory allocation in another process (duh). The most applicable
312 scenario with regards to this document for such a thing are the
313 storage of arbitrary code in memory without size limitations.
314 This allows one to inject a very large function for execution
315 without having fear that they will overrun into another function
316 or harmful spot.
317
318 Memory allocation is relatively simple, but understanding how to
319 get from a to b requires a bit of explaining. The first thing we
320 need to do is figure out where malloc will be in a given process
321 image so that we may call into it. If we can figure that out
322 we should be home free considering what we know from section 1.3.
323
324 Realize that all these steps below can and are easily automated,
325 but for sake of knowing, here they are:
326
327 1) Where could malloc possibly be? Well, let's see what
328 our choices are:
329
330 root@rd-linux:~# ldd ./ownme
331 libc.so.6 => /lib/libc.so.6 (0x40016000)
332 /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
333
334 root@rd-linux:~# objdump --dynamic-syms --section=.text \
335 /lib/libc.so.6 | grep malloc
336 0006df90 w DF .text 00000235 GLIBC_2.0 malloc
337 root@rd-linux:~# objdump --dynamic-syms --section=.text \
338 /lib/ld-linux.so.2 | grep malloc
339 0000c8f0 w DF .text 000000db GLIBC_2.0 malloc
340
341 Alright, so we've got malloc in both libc and ld-linux. We
342 could probably use either but what about programs that don't
343 use libc? In order to be the most flexible, we should use
344 ld-linux. This also has a positive side effect which is
345 that every elf binary has an 'interpreter', and, it just
346 so happens to ld-linux is that interpreter.
347
348 2) Alright, so we know the vma of malloc is at 0x0000c8f0,
349 but that doesn't exactly look like a valid vma. That's
350 because it's not. It's an offset. The actual vma
351 can be calculated by adding the base address from ldd
352 for ld-linux (0x40000000) to the offset (0x0000c8f0)
353 which, in turn produces the full vma 0x4000c8f0. Now
354 we know exactly where malloc is.
355
356 3) Cool, so we know where malloc is, now all we need to do is
357 divert execution to some code that calls it and revert back.
358 We also need the return address from malloc though so we
359 know where our newly allocated buffer is at. Fortunately,
360 this is quite easy with PTRACE_GETREGS. eax will hold the
361 return value (cdecl). The code is pretty simple and,
362 considering we control all the registers, we can use
363 them to pass arguments, such as size, into our code
364 at the time of diversion. Here's some code that will,
365 when diverted to with the correctly initialized registers,
366 call malloc and interrupt into the debugger:
367
368 nop # nop pads
369 nop
370 nop
371 nop
372 nop
373 nop
374
375 push %ebx # push the size to allocate onto the stack
376 call *%eax # call malloc
377 add $0x4, %esp # restore the stack
378 int $0x3 # breakpoint
379 nop
380
381 The above code expects the 'size' parameter in ebx and the
382 address of malloc in eax.
383
384 4) Alrighty, so now we've executed our code and we're ready
385 to restore the process to normal execution, but wait,
386 we need the address malloc returned. We simply use
387 PTRACE_GETREGS and save eax and we've successfully
388 allocated memory in another process, and we have the
389 address to prove it.
390
391 The same steps above can be used for deallocating memory, simply
392 s/malloc/free/g and you're set :).
393
394 [-- 3) Memory management --]
395
396 I'm only going to briefly cover the concept of copying memory
397 from one process to another as it's sort of out of the scope
398 of this document. If you're more curious, read about memgrep
399 in the ``References`` section.
400
401 Copying memory from one process to another simply entails the
402 use of PTRACE_POKEDATA which allows for writing 4 bytes of data
403 to a given address inside a process. Not much more is needed
404 to be known from that point on :).
405
406 [-- 4) Library Injection --]
407
408 Library injection is very powerful when it comes to using
409 functionality inside a running process that it wasn't meant to
410 be doing. One of the more obvious applications is that of loading
411 a personally developed shared object into a running executable.
412
413 This one was fun to figure out, so I'll just kind of walk you
414 through the process I took.
415
416 First thing's first, we need to figure out how to load a library
417 without the binary being linked to libdl. libdl is what provides
418 functions like dlopen(), dlsym(), and dlclose(). The problem is
419 that executables don't link to this library by default. That means
420 we can't do our magic technique of figuring out where dlopen will
421 be in memory because, well, it isn't guaranteed to be there.
422
423 There's still hope though. dl* functions are mainly just stubs
424 that make calling the underlying API easier. Kind of like how
425 libc makes calling syscalls easier. Since these are just wrappers,
426 there have to be implementers, and indeed, there are. Check this
427 out:
428
429 root@rd-linux:~# objdump --dynamic-syms /lib/libc.so.6 | \
430 grep _dl_ | egrep "open|close|sym"
431 000f7d10 g DF .text 000001ad GLIBC_2.2 _dl_vsym
432 000f6f10 g DF .text 000006b8 GLIBC_2.0 _dl_close
433 000f6d80 g DF .text 00000190 GLIBC_2.0 _dl_open
434 000f7c00 g DF .text 0000010d GLIBC_2.2 _dl_sym
435
436 Well, isn't it our lucky day? libc.so.6 has _dl_open, _dl_sym, and
437 _dl_close. These look amazingly similar to their dl* wrappers.
438 In fact, they're almost exactly the same. Compare the prototypes:
439
440 extern void *dlopen (const char *file, int mode);
441 extern void *dlsym (void *handle, const char *name)
442 extern int dlclose (void *handle);
443
444 To:
445
446 void *_dl_open (const char *file, int mode, const void *caller);
447 void *_dl_sym (void *handle, const char *name, void *who);
448 void _dl_close (void *_map);
449
450 Pretty much the same right? Looks very promising. So here's what
451 we know as of now:
452
453 * We know where the _dl_* symbols will be at in the processes
454 virtual memory. (We can calculate it the same way we did
455 malloc)
456 * We know the prototypes.
457
458 One thing we don't know is how the functions expect their arguments.
459 One would think they'd be stack based, right? Well, not so. They
460 seem to use a variation of fastcall (like syscalls). Here's a
461 short dump of _dl_open:
462
463 000f6d80 <.text+0xdde00> (_dl_open):
464 f6d80: 55 push %ebp
465 f6d81: 89 e5 mov %esp,%ebp
466 f6d83: 83 ec 2c sub $0x2c,%esp
467 f6d86: 57 push %edi
468 f6d87: 56 push %esi
469 f6d88: 53 push %ebx
470 f6d89: e8 00 00 00 00 call 0xf6d8e
471 f6d8e: 5b pop %ebx
472 f6d8f: 81 c3 ba 10 02 00 add $0x210ba,%ebx
473 f6d95: 89 c7 mov %eax,%edi
474 f6d97: 89 d6 mov %edx,%esi
475 f6d99: 89 4d e4 mov %ecx,0xffffffe4(%ebp)
476 f6d9c: f7 c6 03 00 00 00 test $0x3,%esi
477 f6da2: 75 1c jne 0xf6dc0
478 f6da4: 83 c4 f4 add $0xfffffff4,%esp
479
480 Looks pretty normal for the most part right? Well, up until 0xf6d95
481 at least. It's quite odd that it's referencing eax, edx, and ecx
482 which have not been initialized in the context of _dl_open, and then
483 using them and operating on them later in the function. Very strange
484 to say the least. Unless, of course, the arguments are being passed
485 in registers instead of via the stack. Let's look at the source
486 code for _dl_open.
487
488 void *
489 internal_function
490 _dl_open (const char *file, int mode, const void *caller)
491 {
492 struct dl_open_args args;
493 const char *objname;
494 const char *errstring;
495 int errcode;
496
497 if ((mode & RTLD_BINDING_MASK) == 0)
498 /* One of the flags must be set. */
499 _dl_signal_error (EINVAL, file, NULL,
500 N_("invalid mode for dlopen()"));
501
502 ....
503
504 }
505
506 Okay, so we see roughly the first thing it does is do a bitwise and
507 on the mode passed in to make sure it's valid. It does the and
508 with 0x00000003 (RTLD_BINDING_MASK). Do we see any bitwise ands
509 with 0x3 in the disasm? We sure do. At 0xf6d9c a bitwise and is
510 performed between $0x3 and esi. So esi must be where our mode is
511 stored, right? Yes. Let's see where esi is set. Looks like it
512 gets set at 0xf6d97 from edx. Okay, so maybe edx originally
513 contained our mode. Where does edx get set? No where in _dl_open.
514 That means the mode must have been passed in a register, and not on
515 the stack.
516
517 If you do some more research, you determine that the arguments
518 are passed as such:
519
520 eax = library name (ex: /lib/libc.so.6)
521 ecx = caller (ex: ./ownme)
522 edx = mode (ex: RTLD_NOW | 0x80000000)
523
524 Alright, so we know how arguments are passed AND we know the address
525 to call when we want to load a library. From this point things
526 should be pretty obvious.
527
528 All one need do is allocate space for the library name and the
529 caller in the image using the ``Memory Allocation`` technique.
530 Then copy the library and image using the ``Memory Management``
531 technique. Then, finally, execute the stub code that loads the
532 library. That code would look something like this:
533
534 nop # nop pads
535 nop
536 nop
537 nop
538 nop
539 nop
540
541 call *%edi # call _dl_open
542 int $0x3 # breakpoint
543 nop
544
545 This code expects the arguments to already be initialized in the
546 proper registers from what we determine above and it expects
547 _dl_open's vma to be in edi.
548
549 Welp, we've successfully injected a shared object into another
550 processes image. What you do from here is up to the desired
551 outcome. Calling _dl_sym and _dl_close uses the same code as above,
552 but their arguments are as follows:
553
554 _dl_sym expects:
555
556 eax = library handle opened by _dl_open
557 edx = symbol name (ex: 'pthread_create')
558
559 _dl_close expects:
560
561 eax = library handle opened by _dl_open
562
563 [-- 5) Code Injection --]
564
565 I must say we're getting rather hardcore, we can allocate memory,
566 copy memory and load shared objects into arbitrary processes.
567 What more could we possibly want? How about some arbitrary,
568 controlled code execution that isn't limited by size? Sounds
569 spiffy!
570
571 [-- 5.1) Forking --]
572
573 Let's say we want to fork a child process inside the context of
574 another process and have it execute an arbitrary function
575 that we've allocated and stored in the processes memory image
576 via the ``Memory Allocation`` and ``Memory Management`` methods.
577 Doing the fork is as simple as writing up some code that will
578 use ``Execution Diversion`` to fork the child and return control
579 to the parent as if nothing happened. An example of forking
580 and executing a supplied function is as follows:
581
582 nop # nop pads
583 nop
584 nop
585 nop
586 nop
587 nop
588
589 mov $0x2, %eax # fork syscall
590 int $0x80 # interrupt
591 cmp $0x00, %eax # is the pid stored in eax 0? if so,
592 # we're the child
593 jne fork_finished # since eax wasn't zero, it means we're the
594 # parent. jmp to finished.
595 push %ebx # since we're the child, we push the start
596 # addr
597 call *%edi # then we call the function
598 mov $0x1, %eax # exit the child process
599 int $0x80 # interrupt
600 fork_finished:
601 int $0x3 # we're the parent, we breakpoint.
602 nop
603
604 This code expects the following registers to be set:
605
606 ebx = the argument to be passed to the function
607 edi = the vma of the function call in the context of the child.
608
609 Forking is really as simple as that. Now, one side effect is that
610 if the daemon does not expect fork children (ie, it doesn't call
611 wait()) then your child process will show up as defunct when it
612 exits due to not being cleaned up properly. There are ways around
613 this, though. You could use the ``Execution Diversion`` technique
614 to perform cleanup of exitted children after for the process.
615
616 [-- 5.2) Threading --]
617
618 Similar to forking, but different by the fact that a thread runs
619 in the context of the caller and shares memory, threading allows
620 for pretty much the same things that forking does. There are
621 some risks with threading though. For instance, it is _NOT_ safe
622 to create a thread in a process that does not natural thread. This
623 is for multiple reasons -- the most important being that the
624 threading environment is setup at load time (in the case of
625 pthreads). If Linux didn't use some ghetto application-level
626 threading architecture, things wouldn't be so bad.
627
628 If you really do want to take the risk of creating a thread,
629 the process would be something like this:
630
631 1) Inject libpthread.so into the process (``Library Injection``)
632 2) Find pthread_create's vma in the process
633 (``Library Injection``)
634 3) Allocate and copy user defined code (``Memory Allocation``)
635 4) Perform ``Execution Diversion`` on the stub code to
636 create the thread. An example of such code is:
637
638 nop # nop pads
639 nop
640 nop
641 nop
642 nop
643 nop
644
645 sub $0x4, %esp # space for the id
646 mov %esp, %ebp # store esp in ebp for pushing
647 push %ebx # push argument
648 push %eax # push function
649 push $0x0 # no attributes
650 push %ebp # push addr to store thread id in
651 call *%edi # call pthread_create
652 add $0x14, %esp # restore stack
653 int $0x3 # breakpoint
654 nop
655
656 Like I said, threading is dangerous. Know your program before
657 attempting to inject a thread. You will get odd results if
658 you inject a thread into a process that doesn't naturally thread.
659
660 [-- 5.3) Function Trampolines --]
661
662 Function trampolines are a great way to transparently hook arbitrary
663 functions in memory. I'll give a brief overview of what a function
664 trampoline is and how it works.
665
666 The basic jist to how function trampolines work is that they
667 overwrite the first x instructions where the size of the x
668 instructions is at least six bytes. The six bytes come from the
669 fact that on x86 unconditional jumps take up 6 bytes in opcodes.
670 The x instructions are replaced with the jmp instruction that
671 jumps to an address in memory that contains the injected function.
672 This function runs before the actual function runs, and thus, has
673 complete control over whether the actual function even gets called.
674 At the end of the injected function the x instructions are appended
675 as well as a jump back to the original function plus the size of
676 the x instructions. Here's an example:
677
678 Let's say we want to hook the function 'testFunction' in the
679 executable 'ownme'.
680
681 root@rd-linux:~# objdump -d ownme --start-addr=0x080484d4
682
683 ownme: file format elf32-i386
684
685 Disassembly of section .init:
686 Disassembly of section .plt:
687 Disassembly of section .text:
688
689 080484d4 <testFunction>:
690 80484d4: 55 push %ebp
691 80484d5: 89 e5 mov %esp,%ebp
692 80484d7: 83 ec 18 sub $0x18,%esp
693 ...
694 8048500: c9 leave
695 8048501: c3 ret
696
697 Well, it looks like the first 3 instructions match our criteria
698 of at least 6 bytes. Let's keep those 6 bytes of opcodes
699 tucked away for now.
700
701 We need to be smart here. We're going to do a jmp that
702 says jmp to address stored in address x. We're also
703 going to want to restore back to the original place. That means
704 when we allocate our memory we should allocate it in a format like
705 this:
706
707 [ 4 bytes storing the address of our code ]
708 [ 4 bytes storing the address to jmp back to ]
709 [ X bytes of arbitrary code ]
710 [ X bytes containing the X instructions that we overwrote ]
711 [ 6 bytes for the jump back ]
712
713 So let's say we want to inject this code and we allocated
714 a buffer in the process of the approriate length which starts
715 at 0x41414140:
716
717 nop
718 movb $0x1, %al
719
720 Our actual buffer in memory would look something like this
721
722 0x41414140 = 0x41414148 (address of our code)
723 0x41414144 = 0x080484d8 (address to jmp back to)
724 0x41414148 = 3 bytes (nop, movb)
725 0x4141414B = 6 bytes of preamble from testFunction
726 0x41414152 = jmp *0x41414144
727
728 The last step now that we have our code injected is to overwrite
729 the actual preamble (the 6 bytes of testFunction) with the jmp
730 to our code. The assembly would look something like this:
731
732 jmp *0x41414140 # Jump to the address stored in 0x41414140
733
734 Once that's overwritten, we're home free. The flow of
735 execution goes like this:
736
737 1) Call to testFunction
738 2) First instruction of testFunction is:
739 jmp *0x41414140
740 3) vm jumps to 0x41414148 an executes:
741 nop
742 movb $0x1, %al
743 push %ebp
744 mov %esp, %ebp
745 sub $0x18, %esp
746 jmp *0x41414144
747 4) vm jumps to 0x080484d8
748 5) Function executes like normal.
749
750 That's all there is to it. There are a couple of restrictions
751 when using trampolines:
752
753 1) NEVER modify the stack without restoring it before
754 the original functions preamble gets called. Bad
755 things will happen.
756 2) Becareful what registers you modify. Some functions
757 may use fastcall.
758
759 For more information on function trampolines, see the ``References``
760 section.
761
762 [-- 6) Conclusion --]
763
764 That about wraps it up. You now have the tools to allocate,
765 copy, inject libraries, create forks, create threads, and
766 install function trampolines. You also have the underlying
767 concept of ``Execution Diversion`` which can be applied across
768 the board to even more things I haven't even thought of yet.
769
770 [-- 7) References --]
771
772 * For information about ``Function Trampolines``:
773
774 http://research.microsoft.com/sn/detours
775
0 ### hotpatch is a dll injection strategy
1 ### Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
2 ### All rights reserved.
3 ###
4 ### Redistribution and use in source and binary forms, with or without
5 ### modification, are permitted provided that the following conditions are met:
6 ###
7 ### * Redistributions of source code must retain the above copyright
8 ### notice, this list of conditions and the following disclaimer.
9 ###
10 ### * Redistributions in binary form must reproduce the above copyright
11 ### notice, this list of conditions and the following disclaimer in the
12 ### documentation and/or other materials provided with the distribution.
13 ###
14 ### * Neither the name of Selective Intellect LLC nor the
15 ### names of its contributors may be used to endorse or promote products
16 ### derived from this software without specific prior written permission.
17 ###
18 ### THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ### WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 ### DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22 ### DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 ### (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 ### LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ### ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 ### (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 ### SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 ###
29 configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/hotpatch_config.h @ONLY)
30 install(FILES hotpatch.h DESTINATION include)
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef __LIBHOTPATCH_CONFIG_H__
32 #define __LIBHOTPATCH_CONFIG_H__
33
34 #if (defined __GNUC__ && !defined _GNU_SOURCE)
35 #define _GNU_SOURCE 1
36 #endif
37
38 #cmakedefine HOTPATCH_HAS_FEATURES_H
39 #ifdef HOTPATCH_HAS_FEATURES_H
40 #include <features.h>
41 #endif
42
43 #cmakedefine HOTPATCH_HAS_ERRNO_H
44 #ifdef HOTPATCH_HAS_ERRNO_H
45 #include <errno.h>
46 #endif
47
48 #cmakedefine HOTPATCH_HAS_STDIO_H
49 #ifdef HOTPATCH_HAS_STDIO_H
50 #include <stdio.h>
51 #endif
52
53 #cmakedefine HOTPATCH_HAS_STDLIB_H
54 #ifdef HOTPATCH_HAS_STDLIB_H
55 #include <stdlib.h>
56 #endif
57
58 #cmakedefine HOTPATCH_HAS_STRING_H
59 #ifdef HOTPATCH_HAS_STRING_H
60 #include <string.h>
61 #endif
62
63 #cmakedefine HOTPATCH_HAS_STRNLEN_FN
64 #ifndef HOTPATCH_HAS_STRNLEN_FN
65 size_t hotpatch_strnlen(const char *str, size_t maxlen);
66 #define strnlen(a,b) hotpatch_strnlen(a,b)
67 #endif
68
69 #cmakedefine HOTPATCH_HAS_STRTOKR_FN
70 #ifndef HOTPATCH_HAS_STRTOKR_FN
71 #define strtok_r(a,b,c) strtok(a,b)
72 #endif
73
74 #cmakedefine HOTPATCH_HAS_STDDEF_H
75 #ifdef HOTPATCH_HAS_STDDEF_H
76 #include <stddef.h>
77 #endif
78
79 #cmakedefine HOTPATCH_HAS_LIMITS_H
80 #ifdef HOTPATCH_HAS_LIMITS_H
81 #include <limits.h>
82 #endif
83
84 #cmakedefine HOTPATCH_HAS_STDINT_H
85 #ifdef HOTPATCH_HAS_STDINT_H
86 #include <stdint.h>
87 #endif
88
89 #cmakedefine HOTPATCH_HAS_STDARG_H
90 #ifdef HOTPATCH_HAS_STDARG_H
91 #include <stdarg.h>
92 #endif
93
94 #cmakedefine HOTPATCH_HAS_STDBOOL_H
95 #ifdef HOTPATCH_HAS_STDBOOL_H
96 #include <stdbool.h>
97 #endif
98
99 #cmakedefine HOTPATCH_HAS_TIME_H
100 #ifdef HOTPATCH_HAS_TIME_H
101 #include <time.h>
102 #endif
103
104 #cmakedefine HOTPATCH_HAS_SYS_TIME_H
105 #ifdef HOTPATCH_HAS_SYS_TIME_H
106 #include <sys/time.h>
107 #endif
108
109 #cmakedefine HOTPATCH_HAS_SYS_TYPES_H
110 #ifdef HOTPATCH_HAS_SYS_TYPES_H
111 #include <sys/types.h>
112 #else
113 #ifndef __cplusplus
114 typedef enum {
115 false = 0,
116 true = 1
117 } bool;
118 #endif
119 #endif
120
121 #cmakedefine HOTPATCH_HAS_UNISTD_H
122 #ifdef HOTPATCH_HAS_UNISTD_H
123 #include <unistd.h>
124 #endif
125
126 #cmakedefine HOTPATCH_HAS_ASSERT_H
127
128 /* for the APPLE */
129 #cmakedefine HOTPATCH_HAS_MACH_MESSAGE_H
130 #cmakedefine HOTPATCH_HAS_MACH_MACH_H
131 #cmakedefine HOTPATCH_HAS_MACH_TASK_H
132 #cmakedefine HOTPATCH_HAS_MACH_MACHTRAPS_H
133 #cmakedefine HOTPATCH_HAS_MACH_MACHERROR_H
134 #cmakedefine HOTPATCH_HAS_MACH_TASKFORPID_FN
135
136 /* for the Linux */
137 #cmakedefine HOTPATCH_HAS_LINUX_ELF_H
138 #ifdef HOTPATCH_HAS_LINUX_ELF_H
139 #include <elf.h>
140 #endif
141
142 #cmakedefine HOTPATCH_HAS_LINUX_DLFCN_H
143 #ifdef HOTPATCH_HAS_LINUX_DLFCN_H
144 #include <dlfcn.h>
145 #endif
146
147 #cmakedefine HOTPATCH_HAS_LINUX_LINK_H
148 #ifdef HOTPATCH_HAS_LINUX_LINK_H
149 #include <link.h>
150 #endif
151
152 #cmakedefine HOTPATCH_HAS_LINUX_PTHREAD_H
153 #ifdef HOTPATCH_HAS_LINUX_PTHREAD_H
154 #include <pthread.h>
155 #endif
156
157 #cmakedefine HOTPATCH_HAS_LINUX_SETJMP_H
158 #ifdef HOTPATCH_HAS_LINUX_SETJMP_H
159 #include <setjmp.h>
160 #endif
161
162 #cmakedefine HOTPATCH_HAS_LINUX_SIGNAL_H
163 #ifdef HOTPATCH_HAS_LINUX_SIGNAL_H
164 #include <signal.h>
165 #endif
166
167 #cmakedefine HOTPATCH_HAS_LINUX_SYS_PTRACE_H
168 #ifdef HOTPATCH_HAS_LINUX_SYS_PTRACE_H
169 #include <sys/ptrace.h>
170 #endif
171
172 #cmakedefine HOTPATCH_HAS_LINUX_SYS_WAIT_H
173 #ifdef HOTPATCH_HAS_LINUX_SYS_WAIT_H
174 #include <sys/wait.h>
175 #endif
176
177 #cmakedefine HOTPATCH_HAS_LINUX_SYS_STAT_H
178 #ifdef HOTPATCH_HAS_LINUX_SYS_STAT_H
179 #include <sys/stat.h>
180 #endif
181
182 #cmakedefine HOTPATCH_HAS_LINUX_FCNTL_H
183 #ifdef HOTPATCH_HAS_LINUX_FCNTL_H
184 #include <fcntl.h>
185 #endif
186
187 #cmakedefine HOTPATCH_HAS_LINUX_SYS_USER_H
188 #ifdef HOTPATCH_HAS_LINUX_SYS_USER_H
189 #include <sys/types.h>
190 #include <sys/user.h>
191 #endif
192
193 #cmakedefine HOTPATCH_HAS_LINUX_SYS_SYSCALL_H
194 #ifdef HOTPATCH_HAS_LINUX_SYS_SYSCALL_H
195 #include <sys/syscall.h>
196 #endif
197
198 #cmakedefine HOTPATCH_HAS_LINUX_DLITERPHDR_FN
199
200 #define HOTPATCH_VOIDPTR_SIZE @HOTPATCH_VOIDPTR_SIZE@
201
202 #cmakedefine HOTPATCH_USE_ASM
203
204 #if __WORDSIZE == 64
205 #define LX "%lx"
206 #define LU "%lu"
207 #else
208 #define LX "%x"
209 #define LU "%u"
210 #endif
211
212 #endif /* __LIBHOTPATCH_CONFIG_H__ */
213
0 /*
1 * hotpatch is a sofile injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #ifndef __LIBHOTPATCH_H__
31 #define __LIBHOTPATCH_H__
32
33 #ifdef __cplusplus
34 extern "C" {
35 #endif /* __cplusplus */
36
37 #include <sys/types.h>
38 #include <stdint.h>
39
40 #define HOTPATCH_MAJOR_VERSION 0
41 #define HOTPATCH_MINOR_VERSION 2
42
43 #ifndef HOTPATCH_LINUX_START
44 #define HOTPATCH_LINUX_START "_start"
45 #endif
46
47 typedef struct hotpatch_is_opaque hotpatch_t;
48 /* Create the hotpatch object for the running process whose PID is given as an
49 * argument. Returns a pointer to an opaque object that must be freed by
50 * hotpatch_delete() function later to conserve memory.
51 */
52 hotpatch_t *hotpatch_create(pid_t, int verbosity);
53 /*
54 * delete memory and close all open handles related to the hotpatch'ed process.
55 * This can lead to the hotpatch'ed process to be unstable if not done in the same
56 * thread as create function above.
57 */
58 void hotpatch_destroy(hotpatch_t *);
59 /*
60 * Inject a shared object into the process and invoke the given symbol without
61 * arguments. No thread will be created by hotpatch.
62 * If the symbol is NULL, then _init() is expected to be in the library.
63 * If data is NULL, no data will be copied over to the other process for the
64 * symbol that is being invoked. If the symbol being invoked is _init(), then
65 * data will be ignored. This data and datalen will be provided as arguments to
66 * the symbol when invoked.
67 * The return address of the dlopen() call can be optionally returned in
68 * the outaddr variable.
69 * The return value from the invocation of the symbol in the process can be
70 * optionally returned in the outres variable. If the symbol is NULL, or if the
71 * symbol returns void, then the return value will be undefined.
72 */
73 int hotpatch_inject_library(hotpatch_t *, const char *sofile,
74 const char *symbol,
75 const unsigned char *data, size_t datalen,
76 uintptr_t *outaddr, uintptr_t *outres);
77
78 /* AUXILLIARY FUNCTIONS */
79
80 void hotpatch_version(int *major, int *minor);
81
82 /* finds the symbol in the symbol table of executable and returns the memory
83 * location of it. On a 64-bit system the running process can be 32 or 64 bit,
84 * and hence they both need to be handled correctly or even simultaneously.
85 * Returns not only the location of the symbol but also the type and size
86 */
87 uintptr_t hotpatch_read_symbol(hotpatch_t *, const char *symbol, int *symtype,
88 size_t *symsize);
89 /*
90 * Get the entry point of the executable in question
91 */
92 uintptr_t hotpatch_get_entry_point(hotpatch_t *);
93 /*
94 * Attach to the process that you wanted to hotpatch. Returns 0 on success and 1
95 * on failure.
96 */
97 int hotpatch_attach(hotpatch_t *);
98 /*
99 * Detach from the process that you wanted to hotpatch. Returns -1 on failure
100 * or if nothing was attached earlier. Returns 0 if detaching succeeded.
101 */
102 int hotpatch_detach(hotpatch_t *);
103 /*
104 * Sets the execution pointer to point to the address given by the user.
105 * Returns 0 on success and -1 on failure.
106 */
107 int hotpatch_set_execution_pointer(hotpatch_t *, uintptr_t location);
108
109 #ifdef __cplusplus
110 } /* end of extern C */
111 #endif /* __cplusplus */
112
113 #endif /* __LIBHOTPATCH_H__ */
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #ifndef __LIBHOTPATCH_INTERNAL_H__
31 #define __LIBHOTPATCH_INTERNAL_H__
32
33 #include <hotpatch_config.h>
34
35 #define OS_MAX_BUFFER 512
36
37 #undef LOG_ERROR_INVALID_PID
38 #define LOG_ERROR_INVALID_PID(A) do { \
39 fprintf(stderr, "[%s:%d] Invalid PID: %d\n", __func__, __LINE__, A); \
40 } while (0)
41
42 #undef LOG_ERROR_OUT_OF_MEMORY
43 #define LOG_ERROR_OUT_OF_MEMORY do { \
44 int err = errno; \
45 fprintf(stderr, "[%s:%d] Out of memory. Error: %s\n", __func__, __LINE__,\
46 strerror(err)); \
47 } while (0)
48
49 #undef LOG_ERROR_FILE_OPEN
50 #define LOG_ERROR_FILE_OPEN(FF) do { \
51 int err = errno; \
52 fprintf(stderr, "[%s:%d] File(%s) open error. Error: %s\n", __func__, __LINE__,\
53 FF, strerror(err)); \
54 } while (0)
55
56 #undef LOG_ERROR_FILE_SEEK
57 #define LOG_ERROR_FILE_SEEK do { \
58 int err = errno; \
59 fprintf(stderr, "[%s:%d] File seek error. Error: %s\n", __func__, __LINE__,\
60 strerror(err)); \
61 } while (0)
62
63 #undef LOG_ERROR_FILE_READ
64 #define LOG_ERROR_FILE_READ do { \
65 int err = errno; \
66 fprintf(stderr, "[%s:%d] File read error. Error: %s\n", __func__, __LINE__,\
67 strerror(err)); \
68 } while (0)
69
70 #undef LOG_ERROR_UNSUPPORTED_PROCESSOR
71 #define LOG_ERROR_UNSUPPORTED_PROCESSOR do { \
72 fprintf(stderr, \
73 "[%s:%d] Only 32/64-bit Intel X86/X86-64 processors are supported.\n",\
74 __func__, __LINE__); \
75 } while (0)
76 #define LOG_INFO_HEADERS_LOADED(verbose) do { \
77 if (verbose > 2) \
78 fprintf(stderr, "[%s:%d] Exe headers loaded.\n", __func__, __LINE__); \
79 } while (0)
80
81 struct ld_procmaps;
82
83 enum elf_bit {
84 HOTPATCH_EXE_IS_NEITHER,
85 HOTPATCH_EXE_IS_32BIT,
86 HOTPATCH_EXE_IS_64BIT
87 };
88
89 struct elf_symbol {
90 char *name; /* null terminated symbol name */
91 uintptr_t address; /* address at which it is available */
92 int type; /* type of symbol */
93 size_t size; /* size of the symbol if available */
94 };
95
96 struct elf_interp {
97 char *name;
98 size_t length;
99 uintptr_t ph_addr;
100 };
101
102 struct ld_library {
103 char *pathname;
104 size_t length;
105 ino_t inode;
106 uintptr_t addr_begin;
107 uintptr_t addr_end;
108 };
109
110 enum {
111 HOTPATCH_LIB_LD = 0,
112 HOTPATCH_LIB_C,
113 HOTPATCH_LIB_DL,
114 HOTPATCH_LIB_PTHREAD,
115 HOTPATCH_LIB_MAX
116 };
117
118 enum {
119 HOTPATCH_SYMBOL_IS_UNKNOWN,
120 HOTPATCH_SYMBOL_IS_FUNCTION,
121 HOTPATCH_SYMBOL_IS_FILENAME,
122 HOTPATCH_SYMBOL_IS_SECTION,
123 HOTPATCH_SYMBOL_IS_OBJECT
124 };
125
126 struct hotpatch_is_opaque {
127 pid_t pid;
128 int verbose;
129 enum elf_bit is64;
130 struct elf_symbol *exe_symbols;
131 size_t exe_symbols_num;
132 uintptr_t exe_entry_point;
133 struct elf_interp exe_interp; /* dynamic loader from .interp in the exe */
134 struct ld_procmaps *ld_maps;
135 size_t ld_maps_num;
136 struct ld_library libs[HOTPATCH_LIB_MAX];
137 /* addresses useful */
138 uintptr_t fn_malloc;
139 uintptr_t fn_realloc;
140 uintptr_t fn_free;
141 uintptr_t fn_dlopen;
142 uintptr_t fn_dlclose;
143 uintptr_t fn_dlsym;
144 uintptr_t fn_pthread_create;
145 uintptr_t fn_pthread_detach;
146 /* actions */
147 bool attached;
148 bool inserted;
149 };
150
151 struct elf_symbol *exe_load_symbols(const char *filename, int verbose,
152 size_t *sym_count,
153 uintptr_t *entry_point,
154 struct elf_interp *interp,
155 enum elf_bit *is64);
156
157 struct ld_procmaps *ld_load_maps(pid_t pid, int verbose, size_t *num);
158
159 void ld_free_maps(struct ld_procmaps *, size_t num);
160
161 /* the full path of the library needs to be given. */
162 int ld_find_library(const struct ld_procmaps *, const size_t num,
163 const char *libpath, bool inode_match,
164 struct ld_library *lib, int verbose);
165
166 /* finds the address of the symbol in the library if it exists */
167 uintptr_t ld_find_address(const struct ld_library *hpl, const char *symbol,
168 int verbose);
169
170 int elf_symbol_cmpqsort(const void *p1, const void *p2);
171 #endif /* __LIBHOTPATCH_INTERNAL_H__ */
0 ### hotpatch is a dll injection strategy
1 ### Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
2 ### All rights reserved.
3 ###
4 ### Redistribution and use in source and binary forms, with or without
5 ### modification, are permitted provided that the following conditions are met:
6 ###
7 ### * Redistributions of source code must retain the above copyright
8 ### notice, this list of conditions and the following disclaimer.
9 ###
10 ### * Redistributions in binary form must reproduce the above copyright
11 ### notice, this list of conditions and the following disclaimer in the
12 ### documentation and/or other materials provided with the distribution.
13 ###
14 ### * Neither the name of Selective Intellect LLC nor the
15 ### names of its contributors may be used to endorse or promote products
16 ### derived from this software without specific prior written permission.
17 ###
18 ### THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ### WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 ### DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22 ### DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 ### (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 ### LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ### ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 ### (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 ### SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 ###
29 project(hotpatch)
30
31 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
32 include_directories(${CMAKE_CURRENT_BINARY_DIR})
33
34 if (USE_ASM)
35 foreach (ASM_VAR call32 call64)
36 set(ASM_F ${CMAKE_CURRENT_SOURCE_DIR}/${ASM_VAR}.s)
37 set(ASM_F_OBJ ${CMAKE_CURRENT_BINARY_DIR}/${ASM_VAR}.o)
38 set(ASM_F_HDR ${CMAKE_CURRENT_BINARY_DIR}/${ASM_VAR}.h)
39 set(ASM_F_VAR hotpatch_${ASM_VAR})
40 set(ASM2HDR ${CMAKE_CURRENT_SOURCE_DIR}/asm2hdr.pl)
41 if (HOTPATCH_ASM AND PERL_FOUND)
42 add_custom_command(OUTPUT ${ASM_F_HDR}
43 COMMAND ${HOTPATCH_ASM} ARGS ${ASM_F} -o ${ASM_F_OBJ}
44 COMMAND ${PERL_EXECUTABLE} ARGS ${ASM2HDR} ${ASM_F_OBJ}
45 ${ASM_F_HDR} ${ASM_F_VAR}
46 DEPENDS ${ASM_F} ${ASM2HDR}
47 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
48 set(ASM_HEADERS ${ASM_HEADERS} ${ASM_F_HDR})
49 else (HOTPATCH_ASM AND PERL_FOUND)
50 message(FATAL_ERROR "You need Perl for this")
51 endif (HOTPATCH_ASM AND PERL_FOUND)
52 endforeach (ASM_VAR call32 call64)
53 add_custom_target(asm_header DEPENDS ${ASM_HEADERS})
54 endif (USE_ASM)
55
56 add_library(hotpatch SHARED hotpatch.c exedetails.c loader.c)
57 add_library(hotpatch_s STATIC hotpatch.c exedetails.c loader.c)
58 if (USE_ASM)
59 add_dependencies(hotpatch asm_header)
60 add_dependencies(hotpatch_s asm_header)
61 endif (USE_ASM)
62 set_target_properties(hotpatch_s PROPERTIES OUTPUT_NAME "hotpatch"
63 CLEAN_DIRECT_OUTPUT 1)
64 set_target_properties(hotpatch PROPERTIES CLEAN_DIRECT_OUTPUT 1)
65 install(TARGETS hotpatch LIBRARY DESTINATION lib)
66 install(TARGETS hotpatch_s ARCHIVE DESTINATION lib)
67
68 add_executable(hotpatcher main.c)
69 target_link_libraries(hotpatcher hotpatch_s)
70 install(TARGETS hotpatcher RUNTIME DESTINATION bin)
0 #!/usr/bin/perl
1 use strict;
2 use warnings;
3 my $usage = "$0 <asm file> <header file> <variable>";
4 my $obj = $ARGV[0] || die $usage;
5 my $hdr = $ARGV[1] || die $usage;
6 my $name = $ARGV[2] || die $usage;
7 my $ifdef = '__' . uc($name) . '_H__';
8 my @chars;
9 do {
10 local $/;
11 open ASM, "<$obj" or die "Unable to open $obj: $!";
12 my $data = <ASM>;
13 @chars = map(ord, split('', $data));
14 };
15 open HDR, ">$hdr" or die "Unable to open $hdr: $!";
16 print HDR "#ifndef $ifdef\n#define $ifdef\n";
17 print HDR 'const unsigned char ' . $name ."[] = {\n";
18 print HDR "\t", join(', ', @chars), "\n";
19 print HDR "};\n#endif /* $ifdef */\n";
20 close HDR;
0 BITS 32
1 ; in 32-bit mode the arguments are passed on the stack. Since we need only two
2 ; arguments at max, we will only push 2 registers. The return value will be
3 ; taken from EAX;
4 ; the function pointer is placed in EBX followed by a triggered breakpoint.
5 push esi
6 push edi
7 call [ebx]
8 int 3
0 BITS 64
1 ; the function pointer is placed in RBX/EBX followed by a triggered breakpoint
2 ; the arguments are expected in RDI and RSI respectively. The return value will
3 ; be extracted from RAX
4 call [rbx]
5 int 3
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <hotpatch_config.h>
31 #include <hotpatch_internal.h>
32 #include <hotpatch.h>
33
34 #if __WORDSIZE == 64
35 typedef Elf64_Ehdr Elf_Ehdr;
36 typedef Elf64_Phdr Elf_Phdr;
37 typedef Elf64_Shdr Elf_Shdr;
38 typedef Elf64_Sym Elf_Sym;
39 #else
40 typedef Elf32_Ehdr Elf_Ehdr;
41 typedef Elf32_Phdr Elf_Phdr;
42 typedef Elf32_Shdr Elf_Shdr;
43 typedef Elf32_Sym Elf_Sym;
44 #endif
45
46 enum {
47 HOTPATCH_SYMBOL_TYPE,
48 HOTPATCH_UNKNOWN
49 };
50
51 struct elf_internals {
52 int fd;
53 enum elf_bit is64;
54 off_t proghdr_offset;
55 void *proghdrs; /* program headers */
56 size_t proghdr_num;
57 size_t proghdr_size; /* total buffer size */
58 off_t sechdr_offset;
59 void *sechdrs; /* section headers */
60 size_t sechdr_num;
61 size_t sechdr_size; /* total buffer size */
62 size_t secnametbl_idx;
63 char *strsectbl; /* string table for section names */
64 size_t strsectbl_size;
65 /*
66 * stored here temporarily, should not be freed unless on failure.
67 */
68 uintptr_t entry_point;
69 struct elf_symbol *symbols;
70 size_t symbols_num;
71 struct elf_interp interp;
72 };
73
74 /* each of the exe_* functions have to be reentrant and thread-safe */
75 static int exe_get_hotpatch_type(int info, int group)
76 {
77 if (group == HOTPATCH_SYMBOL_TYPE) {
78 int value = ELF64_ST_TYPE(info);
79 if (value == STT_FUNC)
80 return HOTPATCH_SYMBOL_IS_FUNCTION;
81 else if (value == STT_FILE)
82 return HOTPATCH_SYMBOL_IS_FILENAME;
83 else if (value == STT_SECTION)
84 return HOTPATCH_SYMBOL_IS_SECTION;
85 else if (value == STT_OBJECT)
86 return HOTPATCH_SYMBOL_IS_OBJECT;
87 else
88 return HOTPATCH_SYMBOL_IS_UNKNOWN;
89 }
90 return -1;
91 }
92
93 static int exe_open_filename(const char *filename, int verbose)
94 {
95 int fd = -1;
96 fd = open(filename, O_RDONLY);
97 if (fd < 0)
98 LOG_ERROR_FILE_OPEN(filename);
99 if (verbose > 3)
100 fprintf(stderr, "[%s:%d] Exe file descriptor: %d\n", __func__,
101 __LINE__, fd);
102 return fd;
103 }
104
105 static int exe_elf_identify(unsigned char *e_ident, size_t size, int verbose)
106 {
107 if (e_ident && size > 0) {
108 if ((e_ident[EI_MAG0] == ELFMAG0) &&
109 (e_ident[EI_MAG1] == ELFMAG1) &&
110 (e_ident[EI_MAG2] == ELFMAG2) &&
111 (e_ident[EI_MAG3] == ELFMAG3)) {
112 int is64 = HOTPATCH_EXE_IS_NEITHER;
113 /* magic number says this is an ELF file */
114 switch (e_ident[EI_CLASS]) {
115 case ELFCLASS32:
116 is64 = HOTPATCH_EXE_IS_32BIT;
117 if (verbose > 3)
118 fprintf(stderr, "[%s:%d] File is 32-bit ELF\n", __func__,
119 __LINE__);
120 break;
121 case ELFCLASS64:
122 is64 = HOTPATCH_EXE_IS_64BIT;
123 if (verbose > 3)
124 fprintf(stderr, "[%s:%d] File is 64-bit ELF\n", __func__,
125 __LINE__);
126 break;
127 case ELFCLASSNONE:
128 default:
129 is64 = HOTPATCH_EXE_IS_NEITHER;
130 if (verbose > 3)
131 fprintf(stderr, "[%s:%d] File is unsupported ELF\n",
132 __func__, __LINE__);
133 break;
134 }
135 if (is64 != HOTPATCH_EXE_IS_NEITHER) {
136 int isbigendian = -1;
137 int iscurrent = 0;
138 int islinux = 0;
139 switch (e_ident[EI_DATA]) {
140 case ELFDATA2LSB:
141 isbigendian = 0;
142 if (verbose > 3)
143 fprintf(stderr, "[%s:%d] Little endian format.\n",
144 __func__, __LINE__);
145 break;
146 case ELFDATA2MSB:
147 isbigendian = 1;
148 if (verbose > 3)
149 fprintf(stderr, "[%s:%d] Big endian format.\n",
150 __func__, __LINE__);
151 break;
152 case ELFDATANONE:
153 default:
154 isbigendian = -1;
155 if (verbose > 2)
156 fprintf(stderr, "[%s:%d] Unknown endian format.\n",
157 __func__, __LINE__);
158 break;
159 }
160 if (e_ident[EI_VERSION] == EV_CURRENT) {
161 iscurrent = 1;
162 if (verbose > 3)
163 fprintf(stderr, "[%s:%d] Current ELF format.\n",
164 __func__, __LINE__);
165 }
166 if (verbose > 3)
167 fprintf(stderr, "[%s:%d] ELFOSABI: %d\n", __func__,
168 __LINE__, e_ident[EI_OSABI]);
169 if (e_ident[EI_OSABI] == ELFOSABI_LINUX ||
170 e_ident[EI_OSABI] == ELFOSABI_SYSV) {
171 islinux = 1;
172 if (verbose > 3)
173 fprintf(stderr, "[%s:%d] OS ABI is Linux.\n", __func__,
174 __LINE__);
175 }
176 if (islinux && isbigendian == 0 && iscurrent) {
177 return is64;
178 }
179 if (verbose > 1)
180 fprintf(stderr, "[%s:%d] Not an acceptable header.\n",
181 __func__, __LINE__);
182 }
183 } else {
184 if (verbose > 3)
185 fprintf(stderr, "[%s:%d] This is not an ELF file format.\n",
186 __func__, __LINE__);
187 }
188 }
189 return HOTPATCH_EXE_IS_NEITHER;
190 }
191
192 static int exe_load_symbol_table(struct elf_internals *ei, Elf_Shdr *symh,
193 Elf_Shdr *strh, int verbose)
194 {
195 char *strsymtbl = NULL;
196 size_t strsymtbl_size = 0;
197 while (ei && symh && strh) {
198 if (verbose > 3)
199 fprintf(stderr, "[%s:%d] Retrieving symbol table.\n", __func__,
200 __LINE__);
201 if (lseek(ei->fd, strh->sh_offset, SEEK_SET) < 0) {
202 LOG_ERROR_FILE_SEEK;
203 break;
204 }
205 strsymtbl_size = strh->sh_size + 0;
206 strsymtbl = malloc(strh->sh_size);
207 if (!strsymtbl) {
208 LOG_ERROR_OUT_OF_MEMORY;
209 break;
210 }
211 if (read(ei->fd, strsymtbl, strh->sh_size) < 0) {
212 LOG_ERROR_FILE_READ;
213 break;
214 }
215 if (symh->sh_entsize > 0 && symh->sh_size > 0) {
216 size_t idx;
217 size_t sym_num = symh->sh_size / symh->sh_entsize;
218 Elf_Sym *syms = malloc(symh->sh_size);
219 if (!syms) {
220 LOG_ERROR_OUT_OF_MEMORY;
221 break;
222 }
223 if (lseek(ei->fd, symh->sh_offset, SEEK_SET) < 0) {
224 LOG_ERROR_FILE_SEEK;
225 free(syms);
226 break;
227 }
228 if (read(ei->fd, syms, symh->sh_size) < 0) {
229 LOG_ERROR_FILE_READ;
230 free(syms);
231 break;
232 }
233 /* there might already exist symbols from another section.
234 * hence using realloc() takes care of that.
235 * */
236 ei->symbols = realloc(ei->symbols,
237 (sym_num + ei->symbols_num) *
238 sizeof(*ei->symbols));
239 if (!ei->symbols) {
240 LOG_ERROR_OUT_OF_MEMORY;
241 break;
242 }
243 memset(&ei->symbols[ei->symbols_num], 0, sizeof(*ei->symbols) * sym_num);
244 /* index 0 is always NULL */
245 for (idx = 1; idx < sym_num; ++idx) {
246 const char *name = syms[idx].st_name > 0 ?
247 &strsymtbl[syms[idx].st_name] : "";
248 if (name) {
249 char *name2;
250 int symtype = exe_get_hotpatch_type(syms[idx].st_info,
251 HOTPATCH_SYMBOL_TYPE);
252 if (verbose > 2)
253 fprintf(stderr,
254 "[%s:%d] Symbol "LU" is %s at %p type %d size "LU"\n",
255 __func__, __LINE__, idx, name,
256 (void *)syms[idx].st_value, symtype,
257 syms[idx].st_size);
258 name2 = strdup(name);
259 if (!name2) {
260 LOG_ERROR_OUT_OF_MEMORY;
261 continue;
262 }
263 ei->symbols[ei->symbols_num].name = name2;
264 ei->symbols[ei->symbols_num].address = (uintptr_t)syms[idx].st_value;
265 ei->symbols[ei->symbols_num].size = (size_t)syms[idx].st_size;
266 ei->symbols[ei->symbols_num].type = symtype;
267 ei->symbols_num++;
268 }
269 }
270 free(syms);
271 if (strsymtbl)
272 free(strsymtbl);
273 return 0;
274 }
275 }
276 if (strsymtbl)
277 free(strsymtbl);
278 return -1;
279 }
280
281 static int exe_load_section_headers(struct elf_internals *ei, int verbose)
282 {
283 Elf_Shdr *strsectblhdr = NULL;
284 Elf_Shdr *sechdrs = NULL;
285 size_t idx = 0;
286 ssize_t symtab = -1;
287 ssize_t strtab = -1;
288
289 if (!ei || ei->sechdr_offset == 0 || ei->sechdr_size == 0)
290 return -1;
291 if (verbose > 3)
292 fprintf(stderr, "[%s:%d] Retrieving section headers.\n", __func__,
293 __LINE__);
294 ei->sechdrs = malloc(ei->sechdr_size);
295 if (!ei->sechdrs) {
296 LOG_ERROR_OUT_OF_MEMORY;
297 return -1;
298 }
299 memset(ei->sechdrs, 0, ei->sechdr_size);
300 if (verbose > 3)
301 fprintf(stderr, "[%s:%d] Reading section header offset at "LU"\n",
302 __func__, __LINE__, (size_t)ei->sechdr_offset);
303 if (lseek(ei->fd, ei->sechdr_offset, SEEK_SET) < 0) {
304 LOG_ERROR_FILE_SEEK;
305 return -1;
306 }
307 if (read(ei->fd, ei->sechdrs, ei->sechdr_size) < 0) {
308 LOG_ERROR_FILE_READ;
309 return -1;
310 }
311 sechdrs = (Elf_Shdr *)ei->sechdrs;
312 strsectblhdr = &sechdrs[ei->secnametbl_idx];
313 if (lseek(ei->fd, strsectblhdr->sh_offset, SEEK_SET) < 0) {
314 LOG_ERROR_FILE_SEEK;
315 return -1;
316 }
317 ei->strsectbl = malloc(strsectblhdr->sh_size);
318 if (!ei->strsectbl) {
319 LOG_ERROR_OUT_OF_MEMORY;
320 return -1;
321 }
322 ei->strsectbl_size = strsectblhdr->sh_size + 0;
323 if (read(ei->fd, ei->strsectbl, strsectblhdr->sh_size) < 0) {
324 LOG_ERROR_FILE_READ;
325 return -1;
326 }
327 if (verbose > 3)
328 fprintf(stderr, "[%s:%d] Number of sections: "LU"\n", __func__, __LINE__,
329 ei->sechdr_num);
330 for (idx = 0; idx < ei->sechdr_num; ++idx) {
331 const char *name = &ei->strsectbl[sechdrs[idx].sh_name];
332 if (verbose > 2) {
333 if (name)
334 fprintf(stderr, "[%s:%d] Section name: %s Addr: %p Len: "LU"\n",
335 __func__, __LINE__, name, (void *)sechdrs[idx].sh_offset,
336 sechdrs[idx].sh_size);
337 else
338 fprintf(stderr, "[%s:%d] Section name: %s Addr: %p Len: "LU"\n",
339 __func__, __LINE__, "N/A", (void *)sechdrs[idx].sh_offset,
340 sechdrs[idx].sh_size);
341 }
342 switch (sechdrs[idx].sh_type) {
343 case SHT_SYMTAB:
344 case SHT_DYNSYM:
345 symtab = idx;
346 if (verbose > 3)
347 fprintf(stderr, "[%s:%d] Symbol table offset: "LU" size: "LU" "
348 "entsize: "LU" entries: "LU"\n",
349 __func__, __LINE__, sechdrs[idx].sh_offset,
350 sechdrs[idx].sh_size, sechdrs[idx].sh_entsize,
351 (sechdrs[idx].sh_entsize > 0 ? sechdrs[idx].sh_size / sechdrs[idx].sh_entsize : 0));
352 break;
353 case SHT_STRTAB:
354 if (idx != ei->secnametbl_idx) {
355 strtab = idx;
356 if (verbose > 2)
357 fprintf(stderr, "[%s:%d] Reading symbol table from %s\n",
358 __func__, __LINE__, name);
359 if (symtab >= 0 && exe_load_symbol_table(ei, &sechdrs[symtab],
360 &sechdrs[strtab], verbose) < 0) {
361 fprintf(stderr, "[%s:%d] Failed to retrieve symbol "
362 "table.\n", __func__, __LINE__);
363 }
364 symtab = -1;
365 }
366 break;
367 default:
368 break;
369 }
370 }
371 return 0;
372 }
373
374 static int exe_load_program_headers(struct elf_internals *ei, int verbose)
375 {
376 Elf_Phdr *proghdrs = NULL;
377 size_t idx = 0;
378 int rc = 0;
379 if (!ei || ei->proghdr_offset == 0 || ei->proghdr_size == 0)
380 return -1;
381 ei->proghdrs = malloc(ei->proghdr_size);
382 if (!ei->proghdrs) {
383 LOG_ERROR_OUT_OF_MEMORY;
384 return -1;
385 }
386 memset(ei->proghdrs, 0, ei->proghdr_size);
387 if (lseek(ei->fd, ei->proghdr_offset, SEEK_SET) < 0) {
388 LOG_ERROR_FILE_SEEK;
389 return -1;
390 }
391 if (read(ei->fd, ei->proghdrs, ei->proghdr_size) < 0) {
392 LOG_ERROR_FILE_READ;
393 return -1;
394 }
395 if (verbose > 3)
396 fprintf(stderr, "[%s:%d] Number of segments: "LU"\n", __func__, __LINE__,
397 ei->proghdr_num);
398 proghdrs = (Elf_Phdr *)ei->proghdrs;
399 for (idx = 0; idx < ei->proghdr_num; ++idx) {
400 rc = 0;
401 if (verbose > 2) {
402 fprintf(stderr,
403 "[%s:%d] Prog-header "LU": Type: %d "
404 "VAddr: %p PAddr: %p FileSz: "LU" MemSz: "LU"\n",
405 __func__, __LINE__, idx, proghdrs[idx].p_type,
406 (void *)proghdrs[idx].p_vaddr,
407 (void *)proghdrs[idx].p_paddr,
408 proghdrs[idx].p_filesz, proghdrs[idx].p_memsz);
409 }
410 if (proghdrs[idx].p_type == PT_INTERP) {
411 if (verbose > 1)
412 fprintf(stderr, "[%s:%d] PT_INTERP section found\n", __func__,
413 __LINE__);
414 if (proghdrs[idx].p_filesz == 0)
415 continue;
416 if (lseek(ei->fd, proghdrs[idx].p_offset, SEEK_SET) < 0) {
417 LOG_ERROR_FILE_SEEK;
418 rc = -1;
419 break;
420 }
421 if (ei->interp.name) {
422 free(ei->interp.name);
423 memset(&ei->interp, 0, sizeof(ei->interp));
424 }
425 ei->interp.name = malloc(proghdrs[idx].p_filesz);
426 if (!ei->interp.name) {
427 LOG_ERROR_OUT_OF_MEMORY;
428 rc = -1;
429 break;
430 }
431 if (read(ei->fd, ei->interp.name, proghdrs[idx].p_filesz) < 0) {
432 LOG_ERROR_FILE_READ;
433 rc = -1;
434 break;
435 }
436 ei->interp.length = proghdrs[idx].p_filesz;
437 ei->interp.ph_addr = proghdrs[idx].p_vaddr;
438 if (verbose > 1)
439 fprintf(stderr, "[%s:%d] Found %s at V-Addr 0x"LX"\n",
440 __func__, __LINE__, ei->interp.name,
441 ei->interp.ph_addr);
442 } else if (proghdrs[idx].p_type == PT_DYNAMIC) {
443 if (verbose > 1)
444 fprintf(stderr, "[%s:%d] PT_DYNAMIC section found\n", __func__,
445 __LINE__);
446 } else if (proghdrs[idx].p_type == PT_LOAD) {
447 if (verbose > 1)
448 fprintf(stderr, "[%s:%d] PT_LOAD section found\n", __func__,
449 __LINE__);
450 }
451 }
452 return rc;
453 }
454
455 static int exe_load_headers(struct elf_internals *ei, int verbose)
456 {
457 Elf_Ehdr hdr;
458 int fd = -1;
459 if (!ei) {
460 return -1;
461 }
462 fd = ei->fd;
463 memset(&hdr, 0, sizeof(hdr));
464 if (lseek(fd, 0, SEEK_SET) < 0) {
465 LOG_ERROR_FILE_SEEK;
466 return -1;
467 }
468 if (read(fd, &hdr, sizeof(hdr)) < 0) {
469 LOG_ERROR_FILE_READ;
470 return -1;
471 }
472 if (verbose > 3)
473 fprintf(stderr, "[%s:%d] Reading Elf header.\n", __func__, __LINE__);
474 ei->is64 = exe_elf_identify(hdr.e_ident, EI_NIDENT, verbose);
475 switch (ei->is64) {
476 case HOTPATCH_EXE_IS_64BIT:
477 if (verbose > 3)
478 fprintf(stderr, "[%s:%d] 64-bit valid exe\n", __func__, __LINE__);
479 break;
480 case HOTPATCH_EXE_IS_32BIT:
481 if (verbose > 3)
482 fprintf(stderr, "[%s:%d] 32-bit valid exe\n", __func__, __LINE__);
483 break;
484 case HOTPATCH_EXE_IS_NEITHER:
485 default:
486 return -1;
487 }
488 if (verbose > 1)
489 fprintf(stderr, "[%s:%d] Entry point %p\n", __func__, __LINE__,
490 (void *)hdr.e_entry);
491 ei->entry_point = (uintptr_t)hdr.e_entry;
492 if (hdr.e_machine != EM_X86_64 && hdr.e_machine != EM_386) {
493 LOG_ERROR_UNSUPPORTED_PROCESSOR;
494 return -1;
495 }
496 if (hdr.e_shoff > 0) {
497 ei->sechdr_offset = 0 + hdr.e_shoff;
498 ei->sechdr_num = 0 + hdr.e_shnum;
499 ei->sechdr_size = 0 + hdr.e_shnum * hdr.e_shentsize;
500 ei->secnametbl_idx = 0 + hdr.e_shstrndx;
501 }
502 if (hdr.e_phoff > 0) {
503 ei->proghdr_offset = 0 + hdr.e_phoff;
504 ei->proghdr_num = 0 + hdr.e_phnum;
505 ei->proghdr_size = 0 + hdr.e_phnum * hdr.e_phentsize;
506 }
507 if (exe_load_section_headers(ei, verbose) < 0) {
508 fprintf(stderr, "[%s:%d] Error in loading section headers\n",
509 __func__, __LINE__);
510 return -1;
511 }
512 if (exe_load_program_headers(ei, verbose) < 0) {
513 fprintf(stderr, "[%s:%d] Error in loading section headers\n",
514 __func__, __LINE__);
515 return -1;
516 }
517 return 0;
518 }
519
520 struct elf_symbol *exe_load_symbols(const char *filename, int verbose,
521 size_t *symbols_num,
522 uintptr_t *entry_point,
523 struct elf_interp *interp,
524 enum elf_bit *is64)
525 {
526 int rc = 0;
527 struct elf_symbol *symbols = NULL;
528 struct elf_internals ei;
529 memset(&ei, 0, sizeof(ei));
530 if (entry_point)
531 *entry_point = 0;
532 ei.fd = exe_open_filename(filename, verbose);
533 if (ei.fd < 0) {
534 return NULL;
535 }
536 if ((rc = exe_load_headers(&ei, verbose)) < 0) {
537 fprintf(stderr, "[%s:%d] Unable to load Elf details for %s\n",
538 __func__, __LINE__, filename);
539 }
540 if (verbose > 3)
541 fprintf(stderr, "[%s:%d] Freeing internal structure.\n",
542 __func__, __LINE__);
543 if (ei.fd >= 0)
544 close(ei.fd);
545 ei.fd = -1;
546 ei.strsectbl_size = 0;
547 if (ei.strsectbl) {
548 free(ei.strsectbl);
549 ei.strsectbl = NULL;
550 }
551 if (ei.sechdrs) {
552 free(ei.sechdrs);
553 ei.sechdrs = NULL;
554 }
555 if (ei.proghdrs) {
556 free(ei.proghdrs);
557 ei.proghdrs = NULL;
558 }
559 if (rc < 0) {
560 if (ei.interp.name)
561 free(ei.interp.name);
562 ei.interp.name = NULL;
563 if (ei.symbols) {
564 size_t idx;
565 for (idx = 0; idx < ei.symbols_num; ++idx) {
566 free(ei.symbols[idx].name);
567 ei.symbols[idx].name = NULL;
568 }
569 free(ei.symbols);
570 }
571 ei.symbols = NULL;
572 ei.symbols_num = 0;
573 } else {
574 if (verbose > 2)
575 fprintf(stderr, "[%s:%d] Readying return values.\n",
576 __func__, __LINE__);
577 symbols = ei.symbols;
578 if (symbols_num)
579 *symbols_num = ei.symbols_num;
580 if (interp) {
581 interp->name = ei.interp.name;
582 interp->length = ei.interp.length;
583 interp->ph_addr = ei.interp.ph_addr;
584 } else {
585 if (ei.interp.name)
586 free(ei.interp.name);
587 ei.interp.name = NULL;
588 }
589 if (is64)
590 *is64 = ei.is64;
591 if (entry_point)
592 *entry_point = ei.entry_point;
593 }
594 return symbols;
595 }
596
597 int elf_symbol_cmpqsort(const void *p1, const void *p2)
598 {
599 return strcmp(((const struct elf_symbol *)p1)->name,
600 ((const struct elf_symbol *)p2)->name);
601 }
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <hotpatch_config.h>
31 #include <hotpatch_internal.h>
32 #include <hotpatch.h>
33 #ifdef HOTPATCH_USE_ASM
34 #include <call32.h>
35 #include <call64.h>
36 #endif
37
38 #define LIB_LD "ld"
39 #define LIB_C "libc"
40 #define LIB_DL "libdl"
41 #define LIB_PTHREAD "libpthread"
42
43 static int hotpatch_gather_functions(hotpatch_t *hp)
44 {
45 int verbose = 0;
46 bool ld_found = false;
47 bool c_found = false;
48 bool dl_found = false;
49 bool pthread_found = false;
50 if (!hp || !hp->libs)
51 return -1;
52 verbose = hp->verbose;
53 if (hp->ld_maps_num <= 0)
54 return -1;
55 memset(hp->libs, 0, sizeof(hp->libs));
56 #undef LD_PROCMAPS_FIND_LIB
57 #define LD_PROCMAPS_FIND_LIB(name,flag,index,retval) \
58 do { \
59 if (verbose > 2) \
60 fprintf(stderr, "[%s:%d] Checking if %s exists in procmaps.\n",\
61 __func__, __LINE__, name);\
62 if (ld_find_library(hp->ld_maps, hp->ld_maps_num, \
63 name, flag, &hp->libs[index], verbose) < 0) { \
64 if (verbose > 0) \
65 fprintf(stderr, "[%s:%d] %s not mapped.\n", \
66 __func__, __LINE__, name); \
67 retval = false; \
68 } else { \
69 retval = true; \
70 if (verbose > 2) \
71 fprintf(stderr, "[%s:%d] Found %s\n", \
72 __func__, __LINE__, name); \
73 } \
74 } while (0)
75 #undef LD_LIB_FIND_FN_ADDR
76 #define LD_LIB_FIND_FN_ADDR(fn,outfn,index) \
77 do { \
78 if (outfn) break; \
79 outfn = ld_find_address(&hp->libs[HOTPATCH_##index], fn, verbose); \
80 if (outfn != 0) { \
81 if (verbose > 0) \
82 fprintf(stderr, "[%s:%d] Found %s at 0x"LX" in %s\n", \
83 __func__, __LINE__, fn, outfn, index); \
84 } else { \
85 if (verbose > 0) \
86 fprintf(stderr, "[%s:%d] %s not found in %s.\n", \
87 __func__, __LINE__, fn, index); \
88 } \
89 } while (0)
90 if (hp->exe_interp.name) {
91 LD_PROCMAPS_FIND_LIB(hp->exe_interp.name, true, HOTPATCH_LIB_LD,
92 ld_found);
93 }
94 if (!ld_found) {
95 if (verbose > 1)
96 fprintf(stderr, "[%s:%d] No interpreter found. Guessing.\n",
97 __func__, __LINE__);
98 LD_PROCMAPS_FIND_LIB(LIB_LD, false, HOTPATCH_LIB_LD, ld_found);
99 }
100 LD_PROCMAPS_FIND_LIB(LIB_C, false, HOTPATCH_LIB_C, c_found);
101 LD_PROCMAPS_FIND_LIB(LIB_DL, false, HOTPATCH_LIB_DL, dl_found);
102 LD_PROCMAPS_FIND_LIB(LIB_PTHREAD, false, HOTPATCH_LIB_PTHREAD,
103 pthread_found);
104 if (c_found) {
105 LD_LIB_FIND_FN_ADDR("malloc", hp->fn_malloc, LIB_C);
106 LD_LIB_FIND_FN_ADDR("realloc", hp->fn_realloc, LIB_C);
107 LD_LIB_FIND_FN_ADDR("free", hp->fn_free, LIB_C);
108 }
109 if (ld_found) {
110 LD_LIB_FIND_FN_ADDR("malloc", hp->fn_malloc, LIB_LD);
111 LD_LIB_FIND_FN_ADDR("realloc", hp->fn_realloc, LIB_LD);
112 LD_LIB_FIND_FN_ADDR("free", hp->fn_free, LIB_LD);
113 }
114 if (!hp->fn_malloc || !hp->fn_realloc || !hp->fn_free) {
115 if (verbose > 0)
116 fprintf(stderr, "[%s:%d] Some memory allocation routines are"
117 " unavailable. Cannot proceed.\n", __func__, __LINE__);
118 return -1;
119 }
120 if (dl_found) {
121 LD_LIB_FIND_FN_ADDR("dlopen", hp->fn_dlopen, LIB_DL);
122 LD_LIB_FIND_FN_ADDR("dlclose", hp->fn_dlclose, LIB_DL);
123 LD_LIB_FIND_FN_ADDR("dlsym", hp->fn_dlsym, LIB_DL);
124 } else {
125 LD_LIB_FIND_FN_ADDR("__libc_dlopen_mode", hp->fn_dlopen, LIB_C);
126 LD_LIB_FIND_FN_ADDR("__libc_dlclose", hp->fn_dlclose, LIB_C);
127 LD_LIB_FIND_FN_ADDR("__libc_dlsym", hp->fn_dlsym, LIB_C);
128 }
129 if (!hp->fn_dlopen || !hp->fn_dlsym) {
130 if (verbose > 0)
131 fprintf(stderr, "[%s:%d] Dynamic Library loading routines were not"
132 " found. Cannot proceed.\n", __func__, __LINE__);
133 return -1;
134 }
135 if (pthread_found) {
136 LD_LIB_FIND_FN_ADDR("pthread_create", hp->fn_pthread_create,
137 LIB_PTHREAD);
138 LD_LIB_FIND_FN_ADDR("pthread_detach", hp->fn_pthread_detach,
139 LIB_PTHREAD);
140 } else {
141 hp->fn_pthread_create = hp->fn_pthread_detach = 0;
142 }
143 if (verbose > 1) {
144 if (hp->fn_pthread_create && hp->fn_pthread_detach)
145 fprintf(stderr, "[%s:%d] Pthread's symbol found. Do not need more"
146 " magic.\n", __func__, __LINE__);
147 else
148 fprintf(stderr, "[%s:%d] Pthread's symbol not found. Will disable"
149 " pthread usage in injection.\n", __func__, __LINE__);
150 }
151 #undef LD_PROCMAPS_FIND_LIB
152 #undef LD_LIB_FIND_FN_ADDR
153 return 0;
154 }
155
156 void hotpatch_version(int *major, int *minor)
157 {
158 if (major)
159 *major = HOTPATCH_MAJOR_VERSION;
160 if (minor)
161 *minor = HOTPATCH_MINOR_VERSION;
162 }
163
164 hotpatch_t *hotpatch_create(pid_t pid, int verbose)
165 {
166 int rc = 0;
167 hotpatch_t *hp = NULL;
168 do {
169 char filename[OS_MAX_BUFFER];
170 if (pid <= 0) {
171 LOG_ERROR_INVALID_PID(pid);
172 break;
173 }
174 memset(filename, 0, sizeof(filename));
175 snprintf(filename, sizeof(filename), "/proc/%d/exe", pid);
176 if (verbose > 3)
177 fprintf(stderr, "[%s:%d] Exe symlink for pid %d : %s\n", __func__,
178 __LINE__, pid, filename);
179 hp = malloc(sizeof(*hp));
180 if (!hp) {
181 LOG_ERROR_OUT_OF_MEMORY;
182 rc = -1;
183 break;
184 }
185 memset(hp, 0, sizeof(*hp));
186 hp->verbose = verbose;
187 hp->pid = pid;
188 hp->is64 = HOTPATCH_EXE_IS_NEITHER;
189 hp->exe_symbols = exe_load_symbols(filename, hp->verbose,
190 &hp->exe_symbols_num,
191 &hp->exe_entry_point,
192 &hp->exe_interp,
193 &hp->is64);
194 if (!hp->exe_symbols) {
195 fprintf(stderr, "[%s:%d] Unable to find any symbols in exe.\n",
196 __func__, __LINE__);
197 rc = -1;
198 break;
199 }
200 if (hp->exe_entry_point == 0) {
201 fprintf(stderr, "[%s:%d] Entry point is 0. Invalid.\n",
202 __func__, __LINE__);
203 rc = -1;
204 break;
205 }
206 LOG_INFO_HEADERS_LOADED(verbose);
207 hp->ld_maps = ld_load_maps(hp->pid, hp->verbose, &hp->ld_maps_num);
208 if (!hp->ld_maps) {
209 fprintf(stderr, "[%s:%d] Unable to load data in "
210 "/proc/%d/maps.\n", __func__, __LINE__, pid);
211 rc = -1;
212 break;
213 }
214 if (verbose > 2)
215 fprintf(stderr, "[%s:%d] /proc/%d/maps loaded.\n",
216 __func__, __LINE__, pid);
217 if (hp->exe_symbols && hp->exe_symbols_num > 0) {
218 qsort(hp->exe_symbols, hp->exe_symbols_num,
219 sizeof(*hp->exe_symbols), elf_symbol_cmpqsort);
220 }
221 if (hotpatch_gather_functions(hp) < 0) {
222 fprintf(stderr, "[%s:%d] Unable to find all the functions"
223 " needed. Cannot proceed.\n", __func__, __LINE__);
224 rc = -1;
225 break;
226 }
227 if (rc < 0) {
228 hotpatch_destroy(hp);
229 hp = NULL;
230 }
231 } while (0);
232 return hp;
233 }
234
235 void hotpatch_destroy(hotpatch_t *hp)
236 {
237 if (hp) {
238 size_t idx;
239 if (hp->attached)
240 hotpatch_detach(hp);
241 if (hp->exe_symbols) {
242 for (idx = 0; idx < hp->exe_symbols_num; ++idx) {
243 free(hp->exe_symbols[idx].name);
244 hp->exe_symbols[idx].name = NULL;
245 }
246 free(hp->exe_symbols);
247 }
248 hp->exe_symbols = NULL;
249 hp->exe_symbols_num = 0;
250 if (hp->exe_interp.name) {
251 free(hp->exe_interp.name);
252 hp->exe_interp.name = NULL;
253 }
254 for (idx = 0; idx < HOTPATCH_LIB_MAX; ++idx) {
255 if (hp->libs[idx].pathname)
256 free(hp->libs[idx].pathname);
257 hp->libs[idx].pathname = NULL;
258 }
259 memset(hp->libs, 0, sizeof(hp->libs));
260 if (hp->ld_maps) {
261 ld_free_maps(hp->ld_maps, hp->ld_maps_num);
262 hp->ld_maps = NULL;
263 hp->ld_maps_num = 0;
264 }
265 free(hp);
266 hp = NULL;
267 }
268 }
269
270 uintptr_t hotpatch_read_symbol(hotpatch_t *hp, const char *symbol, int *type, size_t *sz)
271 {
272 uintptr_t ptr = 0;
273 size_t idx = 0;
274 if (!hp || !symbol || !hp->exe_symbols) {
275 if (hp->verbose > 2)
276 fprintf(stderr, "[%s:%d] Invalid arguments.\n", __func__, __LINE__);
277 return (uintptr_t)0;
278 }
279 for (idx = 0; idx < hp->exe_symbols_num; ++idx) {
280 const char *name = hp->exe_symbols[idx].name;
281 if (strcmp(name, symbol) == 0) {
282 if (hp->verbose > 1)
283 fprintf(stderr, "[%s:%d] Found %s in symbol list at "LU"\n",
284 __func__, __LINE__, symbol, idx);
285 ptr = hp->exe_symbols[idx].address;
286 if (type)
287 *type = hp->exe_symbols[idx].type;
288 if (sz)
289 *sz = hp->exe_symbols[idx].size;
290 break;
291 }
292 }
293 if (hp->verbose > 2)
294 fprintf(stderr, "[%s:%d] Symbol %s has address 0x"LX"\n", __func__,
295 __LINE__, symbol, ptr);
296 return ptr;
297 }
298
299 uintptr_t hotpatch_get_entry_point(hotpatch_t *hp)
300 {
301 return hp ? hp->exe_entry_point : 0;
302 }
303
304 size_t hotpatch_strnlen(const char *str, size_t maxlen)
305 {
306 size_t len = 0;
307 /* succinct code */
308 if (str)
309 while (len < maxlen && str[len++] != '\0');
310 return len;
311 }
312
313 int hotpatch_attach(hotpatch_t *hp)
314 {
315 if (!hp)
316 return -1;
317 if (!hp->attached) {
318 hp->attached = false;
319 if (hp->verbose > 3)
320 fprintf(stderr, "[%s:%d] Trying to attach to PID %d\n", __func__,
321 __LINE__, hp->pid);
322 if (ptrace(PTRACE_ATTACH, hp->pid, NULL, NULL) < 0) {
323 int err = errno;
324 fprintf(stderr, "[%s:%d] Ptrace Attach failed with error %s\n",
325 __func__, __LINE__, strerror(err));
326 } else {
327 int status = 0;
328 if (hp->verbose > 1)
329 fprintf(stderr, "[%s:%d] Waiting for the child.\n", __func__,
330 __LINE__);
331 if (waitpid(-1, &status, 0) < 0) {
332 int err = errno;
333 fprintf(stderr, "[%s:%d] Waitpid failed with error: %s\n",
334 __func__, __LINE__, strerror(err));
335 } else {
336 if (WIFEXITED(status) || WIFSIGNALED(status)) {
337 fprintf(stderr, "[%s:%d] PID %d was terminated.\n",
338 __func__, __LINE__, hp->pid);
339 } else {
340 hp->attached = true;
341 if (hp->verbose > 0)
342 fprintf(stderr, "[%s:%d] Attached to PID %d\n",
343 __func__, __LINE__, hp->pid);
344 }
345 }
346 }
347 }
348 return hp->attached ? 0 : -1;
349 }
350
351 int hotpatch_detach(hotpatch_t *hp)
352 {
353 int rc = -1;
354 if (hp && hp->attached) {
355 if (hp->verbose > 3)
356 fprintf(stderr, "[%s:%d] Detaching from PID %d\n", __func__,
357 __LINE__, hp->pid);
358 if (ptrace(PTRACE_DETACH, hp->pid, NULL, NULL) < 0) {
359 int err = errno;
360 fprintf(stderr, "[%s:%d] Ptrace detach failed with error %s\n",
361 __func__, __LINE__, strerror(err));
362 } else {
363 rc = 0;
364 if (hp->verbose > 0)
365 fprintf(stderr, "[%s:%d] Detached from PID %d\n", __func__,
366 __LINE__, hp->pid);
367 }
368 hp->attached = false;
369 }
370 return rc;
371 }
372
373
374 static int hp_attach(pid_t pid)
375 {
376 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
377 int err = errno;
378 fprintf(stderr,
379 "[%s:%d] Ptrace Attach for PID %d failed with error: %s\n",
380 __func__, __LINE__, pid, strerror(err));
381 return -1;
382 }
383 return 0;
384 }
385
386 static int hp_detach(pid_t pid)
387 {
388 if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {
389 int err = errno;
390 fprintf(stderr,
391 "[%s:%d] Ptrace Detach for PID %d failed with error: %s\n",
392 __func__, __LINE__, pid, strerror(err));
393 return -1;
394 }
395 return 0;
396 }
397
398 static int hp_exec(pid_t pid)
399 {
400 if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
401 int err = errno;
402 fprintf(stderr,
403 "[%s:%d] Ptrace Continue for PID %d failed with error: %s\n",
404 __func__, __LINE__, pid, strerror(err));
405 return -1;
406 }
407 return 0;
408 }
409
410 static int hp_wait(pid_t pid)
411 {
412 int status = 0;
413 if (waitpid(pid, &status, 0) < 0) {
414 int err = errno;
415 fprintf(stderr, "[%s:%d] Waitpid for PID %d failed with error: %s\n",
416 __func__, __LINE__, pid, strerror(err));
417 return -1;
418 }
419 if (WIFEXITED(status) || WIFSIGNALED(status)) {
420 fprintf(stderr, "[%s:%d] PID %d was terminated.\n",
421 __func__, __LINE__, pid);
422 return -1;
423 }
424 return 0;
425 }
426
427 static int hp_get_regs(pid_t pid, struct user *regs)
428 {
429 if (!regs)
430 return -1;
431 memset(regs, 0, sizeof(*regs));
432 if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) {
433 int err = errno;
434 fprintf(stderr,
435 "[%s:%d] Ptrace Getregs for PID %d failed with error: %s\n",
436 __func__, __LINE__, pid, strerror(err));
437 return -1;
438 }
439 return 0;
440 }
441
442 static int hp_set_regs(pid_t pid, const struct user *regs)
443 {
444 if (!regs)
445 return -1;
446 if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) {
447 int err = errno;
448 fprintf(stderr,
449 "[%s:%d] Ptrace Setregs for PID %d failed with error: %s\n",
450 __func__, __LINE__, pid, strerror(err));
451 return -1;
452 }
453 return 0;
454 }
455
456 static int hp_copydata(pid_t pid, uintptr_t target,
457 const unsigned char *data, size_t datasz, int verbose)
458 {
459 size_t pos = 0;
460 size_t idx = 0;
461 while (pos < datasz) {
462 size_t pokedata = 0, jdx = 0;
463 const size_t pksz = sizeof(size_t);
464 for (jdx = 0; jdx < pksz && pos < datasz; ++jdx)
465 ((unsigned char *)&pokedata)[jdx] = data[pos++];
466 if (verbose > 2)
467 fprintf(stderr, "[%s:%d] Pokedata: %p\n", __func__, __LINE__,
468 (void *)pokedata);
469 if (ptrace(PTRACE_POKEDATA, pid, target + idx,
470 pokedata) < 0) {
471 int err = errno;
472 fprintf(stderr,
473 "[%s:%d] Ptrace PokeText for PID %d failed with error: %s\n",
474 __func__, __LINE__, pid, strerror(err));
475 return -1;
476 }
477 idx += sizeof(size_t);
478 }
479 return 0;
480 }
481
482 static int hp_peekdata(pid_t pid, uintptr_t target, uintptr_t *outpeek,
483 int verbose)
484 {
485 int err = 0;
486 long peekdata = ptrace(PTRACE_PEEKDATA, pid, target, NULL);
487 err = errno;
488 if (verbose > 2)
489 fprintf(stderr, "[%s:%d] Peekdata: %p\n", __func__, __LINE__,
490 (void *)peekdata);
491 if (peekdata == -1 && err != 0) {
492 fprintf(stderr,
493 "[%s:%d] Ptrace PeekText for PID %d failed with error: %s\n",
494 __func__, __LINE__, pid, strerror(err));
495 return -1;
496 }
497 if (outpeek)
498 *outpeek = peekdata;
499 else
500 fprintf(stderr, "[%s:%d] Invalid arguments.\n", __func__, __LINE__);
501 return outpeek ? 0 : -1;
502 }
503
504 static int hp_pokedata(pid_t pid, uintptr_t target, uintptr_t pokedata,
505 int verbose)
506 {
507 int err = 0;
508 if (verbose > 2)
509 fprintf(stderr, "[%s:%d] Pokedata: %p\n", __func__, __LINE__,
510 (void *)pokedata);
511 if (ptrace(PTRACE_POKEDATA, pid, target, (void *)pokedata) < 0) {
512 fprintf(stderr,
513 "[%s:%d] Ptrace PokeText for PID %d failed with error: %s\n",
514 __func__, __LINE__, pid, strerror(err));
515 return -1;
516 }
517 return 0;
518 }
519
520 int hotpatch_set_execution_pointer(hotpatch_t *hp, uintptr_t ptr)
521 {
522 #undef HP_REG_IP_STR
523 #undef HP_REG_IP
524 #undef HP_REG_SP
525 #undef HP_REG_AX
526 #if __WORDSIZE == 64
527 #define HP_REG_IP_STR "RIP"
528 #define HP_REG_IP(A) A.regs.rip
529 #define HP_REG_SP(A) A.regs.rsp
530 #define HP_REG_AX(A) A.regs.rax
531 #else
532 #define HP_REG_IP_STR "EIP"
533 #define HP_REG_IP(A) A.regs.eip
534 #define HP_REG_SP(A) A.regs.esp
535 #define HP_REG_AX(A) A.regs.eax
536 #endif
537 int rc = -1;
538 if (ptr && hp && hp->attached) {
539 struct user regs;
540 memset(&regs, 0, sizeof(regs));
541 if (ptrace(PTRACE_GETREGS, hp->pid, NULL, &regs) < 0) {
542 int err = errno;
543 fprintf(stderr, "[%s:%d] Ptrace getregs failed with error %s\n",
544 __func__, __LINE__, strerror(err));
545 } else {
546 if (hp->verbose > 1)
547 fprintf(stderr, "[%s:%d] %s is %p\n", __func__, __LINE__,
548 HP_REG_IP_STR,
549 (void *)HP_REG_IP(regs));
550 if (ptr == hp->exe_entry_point)
551 ptr += sizeof(void *);
552 HP_REG_IP(regs) = ptr;
553 if (ptrace(PTRACE_SETREGS, hp->pid, NULL, &regs) < 0) {
554 int err = errno;
555 fprintf(stderr, "[%s:%d] Ptrace setregs failed with error %s\n",
556 __func__, __LINE__, strerror(err));
557 } else {
558 if (hp->verbose > 0)
559 fprintf(stderr, "[%s:%d] Set %s to 0x"LX"\n",
560 __func__, __LINE__, HP_REG_IP_STR, ptr);
561 rc = 0;
562 }
563 }
564 } else {
565 if (!ptr) {
566 fprintf(stderr, "[%s:%d] The execution pointer is null.\n",
567 __func__, __LINE__);
568 }
569 if (!hp || !hp->attached) {
570 fprintf(stderr, "[%s:%d] The process is not attached to.\n",
571 __func__, __LINE__);
572 }
573 }
574 return rc;
575 }
576
577 int hotpatch_inject_library(hotpatch_t *hp, const char *dll, const char *symbol,
578 const unsigned char *data, size_t datalen,
579 uintptr_t *outaddr, uintptr_t *outres)
580 {
581 size_t dllsz = 0;
582 size_t symsz = 0;
583 size_t datasz = 0;
584 size_t tgtsz = 0;
585 int rc = 0;
586 unsigned char *mdata = NULL;
587 if (!dll || !hp) {
588 fprintf(stderr, "[%s:%d] Invalid arguments.\n", __func__, __LINE__);
589 return -1;
590 }
591 if (!hp->fn_malloc || !hp->fn_dlopen) {
592 fprintf(stderr, "[%s:%d] No malloc/dlopen found.\n", __func__,
593 __LINE__);
594 return -1;
595 }
596 /* calculate the size to allocate */
597 dllsz = strlen(dll) + 1;
598 symsz = symbol ? (strlen(symbol) + 1) : 0;
599 datasz = data ? datalen : 0;
600 tgtsz = dllsz + symsz + datasz + 32; /* general buffer */
601 tgtsz = (tgtsz > 1024) ? tgtsz : 1024;
602 /* align the memory */
603 tgtsz += (tgtsz % sizeof(void *) == 0) ? 0 :
604 (sizeof(void *) - (tgtsz % sizeof(void *)));
605 mdata = calloc(sizeof(unsigned char), tgtsz);
606 if (!mdata) {
607 LOG_ERROR_OUT_OF_MEMORY;
608 return -1;
609 }
610 memcpy(mdata, dll, dllsz);
611 if (symbol) {
612 memcpy(mdata + dllsz, symbol, symsz);
613 }
614 if (data) {
615 memcpy(mdata + dllsz + symsz, data, datasz);
616 }
617 if (hp->verbose > 0)
618 fprintf(stderr, "[%s:%d] Allocating "LU" bytes in the target.\n",
619 __func__, __LINE__, tgtsz);
620 do {
621 /* The stack is read-write and not executable */
622 struct user iregs; /* intermediate registers */
623 struct user oregs; /* original registers */
624 int verbose = hp->verbose;
625 uintptr_t result = 0;
626 uintptr_t stack[4] = { 0, 0, 0, 0}; /* max arguments of the functions we
627 are using */
628 uintptr_t heapptr = 0;
629 int idx = 0;
630 #undef HP_SETEXECWAITGET
631 #undef HP_NULLIFYSTACK
632 #undef HP_PASS_ARGS2FUNC
633 #define HP_NULLIFYSTACK() \
634 do { \
635 uintptr_t nullcode = 0; \
636 if (verbose > 1) \
637 fprintf(stderr, "[%s:%d] Copying Null to stack.\n", \
638 __func__, __LINE__); \
639 if ((rc = hp_pokedata(hp->pid, HP_REG_SP(iregs), nullcode, verbose)) < 0) \
640 break; \
641 } while (0)
642
643 #define HP_SETEXECWAITGET(fn) \
644 do { \
645 if (verbose > 1) \
646 fprintf(stderr, "[%s:%d] Setting registers and invoking %s.\n", \
647 __func__, __LINE__, fn); \
648 if ((rc = hp_set_regs(hp->pid, &iregs)) < 0) \
649 break; \
650 if (verbose > 1) \
651 fprintf(stderr, "[%s:%d] Executing...\n", __func__, __LINE__); \
652 if ((rc = hp_exec(hp->pid)) < 0) \
653 break; \
654 if (verbose > 1) \
655 fprintf(stderr, "[%s:%d] Waiting...\n", __func__, __LINE__); \
656 if ((rc = hp_wait(hp->pid)) < 0) \
657 break; \
658 if (verbose > 1) \
659 fprintf(stderr, "[%s:%d] Getting registers.\n", __func__, __LINE__); \
660 if ((rc = hp_get_regs(hp->pid, &iregs)) < 0) \
661 break; \
662 } while (0)
663 #if __WORDSIZE == 64
664 #define HP_PASS_ARGS2FUNC(A,FN,ARG1,ARG2) \
665 do { \
666 A.regs.rsi = ARG2; \
667 A.regs.rdi = ARG1; \
668 A.regs.rip = FN; \
669 A.regs.rax = 0; \
670 } while (0)
671 #else /* __WORDSIZE == 64 */
672 #define HP_PASS_ARGS2FUNC(A,FN,ARG1,ARG2) \
673 do { \
674 if (verbose > 1) \
675 fprintf(stderr, "[%s:%d] Copying Arg 1 to stack.\n", \
676 __func__, __LINE__); \
677 if ((rc = hp_pokedata(hp->pid, HP_REG_SP(iregs) + sizeof(size_t), \
678 ARG1, verbose)) < 0) \
679 break; \
680 if (verbose > 1) \
681 fprintf(stderr, "[%s:%d] Copying Arg 2 to stack.\n", \
682 __func__, __LINE__); \
683 if ((rc = hp_pokedata(hp->pid, HP_REG_SP(iregs) + 2 * sizeof(size_t), \
684 ARG2, verbose)) < 0) \
685 break; \
686 A.regs.eip = FN; \
687 A.regs.eax = 0; \
688 } while (0)
689 #endif /* __WORDSIZE == 64 */
690 /* Prepare the child for injection */
691 if (verbose > 1)
692 fprintf(stderr, "[%s:%d] Attaching to PID %d\n", __func__,
693 __LINE__, hp->pid);
694 if ((rc = hp_attach(hp->pid)) < 0)
695 break;
696 if (verbose > 1)
697 fprintf(stderr, "[%s:%d] Waiting...\n", __func__, __LINE__);
698 if ((rc = hp_wait(hp->pid)) < 0)
699 break;
700 if (verbose > 1)
701 fprintf(stderr, "[%s:%d] Getting original registers.\n",
702 __func__, __LINE__);
703 if ((rc = hp_get_regs(hp->pid, &oregs)) < 0)
704 break;
705 memcpy(&iregs, &oregs, sizeof(oregs));
706 if (verbose > 1)
707 fprintf(stderr, "[%s:%d] Copying stack out.\n", __func__, __LINE__);
708 for (idx = 0; idx < sizeof(stack)/sizeof(uintptr_t); ++idx) {
709 if ((rc = hp_peekdata(hp->pid, HP_REG_SP(iregs) +
710 idx * sizeof(size_t), &stack[idx], verbose)) < 0)
711 break;
712 }
713 if (rc < 0)
714 break;
715 /* Call malloc */
716 HP_NULLIFYSTACK();
717 HP_PASS_ARGS2FUNC(iregs, hp->fn_malloc, tgtsz, 0);
718 HP_SETEXECWAITGET("malloc");
719 result = HP_REG_AX(iregs);
720 heapptr = HP_REG_AX(iregs); /* keep a copy of this pointer */
721 /* Copy data to the malloced area */
722 if (verbose > 1)
723 fprintf(stderr, "[%s:%d] Copying "LU" bytes to 0x"LX".\n", __func__,
724 __LINE__, tgtsz, result);
725 if (!result)
726 break;
727 if ((rc = hp_copydata(hp->pid, result, mdata, tgtsz, verbose)) < 0)
728 break;
729 /* Call dlopen */
730 HP_NULLIFYSTACK();
731 HP_PASS_ARGS2FUNC(iregs, hp->fn_dlopen, result /* value from malloc */,
732 (RTLD_LAZY | RTLD_GLOBAL));
733 HP_SETEXECWAITGET("dlopen");
734 result = HP_REG_AX(iregs);
735 if (verbose > 0)
736 fprintf(stderr, "[%s:%d] Dll opened at 0x"LX"\n", __func__, __LINE__,
737 result);
738 if (outaddr)
739 *outaddr = result;
740 /* Call dlsym */
741 if (symbol && hp->fn_dlsym && result != 0) {
742 HP_NULLIFYSTACK();
743 HP_PASS_ARGS2FUNC(iregs, hp->fn_dlsym,
744 result /* value from dlopen */,
745 (heapptr + dllsz));
746 HP_SETEXECWAITGET("dlsym");
747 result = HP_REG_AX(iregs);
748 if (verbose > 0)
749 fprintf(stderr, "[%s:%d] Symbol %s found at 0x"LX"\n",
750 __func__, __LINE__, symbol, result);
751 if (result != 0) {
752 HP_NULLIFYSTACK();
753 if (datasz > 0) {
754 HP_PASS_ARGS2FUNC(iregs, result /* value from dlsym */,
755 (heapptr + dllsz + symsz), datasz);
756 } else {
757 HP_PASS_ARGS2FUNC(iregs, result /* value from dlsym */,
758 0, 0);
759 }
760 HP_SETEXECWAITGET(symbol);
761 result = HP_REG_AX(iregs);
762 if (verbose > 0)
763 fprintf(stderr, "[%s:%d] Return value from invoking %s(): %p\n",
764 __func__, __LINE__, symbol, (void *)result);
765 if (outres)
766 *outres = result;
767 } else {
768 if (verbose > 0)
769 fprintf(stderr, "[%s:%d] Unable to find %s(). Dll might "
770 "already have been injected earlier.\n",
771 __func__, __LINE__, symbol);
772 if (outres)
773 *outres = 0;
774 }
775 } else {
776 if (verbose > 1 && symbol)
777 fprintf(stderr, "[%s:%d] %s not invoked as dlsym() wasn't "
778 "found.\n", __func__, __LINE__, symbol);
779 else if (verbose > 1)
780 fprintf(stderr, "[%s:%d] No symbol was specified. _init() might"
781 " have been invoked.\n", __func__, __LINE__);
782 if (outres)
783 *outres = 0;
784 }
785 /* Original reset */
786 if (verbose > 1)
787 fprintf(stderr, "[%s:%d] Setting original registers.\n",
788 __func__, __LINE__);
789 if ((rc = hp_set_regs(hp->pid, &oregs)) < 0) {
790 fprintf(stderr, "[%s:%d] PID %d will be unstable.\n", __func__,
791 __LINE__, hp->pid);
792 break;
793 }
794 if (verbose > 1)
795 fprintf(stderr, "[%s:%d] Copying stack back.\n",
796 __func__, __LINE__);
797 for (idx = 0; idx < sizeof(stack)/sizeof(uintptr_t); ++idx) {
798 if ((rc = hp_pokedata(hp->pid, HP_REG_SP(oregs) +
799 idx * sizeof(size_t), stack[idx], verbose)) < 0)
800 break;
801 }
802 if (rc < 0)
803 break;
804 if (verbose > 1)
805 fprintf(stderr, "[%s:%d] Executing...\n", __func__, __LINE__);
806 if ((rc = hp_exec(hp->pid)) < 0)
807 break;
808 } while (0);
809 if (rc < 0) {
810 if (hp->verbose > 1)
811 fprintf(stderr, "[%s:%d] Detaching from PID %d\n", __func__,
812 __LINE__, hp->pid);
813 if (hp_detach(hp->pid) < 0) {
814 if (hp->verbose > 0)
815 fprintf(stderr, "[%s:%d] Error detaching from PID %d\n", __func__,
816 __LINE__, hp->pid);
817 rc = -1;
818 }
819 }
820 if (mdata)
821 free(mdata);
822 mdata = NULL;
823 #undef HP_PASS_ARGS2FUNC
824 #undef HP_SETEXECWAITGET
825 #undef HP_NULLIFYSTACK
826 #undef HP_REG_IP_STR
827 #undef HP_REG_IP
828 #undef HP_REG_SP
829 #undef HP_REG_AX
830 return rc;
831 }
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <hotpatch_config.h>
31 #include <hotpatch_internal.h>
32
33 enum {
34 PROCMAPS_PERMS_NONE = 0x0,
35 PROCMAPS_PERMS_READ = 0x1,
36 PROCMAPS_PERMS_EXEC = 0x2,
37 PROCMAPS_PERMS_WRITE = 0x4,
38 PROCMAPS_PERMS_PRIVATE = 0x8,
39 PROCMAPS_PERMS_SHARED = 0x10
40 };
41
42 enum {
43 PROCMAPS_FILETYPE_UNKNOWN,
44 PROCMAPS_FILETYPE_EXE,
45 PROCMAPS_FILETYPE_LIB,
46 PROCMAPS_FILETYPE_DATA,
47 PROCMAPS_FILETYPE_VDSO,
48 PROCMAPS_FILETYPE_HEAP,
49 PROCMAPS_FILETYPE_STACK,
50 PROCMAPS_FILETYPE_SYSCALL
51 };
52
53 struct ld_procmaps {
54 uintptr_t addr_begin;
55 uintptr_t addr_end;
56 bool addr_valid;
57 int permissions;
58 off_t offset;
59 int device_major;
60 int device_minor;
61 ino_t inode;
62 char *pathname;
63 size_t pathname_sz;
64 int filetype;
65 };
66
67 void ld_procmaps_dump(struct ld_procmaps *pm)
68 {
69 if (!pm)
70 return;
71 fprintf(stderr, "[%s:%d] Pathname: %s\n", __func__, __LINE__,
72 pm->pathname ? pm->pathname : "Unknown");
73 fprintf(stderr, "[%s:%d] Address Start: "LX" End: "LX" Valid:"
74 " %d Offset: "LU"\n", __func__, __LINE__,
75 pm->addr_begin, pm->addr_end, pm->addr_valid,
76 (size_t)pm->offset);
77 fprintf(stderr, "[%s:%d] Device Major: %d Minor: %d\n",
78 __func__, __LINE__, pm->device_major, pm->device_minor);
79 fprintf(stderr, "[%s:%d] Inode: "LU"\n", __func__, __LINE__,
80 (size_t)pm->inode);
81 fprintf(stderr, "[%s:%d] Permissions: Read(%d) Write(%d) "
82 "Execute(%d) Private(%d) Shared(%d)\n",
83 __func__, __LINE__,
84 (pm->permissions & PROCMAPS_PERMS_READ) ? 1 : 0,
85 (pm->permissions & PROCMAPS_PERMS_WRITE) ? 1 : 0,
86 (pm->permissions & PROCMAPS_PERMS_EXEC) ? 1 : 0,
87 (pm->permissions & PROCMAPS_PERMS_PRIVATE) ? 1 : 0,
88 (pm->permissions & PROCMAPS_PERMS_SHARED) ? 1 : 0
89 );
90 fprintf(stderr, "[%s:%d] Pathname length: "LU"\n", __func__, __LINE__,
91 pm->pathname_sz);
92 fprintf(stderr, "[%s:%d] Filetype: %d\n", __func__, __LINE__,
93 pm->filetype);
94 }
95
96 int ld_procmaps_parse(char *buf, size_t bufsz, struct ld_procmaps *pm,
97 const char *appname, int verbose)
98 {
99 if (!buf || !pm) {
100 if (verbose > 2)
101 fprintf(stderr, "[%s:%d] Invalid arguments.\n", __func__, __LINE__);
102 return -1;
103 }
104 /* this is hardcoded parsing of the maps file */
105 do {
106 char *token = NULL;
107 char *save = NULL;
108 int idx, err;
109 memset(pm, 0, sizeof(*pm));
110 token = strtok_r(buf, "-", &save);
111 if (!token) break;
112 errno = 0;
113 pm->addr_begin = (uintptr_t)strtoul(token, NULL, 16);
114 err = errno;
115 pm->addr_valid = (err == ERANGE || err == EINVAL) ? false : true;
116 if (!pm->addr_valid) {
117 if (verbose > 2)
118 fprintf(stderr, "[%s:%d] Strtoul error(%s) in parsing %s\n",
119 __func__, __LINE__, strerror(err), token);
120 }
121 token = strtok_r(NULL, " ", &save);
122 if (!token) break;
123 errno = 0;
124 pm->addr_end = (intptr_t)strtoul(token, NULL, 16);
125 err = errno;
126 pm->addr_valid = (err == ERANGE || err == EINVAL) ? false : true;
127 if (!pm->addr_valid) {
128 if (verbose > 2)
129 fprintf(stderr, "[%s:%d] Strtoul error(%s) in parsing %s\n",
130 __func__, __LINE__, strerror(err), token);
131 }
132 token = strtok_r(NULL, " ", &save);
133 if (!token) break;
134 pm->permissions = PROCMAPS_PERMS_NONE;
135 for (idx = strlen(token) - 1; idx >= 0; --idx) {
136 switch (token[idx]) {
137 case 'r':
138 pm->permissions |= PROCMAPS_PERMS_READ;
139 break;
140 case 'w':
141 pm->permissions |= PROCMAPS_PERMS_WRITE;
142 break;
143 case 'x':
144 pm->permissions |= PROCMAPS_PERMS_EXEC;
145 break;
146 case 'p':
147 pm->permissions |= PROCMAPS_PERMS_PRIVATE;
148 break;
149 case 's':
150 pm->permissions |= PROCMAPS_PERMS_SHARED;
151 break;
152 case '-':
153 break;
154 default:
155 if (verbose > 2)
156 fprintf(stderr, "[%s:%d] Unknown flag: %c\n", __func__,
157 __LINE__, token[idx]);
158 break;
159 }
160 }
161 token = strtok_r(NULL, " ", &save);
162 if (!token) break;
163 errno = 0;
164 pm->offset = (off_t)strtoul(token, NULL, 16);
165 err = errno;
166 if (err == ERANGE || err == EINVAL) {
167 if (verbose > 2)
168 fprintf(stderr, "[%s:%d] Strtoul error(%s) in parsing %s\n",
169 __func__, __LINE__, strerror(err), token);
170 }
171 token = strtok_r(NULL, ":", &save);
172 if (!token) break;
173 pm->device_major = (int)strtol(token, NULL, 10);
174 token = strtok_r(NULL, " ", &save);
175 if (!token) break;
176 pm->device_minor = (int)strtol(token, NULL, 10);
177 token = strtok_r(NULL, " ", &save);
178 if (!token) break;
179 pm->inode = (ino_t)strtoul(token, NULL, 10);
180 token = strtok_r(NULL, "\n", &save);
181 if (!token) break;
182 pm->pathname_sz = strlen(token);
183 pm->pathname = calloc(sizeof(char), pm->pathname_sz + 1);
184 if (!pm->pathname) {
185 LOG_ERROR_OUT_OF_MEMORY;
186 pm->pathname = NULL;
187 pm->pathname_sz = 0;
188 break;
189 }
190 /* trim the extra spaces out */
191 save = token;
192 /* find the real path names */
193 if ((token = strchr(save, '/'))) {
194 memcpy(pm->pathname, token, strlen(token));
195 if (strstr(pm->pathname, ".so") || strstr(pm->pathname, ".so.")) {
196 pm->filetype = PROCMAPS_FILETYPE_LIB;
197 } else {
198 struct stat statbuf;
199 pm->filetype = PROCMAPS_FILETYPE_DATA;
200 memset(&statbuf, 0, sizeof(statbuf));
201 if (stat(pm->pathname, &statbuf) >= 0) {
202 ino_t inode1 = statbuf.st_ino;
203 memset(&statbuf, 0, sizeof(statbuf));
204 if (stat(appname, &statbuf) >= 0) {
205 if (statbuf.st_ino == inode1)
206 pm->filetype = PROCMAPS_FILETYPE_EXE;
207 }
208 } else {
209 int err = errno;
210 if (verbose > 2)
211 fprintf(stderr, "[%s:%d] Unable to stat file %s. Error:"
212 " %s\n", __func__, __LINE__, pm->pathname,
213 strerror(err));
214 }
215 }
216 } else if ((token = strchr(save, '['))) {
217 memcpy(pm->pathname, token, strlen(token));
218 if (strstr(pm->pathname, "[heap]")) {
219 pm->filetype = PROCMAPS_FILETYPE_HEAP;
220 } else if (strstr(pm->pathname, "[stack]")) {
221 pm->filetype = PROCMAPS_FILETYPE_STACK;
222 } else if (strstr(pm->pathname, "[vdso]")) {
223 pm->filetype = PROCMAPS_FILETYPE_VDSO;
224 } else if (strstr(pm->pathname, "[vsyscall")) {
225 pm->filetype = PROCMAPS_FILETYPE_SYSCALL;
226 } else {
227 if (verbose > 2)
228 fprintf(stderr, "[%s:%d] Unknown memory map: %s\n",
229 __func__, __LINE__, pm->pathname);
230 pm->filetype = PROCMAPS_FILETYPE_UNKNOWN;
231 }
232 } else {
233 memcpy(pm->pathname, token, strlen(token));
234 pm->filetype = PROCMAPS_FILETYPE_UNKNOWN;
235 }
236 } while (0);
237 return 0;
238 }
239
240 struct ld_procmaps *ld_load_maps(pid_t pid, int verbose, size_t *num)
241 {
242 char filename[OS_MAX_BUFFER];
243 char appname[OS_MAX_BUFFER];
244 FILE *ff = NULL;
245 const size_t bufsz = 4096;
246 char *buf = NULL;
247 size_t mapmax = 0;
248 size_t mapnum = 0;
249 struct ld_procmaps *maps = NULL;
250 if (pid == 0) {
251 LOG_ERROR_INVALID_PID(pid);
252 return NULL;
253 }
254 snprintf(filename, OS_MAX_BUFFER, "/proc/%d/maps", pid);
255 snprintf(appname, OS_MAX_BUFFER, "/proc/%d/exe", pid);
256 if (verbose > 2) {
257 fprintf(stderr, "[%s:%d] Using Proc Maps from %s\n", __func__,
258 __LINE__, filename);
259 fprintf(stderr, "[%s:%d] Using Proc Exe from %s\n", __func__,
260 __LINE__, appname);
261 }
262 do {
263 buf = calloc(sizeof(char), bufsz);
264 if (!buf) {
265 LOG_ERROR_OUT_OF_MEMORY;
266 break;
267 }
268 ff = fopen(filename, "r");
269 if (!ff) {
270 LOG_ERROR_FILE_OPEN(filename);
271 break;
272 }
273 while (fgets(buf, bufsz, ff))
274 mapmax++;
275 if (verbose > 0)
276 fprintf(stderr, "[%s:%d] Max number of mappings present: "LU"\n",
277 __func__, __LINE__, mapmax);
278 fseek(ff, 0L, SEEK_SET);
279 maps = calloc(sizeof(*maps), mapmax);
280 if (!maps) {
281 LOG_ERROR_OUT_OF_MEMORY;
282 break;
283 }
284 if (verbose > 1)
285 fprintf(stderr,
286 "[%s:%d] Allocated memory to load proc maps.\n",
287 __func__, __LINE__);
288 memset(buf, 0, bufsz);
289 mapnum = 0;
290 while (fgets(buf, bufsz, ff)) {
291 struct ld_procmaps *pm = &maps[mapnum];
292 if (verbose > 3)
293 fprintf(stderr, "[%s:%d] Parsing %s\n", __func__, __LINE__,
294 buf);
295 if (ld_procmaps_parse(buf, bufsz, pm, appname, verbose) < 0) {
296 if (verbose > 1) {
297 fprintf(stderr, "[%s:%d] Parsing failure. Ignoring.\n",
298 __func__, __LINE__);
299 }
300 continue;
301 }
302 if (verbose > 4)
303 ld_procmaps_dump(pm);
304 mapnum++;
305 }
306 if (num)
307 *num = mapnum;
308 else
309 if (verbose > 3)
310 fprintf(stderr, "[%s:%d] Cannot return size of maps object.\n",
311 __func__, __LINE__);
312 } while (0);
313 if (buf)
314 free(buf);
315 if (ff)
316 fclose(ff);
317 return maps;
318 }
319
320 void ld_free_maps(struct ld_procmaps *maps, size_t num)
321 {
322 if (maps && num > 0) {
323 size_t idx;
324 for (idx = 0; idx < num; ++idx) {
325 if (maps[idx].pathname)
326 free(maps[idx].pathname);
327 maps[idx].pathname = NULL;
328 }
329 free(maps);
330 maps = NULL;
331 }
332 }
333
334 int ld_find_library(const struct ld_procmaps *maps, const size_t mapnum,
335 const char *libpath, bool inode_match,
336 struct ld_library *lib, int verbose)
337 {
338 if (!maps && !libpath) {
339 if (verbose > 3)
340 fprintf(stderr, "[%s:%d] Invalid arguments.\n", __func__,
341 __LINE__);
342 return -1;
343 } else {
344 size_t idx;
345 bool found = false;
346 ino_t inode = 0;
347 bool nonlib_match = false;
348 bool exact_match = false;
349 if (inode_match) {
350 struct stat statbuf = { 0 };
351 if (stat(libpath, &statbuf) < 0) {
352 int err = errno;
353 if (verbose > 1)
354 fprintf(stderr,
355 "[%s:%d] Unable to get inode for %s. Error: %s\n",
356 __func__, __LINE__, libpath, strerror(err));
357 return -1;
358 }
359 inode = statbuf.st_ino;
360 } else {
361 if (verbose > 2)
362 fprintf(stderr, "[%s:%d] Not doing an inode match.\n",
363 __func__, __LINE__);
364 nonlib_match = (strchr(libpath, '[') || strchr(libpath, ']')) ?
365 true : false;
366 if (verbose > 2 && nonlib_match)
367 fprintf(stderr, "[%s:%d] Found '[' or ']' in %s\n",
368 __func__, __LINE__, libpath);
369 exact_match = (strchr(libpath, '/')) ? true : false;
370 if (verbose > 2 && exact_match)
371 fprintf(stderr, "[%s:%d] Found '/' in %s. Doing an exact "
372 "match search\n", __func__, __LINE__, libpath);
373 if (!nonlib_match && !exact_match && verbose > 0)
374 fprintf(stderr, "[%s:%d] Doing best substring search for %s.\n",
375 __func__, __LINE__, libpath);
376 }
377 for (idx = 0; idx < mapnum; ++idx) {
378 const struct ld_procmaps *pm = &maps[idx];
379 if (!pm->pathname)
380 continue;
381 /* first try inode match. the libraries can be symlinks and
382 * all that
383 */
384 if (inode_match) {
385 /* if it has no inode, we do not support it */
386 if (pm->inode == 0)
387 continue;
388 found = (pm->inode == inode) ? true : false;
389 } else {
390 /* Now try string match.
391 * 1. if the string contains a '[' or ']' then do a substring
392 * match
393 * 2. if the string contains a '/' then do an exact match
394 * 3. else substring search all libs and return the first one
395 * with a valid inode
396 */
397 if (nonlib_match) {
398 /* we're looking for a non-library or a non-exe file or a
399 * non-data file
400 */
401 if (pm->filetype == PROCMAPS_FILETYPE_VDSO ||
402 pm->filetype == PROCMAPS_FILETYPE_HEAP ||
403 pm->filetype == PROCMAPS_FILETYPE_STACK ||
404 pm->filetype == PROCMAPS_FILETYPE_SYSCALL) {
405 /* doing a substring match to be safe */
406 found = strstr(pm->pathname, libpath) != NULL ?
407 true :false;
408 }
409 } else {
410 if (pm->filetype != PROCMAPS_FILETYPE_LIB)
411 continue;
412 if (pm->inode == 0)
413 continue;
414 /* we're doing an exact match */
415 if (exact_match) {
416 found = strcmp(libpath, pm->pathname) == 0 ?
417 true : false;
418 } else {
419 /* do a substring match for best fit. If the string
420 * matches then check if the next character is not an
421 * alphabet and is a . or a -
422 */
423 char *sub = strstr(pm->pathname, libpath);
424 found = false;
425 if (sub) {
426 size_t alen = strlen(libpath);
427 if (sub[alen] == '.' || sub[alen] == '-')
428 found = true;
429 }
430 }
431 }
432 }
433 if (found) {
434 if (verbose > 2)
435 fprintf(stderr, "[%s:%d] Found index ("LU") matching.\n",
436 __func__, __LINE__, idx);
437 if (verbose > 0)
438 fprintf(stderr, "[%s:%d] Found entry %s matching %s\n",
439 __func__, __LINE__, pm->pathname, libpath);
440 break;
441 }
442 }
443 if (!found) {
444 if (verbose > 0) {
445 fprintf(stderr, "[%s:%d] Library %s not found in procmaps\n",
446 __func__, __LINE__, libpath);
447 }
448 return -1;
449 }
450 if (found && lib) {
451 const struct ld_procmaps *pm = &maps[idx];
452 if (pm->addr_valid) {
453 lib->addr_begin = pm->addr_begin;
454 lib->addr_end = pm->addr_end;
455 } else {
456 if (verbose > 1)
457 fprintf(stderr, "[%s:%d] Addresses are invalid for %s\n",
458 __func__, __LINE__, lib->pathname);
459 return -1;
460 }
461 lib->inode = pm->inode;
462 lib->pathname = strdup(pm->pathname);
463 if (!lib->pathname) {
464 LOG_ERROR_OUT_OF_MEMORY;
465 lib->pathname = NULL;
466 lib->length = 0;
467 return -1;
468 } else {
469 lib->length = pm->pathname_sz;
470 }
471 }
472 }
473 return 0;
474 }
475
476 uintptr_t ld_find_address(const struct ld_library *lib, const char *symbol,
477 int verbose)
478 {
479 uintptr_t ptr = 0;
480 if (lib && symbol && lib->pathname) {
481 size_t syms_num = 0;
482 struct elf_symbol *syms = exe_load_symbols(lib->pathname, verbose,
483 &syms_num, NULL, NULL, NULL);
484 if (syms && syms_num > 0) {
485 size_t idx = 0;
486 if (verbose > 1)
487 fprintf(stderr, "[%s:%d] "LU" symbols found in %s\n",
488 __func__, __LINE__, syms_num, lib->pathname);
489 qsort(syms, syms_num, sizeof(*syms), elf_symbol_cmpqsort);
490 for (idx = 0; idx < syms_num; ++idx) {
491 if (strcmp(symbol, syms[idx].name) == 0) {
492 if (verbose > 2)
493 fprintf(stderr, "[%s:%d] Found %s in symbol list at "
494 ""LU" with address offset "LX"\n", __func__,
495 __LINE__, symbol, idx, syms[idx].address);
496 if (syms[idx].address > lib->addr_begin)
497 ptr = syms[idx].address;
498 else
499 ptr = syms[idx].address + lib->addr_begin;
500 break;
501 }
502 }
503 /* free memory for all to avoid mem-leaks */
504 for (idx = 0; idx < syms_num; ++idx) {
505 if (syms[idx].name)
506 free(syms[idx].name);
507 syms[idx].name = NULL;
508 }
509 free(syms);
510 syms_num = 0;
511 } else {
512 if (verbose > 0)
513 fprintf(stderr, "[%s:%d] No symbols found in %s\n",
514 __func__, __LINE__, lib->pathname);
515 }
516 } else {
517 if (verbose > 3)
518 fprintf(stderr, "[%s:%d] Invalid arguments.\n", __func__,
519 __LINE__);
520 }
521 return ptr;
522 }
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <hotpatch_config.h>
31 #include <hotpatch.h>
32
33 struct hp_options {
34 pid_t pid;
35 int verbose;
36 bool is__start;
37 char *symbol;
38 bool dryrun;
39 char *dll;
40 };
41
42 void print_usage(const char *app)
43 {
44 printf("\nUsage: %s [options] <PID of process to patch>\n", app);
45 printf("\nOptions:\n");
46 printf("-h This help message\n");
47 printf("-V Version number.\n");
48 printf("-v[vvvv] Enable verbose logging. Add more 'v's for more\n");
49 printf("-N Dry run. Do not modify anything in process\n");
50 printf("-l <.so> Path or name of the .so file to load. Switches off "
51 "execution pointer reset\n");
52 printf("-s <name> Symbol to invoke during the dll inject. Optional.\n");
53 printf("-x <name> Set execution pointer to symbol. Cannot be set with "
54 "-s option\n");
55 }
56
57 void print_options(const struct hp_options *opts)
58 {
59 if (opts && opts->verbose > 0) {
60 printf(
61 "Options Given:\n"
62 "Verbose Level: %d\n"
63 "Process PID: %d\n"
64 "Symbol name: %s\n"
65 "Library name: %s\n"
66 "Dry run: %s\n",
67 opts->verbose,
68 opts->pid,
69 (opts->symbol ? opts->symbol :
70 (opts->dll ? "_init" : "_start")),
71 (opts->dll ? opts->dll : "N/A"),
72 (opts->dryrun ? "true" : "false")
73 );
74 }
75 }
76
77 int parse_arguments(int argc, char **argv, struct hp_options *opts)
78 {
79 if (argc > 0 && argv && opts) {
80 int opt = 0;
81 extern int optind;
82 extern char *optarg;
83 optind = 1;
84 opts->is__start = false;
85 opts->dryrun = false;
86 while ((opt = getopt(argc, argv, "hNVs:x::l:v::")) != -1) {
87 switch (opt) {
88 case 'v':
89 opts->verbose += optarg ? (int)strnlen(optarg, 5) : 1;
90 break;
91 case 's':
92 if (opts->symbol) {
93 free(opts->symbol);
94 opts->symbol = NULL;
95 }
96 opts->symbol = strdup(optarg);
97 if (!opts->symbol) {
98 printf("[%s:%d] Out of memory\n", __func__, __LINE__);
99 return -1;
100 }
101 break;
102 case 'x':
103 if (optarg) {
104 opts->symbol = strdup(optarg);
105 if (strcmp(optarg, HOTPATCH_LINUX_START) == 0)
106 opts->is__start = true;
107 else
108 opts->is__start = false;
109 } else {
110 opts->symbol = strdup(HOTPATCH_LINUX_START);
111 opts->is__start = true;
112 }
113 if (!opts->symbol) {
114 printf("[%s:%d] Out of memory\n", __func__, __LINE__);
115 return -1;
116 }
117 break;
118 case 'N':
119 opts->dryrun = true;
120 break;
121 case 'l':
122 opts->dll = strdup(optarg);
123 if (!opts->dll) {
124 printf("[%s:%d] Out of memory\n", __func__, __LINE__);
125 return -1;
126 }
127 break;
128 case 'V':
129 {
130 int major = 0, minor = 0;
131 hotpatch_version(&major, &minor);
132 printf("Hotpatch version: %d.%d\n", major, minor);
133 return 1;
134 }
135 break;
136 case 'h':
137 default:
138 print_usage(argv[0]);
139 return -1;
140 }
141 }
142 if (optind >= argc) {
143 printf("Expected more arguments.\n");
144 print_usage(argv[0]);
145 return -1;
146 }
147 opts->pid = (pid_t)strtol(argv[optind], NULL, 10);
148 if (opts->pid == 0) {
149 printf("Process PID can't be 0. Tried parsing: %s\n", argv[optind]);
150 return -1;
151 }
152 return 0;
153 }
154 return -1;
155 }
156
157 int main(int argc, char **argv)
158 {
159 struct hp_options opts = { 0 };
160 hotpatch_t *hp = NULL;
161 int rc = 0;
162 /* parse all arguments first */
163 if ((rc = parse_arguments(argc, argv, &opts)) != 0) {
164 return rc;
165 }
166 print_options(&opts);
167 /* break from execution whenever a step fails */
168 do {
169 uintptr_t ptr = 0;
170 hp = hotpatch_create(opts.pid, opts.verbose);
171 if (!hp) {
172 fprintf(stderr, "[%s:%d] Unable to create hotpatch for PID %d\n",
173 __func__, __LINE__, opts.pid);
174 rc = -1;
175 break;
176 }
177 if (opts.dryrun)
178 break;
179 if (opts.dll) {
180 uintptr_t dlres = 0;
181 uintptr_t symres = 0;
182 rc = hotpatch_inject_library(hp, opts.dll, opts.symbol, NULL, 0,
183 &dlres, &symres);
184 if (rc >=0) {
185 printf("Dll was injected at %p\n", (void *)dlres);
186 printf("Invocation of %s() returned %p\n",
187 (opts.symbol ? opts.symbol : "_init"),
188 (void *)symres);
189 }
190 } else {
191 /* handles the stripped apps as well */
192 if (opts.is__start) {
193 ptr = hotpatch_get_entry_point(hp);
194 } else {
195 ptr = hotpatch_read_symbol(hp, opts.symbol, NULL, NULL);
196 }
197 if (!ptr) {
198 printf("Symbol %s not found. Cannot proceed\n", opts.symbol);
199 break;
200 }
201 printf("Setting execution pointer to %s at 0x"LX"\n", opts.symbol, ptr);
202 rc = hotpatch_attach(hp);
203 if (rc < 0) {
204 printf("Failed to attach to process. Cannot proceed\n");
205 break;
206 }
207 rc = hotpatch_set_execution_pointer(hp, ptr);
208 if (rc < 0) {
209 printf("Failed to set execution pointer to 0x"LX"\n", ptr);
210 rc = hotpatch_detach(hp);
211 break;
212 }
213 rc = hotpatch_detach(hp);
214 }
215 } while (0);
216 hotpatch_destroy(hp);
217 hp = NULL;
218 if (opts.symbol)
219 free(opts.symbol);
220 opts.symbol = NULL;
221 if (opts.dll)
222 free(opts.dll);
223 opts.dll = NULL;
224 return rc;
225 }
0 ### hotpatch is a dll injection strategy
1 ### Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
2 ### All rights reserved.
3 ###
4 ### Redistribution and use in source and binary forms, with or without
5 ### modification, are permitted provided that the following conditions are met:
6 ###
7 ### * Redistributions of source code must retain the above copyright
8 ### notice, this list of conditions and the following disclaimer.
9 ###
10 ### * Redistributions in binary form must reproduce the above copyright
11 ### notice, this list of conditions and the following disclaimer in the
12 ### documentation and/or other materials provided with the distribution.
13 ###
14 ### * Neither the name of Selective Intellect LLC nor the
15 ### names of its contributors may be used to endorse or promote products
16 ### derived from this software without specific prior written permission.
17 ###
18 ### THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ### WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 ### DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22 ### DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 ### (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 ### LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ### ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 ### (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 ### SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 ###
29 project(unit_tests)
30
31 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
32 include_directories(${CMAKE_CURRENT_BINARY_DIR})
33
34 if (ARCH STREQUAL "x86_64")
35 add_executable(ptracetest ptrace.c)
36 endif (ARCH STREQUAL "x86_64")
37
38 add_executable(dummy dummy.c)
39 add_executable(loadertest loader.c)
40 target_link_libraries(loadertest hotpatch)
41 add_test(loadertest ${CMAKE_CURRENT_BINARY_DIR}/loadertest)
42
43 add_executable(compiletestcpp cpptest.cpp)
44 target_link_libraries(compiletestcpp hotpatch)
45 add_test(compiletestcpp ${CMAKE_CURRENT_BINARY_DIR}/compiletestcpp)
46
47 add_executable(compiletestc ctest.c)
48 target_link_libraries(compiletestc hotpatch)
49 add_test(compiletestc ${CMAKE_CURRENT_BINARY_DIR}/compiletestc)
50
51 add_library(hotpatchtest SHARED dlltest.c)
52 set_target_properties(hotpatchtest PROPERTIES LINK_FLAGS "-fPIC -nostartfiles")
53 install(TARGETS hotpatchtest LIBRARY DESTINATION lib)
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <hotpatch.h>
31
32 int main(int argc, char **argv)
33 {
34 hotpatch_t *hp = 0;
35 if (hp) {}
36 return 0;
37 }
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <hotpatch.h>
31
32 int main(int argc, char **argv)
33 {
34 hotpatch_t *hp = 0;
35 if (hp) {}
36 return 0;
37 }
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <hotpatch_config.h>
31 #ifdef HOTPATCH_HAS_ASSERT_H
32 #undef NDEBUG
33 #include <assert.h>
34 #endif
35
36 #define HP_DLLTEST(D,L) \
37 do { \
38 time_t tt = time(NULL); \
39 FILE *ff = fopen("/tmp/hotpatchtest.log", "a"); \
40 if (ff) { \
41 fprintf(ff, "Dll opened. %s\n", ctime(&tt)); \
42 if (L > 0) \
43 fprintf(ff, "Data: %s Len: "LU"\n", (char *)D, (size_t)L); \
44 fclose(ff); \
45 } \
46 } while (0)
47
48 void _init()
49 {
50 HP_DLLTEST(__func__, 0);
51 }
52
53 int mysym(char *data, size_t len)
54 {
55 HP_DLLTEST(data, len);
56 return 0xDEADBEEF;
57 }
0 #ifndef _GNU_SOURCE
1 #define _GNU_SOURCE
2 #endif
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdint.h>
6 #include <unistd.h>
7 #include <time.h>
8 #include <sys/time.h>
9 #include <sys/syscall.h>
10 #if __WORDSIZE == 64
11 #define LX "%lx"
12 #define LU "%lu"
13 #else
14 #define LX "%x"
15 #define LU "%u"
16 #endif
17
18 static int counter = 0;
19 void myfun()
20 {
21 printf("%d: I am here in %s on %d\n", counter++,
22 __func__, __LINE__);
23 if (counter >= INT32_MAX)
24 counter = 0;
25 }
26
27 int main()
28 {
29 intptr_t here0 = 0;
30 intptr_t here1 = 0;
31 const char *str = "Hello World!";
32 size_t len = strlen(str);
33 here0 = (intptr_t)syscall(SYS_brk, 0);
34 here1 = (intptr_t)syscall(SYS_brk, here0 + len + 1);
35 printf("Starting dummy 0x"LX" 0x"LX"\n", here0, here1);
36 memcpy((void *)here0, str, len + 1);
37 printf("String: %s\n", (const char *)here0);
38 syscall(SYS_brk, here0);
39 while (1) {
40 struct timeval tv = { 0 };
41 sleep(2);
42 gettimeofday(&tv, NULL);
43 printf("Working "LU"."LU"\n", (size_t)tv.tv_sec, (size_t)tv.tv_usec);
44 myfun();
45 }
46 printf("Stopping dummy\n");
47 return 0;
48 }
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <hotpatch_config.h>
31 #include <hotpatch_internal.h>
32 #ifdef HOTPATCH_HAS_ASSERT_H
33 #undef NDEBUG
34 #include <assert.h>
35 #endif
36
37 int main(int argc, char **argv)
38 {
39 struct ld_procmaps *maps = NULL;
40 size_t mapnum = 0;
41 int ret;
42 pid_t pid = argc > 1 ? (pid_t)strtol(argv[1], NULL, 10) : getpid();
43 assert(pid != 0);
44 maps = ld_load_maps(pid, 6 /* largest verbose */, &mapnum);
45 assert(mapnum > 0);
46 assert(maps != NULL);
47 ret = 0;
48 ret = ld_find_library(maps, mapnum, "[heap]", false, NULL, 6);
49 assert(ret >= 0);
50 ret = ld_find_library(maps, mapnum, "[stack", false, NULL, 6);
51 assert(ret >= 0);
52 ret = ld_find_library(maps, mapnum, "vdso", false, NULL, 6);
53 assert(ret < 0);
54 ret = ld_find_library(maps, mapnum, "libc", false, NULL, 6);
55 assert(ret >= 0);
56 #if __WORDSIZE == 64
57 ret = ld_find_library(maps, mapnum, "/lib64/ld-linux-x86-64.so.2",
58 true, NULL, 6);
59 assert(ret >= 0);
60 ret = ld_find_library(maps, mapnum, "/lib/ld-linux-x86-64.so.2",
61 false, NULL, 6);
62 #else
63 ret = ld_find_library(maps, mapnum, "/lib/ld-linux.so.2",
64 true, NULL, 6);
65 assert(ret >= 0);
66 ret = ld_find_library(maps, mapnum, "/lib32/ld-linux.so.2",
67 false, NULL, 6);
68 #endif
69 assert(ret < 0);
70 ld_free_maps(maps, mapnum);
71 return 0;
72 }
73
0 /*
1 * hotpatch is a dll injection strategy.
2 * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Selective Intellect LLC nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <hotpatch_config.h>
31 #ifdef HOTPATCH_HAS_ASSERT_H
32 #undef NDEBUG
33 #include <assert.h>
34 #endif
35
36 int test_child(pid_t pid)
37 {
38 int st = 0;
39 int memfd = -1;
40 char procfile[4096];
41 memset(procfile, 0, sizeof(procfile));
42 sprintf(procfile, "/proc/%d/maps", pid);
43 printf("Trying to open %s\n", procfile);
44 memfd = open(procfile, O_RDONLY);
45 assert(memfd >= 0);
46 memset(procfile, 0, sizeof(procfile));
47 while ((st = read(memfd, procfile, sizeof(procfile))) >= 0) {
48 printf("st: %d\n", st);
49 printf("%s\n", procfile);
50 if (st == 0) break;
51 }
52 if (st < 0) {
53 st = errno;
54 printf("error: %s\n", strerror(st));
55 }
56 close(memfd);
57 return st;
58 }
59
60 int main(int argc, char **argv, char **envp)
61 {
62 pid_t pid = 0;
63 int status = 0;
64 assert(argc >= 2);
65 pid = (pid_t)strtol(argv[1], NULL, 10);
66 assert(pid > 0);
67
68 assert(ptrace(PTRACE_ATTACH, pid, NULL, NULL) == 0);
69
70 while (1) {
71 struct user *cldata = NULL;
72 long retval = 0;
73 waitpid(-1, &status, 0);
74 if (WIFEXITED(status) || WIFSIGNALED(status)) {
75 break;
76 }
77 cldata = malloc(sizeof(*cldata));
78 if (!cldata) {
79 fprintf(stderr, "Out of memory. Tried to allocate "LU"\n", sizeof(*cldata));
80 break;
81 }
82 memset(cldata, 0, sizeof(*cldata));
83 if (ptrace(PTRACE_GETREGS, pid, NULL, cldata) < 0) {
84 int err = errno;
85 printf("[%s:%d] Error: %s\n", __func__, __LINE__, strerror(err));
86 } else {
87 printf("R15: %p\n", (void *)cldata->regs.r15);
88 printf("R14: %p\n", (void *)cldata->regs.r14);
89 printf("R13: %p\n", (void *)cldata->regs.r13);
90 printf("R12: %p\n", (void *)cldata->regs.r12);
91 printf("RBP: %p\n", (void *)cldata->regs.rbp);
92 printf("RBX: %p\n", (void *)cldata->regs.rbx);
93 printf("R11: %p\n", (void *)cldata->regs.r11);
94 printf("R10: %p\n", (void *)cldata->regs.r10);
95 printf("R9: %p\n", (void *)cldata->regs.r9);
96 printf("R8: %p\n", (void *)cldata->regs.r8);
97 printf("RAX: %p\n", (void *)cldata->regs.rax);
98 printf("RCX: %p\n", (void *)cldata->regs.rcx);
99 printf("RDX: %p\n", (void *)cldata->regs.rdx);
100 printf("RSI: %p\n", (void *)cldata->regs.rsi);
101 printf("RDI: %p\n", (void *)cldata->regs.rdi);
102 printf("ORIG_RAX: %p\n", (void *)cldata->regs.orig_rax);
103 printf("RIP: %p\n", (void *)cldata->regs.rip);
104 printf("CS: %p\n", (void *)cldata->regs.cs);
105 printf("EFLAGS: %p\n", (void *)cldata->regs.eflags);
106 printf("RSP: %p\n", (void *)cldata->regs.rsp);
107 printf("SS: %p\n", (void *)cldata->regs.ss);
108 printf("FS_BASE: %p\n", (void *)cldata->regs.fs_base);
109 printf("GS_BASE: %p\n", (void *)cldata->regs.gs_base);
110 printf("DS: %p\n", (void *)cldata->regs.ds);
111 printf("ES: %p\n", (void *)cldata->regs.es);
112 printf("FS: %p\n", (void *)cldata->regs.fs);
113 printf("GS: %p\n", (void *)cldata->regs.gs);
114 printf("FPVALID: %d\n", cldata->u_fpvalid);
115 printf("TSize: "LU"\n", cldata->u_tsize);
116 printf("DSize: "LU"\n", cldata->u_dsize);
117 printf("SSize: "LU"\n", cldata->u_ssize);
118 printf("Start code: %p\n", (void *)cldata->start_code);
119 printf("Start stack: %p\n", (void *)cldata->start_stack);
120 printf("Signal: "LU"\n", cldata->signal);
121 printf("Reserved: %d\n", cldata->reserved);
122 printf("AR0: %p\n", (void *)cldata->u_ar0);
123 printf("FPSTATE: %p\n", (void *)cldata->u_fpstate);
124 printf("MAGIC: "LU"\n", cldata->magic);
125 printf("U_COMM: %s\n", cldata->u_comm);
126 }
127 cldata->regs.orig_rax++;
128 ptrace(PTRACE_SETREGS, pid, NULL, cldata);
129 if ((retval = ptrace(PTRACE_PEEKUSER, pid, offsetof(struct user, u_fpvalid), NULL)) < 0) {
130 int err = errno;
131 printf("[%s:%d] Return value: "LU" Error: %s\n", __func__, __LINE__, retval, strerror(err));
132 } else {
133 cldata->start_code = retval;
134 printf("Start code: %p\n", (void *)cldata->start_code);
135 }
136 retval = ptrace(PTRACE_PEEKTEXT, pid, cldata->regs.rip, NULL);
137 printf("[%s:%d] Return value: "LU". \n", __func__, __LINE__, retval);
138 if (argc > 2) {
139 ptrace(PTRACE_CONT, pid, 0, 0);
140 }
141 printf("[%s:%d] \n", __func__, __LINE__);
142 free(cldata);
143 if (test_child(pid) < 0) {
144 break;
145 }
146 }
147 assert(ptrace(PTRACE_DETACH, pid, NULL, NULL) == 0);
148 return 0;
149 }