@@ -157,7 +157,136 @@ BOOL appendNewSection(NSMutableData* data) {
157
157
newSect.size = sectSize;
158
158
newSect.offset = newSeg.fileoff ;
159
159
newSect.align = sectSize < 16 ? 0 : 4 ;
160
- newSect.flags = 0x80000400 ; // S_REGULAR | S_ATTR_PURE_INSTRUCTIONS;
160
+ newSect.flags = 0x80000400 ; // S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
161
+
162
+ linkSeg->vmaddr += alignedSize;
163
+ linkSeg->fileoff += alignedSize;
164
+
165
+ // i love mach-o (most of this was assist because this has been giving me a headache) just to shift the linkedit cmds
166
+ searchPtr = lcPtr;
167
+ for (uint32_t i = 0 ; i < ncmds; i++) {
168
+ struct load_command * lc = (struct load_command *)searchPtr;
169
+ if (lc->cmd == LC_DYLD_INFO_ONLY || lc->cmd == LC_DYLD_INFO) {
170
+ struct dyld_info_command * dc = (struct dyld_info_command *)searchPtr;
171
+ #define SHIFT (field ) if (dc->field >= linkFileOff) dc->field += alignedSize
172
+ SHIFT (rebase_off);
173
+ SHIFT (bind_off);
174
+ SHIFT (weak_bind_off);
175
+ SHIFT (lazy_bind_off);
176
+ SHIFT (export_off);
177
+ #undef SHIFT
178
+ } else if (lc->cmd == LC_SYMTAB) {
179
+ struct symtab_command * sc = (struct symtab_command *)searchPtr;
180
+ if (sc->symoff >= linkFileOff)
181
+ sc->symoff += alignedSize;
182
+ if (sc->stroff >= linkFileOff)
183
+ sc->stroff += alignedSize;
184
+ } else if (lc->cmd == LC_DYSYMTAB) {
185
+ struct dysymtab_command * dc = (struct dysymtab_command *)searchPtr;
186
+ #define DS (field ) if (dc->field >= linkFileOff) dc->field += alignedSize
187
+ DS (tocoff);
188
+ DS (modtaboff);
189
+ DS (extrefsymoff);
190
+ DS (indirectsymoff);
191
+ DS (extreloff);
192
+ DS (locreloff);
193
+ #undef DS
194
+ } else if (lc->cmd == LC_CODE_SIGNATURE || lc->cmd == LC_SEGMENT_SPLIT_INFO || lc->cmd == LC_FUNCTION_STARTS || lc->cmd == LC_DATA_IN_CODE ||
195
+ lc->cmd == LC_DYLIB_CODE_SIGN_DRS) {
196
+ struct linkedit_data_command * ld = (struct linkedit_data_command *)searchPtr;
197
+ if (ld->dataoff >= linkFileOff)
198
+ ld->dataoff += alignedSize;
199
+ }
200
+ searchPtr += lc->cmdsize ;
201
+ }
202
+ header->ncmds += 1 ;
203
+ header->sizeofcmds += newSeg.cmdsize ;
204
+
205
+ // rebuilding just in case because binary shifts are wacky
206
+ NSMutableData * out = [NSMutableData data ];
207
+ [out appendBytes: buf length: sizeof (*header)];
208
+ lcPtr = buf + sizeof (*header);
209
+ for (uint32_t i = 0 ; i < ncmds; i++) {
210
+ struct load_command * lc = (struct load_command *)lcPtr;
211
+ if (i == linkIndex) {
212
+ [out appendBytes: &newSeg length: sizeof (newSeg)];
213
+ [out appendBytes: &newSect length: sizeof (newSect)];
214
+ }
215
+ [out appendBytes: lcPtr length: lc->cmdsize];
216
+ lcPtr += lc->cmdsize ;
217
+ }
218
+ NSUInteger headerLen = out.length ;
219
+ if (headerLen < linkFileOff) {
220
+ NSUInteger copySize = linkFileOff - headerLen;
221
+ [out appendBytes: buf + headerLen length: copySize];
222
+ }
223
+ uint8_t * dead = (uint8_t *)calloc (1 , alignedSize);
224
+ [out appendBytes: dead length: sectSize];
225
+ if (alignedSize > sectSize) {
226
+ [out appendBytes: dead + sectSize length: (alignedSize - sectSize)];
227
+ }
228
+ free (dead);
229
+ [out appendBytes: buf + linkFileOff length: origSize - linkFileOff];
230
+ [data setData: out];
231
+ return YES ;
232
+ }
233
+ BOOL appendNewRWSection (NSMutableData * data) {
234
+ NSUInteger origSize = data.length ;
235
+ const char * segNameC = " __STORAGE" ;
236
+ const char * sectNameC = " __storage" ;
237
+ uint64_t sectSize = sizeof (uintptr_t );
238
+
239
+ uint8_t * buf = (uint8_t *)data.mutableBytes ;
240
+ struct mach_header_64 * header = (struct mach_header_64 *)buf;
241
+
242
+ uint8_t * lcPtr = buf + sizeof (*header);
243
+ uint32_t ncmds = header->ncmds ;
244
+
245
+ struct segment_command_64 * linkSeg = NULL ;
246
+ uint32_t linkIndex = 0 ;
247
+ uint64_t linkFileOff = 0 ;
248
+ uint8_t * searchPtr = lcPtr;
249
+ for (uint32_t i = 0 ; i < ncmds; i++) {
250
+ struct load_command * lc = (struct load_command *)searchPtr;
251
+ if (lc->cmd == LC_SEGMENT_64) {
252
+ struct segment_command_64 * sc = (struct segment_command_64 *)searchPtr;
253
+ if (strncmp (sc->segname , " __LINKEDIT" , 16 ) == 0 ) {
254
+ linkSeg = sc;
255
+ linkIndex = i;
256
+ linkFileOff = sc->fileoff ;
257
+ break ;
258
+ }
259
+ }
260
+ searchPtr += lc->cmdsize ;
261
+ }
262
+ if (!linkSeg) {
263
+ AppLog (@" Couldn't find __LINKEDIT segment." );
264
+ return NO ;
265
+ }
266
+
267
+ uint64_t alignedSize = align (MAX (sectSize, 0x4000 ), 0x1000 );
268
+ struct segment_command_64 newSeg;
269
+ struct section_64 newSect;
270
+ memset (&newSeg, 0 , sizeof (newSeg));
271
+ memset (&newSect, 0 , sizeof (newSect));
272
+ newSeg.cmd = LC_SEGMENT_64;
273
+ newSeg.cmdsize = sizeof (newSeg) + sizeof (newSect);
274
+ strncpy (newSeg.segname , segNameC, 16 );
275
+ newSeg.vmaddr = linkSeg->vmaddr ;
276
+ newSeg.vmsize = alignedSize;
277
+ newSeg.fileoff = linkFileOff;
278
+ newSeg.filesize = alignedSize;
279
+ newSeg.maxprot = VM_PROT_READ | VM_PROT_WRITE;
280
+ newSeg.initprot = VM_PROT_READ | VM_PROT_WRITE;
281
+ newSeg.nsects = 1 ;
282
+
283
+ strncpy (newSect.sectname , sectNameC, 16 );
284
+ strncpy (newSect.segname , segNameC, 16 );
285
+ newSect.addr = newSeg.vmaddr ;
286
+ newSect.size = sectSize;
287
+ newSect.offset = newSeg.fileoff ;
288
+ newSect.align = 3 ;
289
+ newSect.flags = 0x0 ; // S_REGULAR
161
290
162
291
linkSeg->vmaddr += alignedSize;
163
292
linkSeg->fileoff += alignedSize;
@@ -496,6 +625,10 @@ + (void)patchGDBinary:(NSURL*)from to:(NSURL*)to withHandlerAddress:(uint64_t)ha
496
625
AppLog (@" Something went wrong when writing a new executable region." );
497
626
return completionHandler (NO , @" Couldn't write new RX region." );
498
627
}
628
+ if (!appendNewRWSection (data)) {
629
+ AppLog (@" Something went wrong when writing a new writable region." );
630
+ return completionHandler (NO , @" Couldn't write new RW region." );
631
+ }
499
632
500
633
// === PATCH STEP 1 ====
501
634
struct segment_command_64 * textSeg = NULL ;
0 commit comments