From ef5abd92fdcf9337e512de1ec541ca310eaaea06 Mon Sep 17 00:00:00 2001 From: comex Date: Sun, 25 Jan 2015 21:09:10 -0500 Subject: this is dumb --- Makefile | 19 ++- generated/darwin-inject-asm.S | 10 +- lib/darwin/execmem.c | 4 +- lib/darwin/inject-asm-raw.c | 41 +++--- lib/darwin/inject.c | 285 ++++++++++++++++++++++++++++++++---------- lib/darwin/manual-syscall.h | 26 ++-- lib/substitute-internal.h | 19 ++- script/gen-inject-asm.sh | 2 +- test/test-inject.c | 22 +++- 9 files changed, 314 insertions(+), 114 deletions(-) diff --git a/Makefile b/Makefile index 9c70b0b..b528cca 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,17 @@ out/%.o: lib/%.S Makefile $(HEADERS) out/jump-dis.o: $(GENERATED_DIS_HEADERS) out/transform-dis.o: $(GENERATED_DIS_HEADERS) +# Note: the order of darwin-inject-asm.o is significant. Per man page, ld is +# guaranteed to link objects in order, which is necessary because +# darwin-inject-asm.S does not itself ensure there is at least 0x4000 bytes of +# executable stuff after inject_page_start (so that arm can remap into arm64). +# By putting it at the beginning, we can just reuse the space for the rest of +# the library rather than having to pad with zeroes. +# (This only matters on 32-bit ARM, and the text segment is currently 0xa000 +# bytes there, more than enough.) + LIB_OBJS := \ + out/darwin-inject-asm.o \ out/darwin/find-syms.o \ out/darwin/inject.o \ out/darwin/interpose.o \ @@ -61,7 +71,6 @@ LIB_OBJS := \ out/darwin/substrate-compat.o \ out/darwin/stop-other-threads.o \ out/darwin/execmem.o \ - out/darwin-inject-asm.o \ out/jump-dis.o \ out/transform-dis.o \ out/hook-functions.o \ @@ -75,7 +84,7 @@ out/libsubstitute.dylib: $(LIB_OBJS) # architectures or something - meh. # Did you know? With -Oz + -marm, Apple clang-600.0.56 actually generated # wrong code for the ARM version. It works with -Os and with newer clang. -IACLANG := clang -Os -dynamiclib -nostartfiles -nodefaultlibs -isysroot /dev/null -Ilib -fPIC +IACLANG := clang -Os -fno-stack-protector -dynamiclib -nostartfiles -nodefaultlibs -isysroot /dev/null -Ilib -fPIC out/inject-asm-raw-x86_64.o: lib/darwin/inject-asm-raw.c Makefile $(IACLANG) -arch x86_64 -o $@ $< out/inject-asm-raw-i386.o: lib/darwin/inject-asm-raw.c Makefile @@ -100,7 +109,7 @@ ifneq (,$(IS_IOS)) ldid -Sent.plist $$@ endif install_name_tool -change /usr/lib/libsubstitute.0.dylib '@executable_path/libsubstitute.dylib' $$@ -all: out/test-$(1) +tests: out/test-$(1) endef $(eval $(call define_test,tdarm-simple,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-arm.inc.h"' -Dxdis=dis_arm -DFORCE_TARGET_arm)) $(eval $(call define_test,tdthumb-simple,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-thumb.inc.h"' -Dxdis=dis_thumb -DFORCE_TARGET_arm)) @@ -123,6 +132,10 @@ $(eval $(call define_test,stop-threads,stop-threads,$(CC) -std=c11 out/darwin/st $(eval $(call define_test,execmem,execmem,$(CC) -std=c11 out/darwin/execmem.o -segprot __TEST rwx rx)) $(eval $(call define_test,hook-functions,hook-functions,$(CC) -std=c11 -lsubstitute)) +out/injected-test-dylib.dylib: test/injected-test-dylib.c Makefile + $(CC) -std=c11 -dynamiclib -o $@ $< +tests: out/injected-test-dylib.dylib + # These are just random sequences of instructions which you can compile to .bin # for testing. diff --git a/generated/darwin-inject-asm.S b/generated/darwin-inject-asm.S index abcb721..bf4914a 100644 --- a/generated/darwin-inject-asm.S +++ b/generated/darwin-inject-asm.S @@ -7,22 +7,22 @@ * disabled in case any future Rosetta-like emulator breaks naive attempts to * inject into foreign-architecture processes), but we need two architectures * anyway, so the rest are included in case doing so is useful someday. */ -.align 12 +.align 14 .globl _inject_page_start _inject_page_start: .align 2 .globl _inject_start_x86_64 _inject_start_x86_64: -.byte 0x55, 0x48, 0x89, 0xe5, 0x53, 0x50, 0x48, 0x89, 0xfb, 0x48, 0x8d, 0x15, 0x6a, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x7d, 0xf4, 0x31, 0xf6, 0x48, 0x89, 0xd9, 0xff, 0x13, 0x48, 0x83, 0x7b, 0x18, 0x00, 0x75, 0x27, 0x49, 0xc7, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xb8, 0x3e, 0x00, 0x00, 0x01, 0x31, 0xff, 0xbe, 0x01, 0x00, 0x00, 0x00, 0x31, 0xd2, 0xb9, 0x40, 0x1f, 0x00, 0x00, 0x41, 0x50, 0x0f, 0x05, 0x41, 0x58, 0x48, 0x83, 0x7b, 0x18, 0x00, 0x74, 0xe0, 0xb8, 0x69, 0x01, 0x00, 0x02, 0x31, 0xd2, 0x31, 0xc9, 0x48, 0x81, 0xe3, 0x00, 0xf0, 0xff, 0xff, 0x45, 0x31, 0xc0, 0xbe, 0x00, 0x20, 0x00, 0x00, 0x48, 0x89, 0xdf, 0x41, 0x50, 0x0f, 0x05, 0x41, 0x58, 0xb9, 0xad, 0x0b, 0x00, 0x00, 0x31, 0xc0, 0xff, 0xd1, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0x5d, 0xc3, 0x55, 0x48, 0x89, 0xe5, 0x53, 0x50, 0x48, 0x89, 0xfb, 0x48, 0x8b, 0x7b, 0x10, 0x31, 0xf6, 0xff, 0x53, 0x08, 0x48, 0xc7, 0x43, 0x18, 0x01, 0x00, 0x00, 0x00, 0x31, 0xc0, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0x5d, 0xc3 +.byte 0x55, 0x48, 0x89, 0xe5, 0x53, 0x50, 0x48, 0x89, 0xfb, 0x48, 0x8d, 0x15, 0x2c, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x7d, 0xf4, 0x31, 0xf6, 0x48, 0x89, 0xd9, 0xff, 0x13, 0x48, 0x8b, 0x4b, 0x28, 0xb8, 0x69, 0x01, 0x00, 0x02, 0x31, 0xff, 0x31, 0xf6, 0x31, 0xd2, 0x0f, 0x05, 0xb9, 0xad, 0x0b, 0x00, 0x00, 0x31, 0xc0, 0xff, 0xd1, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0x5d, 0xc3, 0x55, 0x48, 0x89, 0xe5, 0x53, 0x50, 0x48, 0x89, 0xfb, 0x48, 0x8b, 0x7b, 0x20, 0x31, 0xf6, 0xff, 0x53, 0x08, 0x48, 0x85, 0xc0, 0x74, 0x1c, 0x48, 0x8d, 0x35, 0x46, 0x00, 0x00, 0x00, 0x48, 0x89, 0xc7, 0xff, 0x53, 0x10, 0x48, 0x85, 0xc0, 0x74, 0x0a, 0x48, 0x8d, 0x7b, 0x38, 0x48, 0x8b, 0x73, 0x30, 0xff, 0xd0, 0xb8, 0x24, 0x00, 0x00, 0x01, 0x31, 0xd2, 0x31, 0xc9, 0x48, 0x8b, 0x7b, 0x28, 0x31, 0xf6, 0x0f, 0x05, 0x48, 0x8b, 0x43, 0x18, 0x48, 0x81, 0xe3, 0x00, 0xf0, 0xff, 0xff, 0xbe, 0x00, 0x20, 0x00, 0x00, 0x48, 0x89, 0xdf, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0x5d, 0xff, 0xe0, 0x0f, 0x1f, 0x44, 0x00, 0x00, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 .align 2 .globl _inject_start_i386 _inject_start_i386: -.byte 0x55, 0x89, 0xe5, 0x56, 0x83, 0xec, 0x24, 0x89, 0xce, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0x89, 0x74, 0x24, 0x0c, 0x8d, 0x80, 0x80, 0x00, 0x00, 0x00, 0x89, 0x44, 0x24, 0x08, 0x8d, 0x45, 0xf8, 0x89, 0x04, 0x24, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0x16, 0xeb, 0x21, 0xb8, 0xc2, 0xff, 0xff, 0xff, 0x89, 0xe1, 0x68, 0x40, 0x1f, 0x00, 0x00, 0x6a, 0x00, 0x6a, 0x01, 0x6a, 0x00, 0x50, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0xc2, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x34, 0x83, 0x7e, 0x0c, 0x00, 0x74, 0xd9, 0x81, 0xe6, 0x00, 0xf0, 0xff, 0xff, 0x89, 0x75, 0xf4, 0xb8, 0x69, 0x01, 0x00, 0x00, 0x89, 0xe1, 0x6a, 0x00, 0x6a, 0x00, 0x68, 0x00, 0x20, 0x00, 0x00, 0xff, 0x75, 0xf4, 0x50, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0xc2, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x34, 0xb8, 0xad, 0x0b, 0x00, 0x00, 0xff, 0xd0, 0x83, 0xc4, 0x24, 0x5e, 0x5d, 0xc3, 0x55, 0x89, 0xe5, 0x56, 0x83, 0xec, 0x14, 0x8b, 0x75, 0x08, 0x8b, 0x46, 0x08, 0x89, 0x04, 0x24, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0x56, 0x04, 0xc7, 0x46, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x31, 0xc0, 0x83, 0xc4, 0x14, 0x5e, 0x5d, 0xc3 +.byte 0x55, 0x89, 0xe5, 0x56, 0x83, 0xec, 0x24, 0x89, 0xce, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0x89, 0x74, 0x24, 0x0c, 0x8d, 0x80, 0x55, 0x00, 0x00, 0x00, 0x89, 0x44, 0x24, 0x08, 0x8d, 0x45, 0xf8, 0x89, 0x04, 0x24, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0x16, 0x8b, 0x46, 0x14, 0x89, 0x45, 0xf4, 0xb8, 0x69, 0x01, 0x00, 0x00, 0xff, 0x75, 0xf4, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x89, 0xe1, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0xc2, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x34, 0x83, 0xc4, 0x14, 0xb8, 0xad, 0x0b, 0x00, 0x00, 0xff, 0xd0, 0x83, 0xc4, 0x24, 0x5e, 0x5d, 0xc3, 0x55, 0x89, 0xe5, 0x57, 0x56, 0x83, 0xec, 0x10, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x8b, 0x75, 0x08, 0x8b, 0x46, 0x10, 0x89, 0x04, 0x24, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0x56, 0x04, 0x85, 0xc0, 0x74, 0x23, 0x8d, 0x8f, 0x81, 0x00, 0x00, 0x00, 0x89, 0x4c, 0x24, 0x04, 0x89, 0x04, 0x24, 0xff, 0x56, 0x08, 0x85, 0xc0, 0x74, 0x0f, 0x8d, 0x4e, 0x1c, 0x8b, 0x56, 0x18, 0x89, 0x54, 0x24, 0x04, 0x89, 0x0c, 0x24, 0xff, 0xd0, 0x8b, 0x46, 0x14, 0x89, 0x45, 0xf4, 0xb8, 0xdc, 0xff, 0xff, 0xff, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0xff, 0x75, 0xf4, 0x6a, 0x00, 0x89, 0xe1, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0xc2, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x34, 0x83, 0xc4, 0x14, 0x89, 0xf0, 0x25, 0x00, 0xf0, 0xff, 0xff, 0x89, 0x04, 0x24, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x20, 0x00, 0x00, 0xff, 0x56, 0x0c, 0x83, 0xc4, 0x10, 0x5e, 0x5f, 0x5d, 0xc3, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 .align 2 .globl _inject_start_arm _inject_start_arm: -.byte 0xf0, 0x40, 0x2d, 0xe9, 0x0c, 0x70, 0x8d, 0xe2, 0x04, 0xd0, 0x4d, 0xe2, 0x00, 0x40, 0xa0, 0xe1, 0x0d, 0x00, 0xa0, 0xe1, 0x00, 0x50, 0x94, 0xe5, 0x78, 0x20, 0x00, 0xe3, 0x00, 0x20, 0x40, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x02, 0x20, 0x8f, 0xe0, 0x04, 0x30, 0xa0, 0xe1, 0x00, 0x60, 0xa0, 0xe3, 0x35, 0xff, 0x2f, 0xe1, 0x0c, 0x00, 0x94, 0xe5, 0x00, 0x00, 0x50, 0xe3, 0x0b, 0x00, 0x00, 0x1a, 0x00, 0x50, 0xe0, 0xe3, 0x3d, 0xc0, 0xe0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x20, 0xa0, 0xe3, 0x7d, 0x3d, 0xa0, 0xe3, 0x00, 0x00, 0xa0, 0xe3, 0x04, 0x50, 0x2d, 0xe5, 0x80, 0x00, 0x00, 0xef, 0x04, 0x50, 0x9d, 0xe4, 0x0c, 0x00, 0x94, 0xe5, 0x00, 0x00, 0x50, 0xe3, 0xf8, 0xff, 0xff, 0x0a, 0x1f, 0x40, 0xcb, 0xe7, 0x69, 0xc1, 0x00, 0xe3, 0x02, 0x1a, 0xa0, 0xe3, 0x00, 0x20, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x30, 0xa0, 0xe3, 0x04, 0x60, 0x2d, 0xe5, 0x80, 0x00, 0x00, 0xef, 0x04, 0x60, 0x9d, 0xe4, 0xad, 0x0b, 0x00, 0xe3, 0x30, 0xff, 0x2f, 0xe1, 0x0c, 0xd0, 0x47, 0xe2, 0xf0, 0x80, 0xbd, 0xe8, 0x90, 0x40, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0xd4, 0x20, 0xc4, 0xe1, 0x04, 0x70, 0x8d, 0xe2, 0x03, 0x00, 0xa0, 0xe1, 0x32, 0xff, 0x2f, 0xe1, 0x01, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x84, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x90, 0x80, 0xbd, 0xe8 +.byte 0x90, 0x40, 0x2d, 0xe9, 0x04, 0x70, 0x8d, 0xe2, 0x04, 0xd0, 0x4d, 0xe2, 0x00, 0x40, 0xa0, 0xe1, 0x0d, 0x00, 0xa0, 0xe1, 0x00, 0x90, 0x94, 0xe5, 0x2c, 0x20, 0x00, 0xe3, 0x00, 0x20, 0x40, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x02, 0x20, 0x8f, 0xe0, 0x04, 0x30, 0xa0, 0xe1, 0x39, 0xff, 0x2f, 0xe1, 0x14, 0x30, 0x94, 0xe5, 0x69, 0xc1, 0x00, 0xe3, 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x20, 0xa0, 0xe3, 0x80, 0x00, 0x00, 0xef, 0xad, 0x0b, 0x00, 0xe3, 0x30, 0xff, 0x2f, 0xe1, 0x04, 0xd0, 0x47, 0xe2, 0x90, 0x80, 0xbd, 0xe8, 0x90, 0x40, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0x04, 0x20, 0x94, 0xe5, 0x04, 0x70, 0x8d, 0xe2, 0x10, 0x00, 0x94, 0xe5, 0x32, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x50, 0xe3, 0x0a, 0x00, 0x00, 0x0a, 0x08, 0x20, 0x94, 0xe5, 0x48, 0x10, 0x00, 0xe3, 0x00, 0x10, 0x40, 0xe3, 0x01, 0x10, 0x8f, 0xe0, 0x32, 0xff, 0x2f, 0xe1, 0x00, 0x20, 0xa0, 0xe1, 0x00, 0x00, 0x52, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x18, 0x10, 0x94, 0xe5, 0x1c, 0x00, 0x84, 0xe2, 0x32, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x94, 0xe5, 0x23, 0xc0, 0xe0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x20, 0xa0, 0xe3, 0x00, 0x30, 0xa0, 0xe3, 0x80, 0x00, 0x00, 0xef, 0x0c, 0x20, 0x94, 0xe5, 0x1f, 0x40, 0xcb, 0xe7, 0x02, 0x1a, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0x90, 0x40, 0xbd, 0xe8, 0x12, 0xff, 0x2f, 0xe1, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 .align 2 .globl _inject_start_arm64 _inject_start_arm64: -.byte 0xf4, 0x4f, 0xbe, 0xa9, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91, 0xff, 0x43, 0x00, 0xd1, 0xf3, 0x03, 0x00, 0xaa, 0x68, 0x02, 0x40, 0xf9, 0x01, 0x00, 0x80, 0xd2, 0x02, 0x04, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0xe0, 0x33, 0x00, 0x91, 0xe3, 0x03, 0x13, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0x68, 0x0e, 0x40, 0xf9, 0x88, 0x01, 0x00, 0xb5, 0x08, 0x00, 0x80, 0x92, 0xb0, 0x07, 0x80, 0x92, 0xe1, 0x03, 0x40, 0xb2, 0x03, 0xe8, 0x83, 0xd2, 0x02, 0x00, 0x80, 0xd2, 0x00, 0x00, 0x80, 0xd2, 0xe8, 0x0f, 0x1f, 0xf8, 0x01, 0x10, 0x00, 0xd4, 0xe8, 0x07, 0x41, 0xf8, 0x69, 0x0e, 0x40, 0xf9, 0x69, 0xff, 0xff, 0xb4, 0x02, 0x00, 0x80, 0xd2, 0x60, 0xc6, 0x72, 0x92, 0x30, 0x2d, 0x80, 0xd2, 0xe1, 0x03, 0x73, 0xb2, 0xe3, 0x03, 0x02, 0xaa, 0xe2, 0x0f, 0x1f, 0xf8, 0x01, 0x10, 0x00, 0xd4, 0xe2, 0x07, 0x41, 0xf8, 0xa8, 0x75, 0x81, 0xd2, 0x00, 0x01, 0x3f, 0xd6, 0xbf, 0x43, 0x00, 0xd1, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0xf4, 0x4f, 0xbe, 0xa9, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91, 0xf3, 0x03, 0x00, 0xaa, 0x68, 0x82, 0x40, 0xa9, 0x01, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0xe8, 0x03, 0x40, 0xb2, 0x68, 0x0e, 0x00, 0xf9, 0x00, 0x00, 0x80, 0xd2, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8, 0xc0, 0x03, 0x5f, 0xd6 +.byte 0xf4, 0x4f, 0xbe, 0xa9, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91, 0xff, 0x43, 0x00, 0xd1, 0xf3, 0x03, 0x00, 0xaa, 0x68, 0x02, 0x40, 0xf9, 0x01, 0x00, 0x80, 0xd2, 0x22, 0x02, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0xe0, 0x33, 0x00, 0x91, 0xe3, 0x03, 0x13, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0x63, 0x16, 0x40, 0xf9, 0x30, 0x2d, 0x80, 0xd2, 0x00, 0x00, 0x80, 0xd2, 0x01, 0x00, 0x80, 0xd2, 0x02, 0x00, 0x80, 0xd2, 0x01, 0x10, 0x00, 0xd4, 0xa8, 0x75, 0x81, 0xd2, 0x00, 0x01, 0x3f, 0xd6, 0xbf, 0x43, 0x00, 0xd1, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0xf4, 0x4f, 0xbe, 0xa9, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91, 0xf3, 0x03, 0x00, 0xaa, 0x68, 0x06, 0x40, 0xf9, 0x60, 0x12, 0x40, 0xf9, 0x01, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x40, 0x01, 0x00, 0xb4, 0x68, 0x0a, 0x40, 0xf9, 0x81, 0x02, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0x00, 0x01, 0x3f, 0xd6, 0xe8, 0x03, 0x00, 0xaa, 0x88, 0x00, 0x00, 0xb4, 0x60, 0xe2, 0x00, 0x91, 0x61, 0x1a, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0x01, 0x00, 0x80, 0xd2, 0x02, 0x00, 0x80, 0xd2, 0x03, 0x00, 0x80, 0xd2, 0x60, 0x16, 0x40, 0xf9, 0x70, 0x04, 0x80, 0x92, 0x01, 0x10, 0x00, 0xd4, 0x60, 0xc6, 0x72, 0x92, 0x62, 0x0e, 0x40, 0xf9, 0xe1, 0x03, 0x73, 0xb2, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8, 0x40, 0x00, 0x1f, 0xd6, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 diff --git a/lib/darwin/execmem.c b/lib/darwin/execmem.c index 22c1c2e..76f0643 100644 --- a/lib/darwin/execmem.c +++ b/lib/darwin/execmem.c @@ -34,7 +34,7 @@ int execmem_write(void *dest, const void *src, size_t len) { * (Obviously, it will still break if the user targets some libsubstitute * function within the same page as this one, though.) */ int ret = manual_syscall(SYS_mprotect, lopage, hipage - lopage, - PROT_READ | PROT_WRITE, 0, 0); + PROT_READ | PROT_WRITE, 0); if (ret) { errno = ret; return SUBSTITUTE_ERR_VM; @@ -48,7 +48,7 @@ int execmem_write(void *dest, const void *src, size_t len) { int oldprot = info.protection & (PROT_READ | PROT_WRITE | PROT_EXEC); ret = manual_syscall(SYS_mprotect, lopage, hipage - lopage, - oldprot, 0, 0); + oldprot, 0); if (ret) { errno = ret; return SUBSTITUTE_ERR_VM; diff --git a/lib/darwin/inject-asm-raw.c b/lib/darwin/inject-asm-raw.c index 3b0f1ce..9b272e7 100644 --- a/lib/darwin/inject-asm-raw.c +++ b/lib/darwin/inject-asm-raw.c @@ -8,32 +8,37 @@ struct baton { int (*pthread_create)(int *, void *, void *(*)(void *), void *); - void (*dlopen)(const char *, int); + void *(*dlopen)(const char *, int); + void *(*dlsym)(void *, const char *); + int (*munmap)(void *, long); const char *path; - long done; + /* bsd_thread_func uses this to wait for entry to go away */ + long sem_port; + long nshuttle; + char shuttle[0]; }; -struct baton2 { - void (*dlopen)(const char *, int); - const char *path; - int port; -}; -static void *bsd_thread_func(void *); +static int bsd_thread_func(void *); #if defined(__i386__) __attribute__((fastcall)) #endif -/* xxx need to change this to have host allocate two pages - way easier */ void entry(struct baton *baton) { int pt; - baton->pthread_create(&pt, 0, bsd_thread_func, baton); - unsigned long ptr = (unsigned long) baton & ~(_PAGE_SIZE - 1); - while (!baton->done) - manual_syscall(-62 /*clock_sleep_trap */, 0, 1, 0, 8000 /*ns*/, -1); - manual_syscall(361 /*bsdthread_terminate*/, ptr, 0x2000, 0, 0, 0); + baton->pthread_create(&pt, 0, (void *) bsd_thread_func, baton); + manual_syscall(361 /* bsdthread_terminate */, 0, 0, 0, baton->sem_port); ((void (*)()) 0xbad)(); } -static void *bsd_thread_func(void *arg) { +static int bsd_thread_func(void *arg) { struct baton *baton = arg; - baton->dlopen(baton->path, 0); - baton->done = 1; - return 0; + void *r = baton->dlopen(baton->path, 0); + if (r) { + __attribute__((section("__TEXT,__text"))) + static char name[] = "substitute_init"; + void (*init)(void *, unsigned long) = baton->dlsym(r, name); + if (init) + init(baton->shuttle, baton->nshuttle); + + } + manual_syscall(-36 /* semaphore_wait_trap */, baton->sem_port, 0, 0, 0); + unsigned long ptr = (unsigned long) baton & ~(_PAGE_SIZE - 1); + return baton->munmap((void *) ptr, 0x2000); } diff --git a/lib/darwin/inject.c b/lib/darwin/inject.c index a515ada..4e715d5 100644 --- a/lib/darwin/inject.c +++ b/lib/darwin/inject.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -57,10 +58,14 @@ struct dyld_all_image_infos_64 { #define FFI_SHORT_CIRCUIT -1 -static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t *libpthread_p, char **error) { - *libdyld_p = 0; - *libpthread_p = 0; +struct foreign_image { + const char *name; + uint64_t address; +}; +static int find_foreign_images(mach_port_t task, + struct foreign_image *images, size_t nimages, + char **error) { struct task_dyld_info tdi; mach_msg_type_number_t cnt = TASK_DYLD_INFO_COUNT; @@ -139,6 +144,7 @@ static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t * /* yay, slow file path reads! */ void *info_array_ptr = info_array; + size_t images_left = nimages; for (uint32_t i = 0; i < info_array_count; i++) { uint64_t load_address; uint64_t file_path; @@ -160,7 +166,7 @@ static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t * kr = mach_vm_read_overwrite(task, file_path, toread, (mach_vm_address_t) path_buf, &size); if (kr) { - printf("kr=%d <%p %p>\n", kr, (void *) file_path, path_buf); + /* printf("kr=%d <%p %p>\n", kr, (void *) file_path, path_buf); */ continue; } if (strlen(path_buf) == toread && toread < MAXPATHLEN) { @@ -173,14 +179,15 @@ static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t * path_buf[MAXPATHLEN] = '\0'; } - if (!strcmp(path_buf, "/usr/lib/system/libdyld.dylib")) - *libdyld_p = load_address; - else if (!strcmp(path_buf, "/usr/lib/system/libsystem_pthread.dylib")) - *libpthread_p = load_address; - - if (*libdyld_p && *libpthread_p) { - free(info_array); - return SUBSTITUTE_OK; + for (size_t i = 0; i < nimages; i++) { + if (!images[i].address && + !strcmp(path_buf, images[i].name)) { + images[i].address = load_address; + if (--images_left == 0) { + free(info_array); + return SUBSTITUTE_OK; + } + } } info_array_ptr += info_array_elm_size; @@ -380,26 +387,170 @@ got_symbol:; return true; } -int substitute_dlopen_in_pid(int pid, const char *filename, int options, char **error) { +static int do_baton(const char *filename, size_t filelen, bool is64, + mach_vm_address_t target_stackpage_end, + mach_vm_address_t *target_stack_top_p, + uint64_t sym_addrs[static 4], + const struct shuttle *shuttle, size_t nshuttle, + struct shuttle **target_shuttle_p, + semaphore_t *sem_port_p, + mach_port_t task, + char **error) { + int ret; + + size_t baton_len = 7 * (is64 ? 8 : 4); + size_t shuttles_len = nshuttle * sizeof(struct shuttle); + size_t filelen_rounded = (filelen + 7) & ~7; + size_t total_len = baton_len + shuttles_len + filelen_rounded; + mach_vm_address_t target_stack_top = target_stackpage_end - total_len; + *target_stack_top_p = target_stack_top; + char *stackbuf = calloc(total_len, 1); + if (!stackbuf) { + asprintf(error, "out of memory allocating stackbuf"); + ret = SUBSTITUTE_ERR_OOM; + goto fail; + } + strcpy(stackbuf + baton_len + shuttles_len, filename); + + struct shuttle *target_shuttle = calloc(nshuttle, sizeof(*target_shuttle)); + *target_shuttle_p = target_shuttle; + for (size_t i = 0; i < nshuttle; i++) { + const struct shuttle *in = &shuttle[i]; + struct shuttle *out = &target_shuttle[i]; + out->type = in->type; + switch (in->type) { + case SUBSTITUTE_SHUTTLE_MACH_PORT: + out->u.mach.right_type = in->u.mach.right_type; + while (1) { + mach_port_name_t name; + kern_return_t kr = mach_port_allocate(task, + MACH_PORT_RIGHT_DEAD_NAME, + &name); + if (kr) { + asprintf(error, "mach_port_allocate(temp dead name): kr=%d", + kr); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + kr = mach_port_deallocate(task, name); + if (kr) { + asprintf(error, "mach_port_deallocate(temp dead name): kr=%d", + kr); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + kr = mach_port_insert_right(task, name, in->u.mach.port, + in->u.mach.right_type); + if (kr == KERN_NAME_EXISTS) { + /* between the deallocate and the insert, someone must have + * grabbed this name - just try again */ + continue; + } else if (kr) { + asprintf(error, "mach_port_insert_right(shuttle %zu): kr=%d", + i, kr); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + + /* ok */ + out->u.mach.port = name; + break; + } + break; + default: + asprintf(error, "bad shuttle type %d", in->type); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + } + + memcpy(stackbuf + baton_len, target_shuttle, nshuttle * sizeof(*target_shuttle)); + + semaphore_t sem_port = MACH_PORT_NULL; + kern_return_t kr = semaphore_create(task, &sem_port, SYNC_POLICY_FIFO, 0); + if (kr) { + asprintf(error, "semaphore_create: kr=%d", kr); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + *sem_port_p = sem_port; + + uint64_t baton_vals[] = { + sym_addrs[0], + sym_addrs[1], + sym_addrs[2], + sym_addrs[3], + target_stack_top + baton_len + shuttles_len, + sem_port, + nshuttle + }; + + if (is64) { + uint64_t *p = (void *) stackbuf; + for (size_t i = 0; i < sizeof(baton_vals)/sizeof(*baton_vals); i++) + p[i] = baton_vals[i]; + } else { + uint32_t *p = (void *) stackbuf; + for (size_t i = 0; i < sizeof(baton_vals)/sizeof(*baton_vals); i++) + p[i] = (uint32_t) baton_vals[i]; + } + + kr = mach_vm_write(task, target_stack_top, + (mach_vm_address_t) stackbuf, total_len); + if (kr) { + asprintf(error, "mach_vm_write(stack data): kr=%d", kr); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + + ret = SUBSTITUTE_OK; + +fail: + free(stackbuf); + return ret; +} + +int substitute_dlopen_in_pid(int pid, const char *filename, int options, + const struct shuttle *shuttle, size_t nshuttle, + char **error) { + if (nshuttle > 10) { + asprintf(error, "nshuttle too high"); + return SUBSTITUTE_ERR_MISC; + } + size_t filelen = strlen(filename); + if (filelen >= 0x400) { + asprintf(error, "you gave me a terrible filename (%s)", filename); + return SUBSTITUTE_ERR_MISC; + } + mach_port_t task; mach_vm_address_t target_stack = 0; + struct shuttle *target_shuttle = NULL; + semaphore_t sem_port = MACH_PORT_NULL; + int ret; *error = NULL; + kern_return_t kr = task_for_pid(mach_task_self(), pid, &task); - int ret; if (kr) { asprintf(error, "task_for_pid: kr=%d", kr); return SUBSTITUTE_ERR_TASK_FOR_PID; } - uint64_t libdyld_addr, libpthread_addr; - if ((ret = find_foreign_images(task, &libdyld_addr, &libpthread_addr, error)) > 0) + struct foreign_image images[] = { + {"/usr/lib/system/libdyld.dylib", 0}, + {"/usr/lib/system/libsystem_pthread.dylib", 0}, + {"/usr/lib/system/libsystem_kernel.dylib", 0} + }; + if ((ret = find_foreign_images(task, images, 3, error)) > 0) goto fail; - uint64_t dlopen_addr, pthread_create_addr; + uint64_t pthread_create_addr, dlopen_addr, dlsym_addr, munmap_addr; cpu_type_t cputype; if (ret == FFI_SHORT_CIRCUIT) { - dlopen_addr = (uint64_t) dlopen; pthread_create_addr = (uint64_t) pthread_create; + dlopen_addr = (uint64_t) dlopen; + dlsym_addr = (uint64_t) dlsym; + munmap_addr = (uint64_t) munmap; #if defined(__x86_64__) cputype = CPU_TYPE_X86_64; #elif defined(__i386__) @@ -412,14 +563,18 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options, char ** } else { struct { uint64_t addr; - const char *symname; - uint64_t symaddr; - } libs[2] = { - {libdyld_addr, "_dlopen", 0}, - {libpthread_addr, "_pthread_create", 0} + int nsyms; + struct { + const char *symname; + uint64_t symaddr; + } syms[2]; + } libs[3] = { + {images[0].address, 2, {{"_dlopen", 0}, {"_dlsym", 0}}}, + {images[1].address, 1, {{"_pthread_create", 0}}}, + {images[2].address, 1, {{"_munmap", 0}}}, }; - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 3; i++) { void *linkedit, *export; size_t linkedit_size, export_size; if ((ret = get_foreign_image_export(task, libs[i].addr, @@ -427,18 +582,26 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options, char ** &export, &export_size, &cputype, error))) goto fail; - bool fesr = find_export_symbol(export, export_size, libs[i].symname, - libs[i].addr, &libs[i].symaddr); + const char *failed_symbol = NULL; + for (int j = 0; j < libs[i].nsyms; j++) { + if (!find_export_symbol(export, export_size, libs[i].syms[j].symname, + libs[i].addr, &libs[i].syms[j].symaddr)) { + failed_symbol = libs[i].syms[j].symname; + break; + } + } + vm_deallocate(mach_task_self(), (vm_offset_t) linkedit, (vm_size_t) linkedit_size); - if (!fesr) { - asprintf(error, "couldn't find _dlopen in libdyld"); + if (failed_symbol) { + asprintf(error, "couldn't find target symbol %s", failed_symbol); ret = SUBSTITUTE_ERR_MISC; goto fail; } } - dlopen_addr = libs[0].symaddr; - pthread_create_addr = libs[1].symaddr; + dlopen_addr = libs[0].syms[0].symaddr; + dlsym_addr = libs[0].syms[1].symaddr; + pthread_create_addr = libs[1].syms[0].symaddr; } UNUSED @@ -469,45 +632,13 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options, char ** goto fail; } - size_t filelen = strlen(filename); - if (filelen >= 0x400) { - asprintf(error, "you gave me a terrible filename (%s)", filename); - ret = SUBSTITUTE_ERR_MISC; - goto fail; - } - size_t filelen_rounded = (filelen + 7) & ~7; - - size_t baton_len = (cputype & CPU_ARCH_ABI64) ? 32 : 16; - mach_vm_address_t target_stack_top = target_stack + target_page_size - - baton_len - filelen_rounded; - char *stackbuf = calloc(baton_len + filelen_rounded, 1); - if (!stackbuf) { - ret = SUBSTITUTE_ERR_OOM; + uint64_t sym_addrs[] = {pthread_create_addr, dlopen_addr, dlsym_addr, munmap_addr}; + mach_vm_address_t target_stack_top; + if ((ret = do_baton(filename, filelen, cputype & CPU_ARCH_ABI64, + target_code_page, &target_stack_top, + sym_addrs, shuttle, nshuttle, &target_shuttle, &sem_port, + task, error))) goto fail; - } - strcpy(stackbuf + baton_len, filename); - - uint64_t vals[3] = {pthread_create_addr, dlopen_addr, target_stack_top + baton_len}; - if (cputype & CPU_ARCH_ABI64) { - uint64_t *p = (void *) stackbuf; - p[0] = vals[0]; - p[1] = vals[1]; - p[2] = vals[2]; - } else { - uint32_t *p = (void *) stackbuf; - p[0] = (uint32_t) vals[0]; - p[1] = (uint32_t) vals[1]; - p[2] = (uint32_t) vals[2]; - } - - kr = mach_vm_write(task, target_stack_top, - (mach_vm_address_t) stackbuf, baton_len + filelen_rounded); - free(stackbuf); - if (kr) { - asprintf(error, "mach_vm_write(stack data): kr=%d", kr); - ret = SUBSTITUTE_ERR_MISC; - goto fail; - } union { struct _x86_thread_state_32 x32; @@ -558,7 +689,7 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options, char ** goto fail; } - mach_port_t thread; + mach_port_t thread = MACH_PORT_NULL; kr = thread_create_running(task, flavor, (thread_state_t) &u, state_size / sizeof(int), &thread); if (kr) { @@ -578,6 +709,22 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options, char ** fail: if (target_stack) mach_vm_deallocate(task, target_stack, 2 * target_page_size); + if (target_shuttle) { + if (ret) { + for (size_t i = 0; i < nshuttle; i++) { + const struct shuttle *out = &target_shuttle[i]; + switch (out->type) { + case SUBSTITUTE_SHUTTLE_MACH_PORT: + if (out->u.mach.port) + mach_port_deallocate(task, out->u.mach.port); + break; + } + } + } + free(target_shuttle); + } + if (sem_port && ret) + mach_port_deallocate(task, sem_port); mach_port_deallocate(mach_task_self(), task); return ret; } diff --git a/lib/darwin/manual-syscall.h b/lib/darwin/manual-syscall.h index 4d847ac..9f04d2b 100644 --- a/lib/darwin/manual-syscall.h +++ b/lib/darwin/manual-syscall.h @@ -5,48 +5,48 @@ __attribute__((always_inline)) #if defined(__x86_64__) -static int manual_syscall(long s, long a, long b, long c, long d, long e) { +static int manual_syscall(long s, long a, long b, long c, long d) { if (s < 0) s = -s | 1 << 24; else s |= 2 << 24; REG(s, rax); REG(a, rdi); REG(b, rsi); REG(c, rdx); REG(d, rcx); OREG(out, rax); - __asm__ volatile("push %1; syscall; pop %1" + __asm__ volatile("syscall" : "=r"(out) - : "r"(e), "r"(_s), "r"(_a), "r"(_b), "r"(_c), "r"(_d)); + : "r"(_s), "r"(_a), "r"(_b), "r"(_c), "r"(_d)); return out; } #elif defined(__i386__) -static int manual_syscall(long s, long a, long b, long c, long d, long e) { +static int manual_syscall(long s, long a, long b, long c, long d) { REG(s, eax); OREG(out, eax); - __asm__ volatile("push %6; push %5; push %4; push %3; push %2; push $0;" + __asm__ volatile("push %5; push %4; push %3; push %2; push $0;" "mov %%esp, %%ecx;" "call 1f; 1: pop %%edx; add $(2f-1b), %%edx;" "sysenter;" - "2: add $(6 * 4), %%esp" + "2: add $(5 * 4), %%esp" : "=r"(out) - : "r"(_s), "g"(a), "g"(b), "g"(c), "g"(d), "g"(e) + : "r"(_s), "g"(a), "g"(b), "g"(c), "g"(d) : "edx", "ecx"); return out; } #elif defined(__arm__) -static int manual_syscall(long s, long a, long b, long c, long d, long e) { +static int manual_syscall(long s, long a, long b, long c, long d) { REG(s, r12); REG(a, r0); REG(b, r1); REG(c, r2); REG(d, r3); OREG(out, r0); - __asm__ volatile("push {%1}; svc #0x80; pop {%1}" + __asm__ volatile("svc #0x80" : "=r"(out) - : "r"(e), "r"(_s), "r"(_a), "r"(_b), "r"(_c), "r"(_d)); + : "r"(_s), "r"(_a), "r"(_b), "r"(_c), "r"(_d)); return out; } #elif defined(__arm64__) -static int manual_syscall(long s, long a, long b, long c, long d, long e) { +static int manual_syscall(long s, long a, long b, long c, long d) { REG(s, x16); REG(a, x0); REG(b, x1); REG(c, x2); REG(d, x3); OREG(out, x0); - __asm__ volatile("str %1, [sp, #-0x10]!\n svc #0x80\n ldr %1, [sp], #0x10" + __asm__ volatile("svc #0x80" : "=r"(out) - : "r"(e), "r"(_s), "r"(_a), "r"(_b), "r"(_c), "r"(_d)); + : "r"(_s), "r"(_a), "r"(_b), "r"(_c), "r"(_d)); return out; } #else diff --git a/lib/substitute-internal.h b/lib/substitute-internal.h index 0bfff95..3fd35bc 100644 --- a/lib/substitute-internal.h +++ b/lib/substitute-internal.h @@ -67,5 +67,22 @@ enum { SUBSTITUTE_ERR_MISC, }; -int substitute_dlopen_in_pid(int pid, const char *filename, int options, char **error); +enum shuttle_type { + SUBSTITUTE_SHUTTLE_MACH_PORT, + /* ... */ +}; + +struct shuttle { + int type; + union { + struct { + mach_port_t port; + mach_msg_type_name_t right_type; + } mach; + } u; +}; + +int substitute_dlopen_in_pid(int pid, const char *filename, int options, + const struct shuttle *shuttle, size_t nshuttle, + char **error); #endif diff --git a/script/gen-inject-asm.sh b/script/gen-inject-asm.sh index eacbbad..a4dfc5b 100755 --- a/script/gen-inject-asm.sh +++ b/script/gen-inject-asm.sh @@ -9,7 +9,7 @@ cat < #include #include +#include int main(int argc, char **argv) { if (argc <= 2) { @@ -11,7 +12,24 @@ int main(int argc, char **argv) { return 1; } int pid = atoi(argv[1]); - char *error = NULL; - int ret = substitute_dlopen_in_pid(pid, argv[2], 0, &error); + char *error; + mach_port_t port = 0; + assert(!mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)); + struct shuttle shuttles[] = { + {.type = SUBSTITUTE_SHUTTLE_MACH_PORT, + .u.mach.port = port, + .u.mach.right_type = MACH_MSG_TYPE_MAKE_SEND} + }; + int ret = substitute_dlopen_in_pid(pid, argv[2], 0, shuttles, 1, &error); printf("ret=%d err=%s\n", ret, error); + assert(!ret); + free(error); + static struct { + mach_msg_header_t hdr; + char body[5]; + } msg; + assert(!mach_msg_overwrite(NULL, MACH_RCV_MSG, 0, sizeof(msg), port, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, &msg.hdr, 0)); + printf("received '%.5s'\n", msg.body); + } -- cgit v1.2.3