From 50f9f9e43349bd1a42109fb48af69d015a28eec3 Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Wed, 30 Dec 2020 22:57:40 +0100 Subject: [PATCH] Retrieving ASLR offset using mach_vm_region --- cmd/dlv/cmds/commands.go | 2 +- pkg/proc/bininfo.go | 9 +++++++++ pkg/proc/native/proc_darwin.c | 22 ++++++++++++++++++++++ pkg/proc/native/proc_darwin.go | 23 ++++++++++++++--------- pkg/proc/native/proc_darwin.h | 3 +++ 5 files changed, 49 insertions(+), 10 deletions(-) diff --git a/cmd/dlv/cmds/commands.go b/cmd/dlv/cmds/commands.go index 81ac869417..6fa7f656cc 100644 --- a/cmd/dlv/cmds/commands.go +++ b/cmd/dlv/cmds/commands.go @@ -134,7 +134,7 @@ func New(docCall bool) *cobra.Command { rootCommand.PersistentFlags().StringVar(&backend, "backend", "default", `Backend selection (see 'dlv help backend').`) rootCommand.PersistentFlags().StringArrayVarP(&redirects, "redirect", "r", []string{}, "Specifies redirect rules for target process (see 'dlv help redirect')") rootCommand.PersistentFlags().BoolVar(&allowNonTerminalInteractive, "allow-non-terminal-interactive", false, "Allows interactive sessions of Delve that don't have a terminal as stdin, stdout and stderr") - rootCommand.PersistentFlags().BoolVar(&disableASLR, "disable-aslr", false, "Disables address space randomization. This option is forced to true on darwin/arm64") + rootCommand.PersistentFlags().BoolVar(&disableASLR, "disable-aslr", false, "Disables address space randomization") // 'attach' subcommand. attachCommand := &cobra.Command{ diff --git a/pkg/proc/bininfo.go b/pkg/proc/bininfo.go index b22bb69ffa..b122c70080 100644 --- a/pkg/proc/bininfo.go +++ b/pkg/proc/bininfo.go @@ -1372,6 +1372,15 @@ func loadBinaryInfoMacho(bi *BinaryInfo, image *Image, path string, entryPoint u if err != nil { return err } + + if entryPoint != 0 { + // This is a little bit hacky. We use the entryPoint variable, but it + // actually holds the address of the mach-o header. We can use this + // to calculate the offset to the non-aslr location of the mach-o header + // (which is 0x100000000) + image.StaticBase = entryPoint - 0x100000000 + } + image.closer = exe if !supportedDarwinArch[exe.Cpu] { return &ErrUnsupportedArch{os: "darwin", cpuArch: exe.Cpu} diff --git a/pkg/proc/native/proc_darwin.c b/pkg/proc/native/proc_darwin.c index 15a598b8e5..75a3f13aaa 100644 --- a/pkg/proc/native/proc_darwin.c +++ b/pkg/proc/native/proc_darwin.c @@ -86,6 +86,28 @@ reset_exception_ports(task_t task, mach_port_t *exception_port, mach_port_t *not return KERN_SUCCESS; } +mach_vm_address_t +get_macho_header_offset(task_t task) { + kern_return_t kret; + mach_vm_address_t address; + mach_vm_size_t size; + vm_region_basic_info_data_64_t info; + mach_msg_type_number_t infoCnt = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t object_name; + + // start at 0x0 + address = 0x0; + + kret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, + (vm_region_info_64_t)&info, &infoCnt, &object_name); + // Return 0 if we cannot find the address, since we implicitly use this to denote + // that we do not have the entrypoint in bininfo + if (kret != KERN_SUCCESS) return 0; + + // address will then contain the start address of the section after __PAGEZERO, i.e. the mach-o header + return address; +} + char * find_executable(int pid) { static char pathbuf[PATH_MAX]; diff --git a/pkg/proc/native/proc_darwin.go b/pkg/proc/native/proc_darwin.go index b7aec6bf26..db825c9c91 100644 --- a/pkg/proc/native/proc_darwin.go +++ b/pkg/proc/native/proc_darwin.go @@ -14,7 +14,6 @@ import ( "os" "os/exec" "path/filepath" - "runtime" "unsafe" sys "golang.org/x/sys/unix" @@ -64,7 +63,7 @@ func Launch(cmd []string, wd string, flags proc.LaunchFlags, _ []string, _ strin argvSlice = append(argvSlice, nil) disableASLR := 0 - if flags&proc.LaunchDisableASLR != 0 || (runtime.GOOS == "darwin" && runtime.GOARCH == "arm64") { + if flags&proc.LaunchDisableASLR != 0 { disableASLR = 1 } @@ -119,12 +118,10 @@ func Launch(cmd []string, wd string, flags proc.LaunchFlags, _ []string, _ strin dbp.os.initialized = true - regs, err := dbp.memthread.Registers() - if err != nil { - return nil, err - } - - dbp.os.entryPoint = regs.PC() + // This is a bit hacky. This is technically not the entrypoint, + // but rather we use the variable to points at the mach-o header, + // so we can get the offset in bininfo + dbp.os.entryPoint = uint64(C.get_macho_header_offset(dbp.os.task)) tgt, err := dbp.initialize(argv0Go, []string{}) if err != nil { @@ -161,6 +158,12 @@ func Attach(pid int, _ []string) (*proc.Target, error) { return nil, err } + // TODO: Find out, if the target is actually using ASLR or not + // This is a bit hacky. This is technically not the entrypoint, + // but rather we use the variable to points at the mach-o header, + // so we can get the offset in bininfo + dbp.os.entryPoint = uint64(C.get_macho_header_offset(dbp.os.task)) + tgt, err := dbp.initialize(findExecutable("", dbp.pid), []string{}) if err != nil { dbp.Detach(false) @@ -478,4 +481,6 @@ func (dbp *nativeProcess) EntryPoint() (uint64, error) { return dbp.os.entryPoint, nil } -func initialize(dbp *nativeProcess) error { return nil } +func initialize(dbp *nativeProcess) error { + return nil +} diff --git a/pkg/proc/native/proc_darwin.h b/pkg/proc/native/proc_darwin.h index a686b5ae01..0870a00f5a 100644 --- a/pkg/proc/native/proc_darwin.h +++ b/pkg/proc/native/proc_darwin.h @@ -61,3 +61,6 @@ get_task_for_pid(int pid); int task_is_valid(task_t task); + +mach_vm_address_t +get_macho_header_offset(task_t task); \ No newline at end of file