1#include <mach-o/loader.h>
2#include <mach/machine.h>
3#include <stdlib.h>
4#include <string.h>
5#include <uuid/uuid.h>
6
7int main() {
8 int size_of_load_cmds =
9 sizeof(struct segment_command_64) + sizeof(struct uuid_command);
10 uint8_t *macho_buf =
11 (uint8_t *)malloc(sizeof(struct mach_header_64) + size_of_load_cmds);
12 uint8_t *p = macho_buf;
13 struct mach_header_64 mh;
14 mh.magic = MH_MAGIC_64;
15 mh.cputype = CPU_TYPE_ARM64;
16 mh.cpusubtype = 0;
17 mh.filetype = MH_EXECUTE;
18 mh.ncmds = 2;
19 mh.sizeofcmds = size_of_load_cmds;
20 mh.flags = MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL | MH_PIE;
21
22 memcpy(dest: p, src: &mh, n: sizeof(mh));
23 p += sizeof(mh);
24
25 struct segment_command_64 seg;
26 seg.cmd = LC_SEGMENT_64;
27 seg.cmdsize = sizeof(seg);
28 strcpy(dest: seg.segname, src: "__TEXT");
29 seg.vmaddr = 0x5000;
30 seg.vmsize = 0x1000;
31 seg.fileoff = 0;
32 seg.filesize = 0;
33 seg.maxprot = 0;
34 seg.initprot = 0;
35 seg.nsects = 0;
36 seg.flags = 0;
37
38 memcpy(dest: p, src: &seg, n: sizeof(seg));
39 p += sizeof(seg);
40
41 struct uuid_command uuid;
42 uuid.cmd = LC_UUID;
43 uuid.cmdsize = sizeof(uuid);
44 uuid_clear(uu: uuid.uuid);
45 uuid_parse(in: "1b4e28ba-2fa1-11d2-883f-b9a761bde3fb", uu: uuid.uuid);
46
47 memcpy(dest: p, src: &uuid, n: sizeof(uuid));
48 p += sizeof(uuid);
49
50 // If this needs to be debugged, the memory buffer can be written
51 // to a file with
52 // (lldb) mem rea -b -o /tmp/t -c `p - macho_buf` macho_buf
53 // (lldb) platform shell otool -hlv /tmp/t
54 // to verify that it is well formed.
55
56 // And inside lldb, it should be inspectable via
57 // (lldb) script print(lldb.frame.locals["macho_buf"][0].GetValueAsUnsigned())
58 // 105553162403968
59 // (lldb) process plugin packet send
60 // 'jGetLoadedDynamicLibrariesInfos:{"solib_addresses":[105553162403968]}]'
61
62 return 0; // break here
63}
64

source code of lldb/test/API/macosx/unregistered-macho/main.c