feat-dev: support firefox for windows and macos

pull/116/head
ᴍᴏᴏɴD4ʀᴋ 3 years ago
parent 65b209f582
commit a341928926
  1. 4
      .gitignore
  2. 184
      cmd/cmd.go
  3. 1
      cmd/hackbrowserdata/main.go
  4. 24
      core/data/output.go
  5. 2
      core/data/parse.go
  6. 2
      go.mod
  7. 216
      pkg/browser/browser.go
  8. 11
      pkg/browser/browser_darwin.go
  9. 1
      pkg/browser/browser_linux.go
  10. 20
      pkg/browser/browser_test.go
  11. 98
      pkg/browser/browser_windows.go
  12. 2
      pkg/browser/consts/filename.go
  13. 2
      pkg/browser/data/bookmark.go
  14. 22
      pkg/browser/item.go
  15. 2
      pkg/browser/outputter/outputter.go
  16. 1
      pkg/decrypter/decrypt_windows.go
  17. 4
      utils/utils.go

4
.gitignore vendored

@ -185,3 +185,7 @@ History
*.sqlite-shm *.sqlite-shm
*.sqlite-wal *.sqlite-wal
Chromium*
Firefox*
result/
results/

@ -1,12 +1,13 @@
package cmd package cmd
import ( import (
"fmt"
"os" "os"
"strings" "strings"
"hack-browser-data/core" "hack-browser-data/pkg/browser"
"hack-browser-data/pkg/browser/outputter"
"hack-browser-data/pkg/log" "hack-browser-data/pkg/log"
"hack-browser-data/utils"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -18,7 +19,6 @@ var (
verbose bool verbose bool
compress bool compress bool
customProfilePath string customProfilePath string
customKeyPath string
) )
func Execute() { func Execute() {
@ -30,16 +30,15 @@ func Execute() {
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"}, &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.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: "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: "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: "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, HideHelpCommand: true,
Action: func(c *cli.Context) error { Action: func(ctx *cli.Context) error {
var ( var (
browsers []core.Browser browsers []browser.Browser
err error err error
) )
if verbose { if verbose {
@ -47,69 +46,38 @@ func Execute() {
} else { } else {
log.InitLog("error") log.InitLog("error")
} }
if customProfilePath != "" { browsers = browser.PickBrowsers(browserName)
browsers, err = core.PickCustomBrowser(browserName, customProfilePath, customKeyPath)
if err != nil { output := outputter.NewOutPutter(outputFormat)
log.Error(err) if err := output.MakeDir(exportDir); err != nil {
} panic(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) { for _, b := range browsers {
case *core.Chromium: fmt.Printf("%+v\n", b)
err := item.ChromeParse(key) if err := b.CopyItemFileToLocal(); err != nil {
if err != nil { panic(err)
log.Error(err)
} }
case *core.Firefox: masterKey, err := b.GetMasterKey()
err := item.FirefoxParse()
if err != nil { if err != nil {
log.Error(err) fmt.Println(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 { if err != nil {
log.Error(err) panic(err)
} }
err = item.OutPut(outputFormat, name, exportDir) if err := output.Write(data, file); err != nil {
if err != nil { panic(err)
log.Error(err)
} }
} }
} }
if compress { return err
err = utils.Compress(exportDir)
if err != nil {
log.Error(err)
}
}
return nil
}, },
} }
err := app.Run(os.Args) err := app.Run(os.Args)
@ -117,3 +85,99 @@ func Execute() {
log.Error(err) 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)
// }
// }

@ -1 +0,0 @@
package hackbrowserdata

@ -17,7 +17,7 @@ var (
) )
func (b *bookmarks) outPutJson(browser, dir string) error { 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 { sort.Slice(b.bookmarks, func(i, j int) bool {
return b.bookmarks[i].ID < b.bookmarks[j].ID 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 { 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 { sort.Slice(h.history, func(i, j int) bool {
return h.history[i].VisitCount > h.history[j].VisitCount 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 { 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) err := writeToJson(filename, d.downloads)
if err != nil { if err != nil {
return err return err
@ -53,7 +53,7 @@ func (d *downloads) outPutJson(browser, dir string) error {
} }
func (p *passwords) 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) err := writeToJson(filename, p.logins)
if err != nil { if err != nil {
return err return err
@ -63,7 +63,7 @@ func (p *passwords) outPutJson(browser, dir string) error {
} }
func (c *cookies) 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) err := writeToJson(filename, c.cookies)
if err != nil { if err != nil {
return err return err
@ -73,7 +73,7 @@ func (c *cookies) outPutJson(browser, dir string) error {
} }
func (c *creditCards) 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) err := writeToJson(filename, c.cards)
if err != nil { if err != nil {
return err return err
@ -104,7 +104,7 @@ func writeToJson(filename string, data interface{}) error {
} }
func (b *bookmarks) outPutCsv(browser, dir string) 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 { if err := writeToCsv(filename, b.bookmarks); err != nil {
return err return err
} }
@ -113,7 +113,7 @@ func (b *bookmarks) outPutCsv(browser, dir string) error {
} }
func (h *historyData) 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 { if err := writeToCsv(filename, h.history); err != nil {
return err return err
} }
@ -122,7 +122,7 @@ func (h *historyData) outPutCsv(browser, dir string) error {
} }
func (d *downloads) 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 { if err := writeToCsv(filename, d.downloads); err != nil {
return err return err
} }
@ -131,7 +131,7 @@ func (d *downloads) outPutCsv(browser, dir string) error {
} }
func (p *passwords) 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 { if err := writeToCsv(filename, p.logins); err != nil {
return err return err
} }
@ -140,7 +140,7 @@ func (p *passwords) outPutCsv(browser, dir string) error {
} }
func (c *cookies) 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 var tempSlice []cookie
for _, v := range c.cookies { for _, v := range c.cookies {
tempSlice = append(tempSlice, v...) tempSlice = append(tempSlice, v...)
@ -153,7 +153,7 @@ func (c *cookies) outPutCsv(browser, dir string) error {
} }
func (c *creditCards) 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 var tempSlice []card
for _, v := range c.cards { for _, v := range c.cards {
tempSlice = append(tempSlice, v...) tempSlice = append(tempSlice, v...)

@ -159,7 +159,7 @@ func (b *bookmarks) FirefoxParse() error {
b.bookmarks = append(b.bookmarks, bookmark{ b.bookmarks = append(b.bookmarks, bookmark{
ID: id, ID: id,
Name: title, Name: title,
Type: utils.BookMarkType(bType), Type: utils.BookmarkType(bType),
URL: bookmarkUrl, URL: bookmarkUrl,
DateAdded: utils.TimeStampFormat(dateAdded / 1000000), DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
}) })

@ -1,6 +1,6 @@
module hack-browser-data module hack-browser-data
go 1.14 go 1.16
require ( require (
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9

@ -12,17 +12,40 @@ import (
"hack-browser-data/pkg/browser/data" "hack-browser-data/pkg/browser/data"
) )
type Browser interface {
GetName() string
GetMasterKey() ([]byte, error)
GetBrowsingData() []data.BrowsingData
CopyItemFileToLocal() error
}
var ( var (
// home dir path not for android and ios // home dir path not for android and ios
homeDir, _ = os.UserHomeDir() 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 { func pickChromium(name string) []Browser {
var browsers []*chromium var browsers []Browser
name = strings.ToLower(name) name = strings.ToLower(name)
if name == "all" { if name == "all" {
for _, choice := range chromiumList { for _, choice := range chromiumList {
@ -45,25 +68,21 @@ func PickChromium(name string) []*chromium {
return nil return nil
} }
func PickFirefox(name string) []*firefox { func pickFirefox(name string) []Browser {
var browsers []*firefox var browsers []Browser
name = strings.ToLower(name) name = strings.ToLower(name)
if name == "all" || name == "firefox" { if name == "all" || name == "firefox" {
for _, v := range firefoxList { for _, v := range firefoxList {
b, err := newFirefox(v.browserInfo, v.items) multiFirefox, err := newMultiFirefox(v.browserInfo, v.items)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// b := v.New(v.browserInfo, v.items) for _, browser := range multiFirefox {
browsers = append(browsers, b...) browsers = append(browsers, browser)
}
} }
return browsers return browsers
} }
// if choice, ok := browserList[name]; ok {
// b := choice.New(choice.browserInfo, choice.items)
// browsers = append(browsers, b)
// return browsers
// }
return nil return nil
} }
@ -73,25 +92,6 @@ type chromium struct {
itemPaths map[item]string 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 // NewBrowser 根据浏览器信息生成 Browser Interface
func newChromium(info *browserInfo, items []item) (*chromium, error) { func newChromium(info *browserInfo, items []item) (*chromium, error) {
c := &chromium{ c := &chromium{
@ -106,8 +106,57 @@ func newChromium(info *browserInfo, items []item) (*chromium, error) {
return c, err 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 // newFirefox
func newFirefox(info *browserInfo, items []item) ([]*firefox, error) { func newMultiFirefox(info *browserInfo, items []item) ([]*firefox, error) {
f := &firefox{ f := &firefox{
browserInfo: info, browserInfo: info,
items: items, items: items,
@ -125,7 +174,6 @@ func newFirefox(info *browserInfo, items []item) ([]*firefox, error) {
}, },
items: items, items: items,
itemPaths: value, itemPaths: value,
// multiItemPaths: value,
}) })
} }
return firefoxList, nil return firefoxList, nil
@ -138,7 +186,7 @@ func getFirefoxItemAbsPath(profilePath string, items []item) (map[string]map[ite
return multiItemPaths, err return multiItemPaths, err
} }
func (f *firefox) copyItemFileToLocal() error { func (f *firefox) CopyItemFileToLocal() error {
for item, sourcePath := range f.itemPaths { for item, sourcePath := range f.itemPaths {
var dstFilename = item.FileName() var dstFilename = item.FileName()
locals, _ := filepath.Glob("*") locals, _ := filepath.Glob("*")
@ -163,39 +211,6 @@ func (f *firefox) copyItemFileToLocal() error {
} }
} }
return nil 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 { 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 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) { func (f *firefox) GetMasterKey() ([]byte, error) {
return f.browserInfo.masterKey, nil return f.browserInfo.masterKey, nil
} }
func (f *firefox) GetBrowserName() string { func (f *firefox) GetName() string {
return f.browserInfo.name return f.browserInfo.name
} }
@ -295,6 +272,16 @@ func (f *firefox) GetBrowsingData() []data.BrowsingData {
} }
return 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 { type browserInfo struct {
name string name string
@ -307,6 +294,7 @@ const (
chromeName = "Chrome" chromeName = "Chrome"
edgeName = "Edge" edgeName = "Edge"
firefoxName = "Firefox" firefoxName = "Firefox"
yandexName = "Yandex"
) )
var defaultFirefoxItems = []item{ var defaultFirefoxItems = []item{
@ -321,6 +309,18 @@ var defaultFirefoxItems = []item{
firefoxExtension, firefoxExtension,
} }
var defaultYandexItems = []item{
chromiumKey,
yandexPassword,
chromiumCookie,
chromiumBookmark,
chromiumHistory,
chromiumDownload,
yandexCreditCard,
chromiumLocalStorage,
chromiumExtension,
}
var defaultChromiumItems = []item{ var defaultChromiumItems = []item{
chromiumKey, chromiumKey,
chromiumPassword, chromiumPassword,

@ -18,12 +18,10 @@ var (
"chrome": { "chrome": {
browserInfo: chromeInfo, browserInfo: chromeInfo,
items: defaultChromiumItems, items: defaultChromiumItems,
// New: newBrowser,
}, },
"edge": { "edge": {
browserInfo: edgeInfo, browserInfo: edgeInfo,
items: defaultChromiumItems, items: defaultChromiumItems,
// New: newBrowser,
}, },
} }
firefoxList = map[string]struct { firefoxList = map[string]struct {
@ -47,7 +45,7 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
stdout, stderr bytes.Buffer stdout, stderr bytes.Buffer
) )
// $ security find-generic-password -wa 'Chrome' // $ 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.Stdout = &stdout
cmd.Stderr = &stderr cmd.Stderr = &stderr
err := cmd.Run() 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 // @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) key := pbkdf2.Key(chromeSecret, chromeSalt, 1003, 16, sha1.New)
c.browserInfo.masterKey = key c.browserInfo.masterKey = key
return c.browserInfo.masterKey, nil return key, nil
} }
var ( var (
@ -82,7 +80,7 @@ var (
} }
firefoxInfo = &browserInfo{ firefoxInfo = &browserInfo{
name: firefoxName, name: firefoxName,
profilePath: fireFoxProfilePath, profilePath: firefoxProfilePath,
} }
) )
@ -98,8 +96,9 @@ const (
coccocProfilePath = "/Library/Application Support/Coccoc/" coccocProfilePath = "/Library/Application Support/Coccoc/"
yandexProfilePath = "/Library/Application Support/Yandex/YandexBrowser/" yandexProfilePath = "/Library/Application Support/Yandex/YandexBrowser/"
fireFoxProfilePath = "/Library/Application Support/Firefox/Profiles/" firefoxProfilePath = "/Library/Application Support/Firefox/Profiles/"
) )
const ( const (
chromeStorageName = "Chrome" chromeStorageName = "Chrome"
chromeBetaStorageName = "Chrome" chromeBetaStorageName = "Chrome"

@ -0,0 +1 @@
package browser

@ -5,10 +5,12 @@ import (
"testing" "testing"
"hack-browser-data/pkg/browser/outputter" "hack-browser-data/pkg/browser/outputter"
"hack-browser-data/pkg/log"
) )
func TestPickChromium(t *testing.T) { func TestPickChromium(t *testing.T) {
browsers := PickChromium("all") browsers := pickChromium("chrome")
log.InitLog("debug")
filetype := "json" filetype := "json"
dir := "result" dir := "result"
output := outputter.NewOutPutter(filetype) output := outputter.NewOutPutter(filetype)
@ -17,21 +19,16 @@ func TestPickChromium(t *testing.T) {
} }
for _, b := range browsers { for _, b := range browsers {
fmt.Printf("%+v\n", b) fmt.Printf("%+v\n", b)
if err := b.copyItemFileToLocal(); err != nil { if err := b.CopyItemFileToLocal(); err != nil {
panic(err) panic(err)
} }
masterKey, err := b.GetMasterKey() masterKey, err := b.GetMasterKey()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
browserName := b.GetBrowserName() browserName := b.GetName()
multiData := b.GetBrowsingData() multiData := b.GetBrowsingData()
// TODO: 优化获取 Data 逻辑
for _, data := range multiData { for _, data := range multiData {
if data == nil {
fmt.Println(data)
continue
}
if err := data.Parse(masterKey); err != nil { if err := data.Parse(masterKey); err != nil {
fmt.Println(err) fmt.Println(err)
} }
@ -48,7 +45,7 @@ func TestPickChromium(t *testing.T) {
} }
func TestPickFirefox(t *testing.T) { func TestPickFirefox(t *testing.T) {
browsers := PickFirefox("all") browsers := pickFirefox("all")
filetype := "json" filetype := "json"
dir := "result" dir := "result"
output := outputter.NewOutPutter(filetype) output := outputter.NewOutPutter(filetype)
@ -57,16 +54,15 @@ func TestPickFirefox(t *testing.T) {
} }
for _, b := range browsers { for _, b := range browsers {
fmt.Printf("%+v\n", b) fmt.Printf("%+v\n", b)
if err := b.copyItemFileToLocal(); err != nil { if err := b.CopyItemFileToLocal(); err != nil {
panic(err) panic(err)
} }
masterKey, err := b.GetMasterKey() masterKey, err := b.GetMasterKey()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
browserName := b.GetBrowserName() browserName := b.GetName()
multiData := b.GetBrowsingData() multiData := b.GetBrowsingData()
// TODO: 优化获取 Data 逻辑
for _, data := range multiData { for _, data := range multiData {
if err := data.Parse(masterKey); err != nil { if err := data.Parse(masterKey); err != nil {
fmt.Println(err) fmt.Println(err)

@ -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"
)

@ -20,7 +20,7 @@ const (
FirefoxData = "places.sqlite" FirefoxData = "places.sqlite"
UnknownItem = "unknown item" UnknownItem = "unknown item"
UnSupportItem = "unsupport item" UnsupportedItem = "unsupported item"
) )
// item's renamed filename // item's renamed filename

@ -96,7 +96,7 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error {
*f = append(*f, bookmark{ *f = append(*f, bookmark{
ID: id, ID: id,
Name: title, Name: title,
Type: utils.BookMarkType(bType), Type: utils.BookmarkType(bType),
URL: url, URL: url,
DateAdded: utils.TimeStampFormat(dateAdded / 1000000), DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
}) })

@ -67,13 +67,13 @@ func (i item) DefaultName() string {
case firefoxDownload: case firefoxDownload:
return consts.FirefoxData return consts.FirefoxData
case firefoxLocalStorage: case firefoxLocalStorage:
return consts.UnSupportItem return consts.UnsupportedItem
case firefoxCreditCard: case firefoxCreditCard:
return consts.UnSupportItem return consts.UnsupportedItem
case firefoxHistory: case firefoxHistory:
return consts.FirefoxData return consts.FirefoxData
case firefoxExtension: case firefoxExtension:
return consts.UnSupportItem return consts.UnsupportedItem
default: default:
return consts.UnknownItem return consts.UnknownItem
} }
@ -98,7 +98,11 @@ func (i item) FileName() string {
case chromiumHistory: case chromiumHistory:
return consts.ChromiumHistoryFilename return consts.ChromiumHistoryFilename
case chromiumExtension: case chromiumExtension:
return consts.UnSupportItem return consts.UnsupportedItem
case yandexPassword:
return consts.ChromiumPasswordFilename
case yandexCreditCard:
return consts.ChromiumCreditFilename
case firefoxKey4: case firefoxKey4:
return consts.FirefoxKey4Filename return consts.FirefoxKey4Filename
case firefoxPassword: case firefoxPassword:
@ -110,13 +114,13 @@ func (i item) FileName() string {
case firefoxDownload: case firefoxDownload:
return consts.FirefoxDownloadFilename return consts.FirefoxDownloadFilename
case firefoxLocalStorage: case firefoxLocalStorage:
return consts.UnSupportItem return consts.UnsupportedItem
case firefoxCreditCard: case firefoxCreditCard:
return consts.UnSupportItem return consts.UnsupportedItem
case firefoxHistory: case firefoxHistory:
return consts.FirefoxHistoryFilename return consts.FirefoxHistoryFilename
case firefoxExtension: case firefoxExtension:
return consts.UnSupportItem return consts.UnsupportedItem
default: default:
return consts.UnknownItem return consts.UnknownItem
} }
@ -142,6 +146,10 @@ func (i item) NewBrowsingData() data.BrowsingData {
return nil return nil
case chromiumHistory: case chromiumHistory:
return &data.ChromiumHistory{} return &data.ChromiumHistory{}
case yandexPassword:
return &data.ChromiumPassword{}
case yandexCreditCard:
return &data.ChromiumCreditCard{}
case firefoxPassword: case firefoxPassword:
return &data.FirefoxPassword{} return &data.FirefoxPassword{}
case firefoxCookie: case firefoxCookie:

@ -3,7 +3,6 @@ package outputter
import ( import (
"encoding/csv" "encoding/csv"
"errors" "errors"
"fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
@ -73,7 +72,6 @@ func (o *outPutter) CreateFile(dirname, filename string) (*os.File, error) {
var err error var err error
p := filepath.Join(dirname, filename) p := filepath.Join(dirname, filename)
file, err = os.OpenFile(p, os.O_TRUNC|os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) file, err = os.OpenFile(p, os.O_TRUNC|os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
fmt.Println(err)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -54,6 +54,7 @@ func (b *dataBlob) ToByteArray() []byte {
return d return d
} }
// DPApi
// chrome < 80 https://chromium.googlesource.com/chromium/src/+/76f496a7235c3432983421402951d73905c8be96/components/os_crypt/os_crypt_win.cc#82 // chrome < 80 https://chromium.googlesource.com/chromium/src/+/76f496a7235c3432983421402951d73905c8be96/components/os_crypt/os_crypt_win.cc#82
func DPApi(data []byte) ([]byte, error) { func DPApi(data []byte) ([]byte, error) {
dllCrypt := syscall.NewLazyDLL("Crypt32.dll") dllCrypt := syscall.NewLazyDLL("Crypt32.dll")

@ -23,7 +23,7 @@ func IntToBool(a int) bool {
return true return true
} }
func BookMarkType(a int64) string { func BookmarkType(a int64) string {
switch a { switch a {
case 1: case 1:
return "url" return "url"
@ -66,7 +66,7 @@ func WriteFile(filename string, data []byte) error {
return err 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) r := strings.Replace(strings.TrimSpace(strings.ToLower(browser)), " ", "_", -1)
p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, filename, format)) p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, filename, format))
return p return p

Loading…
Cancel
Save