feat: support export multiple user from browser

Merge pull request #143 from moonD4rk/feat/multiple-user
pull/144/head
ᴍᴏᴏɴD4ʀᴋ 3 years ago committed by GitHub
commit 5526441e21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      cmd/hack-browser-data/main.go
  2. 2
      internal/browingdata/browsingdata.go
  3. 2
      internal/browingdata/creditcard/creditcard.go
  4. 8
      internal/browingdata/localstorage/localstorage.go
  5. 4
      internal/browingdata/outputter.go
  6. 4
      internal/browingdata/password/password.go
  7. 25
      internal/browser/browser.go
  8. 30
      internal/browser/browser_windows.go
  9. 79
      internal/browser/chromium/chromium.go
  10. 4
      internal/browser/chromium/chromium_darwin.go
  11. 4
      internal/browser/chromium/chromium_linux.go
  12. 6
      internal/browser/chromium/chromium_windows.go
  13. 7
      internal/browser/firefox/firefox.go
  14. 2
      internal/decrypter/decrypter_darwin.go
  15. 2
      internal/decrypter/decrypter_linux.go
  16. 11
      internal/utils/fileutil/filetutil.go
  17. 2
      internal/utils/typeutil/typeutil.go
  18. 12
      internal/utils/typeutil/typeutil_test.go

