Pārlūkot izejas kodu

Fixed #TASK_QT-9810 [arm适配]java-client arm适配

Carl 1 gadu atpakaļ
vecāks
revīzija
c11c1b99b5

+ 160 - 0
common/code_type.go

@@ -0,0 +1,160 @@
+package common
+
+type CodeType int16
+
+/*
+|         1           |    0    |    00     |
+| 1:language 2:Gateway|  is AOT | code type |
+*/
+const (
+	CodeTypeUnknown    CodeType = -1
+	CodeTypeWaitCheck  CodeType = 0
+	CodeTypePHP        CodeType = 1001
+	CodeTypeJava       CodeType = 1002
+	CodeTypeJavaAot    CodeType = 1102
+	CodeTypePython     CodeType = 1003
+	CodeTypeDotNet     CodeType = 1004
+	CodeTypeNode       CodeType = 1005
+	CodeTypeGo         CodeType = 1006
+	CodeTypeC          CodeType = 1007
+	CodeTypeNetCore    CodeType = 1008
+	CodeTypeNetCoreAot CodeType = 1108
+	CodeTypeLua        CodeType = 1009
+	CodeTypeJavaC      CodeType = 1010
+	CodeTypeRuby       CodeType = 1012
+)
+
+func (p CodeType) String() string {
+	switch p {
+	case CodeTypeGo:
+		return "GO"
+	case CodeTypeJava:
+		return "JAVA"
+	case CodeTypeJavaAot:
+		return "JAVA_AOT"
+	case CodeTypePHP:
+		return "PHP"
+	case CodeTypePython:
+		return "PYTHON"
+	case CodeTypeDotNet:
+		return "DOTNET"
+	case CodeTypeNode:
+		return "NODE"
+	case CodeTypeC:
+		return "C"
+	case CodeTypeNetCore:
+		return "NETCORE"
+	case CodeTypeNetCoreAot:
+		return "NETCORE_AOT"
+	case CodeTypeLua:
+		return "LUA"
+	case CodeTypeJavaC:
+		return "JAVA_C"
+	case CodeTypeRuby:
+		return "RUBY"
+	case CodeTypeWaitCheck:
+		return "WAIT_CHECK"
+	case CodeTypeUnknown:
+		return "UNKNOWN:Language"
+	default:
+		return "UNKNOWN:Language"
+	}
+}
+
+func (p CodeType) IsWaitCheck() bool {
+	if p == CodeTypeWaitCheck {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsUnknownCode() bool {
+	if p == CodeTypeUnknown {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsJvmCode() bool {
+	if p == CodeTypeJava {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsGoCode() bool {
+	if p == CodeTypeGo {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsJavaAotCode() bool {
+	if p == CodeTypeJavaAot {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsNetCoreAotCode() bool {
+	if p == CodeTypeNetCoreAot {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsDotNetCode() bool {
+	if p == CodeTypeDotNet {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsPHPCode() bool {
+	if p == CodeTypePHP {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsNodeCode() bool {
+	if p == CodeTypeNode {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsCCode() bool {
+	if p == CodeTypeC {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsPythonCode() bool {
+	if p == CodeTypePython {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsLuaCode() bool {
+	if p == CodeTypeLua {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsRubyCode() bool {
+	if p == CodeTypeRuby {
+		return true
+	}
+	return false
+}
+
+func (p CodeType) IsJavaCCode() bool {
+	if p == CodeTypeJavaC {
+		return true
+	}
+	return false
+}

+ 7 - 7
containers/container.go

@@ -1096,21 +1096,21 @@ func (c *Container) attachUprobes(tracer *ebpftracer.Tracer, pid uint32) {
 		return
 	}
 	switch codeType {
-	case CodeTypeJava:
+	case common.CodeTypeJava:
 		c.attachJVMUprobes(tracer, pid)
-	case CodeTypeJavaAot:
+	case common.CodeTypeJavaAot:
 		c.attachJVMUprobes(tracer, pid)
-	case CodeTypeGo:
+	case common.CodeTypeGo:
 		c.attachTlsUprobes(tracer, pid)
-	case CodeTypeNetCore:
+	case common.CodeTypeNetCoreAot:
 		c.attachNetCoreUprobes(tracer, pid)
 	}
 }
 
-func (c *Container) GetCodeTypeFromCache(pid uint32) CodeType {
+func (c *Container) GetCodeTypeFromCache(pid uint32) common.CodeType {
 	p := c.processes[pid]
 	if p == nil {
-		return CodeTypeUnknown
+		return common.CodeTypeUnknown
 	}
 	if p.codeType.IsWaitCheck() {
 		p.codeType = GetExeType(pid)
@@ -1149,7 +1149,7 @@ func (c *Container) attachJVMUprobes(tracer *ebpftracer.Tracer, pid uint32) {
 	if !p.jvmUprobesChecked {
 		codeType := c.GetCodeTypeFromCache(pid)
 		tracer.InitKProcInfo(pid, c.instanceID, uint16(codeType))
-		p.uprobes = append(p.uprobes, tracer.AttachJavaNioReadUprobes(pid, c.instanceID, int32(codeType))...)
+		p.uprobes = append(p.uprobes, tracer.AttachJavaNioReadUprobes(pid, c.instanceID, (codeType))...)
 		p.uprobes = append(p.uprobes, tracer.AttachJavaNetWriteUprobes(pid, c.instanceID)...)
 		p.jvmUprobesChecked = true
 	}

+ 0 - 35
containers/container_apm.go

@@ -18,41 +18,6 @@ import (
 	"time"
 )
 
-type CodeType int16
-
-const (
-	CodeTypeUnknown   CodeType = -1
-	CodeTypeWaitCheck CodeType = 0
-	CodeTypeGo        CodeType = 1006
-	CodeTypeJava      CodeType = 1002
-	CodeTypeJavaAot   CodeType = 1003
-	CodeTypeNetCore   CodeType = 1005
-)
-
-func (p CodeType) String() string {
-	switch p {
-	case CodeTypeGo:
-		return "GO"
-	case CodeTypeJava:
-		return "JAVA"
-	}
-	return "UNKNOWN:Language"
-}
-
-func (p CodeType) IsWaitCheck() bool {
-	if p == CodeTypeWaitCheck {
-		return true
-	}
-	return false
-}
-
-func (p CodeType) IsUnknownCode() bool {
-	if p == CodeTypeUnknown {
-		return true
-	}
-	return false
-}
-
 func (c *Container) getTrace(traceId uint64) (*tracing.Trace, bool) {
 	trace, ok := c.traceMap[traceId]
 	return trace, ok

+ 2 - 1
containers/process.go

@@ -2,6 +2,7 @@ package containers
 
 import (
 	"context"
+	"github.com/coroot/coroot-node-agent/common"
 	"os"
 	"time"
 
@@ -28,7 +29,7 @@ type Process struct {
 	jvmUprobesChecked     bool
 	stackUprobesChecked   bool
 
-	codeType CodeType
+	codeType common.CodeType
 }
 
 func NewProcess(pid uint32, stats *taskstats.Stats) *Process {

+ 4 - 1
containers/registry.go

@@ -243,7 +243,10 @@ func (r *Registry) handleEvents(ch <-chan ebpftracer.Event) {
 					//c.attachTlsUprobes(r.tracer, e.Pid)
 					// c.attachJVMUprobes(r.tracer, e.Pid)
 					c.attachUprobes(r.tracer, e.Pid)
-					c.stackTrace(r.tracer, e.Pid)
+					err := c.stackTrace(r.tracer, e.Pid)
+					if err != nil {
+
+					}
 				} else {
 					klog.Infoln("TCP listen open from unknown container", e)
 				}

+ 14 - 9
containers/stack.go

@@ -35,6 +35,20 @@ func (c *Container) stackTrace(tracer *ebpftracer.Tracer, pid uint32) error {
 			return nil
 		}
 	}
+	codeType := c.GetCodeTypeFromCache(pid)
+	if codeType.IsUnknownCode() || codeType.IsJvmCode() {
+		return nil
+	}
+
+	p := c.processes[pid]
+	if p == nil {
+		return nil
+	}
+
+	if p.stackUprobesChecked {
+		return nil
+	}
+
 	binType := "dotnet"
 	MatchString := ".*HandleFunc|.*main.*|testfun.*|.*serverHandler.*|.*ServeHTTP.*"
 	dbgpath := ""
@@ -63,15 +77,6 @@ func (c *Container) stackTrace(tracer *ebpftracer.Tracer, pid uint32) error {
 		c.Uprobes, _ = c.getUprobes(path, MatchString)
 	}
 
-	p := c.processes[uint32(pid)]
-	if p == nil {
-		return nil
-	}
-
-	if p.stackUprobesChecked {
-		return nil
-	}
-
 	c.UprobesMap = map[string]tracerelf.Uprobe{}
 	fmt.Println("UprobesMap:::init")
 	for _, up := range c.Uprobes {

+ 8 - 7
containers/util.go

@@ -3,6 +3,7 @@ package containers
 import (
 	"debug/elf"
 	"fmt"
+	"github.com/coroot/coroot-node-agent/common"
 	"io/ioutil"
 	"log"
 	"os"
@@ -14,7 +15,7 @@ import (
 
 var libjvmRegex = regexp.MustCompile(`.*/libjvm\.so`)
 
-func GetExeType(pid uint32) CodeType {
+func GetExeType(pid uint32) common.CodeType {
 	mapsFilePath := fmt.Sprintf("/proc/%d/maps", pid)
 
 	data, err := ioutil.ReadFile(mapsFilePath)
@@ -28,20 +29,20 @@ func GetExeType(pid uint32) CodeType {
 		fmt.Println("is java process")
 		if isJavaAotProcess(pid) {
 			fmt.Println("is javaAot process")
-			return CodeTypeJavaAot
+			return common.CodeTypeJavaAot
 		}
-		return CodeTypeJava
+		return common.CodeTypeJava
 	} else if isJavaAotProcess(pid) {
 		fmt.Println("is javaAot process")
-		return CodeTypeJavaAot
+		return common.CodeTypeJavaAot
 	} else if isGoProcess(pid) {
 		fmt.Println("is go process")
-		return CodeTypeGo
+		return common.CodeTypeGo
 	} else if isNetCoreProcess(pid) {
 		fmt.Println("is netcore process")
-		return CodeTypeNetCore
+		return common.CodeTypeNetCoreAot
 	}
-	return CodeTypeUnknown
+	return common.CodeTypeUnknown
 }
 
 // isJavaAotProcess checks if the process with the given PID is a GraalVM native image

+ 1 - 1
ebpftracer/ebpf/utrace/java/include/java_common.h

@@ -9,7 +9,7 @@
 #if defined(__x86_64__)
 #define PT_LEN_REGS(x) (PT_REGS_RBP(x) - 0x10058);
 #elif defined(__aarch64__)
-#define PT_LEN_REGS(x) PT_REGS_SP(x) + 40;
+#define PT_LEN_REGS(x) PT_REGS_SP(x);
 #endif
 
 

+ 10 - 4
ebpftracer/ebpf/utrace/java/net/client.probe.bpf.c

@@ -257,8 +257,13 @@ int uprobe_Java_java_net_SocketOutputStream_socketWrite0(struct pt_regs *ctx) {
 	bpf_probe_read(&len_ptr, sizeof(len_ptr), (void *) len_from_rbp_ptr);
 	cw_bpf_debug("[len_ptr] before addr<0x%lx>, %d \n", len_from_rbp_ptr, len_ptr);
 
-	bpf_probe_read(&len_ptr, sizeof(len_ptr), (void *) len_from_rbp_ptr);
-	cw_bpf_debug("[len_ptr]after  addr<0x%lx>, %d \n", len_from_rbp_ptr, len_ptr);
+//	bpf_probe_read(&len_ptr, sizeof(len_ptr), (void *) len_from_rbp_ptr);
+//	cw_bpf_debug("[len_ptr]after  addr<0x%lx>, %d \n", len_from_rbp_ptr, len_ptr);
+
+	if ( (long) len_ptr != data_count ){
+		cw_bpf_debug("[len_ptr] check error.");
+		return 0;
+	}
 
 	// 获取jbytearray
 	__u32 tgid = (__u32)(bpf_get_current_pid_tgid() >> 32);
@@ -267,10 +272,10 @@ int uprobe_Java_java_net_SocketOutputStream_socketWrite0(struct pt_regs *ctx) {
 		return 0;
 	}
 
-	cw_bpf_debug("[Go] [uprobe/ent]: proc_info_map::%ld, %d, %d\n", proc_info->code_type);
+	cw_bpf_debug("[Java] code_type:%d\n", proc_info->code_type);
 	void *jbytearray_ptr = NULL;
 	// 1003 是 javaAOT 的
-	if (proc_info->code_type == 1003) {
+	if (proc_info->code_type == CodeTypeJavaAot) {
 		jbytearray_ptr = (void *) (PT_REGS_SP(ctx)) + 0x8 + 0x10060+0x20;
 	} else{
 		jbytearray_ptr = (void *) PT_REGS_PARM4(ctx);
@@ -419,6 +424,7 @@ int uprobe_Java_java_net_SocketOutputStream_socketWrite0(struct pt_regs *ctx) {
 	long res = bpf_probe_write_user((void *) len_from_rbp_ptr, &new_val, sizeof(new_val));
 	if (res < 0) {
 		cw_bpf_debug("Failed to write value to user address: %p, error: %ld\n", len_from_rbp_ptr, res);
+//		cw_bpf_debug("Failed to write len to user address: %p\n", len_from_rbp_ptr);
 		return -1;
 	}
 

+ 11 - 8
ebpftracer/jvm.go

@@ -2,7 +2,9 @@ package ebpftracer
 
 import (
 	"errors"
+	"github.com/coroot/coroot-node-agent/common"
 	"io/ioutil"
+	"runtime"
 	"strings"
 
 	"debug/elf"
@@ -23,7 +25,7 @@ const (
 	symbolsocketRead0 = "Java_sun_nio_ch_FileDispatcherImpl_read0"
 )
 
-func (t *Tracer) AttachJavaNioReadUprobes(pid uint32, insID utils.ID, codeType int32) []link.Link {
+func (t *Tracer) AttachJavaNioReadUprobes(pid uint32, insID utils.ID, codeType common.CodeType) []link.Link {
 	if t.disableL7Tracing {
 		return nil
 	}
@@ -31,7 +33,7 @@ func (t *Tracer) AttachJavaNioReadUprobes(pid uint32, insID utils.ID, codeType i
 	var bpath = ""
 
 	// JavaAOT 逻辑
-	if codeType == 1003 {
+	if codeType.IsJavaAotCode() {
 		bpath = proc.Path(uint32(pid), "exe")
 	} else {
 		version := UsePIDToGetJDKVersion(pid)
@@ -137,20 +139,21 @@ func (t *Tracer) AttachJavaNetWriteUprobes(pid uint32, insID utils.ID) []link.Li
 	if t.disableL7Tracing {
 		return nil
 	}
-	//
-	//if pid != 251719 {
-	//	return nil
-	//}
-
 	var libnetSo = "/data/roger/graalvm/lib/libnet.so"
 	var sys = "Java_java_net_SocketOutputStream_socketWrite0"
+	var offset = 53
+	if runtime.GOARCH == "arm64" {
+		libnetSo = "/root/cwlibnet.so"
+		sys = "CW_Java_java_net_SocketOutputStream_socketWrite0"
+		offset = 0
+	}
 	var links []link.Link
 	ex, err := link.OpenExecutable(libnetSo)
 	if err != nil {
 		return nil
 	}
 	opt := link.UprobeOptions{
-		Offset: 53,
+		Offset: uint64(offset),
 		PID:    int(pid),
 	}
 	upread02, err := ex.Uprobe(sys, t.uprobes["uprobe_Java_java_net_SocketOutputStream_socketWrite0"], &opt)

+ 117 - 0
ebpftracer/tracer/inject/include/hotpatch.h

@@ -0,0 +1,117 @@
+/*
+ * hotpatch is a sofile injection strategy.
+ * Copyright (c) 2010-2011, Vikas Naresh Kumar, Selective Intellect LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *	 notice, this list of conditions and the following disclaimer in the
+ *	 documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Selective Intellect LLC nor the
+ *   names of its contributors may be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __LIBHOTPATCH_H__
+#define __LIBHOTPATCH_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#define HOTPATCH_MAJOR_VERSION 0
+#define HOTPATCH_MINOR_VERSION 2
+
+#ifndef HOTPATCH_LINUX_START
+	#define HOTPATCH_LINUX_START "_start"
+#endif
+
+typedef struct hotpatch_is_opaque hotpatch_t;
+/* Create the hotpatch object for the running process whose PID is given as an
+ * argument. Returns a pointer to an opaque object that must be freed by
+ * hotpatch_delete() function later to conserve memory.
+ */
+hotpatch_t *hotpatch_create(pid_t, int verbosity);
+/*
+ * delete memory and close all open handles related to the hotpatch'ed process.
+ * This can lead to the hotpatch'ed process to be unstable if not done in the same
+ * thread as create function above.
+ */
+void hotpatch_destroy(hotpatch_t *);
+/*
+ * Inject a shared object into the process and invoke the given symbol without
+ * arguments. No thread will be created by hotpatch.
+ * If the symbol is NULL, then _init() is expected to be in the library.
+ * If data is NULL, no data will be copied over to the other process for the
+ * symbol that is being invoked. If the symbol being invoked is _init(), then
+ * data will be ignored. This data and datalen will be provided as arguments to
+ * the symbol when invoked.
+ * The return address of the dlopen() call can be optionally returned in
+ * the outaddr variable.
+ * The return value from the invocation of the symbol in the process can be
+ * optionally returned in the outres variable. If the symbol is NULL, or if the
+ * symbol returns void, then the return value will be undefined.
+ */
+int hotpatch_inject_library(hotpatch_t *, const char *sofile,
+							const char *symbol,
+							const unsigned char *data, size_t datalen,
+							uintptr_t *outaddr, uintptr_t *outres);
+
+/* AUXILLIARY FUNCTIONS */
+
+void hotpatch_version(int *major, int *minor);
+
+/* finds the symbol in the symbol table of executable and returns the memory
+ * location of it. On a 64-bit system the running process can be 32 or 64 bit,
+ * and hence they both need to be handled correctly or even simultaneously.
+ * Returns not only the location of the symbol but also the type and size
+ */
+uintptr_t hotpatch_read_symbol(hotpatch_t *, const char *symbol, int *symtype,
+							   size_t *symsize);
+/*
+ * Get the entry point of the executable in question
+ */
+uintptr_t hotpatch_get_entry_point(hotpatch_t *);
+/*
+ * Attach to the process that you wanted to hotpatch. Returns 0 on success and 1
+ * on failure.
+ */
+int hotpatch_attach(hotpatch_t *);
+/*
+ * Detach from the process that you wanted to hotpatch. Returns -1 on failure
+ * or if nothing was attached earlier. Returns 0 if detaching succeeded.
+ */
+int hotpatch_detach(hotpatch_t *);
+/*
+ * Sets the execution pointer to point to the address given by the user.
+ * Returns 0 on success and -1 on failure.
+ */
+int hotpatch_set_execution_pointer(hotpatch_t *, uintptr_t location);
+
+
+int cw_inject_library(int pid, int verbose, char *dll);
+
+#ifdef __cplusplus
+} /* end of extern C */
+#endif /* __cplusplus */
+
+#endif /* __LIBHOTPATCH_H__ */

+ 857 - 0
ebpftracer/tracer/inject/inject_linux_amd64.go

@@ -0,0 +1,857 @@
+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 <stdlib.h>
+*/
+import "C"
+
+import (
+	"bufio"
+	"debug/elf"
+	"fmt"
+	"golang.org/x/arch/x86/x86asm"
+	"log"
+	"os"
+	"strings"
+	"syscall"
+	"time"
+	"unsafe"
+)
+
+const (
+	IO_FD_FDID_SYM_OFFSET = 129
+	NET_SEND_SYM_OFFSET   = 518
+)
+
+type InstInfo struct {
+	SymName          string
+	SymSize          uint64
+	SymAddr          uint64
+	PC               uint64
+	Inst             x86asm.Inst
+	OriginInst       x86asm.Inst
+	OriginCode       []byte
+	TargetAddr       uint64
+	OriginTargetAddr uint64
+}
+
+type InnerSymbolInfo struct {
+	IO_fd_fdID InstInfo
+	NET_Send   InstInfo
+}
+
+type LibNetInfo struct {
+	LibName     string
+	LibPath     string
+	FuncSymbol  InstInfo
+	InnerSymbol InnerSymbolInfo
+}
+
+type JvmInjector struct {
+	Pid               int
+	ReleaseLibNetInfo LibNetInfo
+	DebugLibNetInfo   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
+	}
+}
+
+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
+	}
+	pc := uint64(0)
+	callCount := 0
+	preContext := InstInfo{}
+	for pc < uint64(len(code)) {
+
+		inst, err := x86asm.Decode(code[pc:], 64)
+		if err != nil {
+			fmt.Printf("Decode error at offset 0x%x: %v\n", pc, err)
+			pc++ // Skip this byte and try to decode again
+			continue
+		}
+		//fmt.Printf("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
+		//fmt.Printf("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
+		//fmt.Printf("Decoded GNU instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.GNUSyntax(Inst, 0, nil))
+		currentData := InstInfo{
+			PC:      pc,
+			SymAddr: funcAbsAddress + pc,
+			Inst:    inst,
+			//IntelInst: x86asm.IntelSyntax(inst, 0, nil),
+		}
+		if pc == 0 && inst.Op == x86asm.JMP {
+			// 已经被修改过的首指令
+			return fmt.Errorf("Inst already modified. <%s>", x86asm.IntelSyntax(inst, 0, nil))
+		}
+		if pc == 0 {
+			j.ReleaseLibNetInfo.FuncSymbol.PC = currentData.PC
+			j.ReleaseLibNetInfo.FuncSymbol.Inst = currentData.Inst
+			j.ReleaseLibNetInfo.FuncSymbol.OriginInst = currentData.Inst
+		}
+
+		if inst.Op == x86asm.MOV {
+			if dst, okDst := inst.Args[0].(x86asm.Mem); okDst {
+				if dst.Base == x86asm.RBP {
+					if src, okSrc := inst.Args[1].(x86asm.Reg); okSrc {
+						if src == x86asm.R9L {
+							j.PreCheck.EbpfCanInjection = true
+							return fmt.Errorf("MOV from register %v to memory %v\n", src, dst)
+						}
+					}
+				}
+			}
+
+			//src, okSrc := inst.Args[1].(x86asm.Reg)
+			//fmt.Println(inst.Args)
+			//fmt.Printf("Instruction: %+v\n", inst)
+			//
+			//fmt.Println(okSrc)
+
+			//if okDst && okSrc && dst == x86asm.RBP && src == x86asm.R9L {
+			//	fmt.Println("Instruction is 'mov %r9d, %rbp'")
+			//}
+
+		}
+
+		if inst.Op == x86asm.CALL {
+			//fmt.Printf("Pre instuction at 0x%x: %v\n", preContext.PC, preContext.Inst)
+			if callCount == 0 {
+				releaseFuncSym.IO_fd_fdID = preContext
+				releaseFuncSym.IO_fd_fdID.SymName = "<IO_fd_fdID>(Release)"
+				preInst := preContext.Inst
+				fmt.Println(preInst.Op)
+				fmt.Println((preInst.Args))
+				// 计算目标地址
+				if preInst.Op == x86asm.MOV &&
+					len(preInst.Args) == 4 &&
+					preInst.Args[0] != nil &&
+					preInst.Args[0] == x86asm.RDX &&
+					preInst.Args[1] != nil {
+					if mem, ok := preInst.Args[1].(x86asm.Mem); ok && mem.Base == x86asm.RIP {
+						relOffset := mem.Disp // 直接从Mem结构体中读取偏移
+						targetAddress := preContext.SymAddr + uint64(preInst.Len) + uint64(relOffset)
+						fmt.Printf("Target address: 0x%x\n", targetAddress)
+						releaseFuncSym.IO_fd_fdID.TargetAddr = targetAddress
+					} else {
+						return fmt.Errorf("The instruction does not use RIP-relative addressing.")
+					}
+				} else {
+					return fmt.Errorf("The decoded instruction is not a MOV to RDX.")
+				}
+
+				//os.Exit(1)
+			}
+			callCount++
+			if callCount == 4 {
+				releaseFuncSym.NET_Send = currentData
+				fmt.Printf("4 call Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst)
+
+				relOffset, ok := inst.Args[0].(x86asm.Rel)
+				if !ok {
+					return fmt.Errorf("The instruction does not use RIP-relative addressing.")
+				}
+				targetAddress := currentData.SymAddr + uint64(inst.Len) + uint64(relOffset)
+				releaseFuncSym.NET_Send.TargetAddr = targetAddress
+				fmt.Println(releaseFuncSym.NET_Send)
+				releaseFuncSym.NET_Send.SymName = "<NET_Send>(Release)"
+				fmt.Printf("Target address: 0x%x\n", targetAddress)
+			}
+		}
+		preContext = InstInfo{
+			PC:      pc,
+			SymAddr: funcAbsAddress + pc,
+			Inst:    inst,
+		}
+		pc += uint64(inst.Len)
+	}
+	j.ReleaseLibNetInfo.InnerSymbol = releaseFuncSym
+	j.ReleaseLibNetInfo.FuncSymbol.OriginCode = code[0:5]
+	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)
+	//fmt.Println(code, err)
+	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 {
+			fmt.Printf("Decode error at offset 0x%x: %v\n", pc, err)
+			pc++ // Skip this byte and try to decode again
+			continue
+		}
+		//fmt.Printf("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
+		//fmt.Printf("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
+		//fmt.Printf("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
+		}
+		if pc == IO_FD_FDID_SYM_OFFSET {
+			fmt.Printf("Instuction at 0x%x: %v\n", preContext.PC, preContext.Inst)
+			debugFuncSym.IO_fd_fdID = currentData
+			debugFuncSym.IO_fd_fdID.SymName = "<IO_fd_fdID>(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)
+					fmt.Printf("Find %s Target address: 0x%x\n", debugFuncSym.IO_fd_fdID.SymName, targetAddress)
+					debugFuncSym.IO_fd_fdID.TargetAddr = targetAddress
+					// 保存原始数据
+					debugFuncSym.IO_fd_fdID.OriginTargetAddr = targetAddress
+					debugFuncSym.IO_fd_fdID.OriginInst = currentData.Inst
+					j.PreCheck.IoFdCheck = true
+				} 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
+			fmt.Printf("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 = "<NET_Send>(Debug)"
+			fmt.Printf("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 += uint64(inst.Len)
+	}
+	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 {
+			fmt.Printf("Decode error at offset 0x%x: %v\n", pc, err)
+			pc++ // Skip this byte and try to decode again
+			continue
+		}
+		//fmt.Printf("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
+		//fmt.Printf("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
+		//fmt.Printf("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 {
+			fmt.Printf("Instuction at 0x%x: %v\n", preContext.PC, preContext.Inst)
+			debugFuncSym.IO_fd_fdID = currentData
+			debugFuncSym.IO_fd_fdID.SymName = "<IO_fd_fdID>(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)
+					fmt.Printf("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
+						fmt.Println("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
+			//fmt.Println(currentData.IntelInst)
+			//fmt.Printf("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 = "<NET_Send>(Debug)"
+			fmt.Printf("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") {
+					fmt.Printf("Found library %s\n", path)
+					return start, path, nil
+				}
+			}
+		}
+	}
+
+	return 1, "", fmt.Errorf("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 {
+			fmt.Println("size:", sym.Size)
+			return sym, nil
+		}
+	}
+
+	//textSection := elfFile.Section(".text")
+	//if textSection == nil {
+	//	fmt.Println("textSection is null")
+	//	//return nil
+	//}
+	//textSectionData, err := textSection.Data()
+	//if err != nil {
+	//	fmt.Println("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 {
+		log.Fatalf("Error finding base addresses: %v", err)
+		return err
+	}
+	fmt.Printf("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 {
+		log.Fatalf("Error getting function offset: %v", err)
+		return err
+	}
+	fmt.Printf("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) findDebugFuncContextFromLibPath() error {
+	libName := j.DebugLibNetInfo.LibName
+
+	// 获取release库的基地址
+	baseAddress, libPath, err := j.findLibBaseFromProcMaps(libName)
+	fmt.Println(libPath)
+	functionName := j.DebugLibNetInfo.FuncSymbol.SymName
+	j.DebugLibNetInfo.LibPath = libPath
+	if err != nil {
+		log.Fatalf("Error finding base addresses: %v", err)
+		return err
+	}
+
+	// 获取函数的偏移量
+	functionSym, err := j.getFunctionOffset(libPath, functionName)
+	// 计算函数的实际内存地址
+	j.DebugLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value
+	j.DebugLibNetInfo.FuncSymbol.SymSize = functionSym.Size
+
+	if err != nil {
+		log.Fatalf("Error getting function offset: %v", err)
+		return err
+	}
+	fmt.Printf("Actual memory address of %s at base 0x%x: 0x%x\n", functionName, baseAddress, j.DebugLibNetInfo.FuncSymbol.SymAddr)
+
+	callAddress, err := j.findDebugAddressInfoFromMem()
+	if err != nil || callAddress == 0 {
+		log.Printf("Error finding first CALL instuction: %v", err)
+		return err
+	}
+	fmt.Printf("First CALL instuction o1f %s at base 0x%x: 0x%x\n", functionName, baseAddress, callAddress)
+	return nil
+}
+
+func printCodeData(data LibNetInfo) {
+	fmt.Printf("========FuncEnter <0x%x> \n", data.FuncSymbol.SymAddr)
+	fmt.Printf("Name %s | CurrentAddr:<0x%x>\nOrigin-TargetAddr:<0x%x> | TargetAddr:<0x%x> \nOrigin-Inst:<%s> | Inst:<%s> \n",
+		data.InnerSymbol.IO_fd_fdID.SymName,
+		data.InnerSymbol.IO_fd_fdID.SymAddr,
+		data.InnerSymbol.IO_fd_fdID.OriginTargetAddr,
+		data.InnerSymbol.IO_fd_fdID.TargetAddr,
+		x86asm.IntelSyntax(data.InnerSymbol.IO_fd_fdID.OriginInst, 0, nil),
+		x86asm.IntelSyntax(data.InnerSymbol.IO_fd_fdID.Inst, 0, nil))
+	fmt.Printf("\nName %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,
+		x86asm.IntelSyntax(data.InnerSymbol.NET_Send.OriginInst, 0, nil),
+		x86asm.IntelSyntax(data.InnerSymbol.NET_Send.Inst, 0, nil))
+	fmt.Println("========")
+}
+
+func (j *JvmInjector) jvmInjectLib() int {
+	dll := C.CString(j.DebugLibNetInfo.LibPath) // 替换为实际的DLL路径
+	defer C.free(unsafe.Pointer(dll))           // 确保在使用完字符串后释放内存
+	result := C.cw_inject_library(C.int(j.Pid), C.int(1), dll)
+	fmt.Printf("Result: %d\n", result)
+	return int(result)
+}
+
+func (j *JvmInjector) validateAllPreCheck() bool {
+	return j.PreCheck.NeedInjectionCheck && j.PreCheck.LoadingCheck && j.PreCheck.IoFdCheck && j.PreCheck.NetSendFuncCheck
+}
+
+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, (*[8]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, (*[8]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
+}
+
+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)
+//	fmt.Println(err)
+//}
+
+func JvmInject(jvmInjector *JvmInjector) error {
+	pid := jvmInjector.Pid
+	var err error
+	err = jvmInjector.findReleaseFuncContextFromLibPath()
+
+	// Debug版本无需修改寄存器
+	if jvmInjector.PreCheck.EbpfCanInjection {
+		fmt.Println("Debug version loaded.")
+		return nil
+	}
+
+	if err != nil {
+		log.Fatalf("Error message during release phase: %v", err)
+	}
+
+	// 原指令校验通过
+	if !jvmInjector.PreCheck.NeedInjectionCheck {
+		return err
+	}
+	printCodeData(jvmInjector.ReleaseLibNetInfo)
+	_type, _, err := jvmInjector.findLibBaseFromProcMaps(jvmInjector.DebugLibNetInfo.LibName)
+	if err != nil {
+		// load so
+		if _type == 1 {
+			fmt.Println(err, "Load it.")
+			if jvmInjector.jvmInjectLib() == 0 {
+				jvmInjector.PreCheck.LoadingCheck = true
+			} else {
+				return err
+			}
+		}
+	} else {
+		jvmInjector.PreCheck.LoadingCheck = true
+	}
+
+	if !jvmInjector.PreCheck.LoadingCheck {
+		fmt.Println("Failed load so")
+		return err
+	}
+
+	err = jvmInjector.findDebugFuncContextFromLibPath()
+	if err != nil {
+		log.Fatalf("Failed to find debug Context: %v", err)
+	}
+
+	if !jvmInjector.validateAllPreCheck() {
+		fmt.Println("failed validateAllPreCheck ")
+		return err
+	}
+	// 修改
+	debugFuncEnterAddr := uintptr(jvmInjector.DebugLibNetInfo.FuncSymbol.SymAddr)
+	debugIoFdAddr := uintptr(jvmInjector.DebugLibNetInfo.InnerSymbol.IO_fd_fdID.SymAddr)
+	debugNetSendAddr := uintptr(jvmInjector.DebugLibNetInfo.InnerSymbol.NET_Send.SymAddr)
+
+	originFuncEnterAddr := uintptr(jvmInjector.ReleaseLibNetInfo.FuncSymbol.SymAddr)
+	ioFdReleaseTargetAddr := uintptr(jvmInjector.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID.TargetAddr)
+	netSendReleaseTargetAddr := uintptr(jvmInjector.ReleaseLibNetInfo.InnerSymbol.NET_Send.TargetAddr)
+
+	fmt.Printf("<0x%x> -> <0x%x>\n", originFuncEnterAddr, debugFuncEnterAddr)
+	fmt.Printf("<0x%x> -> <0x%x>\n", debugIoFdAddr, ioFdReleaseTargetAddr)
+	fmt.Printf("<0x%x> -> <0x%x>\n", debugNetSendAddr, netSendReleaseTargetAddr)
+
+	// 附加到目标进程
+	err = syscall.PtraceAttach(pid)
+	if err != nil {
+		fmt.Printf("ptrace ATTACH: %v", err)
+	}
+
+	// 等待目标进程停止
+	if _, err := syscall.Wait4(pid, nil, 0, nil); err != nil {
+		fmt.Printf("wait4: %v", err)
+		return err
+	}
+	time.Now().UnixNano()
+	// 修改目标的内存
+	err = modifyIoFdTargetAddr(pid, debugIoFdAddr, ioFdReleaseTargetAddr)
+	if err != nil {
+		fmt.Println(err)
+		return err
+	}
+
+	err = modifyNetSetTargetAddr(pid, debugNetSendAddr, netSendReleaseTargetAddr)
+	fmt.Println(err)
+	if err != nil {
+		fmt.Println(err)
+		return err
+	}
+	// 二次效验 读取并验证地址
+	_, err = jvmInjector.checkDebugFuncSymAfterChange()
+	printCodeData(jvmInjector.ReleaseLibNetInfo)
+	printCodeData(jvmInjector.DebugLibNetInfo)
+
+	// 效验目标函数内地址是否与预期一致
+	if !jvmInjector.validateAllModifyCheck() && err == nil {
+		return err
+	}
+	// 更新函数入口
+	err = modifyReleaseFuncEnter(pid, originFuncEnterAddr, debugFuncEnterAddr)
+	if err != nil {
+		fmt.Println(err)
+		return err
+	}
+	// 校验jmp地址修改正确
+	err = jvmInjector.checkReleaseFuncSymAfterChange()
+	if err != nil {
+		fmt.Println(err)
+		if len(jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode) == 5 {
+			err = restoreOriginalInstructions(pid, originFuncEnterAddr, jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode)
+			if err != nil {
+				fmt.Println(err)
+				return err
+			}
+		}
+	}
+
+	// 恢复执行
+	if err = syscall.PtraceDetach(pid); err != nil {
+		fmt.Printf("ptrace DETACH: %v", err)
+		return err
+	}
+	return nil
+}

+ 1104 - 0
ebpftracer/tracer/inject/inject_linux_arm64.go

@@ -0,0 +1,1104 @@
+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 <stdlib.h>
+*/
+import "C"
+
+import (
+	"bufio"
+	"debug/elf"
+	"fmt"
+	"golang.org/x/arch/arm64/arm64asm"
+	"golang.org/x/arch/x86/x86asm"
+	"log"
+	"os"
+	"strings"
+	"syscall"
+	//"time"
+	"unsafe"
+)
+
+const (
+	IO_FD_FDID_SYM_OFFSET = 192
+	NET_SEND_SYM_OFFSET   = 776
+)
+const (
+	OFFSET_0  = 0
+	OFFSET_16 = 1
+	OFFSET_32 = 2
+	OFFSET_48 = 3
+	PC_START  = 56
+
+	BLR_X18 = 0xd63f0240
+)
+
+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 JvmInjector struct {
+	Pid               int
+	ReleaseLibNetInfo LibNetInfo
+	DebugLibNetInfo   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
+	}
+}
+
+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
+	}
+	//pc := uint64(0)
+	//add := 0
+	//bl := 0
+	//callCount := 0
+	//preContext := InstInfo{}
+	fmt.Println(j.ReleaseLibNetInfo.FuncSymbol.SymSize)
+	/*
+		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
+	*/
+	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
+	}
+
+	/*	for pc < j.ReleaseLibNetInfo.FuncSymbol.SymSize {
+
+			inst, err := arm64asm.Decode(code[pc:])
+			if err != nil {
+				fmt.Printf("Decode error at offset 0x%x: %v\n", pc, err)
+				pc++ // Skip this byte and try to decode again
+				continue
+			}
+			fmt.Printf("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst)
+			//fmt.Printf("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
+			//fmt.Printf("Decoded GNU instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.GNUSyntax(Inst, 0, nil))
+			currentData := InstInfo{
+				PC:      pc,
+				SymAddr: funcAbsAddress + pc,
+				Inst:    inst,
+				//IntelInst: x86asm.IntelSyntax(inst, 0, nil),
+			}
+			if pc == 0 && (inst.Op == arm64asm.B || inst.Op == arm64asm.BL) {
+				// 已经被修改过的首指令
+				return fmt.Errorf("Inst already modified. <%s>", arm64asm.GNUSyntax(inst))
+			}
+			if pc == 0 {
+				j.ReleaseLibNetInfo.FuncSymbol.PC = currentData.PC
+				j.ReleaseLibNetInfo.FuncSymbol.Inst = currentData.Inst
+				j.ReleaseLibNetInfo.FuncSymbol.OriginInst = currentData.Inst
+			}
+
+			if pc == 88 && inst.Op == arm64asm.STR {
+				fmt.Println(inst.Args[0])
+				fmt.Println(inst.Args[1], inst.Args[1].(arm64asm.MemImmediate).Base, inst.Args[1].(arm64asm.MemImmediate).Mode)
+				fmt.Println("inst.Args[0]", inst.Args[0])
+				fmt.Println("arm64asm.W5", arm64asm.W5)
+				fmt.Println(inst.Args[0] == arm64asm.W5)
+				if inst.Args[0].String() == arm64asm.W5.String() {
+					if src, okSrc := inst.Args[1].(arm64asm.MemImmediate); okSrc {
+						base := arm64asm.Reg(src.Base)
+						if base == arm64asm.X0 {
+							j.PreCheck.EbpfCanInjection = true
+							return nil
+						}
+					}
+				}
+			}
+
+			// IO_fd_fdID
+			if inst.Op == arm64asm.ADD {
+				if add == 1 && preContext.Inst.Op == arm64asm.ADRP && inst.Args[0].String() == arm64asm.X2.String() {
+					fmt.Println("inst.Args[0]", inst.Args[0])
+					fmt.Println("arm64asm.X2", arm64asm.X2)
+
+					if pcRelAddr, okAddr := preContext.Inst.Args[1].(arm64asm.PCRel); okAddr {
+
+						fmt.Println("preContext.Inst", preContext.Inst)
+						fmt.Println("preContext.Inst.args", preContext.Inst.Args)
+						// 掩码:高位全1,低12位为0
+						clearedAddress := preContext.SymAddr & 0xFFFFFFFFFFFFF000
+
+						fmt.Printf("preContext.Inst.args %d \n", clearedAddress+uint64(pcRelAddr))
+						fmt.Println("inst", inst)
+						fmt.Println("inst.Args", inst.Args[2].(arm64asm.ImmShift))
+
+						// 去掉前缀 "#",并提取十六进制部分
+						hexStr := strings.TrimPrefix(inst.Args[2].(arm64asm.ImmShift).String(), "#0x")
+						// 将十六进制字符串转换为整数
+						decimalValue, err := strconv.ParseUint(hexStr, 16, 32)
+						if err != nil {
+							return fmt.Errorf("Error parsing hex string: %v\n", err)
+						}
+						// 打印十进制值
+						fmt.Printf("Decimal value: %d\n", decimalValue)
+						fmt.Printf("preContext.Inst.args %d \n", clearedAddress+uint64(pcRelAddr)+decimalValue)
+						targetAddress := clearedAddress + uint64(pcRelAddr) + decimalValue
+						releaseFuncSym.IO_fd_fdID_ADRP = preContext
+						releaseFuncSym.IO_fd_fdID_ADRP.SymName = "<IO_fd_fdID ADRP>(Release)"
+						releaseFuncSym.IO_fd_fdID_ADRP.TargetAddr = targetAddress
+
+						releaseFuncSym.IO_fd_fdID_ADD = currentData
+						releaseFuncSym.IO_fd_fdID_ADD.SymName = "<IO_fd_fdID ADD>(Release)"
+						releaseFuncSym.IO_fd_fdID_ADD.TargetEnc = currentData.Inst.Enc
+					}
+				}
+				add++
+			}
+
+			if inst.Op == arm64asm.BL {
+
+				//offset = ( target- pc ) / 4
+				// enc = offset +0x94000000
+
+				if bl == 0 {
+					if pcRelAddr, okAddr := inst.Args[0].(arm64asm.PCRel); okAddr {
+						releaseFuncSym.NET_Send = currentData
+						releaseFuncSym.NET_Send.SymName = "<NET_Send>(Release)"
+						targetAddress := currentData.SymAddr + uint64(pcRelAddr)
+						releaseFuncSym.NET_Send.TargetAddr = targetAddress
+					}
+				}
+				bl++
+			}
+			preContext = InstInfo{
+				PC:      pc,
+				SymAddr: funcAbsAddress + pc,
+				Inst:    inst,
+			}
+			pc += 4
+		}
+	*/
+	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)
+	//fmt.Println(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 {
+			fmt.Printf("Decode error at offset 0x%x: %v\n", pc, err)
+			pc++ // Skip this byte and try to decode again
+			continue
+		}
+		//fmt.Printf("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
+		//fmt.Printf("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
+		//fmt.Printf("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 = "<IO_fd_fdID ADD>(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 = "<IO_fd_fdID ADRP>(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
+			//fmt.Printf("4 call Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst)
+			//relOffset, ok := (inst.Args[0].(x86asm.Rel))
+			fmt.Println(inst)
+			fmt.Println(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 = "<NET_Send>(Debug)"
+			//fmt.Printf("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 {
+//			fmt.Printf("Decode error at offset 0x%x: %v\n", pc, err)
+//			pc++ // Skip this byte and try to decode again
+//			continue
+//		}
+//		//fmt.Printf("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
+//		//fmt.Printf("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
+//		//fmt.Printf("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 {
+//			fmt.Printf("Instuction at 0x%x: %v\n", preContext.PC, preContext.Inst)
+//			debugFuncSym.IO_fd_fdID = currentData
+//			debugFuncSym.IO_fd_fdID.SymName = "<IO_fd_fdID>(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)
+//					fmt.Printf("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
+//						fmt.Println("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
+//			//fmt.Println(currentData.IntelInst)
+//			//fmt.Printf("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 = "<NET_Send>(Debug)"
+//			fmt.Printf("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") {
+					fmt.Printf("Found library %s\n", path)
+					return start, path, nil
+				}
+			}
+		}
+	}
+
+	return 1, "", fmt.Errorf("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 {
+			fmt.Println("size:", sym.Size)
+			return sym, nil
+		}
+	}
+
+	//textSection := elfFile.Section(".text")
+	//if textSection == nil {
+	//	fmt.Println("textSection is null")
+	//	//return nil
+	//}
+	//textSectionData, err := textSection.Data()
+	//if err != nil {
+	//	fmt.Println("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 {
+		log.Fatalf("Error finding base addresses: %v", err)
+		return err
+	}
+	fmt.Printf("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 {
+		log.Fatalf("Error getting function offset: %v", err)
+		return err
+	}
+	fmt.Printf("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) findDebugFuncContextFromLibPath() error {
+	libName := j.DebugLibNetInfo.LibName
+
+	// 获取release库的基地址
+	baseAddress, libPath, err := j.findLibBaseFromProcMaps(libName)
+	fmt.Println(libPath)
+	functionName := j.DebugLibNetInfo.FuncSymbol.SymName
+	j.DebugLibNetInfo.LibPath = libPath
+	if err != nil {
+		log.Fatalf("Error finding base addresses: %v", err)
+		return err
+	}
+
+	// 获取函数的偏移量
+	functionSym, err := j.getFunctionOffset(libPath, functionName)
+	// 计算函数的实际内存地址
+	j.DebugLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value
+	j.DebugLibNetInfo.FuncSymbol.SymSize = functionSym.Size
+
+	if err != nil {
+		log.Fatalf("Error getting function offset: %v", err)
+		return err
+	}
+	fmt.Printf("Actual memory address of %s at base 0x%x: 0x%x\n", functionName, baseAddress, j.DebugLibNetInfo.FuncSymbol.SymAddr)
+
+	_, err = j.findDebugAddressInfoFromMem()
+	if err != nil {
+		//log.Printf("Error finding first CALL instuction: %v", err)
+		return err
+	}
+	//fmt.Printf("First CALL instuction o1f %s at base 0x%x: 0x%x\n", functionName, baseAddress, callAddress)
+	return nil
+}
+
+func printCodeData(data LibNetInfo) {
+	fmt.Printf("========FuncEnter <0x%x> \n", data.FuncSymbol.SymAddr)
+	//fmt.Printf("%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)
+	//fmt.Printf("\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)
+	//fmt.Printf("\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))
+	fmt.Println("========")
+}
+
+func (j *JvmInjector) jvmInjectLib() int {
+	dll := C.CString(j.DebugLibNetInfo.LibPath) // 替换为实际的DLL路径
+	defer C.free(unsafe.Pointer(dll))           // 确保在使用完字符串后释放内存
+	result := C.cw_inject_library(C.int(j.Pid), C.int(1), dll)
+	fmt.Printf("Result: %d\n", result)
+	return int(result)
+}
+
+func (j *JvmInjector) validateAllPreCheck() bool {
+	return j.PreCheck.NeedInjectionCheck && j.PreCheck.LoadingCheck && j.PreCheck.IoFdCheck && j.PreCheck.NetSendFuncCheck
+}
+
+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 buildNopEnc(pid int, nopAddr, originAddr uintptr) error {
+
+	// 指令不为空则返回
+	originalData, err := readData(pid, nopAddr)
+	if err != nil {
+		return err
+	}
+	fmt.Printf("0x%016x\n", originalData) // 16个字符宽度,左边补0
+
+	if originalData != 0xd503201f {
+		return fmt.Errorf("The cw enc not nop <0x%016x>\n", originAddr)
+	}
+
+	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
+	}
+	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+4+36, 0xd65f03c0)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func setEncByAddr(pid int, soAddr, originAddr uintptr) error {
+	// 获取目标地址处的数据
+	originalData, err := readData(pid, originAddr)
+	if err != nil {
+		return err
+	}
+	// 更新数据中的目标偏移
+	err = writeData(pid, soAddr, 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
+}
+
+/*
+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, nopAddr uint64, origin uintptr) error {
+	// Original 64-bit address
+	blrAddr := nopAddr
+	// 拆分四段地址
+	// 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
+
+	err := setEnc(pid, origin+56, buildArm64Enc(part1, OFFSET_0))
+	if err != nil {
+		return err
+	}
+	err = setEnc(pid, origin+60, buildArm64Enc(part2, OFFSET_16))
+	if err != nil {
+		return err
+	}
+	err = setEnc(pid, origin+64, buildArm64Enc(part3, OFFSET_32))
+	if err != nil {
+		return err
+	}
+	err = setEnc(pid, origin+68, buildArm64Enc(part4, OFFSET_48))
+	if err != nil {
+		return err
+	}
+
+	err = setEnc(pid, origin+72, BLR_X18)
+	if err != nil {
+		return err
+	}
+	fmt.Printf("# 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)
+	fmt.Printf("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)
+//	fmt.Println(err)
+//}
+
+func JvmInject(jvmInjector *JvmInjector) error {
+	jvmInjector.DebugLibNetInfo.FuncSymbol.SymName = "CW_Java_java_net_SocketOutputStream_socketWrite0"
+	pid := jvmInjector.Pid
+	var err error
+	err = jvmInjector.findReleaseFuncContextFromLibPath()
+
+	fmt.Println(err)
+	// Debug版本无需修改寄存器 TODO 直接使用原函数 需要在ebpf层适配
+	if jvmInjector.PreCheck.EbpfCanInjection {
+		fmt.Println("Debug version loaded.")
+		return nil
+	}
+
+	if err != nil {
+		return err
+	}
+
+	// 原指令校验通过
+	if !jvmInjector.PreCheck.NeedInjectionCheck {
+		return err
+	}
+	printCodeData(jvmInjector.ReleaseLibNetInfo)
+	_type, _, err := jvmInjector.findLibBaseFromProcMaps(jvmInjector.DebugLibNetInfo.LibName)
+	if err != nil {
+		// load so
+		if _type == 1 {
+			fmt.Println(err, "Start load so.")
+			if jvmInjector.jvmInjectLib() == 0 {
+				jvmInjector.PreCheck.LoadingCheck = true
+			} else {
+				return err
+			}
+		}
+	} else {
+		jvmInjector.PreCheck.LoadingCheck = true
+		fmt.Println(err, "So already loaded.")
+		// TODO 指令校验成功后 return nil
+		return fmt.Errorf("So already loaded.")
+	}
+
+	if !jvmInjector.PreCheck.LoadingCheck {
+		fmt.Println("Failed load so")
+		return err
+	}
+
+	err = jvmInjector.findDebugFuncContextFromLibPath()
+	if err != nil {
+		log.Fatalf("Failed to find debug Context: %v", err)
+	}
+	printCodeData(jvmInjector.DebugLibNetInfo)
+
+	//if !jvmInjector.validateAllPreCheck() {
+	//	fmt.Println("failed validateAllPreCheck ")
+	//	return err
+	//}
+	//// 修改
+	debugFuncEnterAddr := uintptr(jvmInjector.DebugLibNetInfo.FuncSymbol.SymAddr)
+	//debugIoFdAddr := uintptr(jvmInjector.DebugLibNetInfo.InnerSymbol.IO_fd_fdID.SymAddr)
+	//debugNetSendAddr := uintptr(jvmInjector.DebugLibNetInfo.InnerSymbol.NET_Send.SymAddr)
+	//
+	originFuncEnterAddr := uintptr(jvmInjector.ReleaseLibNetInfo.FuncSymbol.SymAddr)
+	//ioFdReleaseTargetAddr := uintptr(jvmInjector.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID.TargetAddr)
+	//netSendReleaseTargetAddr := uintptr(jvmInjector.ReleaseLibNetInfo.InnerSymbol.NET_Send.TargetAddr)
+	//
+	//fmt.Printf("<0x%x> -> <0x%x>\n", originFuncEnterAddr, debugFuncEnterAddr)
+	//fmt.Printf("<0x%x> -> <0x%x>\n", debugIoFdAddr, ioFdReleaseTargetAddr)
+	//fmt.Printf("<0x%x> -> <0x%x>\n", debugNetSendAddr, netSendReleaseTargetAddr)
+	//
+	// 附加到目标进程
+	err = syscall.PtraceAttach(pid)
+	if err != nil {
+		fmt.Printf("ptrace ATTACH: %v", err)
+	}
+	//
+	// 等待目标进程停止
+	if _, err := syscall.Wait4(pid, nil, 0, nil); err != nil {
+		fmt.Printf("wait4: %v", err)
+		return err
+	}
+	// 保存原始指令到并扩充新指令
+	err = buildNopEnc(pid, debugFuncEnterAddr, originFuncEnterAddr)
+	if err != nil {
+		fmt.Println(err)
+		return err
+	}
+
+	//
+	//err = modifyNetSetTargetAddr(pid, debugNetSendAddr, netSendReleaseTargetAddr)
+	//fmt.Println(err)
+	//if err != nil {
+	//	fmt.Println(err)
+	//	return err
+	//}
+	// todo 二次效验 读取并验证地址
+	//_, err = jvmInjector.checkDebugFuncSymAfterChange()
+	//printCodeData(jvmInjector.ReleaseLibNetInfo)
+	//printCodeData(jvmInjector.DebugLibNetInfo)
+	//
+	//// todo 效验目标函数内地址是否与预期一致
+	//if !jvmInjector.validateAllModifyCheck() && err == nil {
+	//	return err
+	//}
+
+	//变更原指令 长跳转到新地址
+	err = modifyOriginEnc(pid, uint64(debugFuncEnterAddr), originFuncEnterAddr)
+
+	//// 更新函数入口
+	//err = modifyReleaseFuncEnter(pid, originFuncEnterAddr, debugFuncEnterAddr)
+	//if err != nil {
+	//	fmt.Println(err)
+	//	return err
+	//}
+	//// 校验jmp地址修改正确
+	//err = jvmInjector.checkReleaseFuncSymAfterChange()
+	//if err != nil {
+	//	fmt.Println(err)
+	//	if len(jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode) == 5 {
+	//		err = restoreOriginalInstructions(pid, originFuncEnterAddr, jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode)
+	//		if err != nil {
+	//			fmt.Println(err)
+	//			return err
+	//		}
+	//	}
+	//}
+	//
+	// 恢复执行
+	if err = syscall.PtraceDetach(pid); err != nil {
+		fmt.Printf("ptrace DETACH: %v", err)
+		return err
+	}
+	return nil
+}

BIN
ebpftracer/tracer/inject/lib/libhotpatch_amd64.a


BIN
ebpftracer/tracer/inject/lib/libhotpatch_arm64.a