github.com/HXSecurity/DongTai-agent-go@v0.4.2/service/auxiliary.go (about)

     1  package service
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"github.com/HXSecurity/DongTai-agent-go/model/request"
     8  	"github.com/HXSecurity/DongTai-agent-go/service/version"
     9  	"github.com/HXSecurity/DongTai-agent-go/utils"
    10  	"github.com/pkg/errors"
    11  	"io/fs"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"runtime"
    16  	"strings"
    17  )
    18  
    19  var buildInfoMagic = []byte("\xff Go buildinf:")
    20  
    21  // An exe is a generic interface to an OS executable (ELF, Mach-O, PE, XCOFF).
    22  type exe interface {
    23  	// Close closes the underlying file.
    24  	Close() error
    25  
    26  	// ReadData reads and returns up to size byte starting at virtual address addr.
    27  	ReadData(addr, size uint64) ([]byte, error)
    28  
    29  	// DataStart returns the writable data segment start address.
    30  	DataStart() uint64
    31  }
    32  
    33  // GenAQLForGolang 为golang组件生成aql
    34  func GenAQLForGolang(packageName, version string) string {
    35  	return fmt.Sprintf("golang:%s:%s:", packageName, version)
    36  }
    37  
    38  // 获取包
    39  func GetMod() ([]request.Component, string) {
    40  	//fmt.Println(getCurrentPath())
    41  	path, _ := os.Executable()
    42  	return scanFile(path, true)
    43  }
    44  
    45  // 判断是否是exe文件
    46  func isExe(file string, info fs.FileInfo) bool {
    47  	if runtime.GOOS == "windows" {
    48  		return strings.HasSuffix(strings.ToLower(file), ".exe")
    49  	}
    50  	return info.Mode().IsRegular() && info.Mode()&0111 != 0
    51  }
    52  
    53  // 从二进制文件读取包信息
    54  func scanFile(file string, mustPrint bool) (packages []request.Component, agentVersion string) {
    55  
    56  	i, err := os.Stat(file)
    57  	info := i
    58  
    59  	if !isExe(file, info) {
    60  		if mustPrint {
    61  			fmt.Fprintf(os.Stderr, "%s: not executable file\n", file)
    62  		}
    63  		return
    64  	}
    65  
    66  	x, err := version.OpenExe(file)
    67  	if err != nil {
    68  		if mustPrint {
    69  			fmt.Fprintf(os.Stderr, "%s: %v\n", file, err)
    70  		}
    71  		return
    72  	}
    73  	defer x.Close()
    74  
    75  	vers, mod := findVers(x)
    76  	if vers == "" {
    77  		if mustPrint {
    78  			fmt.Fprintf(os.Stderr, "%s: go version not found\n", file)
    79  		}
    80  		return
    81  	}
    82  
    83  	li := strings.Split(mod[:len(mod)-1], "\n")
    84  	for i := range li {
    85  		licl := strings.Split(li[i], "\t")
    86  		if licl[0] == "dep" {
    87  			fmt.Printf("依赖:%s\t版本:%s\n", licl[1], licl[2])
    88  			aql := GenAQLForGolang(licl[1], licl[2])
    89  			if licl[1] == "github.com/HXSecurity/DongTai-agent-go" {
    90  				fmt.Println("当前探针版本为:" + licl[2])
    91  				agentVersion = licl[2]
    92  			}
    93  			packages = append(packages, request.Component{
    94  				PackageName:      aql,
    95  				PackageAlgorithm: "SHA-1",
    96  				PackagePath:      file,
    97  				PackageVersion:   licl[2],
    98  				PackageSignature: utils.SHA1(aql),
    99  			},
   100  			)
   101  		}
   102  	}
   103  	return packages, agentVersion
   104  }
   105  
   106  // 获取服务信息
   107  func getServerInfo() (server *utils.Server, err error) {
   108  	var s utils.Server
   109  	s.Os = utils.InitOS()
   110  	if s.Cpu, err = utils.InitCPU(); err != nil {
   111  		fmt.Println(err.Error())
   112  		return &s, err
   113  	}
   114  	if s.Rrm, err = utils.InitRAM(); err != nil {
   115  		fmt.Println(err.Error())
   116  		return &s, err
   117  	}
   118  	if s.Disk, err = utils.InitDisk(); err != nil {
   119  		fmt.Println(err.Error())
   120  		return &s, err
   121  	}
   122  
   123  	return &s, nil
   124  }
   125  
   126  func getCurrentPath() (string, error) {
   127  	file, err := exec.LookPath(os.Args[0])
   128  	if err != nil {
   129  		return "", err
   130  	}
   131  	path, err := filepath.Abs(file)
   132  	if err != nil {
   133  		return "", err
   134  	}
   135  	i := strings.LastIndex(path, "/")
   136  	if i < 0 {
   137  		i = strings.LastIndex(path, "\\")
   138  	}
   139  	if i < 0 {
   140  		return "", errors.New(`error: Can't find "/" or "\".`)
   141  	}
   142  	return string(path[0 : i+1]), nil
   143  }
   144  
   145  func findVers(x exe) (vers, mod string) {
   146  	// Read the first 64kB of text to find the build info blob.
   147  	text := x.DataStart()
   148  	data, err := x.ReadData(text, 64*1024)
   149  	if err != nil {
   150  		return
   151  	}
   152  	for ; !bytes.HasPrefix(data, buildInfoMagic); data = data[32:] {
   153  		if len(data) < 32 {
   154  			return
   155  		}
   156  	}
   157  
   158  	// Decode the blob.
   159  	ptrSize := int(data[14])
   160  	bigEndian := data[15] != 0
   161  	var bo binary.ByteOrder
   162  	if bigEndian {
   163  		bo = binary.BigEndian
   164  	} else {
   165  		bo = binary.LittleEndian
   166  	}
   167  	var readPtr func([]byte) uint64
   168  	if ptrSize == 4 {
   169  		readPtr = func(b []byte) uint64 { return uint64(bo.Uint32(b)) }
   170  	} else {
   171  		readPtr = bo.Uint64
   172  	}
   173  	vers = readString(x, ptrSize, readPtr, readPtr(data[16:]))
   174  	if vers == "" {
   175  		return
   176  	}
   177  	mod = readString(x, ptrSize, readPtr, readPtr(data[16+ptrSize:]))
   178  	if len(mod) >= 33 && mod[len(mod)-17] == '\n' {
   179  		// Strip module framing.
   180  		mod = mod[16 : len(mod)-16]
   181  	} else {
   182  		mod = ""
   183  	}
   184  	return
   185  }
   186  
   187  // readString returns the string at address addr in the executable x.
   188  func readString(x exe, ptrSize int, readPtr func([]byte) uint64, addr uint64) string {
   189  	hdr, err := x.ReadData(addr, uint64(2*ptrSize))
   190  	if err != nil || len(hdr) < 2*ptrSize {
   191  		return ""
   192  	}
   193  	dataAddr := readPtr(hdr)
   194  	dataLen := readPtr(hdr[ptrSize:])
   195  	data, err := x.ReadData(dataAddr, dataLen)
   196  	if err != nil || uint64(len(data)) < dataLen {
   197  		return ""
   198  	}
   199  	return string(data)
   200  }