@ -29,7 +29,7 @@ func Execute() {
Name: "hack-browser-data",
Usage: "Export passwords/cookies/history/bookmarks from browser",
UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\nExport all browingdata(password/cookie/history/bookmark) from browser\nGithub Link: https://github.com/moonD4rk/HackBrowserData",
Version: "0.4.2",
Version: "0.4.3",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
&cli.BoolFlag{Name: "compress", Aliases: []string{"zip"}, Destination: &compress, Value: false, Usage: "compress result to zip"},

@ -35,7 +35,6 @@ func New(sources []item.Item) *Data {
}
func (d *Data) Recovery(masterKey []byte) error {
for _, source := range d.sources {
if err := source.Parse(masterKey); err != nil {
log.Errorf("parse %s error %s", source.Name(), err.Error())
@ -48,7 +47,6 @@ func (d *Data) Output(dir, browserName, flag string) {
output := NewOutPutter(flag)
for _, source := range d.sources {
filename := fileutil.Filename(browserName, source.Name(), output.Ext())
f, err := output.CreateFile(dir, filename)

@ -71,6 +71,7 @@ func (c *ChromiumCreditCard) Parse(masterKey []byte) error {
}
return nil
}
func (c *ChromiumCreditCard) Name() string {
return "creditcard"
}
@ -122,6 +123,7 @@ func (c *YandexCreditCard) Parse(masterKey []byte) error {
}
return nil
}
func (c *YandexCreditCard) Name() string {
return "creditcard"
}

@ -40,7 +40,7 @@ func (c *ChromiumLocalStorage) Parse(masterKey []byte) error {
if len(value) > 1024*5 {
continue
}
var s = new(storage)
s := new(storage)
s.fillKey(key)
s.fillValue(value)
// don't save meta data
@ -114,13 +114,11 @@ func (f *FirefoxLocalStorage) Parse(masterKey []byte) error {
}
defer rows.Close()
for rows.Next() {
var (
originKey, key, value string
)
var originKey, key, value string
if err = rows.Scan(&originKey, &key, &value); err != nil {
log.Warn(err)
}
var s = new(storage)
s := new(storage)
s.fillFirefox(originKey, key, value)
*f = append(*f, *s)
}

@ -50,7 +50,7 @@ func (o *OutPutter) CreateFile(dir, filename string) (*os.File, error) {
if dir != "" {
if _, err := os.Stat(dir); os.IsNotExist(err) {
err := os.MkdirAll(dir, 0777)
err := os.MkdirAll(dir, 0o777)
if err != nil {
return nil, err
}
@ -60,7 +60,7 @@ func (o *OutPutter) CreateFile(dir, filename string) (*os.File, error) {
var file *os.File
var err error
p := filepath.Join(dir, 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, 0o666)
if err != nil {
return nil, err
}

@ -229,9 +229,7 @@ func (f *FirefoxPassword) Name() string {
}
func getFirefoxDecryptKey(key4file string) (item1, item2, a11, a102 []byte, err error) {
var (
keyDB *sql.DB
)
var keyDB *sql.DB
keyDB, err = sql.Open("sqlite3", key4file)
if err != nil {
return nil, nil, nil, nil, err

@ -46,9 +46,12 @@ func pickChromium(name, profile string) []Browser {
log.Noticef("find browser %s failed, profile folder does not exist", v.name)
continue
}
if b, err := chromium.New(v.name, v.storage, v.profilePath, v.items); err == nil {
log.Noticef("find browser %s success", b.Name())
browsers = append(browsers, b)
if multiChromium, err := chromium.New(v.name, v.storage, v.profilePath, v.items); err == nil {
log.Noticef("find browser %s success", v.name)
for _, b := range multiChromium {
log.Noticef("find browser %s success", b.Name())
browsers = append(browsers, b)
}
} else {
log.Errorf("new chromium error: %s", err.Error())
}
@ -61,12 +64,14 @@ func pickChromium(name, profile string) []Browser {
if !fileutil.FolderExists(filepath.Clean(profile)) {
log.Fatalf("find browser %s failed, profile folder does not exist", c.name)
}
b, err := chromium.New(c.name, c.storage, profile, c.items)
chromiumList, err := chromium.New(c.name, c.storage, profile, c.items)
if err != nil {
log.Fatalf("new chromium error:", err)
log.Fatalf("new chromium error: %s", err)
}
for _, b := range chromiumList {
log.Noticef("find browser %s success", b.Name())
browsers = append(browsers, b)
}
log.Noticef("find browser %s success", b.Name())
browsers = append(browsers, b)
}
return browsers
}
@ -106,10 +111,8 @@ func ListBrowser() []string {
return l
}
var (
// home dir path for all platforms
homeDir, _ = os.UserHomeDir()
)
// home dir path for all platforms
var homeDir, _ = os.UserHomeDir()
const (
chromeName = "Chrome"

@ -15,7 +15,7 @@ var (
}{
"chrome": {
name: chromeName,
profilePath: chromeProfilePath,
profilePath: chromeUserDataPath,
items: item.DefaultChromium,
},
"edge": {
@ -25,12 +25,12 @@ var (
},
"chromium": {
name: chromiumName,
profilePath: chromiumProfilePath,
profilePath: chromiumUserDataPath,
items: item.DefaultChromium,
},
"chrome-beta": {
name: chromeBetaName,
profilePath: chromeBetaProfilePath,
profilePath: chromeBetaUserDataPath,
items: item.DefaultChromium,
},
"opera": {
@ -89,18 +89,18 @@ var (
)
var (
chromeProfilePath = homeDir + "/AppData/Local/Google/Chrome/User Data/Default/"
chromeBetaProfilePath = homeDir + "/AppData/Local/Google/Chrome Beta/User Data/Default/"
chromiumProfilePath = homeDir + "/AppData/Local/Chromium/User Data/Default/"
edgeProfilePath = homeDir + "/AppData/Local/Microsoft/Edge/User Data/Default/"
braveProfilePath = homeDir + "/AppData/Local/BraveSoftware/Brave-Browser/User Data/Default/"
speed360ProfilePath = homeDir + "/AppData/Local/360chrome/Chrome/User Data/Default/"
qqBrowserProfilePath = homeDir + "/AppData/Local/Tencent/QQBrowser/User Data/Default/"
operaProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera Stable/Default/"
operaGXProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera GX Stable/Default/"
vivaldiProfilePath = homeDir + "/AppData/Local/Vivaldi/User Data/Default/"
coccocProfilePath = homeDir + "/AppData/Local/CocCoc/Browser/User Data/Default/"
yandexProfilePath = homeDir + "/AppData/Local/Yandex/YandexBrowser/User Data/Default/"
chromeUserDataPath = homeDir + "/AppData/Local/Google/Chrome/User Data/Default/"
chromeBetaUserDataPath = homeDir + "/AppData/Local/Google/Chrome Beta/User Data/Default/"
chromiumUserDataPath = homeDir + "/AppData/Local/Chromium/User Data/Default/"
edgeProfilePath = homeDir + "/AppData/Local/Microsoft/Edge/User Data/Default/"
braveProfilePath = homeDir + "/AppData/Local/BraveSoftware/Brave-Browser/User Data/Default/"
speed360ProfilePath = homeDir + "/AppData/Local/360chrome/Chrome/User Data/Default/"
qqBrowserProfilePath = homeDir + "/AppData/Local/Tencent/QQBrowser/User Data/Default/"
operaProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera Stable/Default/"
operaGXProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera GX Stable/"
vivaldiProfilePath = homeDir + "/AppData/Local/Vivaldi/User Data/Default/"
coccocProfilePath = homeDir + "/AppData/Local/CocCoc/Browser/User Data/Default/"
yandexProfilePath = homeDir + "/AppData/Local/Yandex/YandexBrowser/User Data/Default/"
firefoxProfilePath = homeDir + "/AppData/Roaming/Mozilla/Firefox/Profiles/"
)

@ -1,7 +1,7 @@
package chromium
import (
"os"
"io/fs"
"path/filepath"
"strings"
@ -21,19 +21,27 @@ type chromium struct {
}
// New create instance of chromium browser, fill item's path if item is existed.
func New(name, storage, profilePath string, items []item.Item) (*chromium, error) {
func New(name, storage, profilePath string, items []item.Item) ([]*chromium, error) {
c := &chromium{
name: name,
storage: storage,
name: name,
storage: storage,
profilePath: profilePath,
items: items,
}
itemsPaths, err := c.getItemPath(profilePath, items)
multiItemPaths, err := c.getMultiItemPath(c.profilePath, c.items)
if err != nil {
return nil, err
}
c.profilePath = profilePath
c.itemPaths = itemsPaths
c.items = typeutil.Keys(itemsPaths)
return c, err
var chromiumList []*chromium
for user, itemPaths := range multiItemPaths {
chromiumList = append(chromiumList, &chromium{
name: fileutil.BrowserName(name, user),
items: typeutil.Keys(itemPaths),
itemPaths: itemPaths,
storage: storage,
})
}
return chromiumList, nil
}
func (c *chromium) Name() string {
@ -81,28 +89,49 @@ func (c *chromium) copyItemToLocal() error {
return nil
}
func (c *chromium) getItemPath(profilePath string, items []item.Item) (map[item.Item]string, error) {
var itemPaths = make(map[item.Item]string)
func (c *chromium) getMultiItemPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
// multiItemPaths is a map of user to item path, map[profile 1][item's name & path key pair]
multiItemPaths := make(map[string]map[item.Item]string)
parentDir := fileutil.ParentDir(profilePath)
baseDir := fileutil.BaseDir(profilePath)
err := filepath.Walk(parentDir, chromiumWalkFunc(items, itemPaths, baseDir))
err := filepath.Walk(parentDir, chromiumWalkFunc(items, multiItemPaths))
if err != nil {
return itemPaths, err
return nil, err
}
var keyPath string
var dir string
for userDir, v := range multiItemPaths {
for _, p := range v {
if strings.HasSuffix(p, item.ChromiumKey.FileName()) {
keyPath = p
dir = userDir
break
}
}
}
t := make(map[string]map[item.Item]string)
for userDir, v := range multiItemPaths {
if userDir == dir {
continue
}
t[userDir] = v
t[userDir][item.ChromiumKey] = keyPath
fillLocalStoragePath(t[userDir], item.ChromiumLocalStorage)
}
fillLocalStoragePath(itemPaths, item.ChromiumLocalStorage)
return itemPaths, nil
return t, nil
}
func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string, baseDir string) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
for _, it := range items {
switch {
case it.FileName() == info.Name():
if it == item.ChromiumKey {
itemPaths[it] = path
func chromiumWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
return func(path string, info fs.FileInfo, err error) error {
for _, v := range items {
if info.Name() == v.FileName() {
parentBaseDir := fileutil.ParentBaseDir(path)
if parentBaseDir == "System Profile" {
continue
}
if strings.Contains(path, baseDir) {
itemPaths[it] = path
if _, exist := multiItemPaths[parentBaseDir]; exist {
multiItemPaths[parentBaseDir][v] = path
} else {
multiItemPaths[parentBaseDir] = map[item.Item]string{v: path}
}
}
}

@ -1,3 +1,5 @@
//go:build darwin
package chromium
import (
@ -46,7 +48,7 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
if chromeSecret == nil {
return nil, ErrWrongSecurityCommand
}
var chromeSalt = []byte("saltysalt")
chromeSalt := []byte("saltysalt")
// @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)
if key == nil {

@ -1,3 +1,5 @@
//go:build linux
package chromium
import (
@ -60,7 +62,7 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
// @https://source.chromium.org/chromium/chromium/src/+/main:components/os_crypt/os_crypt_linux.cc;l=100
chromiumSecret = []byte("peanuts")
}
var chromiumSalt = []byte("saltysalt")
chromiumSalt := []byte("saltysalt")
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_linux.cc
key := pbkdf2.Key(chromiumSecret, chromiumSalt, 1, 16, sha1.New)
c.masterKey = key

@ -1,3 +1,5 @@
//go:build windows
package chromium
import (
@ -13,9 +15,7 @@ import (
"hack-browser-data/internal/utils/fileutil"
)
var (
errDecodeMasterKeyFailed = errors.New("decode master key failed")
)
var errDecodeMasterKeyFailed = errors.New("decode master key failed")
func (c *chromium) GetMasterKey() ([]byte, error) {
keyFile, err := fileutil.ReadFile(item.TempChromiumKey)

@ -21,13 +21,10 @@ type firefox struct {
itemPaths map[item.Item]string
}
var (
ErrProfilePathNotFound = errors.New("profile path not found")
)
var ErrProfilePathNotFound = errors.New("profile path not found")
// New returns a new firefox instance.
func New(name, storage, profilePath string, items []item.Item) ([]*firefox, error) {
f := &firefox{
name: name,
storage: storage,
@ -50,7 +47,7 @@ func New(name, storage, profilePath string, items []item.Item) ([]*firefox, erro
}
func (f *firefox) getMultiItemPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
var multiItemPaths = make(map[string]map[item.Item]string)
multiItemPaths := make(map[string]map[item.Item]string)
err := filepath.Walk(profilePath, firefoxWalkFunc(items, multiItemPaths))
return multiItemPaths, err
}

@ -5,7 +5,7 @@ func Chromium(key, encryptPass []byte) ([]byte, error) {
if len(key) == 0 {
return nil, errSecurityKeyIsEmpty
}
var chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
chromeIV := []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
return aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
} else {
return nil, errDecryptFailed

@ -1,7 +1,7 @@
package decrypter
func Chromium(key, encryptPass []byte) ([]byte, error) {
var chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
chromeIV := []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
if len(encryptPass) > 3 {
if len(key) == 0 {
return nil, errSecurityKeyIsEmpty

@ -81,7 +81,7 @@ func CopyDirHasSuffix(src, dst, suffix string) error {
if err != nil {
return err
}
if err := os.MkdirAll(dst, 0755); err != nil {
if err := os.MkdirAll(dst, 0o755); err != nil {
return err
}
for index, file := range filelist {
@ -102,7 +102,7 @@ func CopyFile(src, dst string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(dst, d, 0777)
err = ioutil.WriteFile(dst, d, 0o777)
if err != nil {
return err
}
@ -115,6 +115,11 @@ func Filename(browser, item, ext string) string {
return strings.ToLower(fmt.Sprintf("%s_%s.%s", replace.Replace(browser), item, ext))
}
func BrowserName(browser, user string) string {
replace := strings.NewReplacer(" ", "_", ".", "_", "-", "_", "Profile", "User")
return strings.ToLower(fmt.Sprintf("%s_%s", replace.Replace(browser), replace.Replace(user)))
}
// ParentDir returns the parent directory of the provided path
func ParentDir(p string) string {
return filepath.Dir(filepath.Clean(p))
@ -136,7 +141,7 @@ func CompressDir(dir string) error {
if err != nil {
return err
}
var b = new(bytes.Buffer)
b := new(bytes.Buffer)
zw := zip.NewWriter(b)
for _, f := range files {
fw, _ := zw.Create(f.Name())

@ -24,7 +24,7 @@ func IntToBool[T constraints.Signed](a T) bool {
}
func Reverse[T any](s []T) []T {
var h = make([]T, len(s))
h := make([]T, len(s))
for i := 0; i < len(s); i++ {
h[i] = s[len(s)-i-1]
}

@ -4,13 +4,11 @@ import (
"testing"
)
var (
reverseTestCases = [][]any{
[]any{1, 2, 3, 4, 5},
[]any{"1", "2", "3", "4", "5"},
[]any{"1", 2, "3", "4", 5},
}
)
var reverseTestCases = [][]any{
{1, 2, 3, 4, 5},
{"1", "2", "3", "4", "5"},
{"1", 2, "3", "4", 5},
}
func TestReverse(t *testing.T) {
for _, ts := range reverseTestCases {

Loading…
Cancel
Save