├── .gitignore
├── LICENSE.md
├── LibraryInjector.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── LibraryInjector.xcscheme
├── LibraryInjector
├── LibraryInjector.entitlements
└── main.cpp
├── README.md
├── TestHost
└── main.cpp
└── TestLib
└── testlib.c
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | !.keep
3 |
4 | ## Build generated
5 | DerivedData/
6 |
7 | ## Various settings
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata/
17 |
18 | ## Other
19 | *.moved-aside
20 | *.xccheckout
21 | *.xcscmblueprint
22 |
23 | ## Obj-C/Swift specific
24 | *.hmap
25 | *.ipa
26 | *.dSYM.zip
27 | *.dSYM
28 |
29 | ## Playgrounds
30 | timeline.xctimeline
31 | playground.xcworkspace
32 |
33 | ## Swift Package Manager
34 | .build/
35 | */.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
36 |
37 | ## CocoaPods
38 | Pods/
39 |
40 | ## Xcode
41 | UserInterfaceState.xcuserstate
42 |
43 | ## Theos
44 | .theos
45 | /packages
46 | compile_commands.json
47 |
48 | ## VScode
49 | .vscode
50 |
51 | ## Misc
52 | /Private/
53 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | GNU Lesser General Public License
2 | =================================
3 |
4 | _Version 3, 29 June 2007_
5 | _Copyright © 2007 Free Software Foundation, Inc. <>_
6 |
7 | Everyone is permitted to copy and distribute verbatim copies
8 | of this license document, but changing it is not allowed.
9 |
10 |
11 | This version of the GNU Lesser General Public License incorporates
12 | the terms and conditions of version 3 of the GNU General Public
13 | License, supplemented by the additional permissions listed below.
14 |
15 | ### 0. Additional Definitions
16 |
17 | As used herein, “this License” refers to version 3 of the GNU Lesser
18 | General Public License, and the “GNU GPL” refers to version 3 of the GNU
19 | General Public License.
20 |
21 | “The Library” refers to a covered work governed by this License,
22 | other than an Application or a Combined Work as defined below.
23 |
24 | An “Application” is any work that makes use of an interface provided
25 | by the Library, but which is not otherwise based on the Library.
26 | Defining a subclass of a class defined by the Library is deemed a mode
27 | of using an interface provided by the Library.
28 |
29 | A “Combined Work” is a work produced by combining or linking an
30 | Application with the Library. The particular version of the Library
31 | with which the Combined Work was made is also called the “Linked
32 | Version”.
33 |
34 | The “Minimal Corresponding Source” for a Combined Work means the
35 | Corresponding Source for the Combined Work, excluding any source code
36 | for portions of the Combined Work that, considered in isolation, are
37 | based on the Application, and not on the Linked Version.
38 |
39 | The “Corresponding Application Code” for a Combined Work means the
40 | object code and/or source code for the Application, including any data
41 | and utility programs needed for reproducing the Combined Work from the
42 | Application, but excluding the System Libraries of the Combined Work.
43 |
44 | ### 1. Exception to Section 3 of the GNU GPL
45 |
46 | You may convey a covered work under sections 3 and 4 of this License
47 | without being bound by section 3 of the GNU GPL.
48 |
49 | ### 2. Conveying Modified Versions
50 |
51 | If you modify a copy of the Library, and, in your modifications, a
52 | facility refers to a function or data to be supplied by an Application
53 | that uses the facility (other than as an argument passed when the
54 | facility is invoked), then you may convey a copy of the modified
55 | version:
56 |
57 | * **a)** under this License, provided that you make a good faith effort to
58 | ensure that, in the event an Application does not supply the
59 | function or data, the facility still operates, and performs
60 | whatever part of its purpose remains meaningful, or
61 |
62 | * **b)** under the GNU GPL, with none of the additional permissions of
63 | this License applicable to that copy.
64 |
65 | ### 3. Object Code Incorporating Material from Library Header Files
66 |
67 | The object code form of an Application may incorporate material from
68 | a header file that is part of the Library. You may convey such object
69 | code under terms of your choice, provided that, if the incorporated
70 | material is not limited to numerical parameters, data structure
71 | layouts and accessors, or small macros, inline functions and templates
72 | (ten or fewer lines in length), you do both of the following:
73 |
74 | * **a)** Give prominent notice with each copy of the object code that the
75 | Library is used in it and that the Library and its use are
76 | covered by this License.
77 | * **b)** Accompany the object code with a copy of the GNU GPL and this license
78 | document.
79 |
80 | ### 4. Combined Works
81 |
82 | You may convey a Combined Work under terms of your choice that,
83 | taken together, effectively do not restrict modification of the
84 | portions of the Library contained in the Combined Work and reverse
85 | engineering for debugging such modifications, if you also do each of
86 | the following:
87 |
88 | * **a)** Give prominent notice with each copy of the Combined Work that
89 | the Library is used in it and that the Library and its use are
90 | covered by this License.
91 |
92 | * **b)** Accompany the Combined Work with a copy of the GNU GPL and this license
93 | document.
94 |
95 | * **c)** For a Combined Work that displays copyright notices during
96 | execution, include the copyright notice for the Library among
97 | these notices, as well as a reference directing the user to the
98 | copies of the GNU GPL and this license document.
99 |
100 | * **d)** Do one of the following:
101 | - **0)** Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 | - **1)** Use a suitable shared library mechanism for linking with the
109 | Library. A suitable mechanism is one that **(a)** uses at run time
110 | a copy of the Library already present on the user's computer
111 | system, and **(b)** will operate properly with a modified version
112 | of the Library that is interface-compatible with the Linked
113 | Version.
114 |
115 | * **e)** Provide Installation Information, but only if you would otherwise
116 | be required to provide such information under section 6 of the
117 | GNU GPL, and only to the extent that such information is
118 | necessary to install and execute a modified version of the
119 | Combined Work produced by recombining or relinking the
120 | Application with a modified version of the Linked Version. (If
121 | you use option **4d0**, the Installation Information must accompany
122 | the Minimal Corresponding Source and Corresponding Application
123 | Code. If you use option **4d1**, you must provide the Installation
124 | Information in the manner specified by section 6 of the GNU GPL
125 | for conveying Corresponding Source.)
126 |
127 | ### 5. Combined Libraries
128 |
129 | You may place library facilities that are a work based on the
130 | Library side by side in a single library together with other library
131 | facilities that are not Applications and are not covered by this
132 | License, and convey such a combined library under terms of your
133 | choice, if you do both of the following:
134 |
135 | * **a)** Accompany the combined library with a copy of the same work based
136 | on the Library, uncombined with any other library facilities,
137 | conveyed under the terms of this License.
138 | * **b)** Give prominent notice with the combined library that part of it
139 | is a work based on the Library, and explaining where to find the
140 | accompanying uncombined form of the same work.
141 |
142 | ### 6. Revised Versions of the GNU Lesser General Public License
143 |
144 | The Free Software Foundation may publish revised and/or new versions
145 | of the GNU Lesser General Public License from time to time. Such new
146 | versions will be similar in spirit to the present version, but may
147 | differ in detail to address new problems or concerns.
148 |
149 | Each version is given a distinguishing version number. If the
150 | Library as you received it specifies that a certain numbered version
151 | of the GNU Lesser General Public License “or any later version”
152 | applies to it, you have the option of following the terms and
153 | conditions either of that published version or of any later version
154 | published by the Free Software Foundation. If the Library as you
155 | received it does not specify a version number of the GNU Lesser
156 | General Public License, you may choose any version of the GNU Lesser
157 | General Public License ever published by the Free Software Foundation.
158 |
159 | If the Library as you received it specifies that a proxy can decide
160 | whether future versions of the GNU Lesser General Public License shall
161 | apply, that proxy's public statement of acceptance of any version is
162 | permanent authorization for you to choose that version for the
163 | Library.
164 |
--------------------------------------------------------------------------------
/LibraryInjector.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 56760EE226E46D2E0023A211 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56760EE126E46D2E0023A211 /* main.cpp */; };
11 | 56760EEA26E46D640023A211 /* libEndpointSecurity.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 56760EE926E46D640023A211 /* libEndpointSecurity.tbd */; };
12 | 56760EEC26E46D700023A211 /* libbsm.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 56760EEB26E46D700023A211 /* libbsm.tbd */; };
13 | 56E2987326E46E1C00FFBC1F /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56E2987226E46E1C00FFBC1F /* main.cpp */; };
14 | 56E2988126E46E5F00FFBC1F /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 56E2988026E46E5F00FFBC1F /* testlib.c */; };
15 | /* End PBXBuildFile section */
16 |
17 | /* Begin PBXCopyFilesBuildPhase section */
18 | 56760EDC26E46D2E0023A211 /* CopyFiles */ = {
19 | isa = PBXCopyFilesBuildPhase;
20 | buildActionMask = 2147483647;
21 | dstPath = /usr/share/man/man1/;
22 | dstSubfolderSpec = 0;
23 | files = (
24 | );
25 | runOnlyForDeploymentPostprocessing = 1;
26 | };
27 | 56E2986E26E46E1C00FFBC1F /* CopyFiles */ = {
28 | isa = PBXCopyFilesBuildPhase;
29 | buildActionMask = 2147483647;
30 | dstPath = /usr/share/man/man1/;
31 | dstSubfolderSpec = 0;
32 | files = (
33 | );
34 | runOnlyForDeploymentPostprocessing = 1;
35 | };
36 | /* End PBXCopyFilesBuildPhase section */
37 |
38 | /* Begin PBXFileReference section */
39 | 56760EDE26E46D2E0023A211 /* LibraryInjector */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = LibraryInjector; sourceTree = BUILT_PRODUCTS_DIR; };
40 | 56760EE126E46D2E0023A211 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; };
41 | 56760EE926E46D640023A211 /* libEndpointSecurity.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libEndpointSecurity.tbd; path = usr/lib/libEndpointSecurity.tbd; sourceTree = SDKROOT; };
42 | 56760EEB26E46D700023A211 /* libbsm.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbsm.tbd; path = usr/lib/libbsm.tbd; sourceTree = SDKROOT; };
43 | 56760EED26E46D8F0023A211 /* LibraryInjector.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LibraryInjector.entitlements; sourceTree = ""; };
44 | 56E2987026E46E1C00FFBC1F /* TestHost */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = TestHost; sourceTree = BUILT_PRODUCTS_DIR; };
45 | 56E2987226E46E1C00FFBC1F /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; };
46 | 56E2987B26E46E3D00FFBC1F /* libTestLib.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libTestLib.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
47 | 56E2988026E46E5F00FFBC1F /* testlib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = testlib.c; sourceTree = ""; };
48 | 56E2988626E48F7000FFBC1F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
49 | 56E2988726E4906600FFBC1F /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = ""; };
50 | /* End PBXFileReference section */
51 |
52 | /* Begin PBXFrameworksBuildPhase section */
53 | 56760EDB26E46D2E0023A211 /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | 56760EEC26E46D700023A211 /* libbsm.tbd in Frameworks */,
58 | 56760EEA26E46D640023A211 /* libEndpointSecurity.tbd in Frameworks */,
59 | );
60 | runOnlyForDeploymentPostprocessing = 0;
61 | };
62 | 56E2986D26E46E1C00FFBC1F /* Frameworks */ = {
63 | isa = PBXFrameworksBuildPhase;
64 | buildActionMask = 2147483647;
65 | files = (
66 | );
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | 56E2987926E46E3D00FFBC1F /* Frameworks */ = {
70 | isa = PBXFrameworksBuildPhase;
71 | buildActionMask = 2147483647;
72 | files = (
73 | );
74 | runOnlyForDeploymentPostprocessing = 0;
75 | };
76 | /* End PBXFrameworksBuildPhase section */
77 |
78 | /* Begin PBXGroup section */
79 | 56760ED526E46D2E0023A211 = {
80 | isa = PBXGroup;
81 | children = (
82 | 56E2988726E4906600FFBC1F /* LICENSE.md */,
83 | 56E2988626E48F7000FFBC1F /* README.md */,
84 | 56E2987F26E46E4F00FFBC1F /* TestLib */,
85 | 56760EE026E46D2E0023A211 /* LibraryInjector */,
86 | 56E2987126E46E1C00FFBC1F /* TestHost */,
87 | 56760EDF26E46D2E0023A211 /* Products */,
88 | 56760EE826E46D640023A211 /* Frameworks */,
89 | );
90 | sourceTree = "";
91 | };
92 | 56760EDF26E46D2E0023A211 /* Products */ = {
93 | isa = PBXGroup;
94 | children = (
95 | 56760EDE26E46D2E0023A211 /* LibraryInjector */,
96 | 56E2987026E46E1C00FFBC1F /* TestHost */,
97 | 56E2987B26E46E3D00FFBC1F /* libTestLib.dylib */,
98 | );
99 | name = Products;
100 | sourceTree = "";
101 | };
102 | 56760EE026E46D2E0023A211 /* LibraryInjector */ = {
103 | isa = PBXGroup;
104 | children = (
105 | 56760EE126E46D2E0023A211 /* main.cpp */,
106 | 56760EED26E46D8F0023A211 /* LibraryInjector.entitlements */,
107 | );
108 | path = LibraryInjector;
109 | sourceTree = "";
110 | };
111 | 56760EE826E46D640023A211 /* Frameworks */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 56760EEB26E46D700023A211 /* libbsm.tbd */,
115 | 56760EE926E46D640023A211 /* libEndpointSecurity.tbd */,
116 | );
117 | name = Frameworks;
118 | sourceTree = "";
119 | };
120 | 56E2987126E46E1C00FFBC1F /* TestHost */ = {
121 | isa = PBXGroup;
122 | children = (
123 | 56E2987226E46E1C00FFBC1F /* main.cpp */,
124 | );
125 | path = TestHost;
126 | sourceTree = "";
127 | };
128 | 56E2987F26E46E4F00FFBC1F /* TestLib */ = {
129 | isa = PBXGroup;
130 | children = (
131 | 56E2988026E46E5F00FFBC1F /* testlib.c */,
132 | );
133 | path = TestLib;
134 | sourceTree = "";
135 | };
136 | /* End PBXGroup section */
137 |
138 | /* Begin PBXHeadersBuildPhase section */
139 | 56E2987726E46E3D00FFBC1F /* Headers */ = {
140 | isa = PBXHeadersBuildPhase;
141 | buildActionMask = 2147483647;
142 | files = (
143 | );
144 | runOnlyForDeploymentPostprocessing = 0;
145 | };
146 | /* End PBXHeadersBuildPhase section */
147 |
148 | /* Begin PBXNativeTarget section */
149 | 56760EDD26E46D2E0023A211 /* LibraryInjector */ = {
150 | isa = PBXNativeTarget;
151 | buildConfigurationList = 56760EE526E46D2E0023A211 /* Build configuration list for PBXNativeTarget "LibraryInjector" */;
152 | buildPhases = (
153 | 56760EDA26E46D2E0023A211 /* Sources */,
154 | 56760EDB26E46D2E0023A211 /* Frameworks */,
155 | 56760EDC26E46D2E0023A211 /* CopyFiles */,
156 | );
157 | buildRules = (
158 | );
159 | dependencies = (
160 | );
161 | name = LibraryInjector;
162 | productName = LibraryInjector;
163 | productReference = 56760EDE26E46D2E0023A211 /* LibraryInjector */;
164 | productType = "com.apple.product-type.tool";
165 | };
166 | 56E2986F26E46E1C00FFBC1F /* TestHost */ = {
167 | isa = PBXNativeTarget;
168 | buildConfigurationList = 56E2987626E46E1C00FFBC1F /* Build configuration list for PBXNativeTarget "TestHost" */;
169 | buildPhases = (
170 | 56E2986C26E46E1C00FFBC1F /* Sources */,
171 | 56E2986D26E46E1C00FFBC1F /* Frameworks */,
172 | 56E2986E26E46E1C00FFBC1F /* CopyFiles */,
173 | );
174 | buildRules = (
175 | );
176 | dependencies = (
177 | );
178 | name = TestHost;
179 | productName = TestHost;
180 | productReference = 56E2987026E46E1C00FFBC1F /* TestHost */;
181 | productType = "com.apple.product-type.tool";
182 | };
183 | 56E2987A26E46E3D00FFBC1F /* TestLib */ = {
184 | isa = PBXNativeTarget;
185 | buildConfigurationList = 56E2987C26E46E3D00FFBC1F /* Build configuration list for PBXNativeTarget "TestLib" */;
186 | buildPhases = (
187 | 56E2987726E46E3D00FFBC1F /* Headers */,
188 | 56E2987826E46E3D00FFBC1F /* Sources */,
189 | 56E2987926E46E3D00FFBC1F /* Frameworks */,
190 | );
191 | buildRules = (
192 | );
193 | dependencies = (
194 | );
195 | name = TestLib;
196 | productName = TestLib;
197 | productReference = 56E2987B26E46E3D00FFBC1F /* libTestLib.dylib */;
198 | productType = "com.apple.product-type.library.dynamic";
199 | };
200 | /* End PBXNativeTarget section */
201 |
202 | /* Begin PBXProject section */
203 | 56760ED626E46D2E0023A211 /* Project object */ = {
204 | isa = PBXProject;
205 | attributes = {
206 | LastUpgradeCheck = 1250;
207 | TargetAttributes = {
208 | 56760EDD26E46D2E0023A211 = {
209 | CreatedOnToolsVersion = 12.5;
210 | };
211 | 56E2986F26E46E1C00FFBC1F = {
212 | CreatedOnToolsVersion = 12.5;
213 | };
214 | 56E2987A26E46E3D00FFBC1F = {
215 | CreatedOnToolsVersion = 12.5;
216 | };
217 | };
218 | };
219 | buildConfigurationList = 56760ED926E46D2E0023A211 /* Build configuration list for PBXProject "LibraryInjector" */;
220 | compatibilityVersion = "Xcode 9.3";
221 | developmentRegion = en;
222 | hasScannedForEncodings = 0;
223 | knownRegions = (
224 | en,
225 | Base,
226 | );
227 | mainGroup = 56760ED526E46D2E0023A211;
228 | productRefGroup = 56760EDF26E46D2E0023A211 /* Products */;
229 | projectDirPath = "";
230 | projectRoot = "";
231 | targets = (
232 | 56760EDD26E46D2E0023A211 /* LibraryInjector */,
233 | 56E2986F26E46E1C00FFBC1F /* TestHost */,
234 | 56E2987A26E46E3D00FFBC1F /* TestLib */,
235 | );
236 | };
237 | /* End PBXProject section */
238 |
239 | /* Begin PBXSourcesBuildPhase section */
240 | 56760EDA26E46D2E0023A211 /* Sources */ = {
241 | isa = PBXSourcesBuildPhase;
242 | buildActionMask = 2147483647;
243 | files = (
244 | 56760EE226E46D2E0023A211 /* main.cpp in Sources */,
245 | );
246 | runOnlyForDeploymentPostprocessing = 0;
247 | };
248 | 56E2986C26E46E1C00FFBC1F /* Sources */ = {
249 | isa = PBXSourcesBuildPhase;
250 | buildActionMask = 2147483647;
251 | files = (
252 | 56E2987326E46E1C00FFBC1F /* main.cpp in Sources */,
253 | );
254 | runOnlyForDeploymentPostprocessing = 0;
255 | };
256 | 56E2987826E46E3D00FFBC1F /* Sources */ = {
257 | isa = PBXSourcesBuildPhase;
258 | buildActionMask = 2147483647;
259 | files = (
260 | 56E2988126E46E5F00FFBC1F /* testlib.c in Sources */,
261 | );
262 | runOnlyForDeploymentPostprocessing = 0;
263 | };
264 | /* End PBXSourcesBuildPhase section */
265 |
266 | /* Begin XCBuildConfiguration section */
267 | 56760EE326E46D2E0023A211 /* Debug */ = {
268 | isa = XCBuildConfiguration;
269 | buildSettings = {
270 | ALWAYS_SEARCH_USER_PATHS = NO;
271 | CLANG_ANALYZER_NONNULL = YES;
272 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
273 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
274 | CLANG_CXX_LIBRARY = "libc++";
275 | CLANG_ENABLE_MODULES = YES;
276 | CLANG_ENABLE_OBJC_ARC = YES;
277 | CLANG_ENABLE_OBJC_WEAK = YES;
278 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
279 | CLANG_WARN_BOOL_CONVERSION = YES;
280 | CLANG_WARN_COMMA = YES;
281 | CLANG_WARN_CONSTANT_CONVERSION = YES;
282 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
283 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
284 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
285 | CLANG_WARN_EMPTY_BODY = YES;
286 | CLANG_WARN_ENUM_CONVERSION = YES;
287 | CLANG_WARN_INFINITE_RECURSION = YES;
288 | CLANG_WARN_INT_CONVERSION = YES;
289 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
290 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
291 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
292 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
293 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
294 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
295 | CLANG_WARN_STRICT_PROTOTYPES = YES;
296 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
297 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
298 | CLANG_WARN_UNREACHABLE_CODE = YES;
299 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
300 | COPY_PHASE_STRIP = NO;
301 | DEBUG_INFORMATION_FORMAT = dwarf;
302 | ENABLE_STRICT_OBJC_MSGSEND = YES;
303 | ENABLE_TESTABILITY = YES;
304 | GCC_C_LANGUAGE_STANDARD = gnu11;
305 | GCC_DYNAMIC_NO_PIC = NO;
306 | GCC_NO_COMMON_BLOCKS = YES;
307 | GCC_OPTIMIZATION_LEVEL = 0;
308 | GCC_PREPROCESSOR_DEFINITIONS = (
309 | "DEBUG=1",
310 | "$(inherited)",
311 | );
312 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
313 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
314 | GCC_WARN_UNDECLARED_SELECTOR = YES;
315 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
316 | GCC_WARN_UNUSED_FUNCTION = YES;
317 | GCC_WARN_UNUSED_VARIABLE = YES;
318 | MACOSX_DEPLOYMENT_TARGET = 11.3;
319 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
320 | MTL_FAST_MATH = YES;
321 | ONLY_ACTIVE_ARCH = YES;
322 | SDKROOT = macosx;
323 | };
324 | name = Debug;
325 | };
326 | 56760EE426E46D2E0023A211 /* Release */ = {
327 | isa = XCBuildConfiguration;
328 | buildSettings = {
329 | ALWAYS_SEARCH_USER_PATHS = NO;
330 | CLANG_ANALYZER_NONNULL = YES;
331 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
333 | CLANG_CXX_LIBRARY = "libc++";
334 | CLANG_ENABLE_MODULES = YES;
335 | CLANG_ENABLE_OBJC_ARC = YES;
336 | CLANG_ENABLE_OBJC_WEAK = YES;
337 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
338 | CLANG_WARN_BOOL_CONVERSION = YES;
339 | CLANG_WARN_COMMA = YES;
340 | CLANG_WARN_CONSTANT_CONVERSION = YES;
341 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
342 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
343 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
344 | CLANG_WARN_EMPTY_BODY = YES;
345 | CLANG_WARN_ENUM_CONVERSION = YES;
346 | CLANG_WARN_INFINITE_RECURSION = YES;
347 | CLANG_WARN_INT_CONVERSION = YES;
348 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
349 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
350 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
351 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
352 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
353 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
354 | CLANG_WARN_STRICT_PROTOTYPES = YES;
355 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
356 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
357 | CLANG_WARN_UNREACHABLE_CODE = YES;
358 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
359 | COPY_PHASE_STRIP = NO;
360 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
361 | ENABLE_NS_ASSERTIONS = NO;
362 | ENABLE_STRICT_OBJC_MSGSEND = YES;
363 | GCC_C_LANGUAGE_STANDARD = gnu11;
364 | GCC_NO_COMMON_BLOCKS = YES;
365 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
366 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
367 | GCC_WARN_UNDECLARED_SELECTOR = YES;
368 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
369 | GCC_WARN_UNUSED_FUNCTION = YES;
370 | GCC_WARN_UNUSED_VARIABLE = YES;
371 | MACOSX_DEPLOYMENT_TARGET = 11.3;
372 | MTL_ENABLE_DEBUG_INFO = NO;
373 | MTL_FAST_MATH = YES;
374 | SDKROOT = macosx;
375 | };
376 | name = Release;
377 | };
378 | 56760EE626E46D2E0023A211 /* Debug */ = {
379 | isa = XCBuildConfiguration;
380 | buildSettings = {
381 | CLANG_CXX_LANGUAGE_STANDARD = "c++20";
382 | CODE_SIGN_ENTITLEMENTS = LibraryInjector/LibraryInjector.entitlements;
383 | CODE_SIGN_STYLE = Automatic;
384 | DEVELOPMENT_TEAM = 25MTNC334J;
385 | ENABLE_HARDENED_RUNTIME = YES;
386 | PRODUCT_NAME = "$(TARGET_NAME)";
387 | };
388 | name = Debug;
389 | };
390 | 56760EE726E46D2E0023A211 /* Release */ = {
391 | isa = XCBuildConfiguration;
392 | buildSettings = {
393 | CLANG_CXX_LANGUAGE_STANDARD = "c++20";
394 | CODE_SIGN_ENTITLEMENTS = LibraryInjector/LibraryInjector.entitlements;
395 | CODE_SIGN_STYLE = Automatic;
396 | DEVELOPMENT_TEAM = 25MTNC334J;
397 | ENABLE_HARDENED_RUNTIME = YES;
398 | PRODUCT_NAME = "$(TARGET_NAME)";
399 | };
400 | name = Release;
401 | };
402 | 56E2987426E46E1C00FFBC1F /* Debug */ = {
403 | isa = XCBuildConfiguration;
404 | buildSettings = {
405 | CODE_SIGN_STYLE = Automatic;
406 | DEVELOPMENT_TEAM = 25MTNC334J;
407 | ENABLE_HARDENED_RUNTIME = YES;
408 | PRODUCT_NAME = "$(TARGET_NAME)";
409 | };
410 | name = Debug;
411 | };
412 | 56E2987526E46E1C00FFBC1F /* Release */ = {
413 | isa = XCBuildConfiguration;
414 | buildSettings = {
415 | CODE_SIGN_STYLE = Automatic;
416 | DEVELOPMENT_TEAM = 25MTNC334J;
417 | ENABLE_HARDENED_RUNTIME = YES;
418 | PRODUCT_NAME = "$(TARGET_NAME)";
419 | };
420 | name = Release;
421 | };
422 | 56E2987D26E46E3D00FFBC1F /* Debug */ = {
423 | isa = XCBuildConfiguration;
424 | buildSettings = {
425 | CODE_SIGN_STYLE = Automatic;
426 | DEVELOPMENT_TEAM = 25MTNC334J;
427 | DYLIB_COMPATIBILITY_VERSION = 1;
428 | DYLIB_CURRENT_VERSION = 1;
429 | EXECUTABLE_PREFIX = lib;
430 | PRODUCT_NAME = "$(TARGET_NAME)";
431 | SKIP_INSTALL = YES;
432 | };
433 | name = Debug;
434 | };
435 | 56E2987E26E46E3D00FFBC1F /* Release */ = {
436 | isa = XCBuildConfiguration;
437 | buildSettings = {
438 | CODE_SIGN_STYLE = Automatic;
439 | DEVELOPMENT_TEAM = 25MTNC334J;
440 | DYLIB_COMPATIBILITY_VERSION = 1;
441 | DYLIB_CURRENT_VERSION = 1;
442 | EXECUTABLE_PREFIX = lib;
443 | PRODUCT_NAME = "$(TARGET_NAME)";
444 | SKIP_INSTALL = YES;
445 | };
446 | name = Release;
447 | };
448 | /* End XCBuildConfiguration section */
449 |
450 | /* Begin XCConfigurationList section */
451 | 56760ED926E46D2E0023A211 /* Build configuration list for PBXProject "LibraryInjector" */ = {
452 | isa = XCConfigurationList;
453 | buildConfigurations = (
454 | 56760EE326E46D2E0023A211 /* Debug */,
455 | 56760EE426E46D2E0023A211 /* Release */,
456 | );
457 | defaultConfigurationIsVisible = 0;
458 | defaultConfigurationName = Release;
459 | };
460 | 56760EE526E46D2E0023A211 /* Build configuration list for PBXNativeTarget "LibraryInjector" */ = {
461 | isa = XCConfigurationList;
462 | buildConfigurations = (
463 | 56760EE626E46D2E0023A211 /* Debug */,
464 | 56760EE726E46D2E0023A211 /* Release */,
465 | );
466 | defaultConfigurationIsVisible = 0;
467 | defaultConfigurationName = Release;
468 | };
469 | 56E2987626E46E1C00FFBC1F /* Build configuration list for PBXNativeTarget "TestHost" */ = {
470 | isa = XCConfigurationList;
471 | buildConfigurations = (
472 | 56E2987426E46E1C00FFBC1F /* Debug */,
473 | 56E2987526E46E1C00FFBC1F /* Release */,
474 | );
475 | defaultConfigurationIsVisible = 0;
476 | defaultConfigurationName = Release;
477 | };
478 | 56E2987C26E46E3D00FFBC1F /* Build configuration list for PBXNativeTarget "TestLib" */ = {
479 | isa = XCConfigurationList;
480 | buildConfigurations = (
481 | 56E2987D26E46E3D00FFBC1F /* Debug */,
482 | 56E2987E26E46E3D00FFBC1F /* Release */,
483 | );
484 | defaultConfigurationIsVisible = 0;
485 | defaultConfigurationName = Release;
486 | };
487 | /* End XCConfigurationList section */
488 | };
489 | rootObject = 56760ED626E46D2E0023A211 /* Project object */;
490 | }
491 |
--------------------------------------------------------------------------------
/LibraryInjector.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LibraryInjector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LibraryInjector.xcodeproj/xcshareddata/xcschemes/LibraryInjector.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
44 |
46 |
52 |
53 |
54 |
55 |
61 |
63 |
69 |
70 |
71 |
72 |
74 |
75 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/LibraryInjector/LibraryInjector.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.endpoint-security.client
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LibraryInjector/main.cpp:
--------------------------------------------------------------------------------
1 | // Based on this gist by Saagar Jha:
2 | // https://gist.github.com/saagarjha/a70d44951cb72f82efee3317d80ac07f
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #ifdef __arm64__
15 | #include
16 | #define x_thread_state_get_sp(state) (arm_thread_state64_get_sp(state))
17 | #define x_thread_state_set_sp(state, sp) (arm_thread_state64_set_sp(state, sp))
18 | #define X_THREAD_STATE ARM_THREAD_STATE64
19 | typedef arm_thread_state64_t x_thread_state_t;
20 | #elif __x86_64__
21 | #include
22 | #define x_thread_state_get_sp(state) (state.__rsp)
23 | #define x_thread_state_set_sp(state, sp) do { state.__rsp = sp; } while (0)
24 | #define X_THREAD_STATE x86_THREAD_STATE64
25 | typedef x86_thread_state64_t x_thread_state_t;
26 | #else
27 | #error "Only arm64 and x86_64 are currently supported"
28 | #endif
29 |
30 | namespace fs = std::filesystem;
31 |
32 | static inline void _ensure(bool cond, const char *cond_s, const char *file, long line, const char *fn) {
33 | if (!(cond)) {
34 | throw std::runtime_error(std::string("") + "Check \"" + cond_s + "\" failed at " +
35 | file + ":" + std::to_string(line) + " in function " + fn);
36 | }
37 | }
38 | #define ensure(condition) (_ensure(condition, #condition, __FILE__, __LINE__, __FUNCTION__))
39 |
40 | template
41 | static inline void _ensureEq(const T &a, const U &b,
42 | const char *a_s, const char *b_s,
43 | const char *file, long line, const char *fn) {
44 | if (a != b) {
45 | throw std::runtime_error(std::string("") + "Check \"" + a_s + " == " + b_s + "\" failed at " +
46 | file + ":" + std::to_string(line) + " in function " + fn + " (got " +
47 | std::to_string(a) + " != " + std::to_string(b) + ")");
48 | }
49 | }
50 | #define ensureEq(a, b) (_ensureEq(a, b, #a, #b, __FILE__, __LINE__, __FUNCTION__))
51 |
52 | #define kcheck(a) (ensureEq(a, KERN_SUCCESS))
53 |
54 | template
55 | static constexpr inline T align(T orig) {
56 | static_assert(alignment <= (1 << sizeof(T)), "alignment too large for given type");
57 | static_assert(alignment && ((alignment & (alignment - 1)) == 0),
58 | "alignment must be a positive power of two");
59 | return (orig + (T)alignment - 1) & ~((T)alignment - 1);
60 | }
61 | // static_assert(align<8>(15) == 16);
62 | // static_assert(align<8>(16) == 16);
63 | // static_assert(align<8>(17) == 24);
64 |
65 | template
66 | static constexpr inline T round_down(T orig, U boundary) {
67 | return orig / boundary * boundary;
68 | }
69 | //static_assert(round_down(8, 7) == 7);
70 | //static_assert(round_down(12, 7) == 7);
71 | //static_assert(round_down(14, 7) == 14);
72 |
73 | class TaskCursor {
74 | private:
75 | const task_t task_;
76 | std::uintptr_t address_;
77 | public:
78 | TaskCursor(task_t task, std::uintptr_t address) : task_(task), address_(address) {}
79 |
80 | const task_t &task() { return task_; }
81 | std::uintptr_t &address() { return address_; }
82 |
83 | // write next val_size bytes without moving cursor
84 | void write_ahead(const void *val, unsigned int val_size) const {
85 | vm_region_basic_info_data_64_t info;
86 | mach_msg_type_number_t info_sz = sizeof(info);
87 | vm_address_t region_addr = round_down(address_, PAGE_SIZE);
88 | vm_size_t region_size;
89 | mach_port_t object; // unused
90 | kcheck(vm_region_64(task_, ®ion_addr, ®ion_size, VM_REGION_BASIC_INFO_64, reinterpret_cast(&info), &info_sz, &object));
91 | kcheck(vm_protect(task_, region_addr, region_size, false, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY));
92 | kcheck(vm_write(task_, address_, reinterpret_cast(val), val_size));
93 | kcheck(vm_protect(task_, region_addr, region_size, false, info.protection));
94 | }
95 |
96 | void write(const void *val, unsigned int val_size) {
97 | write_ahead(val, val_size);
98 | address_ += val_size;
99 | }
100 |
101 | template
102 | void write_ahead(const T &val) const {
103 | write_ahead(&val, sizeof(val));
104 | }
105 |
106 | template
107 | void write(const T &val) {
108 | write(&val, sizeof(val));
109 | }
110 |
111 | void peek(void *out, size_t size) const {
112 | size_t count;
113 | kcheck(vm_read_overwrite(task_, address_, size, reinterpret_cast(out), &count));
114 | ensureEq(count, size);
115 | }
116 |
117 | std::unique_ptr peek(size_t size) const {
118 | auto ptr = std::make_unique(size);
119 | peek(ptr.get(), size);
120 | return ptr;
121 | }
122 |
123 | void scan(void *out, size_t size) {
124 | peek(out, size);
125 | address_ += size;
126 | }
127 |
128 | std::unique_ptr scan(size_t size) {
129 | auto ptr = peek(size);
130 | address_ += size;
131 | return ptr;
132 | }
133 |
134 | template
135 | T peek() const {
136 | T t;
137 | peek(&t, sizeof(t));
138 | return t;
139 | }
140 |
141 | template
142 | T scan() {
143 | T t;
144 | scan(&t, sizeof(t));
145 | return t;
146 | }
147 |
148 | std::vector scan_string_array() {
149 | std::vector strings;
150 | std::uintptr_t string;
151 | while ((string = scan())) {
152 | strings.push_back(string);
153 | }
154 | return strings;
155 | }
156 |
157 | std::string scan_string() {
158 | std::string string;
159 | char c;
160 | while ((c = scan())) {
161 | string.push_back(c);
162 | }
163 | return string;
164 | }
165 | };
166 |
167 | // Adds DYLD_INSERT_LIBRARIES= to stack envp, moves cursor to new stack base
168 | // Returns load address.
169 | //
170 | // This function is needed because without DYLD_INSERT_LIBRARIES or some
171 | // other dyld env var, dyld may use a cached launch closure and ignore
172 | // our new load command. We're good as long as we have a relevant dyld
173 | // env var, even if it's empty and/or ignored by dyld.
174 | static std::uintptr_t rearrange_stack(TaskCursor &cur) {
175 | /// https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/kern/kern_exec.c#L4919
176 | ///
177 | /// initial stack layout (with dummy addresses):
178 | /// ...
179 | /// 0xFFB8
180 | /// 0xFFC0
181 | /// --- _dyld_start frame vvv ---
182 | /// 0xFFC8 (cursor) load_address
183 | /// 0xFFD0 argc
184 | /// 0xFFD8 argv[]
185 | /// 0xFFE0 envp[]
186 | /// 0xFFE8 apple[]
187 | /// 0xFFF0 strings
188 | /// --- start of stack ---
189 | ///
190 | /// final stack layout (with dummy addresses, slightly simplified):
191 | /// ...
192 | /// 0xFFB8
193 | /// --- _dyld_start frame vvv ---
194 | /// 0xFFC0 (cursor) load_address
195 | /// 0xFFC8 argc
196 | /// 0xFFD0 argv[] -|
197 | /// 0xFFD8 envp[] | - rebased
198 | /// 0xFFE0 apple[] -|
199 | /// 0xFFE8 strings
200 | /// 0xFFF0 "DYLD_INSERT_LIBRARIES="
201 | /// --- start of stack ---
202 |
203 | std::cout << "Rearranging... SP: " << (void *)cur.address() << std::endl;
204 |
205 | auto loadAddress = cur.scan();
206 | auto argc = cur.scan();
207 | auto argvAddresses = cur.scan_string_array();
208 | auto envpAddresses = cur.scan_string_array();
209 | auto appleAddresses = cur.scan_string_array();
210 |
211 | // cursor is now at the strings
212 |
213 | auto stringReader = [&](const std::uintptr_t address) {
214 | auto oldAddr = cur.address();
215 | cur.address() = address;
216 | auto str = cur.scan_string();
217 | cur.address() = oldAddr;
218 | return str;
219 | };
220 | std::vector argv;
221 | std::transform(argvAddresses.begin(), argvAddresses.end(), std::back_inserter(argv), stringReader);
222 | std::vector envp;
223 | std::transform(envpAddresses.begin(), envpAddresses.end(), std::back_inserter(envp), stringReader);
224 | std::vector apple;
225 | std::transform(appleAddresses.begin(), appleAddresses.end(), std::back_inserter(apple), stringReader);
226 |
227 | auto dyld_insert_libraries = std::find_if(envp.begin(), envp.end(), [&](const auto &string) {
228 | return string.starts_with("DYLD_INSERT_LIBRARIES=");
229 | });
230 | // if envp already has a DYLD_INSERT_LIBRARIES, no need to do anything
231 | if (dyld_insert_libraries == envp.end()) {
232 | // we don't actually insert the library this way; we just need
233 | // to ensure this env var exists so that dyld discards its
234 | // closure.
235 | envp.push_back("DYLD_INSERT_LIBRARIES=");
236 | }
237 |
238 | argvAddresses.clear();
239 | envpAddresses.clear();
240 | appleAddresses.clear();
241 |
242 | std::vector strings;
243 |
244 | auto arrayGenerator = [&](auto &addresses, const auto &string) {
245 | addresses.push_back(strings.size());
246 | std::copy(string.begin(), string.end(), std::back_inserter(strings));
247 | strings.push_back('\0');
248 | };
249 | std::for_each(argv.begin(), argv.end(), std::bind(arrayGenerator, std::ref(argvAddresses), std::placeholders::_1));
250 | std::for_each(envp.begin(), envp.end(), std::bind(arrayGenerator, std::ref(envpAddresses), std::placeholders::_1));
251 | std::for_each(apple.begin(), apple.end(), std::bind(arrayGenerator, std::ref(appleAddresses), std::placeholders::_1));
252 |
253 | // it's okay if this overwrites the arguments on the stack since we've saved them
254 | // locally, and intend to write rebased versions onto the stack later
255 | cur.address() = round_down(cur.address() - strings.size(), sizeof(std::uintptr_t));
256 | cur.write_ahead(strings.data(), (unsigned int)strings.size());
257 |
258 | auto rebaser = [&](auto &&address) {
259 | address += cur.address();
260 | };
261 | std::for_each(argvAddresses.begin(), argvAddresses.end(), rebaser);
262 | std::for_each(envpAddresses.begin(), envpAddresses.end(), rebaser);
263 | std::for_each(appleAddresses.begin(), appleAddresses.end(), rebaser);
264 |
265 | std::vector addresses;
266 | addresses.reserve(argvAddresses.size() + 1 + envpAddresses.size() + 1 + appleAddresses.size() + 1);
267 | std::copy(argvAddresses.begin(), argvAddresses.end(), std::back_inserter(addresses));
268 | addresses.push_back(0);
269 | std::copy(envpAddresses.begin(), envpAddresses.end(), std::back_inserter(addresses));
270 | addresses.push_back(0);
271 | std::copy(appleAddresses.begin(), appleAddresses.end(), std::back_inserter(addresses));
272 | addresses.push_back(0);
273 |
274 | const auto stackTop = cur.address() - (addresses.size() + 2) * sizeof(std::uintptr_t);
275 | cur.address() = stackTop;
276 | cur.write(loadAddress);
277 | cur.write(argc);
278 | cur.write(addresses.data(), (unsigned int)addresses.size() * sizeof(std::uintptr_t));
279 | cur.address() = stackTop;
280 |
281 | std::cout << "Rearranged! SP: " << (void *)stackTop << std::endl;
282 |
283 | return loadAddress;
284 | }
285 |
286 | // the cursor should point to the desired image header
287 | static void insert_dylib(TaskCursor &cur, const std::string &library) {
288 | const auto base = cur.address();
289 |
290 | std::cout << "Inserting... MH: " << (void *)base << std::endl;
291 |
292 | auto mh = cur.scan();
293 | cur.address() += mh.sizeofcmds;
294 |
295 | // +1 to NUL-terminate library
296 | auto cmdsize = (uint32_t)align<8>(sizeof(dylib_command) + library.length() + 1);
297 | std::unique_ptr mem = cur.peek(cmdsize);
298 |
299 | bool has_space = true;
300 | // TODO: Make this check smarter; the memory might be zeroed but still used somewhere (i.e. not just padding)
301 | for (unsigned i = 0; i < cmdsize; i++) {
302 | if (mem[i] != 0) {
303 | has_space = false;
304 | break;
305 | }
306 | }
307 |
308 | if (!has_space) {
309 | // use alternate mechanism, such as overwriting an existing LC?
310 | ensure(false && "not enough space");
311 | }
312 |
313 | dylib_command cmd = {
314 | .cmd = LC_LOAD_DYLIB,
315 | .cmdsize = cmdsize,
316 | .dylib = {
317 | .name = {
318 | .offset = sizeof(dylib_command)
319 | }
320 | }
321 | };
322 | memcpy(mem.get(), &cmd, sizeof(cmd));
323 | memcpy(mem.get() + sizeof(cmd), library.c_str(), library.length());
324 | cur.write(mem.get(), cmdsize);
325 |
326 | mh.sizeofcmds += cmdsize;
327 | mh.ncmds += 1;
328 |
329 | cur.address() = base;
330 | cur.write(mh);
331 |
332 | std::cout << "Inserted!" << std::endl;
333 | }
334 |
335 | static void inject(pid_t pid, const std::string &library) {
336 | std::string libname = fs::path(library).filename().string();
337 | std::cout << "Injecting " << libname << " into pid " << pid << std::endl;
338 |
339 | task_port_t task;
340 | kcheck(task_for_pid(mach_task_self(), pid, &task));
341 |
342 | thread_act_array_t threads;
343 | mach_msg_type_number_t count;
344 | kcheck(task_threads(task, &threads, &count));
345 | ensureEq(count, 1);
346 |
347 | x_thread_state_t state;
348 | count = sizeof(state);
349 | kcheck(thread_get_state(threads[0], X_THREAD_STATE, reinterpret_cast(&state), &count));
350 | kcheck(thread_convert_thread_state(threads[0], THREAD_CONVERT_THREAD_STATE_TO_SELF, X_THREAD_STATE, reinterpret_cast(&state), count, reinterpret_cast(&state), &count));
351 |
352 | auto cur = TaskCursor(task, x_thread_state_get_sp(state));
353 | const auto load_addr = rearrange_stack(cur);
354 | x_thread_state_set_sp(state, cur.address());
355 | cur.address() = load_addr;
356 |
357 | kcheck(thread_convert_thread_state(*threads, THREAD_CONVERT_THREAD_STATE_FROM_SELF, X_THREAD_STATE, reinterpret_cast(&state), count, reinterpret_cast(&state), &count));
358 | kcheck(thread_set_state(*threads, X_THREAD_STATE, reinterpret_cast(&state), count));
359 |
360 | insert_dylib(cur, library);
361 |
362 | std::cout << "Injected " << libname << "!" << std::endl;
363 | }
364 |
365 | int main(int argc, char **argv) {
366 | if (argc != 3) {
367 | std::cerr << "Usage: " << argv[0] << " " << std::endl;
368 | std::exit(1);
369 | }
370 |
371 | if (geteuid() != 0) {
372 | std::cerr << "You must run this program as root." << std::endl;
373 | std::exit(1);
374 | }
375 |
376 | fs::path process = argv[1];
377 | fs::path library = fs::canonical(argv[2]);
378 |
379 | es_client_t *client = NULL;
380 | ensureEq(es_new_client(&client, ^(es_client_t *client, const es_message_t *message) {
381 | switch (message->event_type) {
382 | case ES_EVENT_TYPE_AUTH_EXEC: {
383 | const char *name = message->event.exec.target->executable->path.data;
384 | if (fs::equivalent(name, process)) {
385 | pid_t pid = audit_token_to_pid(message->process->audit_token);
386 | try {
387 | inject(pid, library);
388 | } catch (const std::exception &e) {
389 | std::cerr << "error: Failed to inject: " << e.what() << std::endl;
390 | }
391 | }
392 | es_respond_auth_result(client, message, ES_AUTH_RESULT_ALLOW, false);
393 | break;
394 | }
395 | default:
396 | ensure(false && "Unexpected event type!");
397 | }
398 | }), ES_NEW_CLIENT_RESULT_SUCCESS);
399 | es_event_type_t events[] = { ES_EVENT_TYPE_AUTH_EXEC };
400 | ensureEq(es_subscribe(client, events, sizeof(events) / sizeof(*events)), ES_RETURN_SUCCESS);
401 | std::cout << "Listening..." << std::endl;
402 | dispatch_main();
403 | }
404 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Library Injector
2 |
3 | Load a library into newly spawned processes using EndpointSecurity.
4 |
5 | Based on [this gist](https://gist.github.com/saagarjha/a70d44951cb72f82efee3317d80ac07f) by Saagar Jha.
6 |
--------------------------------------------------------------------------------
/TestHost/main.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // main.cpp
3 | // TestHost
4 | //
5 | // Created by Kabir Oberai on 05/09/21.
6 | //
7 |
8 | #include
9 |
10 | int main(int argc, const char * argv[]) {
11 | std::cout << "Hello, World!\n";
12 | return 0;
13 | }
14 |
--------------------------------------------------------------------------------
/TestLib/testlib.c:
--------------------------------------------------------------------------------
1 | //
2 | // testlib.c
3 | // TestLib
4 | //
5 | // Created by Kabir Oberai on 05/09/21.
6 | //
7 |
8 | #include
9 |
10 | __attribute__((constructor)) static void init() {
11 | printf("testlib loaded!\n");
12 | }
13 |
--------------------------------------------------------------------------------