Skip to content

Commit

Permalink
update user
Browse files Browse the repository at this point in the history
  • Loading branch information
yuweizzz committed Nov 4, 2024
1 parent c348fc0 commit 843c124
Show file tree
Hide file tree
Showing 7 changed files with 308 additions and 113 deletions.
3 changes: 2 additions & 1 deletion cli/cmd/gnutls.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ ecapture gnutls
ecapture gnutls --hex --pid=3423
ecapture gnutls -l save.log --pid=3423
ecapture gnutls --gnutls=/lib/x86_64-linux-gnu/libgnutls.so
ecapture gnutls -m keylog -k ecapture_gnutls_key.og
ecapture gnutls -m keylog -k ecapture_gnutls_key.og --ssl_version=3.7.9
ecapture gnutls -m pcap --pcapfile save.pcapng -i eth0 --gnutls=/lib/x86_64-linux-gnu/libgnutls.so tcp port 443
`,
Run: gnuTlsCommandFunc,
Expand All @@ -50,6 +50,7 @@ func init() {
gnutlsCmd.PersistentFlags().StringVarP(&gc.KeylogFile, "keylogfile", "k", "ecapture_gnutls_key.og", "The file stores SSL/TLS keys, and eCapture captures these keys during encrypted traffic communication and saves them to the file.")
gnutlsCmd.PersistentFlags().StringVarP(&gc.PcapFile, "pcapfile", "w", "save.pcapng", "write the raw packets to file as pcapng format.")
gnutlsCmd.PersistentFlags().StringVarP(&gc.Ifname, "ifname", "i", "", "(TC Classifier) Interface name on which the probe will be attached.")
gnutlsCmd.PersistentFlags().StringVar(&gc.SslVersion, "ssl_version", "", "GnuTLS version, e.g: --ssl_version=\"3.7.9\"")
rootCmd.AddCommand(gnutlsCmd)
}

Expand Down
1 change: 1 addition & 0 deletions user/config/config_gnutls.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type GnutlsConfig struct {
KeylogFile string `json:"keylog"`
Ifname string `json:"ifname"`
PcapFilter string `json:"pcapfilter"`
SslVersion string `json:"sslversion"`
ElfType uint8
}

Expand Down
105 changes: 10 additions & 95 deletions user/module/probe_gnutls.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,9 @@ package module
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"math"
"os"
"path"
"path/filepath"
"sync"
"time"
Expand Down Expand Up @@ -50,6 +47,8 @@ type MGnutlsProbe struct {
keylogger *os.File
masterKeys map[string]bool
eBPFProgramType TlsCaptureModelType
sslVersion string
sslBpfFile string
}

// 对象初始化
Expand Down Expand Up @@ -118,11 +117,14 @@ func (g *MGnutlsProbe) Start() error {
}

func (g *MGnutlsProbe) start() error {
// get gnutls sslVersion and sslBpfFile
err := g.detectGnutls()
if err != nil {
g.logger.Error().Err(err).Msg("detectGnutls failed")
return fmt.Errorf("detectGnutls failed: %v", err)
}
// fetch ebpf assets
var err error
bpfFileName := g.geteBPFName("user/bytecode/gnutls_kern.o")
g.logger.Info().Str("bytecode filename", bpfFileName).Msg("BPF bytecode loaded")
byteBuf, err := assets.Asset(bpfFileName)
byteBuf, err := assets.Asset(g.sslBpfFile)
if err != nil {
g.logger.Error().Err(err).Strs("bytecode files", assets.AssetNames()).Msg("couldn't find bpf bytecode file")
return fmt.Errorf("couldn't find asset %v", err)
Expand All @@ -143,7 +145,7 @@ func (g *MGnutlsProbe) start() error {
case TlsCaptureModelTypeText:
fallthrough
default:
err = g.setupManagers()
err = g.setupManagersText()
}
if err != nil {
return fmt.Errorf("tls(gnutls) module couldn't find binPath %v", err)
Expand Down Expand Up @@ -202,98 +204,11 @@ func (g *MGnutlsProbe) constantEditor() []manager.ConstantEditor {
return editor
}

func (g *MGnutlsProbe) setupManagers() error {
var binaryPath string
switch g.conf.(*config.GnutlsConfig).ElfType {
case config.ElfTypeSo:
binaryPath = g.conf.(*config.GnutlsConfig).Gnutls
default:
//如果没找到 "/lib/x86_64-linux-gnu/libgnutls.so.30"
binaryPath = path.Join(defaultSoPath, "libgnutls.so.30")
}
_, err := os.Stat(binaryPath)
if err != nil {
return err
}

g.logger.Info().Str("binaryPath", binaryPath).Uint8("elfType", g.conf.(*config.GnutlsConfig).ElfType).Msg("gnutls binary path")
g.bpfManager = &manager.Manager{
Probes: []*manager.Probe{
{
Section: "uprobe/gnutls_record_send",
EbpfFuncName: "probe_entry_SSL_write",
AttachToFuncName: "gnutls_record_send",
BinaryPath: binaryPath,
},
{
Section: "uretprobe/gnutls_record_send",
EbpfFuncName: "probe_ret_SSL_write",
AttachToFuncName: "gnutls_record_send",
BinaryPath: binaryPath,
},
{
Section: "uprobe/gnutls_record_recv",
EbpfFuncName: "probe_entry_SSL_read",
AttachToFuncName: "gnutls_record_recv",
BinaryPath: binaryPath,
},
{
Section: "uretprobe/gnutls_record_recv",
EbpfFuncName: "probe_ret_SSL_read",
AttachToFuncName: "gnutls_record_recv",
BinaryPath: binaryPath,
},
},

Maps: []*manager.Map{
{
Name: "gnutls_events",
},
},
}

g.bpfManagerOptions = manager.Options{
DefaultKProbeMaxActive: 512,

VerifierOptions: ebpf.CollectionOptions{
Programs: ebpf.ProgramOptions{
LogSize: 2097152,
},
},

RLimit: &unix.Rlimit{
Cur: math.MaxUint64,
Max: math.MaxUint64,
},
}

if g.conf.EnableGlobalVar() {
// 填充 RewriteContants 对应map
g.bpfManagerOptions.ConstantEditors = g.constantEditor()
}
return nil
}

func (g *MGnutlsProbe) DecodeFun(em *ebpf.Map) (event.IEventStruct, bool) {
fun, found := g.eventFuncMaps[em]
return fun, found
}

func (g *MGnutlsProbe) initDecodeFunText() error {
//GnutlsEventsMap 与解码函数映射
GnutlsEventsMap, found, err := g.bpfManager.GetMap("gnutls_events")
if err != nil {
return err
}
if !found {
return errors.New("cant found map:gnutls_events")
}
g.eventMaps = append(g.eventMaps, GnutlsEventsMap)
g.eventFuncMaps[GnutlsEventsMap] = &event.GnutlsDataEvent{}

return nil
}

func (g *MGnutlsProbe) Events() []*ebpf.Map {
return g.eventMaps
}
Expand Down
17 changes: 1 addition & 16 deletions user/module/probe_gnutls_keylog.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import (
"errors"
"fmt"
"math"
"os"
"path"

"github.com/cilium/ebpf"
manager "github.com/gojue/ebpfmanager"
Expand Down Expand Up @@ -54,20 +52,7 @@ var GnutlsVersionToString = map[int32]string{
}

func (g *MGnutlsProbe) setupManagersKeylog() error {
var binaryPath string
switch g.conf.(*config.GnutlsConfig).ElfType {
case config.ElfTypeSo:
binaryPath = g.conf.(*config.GnutlsConfig).Gnutls
default:
//如果没找到 "/lib/x86_64-linux-gnu/libgnutls.so.30"
binaryPath = path.Join(defaultSoPath, "libgnutls.so.30")
}
_, err := os.Stat(binaryPath)
if err != nil {
return err
}

g.logger.Info().Str("binaryPath", binaryPath).Uint8("elfType", g.conf.(*config.GnutlsConfig).ElfType).Msg("gnutls binary path")
binaryPath := g.conf.(*config.GnutlsConfig).Gnutls
g.bpfManager = &manager.Manager{
Probes: []*manager.Probe{
{
Expand Down
194 changes: 194 additions & 0 deletions user/module/probe_gnutls_lib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
// Author: yuweizzz <yuwei764969238@gmail.com>.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package module

import (
"debug/elf"
"fmt"
"os"
"path"
"regexp"

"github.com/gojue/ecapture/user/config"
)

const GnuTLSDefaultVersion = "3.6.12"
const GnuTLSVersionLen = 32

func readelf(binaryPath string) (string, error) {
f, err := os.OpenFile(binaryPath, os.O_RDONLY, os.ModePerm)
if err != nil {
return "", fmt.Errorf("Can not open %s, with error: %v", binaryPath, err)
}
defer f.Close()
r, err := elf.NewFile(f)
if err != nil {
return "", fmt.Errorf("Parse the ELF file %s failed, with error: %v", binaryPath, err)
}
defer r.Close()

switch r.FileHeader.Machine {
case elf.EM_X86_64:
case elf.EM_AARCH64:
default:
return "", fmt.Errorf(
"Unsupported arch library, ELF Header Machine is: %s, must be one of EM_X86_64 and EM_AARCH64",
r.FileHeader.Machine.String())
}

s := r.Section(".rodata")
if s == nil {
// .rodata not found
return "", fmt.Errorf("Detect GnuTLS version failed, cant read .rodata section from %s", binaryPath)
}

sectionOffset := int64(s.Offset)
sectionSize := s.Size

_, err = f.Seek(0, 0)
if err != nil {
return "", err
}

ret, err := f.Seek(sectionOffset, 0)
if ret != sectionOffset || err != nil {
return "", err
}

rex, err := regexp.Compile(`Enabled GnuTLS ([0-9\.]+) logging...`)
if err != nil {
return "", err
}

buf := make([]byte, 1024*1024) // 1Mb
totalReadCount := 0
for totalReadCount < int(sectionSize) {
readCount, err := f.Read(buf)
if err != nil {
return "", err
}

if readCount == 0 {
break
}

match := rex.FindSubmatch(buf)
if len(match) == 2 {
return string(match[1]), nil
}

// just like "probe_openssl_lib.go",
// "Enabled GnuTLS 3.x.xx logging..." is 32 chars.
totalReadCount += readCount - GnuTLSVersionLen

_, err = f.Seek(sectionOffset+int64(totalReadCount), 0)
if err != nil {
return "", err
}
clear(buf)
}
return "", fmt.Errorf("Unknown error")
}

func (m *MGnutlsProbe) detectGnutls() error {
var binaryPath string
switch m.conf.(*config.GnutlsConfig).ElfType {
case config.ElfTypeSo:
binaryPath = m.conf.(*config.GnutlsConfig).Gnutls
default:
// Default: "/lib/x86_64-linux-gnu/libgnutls.so.30"
binaryPath = path.Join(defaultSoPath, "libgnutls.so.30")
}
_, err := os.Stat(binaryPath)
if err != nil {
return err
}

ConfigSslVersion := m.conf.(*config.GnutlsConfig).SslVersion
if len(ConfigSslVersion) > 0 {
m.sslVersion = ConfigSslVersion
m.logger.Info().Str("GnuTLS Version", m.sslVersion).Msg("GnuTLS version configured")
} else {
sslVersion, err := readelf(binaryPath)
if err != nil {
m.logger.Error().Err(err)
}
m.sslVersion = sslVersion
if len(m.sslVersion) == 0 {
m.logger.Warn().Str("GnuTLS Version", GnuTLSDefaultVersion).Msg("GnuTLS version not found, used default version")
m.sslVersion = GnuTLSDefaultVersion
}
m.logger.Info().Str("Version", m.sslVersion).Msg("GnuTLS version found")
}

m.logger.Info().Str("binaryPath", binaryPath).Uint8("elfType", m.conf.(*config.GnutlsConfig).ElfType).Msg("GnuTLS binary path")
switch m.sslVersion {
case "3.8.7":
m.sslBpfFile = m.geteBPFName("user/bytecode/gnutls_3_8_7_kern.o")
case "3.8.6":
fallthrough
case "3.8.5":
fallthrough
case "3.8.4":
m.sslBpfFile = m.geteBPFName("user/bytecode/gnutls_3_8_4_kern.o")
case "3.8.3":
fallthrough
case "3.8.2":
fallthrough
case "3.8.1":
fallthrough
case "3.8.0":
fallthrough
case "3.7.11":
fallthrough
case "3.7.10":
fallthrough
case "3.7.9":
fallthrough
case "3.7.8":
fallthrough
case "3.7.7":
m.sslBpfFile = m.geteBPFName("user/bytecode/gnutls_3_7_7_kern.o")
case "3.7.6":
fallthrough
case "3.7.5":
fallthrough
case "3.7.4":
fallthrough
case "3.7.3":
m.sslBpfFile = m.geteBPFName("user/bytecode/gnutls_3_7_3_kern.o")
case "3.7.2":
fallthrough
case "3.7.1":
fallthrough
case "3.7.0":
m.sslBpfFile = m.geteBPFName("user/bytecode/gnutls_3_7_0_kern.o")
case "3.6.16":
fallthrough
case "3.6.15":
fallthrough
case "3.6.14":
m.sslBpfFile = m.geteBPFName("user/bytecode/gnutls_3_6_14_kern.o")
case "3.6.13":
fallthrough
case "3.6.12":
m.sslBpfFile = m.geteBPFName("user/bytecode/gnutls_3_6_12_kern.o")
default:
m.sslBpfFile = m.geteBPFName("user/bytecode/gnutls_3_6_12_kern.o")
m.logger.Warn().Msg("GnuTLS version not supported, used default bpf bytecode file")
}
m.logger.Info().Str("bytecode filename", m.sslBpfFile).Msg("BPF bytecode loaded")
return nil
}
Loading

0 comments on commit 843c124

Please sign in to comment.