Skip to content

Commit

Permalink
support symbols in sections .data.rel.ro.gopclntab and .data.rel.ro.
Browse files Browse the repository at this point in the history
see PR #512 for more info .

Signed-off-by: CFC4N <cfc4n.cs@gmail.com>
  • Loading branch information
cfc4n committed Mar 30, 2024
1 parent dd0c48a commit d53387f
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 60 deletions.
2 changes: 1 addition & 1 deletion kern/gotls_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ static __always_inline int gotls_mastersecret(struct pt_regs *ctx,
return 0;
}

debug_bpf_printk("gotls_mastersecret read mastersecret label%s\n",
debug_bpf_printk("gotls_mastersecret read mastersecret label:%s\n",
mastersecret_gotls.label);
ret = bpf_probe_read_user_str(&mastersecret_gotls.client_random,
sizeof(mastersecret_gotls.client_random),
Expand Down
146 changes: 90 additions & 56 deletions user/config/config_gotls.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ import (
)

const (
// 46EE50 - 46EDB0
//
GoTlsReadFunc = "crypto/tls.(*Conn).Read"

GoTlsReadFunc = "crypto/tls.(*Conn).Read"
GoTlsWriteFunc = "crypto/tls.(*Conn).writeRecordLocked"
GoTlsMasterSecretFunc = "crypto/tls.(*Config).writeKeyLog"
// crypto_tls._ptr_Conn.Read
GoTlsReadFuncArm64 = "crypto_tls._ptr_Conn.Read"

/*
我是通过IDA静态分析符号发现`crypto/tls.(*Conn).Read`的地址是`46EE50`。用程序计算出来的总是比这个数字少了`0x120` ,通过分析其他多个编译的程序,发现差值总是`0x120`。
所以,我定义了一个常量,增加到程序计算的地址上。但是我不知道原因,如果你知道,请告诉我。更多信息见:https://github.com/gojue/ecapture/pull/512
*/
IdaProOffset = 0x120
)

var (
Expand Down Expand Up @@ -88,7 +89,7 @@ type GoTLSConfig struct {
PcapFilter string `json:"pcapFilter"` // pcap filter
goElfArch string //
goElf *elf.File //
buildinfo *buildinfo.BuildInfo
Buildinfo *buildinfo.BuildInfo
ReadTlsAddrs []int
GoTlsWriteAddr uint64
GoTlsMasterSecretAddr uint64
Expand Down Expand Up @@ -119,7 +120,7 @@ func (gc *GoTLSConfig) Check() error {
}

// Read the build information of the Go application
gc.buildinfo, err = buildinfo.ReadFile(gc.Path)
gc.Buildinfo, err = buildinfo.ReadFile(gc.Path)
if err != nil {
return err
}
Expand Down Expand Up @@ -154,7 +155,7 @@ func (gc *GoTLSConfig) Check() error {
gc.goElf = goElf
// If built with PIE and stripped, gopclntab is
// unlabeled and nested under .data.rel.ro.
for _, bs := range gc.buildinfo.Settings {
for _, bs := range gc.Buildinfo.Settings {
if bs.Key == "-buildmode" {
if bs.Value == "pie" {
gc.IsPieBuildMode = true
Expand All @@ -167,16 +168,21 @@ func (gc *GoTLSConfig) Check() error {
if err != nil {
return err
}
fun := gc.goSymTab.LookupFunc(GoTlsWriteFunc)
if fun != nil {
gc.GoTlsWriteAddr = fun.Entry
var addr uint64
addr, err = gc.findPieSymbolAddr(GoTlsWriteFunc)
if err != nil {
return fmt.Errorf("%s symbol address error:%s", GoTlsWriteFunc, err.Error())
}
fun = gc.goSymTab.LookupFunc(GoTlsMasterSecretFunc)
if fun != nil {
gc.GoTlsMasterSecretAddr = fun.Entry
gc.GoTlsWriteAddr = addr
addr, err = gc.findPieSymbolAddr(GoTlsMasterSecretFunc)
if err != nil {
return fmt.Errorf("%s symbol address error:%s", GoTlsMasterSecretFunc, err.Error())
}
gc.GoTlsMasterSecretAddr = addr

gc.ReadTlsAddrs, err = gc.findRetOffsetsPie(GoTlsReadFunc)
if err != nil {
panic(err)
return err
}
} else {
Expand All @@ -188,20 +194,6 @@ func (gc *GoTLSConfig) Check() error {
return err
}

func (gc *GoTLSConfig) findRetOffsetsPie(symbolName string) ([]int, error) {
var offsets []int
var err error

fun := gc.goSymTab.LookupFunc(symbolName)
if fun == nil {
return nil, ErrorSymbolNotFoundFromTable
}

//fmt.Printf("found in %s, entry:%x, end:%x , end-entry:%x\n", fun.Name, fun.Entry, fun.End, fun.End-fun.Entry)
offsets, err = gc.findFuncOffsetBySymfun(fun, gc.goElf)
return offsets, err
}

// FindRetOffsets searches for the addresses of all RET instructions within
// the instruction set associated with the specified symbol in an ELF program.
// It is used for mounting uretprobe programs for Golang programs,
Expand All @@ -214,7 +206,6 @@ func (gc *GoTLSConfig) findRetOffsets(symbolName string) ([]int, error) {
if len(goSymbs) > 0 {
allSymbs = append(allSymbs, goSymbs...)
}

goDynamicSymbs, _ := gc.goElf.DynamicSymbols()
if len(goDynamicSymbs) > 0 {
allSymbs = append(allSymbs, goDynamicSymbs...)
Expand Down Expand Up @@ -256,6 +247,23 @@ func (gc *GoTLSConfig) findRetOffsets(symbolName string) ([]int, error) {
if len(offsets) == 0 {
return offsets, ErrorNoRetFound
}

address := symbol.Value
for _, prog := range gc.goElf.Progs {
// Skip uninteresting segments.
if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {
continue
}

if prog.Vaddr <= symbol.Value && symbol.Value < (prog.Vaddr+prog.Memsz) {
// stackoverflow.com/a/40249502
address = symbol.Value - prog.Vaddr + prog.Off
break
}
}
for i, offset := range offsets {
offsets[i] = int(address) + offset
}
return offsets, nil
}

Expand All @@ -278,29 +286,33 @@ func (gc *GoTLSConfig) checkModel() (string, error) {
}

func (gc *GoTLSConfig) ReadTable() (*gosym.Table, error) {
sectionLabel := ".data.rel.ro"
sectionLabel := ".gopclntab"
section := gc.goElf.Section(sectionLabel)
if section == nil {
// binary may be built with -pie
sectionLabel = ".gopclntab"
sectionLabel = ".data.rel.ro.gopclntab"
section = gc.goElf.Section(sectionLabel)
if section == nil {
return nil, fmt.Errorf("could not read section %s from %s ", sectionLabel, gc.Path)
sectionLabel = ".data.rel.ro"
section = gc.goElf.Section(sectionLabel)
if section == nil {
return nil, fmt.Errorf("could not read section %s from %s ", sectionLabel, gc.Path)
}
}
}
tableData, err := section.Data()
if err != nil {
return nil, fmt.Errorf("found section but could not read %s from %s ", sectionLabel, gc.Path)
}

// Find .gopclntab by magic number even if there is no section label
magic := magicNumber(gc.buildinfo.GoVersion)
magic := magicNumber(gc.Buildinfo.GoVersion)
pclntabIndex := bytes.Index(tableData, magic)
//fmt.Printf("buildinfo :%v, magic:%x, pclntabIndex:%d offset:%x , section:%v \n", gc.buildinfo, magic, pclntabIndex, section.Offset, section)
//fmt.Printf("Buildinfo :%v, magic:%x, pclntabIndex:%d offset:%x , section:%v \n", gc.Buildinfo, magic, pclntabIndex, section.Offset, section)
if pclntabIndex < 0 {
return nil, fmt.Errorf("could not find magic number in %s ", gc.Path)
}
tableData = tableData[pclntabIndex:]

addr := gc.goElf.Section(".text").Addr
lineTable := gosym.NewLineTable(tableData, addr)
symTable, err := gosym.NewTable([]byte{}, lineTable)
Expand All @@ -310,38 +322,60 @@ func (gc *GoTLSConfig) ReadTable() (*gosym.Table, error) {
return symTable, nil
}

func (gc *GoTLSConfig) findFuncOffsetBySymfun(f *gosym.Func, elfF *elf.File) ([]int, error) {
func (gc *GoTLSConfig) findRetOffsetsPie(lfunc string) ([]int, error) {
var offsets []int
var address uint64
var err error
address, err = gc.findPieSymbolAddr(lfunc)
if err != nil {
return offsets, err
}
f := gc.goSymTab.LookupFunc(lfunc)
funcLen := f.End - f.Entry
for _, prog := range gc.goElf.Progs {
if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {
continue
}
data := make([]byte, funcLen)
_, err = prog.ReadAt(data, int64(address))
if err != nil {
return offsets, fmt.Errorf("finding function return: %w", err)
}
offsets, err = gc.decodeInstruction(data)
if err != nil {
return offsets, fmt.Errorf("finding function return: %w", err)
}
for i, offset := range offsets {
offsets[i] = int(address) + offset
}
return offsets, nil
}
return offsets, errors.New("cant found gotls symbol offsets.")
}

for _, prog := range elfF.Progs {
func (gc *GoTLSConfig) findPieSymbolAddr(lfunc string) (uint64, error) {
f := gc.goSymTab.LookupFunc(lfunc)
if f == nil {
return 0, errors.New("Cant found symbol address on pie model.")
}
var err error
var address uint64
for _, prog := range gc.goElf.Progs {
if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {
continue
}
// For more info on this calculation: stackoverflow.com/a/40249502
/*
ida : start : 46EE50, end : 46F258 , len :0x408
elf info: start : 46ed30, end : , len: 0x3B0, 0x58
*/
address = f.Value

Check failure on line 368 in user/config/config_gotls.go

View workflow job for this annotation

GitHub Actions / build on ubuntu-20.04 x86_64

SA4006: this value of `address` is never used (staticcheck)

Check failure on line 368 in user/config/config_gotls.go

View workflow job for this annotation

GitHub Actions / build on ubuntu-22.04 x86_64

SA4006: this value of `address` is never used (staticcheck)
if prog.Vaddr <= f.Value && f.Value < (prog.Vaddr+prog.Memsz) {
funcLen := f.End - f.Entry
fmt.Printf("name :%s, f.Value:%x, f.Entry:%x, f.End:%x, funcLen:%X \n ", f.Name, f.Value, f.Entry, f.End, funcLen)
data := make([]byte, funcLen)
_, err = prog.ReadAt(data, int64(f.Value-prog.Vaddr))
address = f.Value - prog.Vaddr + prog.Off + IdaProOffset
_, err = prog.ReadAt(data, int64(address))
if err != nil {
return offsets, fmt.Errorf("finding function return: %w", err)
}

offsets, err = gc.decodeInstruction(data)
if err != nil {
return offsets, fmt.Errorf("finding function return: %w", err)
}
for i, offset := range offsets {
offsets[i] = int(f.Entry) + offset
return 0, fmt.Errorf("search function return: %w", err)
}
return offsets, nil
return address, nil
}
}
return offsets, ErrorNoRetFoundFromSymTabFun
return 0, ErrorNoRetFoundFromSymTabFun
}
2 changes: 2 additions & 0 deletions user/event/event_gotls.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ func (ge *GoTLSEvent) Decode(payload []byte) error {
if err = binary.Read(r, binary.LittleEndian, &ge.Data); err != nil {
return err
}
} else {
ge.Len = 0
}
decodedKtime, err := DecodeKtime(int64(ge.TimestampNS), true)
if err == nil {
Expand Down
22 changes: 19 additions & 3 deletions user/module/probe_gotls_keylog.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,28 @@ import (
manager "github.com/gojue/ebpfmanager"
"golang.org/x/sys/unix"
"math"
"strings"
)

func (g *GoTLSProbe) setupManagersKeylog() error {

g.logger.Printf("%s\tHOOK type:golang elf, binrayPath:%s\n", g.Name(), g.path)
g.logger.Printf("%s\tHook masterKey function:%s, Address:%x \n", g.Name(), config.GoTlsMasterSecretFunc, g.conf.(*config.GoTLSConfig).GoTlsMasterSecretAddr)
var gotlsConf = g.conf.(*config.GoTLSConfig)
var buildInfo = new(strings.Builder)
for _, setting := range gotlsConf.Buildinfo.Settings {
if setting.Value == "" {
continue
}
buildInfo.WriteString(" ")
buildInfo.WriteString(setting.Key)
buildInfo.WriteString("=")
buildInfo.WriteString(setting.Value)
}
g.logger.Printf("%s\tHOOK type:Golang elf, binrayPath:%s\n", g.Name(), g.path)
g.logger.Printf("%s\tGolang buildInfo version:%s, Params: %s\n", g.Name(), gotlsConf.Buildinfo.GoVersion, buildInfo.String())
if gotlsConf.IsPieBuildMode {
// buildmode pie is enabled.
g.logger.Printf("%s\tGolang elf buildmode with pie\n", g.Name())
}
g.logger.Printf("%s\tHook masterKey function:%s, Address:%x \n", g.Name(), config.GoTlsMasterSecretFunc, gotlsConf.GoTlsMasterSecretAddr)

var (
sec string
Expand Down
4 changes: 4 additions & 0 deletions user/module/probe_gotls_text.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func (g *GoTLSProbe) setupManagersText() error {
readFn = "gotls_read_stack"
}
g.logger.Printf("%s\teBPF Function Name:%s, isRegisterABI:%t\n", g.Name(), fn, g.isRegisterABI)
if g.conf.(*config.GoTLSConfig).IsPieBuildMode {
// buildmode pie is enabled.
g.logger.Printf("%s\tGolang elf buildmode with pie\n", g.Name())
}
g.bpfManager = &manager.Manager{
Probes: []*manager.Probe{
{
Expand Down

0 comments on commit d53387f

Please sign in to comment.