From b93e20cd9f268dfb3a98b57b4d73d9e449939da0 Mon Sep 17 00:00:00 2001 From: myzhan Date: Thu, 9 Nov 2023 13:59:11 +0800 Subject: [PATCH] try to write memory with mach_vm_protect on mac --- modify_binary_darwin.go | 37 +++++++++++------------- write_darwin_amd64.s | 64 +++++++++++++++++++++++++++++++++++++++++ write_darwin_arm64.s | 63 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 write_darwin_amd64.s create mode 100644 write_darwin_arm64.s diff --git a/modify_binary_darwin.go b/modify_binary_darwin.go index 4117bc6..478bbec 100644 --- a/modify_binary_darwin.go +++ b/modify_binary_darwin.go @@ -1,27 +1,24 @@ package gomonkey -import "syscall" +import ( + "fmt" + "reflect" + "syscall" + "unsafe" +) -func modifyBinary(target uintptr, bytes []byte) { - function := entryAddress(target, len(bytes)) - err := mprotectCrossPage(target, len(bytes), syscall.PROT_READ|syscall.PROT_WRITE) - if err != nil { - panic(err) - } - copy(function, bytes) - err = mprotectCrossPage(target, len(bytes), syscall.PROT_READ|syscall.PROT_EXEC) - if err != nil { - panic(err) - } +func PtrOf(val []byte) uintptr { + return (*reflect.SliceHeader)(unsafe.Pointer(&val)).Data } -func mprotectCrossPage(addr uintptr, length int, prot int) error { - pageSize := syscall.Getpagesize() - for p := pageStart(addr); p < addr+uintptr(length); p += uintptr(pageSize) { - page := entryAddress(p, pageSize) - if err := syscall.Mprotect(page, prot); err != nil { - return err - } +func modifyBinary(target uintptr, bytes []byte) { + targetPage := pageStart(target) + res := write(target, PtrOf(bytes), len(bytes), targetPage, syscall.Getpagesize(), syscall.PROT_READ|syscall.PROT_EXEC) + if res != 0 { + panic(fmt.Errorf("failed to write memory, code %v", res)) } - return nil } + +//go:cgo_import_dynamic mach_task_self mach_task_self "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic mach_vm_protect mach_vm_protect "/usr/lib/libSystem.B.dylib" +func write(target, data uintptr, len int, page uintptr, pageSize, oriProt int) int diff --git a/write_darwin_amd64.s b/write_darwin_amd64.s new file mode 100644 index 0000000..9b20a1f --- /dev/null +++ b/write_darwin_amd64.s @@ -0,0 +1,64 @@ +/* + * Copyright 2022 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "textflag.h" + +#define NOP8 BYTE $0x90; BYTE $0x90; BYTE $0x90; BYTE $0x90; BYTE $0x90; BYTE $0x90; BYTE $0x90; BYTE $0x90; +#define NOP64 NOP8; NOP8; NOP8; NOP8; NOP8; NOP8; NOP8; NOP8; +#define NOP512 NOP64; NOP64; NOP64; NOP64; NOP64; NOP64; NOP64; NOP64; +#define NOP4096 NOP512; NOP512; NOP512; NOP512; NOP512; NOP512; NOP512; NOP512; + +#define protRW $(0x1|0x2|0x10) +#define mProtect $(0x2000000+74) + +TEXT ·write(SB),NOSPLIT,$24 + JMP START + NOP4096 +START: + MOVQ mProtect, AX + MOVQ page+24(FP), DI + MOVQ pageSize+32(FP), SI + MOVQ protRW, DX + SYSCALL + CMPQ AX, $0 + JZ PROTECT_OK + CALL mach_task_self(SB) + MOVQ AX, DI + MOVQ target+0(FP), SI + MOVQ len+16(FP), DX + MOVQ $0, CX + MOVQ protRW, R8 + CALL mach_vm_protect(SB) + CMPQ AX, $0 + JNZ RETURN +PROTECT_OK: + MOVQ target+0(FP), DI + MOVQ data+8(FP), SI + MOVQ len+16(FP), CX + MOVQ DI, to-24(SP) + MOVQ SI, from-16(SP) + MOVQ CX, n-8(SP) + CALL runtime·memmove(SB) + MOVQ mProtect, AX + MOVQ page+24(FP), DI + MOVQ pageSize+32(FP), SI + MOVQ oriProt+40(FP), DX + SYSCALL + JMP RETURN + NOP4096 +RETURN: + MOVQ AX, ret+48(FP) + RET diff --git a/write_darwin_arm64.s b/write_darwin_arm64.s new file mode 100644 index 0000000..c6cd376 --- /dev/null +++ b/write_darwin_arm64.s @@ -0,0 +1,63 @@ +/* + * Copyright 2022 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "textflag.h" + +#define NOP64 WORD $0x1f2003d5; WORD $0x1f2003d5; +#define NOP512 NOP64; NOP64; NOP64; NOP64; NOP64; NOP64; NOP64; NOP64; +#define NOP4096 NOP512; NOP512; NOP512; NOP512; NOP512; NOP512; NOP512; NOP512; +#define NOP16384 NOP4096; NOP4096; NOP4096; NOP4096; NOP4096; NOP4096; NOP4096; NOP4096; + +#define protRW $(0x1|0x2|0x10) +#define mProtect $(0x2000000+74) + +TEXT ·write(SB),NOSPLIT,$24 + B START + NOP16384 +START: + MOVD mProtect, R16 + MOVD page+24(FP), R0 + MOVD pageSize+32(FP), R1 + MOVD protRW, R2 + SVC $0x80 + CMP $0, R0 + BEQ PROTECT_OK + CALL mach_task_self(SB) + MOVD target+0(FP), R1 + MOVD len+16(FP), R2 + MOVD $0, R3 + MOVD protRW, R4 + CALL mach_vm_protect(SB) + CMP $0, R0 + BNE RETURN +PROTECT_OK: + MOVD target+0(FP), R0 + MOVD data+8(FP), R1 + MOVD len+16(FP), R2 + MOVD R0, to-24(SP) + MOVD R1, from-16(SP) + MOVD R2, n-8(SP) + CALL runtime·memmove(SB) + MOVD mProtect, R16 + MOVD page+24(FP), R0 + MOVD pageSize+32(FP), R1 + MOVD oriProt+40(FP), R2 + SVC $0x80 + B RETURN + NOP16384 +RETURN: + MOVD R0, ret+48(FP) + RET