inject_aot.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. package aotinject
  2. /*
  3. #cgo CFLAGS: -I ../inject/include
  4. #cgo amd64 LDFLAGS: ${SRCDIR}/../inject/lib/libhotpatch_amd64.a
  5. #cgo arm64 LDFLAGS: ${SRCDIR}/../inject/lib/libhotpatch_arm64.a
  6. #include "hotpatch.h"
  7. #include <stdlib.h>
  8. */
  9. import "C"
  10. import (
  11. "bufio"
  12. "debug/dwarf"
  13. "debug/elf"
  14. "flag"
  15. "fmt"
  16. "io"
  17. "log"
  18. "os"
  19. "strconv"
  20. "strings"
  21. "syscall"
  22. "unsafe"
  23. )
  24. func InjectLib(pid int, libPath string) int {
  25. dll := C.CString(libPath) // 替换为实际的DLL路径
  26. fmt.Printf("dll: %s\n", libPath)
  27. rootfs := C.CString("")
  28. defer C.free(unsafe.Pointer(dll)) // 确保在使用完字符串后释放内存
  29. result := C.cw_inject_library(C.int(pid), C.int(0), dll, rootfs)
  30. fmt.Printf("Result JVM: %d\n", result)
  31. return int(result)
  32. }
  33. // readMemory 用于读取指定地址的内存数据
  34. func readMemory(pid int, address uint64, size uint64) ([]byte, error) {
  35. memFile := fmt.Sprintf("/proc/%d/mem", pid)
  36. file, err := os.Open(memFile)
  37. if err != nil {
  38. return nil, err
  39. }
  40. defer file.Close()
  41. data := make([]byte, size)
  42. _, err = file.ReadAt(data, int64(address))
  43. if err != nil {
  44. return nil, err
  45. }
  46. return data, nil
  47. }
  48. func getFunctionOffsetDBG(libPath, functionName string) (elf.Symbol, error) {
  49. dwarfFile, err := elf.Open(libPath)
  50. if err != nil {
  51. return elf.Symbol{}, fmt.Errorf("failed to open libPath %s: %v", libPath, err)
  52. }
  53. dwarfData, err := dwarfFile.DWARF()
  54. if err != nil {
  55. return elf.Symbol{}, fmt.Errorf("failed to read DWARF data: %v", err)
  56. }
  57. type uprobesDef struct {
  58. Name string
  59. Offset uint64
  60. EntAddress uint64
  61. RetAddress uint64
  62. }
  63. listEntry := make(map[dwarf.Offset]uprobesDef)
  64. SpecListEntry := []dwarf.Entry{}
  65. entryReader := dwarfData.Reader()
  66. for {
  67. entry, err := entryReader.Next()
  68. if err == io.EOF {
  69. // We've reached the end of DWARF entries
  70. break
  71. }
  72. if err != nil {
  73. log.Println("Error reading entry: %v", err)
  74. }
  75. if entry == nil {
  76. log.Println("Warning: a nil entry was returned with no error")
  77. break
  78. }
  79. // 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))
  80. if entry.Tag == dwarf.TagSubprogram {
  81. // fmt.Printf("entry address: %x, %d\n", entry.Offset, entry.Children)
  82. funName, ok := entry.Val(dwarf.AttrName).(string)
  83. if !ok {
  84. continue
  85. }
  86. if functionName == funName {
  87. entAddress, ok := entry.Val(dwarf.AttrLowpc).(uint64)
  88. if !ok {
  89. entAddress = 0
  90. }
  91. retAddress, ok := entry.Val(dwarf.AttrHighpc).(uint64)
  92. if !ok {
  93. retAddress = 0
  94. }
  95. fmt.Printf("Function %s address: %x, %x, %x\n", funName, entAddress, entry.Offset, retAddress)
  96. uprobes := uprobesDef{
  97. Name: funName,
  98. Offset: uint64(entry.Offset),
  99. EntAddress: entAddress,
  100. RetAddress: retAddress,
  101. }
  102. listEntry[entry.Offset] = uprobes
  103. }
  104. specAddr, _ := entry.Val(dwarf.AttrSpecification).(dwarf.Offset)
  105. lowpc := entry.Val(dwarf.AttrLowpc)
  106. if lowpc != nil && specAddr > 0 && lowpc.(uint64) > 0 {
  107. SpecListEntry = append(SpecListEntry, *entry)
  108. }
  109. }
  110. }
  111. for _, v := range SpecListEntry {
  112. specAddr, _ := v.Val(dwarf.AttrSpecification).(dwarf.Offset)
  113. // fmt.Printf("SpecListEntrySpecListEntrySpecListEntry Attach Function: %x\n", specAddr)
  114. _, ok := listEntry[specAddr]
  115. if ok {
  116. vv := listEntry[specAddr]
  117. entAddr := v.Val(dwarf.AttrLowpc)
  118. if entAddr != nil {
  119. vv.EntAddress = entAddr.(uint64)
  120. }
  121. retAddr := v.Val(dwarf.AttrHighpc)
  122. if retAddr != nil {
  123. switch retAddr.(type) {
  124. case uint64:
  125. vv.RetAddress = uint64(retAddr.(uint64))
  126. case int64:
  127. vv.RetAddress = uint64(retAddr.(int64))
  128. default:
  129. fmt.Println("Unknown type")
  130. }
  131. }
  132. listEntry[specAddr] = vv
  133. }
  134. }
  135. for _, v := range listEntry {
  136. sSize := v.RetAddress
  137. if v.RetAddress > v.EntAddress {
  138. sSize = v.RetAddress - v.EntAddress
  139. }
  140. symbol := elf.Symbol{
  141. Name: v.Name,
  142. Value: v.EntAddress,
  143. Size: 180,
  144. }
  145. fmt.Printf("Need Attach Function %s address: %x, %x, %d\n", v.Name, v.EntAddress, v.RetAddress, sSize)
  146. return symbol, nil
  147. }
  148. return elf.Symbol{}, fmt.Errorf("function %s not found", functionName)
  149. }
  150. func getFunctionOffset(libPath, functionName string) (elf.Symbol, error) {
  151. elfFile, err := elf.Open(libPath)
  152. if err != nil {
  153. return elf.Symbol{}, fmt.Errorf("failed to open ELF file: %v", err)
  154. }
  155. defer elfFile.Close()
  156. // 优先从 Symbols 中查找函数的地址,如果找不到则从 DynamicSymbols 中查找
  157. symbols, err := elfFile.Symbols()
  158. if err != nil {
  159. fmt.Printf("Can Not find Symbols: %s, %s, %v, can find from DynamicSymbols\n", libPath, functionName, err)
  160. symbols, err = elfFile.DynamicSymbols()
  161. if err != nil {
  162. return elf.Symbol{}, fmt.Errorf("failed to read dynamic symbols: %v", err)
  163. }
  164. }
  165. for _, sym := range symbols {
  166. if sym.Name == functionName {
  167. return sym, nil
  168. }
  169. }
  170. return elf.Symbol{}, fmt.Errorf("function %s not found from Symbols", functionName)
  171. }
  172. // getProcessMapsInfo reads the first line of /proc/<pid>/maps file and returns the memory map as a MemoryMap struct
  173. // If a library name is provided, it returns the start address of that library
  174. func getProcessMapsInfo(pid int, libraryName ...string) (*ProcessMapsInfo, error) {
  175. file, err := os.Open(fmt.Sprintf("/proc/%d/maps", pid))
  176. if err != nil {
  177. return nil, err
  178. }
  179. defer file.Close()
  180. scanner := bufio.NewScanner(file)
  181. for scanner.Scan() {
  182. line := scanner.Text()
  183. fields := strings.Fields(line)
  184. addresses := strings.Split(fields[0], "-")
  185. if len(addresses) != 2 {
  186. return nil, fmt.Errorf("unexpected format in /proc/%d/maps", pid)
  187. }
  188. start, err := strconv.ParseUint(addresses[0], 16, 64)
  189. if err != nil {
  190. return nil, err
  191. }
  192. end, err := strconv.ParseUint(addresses[1], 16, 64)
  193. if err != nil {
  194. return nil, err
  195. }
  196. if len(libraryName) == 0 || (len(fields) > 5 && strings.Contains(fields[5], libraryName[0])) {
  197. return &ProcessMapsInfo{
  198. Start: start,
  199. End: end,
  200. Path: fields[5],
  201. }, nil
  202. }
  203. }
  204. if err := scanner.Err(); err != nil {
  205. return nil, err
  206. }
  207. return nil, fmt.Errorf("specified library or process start address not found in /proc/%d/maps", pid)
  208. }
  209. func GetProcessFunctionInfo(pid int, libPath string, functionName string, libraryName ...string) (*ProcessFunctionInfo, error) {
  210. processMapsInfo, _ := getProcessMapsInfo(pid, libraryName...)
  211. baseAddress := uint64(processMapsInfo.Start)
  212. // functionName 是以 @plt 结尾的函数名,则调用 getFunctionOffsetPLT 获取函数的地址,并且去掉 @plt 后缀
  213. if strings.HasSuffix(functionName, "@plt") {
  214. functionName = functionName[:len(functionName)-4]
  215. sendFunctionNew, _ := getFunctionOffsetPLT(pid, libPath, functionName)
  216. return &ProcessFunctionInfo{
  217. Name: functionName,
  218. Offset: sendFunctionNew.Value,
  219. Start: baseAddress + sendFunctionNew.Value,
  220. Size: sendFunctionNew.Size,
  221. }, nil
  222. }
  223. // 获取函数的偏移量,有限直接从 ELF 文件中获取,如果失败则从 DWARF 文件中获取
  224. functionSym, err := getFunctionOffset(libPath, functionName)
  225. if err != nil {
  226. fmt.Printf("Error getting function offset: %v, now to find dbg %s\n", err, libPath+".dbg")
  227. functionSym, err = getFunctionOffsetDBG(libPath+".dbg", functionName)
  228. if err != nil {
  229. fmt.Printf("Error getting function offset from DWARF file: %v\n", err)
  230. return nil, err
  231. }
  232. }
  233. fmt.Printf("get ProcessFunctionInfo: 0x%x, 0x%x\n", baseAddress, functionSym.Value)
  234. funRelAddr := functionSym.Value
  235. if functionSym.Value < baseAddress {
  236. funRelAddr += baseAddress
  237. }
  238. return &ProcessFunctionInfo{
  239. Name: functionSym.Name,
  240. Offset: functionSym.Value,
  241. Start: funRelAddr,
  242. Size: functionSym.Size,
  243. }, nil
  244. }
  245. func AotInject(aotInjector AOTInjector) (int, error) {
  246. isInject := false
  247. // lib 注入
  248. cwLibraryInfo, err := getProcessMapsInfo(aotInjector.PID, aotInjector.CWLibName)
  249. if err != nil {
  250. fmt.Printf("Not Find Lib %s: Now to InjectLib: %v\n", aotInjector.CWLibName, err)
  251. InjectLib(aotInjector.PID, aotInjector.CWLibPath)
  252. cwLibraryInfo, err = getProcessMapsInfo(aotInjector.PID, aotInjector.CWLibName)
  253. if err != nil {
  254. fmt.Printf("InjectLib %s Err: %v\n", aotInjector.CWLibName, err)
  255. return 0, fmt.Errorf("InjectLib %s Err: %v", aotInjector.CWLibName, err)
  256. }
  257. } else {
  258. isInject = true
  259. }
  260. fmt.Printf("find %s Lib Start: %x, End: %x, Path: %s\n", aotInjector.CWLibName, cwLibraryInfo.Start, cwLibraryInfo.End, cwLibraryInfo.Path)
  261. // 查找 cwFunctionName 函数的偏移量
  262. cwSym, _ := GetProcessFunctionInfo(aotInjector.PID, cwLibraryInfo.Path, aotInjector.CWFunctionName, aotInjector.CWLibName)
  263. // 打印 cwFunctionName 函数的偏移量
  264. fmt.Printf("%s: addr %x, size %d\n", aotInjector.CWFunctionName, cwSym.Start, cwSym.Size)
  265. if isInject == true {
  266. fmt.Printf("cwLibrary is already Injected, to find hookOffset\n")
  267. hookOffset, err := findNopFunctionHookOffset(aotInjector.PID, cwSym)
  268. if err != nil {
  269. fmt.Printf("findNopFunctionHookOffset Err: %v Need Inject\n", err)
  270. } else {
  271. fmt.Printf("findNopFunctionHookOffset: %d[%d]\n", hookOffset, hookOffset+nopEntryOffset)
  272. return hookOffset + nopEntryOffset, nil
  273. }
  274. }
  275. // 获取socketWrite0 和 NET_Send 函数的偏移量
  276. jvmInjectorFunction, err := GetProcessFunctionInfo(aotInjector.PID, aotInjector.InjectLibPath, aotInjector.InjectFunctionName)
  277. if err != nil {
  278. fmt.Printf("Error getting function %s offset: %v\n", aotInjector.InjectFunctionName, err)
  279. return 0, fmt.Errorf("error getting function %s offset: %v", aotInjector.InjectFunctionName, err)
  280. }
  281. sendFunction, err := GetProcessFunctionInfo(aotInjector.PID, aotInjector.SendFunctionLibPath, aotInjector.SendFunctionName)
  282. if err != nil {
  283. fmt.Printf("Error getting function %s offset: %v\n", aotInjector.SendFunctionName, err)
  284. return 0, fmt.Errorf("error getting function %s offset: %v", aotInjector.SendFunctionName, err)
  285. }
  286. fmt.Printf("find %s, addr: %x, size:%d\n", aotInjector.InjectFunctionName, jvmInjectorFunction.Start, jvmInjectorFunction.Size)
  287. fmt.Printf("find %s, addr: %x, size:%d\n", aotInjector.SendFunctionName, sendFunction.Start, sendFunction.Size)
  288. // 读取 socketWrite0 函数的内存数据并解析 NET_Send 在 socketWrite0 中的调用位置
  289. code, err := readMemory(aotInjector.PID, jvmInjectorFunction.Start, jvmInjectorFunction.Size)
  290. if err != nil {
  291. fmt.Printf("Error reading jvmInjectorFunction memory: %v\n", err)
  292. return 0, fmt.Errorf("error reading jvmInjectorFunction memory: %v", err)
  293. }
  294. // 打印 socketWrite0 函数的内存数据
  295. fmt.Printf("socketWrite0 code: %v\n", code)
  296. SendFunctionAbsOffset, SendFunctionRelOffset, err := findSendFunctionNameAddr(jvmInjectorFunction.Start, code, aotInjector.SendFunctionName, sendFunction.Start)
  297. if err != nil {
  298. fmt.Printf("findSendFunctionNameAddr Err: %v\n", err)
  299. return 0, fmt.Errorf("findSendFunctionNameAddr Err: %v", err)
  300. }
  301. fmt.Printf("find %s : SendFunctionAbsOffset:%x, SendFunctionRelOffset: %d\n", aotInjector.SendFunctionName, SendFunctionAbsOffset, SendFunctionRelOffset)
  302. // 尝试获取 NET_Send 附近的数据凑够 17 个字节,用于长跳转到 libmylib 中
  303. instMemStruct, err := findMemForLongJump(jvmInjectorFunction.Start, code, aotInjector.SendFunctionName, SendFunctionAbsOffset)
  304. if err != nil {
  305. fmt.Printf("findMemForLongJump Err: %v\n", err)
  306. return 0, fmt.Errorf("findMemForLongJump Err: %v", err)
  307. }
  308. // 打印 instMemStruct 结构体的内容
  309. fmt.Printf("instMemStruct: %v\n", instMemStruct)
  310. // 生成长跳指令,跳转到 libmylib 中的 cwFunctionName 函数的+12地址
  311. jumpCode := generateLongJumpCode(cwSym.Start+nopEntryOffset, len(instMemStruct.CodeArray), true)
  312. // 使用 parseAndPrintInstructions打印 jumpCode 的内容
  313. fmt.Printf("jumpCode: %v\n", jumpCode)
  314. parseAndPrintInstructions(jumpCode)
  315. // 生成新的指令,用于替换原来的指令,一个参数是原来的指令 instCodeArray,另一个参数是跳转回去的地址,第三个参数是原始 Send 函数的地址,第四个参数是在哪个指令前插入自定义指令
  316. newCode, hookOffset := generateNewCode(instMemStruct.InstCodeArray, instMemStruct.InstStartAddr+jumpBackAddrOffset, sendFunction.Start, instMemStruct.InsertIndex)
  317. if hookOffset == 0 {
  318. fmt.Printf("generateNewCode Err: %v\n", instMemStruct)
  319. return 0, fmt.Errorf("generateNewCode Err: %v", instMemStruct)
  320. }
  321. // 打印 hookIndex
  322. fmt.Printf("ebpf should hookIndex: %d[%d]\n", hookOffset, nopEntryOffset+hookOffset)
  323. // 使用 parseAndPrintInstructions 打印 newCode 的内容
  324. fmt.Printf("newCode: %v\n", newCode)
  325. parseAndPrintInstructions(newCode)
  326. // 使用 ptrace attach 目标进程
  327. fmt.Printf("Attach Process: %d\n", aotInjector.PID)
  328. if err := syscall.PtraceAttach(aotInjector.PID); err != nil {
  329. fmt.Printf("PtraceAttach Err: %v\n", err)
  330. return 0, fmt.Errorf("ptrace attach: %v", err)
  331. }
  332. // 等待目标进程停止
  333. if _, err := syscall.Wait4(aotInjector.PID, nil, 0, nil); err != nil {
  334. fmt.Printf("wait4: %v", err)
  335. if err = syscall.PtraceDetach(aotInjector.PID); err != nil {
  336. fmt.Printf("ptrace DETACH: %v", err)
  337. }
  338. return 0, fmt.Errorf("wait4: %v", err)
  339. }
  340. fmt.Printf("Ptrace 将newCode使用ptrace写入到目标进程的内存中: %x\n", cwSym.Start+nopEntryOffset)
  341. // 将newCode使用ptrace写入到目标进程的的空白内存中,地址为 cwSym.Start+12
  342. _, err = syscall.PtracePokeData(aotInjector.PID, uintptr(cwSym.Start+nopEntryOffset), newCode)
  343. if err != nil {
  344. fmt.Printf("PtracePokeData Err: %v\n", err)
  345. }
  346. fmt.Printf("Ptrace 将jumpCode使用ptrace写入到目标进程的内存中: %x\n", instMemStruct.InstStartAddr)
  347. // 将jumpCode使用ptrace写入到目标进程的内存中
  348. _, err = syscall.PtracePokeData(aotInjector.PID, uintptr(instMemStruct.InstStartAddr), jumpCode)
  349. if err != nil {
  350. fmt.Printf("PtracePokeData Err: %v\n", err)
  351. }
  352. fmt.Printf("Ptrace DETACH: %d\n", aotInjector.PID)
  353. // 恢复执行
  354. if err = syscall.PtraceDetach(aotInjector.PID); err != nil {
  355. fmt.Printf("ptrace DETACH: %v", err)
  356. }
  357. return hookOffset + nopEntryOffset, nil
  358. }
  359. type AOTInjector struct {
  360. PID int
  361. SendFunctionLibPath string
  362. SendFunctionName string
  363. InjectLibPath string
  364. InjectFunctionName string
  365. CWLibName string
  366. CWFunctionName string
  367. CWLibPath string
  368. }
  369. func main() {
  370. flag.StringVar(&PID, "p", "", "PID")
  371. flag.Parse()
  372. pidStr := PID // 替换为目标进程的 PID
  373. pid, err := strconv.Atoi(pidStr)
  374. if err != nil {
  375. log.Fatalf("Invalid PID: %v", err)
  376. }
  377. // NETCoreAOTInject
  378. // netCoreAotInjector := AOTInjector{
  379. // PID: pid,
  380. // SendFunctionLibPath: "/data/NET8/CoreAoT/bin/Debug/net8.0/linux-x64/publish/CoreAoT",
  381. // SendFunctionName: "send@plt",
  382. // InjectLibPath: "/data/NET8/CoreAoT/bin/Debug/net8.0/linux-x64/publish/CoreAoT",
  383. // InjectFunctionName: "SystemNative_Send",
  384. // CWLibName: "libmylib.so",
  385. // CWFunctionName: "asmnop",
  386. // CWLibPath: "/data/NET8/CoreAoT/bin/Debug/net8.0/linux-x64/publish/CoreAoT",
  387. // }
  388. // JavaAOTInject
  389. javaAotInjector := AOTInjector{
  390. PID: pid,
  391. SendFunctionLibPath: "/data/roger/ebpfdemo/graalve_demo/SimpleHttpServer",
  392. SendFunctionName: "NET_Send",
  393. InjectLibPath: "/data/roger/ebpfdemo/graalve_demo/SimpleHttpServer",
  394. InjectFunctionName: "Java_java_net_SocketOutputStream_socketWrite0",
  395. CWLibName: "libmylib.so",
  396. CWFunctionName: "asmnop",
  397. CWLibPath: "/data/roger/ebpfdemo/mylib/libmylib.so",
  398. }
  399. hookOffset, err := AotInject(javaAotInjector)
  400. if err != nil {
  401. fmt.Printf("AotInject Err: %v\n", err)
  402. }
  403. fmt.Printf("AotInject result hookOffset: %d\n", hookOffset)
  404. }