package inject /* #cgo CFLAGS: -I include #cgo amd64 LDFLAGS: ${SRCDIR}/lib/libhotpatch_amd64.a #cgo arm64 LDFLAGS: ${SRCDIR}/lib/libhotpatch_arm64.a #include "hotpatch.h" #include */ import "C" import ( "bufio" "bytes" "fmt" "github.com/coroot/coroot-node-agent/utils" klog "github.com/sirupsen/logrus" "os" "path/filepath" "strconv" "strings" "syscall" "golang.org/x/arch/arm64/arm64asm" "golang.org/x/arch/x86/x86asm" //"time" "unsafe" ) var jumpOps = map[arm64asm.Op]bool{ arm64asm.CBZ: true, arm64asm.CBNZ: true, arm64asm.B: true, arm64asm.TBZ: true, arm64asm.TBNZ: true, arm64asm.ADRP: true, arm64asm.BL: true, arm64asm.BLR: true, arm64asm.RET: true, arm64asm.BR: true, } const NOP_ENC = 0xd503201f const RET_ENC = 0xd65f03c0 var nopBytes = []byte{0xd5, 0x03, 0x20, 0x1f} const ( IO_FD_FDID_SYM_OFFSET = 192 NET_SEND_SYM_OFFSET = 776 ) const ( OFFSET_0 = 0 OFFSET_16_BIT = 1 OFFSET_32_BIT = 2 OFFSET_48_BIT = 3 PC_START = 0 BLR_X18 = 0xd63f0240 ) var SrcAddrOffset uintptr const ChangeEncLen = 3 type InstInfo struct { SymName string SymSize uint64 SymAddr uint64 PC uint64 Inst arm64asm.Inst OriginInst arm64asm.Inst OriginCode []byte TargetAddr uint64 OriginTargetAddr uint64 TargetEnc uint32 OriginEnc uint32 } type InnerSymbolInfo struct { IO_fd_fdID_ADRP InstInfo IO_fd_fdID_ADD InstInfo NET_Send InstInfo } // //type LibNetInfo struct { // LibName string // LibPath string // FuncSymbol InstInfo // InnerSymbol InnerSymbolInfo //} // //type UprobeData struct { // Offset int // Func string // ELFPath string //} // //type JvmInjector struct { // Pid int // ReleaseLibNetInfo LibNetInfo // DebugLibNetInfo LibNetInfo // RecodeInfo LibNetInfo // // 原方法首个指令不为jmp | ReleaseLibNetInfo 读取无异常 // PreCheck struct { // NeedInjectionCheck bool // 原指令校验 true表示可以继续执行注入 // LoadingCheck bool // true 表示加载成功 // IoFdCheck bool // fd地址校验 // NetSendFuncCheck bool // netsend校验 // EbpfCanInjection bool // } // AfterCheck struct { // IoFdCheck bool // NetSendFuncCheck bool // } // Uprobe UprobeData // Rootfs string //} func (j *JvmInjector) checkEnc(code []byte, start, len uint64, enc uint32) error { end := start + len inst, err := arm64asm.Decode(code[start:end]) if err != nil { return fmt.Errorf("Decode code[%d:%d] %s: err is <%v>", start, end, arm64asm.GNUSyntax(inst), err) } else { if inst.Enc != enc { return fmt.Errorf("Validation inst failed:'%s <+%d>: %s'", fmt.Sprintf("0x%016x", j.ReleaseLibNetInfo.FuncSymbol.SymAddr+start), start, arm64asm.GNUSyntax(inst)) } } return nil } func (j *JvmInjector) findReleaseAddressInfoFromMem() error { funcAbsAddress := j.ReleaseLibNetInfo.FuncSymbol.SymAddr releaseFuncSym := InnerSymbolInfo{} code, err := j.readMemory(funcAbsAddress, j.ReleaseLibNetInfo.FuncSymbol.SymSize) if err != nil { return err } klog.Infof("[inject] SymSize %d", j.ReleaseLibNetInfo.FuncSymbol.SymSize) // cwso是否载入,载入则从recode判断指令 ToDo更新位置信息 baseAddress, _, err := j.findLibBaseFromProcMaps(j.DebugLibNetInfo.LibName) if err == nil { j.PreCheck.LoadingCheck = true klog.Infof("[inject] so already loaded check enc...") // 获取recode地址 klog.Infof("[inject] baseAddress %d", baseAddress) recodeFunctionSym, err := GetFunctionOffset(j.DebugLibNetInfo.LibPath, j.RecodeInfo.FuncSymbol.SymName) if err != nil { klog.WithError(err).Errorf("[inject] get recode function symbol failed.") return err } j.RecodeInfo.FuncSymbol.SymAddr = baseAddress + recodeFunctionSym.Value recode, err := j.readMemory(j.RecodeInfo.FuncSymbol.SymAddr, 4) if err != nil { return err } if !bytes.Equal(recode, nopBytes) { j.PreCheck.EbpfCanInjection = true klog.Infof("[inject] successful...") return nil } klog.Infof("[inject] so already loaded. check failed.") } /* 0x0000fffbdc0ef24c <+56>: str x2, [x6,#120] 0x0000fffbdc0ef250 <+60>: str x3, [x29,#96] 0x0000fffbdc0ef254 <+64>: mov x21, x0 0x0000fffbdc0ef258 <+68>: mov w28, w4 0x0000fffbdc0ef25c <+72>: mov w23, w5 */ // 修改指令效验方式为首地址 w5向上偏移4段 // TODO Position Independent check klog.Infof("[inject] start check...") if os.Getenv("jvm_offset") != "" { if off, err := strconv.Atoi(os.Getenv("jvm_offset")); err == nil { SrcAddrOffset = uintptr(off) if SrcAddrOffset == 0 { return fmt.Errorf("[attach] jvm_offset have no hook point.") } else { klog.Infof("[attach] use jvm_offset off:%d", SrcAddrOffset) return nil } } } pc := uint64(0) var findw5 bool var findx3 bool for pc < uint64(len(code)) { //err = j.checkEnc(code, pc, 4, 0x2a0503f3) // mov w19, w5 inst, err := arm64asm.Decode(code[pc:]) if err == nil && inst.Op == arm64asm.STR && inst.Args[0] == arm64asm.X3 && !findw5 { findx3 = true forwardOk := true // Step 1: 向后检查 for i := 0; i <= ChangeEncLen; i++ { offset := pc + uint64(i*4) if offset+4 > uint64(len(code)) { forwardOk = false break } inst, err := arm64asm.Decode(code[offset : offset+4]) if err != nil || jumpOps[inst.Op] { forwardOk = false break } } if forwardOk { SrcAddrOffset = uintptr(pc) klog.Infof("[inject] x3 start check ok [after]... SrcAddrOffset:%d", SrcAddrOffset) return nil } } if err == nil && inst.Op == arm64asm.MOV && inst.Args[1] == arm64asm.W5 && !findx3 { findw5 = true // Step 1: 向前检查(不包含当前指令) if pc >= uint64(ChangeEncLen*4) { backwardOk := true for i := 1; i <= ChangeEncLen; i++ { offset := pc - uint64(i*4) inst, err := arm64asm.Decode(code[offset : offset+4]) if err != nil || jumpOps[inst.Op] { backwardOk = false break } } if backwardOk { SrcAddrOffset = uintptr(pc - uint64(ChangeEncLen*4)) klog.Infof("[inject] w5 start check ok [before]... SrcAddrOffset:%d", SrcAddrOffset) return nil } } // Step 2: 向前失败 → 尝试向后 forwardOk := true for i := 0; i <= ChangeEncLen; i++ { offset := pc + uint64(i*4) if offset+4 > uint64(len(code)) { forwardOk = false break } inst, err := arm64asm.Decode(code[offset : offset+4]) if err != nil || jumpOps[inst.Op] { forwardOk = false break } } if forwardOk { SrcAddrOffset = uintptr(pc) klog.Infof("[inject] w5 start check ok [after]... SrcAddrOffset:%d", SrcAddrOffset) return nil } } pc += 4 } klog.Infof("[inject] SrcAddrOffset:", SrcAddrOffset) //aaa, _ := strconv.Atoi(os.Getenv("offset")) //SrcAddrOffset = uintptr(aaa) if SrcAddrOffset == 0 { return fmt.Errorf("[attach] have no hook point.") } //err = j.checkEnc(code, 56, 4, 0xf9003cc2) //if err != nil { // return err //} //err = j.checkEnc(code, 60, 4, 0xf90033a3) //if err != nil { // return err //} //err = j.checkEnc(code, 64, 4, 0xaa0003f5) //if err != nil { // return err //} //err = j.checkEnc(code, 68, 4, 0x2a0403fc) //if err != nil { // return err //} //err = j.checkEnc(code, 72, 4, 0x2a0503f7) //if err != nil { // return err //} j.ReleaseLibNetInfo.InnerSymbol = releaseFuncSym j.ReleaseLibNetInfo.FuncSymbol.OriginCode = code[0:4] return nil } func (j *JvmInjector) findDebugAddressInfoFromMem() (uint64, error) { funcAbsAddress := j.DebugLibNetInfo.FuncSymbol.SymAddr debugFuncSym := InnerSymbolInfo{} //debugFuncSym.FuncSymbol.SymAddr = funcAbsAddress //offset := sym.Value size := j.DebugLibNetInfo.FuncSymbol.SymSize code, err := j.readMemory(funcAbsAddress, size) //klog.Infoln(code, err) if err != nil { return 0, err } pc := uint64(0) preContext := InstInfo{} for pc < uint64(len(code)) { inst, err := arm64asm.Decode(code[pc:]) if err != nil { klog.Infof("Decode error at offset 0x%x: %v\n", pc, err) pc++ // Skip this byte and try to decode again continue } //klog.Infof("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst) //klog.Infof("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil)) //klog.Infof("Decoded GNU instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.GNUSyntax(Inst, 0, nil)) currentData := InstInfo{ PC: pc, SymAddr: funcAbsAddress + pc, Inst: inst, } if pc == 0 { j.DebugLibNetInfo.FuncSymbol.PC = currentData.PC j.DebugLibNetInfo.FuncSymbol.Inst = currentData.Inst j.DebugLibNetInfo.FuncSymbol.OriginInst = currentData.Inst } // IO_fd_fdID if pc == IO_FD_FDID_SYM_OFFSET { if inst.Op == arm64asm.ADD { if preContext.Inst.Op == arm64asm.ADRP && inst.Args[0].String() == arm64asm.X0.String() { debugFuncSym.IO_fd_fdID_ADD = currentData debugFuncSym.IO_fd_fdID_ADD.SymName = "(Debug)" debugFuncSym.IO_fd_fdID_ADD.OriginEnc = currentData.Inst.Enc debugFuncSym.IO_fd_fdID_ADD.TargetEnc = j.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID_ADD.Inst.Enc & uint32(0xFFFFF000) /* |31 immlo | 27-24 |23 immhi 5|4 Rd 0| 1 00 1 0000 0001 1000 0000 1110 011 0 0000 9 0 1 8 0 e 6 0 ( target- pc >> zero(12) )/4k */ debugFuncSym.IO_fd_fdID_ADRP = preContext debugFuncSym.IO_fd_fdID_ADRP.SymName = "(Debug)" debugFuncSym.IO_fd_fdID_ADRP.OriginEnc = preContext.Inst.Enc releaseTarget := j.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID_ADRP.TargetAddr offset := (releaseTarget - preContext.SymAddr&0xFFFFFFFFFFFFF000) / (1 << 12) immhi := offset >> 2 immlo := offset & 0x03 decimal31_24 := (1 << 7) + (immlo << 5) + (1 << 4) targetEnc := (decimal31_24 << 24) | (immhi << 5) debugFuncSym.IO_fd_fdID_ADRP.TargetEnc = uint32(targetEnc) j.PreCheck.IoFdCheck = true } else { return 0, fmt.Errorf("The decoded instruction is not a ADRP or X0. inst:<%s>, arg:<%s>", inst.String(), inst.Args) } } else { return 0, fmt.Errorf("The decoded instruction is not a ADD. inst:<%s>, arg:<%s>", inst.String(), inst.Args) } } if pc == NET_SEND_SYM_OFFSET { debugFuncSym.NET_Send = currentData //klog.Infof("4 call Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst) //relOffset, ok := (inst.Args[0].(x86asm.Rel)) klog.Infoln(inst) klog.Infoln(inst.Args) //if !ok { // return 0, fmt.Errorf("The decoded instruction is not a Rel.") //} //targetAddress := currentData.SymAddr + uint64(inst.Len) + uint64(relOffset) //debugFuncSym.NET_Send.TargetAddr = targetAddress debugFuncSym.NET_Send.SymName = "(Debug)" //klog.Infof("Find %s Target address: 0x%x\n", debugFuncSym.NET_Send.SymName, targetAddress) // //// 保存原始数据 //debugFuncSym.NET_Send.OriginTargetAddr = targetAddress //debugFuncSym.NET_Send.OriginInst = currentData.Inst j.PreCheck.NetSendFuncCheck = true } preContext = InstInfo{ PC: pc, SymAddr: funcAbsAddress + pc, Inst: inst, } pc += 4 } j.DebugLibNetInfo.InnerSymbol = debugFuncSym return 0, nil } //func (j *JvmInjector) checkDebugFuncSymAfterChange() (uint64, error) { // funcAbsAddress := j.DebugLibNetInfo.FuncSymbol.SymAddr // debugFuncSym := InnerSymbolInfo{} // code, err := j.readMemory(funcAbsAddress, j.DebugLibNetInfo.FuncSymbol.SymSize) // if err != nil { // return 0, err // } // // pc := uint64(0) // preContext := InstInfo{} // // for pc < uint64(len(code)) { // inst, err := x86asm.Decode(code[pc:], 64) // if err != nil { // klog.Infof("Decode error at offset 0x%x: %v\n", pc, err) // pc++ // Skip this byte and try to decode again // continue // } // //klog.Infof("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst) // //klog.Infof("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil)) // //klog.Infof("Decoded GNU instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.GNUSyntax(Inst, 0, nil)) // currentData := InstInfo{ // PC: pc, // SymAddr: funcAbsAddress + pc, // Inst: inst, // } // if pc == NET_SEND_SYM_OFFSET { // klog.Infof("Instuction at 0x%x: %v\n", preContext.PC, preContext.Inst) // debugFuncSym.IO_fd_fdID = currentData // debugFuncSym.IO_fd_fdID.SymName = "(Debug)" // // 计算目标地址 // if currentData.Inst.Op == x86asm.MOV && // len(currentData.Inst.Args) == 4 && // currentData.Inst.Args[0] != nil && // currentData.Inst.Args[0] == x86asm.RDX && // currentData.Inst.Args[1] != nil { // if mem, ok := currentData.Inst.Args[1].(x86asm.Mem); ok && mem.Base == x86asm.RIP { // // 直接从Mem结构体中读取偏移 // relOffset := mem.Disp // targetAddress := currentData.SymAddr + uint64(currentData.Inst.Len) + uint64(relOffset) // klog.Infof("Find %s Target address: 0x%x\n", debugFuncSym.IO_fd_fdID.SymName, targetAddress) // debugFuncSym.IO_fd_fdID.TargetAddr = targetAddress // //j.PreCheck.IoFdCheck = true // // if targetAddress == j.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID.TargetAddr { // j.DebugLibNetInfo.InnerSymbol.IO_fd_fdID.TargetAddr = targetAddress // j.DebugLibNetInfo.InnerSymbol.IO_fd_fdID.Inst = currentData.Inst // j.AfterCheck.IoFdCheck = true // klog.Infoln("ok") // } // } else { // return 0, fmt.Errorf("The instruction does not use RIP-relative addressing.") // } // } else { // return 0, fmt.Errorf("The decoded instruction is not a MOV to RDX.") // } // } // if pc == NET_SEND_SYM_OFFSET { // debugFuncSym.NET_Send = currentData // //klog.Infoln(currentData.IntelInst) // //klog.Infof("4 call Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst) // relOffset, ok := (inst.Args[0].(x86asm.Rel)) // if !ok { // return 0, fmt.Errorf("The decoded instruction is not a Rel.") // } // targetAddress := currentData.SymAddr + uint64(inst.Len) + uint64(relOffset) // debugFuncSym.NET_Send.TargetAddr = targetAddress // debugFuncSym.NET_Send.SymName = "(Debug)" // klog.Infof("Find %s Target address: 0x%x\n", debugFuncSym.NET_Send.SymName, targetAddress) // // if targetAddress == j.ReleaseLibNetInfo.InnerSymbol.NET_Send.TargetAddr { // j.DebugLibNetInfo.InnerSymbol.NET_Send.TargetAddr = targetAddress // j.DebugLibNetInfo.InnerSymbol.NET_Send.Inst = currentData.Inst // j.AfterCheck.NetSendFuncCheck = true // } // } // // preContext = InstInfo{ // PC: pc, // SymAddr: funcAbsAddress + pc, // Inst: inst, // } // pc += uint64(inst.Len) // } // return 0, nil //} func (j *JvmInjector) checkReleaseFuncSymAfterChange() error { funcAbsAddress := j.ReleaseLibNetInfo.FuncSymbol.SymAddr code, err := j.readMemory(funcAbsAddress, j.ReleaseLibNetInfo.FuncSymbol.SymSize) if err != nil { return fmt.Errorf("readMemory error in checkReleaseFuncSymAfterChange <%v>", err) } inst, err := x86asm.Decode(code[0:], 64) if err != nil { return fmt.Errorf("Decode error in checkReleaseFuncSymAfterChange <%v>", err) } if inst.Op != x86asm.JMP { return fmt.Errorf("The instruction does not JMP.") } relOffset, ok := inst.Args[0].(x86asm.Rel) if !ok { return fmt.Errorf("The instruction does not use RIP-relative addressing.") } // 验证target与Debug入口是否一致 targetAddress := funcAbsAddress + uint64(inst.Len) + uint64(relOffset) if targetAddress != j.DebugLibNetInfo.FuncSymbol.SymAddr { return fmt.Errorf("Function entry jmp address does not match expectations.") } return nil } // readMemory 用于读取指定地址的内存数据 func (j *JvmInjector) readMemory(address uint64, size uint64) ([]byte, error) { memFile := fmt.Sprintf("/proc/%d/mem", j.Pid) file, err := os.Open(memFile) if err != nil { return nil, err } defer file.Close() data := make([]byte, size) _, err = file.ReadAt(data, int64(address)) if err != nil { return nil, err } return data, nil } // findLibraryBases 用于在 /proc/[pid]/maps 文件中查找库的所有基地址 func findLibraryBasesList(pid int, libraryName string, libPath string) ([]uint64, error) { mapsFile := fmt.Sprintf("/proc/%d/maps", pid) file, err := os.Open(mapsFile) if err != nil { return nil, err } defer file.Close() var bases []uint64 scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, libraryName) && strings.Contains(line, libPath) { var start, end uint64 fmt.Sscanf(line, "%x-%x", &start, &end) bases = append(bases, start) } } if len(bases) == 0 { return nil, fmt.Errorf("library %s not found", libraryName) } return bases, nil } func (j *JvmInjector) findLibBaseFromProcMaps(libName string) (uint64, string, error) { mapsFile := fmt.Sprintf("/proc/%d/maps", j.Pid) file, err := os.Open(mapsFile) if err != nil { return 0, "", err } defer file.Close() var start, end uint64 scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, "/"+libName) { fmt.Sscanf(line, "%x-%x", &start, &end) fields := strings.Fields(line) if len(fields) > 5 { path := fields[5] if strings.HasSuffix(path, ".so") { klog.Infof("Found library %s\n", path) return start, path, nil } } } } return 1, "", fmt.Errorf("[findLibBaseFromProcMaps] library %s not found", libName) } //func (j *JvmInjector) getFunctionOffset(libPath, functionName string) (elf.Symbol, error) { // elfFile, err := elf.Open(libPath) // if err != nil { // return elf.Symbol{}, fmt.Errorf("failed to open ELF file: %v", err) // } // defer elfFile.Close() // // symbols, err := elfFile.DynamicSymbols() // if err != nil { // return elf.Symbol{}, fmt.Errorf("failed to read dynamic symbols: %v", err) // } // // for _, sym := range symbols { // if sym.Name == functionName { // return sym, nil // } // } // // //textSection := elfFile.Section(".text") // //if textSection == nil { // // klog.Infoln("textSection is null") // // //return nil // //} // //textSectionData, err := textSection.Data() // //if err != nil { // // klog.Infoln("textSectionData error is", err) // // //return nil // //} // //textSectionLen := uint64(len(textSectionData) - 1) // // return elf.Symbol{}, fmt.Errorf("function %s not found", functionName) //} //var PID string //func (j *JvmInjector) findReleaseFuncContextFromLibPath() error { // // 获取release库的基地址 // baseAddress, libPath, err := j.findLibBaseFromProcMaps(j.ReleaseLibNetInfo.LibName) // functionName := j.ReleaseLibNetInfo.FuncSymbol.SymName // j.ReleaseLibNetInfo.LibPath = libPath // libName := j.ReleaseLibNetInfo.LibName // if err != nil { // return fmt.Errorf("Error finding base addresses: %v", err) // } // klog.Infof("Base address of (%s)%s: %x\n", "", libName, baseAddress) // // // 获取函数的偏移量 // functionSym, err := j.getFunctionOffset(libPath, functionName) // // // 计算函数的实际内存地址 // j.ReleaseLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value // j.ReleaseLibNetInfo.FuncSymbol.SymSize = functionSym.Size // if err != nil { // return fmt.Errorf("Error getting function offset: %v", err) // } // klog.Infof("Actual memory address of %s at base 0x%x: 0x%x\n", functionName, baseAddress, j.ReleaseLibNetInfo.FuncSymbol.SymAddr) // err = j.findReleaseAddressInfoFromMem() // // if err != nil { // return err // } else { // j.PreCheck.NeedInjectionCheck = true // } // // return nil //} func (j *JvmInjector) InitProg() error { // 获取release库的基地址 klog.Infof("[InitProg] find lib base from proc maps: %d|%s", j.Pid, j.ReleaseLibNetInfo.LibName) baseAddress, releaseSoFilePathInProc, mapFilesPath, deleted, err := FindLibBaseFromProcMaps(j.Pid, j.ReleaseLibNetInfo.LibName) //j.ReleaseLibNetInfo.LibPath = releaseSoFilePathInProc j.ReleaseLibNetInfo.FileDeleted = deleted j.ReleaseLibNetInfo.MapFile = mapFilesPath pJvmlibnetPhysicalPath := j.Rootfs + releaseSoFilePathInProc j.ReleaseLibNetInfo.LibPath = pJvmlibnetPhysicalPath if err != nil { klog.Errorf("[InitProg] Error finding base addresses: %v", err) return fmt.Errorf("[InitProg] Error finding base addresses: %v", err) } // jvm prog base //pJvmLibBaseDir := filepath.Dir(pJvmlibnetPhysicalPath) jvmLibBaseDir := filepath.Dir(releaseSoFilePathInProc) // proc maps load path debugSoFilePathInProc := filepath.Join(jvmLibBaseDir, j.DebugLibNetInfo.LibName) // Physical path debugSoFilePhysicalPath := filepath.Join(j.Rootfs, debugSoFilePathInProc) _, noFileErr := os.Stat(debugSoFilePhysicalPath) // find cwlibnet.so in proc maps var readDebugSoPathInMaps string _, readDebugSoPathInMaps, j.DebugLibNetInfo.MapFile, j.DebugLibNetInfo.FileDeleted, _ = FindLibBaseFromProcMaps(j.Pid, j.DebugLibNetInfo.LibName) j.DebugLibNetInfo.LibPath = debugSoFilePhysicalPath j.DebugLibNetInfo.ProcLoadPath = filepath.Join(jvmLibBaseDir, j.DebugLibNetInfo.LibName) // condition create pathFromProg := utils.GetDefaultLibsPath("jvm", j.DebugLibNetInfo.LibName) if noFileErr != nil && readDebugSoPathInMaps == "" && !j.DebugLibNetInfo.FileDeleted { err = CopyFileAndMatchPermissions(pathFromProg, debugSoFilePhysicalPath, pJvmlibnetPhysicalPath) klog.Infof("[src:%s],[target:%s],[perm:%s]", pathFromProg, debugSoFilePhysicalPath, pJvmlibnetPhysicalPath) if err != nil { klog.WithError(err).Errorf("[InitProg] Error copy.") return err } } functionName := j.ReleaseLibNetInfo.FuncSymbol.SymName //j.ReleaseLibNetInfo.LibPath = pJvmlibnetPhysicalPath klog.Infof("[inject] Base address of [%s]:[%x]", j.ReleaseLibNetInfo.LibName, baseAddress) // 获取函数的偏移量 functionSym, err := GetFunctionOffset(pJvmlibnetPhysicalPath, functionName) // 计算函数的实际内存地址 j.ReleaseLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value j.ReleaseLibNetInfo.FuncSymbol.SymSize = functionSym.Size if err != nil { klog.WithError(err).Errorf("Error getting function offset") return err } klog.Infof("[inject] Actual memory address of %s at base 0x%x: 0x%x", functionName, baseAddress, j.ReleaseLibNetInfo.FuncSymbol.SymAddr) if j.Uprobe.ELFPath == "" { if j.DebugLibNetInfo.FileDeleted { j.Uprobe.ELFPath = j.DebugLibNetInfo.MapFile } else { j.Uprobe.ELFPath = debugSoFilePhysicalPath } } err = j.findReleaseAddressInfoFromMem() if err != nil { klog.WithError(err).Errorf("[InitProg] Error copy.") return err } else { j.PreCheck.NeedInjectionCheck = true } // copy /NativeAgent nativePath := filepath.Join(j.Rootfs, "/tmp/NativeAgent") klog.Infof("[InitProg] init /tmp/NativeAgent.") if _, err := os.Stat(nativePath); err == nil { // 目标已存在,直接跳过 klog.Infof("[InitProg] found /tmp/NativeAgent.") return nil } err = CopyFileAndMatchPermissions(utils.GetDefaultAgentsPath("NativeAgent"), nativePath, pJvmlibnetPhysicalPath) if err != nil { klog.WithError(err).Errorf("[InitProg] NativeAgent Error copy.") } return nil } func (j *JvmInjector) findDebugFuncContextFromLibPath() error { //libName := j.DebugLibNetInfo.LibName // 获取release库的基地址 baseAddress, libPath, err := FindLibBaseByPathFromProcMaps(j.Pid, j.DebugLibNetInfo.ProcLoadPath) klog.Infof("[inject] debug base address of [%s] : %x", libPath, baseAddress) functionName := j.DebugLibNetInfo.FuncSymbol.SymName //j.DebugLibNetInfo.LibPath = libPath if err != nil { klog.WithError(err).Errorf("[inject] error.") return err } // 获取函数的偏移量 functionSym, err := GetFunctionOffset(j.DebugLibNetInfo.LibPath, functionName) // 计算函数的实际内存地址 j.DebugLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value j.DebugLibNetInfo.FuncSymbol.SymSize = functionSym.Size if err != nil { return fmt.Errorf("Error getting debug function:[%s] error: %v", functionName, err) } // 计算recode内存地址 recodeFunctionSym, err := GetFunctionOffset(j.DebugLibNetInfo.LibPath, j.RecodeInfo.FuncSymbol.SymName) j.RecodeInfo.FuncSymbol.SymAddr = baseAddress + recodeFunctionSym.Value if err != nil { return fmt.Errorf("Error getting recode function:[%s] error: %v", j.RecodeInfo.FuncSymbol.SymName, err) } //klog.Infof("DEBUG Actual memory address of %s at base 0x%x: 0x%x\n", functionName, baseAddress, j.DebugLibNetInfo.FuncSymbol.SymAddr) //klog.Infof("DEBUG Actual memory address of %s at base 0x%x: 0x%x\n", j.RecodeInfo.FuncSymbol.SymName, baseAddress, j.RecodeInfo.FuncSymbol.SymAddr) //_, err = j.findDebugAddressInfoFromMem() //if err != nil { // return err //} return nil } func printCodeData(data LibNetInfo) { klog.Infof("========FuncEnter <0x%x> \n", data.FuncSymbol.SymAddr) //klog.Infof("%s | CurrentAddr:<0x%x>\nOrigin-TargetAddr:<0x%x> | TargetAddr:<0x%x> \nOrigin-Enc:<0x%x> | TargetEnc:<0x%x> \n", // data.InnerSymbol.IO_fd_fdID_ADRP.SymName, // data.InnerSymbol.IO_fd_fdID_ADRP.SymAddr, // data.InnerSymbol.IO_fd_fdID_ADRP.OriginTargetAddr, // data.InnerSymbol.IO_fd_fdID_ADRP.TargetAddr, // data.InnerSymbol.IO_fd_fdID_ADRP.OriginEnc, // data.InnerSymbol.IO_fd_fdID_ADRP.TargetEnc) //klog.Infof("\n%s | CurrentAddr:<0x%x>\nOrigin-TargetAddr:<0x%x> | TargetAddr:<0x%x> \nOrigin-Enc:<0x%x> | TargetEnc:<0x%x> \n", // data.InnerSymbol.IO_fd_fdID_ADD.SymName, // data.InnerSymbol.IO_fd_fdID_ADD.SymAddr, // data.InnerSymbol.IO_fd_fdID_ADD.OriginTargetAddr, // data.InnerSymbol.IO_fd_fdID_ADD.TargetAddr, // data.InnerSymbol.IO_fd_fdID_ADD.OriginEnc, // data.InnerSymbol.IO_fd_fdID_ADD.TargetEnc) //klog.Infof("\n%s | CurrentAddr:<0x%x>\nOrigin-TargetAddr:<0x%x> | TargetAddr:<0x%x>\nOrigin-Inst:<%s> | Inst:<%s> \n", // data.InnerSymbol.NET_Send.SymName, // data.InnerSymbol.NET_Send.SymAddr, // data.InnerSymbol.NET_Send.OriginTargetAddr, // data.InnerSymbol.NET_Send.TargetAddr, // arm64asm.GNUSyntax(data.InnerSymbol.NET_Send.OriginInst), // arm64asm.GNUSyntax(data.InnerSymbol.NET_Send.Inst)) klog.Infoln("========") } func (j *JvmInjector) jvmInjectLib() int { dll := C.CString(j.DebugLibNetInfo.ProcLoadPath) // 替换为实际的DLL路径 rootfs := C.CString(j.Rootfs) // 替换为实际的DLL路径 defer C.free(unsafe.Pointer(dll)) // 确保在使用完字符串后释放内存 result := C.cw_inject_library(C.int(j.Pid), C.int(1), dll, rootfs) klog.Infof("[inject] [pid:%d][rootfs:%s][dll:%s][result:%d]\n", j.Pid, j.Rootfs, j.DebugLibNetInfo.ProcLoadPath, int(result)) return int(result) } func (j *JvmInjector) validateAllPreCheck() bool { return j.PreCheck.NeedInjectionCheck && j.PreCheck.LoadingCheck } func (j *JvmInjector) validateAllModifyCheck() bool { return j.AfterCheck.IoFdCheck && j.AfterCheck.NetSendFuncCheck } /*修改部分*/ func readData(pid int, addr uintptr) (uint64, error) { var data uint64 if _, err := syscall.PtracePeekData(pid, addr, (*[4]byte)(unsafe.Pointer(&data))[:]); err != nil { return 0, fmt.Errorf("ptrace PEEKDATA: %v", err) } return data, nil } func writeData(pid int, addr uintptr, data uint64) error { if _, err := syscall.PtracePokeData(pid, addr, (*[4]byte)(unsafe.Pointer(&data))[:]); err != nil { return fmt.Errorf("ptrace POKEDATA: %v", err) } return nil } func modifyIoFdTargetAddr(pid int, insertAddr, distAddr uintptr) error { newOffset := distAddr - (insertAddr + 7) targetAddr := insertAddr + 3 // 获取目标地址处的数据 originalData, err := readData(pid, targetAddr) if err != nil { return err } // 更新数据中的目标偏移 updatedData := (originalData & 0xFFFFFFFF00000000) | uint64(newOffset&0xFFFFFFFF) err = writeData(pid, targetAddr, updatedData) if err != nil { return err } return nil } /* set *(unsigned int*)($debug) = *(unsigned int*)($origin+56) set *(unsigned int*)($debug+4) = *(unsigned int*)($origin+60) set *(unsigned int*)($debug+8) = *(unsigned int*)($origin+64) set *(unsigned int*)($debug+12) = *(unsigned int*)($origin+68) # SUB SP, SP, #0x080 // 将栈指针下移 8 字节,创建栈帧空间 set *(unsigned int*)($debug+16) = 0xd10203ff # STR W5, [SP] // 将 W5 的值存储到栈顶 set *(unsigned int*)($debug+20) = 0xb90003e5 # LDR W5, [SP] // 从栈顶加载数据回 W5 set *(unsigned int*)($debug+24) = 0xb94003e5 # ADD SP, SP, #0x080 // 恢复栈指针 set *(unsigned int*)($debug+28) = 0x910203ff #mov w23, w5 set *(unsigned int*)($debug+32) = *(unsigned int*)($origin+72) # ret set *(unsigned int*)($debug+36) = 0xd65f03c0 */ func buildCwNopEnc(pid int, nopAddr, originAddr uintptr) error { // 指令不为空则返回 originalData, err := readData(pid, nopAddr) if err != nil { return err } klog.Infof("0x%016x\n", originalData) // 16个字符宽度,左边补0 if originalData != 0xd503201f { return fmt.Errorf("The cw enc not nop <0x%016x>\n", originAddr) } /* sub sp, sp, #0x80 ; 分配栈空间 str w5, [sp] ; 保存 w5 // nop ldr w5, [sp] ; 恢复 w5 add sp, sp, #0x80 ; 回收栈空间 */ encodings := []uint64{ 0xd10203ff, // sub sp, sp, #0x80 0xb90003e5, // str w5, [sp] NOP_ENC, // nop 0xb94003e5, // ldr w5, [sp] 0x910203ff, // add sp, sp, #0x80 } for i, enc := range encodings { if enc == NOP_ENC { continue } addr := nopAddr + uintptr(i*4) if err = setEnc(pid, addr, enc); err != nil { return err } } //err = setEnc(pid, nopAddr+0, 0xd10203ff) //if err != nil { // return err //} //err = setEnc(pid, nopAddr+4, 0xb90003e5) //if err != nil { // return err //} ////nop //err = setEnc(pid, nopAddr+4+4, 0xd503201f) //if err != nil { // return err //} //err = setEnc(pid, nopAddr+4+8, 0xb94003e5) //if err != nil { // return err //} // //err = setEnc(pid, nopAddr+4+12, 0x910203ff) //if err != nil { // return err //} var encLine = ChangeEncLen for i := 0; i < encLine; i++ { src := originAddr + SrcAddrOffset + 4*uintptr(i) dst := nopAddr + (4 + 16) + 4*uintptr(i) err = setEncByAddr(pid, dst, src) if err != nil { return err } } //err = setEncByAddr(pid, nopAddr+4+16, originAddr+56) //if err != nil { // return err //} //err = setEncByAddr(pid, nopAddr+4+20, originAddr+60) //if err != nil { // return err //} //err = setEncByAddr(pid, nopAddr+4+24, originAddr+64) //if err != nil { // return err //} //err = setEncByAddr(pid, nopAddr+4+28, originAddr+68) //if err != nil { // return err //} // //err = setEncByAddr(pid, nopAddr+4+32, originAddr+72) //if err != nil { // return err //} //err = setEnc(pid, nopAddr+8 * 4, 0xd65f03c0) //if err != nil { // return err //} return nil } func setEncByAddr(pid int, currentAddr, targetAddr uintptr) error { // 获取目标地址处的数据 originalData, err := readData(pid, targetAddr) if err != nil { return err } // 更新数据中的目标偏移 err = writeData(pid, currentAddr, originalData) if err != nil { return err } return nil } func setEnc(pid int, soAddr uintptr, enc uint64) error { // 更新数据中的目标偏移 err := writeData(pid, soAddr, enc) if err != nil { return err } return nil } func encodeADRP(rd int, targetAddr, originAddr uint64) uint32 { targetPage := targetAddr >> 12 originPage := originAddr >> 12 imm := int64(targetPage) - int64(originPage) // offset in 4KB pages if imm < -(1<<20) || imm >= (1<<20) { panic("adrp offset out of range") } immlo := uint32(imm & 0x3) // bits 30:29 immhi := uint32((imm >> 2) & 0x7FFFF) // bits 23:5 return (0x90000000 | (immlo << 29) | (immhi << 5) | uint32(rd)) } func encodeADDLO12(rd int, targetAddr uint64) uint32 { imm12 := targetAddr & 0xFFF return (0x91000000 | uint32(imm12<<10) | uint32(rd<<5) | uint32(rd)) } /* set *(unsigned int*)($origin+56) = 0xf2889692 set *(unsigned int*)($origin+60) = 0xf2a363b2 set *(unsigned int*)($origin+64) = 0xf2dfff92 set *(unsigned int*)($origin+68) = 0xf2e00012 # blr x18 set *(unsigned int*)($origin+72) = 0xd63f0240 */ func modifyOriginEnc(pid int, trampolineAddr uint64, origin uintptr, recode uintptr) error { var err error // Original 64-bit address //blrAddr := trampolineAddr // 拆分四段16位地址 // Extract the 16-bit chunks //part1 := blrAddr & 0xFFFF // Lower 16 bits //part2 := (blrAddr >> 16) & 0xFFFF // Next 16 bits //part3 := (blrAddr >> 32) & 0xFFFF // Upper 16 bits //part4 := (blrAddr >> 48) & 0xFFFF // MAXUpper 16 bits //changeParts := []struct { // part uint64 // offset uint64 // enc uint64 //}{ // {blrAddr & 0xFFFF, OFFSET_0, 0}, // Lower 16 bits // {(blrAddr >> 16) & 0xFFFF, OFFSET_16_BIT, 0}, // Next 16 bits // {(blrAddr >> 32) & 0xFFFF, OFFSET_32_BIT, 0}, // Upper 16 bits // {(blrAddr >> 48) & 0xFFFF, OFFSET_48_BIT, 0}, // MAXUpper 16 bits // {0, 0, BLR_X18}, //} StepCount := ChangeEncLen originAddr := make([]uintptr, StepCount) for i := 0; i < StepCount; i++ { originAddr[i] = origin + SrcAddrOffset + uintptr(i*4) } changeParts := []struct { enc uint32 }{ {encodeADRP(18, trampolineAddr, uint64(originAddr[0]))}, // adrp x18, trampolineAddr {encodeADDLO12(18, trampolineAddr)}, // add x18, x18, :lo12:trampolineAddr {BLR_X18}, // blr x18 } //for i, p := range changeParts { // if err := setEnc(pid, originInst[i], uint64(p.enc)); err != nil { // return err // } //} //callAddrOffset = 44 //var addrSteps = []uintptr{ // origin + callAddrOffset, // origin + callAddrOffset + 4, // origin + callAddrOffset + 8, // origin + callAddrOffset + 12, // origin + callAddrOffset + 16, //} // Save Change for i := 0; i < StepCount; i++ { if err = setEncByAddr(pid, recode+uintptr(i*4), originAddr[i]); err != nil { return err } } // 修改原函数入口 for i, p := range changeParts { if err = setEnc(pid, originAddr[i], uint64(p.enc)); err != nil { return err } } //for i, p := range changeParts { // if p.enc == 0 { // p.enc = buildArm64Enc(p.part, p.offset) // } // if err = setEnc(pid, originInst[i], p.enc); err != nil { // return err // } //} // blr x18 //if err = setEnc(pid, addrSteps[stepCount-1], BLR_X18); err != nil { // return err //} //err = setEnc(pid, addrSteps[0], buildArm64Enc(part1, OFFSET_0)) //if err != nil { // return err //} //err = setEnc(pid, addrSteps[1], buildArm64Enc(part2, OFFSET_16_BIT)) //if err != nil { // return err //} //err = setEnc(pid, addrSteps[2], buildArm64Enc(part3, OFFSET_32_BIT)) //if err != nil { // return err //} //err = setEnc(pid, addrSteps[3], buildArm64Enc(part4, OFFSET_48_BIT)) //if err != nil { // return err //} klog.Infof("# blr x18 \nset *(unsigned int*)($origin+%d) = 0x%08x\n", PC_START+4*4, 0xD63F0240) return nil } func buildArm64Enc(imm16, hw uint64) uint64 { rd := 0x12 // x18 fixed := 0x1e5 // Combine all parts into a single 32-bit value result := uint64(rd<<0) | (imm16 << 5) | (hw << 21) | uint64(fixed<<23) klog.Infof("set *(unsigned int*)($origin+%d) = 0x%08x\n", PC_START+hw*4, result) return result } func modifyNetSetTargetAddr(pid int, sendDebugAddr, sendReleaseAddr uintptr) error { sendOffset := sendReleaseAddr - sendDebugAddr - 5 // 读取原始数据 alignedAddr := sendDebugAddr & ^(uintptr(unsafe.Sizeof(uintptr(0))) - 1) originalData, err := readData(pid, alignedAddr) if err != nil { return err } bytes := (*[8]byte)(unsafe.Pointer(&originalData)) offsetLocation := (sendDebugAddr % uintptr(unsafe.Sizeof(uintptr(0)))) + 1 *(*uint32)(unsafe.Pointer(&bytes[offsetLocation])) = uint32(sendOffset) err = writeData(pid, alignedAddr, originalData) if err != nil { return err } return nil } func modifyReleaseFuncEnter(pid int, originEnterAddr, debugEnterAddr uintptr) error { offset := debugEnterAddr - (originEnterAddr + 5) // 读取原始数据 alignedAddr := originEnterAddr & ^(uintptr(unsafe.Sizeof(uintptr(0))) - 1) originalData, err := readData(pid, alignedAddr) if err != nil { return err } bytes := (*[8]byte)(unsafe.Pointer(&originalData)) bytes[originEnterAddr%uintptr(unsafe.Sizeof(uintptr(0)))] = 0xe9 *(*uint32)(unsafe.Pointer(&bytes[(originEnterAddr%uintptr(unsafe.Sizeof(uintptr(0))))+1])) = uint32(offset) err = writeData(pid, alignedAddr, originalData) if err != nil { return err } return nil } func restoreOriginalInstructions(pid int, addr uintptr, instructions []byte) error { alignedAddr := addr & ^(uintptr(unsafe.Sizeof(uintptr(0))) - 1) originalData, err := readData(pid, alignedAddr) if err != nil { return err } bytes := (*[8]byte)(unsafe.Pointer(&originalData)) for i := 0; i < len(instructions); i++ { bytes[addr%uintptr(unsafe.Sizeof(uintptr(0)))+uintptr(i)] = instructions[i] } err = writeData(pid, alignedAddr, originalData) if err != nil { return err } return nil } //func main() { // flag.StringVar(&PID, "p", "", "PID") // flag.Parse() // pidStr := PID // 替换为目标进程的 PID // pid, err := strconv.Atoi(pidStr) // if err != nil { // log.Fatalf("Invalid PID: %v", err) // } // functionName := "Java_java_net_SocketOutputStream_socketWrite0" // libraryName := "libnet.so" // // cwLibraryName := "cwlibnet.so" // cwLibraryPath := "/root/cwlibnet.so" // // jvmInjector := &JvmInjector{ // pid: pid, // ReleaseLibNetInfo: LibNetInfo{ // libName: libraryName, // FuncSymbol: instInfo{ // SymName: functionName, // }, // }, // DebugLibNetInfo: LibNetInfo{ // // TODO 根据版本设置 // libName: cwLibraryName, // // TODO 根据版本设置 // libPath: cwLibraryPath, // FuncSymbol: instInfo{ // SymName: functionName, // }, // }, // } // // err = jvmInject(jvmInjector) // klog.Infoln(err) //} func JvmInject(jvmInjector *JvmInjector) error { jvmInjector.DebugLibNetInfo.FuncSymbol.SymName = "CW_Java_java_net_SocketOutputStream_socketWrite0" pid := jvmInjector.Pid var err error err = jvmInjector.InitProg() //err = jvmInjector.findReleaseFuncContextFromLibPath() //klog.Infoln(err) // Debug版本无需修改寄存器 TODO 直接使用原函数 需要在ebpf层适配 // 已经加载so并指令修改正确的 if jvmInjector.PreCheck.EbpfCanInjection { klog.Infoln("[inject] eBPF can injection.") return nil } if err != nil { klog.WithError(err).Errorf("[inject] Error message during release phase.") return err } // 原指令校验通过 if !jvmInjector.PreCheck.NeedInjectionCheck { return err } printCodeData(jvmInjector.ReleaseLibNetInfo) klog.Info("[inject] Pre check suc.") _type, _, err := jvmInjector.findLibBaseFromProcMaps(jvmInjector.DebugLibNetInfo.LibName) if err != nil { // load so if _type == 1 { klog.Infoln("[inject] start load so.") resCode := jvmInjector.jvmInjectLib() if resCode == 0 { klog.Infof("[inject] load so successful. proc load path is [%s], file path in node is [%s]", jvmInjector.DebugLibNetInfo.ProcLoadPath, jvmInjector.DebugLibNetInfo.LibPath) jvmInjector.PreCheck.LoadingCheck = true } else { klog.Errorf("[inject] Failed load so. so path is [%s]", jvmInjector.DebugLibNetInfo.LibPath) return fmt.Errorf("[inject] Failed load so. code is %d so path is [%s]", resCode, jvmInjector.DebugLibNetInfo.LibPath) } } } else { klog.Infoln("[inject] so already loaded.") jvmInjector.PreCheck.LoadingCheck = true } if !jvmInjector.PreCheck.LoadingCheck { klog.Infof("Failed load so") return err } err = jvmInjector.findDebugFuncContextFromLibPath() if err != nil { klog.WithError(err).Errorf("[inject] Failed to find debug Func Context from libPath") return err } if !jvmInjector.validateAllPreCheck() { klog.Errorf("[inject] validateAllPreCheck failed : "+ "NeedInjectionCheck=%v, LoadingCheck=%v", jvmInjector.PreCheck.NeedInjectionCheck, jvmInjector.PreCheck.LoadingCheck, ) return err } //printCodeData(jvmInjector.DebugLibNetInfo) //// 修改 debugFuncEnterAddr := uintptr(jvmInjector.DebugLibNetInfo.FuncSymbol.SymAddr) originFuncEnterAddr := uintptr(jvmInjector.ReleaseLibNetInfo.FuncSymbol.SymAddr) recodeFuncEnterAddr := uintptr(jvmInjector.RecodeInfo.FuncSymbol.SymAddr) //klog.Infof("<0x%x> -> <0x%x>\n", originFuncEnterAddr, debugFuncEnterAddr) //klog.Infof("<0x%x> -> <0x%x>\n", debugIoFdAddr, ioFdReleaseTargetAddr) //klog.Infof("<0x%x> -> <0x%x>\n", debugNetSendAddr, netSendReleaseTargetAddr) // // 附加到目标进程 klog.Infof("[inject] %d attach", pid) err = syscall.PtraceAttach(pid) if err != nil { klog.Infof("ptrace ATTACH: %v", err) } // // 等待目标进程停止 klog.Infof("[inject] %d attach wait.", pid) if _, err := syscall.Wait4(pid, nil, 0, nil); err != nil { klog.WithError(err).Errorf("[inject] Wait4 error") return err } // 保存原始指令并扩充新指令 klog.Infof("[inject] %d build cw enc", pid) err = buildCwNopEnc(pid, debugFuncEnterAddr, originFuncEnterAddr) if err != nil { klog.Errorln(err) return err } // //err = modifyNetSetTargetAddr(pid, debugNetSendAddr, netSendReleaseTargetAddr) //klog.Infoln(err) //if err != nil { // klog.Infoln(err) // return err //} // todo 二次效验 读取并验证地址 //_, err = jvmInjector.checkDebugFuncSymAfterChange() //printCodeData(jvmInjector.ReleaseLibNetInfo) //printCodeData(jvmInjector.DebugLibNetInfo) // //// todo 效验目标函数内地址是否与预期一致 //if !jvmInjector.validateAllModifyCheck() && err == nil { // return err //} //变更原指令 长跳转到新地址 保存到recode klog.Infof("[inject] %d modifyNetSetTargetAddr", pid) err = modifyOriginEnc(pid, uint64(debugFuncEnterAddr), originFuncEnterAddr, recodeFuncEnterAddr) //// 更新函数入口 //err = modifyReleaseFuncEnter(pid, originFuncEnterAddr, debugFuncEnterAddr) //if err != nil { // klog.Infoln(err) // return err //} //// 校验jmp地址修改正确 //err = jvmInjector.checkReleaseFuncSymAfterChange() //if err != nil { // klog.Infoln(err) // if len(jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode) == 5 { // err = restoreOriginalInstructions(pid, originFuncEnterAddr, jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode) // if err != nil { // klog.Infoln(err) // return err // } // } //} // // 恢复执行 klog.Infof("[inject] %d Detach", pid) if err = syscall.PtraceDetach(pid); err != nil { klog.Errorf("ptrace DETACH: %v", err) return err } return nil }