|
@@ -0,0 +1,445 @@
|
|
|
|
|
+package aotinject
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+#cgo CFLAGS: -I ../inject/include
|
|
|
|
|
+#cgo amd64 LDFLAGS: ${SRCDIR}/../inject/lib/libhotpatch_amd64.a
|
|
|
|
|
+#cgo arm64 LDFLAGS: ${SRCDIR}/../inject/lib/libhotpatch_arm64.a
|
|
|
|
|
+#include "hotpatch.h"
|
|
|
|
|
+#include <stdlib.h>
|
|
|
|
|
+*/
|
|
|
|
|
+import "C"
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "bufio"
|
|
|
|
|
+ "debug/dwarf"
|
|
|
|
|
+ "debug/elf"
|
|
|
|
|
+ "flag"
|
|
|
|
|
+ "fmt"
|
|
|
|
|
+ "io"
|
|
|
|
|
+ "log"
|
|
|
|
|
+ "os"
|
|
|
|
|
+ "strconv"
|
|
|
|
|
+ "strings"
|
|
|
|
|
+ "syscall"
|
|
|
|
|
+ "unsafe"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+func InjectLib(pid int, libPath string) int {
|
|
|
|
|
+ dll := C.CString(libPath) // 替换为实际的DLL路径
|
|
|
|
|
+ fmt.Printf("dll: %s\n", libPath)
|
|
|
|
|
+ rootfs := C.CString("")
|
|
|
|
|
+ defer C.free(unsafe.Pointer(dll)) // 确保在使用完字符串后释放内存
|
|
|
|
|
+ result := C.cw_inject_library(C.int(pid), C.int(0), dll, rootfs)
|
|
|
|
|
+ fmt.Printf("Result JVM: %d\n", result)
|
|
|
|
|
+ return int(result)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// readMemory 用于读取指定地址的内存数据
|
|
|
|
|
+func readMemory(pid int, address uint64, size uint64) ([]byte, error) {
|
|
|
|
|
+ memFile := fmt.Sprintf("/proc/%d/mem", 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
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func getFunctionOffsetDBG(libPath, functionName string) (elf.Symbol, error) {
|
|
|
|
|
+ dwarfFile, err := elf.Open(libPath)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return elf.Symbol{}, fmt.Errorf("failed to open libPath %s: %v", libPath, err)
|
|
|
|
|
+ }
|
|
|
|
|
+ dwarfData, err := dwarfFile.DWARF()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return elf.Symbol{}, fmt.Errorf("failed to read DWARF data: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ type uprobesDef struct {
|
|
|
|
|
+ Name string
|
|
|
|
|
+ Offset uint64
|
|
|
|
|
+ EntAddress uint64
|
|
|
|
|
+ RetAddress uint64
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ listEntry := make(map[dwarf.Offset]uprobesDef)
|
|
|
|
|
+ SpecListEntry := []dwarf.Entry{}
|
|
|
|
|
+
|
|
|
|
|
+ entryReader := dwarfData.Reader()
|
|
|
|
|
+
|
|
|
|
|
+ for {
|
|
|
|
|
+ entry, err := entryReader.Next()
|
|
|
|
|
+ if err == io.EOF {
|
|
|
|
|
+ // We've reached the end of DWARF entries
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ log.Println("Error reading entry: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if entry == nil {
|
|
|
|
|
+ log.Println("Warning: a nil entry was returned with no error")
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ // fmt.Printf("-----entry address: %v, %v, %v, %v, %v\n", entry, entry.Val(dwarf.AttrName), entry.Tag, entry.Val(dwarf.AttrLowpc), entry.Val(dwarf.AttrHighpc))
|
|
|
|
|
+ if entry.Tag == dwarf.TagSubprogram {
|
|
|
|
|
+ // fmt.Printf("entry address: %x, %d\n", entry.Offset, entry.Children)
|
|
|
|
|
+ funName, ok := entry.Val(dwarf.AttrName).(string)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ if functionName == funName {
|
|
|
|
|
+ entAddress, ok := entry.Val(dwarf.AttrLowpc).(uint64)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ entAddress = 0
|
|
|
|
|
+ }
|
|
|
|
|
+ retAddress, ok := entry.Val(dwarf.AttrHighpc).(uint64)
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ retAddress = 0
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("Function %s address: %x, %x, %x\n", funName, entAddress, entry.Offset, retAddress)
|
|
|
|
|
+ uprobes := uprobesDef{
|
|
|
|
|
+ Name: funName,
|
|
|
|
|
+ Offset: uint64(entry.Offset),
|
|
|
|
|
+ EntAddress: entAddress,
|
|
|
|
|
+ RetAddress: retAddress,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ listEntry[entry.Offset] = uprobes
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ specAddr, _ := entry.Val(dwarf.AttrSpecification).(dwarf.Offset)
|
|
|
|
|
+ lowpc := entry.Val(dwarf.AttrLowpc)
|
|
|
|
|
+ if lowpc != nil && specAddr > 0 && lowpc.(uint64) > 0 {
|
|
|
|
|
+ SpecListEntry = append(SpecListEntry, *entry)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, v := range SpecListEntry {
|
|
|
|
|
+ specAddr, _ := v.Val(dwarf.AttrSpecification).(dwarf.Offset)
|
|
|
|
|
+ // fmt.Printf("SpecListEntrySpecListEntrySpecListEntry Attach Function: %x\n", specAddr)
|
|
|
|
|
+ _, ok := listEntry[specAddr]
|
|
|
|
|
+ if ok {
|
|
|
|
|
+ vv := listEntry[specAddr]
|
|
|
|
|
+ entAddr := v.Val(dwarf.AttrLowpc)
|
|
|
|
|
+ if entAddr != nil {
|
|
|
|
|
+ vv.EntAddress = entAddr.(uint64)
|
|
|
|
|
+ }
|
|
|
|
|
+ retAddr := v.Val(dwarf.AttrHighpc)
|
|
|
|
|
+ if retAddr != nil {
|
|
|
|
|
+ switch retAddr.(type) {
|
|
|
|
|
+ case uint64:
|
|
|
|
|
+ vv.RetAddress = uint64(retAddr.(uint64))
|
|
|
|
|
+ case int64:
|
|
|
|
|
+ vv.RetAddress = uint64(retAddr.(int64))
|
|
|
|
|
+ default:
|
|
|
|
|
+ fmt.Println("Unknown type")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ listEntry[specAddr] = vv
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, v := range listEntry {
|
|
|
|
|
+ sSize := v.RetAddress
|
|
|
|
|
+ if v.RetAddress > v.EntAddress {
|
|
|
|
|
+ sSize = v.RetAddress - v.EntAddress
|
|
|
|
|
+ }
|
|
|
|
|
+ symbol := elf.Symbol{
|
|
|
|
|
+ Name: v.Name,
|
|
|
|
|
+ Value: v.EntAddress,
|
|
|
|
|
+ Size: 180,
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("Need Attach Function %s address: %x, %x, %d\n", v.Name, v.EntAddress, v.RetAddress, sSize)
|
|
|
|
|
+ return symbol, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ return elf.Symbol{}, fmt.Errorf("function %s not found", functionName)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func 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 中查找函数的地址,如果找不到则从 DynamicSymbols 中查找
|
|
|
|
|
+ symbols, err := elfFile.Symbols()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("Can Not find Symbols: %s, %s, %v, can find from DynamicSymbols\n", libPath, functionName, err)
|
|
|
|
|
+ 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
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return elf.Symbol{}, fmt.Errorf("function %s not found from Symbols", functionName)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// getProcessMapsInfo reads the first line of /proc/<pid>/maps file and returns the memory map as a MemoryMap struct
|
|
|
|
|
+// If a library name is provided, it returns the start address of that library
|
|
|
|
|
+func getProcessMapsInfo(pid int, libraryName ...string) (*ProcessMapsInfo, error) {
|
|
|
|
|
+ file, err := os.Open(fmt.Sprintf("/proc/%d/maps", pid))
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ defer file.Close()
|
|
|
|
|
+
|
|
|
|
|
+ scanner := bufio.NewScanner(file)
|
|
|
|
|
+ for scanner.Scan() {
|
|
|
|
|
+ line := scanner.Text()
|
|
|
|
|
+ fields := strings.Fields(line)
|
|
|
|
|
+ addresses := strings.Split(fields[0], "-")
|
|
|
|
|
+ if len(addresses) != 2 {
|
|
|
|
|
+ return nil, fmt.Errorf("unexpected format in /proc/%d/maps", pid)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ start, err := strconv.ParseUint(addresses[0], 16, 64)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ end, err := strconv.ParseUint(addresses[1], 16, 64)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if len(libraryName) == 0 || (len(fields) > 5 && strings.Contains(fields[5], libraryName[0])) {
|
|
|
|
|
+ return &ProcessMapsInfo{
|
|
|
|
|
+ Start: start,
|
|
|
|
|
+ End: end,
|
|
|
|
|
+ Path: fields[5],
|
|
|
|
|
+ }, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := scanner.Err(); err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil, fmt.Errorf("specified library or process start address not found in /proc/%d/maps", pid)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func GetProcessFunctionInfo(pid int, libPath string, functionName string, libraryName ...string) (*ProcessFunctionInfo, error) {
|
|
|
|
|
+ processMapsInfo, _ := getProcessMapsInfo(pid, libraryName...)
|
|
|
|
|
+
|
|
|
|
|
+ baseAddress := uint64(processMapsInfo.Start)
|
|
|
|
|
+
|
|
|
|
|
+ // functionName 是以 @plt 结尾的函数名,则调用 getFunctionOffsetPLT 获取函数的地址,并且去掉 @plt 后缀
|
|
|
|
|
+ if strings.HasSuffix(functionName, "@plt") {
|
|
|
|
|
+ functionName = functionName[:len(functionName)-4]
|
|
|
|
|
+ sendFunctionNew, _ := getFunctionOffsetPLT(pid, libPath, functionName)
|
|
|
|
|
+ return &ProcessFunctionInfo{
|
|
|
|
|
+ Name: functionName,
|
|
|
|
|
+ Offset: sendFunctionNew.Value,
|
|
|
|
|
+ Start: baseAddress + sendFunctionNew.Value,
|
|
|
|
|
+ Size: sendFunctionNew.Size,
|
|
|
|
|
+ }, nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取函数的偏移量,有限直接从 ELF 文件中获取,如果失败则从 DWARF 文件中获取
|
|
|
|
|
+ functionSym, err := getFunctionOffset(libPath, functionName)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("Error getting function offset: %v, now to find dbg %s\n", err, libPath+".dbg")
|
|
|
|
|
+ functionSym, err = getFunctionOffsetDBG(libPath+".dbg", functionName)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("Error getting function offset from DWARF file: %v\n", err)
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("get ProcessFunctionInfo: 0x%x, 0x%x\n", baseAddress, functionSym.Value)
|
|
|
|
|
+ funRelAddr := functionSym.Value
|
|
|
|
|
+ if functionSym.Value < baseAddress {
|
|
|
|
|
+ funRelAddr += baseAddress
|
|
|
|
|
+ }
|
|
|
|
|
+ return &ProcessFunctionInfo{
|
|
|
|
|
+ Name: functionSym.Name,
|
|
|
|
|
+ Offset: functionSym.Value,
|
|
|
|
|
+ Start: funRelAddr,
|
|
|
|
|
+ Size: functionSym.Size,
|
|
|
|
|
+ }, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func AotInject(aotInjector AOTInjector) (int, error) {
|
|
|
|
|
+ isInject := false
|
|
|
|
|
+
|
|
|
|
|
+ // lib 注入
|
|
|
|
|
+ cwLibraryInfo, err := getProcessMapsInfo(aotInjector.PID, aotInjector.CWLibName)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("Not Find Lib %s: Now to InjectLib: %v\n", aotInjector.CWLibName, err)
|
|
|
|
|
+ InjectLib(aotInjector.PID, aotInjector.CWLibPath)
|
|
|
|
|
+ cwLibraryInfo, err = getProcessMapsInfo(aotInjector.PID, aotInjector.CWLibName)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("InjectLib %s Err: %v\n", aotInjector.CWLibName, err)
|
|
|
|
|
+ return 0, fmt.Errorf("InjectLib %s Err: %v", aotInjector.CWLibName, err)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ isInject = true
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("find %s Lib Start: %x, End: %x, Path: %s\n", aotInjector.CWLibName, cwLibraryInfo.Start, cwLibraryInfo.End, cwLibraryInfo.Path)
|
|
|
|
|
+ // 查找 cwFunctionName 函数的偏移量
|
|
|
|
|
+ cwSym, _ := GetProcessFunctionInfo(aotInjector.PID, cwLibraryInfo.Path, aotInjector.CWFunctionName, aotInjector.CWLibName)
|
|
|
|
|
+ // 打印 cwFunctionName 函数的偏移量
|
|
|
|
|
+ fmt.Printf("%s: addr %x, size %d\n", aotInjector.CWFunctionName, cwSym.Start, cwSym.Size)
|
|
|
|
|
+
|
|
|
|
|
+ if isInject == true {
|
|
|
|
|
+ fmt.Printf("cwLibrary is already Injected, to find hookOffset\n")
|
|
|
|
|
+ hookOffset, err := findNopFunctionHookOffset(aotInjector.PID, cwSym)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("findNopFunctionHookOffset Err: %v Need Inject\n", err)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ fmt.Printf("findNopFunctionHookOffset: %d[%d]\n", hookOffset, hookOffset+nopEntryOffset)
|
|
|
|
|
+ return hookOffset + nopEntryOffset, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取socketWrite0 和 NET_Send 函数的偏移量
|
|
|
|
|
+ jvmInjectorFunction, err := GetProcessFunctionInfo(aotInjector.PID, aotInjector.InjectLibPath, aotInjector.InjectFunctionName)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("Error getting function %s offset: %v\n", aotInjector.InjectFunctionName, err)
|
|
|
|
|
+ return 0, fmt.Errorf("error getting function %s offset: %v", aotInjector.InjectFunctionName, err)
|
|
|
|
|
+ }
|
|
|
|
|
+ sendFunction, err := GetProcessFunctionInfo(aotInjector.PID, aotInjector.SendFunctionLibPath, aotInjector.SendFunctionName)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("Error getting function %s offset: %v\n", aotInjector.SendFunctionName, err)
|
|
|
|
|
+ return 0, fmt.Errorf("error getting function %s offset: %v", aotInjector.SendFunctionName, err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("find %s, addr: %x, size:%d\n", aotInjector.InjectFunctionName, jvmInjectorFunction.Start, jvmInjectorFunction.Size)
|
|
|
|
|
+ fmt.Printf("find %s, addr: %x, size:%d\n", aotInjector.SendFunctionName, sendFunction.Start, sendFunction.Size)
|
|
|
|
|
+
|
|
|
|
|
+ // 读取 socketWrite0 函数的内存数据并解析 NET_Send 在 socketWrite0 中的调用位置
|
|
|
|
|
+ code, err := readMemory(aotInjector.PID, jvmInjectorFunction.Start, jvmInjectorFunction.Size)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("Error reading jvmInjectorFunction memory: %v\n", err)
|
|
|
|
|
+ return 0, fmt.Errorf("error reading jvmInjectorFunction memory: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ // 打印 socketWrite0 函数的内存数据
|
|
|
|
|
+ fmt.Printf("socketWrite0 code: %v\n", code)
|
|
|
|
|
+ SendFunctionAbsOffset, SendFunctionRelOffset, err := findSendFunctionNameAddr(jvmInjectorFunction.Start, code, aotInjector.SendFunctionName, sendFunction.Start)
|
|
|
|
|
+
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("findSendFunctionNameAddr Err: %v\n", err)
|
|
|
|
|
+ return 0, fmt.Errorf("findSendFunctionNameAddr Err: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("find %s : SendFunctionAbsOffset:%x, SendFunctionRelOffset: %d\n", aotInjector.SendFunctionName, SendFunctionAbsOffset, SendFunctionRelOffset)
|
|
|
|
|
+ // 尝试获取 NET_Send 附近的数据凑够 17 个字节,用于长跳转到 libmylib 中
|
|
|
|
|
+ instMemStruct, err := findMemForLongJump(jvmInjectorFunction.Start, code, aotInjector.SendFunctionName, SendFunctionAbsOffset)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("findMemForLongJump Err: %v\n", err)
|
|
|
|
|
+ return 0, fmt.Errorf("findMemForLongJump Err: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ // 打印 instMemStruct 结构体的内容
|
|
|
|
|
+ fmt.Printf("instMemStruct: %v\n", instMemStruct)
|
|
|
|
|
+
|
|
|
|
|
+ // 生成长跳指令,跳转到 libmylib 中的 cwFunctionName 函数的+12地址
|
|
|
|
|
+ jumpCode := generateLongJumpCode(cwSym.Start+nopEntryOffset, len(instMemStruct.CodeArray), true)
|
|
|
|
|
+ // 使用 parseAndPrintInstructions打印 jumpCode 的内容
|
|
|
|
|
+ fmt.Printf("jumpCode: %v\n", jumpCode)
|
|
|
|
|
+ parseAndPrintInstructions(jumpCode)
|
|
|
|
|
+ // 生成新的指令,用于替换原来的指令,一个参数是原来的指令 instCodeArray,另一个参数是跳转回去的地址,第三个参数是原始 Send 函数的地址,第四个参数是在哪个指令前插入自定义指令
|
|
|
|
|
+ newCode, hookOffset := generateNewCode(instMemStruct.InstCodeArray, instMemStruct.InstStartAddr+jumpBackAddrOffset, sendFunction.Start, instMemStruct.InsertIndex)
|
|
|
|
|
+ if hookOffset == 0 {
|
|
|
|
|
+ fmt.Printf("generateNewCode Err: %v\n", instMemStruct)
|
|
|
|
|
+ return 0, fmt.Errorf("generateNewCode Err: %v", instMemStruct)
|
|
|
|
|
+ }
|
|
|
|
|
+ // 打印 hookIndex
|
|
|
|
|
+ fmt.Printf("ebpf should hookIndex: %d[%d]\n", hookOffset, nopEntryOffset+hookOffset)
|
|
|
|
|
+ // 使用 parseAndPrintInstructions 打印 newCode 的内容
|
|
|
|
|
+ fmt.Printf("newCode: %v\n", newCode)
|
|
|
|
|
+ parseAndPrintInstructions(newCode)
|
|
|
|
|
+ // 使用 ptrace attach 目标进程
|
|
|
|
|
+ fmt.Printf("Attach Process: %d\n", aotInjector.PID)
|
|
|
|
|
+ if err := syscall.PtraceAttach(aotInjector.PID); err != nil {
|
|
|
|
|
+ fmt.Printf("PtraceAttach Err: %v\n", err)
|
|
|
|
|
+ return 0, fmt.Errorf("ptrace attach: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ // 等待目标进程停止
|
|
|
|
|
+ if _, err := syscall.Wait4(aotInjector.PID, nil, 0, nil); err != nil {
|
|
|
|
|
+ fmt.Printf("wait4: %v", err)
|
|
|
|
|
+ if err = syscall.PtraceDetach(aotInjector.PID); err != nil {
|
|
|
|
|
+ fmt.Printf("ptrace DETACH: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0, fmt.Errorf("wait4: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("Ptrace 将newCode使用ptrace写入到目标进程的内存中: %x\n", cwSym.Start+nopEntryOffset)
|
|
|
|
|
+ // 将newCode使用ptrace写入到目标进程的的空白内存中,地址为 cwSym.Start+12
|
|
|
|
|
+ _, err = syscall.PtracePokeData(aotInjector.PID, uintptr(cwSym.Start+nopEntryOffset), newCode)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("PtracePokeData Err: %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("Ptrace 将jumpCode使用ptrace写入到目标进程的内存中: %x\n", instMemStruct.InstStartAddr)
|
|
|
|
|
+ // 将jumpCode使用ptrace写入到目标进程的内存中
|
|
|
|
|
+ _, err = syscall.PtracePokeData(aotInjector.PID, uintptr(instMemStruct.InstStartAddr), jumpCode)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("PtracePokeData Err: %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("Ptrace DETACH: %d\n", aotInjector.PID)
|
|
|
|
|
+ // 恢复执行
|
|
|
|
|
+ if err = syscall.PtraceDetach(aotInjector.PID); err != nil {
|
|
|
|
|
+ fmt.Printf("ptrace DETACH: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return hookOffset + nopEntryOffset, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type AOTInjector struct {
|
|
|
|
|
+ PID int
|
|
|
|
|
+ SendFunctionLibPath string
|
|
|
|
|
+ SendFunctionName string
|
|
|
|
|
+ InjectLibPath string
|
|
|
|
|
+ InjectFunctionName string
|
|
|
|
|
+ CWLibName string
|
|
|
|
|
+ CWFunctionName string
|
|
|
|
|
+ CWLibPath string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+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)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // NETCoreAOTInject
|
|
|
|
|
+ // netCoreAotInjector := AOTInjector{
|
|
|
|
|
+ // PID: pid,
|
|
|
|
|
+ // SendFunctionLibPath: "/data/NET8/CoreAoT/bin/Debug/net8.0/linux-x64/publish/CoreAoT",
|
|
|
|
|
+ // SendFunctionName: "send@plt",
|
|
|
|
|
+ // InjectLibPath: "/data/NET8/CoreAoT/bin/Debug/net8.0/linux-x64/publish/CoreAoT",
|
|
|
|
|
+ // InjectFunctionName: "SystemNative_Send",
|
|
|
|
|
+ // CWLibName: "libmylib.so",
|
|
|
|
|
+ // CWFunctionName: "asmnop",
|
|
|
|
|
+ // CWLibPath: "/data/NET8/CoreAoT/bin/Debug/net8.0/linux-x64/publish/CoreAoT",
|
|
|
|
|
+ // }
|
|
|
|
|
+ // JavaAOTInject
|
|
|
|
|
+ javaAotInjector := AOTInjector{
|
|
|
|
|
+ PID: pid,
|
|
|
|
|
+ SendFunctionLibPath: "/data/roger/ebpfdemo/graalve_demo/SimpleHttpServer",
|
|
|
|
|
+ SendFunctionName: "NET_Send",
|
|
|
|
|
+ InjectLibPath: "/data/roger/ebpfdemo/graalve_demo/SimpleHttpServer",
|
|
|
|
|
+ InjectFunctionName: "Java_java_net_SocketOutputStream_socketWrite0",
|
|
|
|
|
+ CWLibName: "libmylib.so",
|
|
|
|
|
+ CWFunctionName: "asmnop",
|
|
|
|
|
+ CWLibPath: "/data/roger/ebpfdemo/mylib/libmylib.so",
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ hookOffset, err := AotInject(javaAotInjector)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Printf("AotInject Err: %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("AotInject result hookOffset: %d\n", hookOffset)
|
|
|
|
|
+}
|