-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] support capture dash and zsh command #671
Conversation
@yuweizzz Could you review and test it? |
@@ -0,0 +1,54 @@ | |||
// Copyright 2022 CFC4N <cfc4n.cs@gmail.com>. All Rights Reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please disable compilation of the Android version, including other golang files involving dash/zsh
.
//go:build !androidgki
// +build !androidgki
|
||
func init() { | ||
dashCmd.PersistentFlags().StringVar(&dc.Dashpath, "dash", "", "$SHELL file path, eg: /bin/dash , will automatically find it from $ENV default.") | ||
dashCmd.PersistentFlags().StringVar(&dc.Readline, "readlineso", "", "readline.so file path, will automatically find it from $BASH_PATH default.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the readlineso
flag required? And, is the from $BASH_PATH default
description wrong?
|
||
func init() { | ||
zshCmd.PersistentFlags().StringVar(&zc.Zshpath, "zsh", "", "$SHELL file path, eg: /bin/zsh , will automatically find it from $ENV default.") | ||
zshCmd.PersistentFlags().StringVar(&zc.Readline, "readlineso", "", "readline.so file path, will automatically find it from $BASH_PATH default.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here
kern/dash_kern.c
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that the kernel space code is not very different from bash_kern.c
. Is it possible to reuse a copy of the bytecode? Is this possible by just setting different hook functions in the ebpf loader?
@ruitianzhong @sancppp What do you think?
func calReadFuncAddressByObjdump(elfPath string) (uint64, error) { | ||
//0000000000005800 <read@plt>: | ||
cmd := fmt.Sprintf("%s -d /bin/dash | grep read@plt | head -n 1", elfPath) | ||
out, err := exec.Command("/bin/sh", "-c", cmd).Output() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Executing external commands is not a good practice, can it be achieved using debug/elf
?
via:
ecapture/user/config/config_gotls.go
Lines 124 to 187 in fcddaeb
goElf, err = elf.Open(gc.Path) | |
if err != nil { | |
return err | |
} | |
var goElfArch string | |
switch goElf.FileHeader.Machine.String() { | |
case elf.EM_AARCH64.String(): | |
goElfArch = "arm64" | |
case elf.EM_X86_64.String(): | |
goElfArch = "amd64" | |
default: | |
goElfArch = "unsupport_arch" | |
} | |
if goElfArch != runtime.GOARCH { | |
err = fmt.Errorf("Go Application not match, want:%s, have:%s", runtime.GOARCH, goElfArch) | |
return err | |
} | |
switch goElfArch { | |
case "amd64": | |
case "arm64": | |
default: | |
return fmt.Errorf("unsupport CPU arch :%s", goElfArch) | |
} | |
gc.goElfArch = goElfArch | |
gc.goElf = goElf | |
// If built with PIE and stripped, gopclntab is | |
// unlabeled and nested under .data.rel.ro. | |
for _, bs := range gc.Buildinfo.Settings { | |
if bs.Key == "-buildmode" { | |
if bs.Value == "pie" { | |
gc.IsPieBuildMode = true | |
} | |
break | |
} | |
} | |
if gc.IsPieBuildMode { | |
gc.goSymTab, err = gc.ReadTable() | |
if err != nil { | |
return err | |
} | |
var addr uint64 | |
addr, err = gc.findPieSymbolAddr(GoTlsWriteFunc) | |
if err != nil { | |
return fmt.Errorf("%s symbol address error:%s", GoTlsWriteFunc, err.Error()) | |
} | |
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 { | |
return err | |
} | |
} else { | |
gc.ReadTlsAddrs, err = gc.findRetOffsets(GoTlsReadFunc) | |
if err != nil { | |
return err | |
} | |
} |
|
||
var readlineFuncName string // 将默认hook函数改为readline_internal_teardown说明:https://github.com/gojue/ecapture/pull/479 | ||
readlineFuncName = b.conf.(*config.DashConfig).ReadlineFuncName | ||
addr, err := b.calReadFuncAddress() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addr
should be a configuration item, passed in by the config.DashConfig
structure, that is to say, the function of finding the offset address should be placed in the config
package.
different behavior with bash, a single enter will trigger new event:
ditto:
|
dash源码中,当前考虑通过probe libc库中read函数进行命令行读取, |
support dash and zsh command capture via ebpf u[ret]probe