inject_linux_amd64.go 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. package inject
  2. /*
  3. #cgo CFLAGS: -I include
  4. #cgo amd64 LDFLAGS: ${SRCDIR}/lib/libhotpatch_amd64.a
  5. #cgo arm64 LDFLAGS: ${SRCDIR}/lib/libhotpatch_arm64.a
  6. #include "hotpatch.h"
  7. #include <stdlib.h>
  8. */
  9. import "C"
  10. import (
  11. "bufio"
  12. "debug/elf"
  13. "fmt"
  14. "github.com/coroot/coroot-node-agent/utils"
  15. klog "github.com/sirupsen/logrus"
  16. "golang.org/x/arch/x86/x86asm"
  17. "io"
  18. "os"
  19. "path/filepath"
  20. "strings"
  21. "syscall"
  22. "unsafe"
  23. )
  24. const (
  25. IO_FD_FDID_SYM_OFFSET = 129
  26. NET_SEND_SYM_OFFSET = 518
  27. )
  28. type InstInfo struct {
  29. SymName string
  30. SymSize uint64
  31. SymAddr uint64
  32. PC uint64
  33. Inst x86asm.Inst
  34. OriginInst x86asm.Inst
  35. OriginCode []byte
  36. TargetAddr uint64
  37. OriginTargetAddr uint64
  38. }
  39. type InnerSymbolInfo struct {
  40. IO_fd_fdID InstInfo
  41. NET_Send InstInfo
  42. }
  43. type LibNetInfo struct {
  44. LibName string
  45. LibPath string
  46. FuncSymbol InstInfo
  47. InnerSymbol InnerSymbolInfo
  48. ProcLoadPath string
  49. FileDeleted bool
  50. MapFile string
  51. }
  52. type UprobeData struct {
  53. Offset int
  54. Func string
  55. ELFPath string
  56. }
  57. type JvmInjector struct {
  58. Pid int
  59. ReleaseLibNetInfo LibNetInfo
  60. DebugLibNetInfo LibNetInfo
  61. RecodeInfo LibNetInfo
  62. // 原方法首个指令不为jmp | ReleaseLibNetInfo 读取无异常
  63. PreCheck struct {
  64. NeedInjectionCheck bool // 原指令校验 true表示可以继续执行注入
  65. LoadingCheck bool // true 表示加载成功
  66. IoFdCheck bool // fd地址校验
  67. NetSendFuncCheck bool // netsend校验
  68. EbpfCanInjection bool // 满足则注入ebpf
  69. }
  70. AfterCheck struct {
  71. IoFdCheck bool
  72. NetSendFuncCheck bool
  73. }
  74. Uprobe UprobeData
  75. Rootfs string
  76. }
  77. func (j *JvmInjector) findReleaseAddressInfoFromMem() error {
  78. funcAbsAddress := j.ReleaseLibNetInfo.FuncSymbol.SymAddr
  79. releaseFuncSym := InnerSymbolInfo{}
  80. code, err := j.readMemory(funcAbsAddress, j.ReleaseLibNetInfo.FuncSymbol.SymSize)
  81. if err != nil {
  82. return err
  83. }
  84. pc := uint64(0)
  85. callCount := 0
  86. preContext := InstInfo{}
  87. for pc < uint64(len(code)) {
  88. inst, err := x86asm.Decode(code[pc:], 64)
  89. if err != nil {
  90. fmt.Printf("Decode error at offset 0x%x: %v\n", pc, err)
  91. pc++ // Skip this byte and try to decode again
  92. continue
  93. }
  94. //fmt.Printf("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
  95. //fmt.Printf("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
  96. //fmt.Printf("Decoded GNU instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.GNUSyntax(Inst, 0, nil))
  97. currentData := InstInfo{
  98. PC: pc,
  99. SymAddr: funcAbsAddress + pc,
  100. Inst: inst,
  101. //IntelInst: x86asm.IntelSyntax(inst, 0, nil),
  102. }
  103. if pc == 0 && inst.Op == x86asm.JMP {
  104. // 已经被修改过的首指令
  105. j.PreCheck.EbpfCanInjection = true
  106. j.Uprobe.ELFPath = j.DebugLibNetInfo.LibPath
  107. if j.DebugLibNetInfo.FileDeleted {
  108. j.Uprobe.ELFPath = j.DebugLibNetInfo.MapFile
  109. }
  110. klog.Infof("[inject] Inst already modified. <%s>;elf:%s", x86asm.IntelSyntax(inst, 0, nil), j.Uprobe.ELFPath)
  111. return nil
  112. }
  113. if pc == 0 {
  114. j.ReleaseLibNetInfo.FuncSymbol.PC = currentData.PC
  115. j.ReleaseLibNetInfo.FuncSymbol.Inst = currentData.Inst
  116. j.ReleaseLibNetInfo.FuncSymbol.OriginInst = currentData.Inst
  117. }
  118. if inst.Op == x86asm.MOV {
  119. if dst, okDst := inst.Args[0].(x86asm.Mem); okDst {
  120. if dst.Base == x86asm.RBP {
  121. if src, okSrc := inst.Args[1].(x86asm.Reg); okSrc {
  122. if src == x86asm.R9L {
  123. // debug so
  124. klog.Infof("[inject] release.so is debug.so. <%s>", x86asm.IntelSyntax(inst, 0, nil))
  125. j.PreCheck.EbpfCanInjection = true
  126. j.Uprobe.ELFPath = j.ReleaseLibNetInfo.LibPath
  127. if j.ReleaseLibNetInfo.FileDeleted {
  128. j.Uprobe.ELFPath = j.ReleaseLibNetInfo.MapFile
  129. }
  130. return fmt.Errorf("MOV from register %v to memory %v\n", src, dst)
  131. //return nil
  132. }
  133. }
  134. }
  135. }
  136. //src, okSrc := inst.Args[1].(x86asm.Reg)
  137. //fmt.Println(inst.Args)
  138. //fmt.Printf("Instruction: %+v\n", inst)
  139. //
  140. //fmt.Println(okSrc)
  141. //if okDst && okSrc && dst == x86asm.RBP && src == x86asm.R9L {
  142. // fmt.Println("Instruction is 'mov %r9d, %rbp'")
  143. //}
  144. }
  145. if inst.Op == x86asm.CALL {
  146. //fmt.Printf("Pre instuction at 0x%x: %v\n", preContext.PC, preContext.Inst)
  147. if callCount == 0 {
  148. releaseFuncSym.IO_fd_fdID = preContext
  149. releaseFuncSym.IO_fd_fdID.SymName = "<IO_fd_fdID>(Release)"
  150. preInst := preContext.Inst
  151. fmt.Println(preInst.Op)
  152. fmt.Println((preInst.Args))
  153. // 计算目标地址
  154. if preInst.Op == x86asm.MOV &&
  155. len(preInst.Args) == 4 &&
  156. preInst.Args[0] != nil &&
  157. preInst.Args[0] == x86asm.RDX &&
  158. preInst.Args[1] != nil {
  159. if mem, ok := preInst.Args[1].(x86asm.Mem); ok && mem.Base == x86asm.RIP {
  160. relOffset := mem.Disp // 直接从Mem结构体中读取偏移
  161. targetAddress := preContext.SymAddr + uint64(preInst.Len) + uint64(relOffset)
  162. fmt.Printf("Target address: 0x%x\n", targetAddress)
  163. releaseFuncSym.IO_fd_fdID.TargetAddr = targetAddress
  164. } else {
  165. return fmt.Errorf("The instruction does not use RIP-relative addressing.")
  166. }
  167. } else {
  168. return fmt.Errorf("The decoded instruction is not a MOV to RDX.")
  169. }
  170. //os.Exit(1)
  171. }
  172. callCount++
  173. if callCount == 4 {
  174. releaseFuncSym.NET_Send = currentData
  175. fmt.Printf("4 call Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst)
  176. relOffset, ok := inst.Args[0].(x86asm.Rel)
  177. if !ok {
  178. return fmt.Errorf("The instruction does not use RIP-relative addressing.")
  179. }
  180. targetAddress := currentData.SymAddr + uint64(inst.Len) + uint64(relOffset)
  181. releaseFuncSym.NET_Send.TargetAddr = targetAddress
  182. fmt.Println(releaseFuncSym.NET_Send)
  183. releaseFuncSym.NET_Send.SymName = "<NET_Send>(Release)"
  184. fmt.Printf("Target address: 0x%x\n", targetAddress)
  185. }
  186. }
  187. preContext = InstInfo{
  188. PC: pc,
  189. SymAddr: funcAbsAddress + pc,
  190. Inst: inst,
  191. }
  192. pc += uint64(inst.Len)
  193. }
  194. j.ReleaseLibNetInfo.InnerSymbol = releaseFuncSym
  195. j.ReleaseLibNetInfo.FuncSymbol.OriginCode = code[0:5]
  196. return nil
  197. }
  198. func (j *JvmInjector) findDebugAddressInfoFromMem() (uint64, error) {
  199. funcAbsAddress := j.DebugLibNetInfo.FuncSymbol.SymAddr
  200. debugFuncSym := InnerSymbolInfo{}
  201. //debugFuncSym.FuncSymbol.SymAddr = funcAbsAddress
  202. //offset := sym.Value
  203. size := j.DebugLibNetInfo.FuncSymbol.SymSize
  204. code, err := j.readMemory(funcAbsAddress, size)
  205. //fmt.Println(code, err)
  206. if err != nil {
  207. return 0, err
  208. }
  209. pc := uint64(0)
  210. preContext := InstInfo{}
  211. for pc < uint64(len(code)) {
  212. inst, err := x86asm.Decode(code[pc:], 64)
  213. if err != nil {
  214. fmt.Printf("Decode error at offset 0x%x: %v\n", pc, err)
  215. pc++ // Skip this byte and try to decode again
  216. continue
  217. }
  218. //fmt.Printf("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
  219. //fmt.Printf("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
  220. //fmt.Printf("Decoded GNU instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.GNUSyntax(Inst, 0, nil))
  221. currentData := InstInfo{
  222. PC: pc,
  223. SymAddr: funcAbsAddress + pc,
  224. Inst: inst,
  225. }
  226. if pc == 0 {
  227. j.DebugLibNetInfo.FuncSymbol.PC = currentData.PC
  228. j.DebugLibNetInfo.FuncSymbol.Inst = currentData.Inst
  229. j.DebugLibNetInfo.FuncSymbol.OriginInst = currentData.Inst
  230. }
  231. if pc == IO_FD_FDID_SYM_OFFSET {
  232. fmt.Printf("Instuction at 0x%x: %v\n", preContext.PC, preContext.Inst)
  233. debugFuncSym.IO_fd_fdID = currentData
  234. debugFuncSym.IO_fd_fdID.SymName = "<IO_fd_fdID>(Debug)"
  235. // 计算目标地址
  236. if currentData.Inst.Op == x86asm.MOV &&
  237. len(currentData.Inst.Args) == 4 &&
  238. currentData.Inst.Args[0] != nil &&
  239. currentData.Inst.Args[0] == x86asm.RDX &&
  240. currentData.Inst.Args[1] != nil {
  241. if mem, ok := currentData.Inst.Args[1].(x86asm.Mem); ok && mem.Base == x86asm.RIP {
  242. // 直接从Mem结构体中读取偏移
  243. relOffset := mem.Disp
  244. targetAddress := currentData.SymAddr + uint64(currentData.Inst.Len) + uint64(relOffset)
  245. fmt.Printf("Find %s Target address: 0x%x\n", debugFuncSym.IO_fd_fdID.SymName, targetAddress)
  246. debugFuncSym.IO_fd_fdID.TargetAddr = targetAddress
  247. // 保存原始数据
  248. debugFuncSym.IO_fd_fdID.OriginTargetAddr = targetAddress
  249. debugFuncSym.IO_fd_fdID.OriginInst = currentData.Inst
  250. j.PreCheck.IoFdCheck = true
  251. } else {
  252. return 0, fmt.Errorf("The instruction does not use RIP-relative addressing.")
  253. }
  254. } else {
  255. return 0, fmt.Errorf("The decoded instruction is not a MOV to RDX.")
  256. }
  257. }
  258. if pc == NET_SEND_SYM_OFFSET {
  259. debugFuncSym.NET_Send = currentData
  260. fmt.Printf("4 call Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst)
  261. relOffset, ok := (inst.Args[0].(x86asm.Rel))
  262. if !ok {
  263. return 0, fmt.Errorf("The decoded instruction is not a Rel.")
  264. }
  265. targetAddress := currentData.SymAddr + uint64(inst.Len) + uint64(relOffset)
  266. debugFuncSym.NET_Send.TargetAddr = targetAddress
  267. debugFuncSym.NET_Send.SymName = "<NET_Send>(Debug)"
  268. fmt.Printf("Find %s Target address: 0x%x\n", debugFuncSym.NET_Send.SymName, targetAddress)
  269. // 保存原始数据
  270. debugFuncSym.NET_Send.OriginTargetAddr = targetAddress
  271. debugFuncSym.NET_Send.OriginInst = currentData.Inst
  272. j.PreCheck.NetSendFuncCheck = true
  273. }
  274. preContext = InstInfo{
  275. PC: pc,
  276. SymAddr: funcAbsAddress + pc,
  277. Inst: inst,
  278. }
  279. pc += uint64(inst.Len)
  280. }
  281. j.DebugLibNetInfo.InnerSymbol = debugFuncSym
  282. return 0, nil
  283. }
  284. func (j *JvmInjector) checkDebugFuncSymAfterChange() (uint64, error) {
  285. funcAbsAddress := j.DebugLibNetInfo.FuncSymbol.SymAddr
  286. debugFuncSym := InnerSymbolInfo{}
  287. code, err := j.readMemory(funcAbsAddress, j.DebugLibNetInfo.FuncSymbol.SymSize)
  288. if err != nil {
  289. return 0, err
  290. }
  291. pc := uint64(0)
  292. preContext := InstInfo{}
  293. for pc < uint64(len(code)) {
  294. inst, err := x86asm.Decode(code[pc:], 64)
  295. if err != nil {
  296. fmt.Printf("Decode error at offset 0x%x: %v\n", pc, err)
  297. pc++ // Skip this byte and try to decode again
  298. continue
  299. }
  300. //fmt.Printf("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
  301. //fmt.Printf("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
  302. //fmt.Printf("Decoded GNU instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.GNUSyntax(Inst, 0, nil))
  303. currentData := InstInfo{
  304. PC: pc,
  305. SymAddr: funcAbsAddress + pc,
  306. Inst: inst,
  307. }
  308. if pc == NET_SEND_SYM_OFFSET {
  309. fmt.Printf("Instuction at 0x%x: %v\n", preContext.PC, preContext.Inst)
  310. debugFuncSym.IO_fd_fdID = currentData
  311. debugFuncSym.IO_fd_fdID.SymName = "<IO_fd_fdID>(Debug)"
  312. // 计算目标地址
  313. if currentData.Inst.Op == x86asm.MOV &&
  314. len(currentData.Inst.Args) == 4 &&
  315. currentData.Inst.Args[0] != nil &&
  316. currentData.Inst.Args[0] == x86asm.RDX &&
  317. currentData.Inst.Args[1] != nil {
  318. if mem, ok := currentData.Inst.Args[1].(x86asm.Mem); ok && mem.Base == x86asm.RIP {
  319. // 直接从Mem结构体中读取偏移
  320. relOffset := mem.Disp
  321. targetAddress := currentData.SymAddr + uint64(currentData.Inst.Len) + uint64(relOffset)
  322. fmt.Printf("Find %s Target address: 0x%x\n", debugFuncSym.IO_fd_fdID.SymName, targetAddress)
  323. debugFuncSym.IO_fd_fdID.TargetAddr = targetAddress
  324. //j.PreCheck.IoFdCheck = true
  325. if targetAddress == j.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID.TargetAddr {
  326. j.DebugLibNetInfo.InnerSymbol.IO_fd_fdID.TargetAddr = targetAddress
  327. j.DebugLibNetInfo.InnerSymbol.IO_fd_fdID.Inst = currentData.Inst
  328. j.AfterCheck.IoFdCheck = true
  329. fmt.Println("ok")
  330. }
  331. } else {
  332. return 0, fmt.Errorf("The instruction does not use RIP-relative addressing.")
  333. }
  334. } else {
  335. return 0, fmt.Errorf("The decoded instruction is not a MOV to RDX.")
  336. }
  337. }
  338. if pc == NET_SEND_SYM_OFFSET {
  339. debugFuncSym.NET_Send = currentData
  340. //fmt.Println(currentData.IntelInst)
  341. //fmt.Printf("4 call Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst)
  342. relOffset, ok := (inst.Args[0].(x86asm.Rel))
  343. if !ok {
  344. return 0, fmt.Errorf("The decoded instruction is not a Rel.")
  345. }
  346. targetAddress := currentData.SymAddr + uint64(inst.Len) + uint64(relOffset)
  347. debugFuncSym.NET_Send.TargetAddr = targetAddress
  348. debugFuncSym.NET_Send.SymName = "<NET_Send>(Debug)"
  349. fmt.Printf("Find %s Target address: 0x%x\n", debugFuncSym.NET_Send.SymName, targetAddress)
  350. if targetAddress == j.ReleaseLibNetInfo.InnerSymbol.NET_Send.TargetAddr {
  351. j.DebugLibNetInfo.InnerSymbol.NET_Send.TargetAddr = targetAddress
  352. j.DebugLibNetInfo.InnerSymbol.NET_Send.Inst = currentData.Inst
  353. j.AfterCheck.NetSendFuncCheck = true
  354. }
  355. }
  356. preContext = InstInfo{
  357. PC: pc,
  358. SymAddr: funcAbsAddress + pc,
  359. Inst: inst,
  360. }
  361. pc += uint64(inst.Len)
  362. }
  363. return 0, nil
  364. }
  365. func (j *JvmInjector) checkReleaseFuncSymAfterChange() error {
  366. funcAbsAddress := j.ReleaseLibNetInfo.FuncSymbol.SymAddr
  367. code, err := j.readMemory(funcAbsAddress, j.ReleaseLibNetInfo.FuncSymbol.SymSize)
  368. if err != nil {
  369. return fmt.Errorf("readMemory error in checkReleaseFuncSymAfterChange <%v>", err)
  370. }
  371. inst, err := x86asm.Decode(code[0:], 64)
  372. if err != nil {
  373. return fmt.Errorf("Decode error in checkReleaseFuncSymAfterChange <%v>", err)
  374. }
  375. if inst.Op != x86asm.JMP {
  376. return fmt.Errorf("The instruction does not JMP.")
  377. }
  378. relOffset, ok := inst.Args[0].(x86asm.Rel)
  379. if !ok {
  380. return fmt.Errorf("The instruction does not use RIP-relative addressing.")
  381. }
  382. // 验证target与Debug入口是否一致
  383. targetAddress := funcAbsAddress + uint64(inst.Len) + uint64(relOffset)
  384. if targetAddress != j.DebugLibNetInfo.FuncSymbol.SymAddr {
  385. return fmt.Errorf("Function entry jmp address does not match expectations.")
  386. }
  387. return nil
  388. }
  389. // readMemory 用于读取指定地址的内存数据
  390. func (j *JvmInjector) readMemory(address uint64, size uint64) ([]byte, error) {
  391. memFile := fmt.Sprintf("/proc/%d/mem", j.Pid)
  392. file, err := os.Open(memFile)
  393. if err != nil {
  394. return nil, err
  395. }
  396. defer file.Close()
  397. data := make([]byte, size)
  398. _, err = file.ReadAt(data, int64(address))
  399. if err != nil {
  400. return nil, err
  401. }
  402. return data, nil
  403. }
  404. // findLibraryBases 用于在 /proc/[pid]/maps 文件中查找库的所有基地址
  405. func findLibraryBasesList(pid int, libraryName string, libPath string) ([]uint64, error) {
  406. mapsFile := fmt.Sprintf("/proc/%d/maps", pid)
  407. file, err := os.Open(mapsFile)
  408. if err != nil {
  409. return nil, err
  410. }
  411. defer file.Close()
  412. var bases []uint64
  413. scanner := bufio.NewScanner(file)
  414. for scanner.Scan() {
  415. line := scanner.Text()
  416. if strings.Contains(line, libraryName) && strings.Contains(line, libPath) {
  417. var start, end uint64
  418. fmt.Sscanf(line, "%x-%x", &start, &end)
  419. bases = append(bases, start)
  420. }
  421. }
  422. if len(bases) == 0 {
  423. return nil, fmt.Errorf("library %s not found", libraryName)
  424. }
  425. return bases, nil
  426. }
  427. func (j *JvmInjector) findLibBaseFromProcMaps(libName string) (uint64, string, string, bool, error) {
  428. mapsFile := fmt.Sprintf("/proc/%d/maps", j.Pid)
  429. file, err := os.Open(mapsFile)
  430. if err != nil {
  431. return 0, "", "", false, err
  432. }
  433. defer file.Close()
  434. var start, end uint64
  435. var deleted bool
  436. scanner := bufio.NewScanner(file)
  437. for scanner.Scan() {
  438. line := scanner.Text()
  439. if strings.Contains(line, "/"+libName) {
  440. fmt.Sscanf(line, "%x-%x", &start, &end)
  441. fields := strings.Fields(line)
  442. if len(fields) > 5 {
  443. path := fields[5]
  444. if len(fields) > 6 && fields[6] == "(deleted)" {
  445. deleted = true
  446. }
  447. if strings.HasSuffix(path, ".so") {
  448. klog.Infof("[inject] found library in map %s", path)
  449. return start, path, fmt.Sprintf("/proc/%d/map_files/%s", j.Pid, fields[0]), deleted, nil
  450. }
  451. }
  452. }
  453. }
  454. return 1, "", "", false, fmt.Errorf("library %s not found", libName)
  455. }
  456. func (j *JvmInjector) findLibBaseByPathFromProcMaps(libPath string) (uint64, string, error) {
  457. mapsFile := fmt.Sprintf("/proc/%d/maps", j.Pid)
  458. file, err := os.Open(mapsFile)
  459. if err != nil {
  460. return 0, "", err
  461. }
  462. defer file.Close()
  463. var start, end uint64
  464. scanner := bufio.NewScanner(file)
  465. for scanner.Scan() {
  466. line := scanner.Text()
  467. if strings.Contains(line, libPath) {
  468. fmt.Sscanf(line, "%x-%x", &start, &end)
  469. fields := strings.Fields(line)
  470. if len(fields) > 5 {
  471. path := fields[5]
  472. if strings.HasSuffix(path, ".so") {
  473. return start, path, nil
  474. }
  475. }
  476. }
  477. }
  478. return 1, "", fmt.Errorf("library %s not found in process.", libPath)
  479. }
  480. func (j *JvmInjector) getFunctionOffset(libPath, functionName string) (elf.Symbol, error) {
  481. elfFile, err := elf.Open(libPath)
  482. if err != nil {
  483. return elf.Symbol{}, fmt.Errorf("failed to open ELF file: %v", err)
  484. }
  485. defer elfFile.Close()
  486. symbols, err := elfFile.DynamicSymbols()
  487. if err != nil {
  488. return elf.Symbol{}, fmt.Errorf("failed to read dynamic symbols: %v", err)
  489. }
  490. for _, sym := range symbols {
  491. if sym.Name == functionName {
  492. //fmt.Println("size:", sym.Size)
  493. return sym, nil
  494. }
  495. }
  496. //textSection := elfFile.Section(".text")
  497. //if textSection == nil {
  498. // fmt.Println("textSection is null")
  499. // //return nil
  500. //}
  501. //textSectionData, err := textSection.Data()
  502. //if err != nil {
  503. // fmt.Println("textSectionData error is", err)
  504. // //return nil
  505. //}
  506. //textSectionLen := uint64(len(textSectionData) - 1)
  507. return elf.Symbol{}, fmt.Errorf("function %s not found", functionName)
  508. }
  509. //var PID string
  510. func (j *JvmInjector) InitProg() error {
  511. // 获取release库的基地址
  512. baseAddress, releaseSoFilePathInProc, mapFilesPath, deleted, err := j.findLibBaseFromProcMaps(j.ReleaseLibNetInfo.LibName)
  513. //j.ReleaseLibNetInfo.LibPath = releaseSoFilePathInProc
  514. j.ReleaseLibNetInfo.FileDeleted = deleted
  515. j.ReleaseLibNetInfo.MapFile = mapFilesPath
  516. pJvmlibnetPhysicalPath := j.Rootfs + releaseSoFilePathInProc
  517. j.ReleaseLibNetInfo.LibPath = pJvmlibnetPhysicalPath
  518. if err != nil {
  519. return fmt.Errorf("Error finding base addresses: %v", err)
  520. }
  521. // jvm prog base
  522. //pJvmLibBaseDir := filepath.Dir(pJvmlibnetPhysicalPath)
  523. jvmLibBaseDir := filepath.Dir(releaseSoFilePathInProc)
  524. // proc maps load path
  525. debugSoFilePathInProc := filepath.Join(jvmLibBaseDir, j.DebugLibNetInfo.LibName)
  526. // Physical path
  527. debugSoFilePhysicalPath := filepath.Join(j.Rootfs, debugSoFilePathInProc)
  528. _, noFileErr := os.Stat(debugSoFilePhysicalPath)
  529. // find cwlibnet.so in proc maps
  530. var readDebugSoPathInMaps string
  531. _, readDebugSoPathInMaps, j.DebugLibNetInfo.MapFile, j.DebugLibNetInfo.FileDeleted, _ = j.findLibBaseFromProcMaps(j.DebugLibNetInfo.LibName)
  532. j.DebugLibNetInfo.LibPath = debugSoFilePhysicalPath
  533. j.DebugLibNetInfo.ProcLoadPath = filepath.Join(jvmLibBaseDir, j.DebugLibNetInfo.LibName)
  534. // condition create
  535. pathFromProg := utils.GetDefaultLibsPath("jvm", j.DebugLibNetInfo.LibName)
  536. if noFileErr != nil && readDebugSoPathInMaps == "" && !j.DebugLibNetInfo.FileDeleted {
  537. err = copyFileAndMatchPermissions(pathFromProg, debugSoFilePhysicalPath, pJvmlibnetPhysicalPath)
  538. klog.Infof("[src:%s],[target:%s],[perm:%s]", pathFromProg, debugSoFilePhysicalPath, pJvmlibnetPhysicalPath)
  539. if err != nil {
  540. return err
  541. }
  542. }
  543. functionName := j.ReleaseLibNetInfo.FuncSymbol.SymName
  544. //j.ReleaseLibNetInfo.LibPath = pJvmlibnetPhysicalPath
  545. klog.Infof("[inject] Base address of [%s]:[%x]", j.ReleaseLibNetInfo.LibName, baseAddress)
  546. // 获取函数的偏移量
  547. functionSym, err := j.getFunctionOffset(pJvmlibnetPhysicalPath, functionName)
  548. // 计算函数的实际内存地址
  549. j.ReleaseLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value
  550. j.ReleaseLibNetInfo.FuncSymbol.SymSize = functionSym.Size
  551. if err != nil {
  552. klog.WithError(err).Errorf("Error getting function offset")
  553. return err
  554. }
  555. klog.Infof("[inject] Actual memory address of %s at base 0x%x: 0x%x", functionName, baseAddress, j.ReleaseLibNetInfo.FuncSymbol.SymAddr)
  556. if j.Uprobe.ELFPath == "" {
  557. if j.DebugLibNetInfo.FileDeleted {
  558. j.Uprobe.ELFPath = j.DebugLibNetInfo.MapFile
  559. } else {
  560. j.Uprobe.ELFPath = debugSoFilePhysicalPath
  561. }
  562. }
  563. err = j.findReleaseAddressInfoFromMem()
  564. if err != nil {
  565. return err
  566. } else {
  567. j.PreCheck.NeedInjectionCheck = true
  568. }
  569. return nil
  570. }
  571. func (j *JvmInjector) findDebugFuncContextFromLibPath() error {
  572. //libName := j.DebugLibNetInfo.LibPath
  573. // 获取release库的基地址
  574. baseAddress, libPath, err := j.findLibBaseByPathFromProcMaps(j.DebugLibNetInfo.ProcLoadPath)
  575. klog.Infof("[inject] debug base address of [%s] : %x", libPath, baseAddress)
  576. functionName := j.DebugLibNetInfo.FuncSymbol.SymName
  577. //j.DebugLibNetInfo.LibPath = libPath
  578. if err != nil {
  579. klog.WithError(err).Errorf("[inject] error.")
  580. return err
  581. }
  582. // 获取函数的偏移量
  583. functionSym, err := j.getFunctionOffset(j.DebugLibNetInfo.LibPath, functionName)
  584. // 计算函数的实际内存地址
  585. j.DebugLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value
  586. j.DebugLibNetInfo.FuncSymbol.SymSize = functionSym.Size
  587. if err != nil {
  588. return fmt.Errorf("Error getting function offset: %v", err)
  589. }
  590. _, err = j.findDebugAddressInfoFromMem()
  591. if err != nil {
  592. return fmt.Errorf("Error finding first CALL instuction: %v", err)
  593. }
  594. fmt.Printf("First CALL instuction o1f %s at base 0x%x\n", functionName, baseAddress)
  595. return nil
  596. }
  597. func printCodeData(data LibNetInfo) {
  598. fmt.Printf("========FuncEnter <0x%x> \n", data.FuncSymbol.SymAddr)
  599. fmt.Printf("Name %s | CurrentAddr:<0x%x>\nOrigin-TargetAddr:<0x%x> | TargetAddr:<0x%x> \nOrigin-Inst:<%s> | Inst:<%s> \n",
  600. data.InnerSymbol.IO_fd_fdID.SymName,
  601. data.InnerSymbol.IO_fd_fdID.SymAddr,
  602. data.InnerSymbol.IO_fd_fdID.OriginTargetAddr,
  603. data.InnerSymbol.IO_fd_fdID.TargetAddr,
  604. x86asm.IntelSyntax(data.InnerSymbol.IO_fd_fdID.OriginInst, 0, nil),
  605. x86asm.IntelSyntax(data.InnerSymbol.IO_fd_fdID.Inst, 0, nil))
  606. fmt.Printf("\nName %s | CurrentAddr:<0x%x>\nOrigin-TargetAddr:<0x%x> | TargetAddr:<0x%x>\nOrigin-Inst:<%s> | Inst:<%s> \n",
  607. data.InnerSymbol.NET_Send.SymName,
  608. data.InnerSymbol.NET_Send.SymAddr,
  609. data.InnerSymbol.NET_Send.OriginTargetAddr,
  610. data.InnerSymbol.NET_Send.TargetAddr,
  611. x86asm.IntelSyntax(data.InnerSymbol.NET_Send.OriginInst, 0, nil),
  612. x86asm.IntelSyntax(data.InnerSymbol.NET_Send.Inst, 0, nil))
  613. fmt.Println("========")
  614. }
  615. func (j *JvmInjector) jvmInjectLib() int {
  616. dll := C.CString(j.DebugLibNetInfo.ProcLoadPath)
  617. rootfs := C.CString(j.Rootfs)
  618. defer C.free(unsafe.Pointer(dll))
  619. result := C.cw_inject_library(C.int(j.Pid), C.int(1), dll, rootfs)
  620. fmt.Printf("Result: %d\n", result)
  621. return int(result)
  622. }
  623. func (j *JvmInjector) validateAllPreCheck() bool {
  624. return j.PreCheck.NeedInjectionCheck && j.PreCheck.LoadingCheck && j.PreCheck.IoFdCheck && j.PreCheck.NetSendFuncCheck
  625. }
  626. func (j *JvmInjector) validateAllModifyCheck() bool {
  627. return j.AfterCheck.IoFdCheck && j.AfterCheck.NetSendFuncCheck
  628. }
  629. /*修改部分*/
  630. func readData(pid int, addr uintptr) (uint64, error) {
  631. var data uint64
  632. if _, err := syscall.PtracePeekData(pid, addr, (*[8]byte)(unsafe.Pointer(&data))[:]); err != nil {
  633. return 0, fmt.Errorf("ptrace PEEKDATA: %v", err)
  634. }
  635. return data, nil
  636. }
  637. func writeData(pid int, addr uintptr, data uint64) error {
  638. if _, err := syscall.PtracePokeData(pid, addr, (*[8]byte)(unsafe.Pointer(&data))[:]); err != nil {
  639. return fmt.Errorf("ptrace POKEDATA: %v", err)
  640. }
  641. return nil
  642. }
  643. func modifyIoFdTargetAddr(pid int, insertAddr, distAddr uintptr) error {
  644. newOffset := distAddr - (insertAddr + 7)
  645. targetAddr := insertAddr + 3
  646. // 获取目标地址处的数据
  647. originalData, err := readData(pid, targetAddr)
  648. if err != nil {
  649. return err
  650. }
  651. // 更新数据中的目标偏移
  652. updatedData := (originalData & 0xFFFFFFFF00000000) | uint64(newOffset&0xFFFFFFFF)
  653. err = writeData(pid, targetAddr, updatedData)
  654. if err != nil {
  655. return err
  656. }
  657. return nil
  658. }
  659. func modifyNetSetTargetAddr(pid int, sendDebugAddr, sendReleaseAddr uintptr) error {
  660. sendOffset := sendReleaseAddr - sendDebugAddr - 5
  661. // 读取原始数据
  662. alignedAddr := sendDebugAddr & ^(uintptr(unsafe.Sizeof(uintptr(0))) - 1)
  663. originalData, err := readData(pid, alignedAddr)
  664. if err != nil {
  665. return err
  666. }
  667. bytes := (*[8]byte)(unsafe.Pointer(&originalData))
  668. offsetLocation := (sendDebugAddr % uintptr(unsafe.Sizeof(uintptr(0)))) + 1
  669. *(*uint32)(unsafe.Pointer(&bytes[offsetLocation])) = uint32(sendOffset)
  670. err = writeData(pid, alignedAddr, originalData)
  671. if err != nil {
  672. return err
  673. }
  674. return nil
  675. }
  676. func modifyReleaseFuncEnter(pid int, originEnterAddr, debugEnterAddr uintptr) error {
  677. offset := debugEnterAddr - (originEnterAddr + 5)
  678. // 读取原始数据
  679. alignedAddr := originEnterAddr & ^(uintptr(unsafe.Sizeof(uintptr(0))) - 1)
  680. originalData, err := readData(pid, alignedAddr)
  681. if err != nil {
  682. return err
  683. }
  684. bytes := (*[8]byte)(unsafe.Pointer(&originalData))
  685. bytes[originEnterAddr%uintptr(unsafe.Sizeof(uintptr(0)))] = 0xe9
  686. *(*uint32)(unsafe.Pointer(&bytes[(originEnterAddr%uintptr(unsafe.Sizeof(uintptr(0))))+1])) = uint32(offset)
  687. err = writeData(pid, alignedAddr, originalData)
  688. if err != nil {
  689. return err
  690. }
  691. return nil
  692. }
  693. func restoreOriginalInstructions(pid int, addr uintptr, instructions []byte) error {
  694. alignedAddr := addr & ^(uintptr(unsafe.Sizeof(uintptr(0))) - 1)
  695. originalData, err := readData(pid, alignedAddr)
  696. if err != nil {
  697. return err
  698. }
  699. bytes := (*[8]byte)(unsafe.Pointer(&originalData))
  700. for i := 0; i < len(instructions); i++ {
  701. bytes[addr%uintptr(unsafe.Sizeof(uintptr(0)))+uintptr(i)] = instructions[i]
  702. }
  703. err = writeData(pid, alignedAddr, originalData)
  704. if err != nil {
  705. return err
  706. }
  707. return nil
  708. }
  709. // func main() {
  710. // flag.StringVar(&PID, "p", "", "PID")
  711. // flag.Parse()
  712. // pidStr := PID // 替换为目标进程的 PID
  713. // pid, err := strconv.Atoi(pidStr)
  714. // if err != nil {
  715. // log.Fatalf("Invalid PID: %v", err)
  716. // }
  717. // functionName := "Java_java_net_SocketOutputStream_socketWrite0"
  718. // libraryName := "libnet.so"
  719. //
  720. // cwLibraryName := "cwlibnet.so"
  721. // cwLibraryPath := "/root/cwlibnet.so"
  722. //
  723. // jvmInjector := &JvmInjector{
  724. // pid: pid,
  725. // ReleaseLibNetInfo: LibNetInfo{
  726. // libName: libraryName,
  727. // FuncSymbol: instInfo{
  728. // SymName: functionName,
  729. // },
  730. // },
  731. // DebugLibNetInfo: LibNetInfo{
  732. // // TODO 根据版本设置
  733. // libName: cwLibraryName,
  734. // // TODO 根据版本设置
  735. // libPath: cwLibraryPath,
  736. // FuncSymbol: instInfo{
  737. // SymName: functionName,
  738. // },
  739. // },
  740. // }
  741. //
  742. // err = jvmInject(jvmInjector)
  743. // fmt.Println(err)
  744. // }
  745. func JvmInject(jvmInjector *JvmInjector) error {
  746. pid := jvmInjector.Pid
  747. var err error
  748. err = jvmInjector.InitProg()
  749. // Debug版本无需修改寄存器
  750. // 已经加载so并指令修改正确的
  751. if jvmInjector.PreCheck.EbpfCanInjection {
  752. klog.Infoln("[inject] eBPF can injection.")
  753. return nil
  754. }
  755. if err != nil {
  756. klog.WithError(err).Errorf("[inject] Error message during release phase.")
  757. return err
  758. }
  759. // 原指令校验通过
  760. if !jvmInjector.PreCheck.NeedInjectionCheck {
  761. return err
  762. }
  763. printCodeData(jvmInjector.ReleaseLibNetInfo)
  764. _type, _, err := jvmInjector.findLibBaseByPathFromProcMaps(jvmInjector.DebugLibNetInfo.ProcLoadPath)
  765. if err != nil {
  766. // load so
  767. if _type == 1 {
  768. klog.Infoln("[inject] start load so.")
  769. resCode := jvmInjector.jvmInjectLib()
  770. if resCode == 0 {
  771. klog.Infof("[inject] load so successful. proc load path is [%s], file path in node is [%s]", jvmInjector.DebugLibNetInfo.ProcLoadPath, jvmInjector.DebugLibNetInfo.LibPath)
  772. jvmInjector.PreCheck.LoadingCheck = true
  773. } else {
  774. klog.Errorf("[inject] Failed load so. so path is [%s]", jvmInjector.DebugLibNetInfo.LibPath)
  775. return fmt.Errorf("[inject] Failed load so. code is %d so path is [%s]", resCode, jvmInjector.DebugLibNetInfo.LibPath)
  776. }
  777. }
  778. } else {
  779. jvmInjector.PreCheck.LoadingCheck = true
  780. }
  781. if !jvmInjector.PreCheck.LoadingCheck {
  782. klog.Infof("Failed load so")
  783. return err
  784. }
  785. err = jvmInjector.findDebugFuncContextFromLibPath()
  786. if err != nil {
  787. klog.WithError(err).Errorf("[inject] Failed to find debug Func Context from libPath")
  788. return err
  789. }
  790. if !jvmInjector.validateAllPreCheck() {
  791. klog.Infof("[inject] validate all pre check")
  792. return err
  793. }
  794. // 修改
  795. debugFuncEnterAddr := uintptr(jvmInjector.DebugLibNetInfo.FuncSymbol.SymAddr)
  796. debugIoFdAddr := uintptr(jvmInjector.DebugLibNetInfo.InnerSymbol.IO_fd_fdID.SymAddr)
  797. debugNetSendAddr := uintptr(jvmInjector.DebugLibNetInfo.InnerSymbol.NET_Send.SymAddr)
  798. originFuncEnterAddr := uintptr(jvmInjector.ReleaseLibNetInfo.FuncSymbol.SymAddr)
  799. ioFdReleaseTargetAddr := uintptr(jvmInjector.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID.TargetAddr)
  800. netSendReleaseTargetAddr := uintptr(jvmInjector.ReleaseLibNetInfo.InnerSymbol.NET_Send.TargetAddr)
  801. fmt.Printf("<0x%x> -> <0x%x>\n", originFuncEnterAddr, debugFuncEnterAddr)
  802. fmt.Printf("<0x%x> -> <0x%x>\n", debugIoFdAddr, ioFdReleaseTargetAddr)
  803. fmt.Printf("<0x%x> -> <0x%x>\n", debugNetSendAddr, netSendReleaseTargetAddr)
  804. // 附加到目标进程
  805. klog.Infof("attach")
  806. err = syscall.PtraceAttach(pid)
  807. if err != nil {
  808. fmt.Printf("ptrace ATTACH: %v", err)
  809. }
  810. // 等待目标进程停止
  811. klog.Infof("attach Wait")
  812. if _, err := syscall.Wait4(pid, nil, 0, nil); err != nil {
  813. fmt.Printf("wait4: %v", err)
  814. return err
  815. }
  816. //time.Now().UnixNano()
  817. // 修改目标的内存
  818. klog.Infof("modifyIoFdTargetAddr")
  819. err = modifyIoFdTargetAddr(pid, debugIoFdAddr, ioFdReleaseTargetAddr)
  820. if err != nil {
  821. fmt.Println(err)
  822. return err
  823. }
  824. klog.Infof("modifyNetSetTargetAddr")
  825. err = modifyNetSetTargetAddr(pid, debugNetSendAddr, netSendReleaseTargetAddr)
  826. if err != nil {
  827. fmt.Println(err)
  828. return err
  829. }
  830. // 二次效验 读取并验证地址
  831. klog.Infof("checkDebugFuncSymAfterChange")
  832. _, err = jvmInjector.checkDebugFuncSymAfterChange()
  833. printCodeData(jvmInjector.ReleaseLibNetInfo)
  834. printCodeData(jvmInjector.DebugLibNetInfo)
  835. // 效验目标函数内地址是否与预期一致
  836. if !jvmInjector.validateAllModifyCheck() && err == nil {
  837. klog.Errorf("[inject] failed validateAllModifyCheck")
  838. return err
  839. }
  840. // 更新函数入口
  841. klog.Infof("modifyReleaseFuncEnter")
  842. err = modifyReleaseFuncEnter(pid, originFuncEnterAddr, debugFuncEnterAddr)
  843. if err != nil {
  844. klog.Errorf("[inject] failed modifyReleaseFuncEnter")
  845. return err
  846. }
  847. // 校验jmp地址修改正确
  848. klog.Infof("checkReleaseFuncSymAfterChange")
  849. err = jvmInjector.checkReleaseFuncSymAfterChange()
  850. if err != nil {
  851. klog.Errorf("[inject] failed checkReleaseFuncSymAfterChange")
  852. if len(jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode) == 5 {
  853. err = restoreOriginalInstructions(pid, originFuncEnterAddr, jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode)
  854. if err != nil {
  855. fmt.Println(err)
  856. return err
  857. }
  858. }
  859. }
  860. // 恢复执行
  861. klog.Infof("Detach")
  862. if err = syscall.PtraceDetach(pid); err != nil {
  863. klog.Errorf("ptrace DETACH: %v", err)
  864. return err
  865. }
  866. return nil
  867. }
  868. func copyFileAndMatchPermissions(srcFile, destFile, permFile string) error {
  869. // 获取权限文件的信息
  870. permInfo, err := os.Stat(permFile)
  871. if err != nil {
  872. return fmt.Errorf("failed to stat permission file: %w", err)
  873. }
  874. // 打开源文件
  875. src, err := os.Open(srcFile)
  876. if err != nil {
  877. return fmt.Errorf("failed to open source file: %w", err)
  878. }
  879. defer src.Close()
  880. // 创建目标文件
  881. dst, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, permInfo.Mode())
  882. if err != nil {
  883. return fmt.Errorf("failed to create destination file: %w", err)
  884. }
  885. defer dst.Close()
  886. // 复制文件内容
  887. if _, err := io.Copy(dst, src); err != nil {
  888. return fmt.Errorf("failed to copy file content: %w", err)
  889. }
  890. // 获取用户和组信息并设置
  891. if stat, ok := permInfo.Sys().(*syscall.Stat_t); ok {
  892. fmt.Println(stat.Uid)
  893. fmt.Println(stat.Gid)
  894. if err := dst.Chown(int(stat.Uid), int(stat.Gid)); err != nil {
  895. return fmt.Errorf("failed to set file ownership: %w", err)
  896. }
  897. } else {
  898. return fmt.Errorf("failed to retrieve ownership information")
  899. }
  900. return nil
  901. }