From 4d444891abe76e3a5c7350ad06a709f46bb98f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?= Date: Sun, 16 Jan 2022 22:31:51 +0800 Subject: [PATCH] feat-dev: support firefox for windows and macos --- .gitignore | 4 + cmd/cmd.go | 184 ++++++++++++++++-------- cmd/hackbrowserdata/main.go | 1 - core/data/output.go | 24 ++-- core/data/parse.go | 2 +- go.mod | 2 +- pkg/browser/browser.go | 216 ++++++++++++++--------------- pkg/browser/browser_darwin.go | 11 +- pkg/browser/browser_linux.go | 1 + pkg/browser/browser_test.go | 20 ++- pkg/browser/browser_windows.go | 98 +++++++++++++ pkg/browser/consts/filename.go | 4 +- pkg/browser/data/bookmark.go | 2 +- pkg/browser/item.go | 22 ++- pkg/browser/outputter/outputter.go | 2 - pkg/decrypter/decrypt_windows.go | 1 + utils/utils.go | 4 +- 17 files changed, 383 insertions(+), 215 deletions(-) delete mode 100644 cmd/hackbrowserdata/main.go create mode 100644 pkg/browser/browser_linux.go create mode 100644 pkg/browser/browser_windows.go diff --git a/.gitignore b/.gitignore index 5ced80a..df9423f 100644 --- a/.gitignore +++ b/.gitignore @@ -185,3 +185,7 @@ History *.sqlite-shm *.sqlite-wal +Chromium* +Firefox* +result/ +results/ diff --git a/cmd/cmd.go b/cmd/cmd.go index 1754145..6b06e4a 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -1,12 +1,13 @@ package cmd import ( + "fmt" "os" "strings" - "hack-browser-data/core" + "hack-browser-data/pkg/browser" + "hack-browser-data/pkg/browser/outputter" "hack-browser-data/pkg/log" - "hack-browser-data/utils" "github.com/urfave/cli/v2" ) @@ -18,7 +19,6 @@ var ( verbose bool compress bool customProfilePath string - customKeyPath string ) func Execute() { @@ -30,16 +30,15 @@ func Execute() { Flags: []cli.Flag{ &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"}, &cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"}, - &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(core.ListBrowser(), "|")}, + &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(browser.ListBrowser(), "|")}, &cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "export dir"}, &cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "format, csv|json|console"}, &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"}, - &cli.StringFlag{Name: "key-file-path", Aliases: []string{"k"}, Destination: &customKeyPath, Value: "", Usage: "custom key file path"}, }, HideHelpCommand: true, - Action: func(c *cli.Context) error { + Action: func(ctx *cli.Context) error { var ( - browsers []core.Browser + browsers []browser.Browser err error ) if verbose { @@ -47,69 +46,38 @@ func Execute() { } else { log.InitLog("error") } - if customProfilePath != "" { - browsers, err = core.PickCustomBrowser(browserName, customProfilePath, customKeyPath) - if err != nil { - log.Error(err) - } - } else { - // default select all browsers - browsers, err = core.PickBrowser(browserName) - if err != nil { - log.Error(err) - } - } - err = utils.MakeDir(exportDir) - if err != nil { - log.Error(err) + browsers = browser.PickBrowsers(browserName) + + output := outputter.NewOutPutter(outputFormat) + if err := output.MakeDir(exportDir); err != nil { + panic(err) } - for _, browser := range browsers { - err := browser.InitSecretKey() - if err != nil { - log.Error(err) + for _, b := range browsers { + fmt.Printf("%+v\n", b) + if err := b.CopyItemFileToLocal(); err != nil { + panic(err) } - // default select all items - // you can get single item with browser.GetItem(itemName) - items, err := browser.GetAllItems() + masterKey, err := b.GetMasterKey() if err != nil { - log.Error(err) + fmt.Println(err) } - name := browser.GetName() - key := browser.GetSecretKey() - for _, item := range items { - err := item.CopyDB() - if err != nil { - log.Error(err) - } - switch browser.(type) { - case *core.Chromium: - err := item.ChromeParse(key) - if err != nil { - log.Error(err) - } - case *core.Firefox: - err := item.FirefoxParse() - if err != nil { - log.Error(err) - } + browserName := b.GetName() + multiData := b.GetBrowsingData() + for _, data := range multiData { + if err := data.Parse(masterKey); err != nil { + fmt.Println(err) } - err = item.Release() + filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), outputFormat) + file, err := output.CreateFile(exportDir, filename) if err != nil { - log.Error(err) + panic(err) } - err = item.OutPut(outputFormat, name, exportDir) - if err != nil { - log.Error(err) + if err := output.Write(data, file); err != nil { + panic(err) } } } - if compress { - err = utils.Compress(exportDir) - if err != nil { - log.Error(err) - } - } - return nil + return err }, } err := app.Run(os.Args) @@ -117,3 +85,99 @@ func Execute() { log.Error(err) } } + +// func Execute() { +// app := &cli.App{ +// Name: "hack-browser-data", +// Usage: "Export passwords/cookies/history/bookmarks from browser", +// UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\n Get all data(password/cookie/history/bookmark) from chrome", +// Version: "0.3.7", +// Flags: []cli.Flag{ +// &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"}, +// &cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"}, +// &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(core.ListBrowser(), "|")}, +// &cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "export dir"}, +// &cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "format, csv|json|console"}, +// &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"}, +// }, +// HideHelpCommand: true, +// Action: func(c *cli.Context) error { +// var ( +// browsers []core.Browser +// err error +// ) +// if verbose { +// log.InitLog("debug") +// } else { +// log.InitLog("error") +// } +// if customProfilePath != "" { +// browsers, err = core.PickCustomBrowser(browserName, customProfilePath, customKeyPath) +// if err != nil { +// log.Error(err) +// } +// } else { +// // default select all browsers +// browsers, err = core.PickBrowser(browserName) +// if err != nil { +// log.Error(err) +// } +// } +// err = utils.MakeDir(exportDir) +// if err != nil { +// log.Error(err) +// } +// for _, browser := range browsers { +// err := browser.InitSecretKey() +// if err != nil { +// log.Error(err) +// } +// // default select all items +// // you can get single item with browser.GetItem(itemName) +// items, err := browser.GetAllItems() +// if err != nil { +// log.Error(err) +// } +// name := browser.GetName() +// key := browser.GetSecretKey() +// for _, item := range items { +// err := item.CopyDB() +// if err != nil { +// log.Error(err) +// } +// switch browser.(type) { +// case *core.Chromium: +// err := item.ChromeParse(key) +// if err != nil { +// log.Error(err) +// } +// case *core.Firefox: +// err := item.FirefoxParse() +// if err != nil { +// log.Error(err) +// } +// } +// err = item.Release() +// if err != nil { +// log.Error(err) +// } +// err = item.OutPut(outputFormat, name, exportDir) +// if err != nil { +// log.Error(err) +// } +// } +// } +// if compress { +// err = utils.Compress(exportDir) +// if err != nil { +// log.Error(err) +// } +// } +// return nil +// }, +// } +// err := app.Run(os.Args) +// if err != nil { +// log.Error(err) +// } +// } diff --git a/cmd/hackbrowserdata/main.go b/cmd/hackbrowserdata/main.go deleted file mode 100644 index 190ebe2..0000000 --- a/cmd/hackbrowserdata/main.go +++ /dev/null @@ -1 +0,0 @@ -package hackbrowserdata diff --git a/core/data/output.go b/core/data/output.go index 45b7a57..10cd42b 100644 --- a/core/data/output.go +++ b/core/data/output.go @@ -17,7 +17,7 @@ var ( ) func (b *bookmarks) outPutJson(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "bookmark", "json") + filename := utils.FormatFilename(dir, browser, "bookmark", "json") sort.Slice(b.bookmarks, func(i, j int) bool { return b.bookmarks[i].ID < b.bookmarks[j].ID }) @@ -30,7 +30,7 @@ func (b *bookmarks) outPutJson(browser, dir string) error { } func (h *historyData) outPutJson(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "history", "json") + filename := utils.FormatFilename(dir, browser, "history", "json") sort.Slice(h.history, func(i, j int) bool { return h.history[i].VisitCount > h.history[j].VisitCount }) @@ -43,7 +43,7 @@ func (h *historyData) outPutJson(browser, dir string) error { } func (d *downloads) outPutJson(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "download", "json") + filename := utils.FormatFilename(dir, browser, "download", "json") err := writeToJson(filename, d.downloads) if err != nil { return err @@ -53,7 +53,7 @@ func (d *downloads) outPutJson(browser, dir string) error { } func (p *passwords) outPutJson(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "password", "json") + filename := utils.FormatFilename(dir, browser, "password", "json") err := writeToJson(filename, p.logins) if err != nil { return err @@ -63,7 +63,7 @@ func (p *passwords) outPutJson(browser, dir string) error { } func (c *cookies) outPutJson(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "cookie", "json") + filename := utils.FormatFilename(dir, browser, "cookie", "json") err := writeToJson(filename, c.cookies) if err != nil { return err @@ -73,7 +73,7 @@ func (c *cookies) outPutJson(browser, dir string) error { } func (c *creditCards) outPutJson(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "credit", "json") + filename := utils.FormatFilename(dir, browser, "credit", "json") err := writeToJson(filename, c.cards) if err != nil { return err @@ -104,7 +104,7 @@ func writeToJson(filename string, data interface{}) error { } func (b *bookmarks) outPutCsv(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "bookmark", "csv") + filename := utils.FormatFilename(dir, browser, "bookmark", "csv") if err := writeToCsv(filename, b.bookmarks); err != nil { return err } @@ -113,7 +113,7 @@ func (b *bookmarks) outPutCsv(browser, dir string) error { } func (h *historyData) outPutCsv(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "history", "csv") + filename := utils.FormatFilename(dir, browser, "history", "csv") if err := writeToCsv(filename, h.history); err != nil { return err } @@ -122,7 +122,7 @@ func (h *historyData) outPutCsv(browser, dir string) error { } func (d *downloads) outPutCsv(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "download", "csv") + filename := utils.FormatFilename(dir, browser, "download", "csv") if err := writeToCsv(filename, d.downloads); err != nil { return err } @@ -131,7 +131,7 @@ func (d *downloads) outPutCsv(browser, dir string) error { } func (p *passwords) outPutCsv(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "password", "csv") + filename := utils.FormatFilename(dir, browser, "password", "csv") if err := writeToCsv(filename, p.logins); err != nil { return err } @@ -140,7 +140,7 @@ func (p *passwords) outPutCsv(browser, dir string) error { } func (c *cookies) outPutCsv(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "cookie", "csv") + filename := utils.FormatFilename(dir, browser, "cookie", "csv") var tempSlice []cookie for _, v := range c.cookies { tempSlice = append(tempSlice, v...) @@ -153,7 +153,7 @@ func (c *cookies) outPutCsv(browser, dir string) error { } func (c *creditCards) outPutCsv(browser, dir string) error { - filename := utils.FormatFileName(dir, browser, "credit", "csv") + filename := utils.FormatFilename(dir, browser, "credit", "csv") var tempSlice []card for _, v := range c.cards { tempSlice = append(tempSlice, v...) diff --git a/core/data/parse.go b/core/data/parse.go index 992c82d..de51608 100644 --- a/core/data/parse.go +++ b/core/data/parse.go @@ -159,7 +159,7 @@ func (b *bookmarks) FirefoxParse() error { b.bookmarks = append(b.bookmarks, bookmark{ ID: id, Name: title, - Type: utils.BookMarkType(bType), + Type: utils.BookmarkType(bType), URL: bookmarkUrl, DateAdded: utils.TimeStampFormat(dateAdded / 1000000), }) diff --git a/go.mod b/go.mod index 3783eea..3c4bc91 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module hack-browser-data -go 1.14 +go 1.16 require ( github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 diff --git a/pkg/browser/browser.go b/pkg/browser/browser.go index 2e2a63c..b34a777 100644 --- a/pkg/browser/browser.go +++ b/pkg/browser/browser.go @@ -12,17 +12,40 @@ import ( "hack-browser-data/pkg/browser/data" ) +type Browser interface { + GetName() string + + GetMasterKey() ([]byte, error) + + GetBrowsingData() []data.BrowsingData + + CopyItemFileToLocal() error +} + var ( // home dir path not for android and ios homeDir, _ = os.UserHomeDir() ) -func PickBrowsers(name string) { - +func PickBrowsers(name string) []Browser { + var browsers []Browser + chromiumList := pickChromium(name) + for _, b := range chromiumList { + if b != nil { + browsers = append(browsers, b) + } + } + firefoxList := pickFirefox(name) + for _, b := range firefoxList { + if b != nil { + browsers = append(browsers, b) + } + } + return browsers } -func PickChromium(name string) []*chromium { - var browsers []*chromium +func pickChromium(name string) []Browser { + var browsers []Browser name = strings.ToLower(name) if name == "all" { for _, choice := range chromiumList { @@ -45,25 +68,21 @@ func PickChromium(name string) []*chromium { return nil } -func PickFirefox(name string) []*firefox { - var browsers []*firefox +func pickFirefox(name string) []Browser { + var browsers []Browser name = strings.ToLower(name) if name == "all" || name == "firefox" { for _, v := range firefoxList { - b, err := newFirefox(v.browserInfo, v.items) + multiFirefox, err := newMultiFirefox(v.browserInfo, v.items) if err != nil { panic(err) } - // b := v.New(v.browserInfo, v.items) - browsers = append(browsers, b...) + for _, browser := range multiFirefox { + browsers = append(browsers, browser) + } } return browsers } - // if choice, ok := browserList[name]; ok { - // b := choice.New(choice.browserInfo, choice.items) - // browsers = append(browsers, b) - // return browsers - // } return nil } @@ -73,25 +92,6 @@ type chromium struct { itemPaths map[item]string } -func (c *chromium) GetProfilePath() string { - return c.browserInfo.profilePath -} - -func (c *chromium) GetStorageName() string { - return c.browserInfo.storage -} - -func (c *chromium) GetBrowserName() string { - return c.browserInfo.name -} - -type firefox struct { - browserInfo *browserInfo - items []item - itemPaths map[item]string - multiItemPaths map[string]map[item]string -} - // NewBrowser 根据浏览器信息生成 Browser Interface func newChromium(info *browserInfo, items []item) (*chromium, error) { c := &chromium{ @@ -106,8 +106,57 @@ func newChromium(info *browserInfo, items []item) (*chromium, error) { return c, err } +func (c *chromium) GetName() string { + return c.browserInfo.name +} + +func (c *chromium) GetBrowsingData() []data.BrowsingData { + var browsingData []data.BrowsingData + for item := range c.itemPaths { + d := item.NewBrowsingData() + if d != nil { + browsingData = append(browsingData, d) + } + } + return browsingData +} + +func (c *chromium) CopyItemFileToLocal() error { + for item, sourcePath := range c.itemPaths { + var dstFilename = item.FileName() + locals, _ := filepath.Glob("*") + for _, v := range locals { + if v == dstFilename { + err := os.Remove(dstFilename) + // TODO: Should Continue all iteration error + if err != nil { + return err + } + } + } + + // TODO: Handle read file error + sourceFile, err := ioutil.ReadFile(sourcePath) + if err != nil { + fmt.Println(err.Error()) + } + err = ioutil.WriteFile(dstFilename, sourceFile, 0777) + if err != nil { + return err + } + } + return nil +} + +type firefox struct { + browserInfo *browserInfo + items []item + itemPaths map[item]string + multiItemPaths map[string]map[item]string +} + // newFirefox -func newFirefox(info *browserInfo, items []item) ([]*firefox, error) { +func newMultiFirefox(info *browserInfo, items []item) ([]*firefox, error) { f := &firefox{ browserInfo: info, items: items, @@ -125,7 +174,6 @@ func newFirefox(info *browserInfo, items []item) ([]*firefox, error) { }, items: items, itemPaths: value, - // multiItemPaths: value, }) } return firefoxList, nil @@ -138,7 +186,7 @@ func getFirefoxItemAbsPath(profilePath string, items []item) (map[string]map[ite return multiItemPaths, err } -func (f *firefox) copyItemFileToLocal() error { +func (f *firefox) CopyItemFileToLocal() error { for item, sourcePath := range f.itemPaths { var dstFilename = item.FileName() locals, _ := filepath.Glob("*") @@ -163,39 +211,6 @@ func (f *firefox) copyItemFileToLocal() error { } } return nil - // for name, itemPaths := range f.multiItemPaths { - // for item, path := range itemPaths { - // var dstFilename = item.FileName() - // locals, _ := filepath.Glob("*") - // for _, v := range locals { - // if v == dstFilename { - // // TODO: Should Continue all iteration error - // err := os.Remove(dstFilename) - // if err != nil { - // return err - // } - // } - // } - // } - // // if v == dstFilename { - // // err := os.Remove(dstFilename) - // // if err != nil { - // // return err - // // } - // // } - // // } - // // - // // // TODO: Handle read file name error - // // sourceFile, err := ioutil.ReadFile(sourcePath) - // // if err != nil { - // // fmt.Println(err.Error()) - // // } - // // err = ioutil.WriteFile(dstFilename, sourceFile, 0777) - // // if err != nil { - // // return err - // // } - // } - // return nil } func firefoxWalkFunc(items []item, multiItemPaths map[string]map[item]string) filepath.WalkFunc { @@ -239,49 +254,11 @@ func getChromiumItemAbsPath(profilePath string, items []item) (map[item]string, return itemPaths, err } -func (c *chromium) copyItemFileToLocal() error { - for item, sourcePath := range c.itemPaths { - var dstFilename = item.FileName() - locals, _ := filepath.Glob("*") - for _, v := range locals { - if v == dstFilename { - err := os.Remove(dstFilename) - // TODO: Should Continue all iteration error - if err != nil { - return err - } - } - } - - // TODO: Handle read file name error - sourceFile, err := ioutil.ReadFile(sourcePath) - if err != nil { - fmt.Println(err.Error()) - } - err = ioutil.WriteFile(dstFilename, sourceFile, 0777) - if err != nil { - return err - } - } - return nil -} - -func (c *chromium) GetBrowsingData() []data.BrowsingData { - var browsingData []data.BrowsingData - for item := range c.itemPaths { - if item != chromiumKey { - d := item.NewBrowsingData() - browsingData = append(browsingData, d) - } - } - return browsingData -} - func (f *firefox) GetMasterKey() ([]byte, error) { return f.browserInfo.masterKey, nil } -func (f *firefox) GetBrowserName() string { +func (f *firefox) GetName() string { return f.browserInfo.name } @@ -295,6 +272,16 @@ func (f *firefox) GetBrowsingData() []data.BrowsingData { } return browsingData } +func ListBrowser() []string { + var l []string + for c := range chromiumList { + l = append(l, c) + } + for f := range firefoxList { + l = append(l, f) + } + return l +} type browserInfo struct { name string @@ -307,6 +294,7 @@ const ( chromeName = "Chrome" edgeName = "Edge" firefoxName = "Firefox" + yandexName = "Yandex" ) var defaultFirefoxItems = []item{ @@ -321,6 +309,18 @@ var defaultFirefoxItems = []item{ firefoxExtension, } +var defaultYandexItems = []item{ + chromiumKey, + yandexPassword, + chromiumCookie, + chromiumBookmark, + chromiumHistory, + chromiumDownload, + yandexCreditCard, + chromiumLocalStorage, + chromiumExtension, +} + var defaultChromiumItems = []item{ chromiumKey, chromiumPassword, diff --git a/pkg/browser/browser_darwin.go b/pkg/browser/browser_darwin.go index 0b0177d..2a167d8 100644 --- a/pkg/browser/browser_darwin.go +++ b/pkg/browser/browser_darwin.go @@ -18,12 +18,10 @@ var ( "chrome": { browserInfo: chromeInfo, items: defaultChromiumItems, - // New: newBrowser, }, "edge": { browserInfo: edgeInfo, items: defaultChromiumItems, - // New: newBrowser, }, } firefoxList = map[string]struct { @@ -47,7 +45,7 @@ func (c *chromium) GetMasterKey() ([]byte, error) { stdout, stderr bytes.Buffer ) // $ security find-generic-password -wa 'Chrome' - cmd = exec.Command("security", "find-generic-password", "-wa", c.GetStorageName()) + cmd = exec.Command("security", "find-generic-password", "-wa", c.browserInfo.storage) cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() @@ -66,7 +64,7 @@ func (c *chromium) GetMasterKey() ([]byte, error) { // @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_mac.mm;l=157 key := pbkdf2.Key(chromeSecret, chromeSalt, 1003, 16, sha1.New) c.browserInfo.masterKey = key - return c.browserInfo.masterKey, nil + return key, nil } var ( @@ -82,7 +80,7 @@ var ( } firefoxInfo = &browserInfo{ name: firefoxName, - profilePath: fireFoxProfilePath, + profilePath: firefoxProfilePath, } ) @@ -98,8 +96,9 @@ const ( coccocProfilePath = "/Library/Application Support/Coccoc/" yandexProfilePath = "/Library/Application Support/Yandex/YandexBrowser/" - fireFoxProfilePath = "/Library/Application Support/Firefox/Profiles/" + firefoxProfilePath = "/Library/Application Support/Firefox/Profiles/" ) + const ( chromeStorageName = "Chrome" chromeBetaStorageName = "Chrome" diff --git a/pkg/browser/browser_linux.go b/pkg/browser/browser_linux.go new file mode 100644 index 0000000..199464e --- /dev/null +++ b/pkg/browser/browser_linux.go @@ -0,0 +1 @@ +package browser diff --git a/pkg/browser/browser_test.go b/pkg/browser/browser_test.go index d5f9525..f19eb61 100644 --- a/pkg/browser/browser_test.go +++ b/pkg/browser/browser_test.go @@ -5,10 +5,12 @@ import ( "testing" "hack-browser-data/pkg/browser/outputter" + "hack-browser-data/pkg/log" ) func TestPickChromium(t *testing.T) { - browsers := PickChromium("all") + browsers := pickChromium("chrome") + log.InitLog("debug") filetype := "json" dir := "result" output := outputter.NewOutPutter(filetype) @@ -17,21 +19,16 @@ func TestPickChromium(t *testing.T) { } for _, b := range browsers { fmt.Printf("%+v\n", b) - if err := b.copyItemFileToLocal(); err != nil { + if err := b.CopyItemFileToLocal(); err != nil { panic(err) } masterKey, err := b.GetMasterKey() if err != nil { fmt.Println(err) } - browserName := b.GetBrowserName() + browserName := b.GetName() multiData := b.GetBrowsingData() - // TODO: 优化获取 Data 逻辑 for _, data := range multiData { - if data == nil { - fmt.Println(data) - continue - } if err := data.Parse(masterKey); err != nil { fmt.Println(err) } @@ -48,7 +45,7 @@ func TestPickChromium(t *testing.T) { } func TestPickFirefox(t *testing.T) { - browsers := PickFirefox("all") + browsers := pickFirefox("all") filetype := "json" dir := "result" output := outputter.NewOutPutter(filetype) @@ -57,16 +54,15 @@ func TestPickFirefox(t *testing.T) { } for _, b := range browsers { fmt.Printf("%+v\n", b) - if err := b.copyItemFileToLocal(); err != nil { + if err := b.CopyItemFileToLocal(); err != nil { panic(err) } masterKey, err := b.GetMasterKey() if err != nil { fmt.Println(err) } - browserName := b.GetBrowserName() + browserName := b.GetName() multiData := b.GetBrowsingData() - // TODO: 优化获取 Data 逻辑 for _, data := range multiData { if err := data.Parse(masterKey); err != nil { fmt.Println(err) diff --git a/pkg/browser/browser_windows.go b/pkg/browser/browser_windows.go new file mode 100644 index 0000000..e092d48 --- /dev/null +++ b/pkg/browser/browser_windows.go @@ -0,0 +1,98 @@ +package browser + +import ( + "encoding/base64" + "errors" + + "github.com/tidwall/gjson" + + "hack-browser-data/pkg/browser/consts" + "hack-browser-data/pkg/decrypter" + "hack-browser-data/utils" +) + +var ( + chromiumList = map[string]struct { + browserInfo *browserInfo + items []item + }{ + "chrome": { + browserInfo: chromeInfo, + items: defaultChromiumItems, + }, + "edge": { + browserInfo: edgeInfo, + items: defaultChromiumItems, + }, + "yandex": { + browserInfo: yandexInfo, + items: defaultYandexItems, + }, + } + firefoxList = map[string]struct { + browserInfo *browserInfo + items []item + }{ + "firefox": { + browserInfo: firefoxInfo, + items: defaultFirefoxItems, + }, + } +) + +var ( + errDecodeMasterKeyFailed = errors.New("decode master key failed") +) + +func (c *chromium) GetMasterKey() ([]byte, error) { + keyFile, err := utils.ReadFile(consts.ChromiumKeyFilename) + if err != nil { + return nil, err + } + encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key") + if encryptedKey.Exists() { + pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String()) + if err != nil { + return nil, errDecodeMasterKeyFailed + } + c.browserInfo.masterKey, err = decrypter.DPApi(pureKey[5:]) + return c.browserInfo.masterKey, err + } + return nil, nil +} + +var ( + chromeInfo = &browserInfo{ + name: chromeName, + profilePath: chromeProfilePath, + } + edgeInfo = &browserInfo{ + name: edgeName, + profilePath: edgeProfilePath, + } + yandexInfo = &browserInfo{ + name: yandexName, + profilePath: edgeProfilePath, + } + firefoxInfo = &browserInfo{ + name: firefoxName, + profilePath: firefoxProfilePath, + } +) + +const ( + chromeProfilePath = "/AppData/Local/Google/Chrome/User Data/" + chromeBetaProfilePath = "/AppData/Local/Google/Chrome Beta/User Data/" + chromiumProfilePath = "/AppData/Local/Chromium/User Data/" + edgeProfilePath = "/AppData/Local/Microsoft/Edge/User Data/" + braveProfilePath = "/AppData/Local/BraveSoftware/Brave-Browser/User Data/" + speed360ProfilePath = "/AppData/Local/360chrome/Chrome/User Data/" + qqBrowserProfilePath = "/AppData/Local/Tencent/QQBrowser/User Data/" + operaProfilePath = "/AppData/Roaming/Opera Software/Opera Stable/" + operaGXProfilePath = "/AppData/Roaming/Opera Software/Opera GX Stable/" + vivaldiProfilePath = "/AppData/Local/Vivaldi/User Data/Default/" + coccocProfilePath = "/AppData/Local/CocCoc/Browser/User Data/Default/" + yandexProfilePath = "/AppData/Local/Yandex/YandexBrowser/User Data/Default" + + firefoxProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles" +) diff --git a/pkg/browser/consts/filename.go b/pkg/browser/consts/filename.go index 2f2f35d..16fcb30 100644 --- a/pkg/browser/consts/filename.go +++ b/pkg/browser/consts/filename.go @@ -19,8 +19,8 @@ const ( FirefoxPassword = "logins.json" FirefoxData = "places.sqlite" - UnknownItem = "unknown item" - UnSupportItem = "unsupport item" + UnknownItem = "unknown item" + UnsupportedItem = "unsupported item" ) // item's renamed filename diff --git a/pkg/browser/data/bookmark.go b/pkg/browser/data/bookmark.go index 9de9411..9c66dda 100644 --- a/pkg/browser/data/bookmark.go +++ b/pkg/browser/data/bookmark.go @@ -96,7 +96,7 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error { *f = append(*f, bookmark{ ID: id, Name: title, - Type: utils.BookMarkType(bType), + Type: utils.BookmarkType(bType), URL: url, DateAdded: utils.TimeStampFormat(dateAdded / 1000000), }) diff --git a/pkg/browser/item.go b/pkg/browser/item.go index 745ecce..3f7968f 100644 --- a/pkg/browser/item.go +++ b/pkg/browser/item.go @@ -67,13 +67,13 @@ func (i item) DefaultName() string { case firefoxDownload: return consts.FirefoxData case firefoxLocalStorage: - return consts.UnSupportItem + return consts.UnsupportedItem case firefoxCreditCard: - return consts.UnSupportItem + return consts.UnsupportedItem case firefoxHistory: return consts.FirefoxData case firefoxExtension: - return consts.UnSupportItem + return consts.UnsupportedItem default: return consts.UnknownItem } @@ -98,7 +98,11 @@ func (i item) FileName() string { case chromiumHistory: return consts.ChromiumHistoryFilename case chromiumExtension: - return consts.UnSupportItem + return consts.UnsupportedItem + case yandexPassword: + return consts.ChromiumPasswordFilename + case yandexCreditCard: + return consts.ChromiumCreditFilename case firefoxKey4: return consts.FirefoxKey4Filename case firefoxPassword: @@ -110,13 +114,13 @@ func (i item) FileName() string { case firefoxDownload: return consts.FirefoxDownloadFilename case firefoxLocalStorage: - return consts.UnSupportItem + return consts.UnsupportedItem case firefoxCreditCard: - return consts.UnSupportItem + return consts.UnsupportedItem case firefoxHistory: return consts.FirefoxHistoryFilename case firefoxExtension: - return consts.UnSupportItem + return consts.UnsupportedItem default: return consts.UnknownItem } @@ -142,6 +146,10 @@ func (i item) NewBrowsingData() data.BrowsingData { return nil case chromiumHistory: return &data.ChromiumHistory{} + case yandexPassword: + return &data.ChromiumPassword{} + case yandexCreditCard: + return &data.ChromiumCreditCard{} case firefoxPassword: return &data.FirefoxPassword{} case firefoxCookie: diff --git a/pkg/browser/outputter/outputter.go b/pkg/browser/outputter/outputter.go index 9e57a3c..e330254 100644 --- a/pkg/browser/outputter/outputter.go +++ b/pkg/browser/outputter/outputter.go @@ -3,7 +3,6 @@ package outputter import ( "encoding/csv" "errors" - "fmt" "io" "os" "path/filepath" @@ -73,7 +72,6 @@ func (o *outPutter) CreateFile(dirname, filename string) (*os.File, error) { var err error p := filepath.Join(dirname, filename) file, err = os.OpenFile(p, os.O_TRUNC|os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) - fmt.Println(err) if err != nil { return nil, err } diff --git a/pkg/decrypter/decrypt_windows.go b/pkg/decrypter/decrypt_windows.go index 4b8aaec..7dda3f0 100644 --- a/pkg/decrypter/decrypt_windows.go +++ b/pkg/decrypter/decrypt_windows.go @@ -54,6 +54,7 @@ func (b *dataBlob) ToByteArray() []byte { return d } +// DPApi // chrome < 80 https://chromium.googlesource.com/chromium/src/+/76f496a7235c3432983421402951d73905c8be96/components/os_crypt/os_crypt_win.cc#82 func DPApi(data []byte) ([]byte, error) { dllCrypt := syscall.NewLazyDLL("Crypt32.dll") diff --git a/utils/utils.go b/utils/utils.go index 060ac62..e67d9c8 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -23,7 +23,7 @@ func IntToBool(a int) bool { return true } -func BookMarkType(a int64) string { +func BookmarkType(a int64) string { switch a { case 1: return "url" @@ -66,7 +66,7 @@ func WriteFile(filename string, data []byte) error { return err } -func FormatFileName(dir, browser, filename, format string) string { +func FormatFilename(dir, browser, filename, format string) string { r := strings.Replace(strings.TrimSpace(strings.ToLower(browser)), " ", "_", -1) p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, filename, format)) return p