|
|
@@ -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
|
|
|
+}
|