From 675791b10ad0fa8b0ef05a785df60444106fa208 Mon Sep 17 00:00:00 2001 From: cfc4n Date: Fri, 1 Dec 2023 23:23:12 +0800 Subject: [PATCH 1/3] split gnutls module. Signed-off-by: cfc4n --- cli/cmd/gnutls.go | 149 ++++++++++++++++++++++++++++++++++++++++++++++ cli/cmd/root.go | 2 +- cli/cmd/tls.go | 11 +--- 3 files changed, 153 insertions(+), 9 deletions(-) create mode 100644 cli/cmd/gnutls.go diff --git a/cli/cmd/gnutls.go b/cli/cmd/gnutls.go new file mode 100644 index 000000000..e6962ab5c --- /dev/null +++ b/cli/cmd/gnutls.go @@ -0,0 +1,149 @@ +//go:build !androidgki +// +build !androidgki + +// Copyright 2022 CFC4N . All Rights Reserved. +// +// 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 cmd + +import ( + "context" + "ecapture/pkg/util/kernel" + "ecapture/user/config" + "ecapture/user/module" + "log" + "os" + "os/signal" + "sync" + "syscall" + + "github.com/spf13/cobra" +) + +var gc = config.NewGnutlsConfig() + +// gnutlsCmd represents the openssl command +var gnutlsCmd = &cobra.Command{ + Use: "gnutls", + Aliases: []string{"gnu"}, + Short: "capture gnutls text content without CA cert for gnutls libraries.", + Long: `use eBPF uprobe/TC to capture process event data and network data.also support pcap-NG format. +ecapture gnutls +ecapture gnutls --hex --pid=3423 +ecapture gnutls -l save.log --pid=3423 +ecapture gnutls --gnutls=/lib/x86_64-linux-gnu/libgnutls.so +`, + Run: gnuTlsCommandFunc, +} + +func init() { + //opensslCmd.PersistentFlags().StringVar(&gc.Curlpath, "wget", "", "wget file path, default: /usr/bin/wget. (Deprecated)") + gnutlsCmd.PersistentFlags().StringVar(&gc.Gnutls, "gnutls", "", "libgnutls.so file path, will automatically find it from curl default.") + rootCmd.AddCommand(gnutlsCmd) +} + +// gnuTlsCommandFunc executes the "bash" command. +func gnuTlsCommandFunc(command *cobra.Command, args []string) { + stopper := make(chan os.Signal, 1) + signal.Notify(stopper, os.Interrupt, syscall.SIGTERM) + ctx, cancelFun := context.WithCancel(context.TODO()) + + logger := log.New(os.Stdout, "tls_", log.LstdFlags) + + // save global config + gConf, err := getGlobalConf(command) + if err != nil { + logger.Fatal(err) + } + logger.SetOutput(gConf.writer) + + logger.Printf("ECAPTURE :: %s Version : %s", cliName, GitVersion) + logger.Printf("ECAPTURE :: Pid Info : %d", os.Getpid()) + var version kernel.Version + version, err = kernel.HostVersion() + logger.Printf("ECAPTURE :: Kernel Info : %s", version.String()) + modNames := []string{module.ModuleNameGnutls} + + var runMods uint8 + var runModules = make(map[string]module.IModule) + var wg sync.WaitGroup + + for _, modName := range modNames { + mod := module.GetModuleByName(modName) + if mod == nil { + logger.Printf("ECAPTURE :: \tcant found module: %s", modName) + break + } + + var conf config.IConfig + conf = gc + if conf == nil { + logger.Printf("ECAPTURE :: \tcant found module %s config info.", mod.Name()) + break + } + + conf.SetPid(gConf.Pid) + conf.SetUid(gConf.Uid) + conf.SetDebug(gConf.Debug) + conf.SetHex(gConf.IsHex) + + err = conf.Check() + + if err != nil { + logger.Printf("%s\tmodule initialization failed. [skip it]. error:%+v", mod.Name(), err) + continue + } + + logger.Printf("%s\tmodule initialization", mod.Name()) + + //初始化 + err = mod.Init(ctx, logger, conf) + if err != nil { + logger.Printf("%s\tmodule initialization failed, [skip it]. error:%+v", mod.Name(), err) + continue + } + + err = mod.Run() + if err != nil { + logger.Printf("%s\tmodule run failed, [skip it]. error:%+v", mod.Name(), err) + continue + } + runModules[mod.Name()] = mod + logger.Printf("%s\tmodule started successfully.", mod.Name()) + wg.Add(1) + runMods++ + } + + // needs runmods > 0 + if runMods > 0 { + logger.Printf("ECAPTURE :: \tstart %d modules", runMods) + <-stopper + } else { + logger.Println("ECAPTURE :: \tNo runnable modules, Exit(1)") + os.Exit(1) + } + cancelFun() + + // clean up + for _, mod := range runModules { + err = mod.Close() + wg.Done() + if err != nil { + logger.Fatalf("%s\tmodule close failed. error:%+v", mod.Name(), err) + } + } + + wg.Wait() + os.Exit(0) +} diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 6bfed1be8..6dfef3dcf 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -46,7 +46,7 @@ var rootCmd = &cobra.Command{ such as HTTPS and TLS without installing a CA certificate. It can also capture bash commands, which is suitable for security auditing scenarios, such as database auditing of mysqld, etc (disabled on Android). - +Support Linux(Android) X86_64 4.18/aarch64 5.5 or newer. Repository: https://github.com/gojue/ecapture HomePage: https://ecapture.cc diff --git a/cli/cmd/tls.go b/cli/cmd/tls.go index 732f8f467..e577e4741 100644 --- a/cli/cmd/tls.go +++ b/cli/cmd/tls.go @@ -29,14 +29,13 @@ import ( ) var oc = config.NewOpensslConfig() -var gc = config.NewGnutlsConfig() var nc = config.NewNsprConfig() // opensslCmd represents the openssl command var opensslCmd = &cobra.Command{ Use: "tls", - Aliases: []string{"openssl", "gnutls", "nss"}, - Short: "use to capture tls/ssl text content without CA cert. (Support Linux(Android) X86_64 4.18/aarch64 5.5 or newer).", + Aliases: []string{"openssl", "nss"}, + Short: "use to capture tls/ssl text content without CA cert. (Support openssl 1.0.x/1.1.x/3.0.x or newer).", Long: `use eBPF uprobe/TC to capture process event data and network data.also support pcap-NG format. ecapture tls ecapture tls --hex --pid=3423 @@ -52,8 +51,6 @@ func init() { //opensslCmd.PersistentFlags().StringVar(&oc.Curlpath, "curl", "", "curl or wget file path, use to dectet openssl.so path, default:/usr/bin/curl. (Deprecated)") opensslCmd.PersistentFlags().StringVar(&oc.Openssl, "libssl", "", "libssl.so file path, will automatically find it from curl default.") opensslCmd.PersistentFlags().StringVar(&oc.CGroupPath, "cgroup_path", "/sys/fs/cgroup", "cgroup path, default: /sys/fs/cgroup.") - opensslCmd.PersistentFlags().StringVar(&gc.Gnutls, "gnutls", "", "libgnutls.so file path, will automatically find it from curl default.") - //opensslCmd.PersistentFlags().StringVar(&gc.Curlpath, "wget", "", "wget file path, default: /usr/bin/wget. (Deprecated)") //opensslCmd.PersistentFlags().StringVar(&nc.Firefoxpath, "firefox", "", "firefox file path, default: /usr/lib/firefox/firefox. (Deprecated)") opensslCmd.PersistentFlags().StringVar(&nc.Nsprpath, "nspr", "", "libnspr44.so file path, will automatically find it from curl default.") opensslCmd.PersistentFlags().StringVar(&oc.Pthread, "pthread", "", "libpthread.so file path, use to hook connect to capture socket FD.will automatically find it from curl.") @@ -89,7 +86,7 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { if config.ElfArchIsandroid || oc.Write != "" { modNames = []string{module.ModuleNameOpenssl} } else { - modNames = []string{module.ModuleNameOpenssl, module.ModuleNameGnutls, module.ModuleNameNspr} + modNames = []string{module.ModuleNameOpenssl, module.ModuleNameNspr} } var runMods uint8 @@ -107,8 +104,6 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { switch mod.Name() { case module.ModuleNameOpenssl: conf = oc - case module.ModuleNameGnutls: - conf = gc case module.ModuleNameNspr: conf = nc default: From 8d0cc8c19977b96009b4dc847d63c7b195dc5428 Mon Sep 17 00:00:00 2001 From: cfc4n Date: Fri, 1 Dec 2023 23:36:04 +0800 Subject: [PATCH 2/3] splitting nss/nspr module. Signed-off-by: cfc4n --- cli/cmd/gnutls.go | 2 +- cli/cmd/nss.go | 149 ++++++++++++++++++++++++++++++++++++++++++++++ cli/cmd/tls.go | 21 +------ 3 files changed, 153 insertions(+), 19 deletions(-) create mode 100644 cli/cmd/nss.go diff --git a/cli/cmd/gnutls.go b/cli/cmd/gnutls.go index e6962ab5c..f14d3ff4b 100644 --- a/cli/cmd/gnutls.go +++ b/cli/cmd/gnutls.go @@ -38,7 +38,7 @@ var gnutlsCmd = &cobra.Command{ Use: "gnutls", Aliases: []string{"gnu"}, Short: "capture gnutls text content without CA cert for gnutls libraries.", - Long: `use eBPF uprobe/TC to capture process event data and network data.also support pcap-NG format. + Long: `use eBPF uprobe/TC to capture process event data. ecapture gnutls ecapture gnutls --hex --pid=3423 ecapture gnutls -l save.log --pid=3423 diff --git a/cli/cmd/nss.go b/cli/cmd/nss.go new file mode 100644 index 000000000..faff747ce --- /dev/null +++ b/cli/cmd/nss.go @@ -0,0 +1,149 @@ +//go:build !androidgki +// +build !androidgki + +// Copyright 2022 CFC4N . All Rights Reserved. +// +// 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 cmd + +import ( + "context" + "ecapture/pkg/util/kernel" + "ecapture/user/config" + "ecapture/user/module" + "log" + "os" + "os/signal" + "sync" + "syscall" + + "github.com/spf13/cobra" +) + +var nc = config.NewNsprConfig() + +// gnutlsCmd represents the openssl command +var nssCmd = &cobra.Command{ + Use: "nss", + Aliases: []string{"nspr"}, + Short: "capture nss/nspr encrypted text content without CA cert for nss/nspr libraries.", + Long: `use eBPF uprobe/TC to capture process event data. +ecapture nss +ecapture nss --hex --pid=3423 +ecapture nss -l save.log --pid=3423 +ecapture nss --nspr=/lib/x86_64-linux-gnu/libnspr44.so +`, + Run: nssCommandFunc, +} + +func init() { + //nssCmd.PersistentFlags().StringVar(&nc.Firefoxpath, "firefox", "", "firefox file path, default: /usr/lib/firefox/firefox. (Deprecated)") + nssCmd.PersistentFlags().StringVar(&nc.Nsprpath, "nspr", "", "libnspr44.so file path, will automatically find it from curl default.") + rootCmd.AddCommand(nssCmd) +} + +// nssCommandFunc executes the "bash" command. +func nssCommandFunc(command *cobra.Command, args []string) { + stopper := make(chan os.Signal, 1) + signal.Notify(stopper, os.Interrupt, syscall.SIGTERM) + ctx, cancelFun := context.WithCancel(context.TODO()) + + logger := log.New(os.Stdout, "tls_", log.LstdFlags) + + // save global config + gConf, err := getGlobalConf(command) + if err != nil { + logger.Fatal(err) + } + logger.SetOutput(gConf.writer) + + logger.Printf("ECAPTURE :: %s Version : %s", cliName, GitVersion) + logger.Printf("ECAPTURE :: Pid Info : %d", os.Getpid()) + var version kernel.Version + version, err = kernel.HostVersion() + logger.Printf("ECAPTURE :: Kernel Info : %s", version.String()) + modNames := []string{module.ModuleNameNspr} + + var runMods uint8 + var runModules = make(map[string]module.IModule) + var wg sync.WaitGroup + + for _, modName := range modNames { + mod := module.GetModuleByName(modName) + if mod == nil { + logger.Printf("ECAPTURE :: \tcant found module: %s", modName) + break + } + + var conf config.IConfig + conf = gc + if conf == nil { + logger.Printf("ECAPTURE :: \tcant found module %s config info.", mod.Name()) + break + } + + conf.SetPid(gConf.Pid) + conf.SetUid(gConf.Uid) + conf.SetDebug(gConf.Debug) + conf.SetHex(gConf.IsHex) + + err = conf.Check() + + if err != nil { + logger.Printf("%s\tmodule initialization failed. [skip it]. error:%+v", mod.Name(), err) + continue + } + + logger.Printf("%s\tmodule initialization", mod.Name()) + + //初始化 + err = mod.Init(ctx, logger, conf) + if err != nil { + logger.Printf("%s\tmodule initialization failed, [skip it]. error:%+v", mod.Name(), err) + continue + } + + err = mod.Run() + if err != nil { + logger.Printf("%s\tmodule run failed, [skip it]. error:%+v", mod.Name(), err) + continue + } + runModules[mod.Name()] = mod + logger.Printf("%s\tmodule started successfully.", mod.Name()) + wg.Add(1) + runMods++ + } + + // needs runmods > 0 + if runMods > 0 { + logger.Printf("ECAPTURE :: \tstart %d modules", runMods) + <-stopper + } else { + logger.Println("ECAPTURE :: \tNo runnable modules, Exit(1)") + os.Exit(1) + } + cancelFun() + + // clean up + for _, mod := range runModules { + err = mod.Close() + wg.Done() + if err != nil { + logger.Fatalf("%s\tmodule close failed. error:%+v", mod.Name(), err) + } + } + + wg.Wait() + os.Exit(0) +} diff --git a/cli/cmd/tls.go b/cli/cmd/tls.go index e577e4741..963743861 100644 --- a/cli/cmd/tls.go +++ b/cli/cmd/tls.go @@ -29,12 +29,11 @@ import ( ) var oc = config.NewOpensslConfig() -var nc = config.NewNsprConfig() // opensslCmd represents the openssl command var opensslCmd = &cobra.Command{ Use: "tls", - Aliases: []string{"openssl", "nss"}, + Aliases: []string{"openssl"}, Short: "use to capture tls/ssl text content without CA cert. (Support openssl 1.0.x/1.1.x/3.0.x or newer).", Long: `use eBPF uprobe/TC to capture process event data and network data.also support pcap-NG format. ecapture tls @@ -51,8 +50,6 @@ func init() { //opensslCmd.PersistentFlags().StringVar(&oc.Curlpath, "curl", "", "curl or wget file path, use to dectet openssl.so path, default:/usr/bin/curl. (Deprecated)") opensslCmd.PersistentFlags().StringVar(&oc.Openssl, "libssl", "", "libssl.so file path, will automatically find it from curl default.") opensslCmd.PersistentFlags().StringVar(&oc.CGroupPath, "cgroup_path", "/sys/fs/cgroup", "cgroup path, default: /sys/fs/cgroup.") - //opensslCmd.PersistentFlags().StringVar(&nc.Firefoxpath, "firefox", "", "firefox file path, default: /usr/lib/firefox/firefox. (Deprecated)") - opensslCmd.PersistentFlags().StringVar(&nc.Nsprpath, "nspr", "", "libnspr44.so file path, will automatically find it from curl default.") opensslCmd.PersistentFlags().StringVar(&oc.Pthread, "pthread", "", "libpthread.so file path, use to hook connect to capture socket FD.will automatically find it from curl.") opensslCmd.PersistentFlags().StringVarP(&oc.Write, "write", "w", "", "write the raw packets to file as pcapng format.") opensslCmd.PersistentFlags().StringVarP(&oc.Ifname, "ifname", "i", "", "(TC Classifier) Interface name on which the probe will be attached.") @@ -83,11 +80,7 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { version, err = kernel.HostVersion() logger.Printf("ECAPTURE :: Kernel Info : %s", version.String()) modNames := []string{} - if config.ElfArchIsandroid || oc.Write != "" { - modNames = []string{module.ModuleNameOpenssl} - } else { - modNames = []string{module.ModuleNameOpenssl, module.ModuleNameNspr} - } + modNames = []string{module.ModuleNameOpenssl} var runMods uint8 var runModules = make(map[string]module.IModule) @@ -101,15 +94,7 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { } var conf config.IConfig - switch mod.Name() { - case module.ModuleNameOpenssl: - conf = oc - case module.ModuleNameNspr: - conf = nc - default: - logger.Printf("ECAPTURE :: \t unknow module :%s", mod.Name()) - continue - } + conf = oc if conf == nil { logger.Printf("ECAPTURE :: \tcant found module %s config info.", mod.Name()) From 2676f1dfe12e802b97d0a462b298bfda9ab7edaa Mon Sep 17 00:00:00 2001 From: cfc4n Date: Fri, 1 Dec 2023 23:38:10 +0800 Subject: [PATCH 3/3] add cgo code for striped golang https client see https://github.com/gojue/ecapture/pull/426 for more detail. Signed-off-by: cfc4n --- tests/golang_https.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/golang_https.go b/tests/golang_https.go index 670a1f4c1..75a0bdb22 100644 --- a/tests/golang_https.go +++ b/tests/golang_https.go @@ -1,5 +1,14 @@ package main +/* +#include +#include + +void test() { + printf("hello CGO!\n"); +} +*/ +import "C" import ( "crypto/tls" "fmt" @@ -10,7 +19,7 @@ import ( ) func main() { - + C.test() b, e := GetHttp("https://baidu.com") if e == nil { fmt.Printf("response body: %s\n\n", b)