feat: support firefox for mac

pull/116/head
ᴍᴏᴏɴD4ʀᴋ 3 years ago
parent 3c94e68780
commit 65b209f582
  1. 215
      pkg/browser/browser.go
  2. 32
      pkg/browser/browser_darwin.go
  3. 44
      pkg/browser/browser_test.go
  4. 16
      pkg/browser/consts/filename.go
  5. 48
      pkg/browser/data/bookmark.go
  6. 69
      pkg/browser/data/browsingdata.go
  7. 42
      pkg/browser/data/cookie.go
  8. 2
      pkg/browser/data/creditcard.go
  9. 60
      pkg/browser/data/download.go
  10. 50
      pkg/browser/data/history.go
  11. 72
      pkg/browser/data/model.go
  12. 121
      pkg/browser/data/password.go
  13. 71
      pkg/browser/item.go

@ -2,6 +2,7 @@ package browser
import ( import (
"fmt" "fmt"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"path" "path"
@ -16,29 +17,60 @@ var (
homeDir, _ = os.UserHomeDir() homeDir, _ = os.UserHomeDir()
) )
func PickBrowsers(name string) []*chromium { func PickBrowsers(name string) {
}
func PickChromium(name string) []*chromium {
var browsers []*chromium var browsers []*chromium
name = strings.ToLower(name) name = strings.ToLower(name)
if name == "all" { if name == "all" {
for _, v := range browserList { for _, choice := range chromiumList {
b := v.New(v.browserInfo, v.items) b, err := newChromium(choice.browserInfo, choice.items)
if err != nil {
panic(err)
}
browsers = append(browsers, b) browsers = append(browsers, b)
} }
return browsers return browsers
} }
if choice, ok := browserList[name]; ok { if choice, ok := chromiumList[name]; ok {
b := choice.New(choice.browserInfo, choice.items) b, err := newChromium(choice.browserInfo, choice.items)
if err != nil {
panic(err)
}
browsers = append(browsers, b) browsers = append(browsers, b)
return browsers return browsers
} }
return nil return nil
} }
func PickFirefox(name string) []*firefox {
var browsers []*firefox
name = strings.ToLower(name)
if name == "all" || name == "firefox" {
for _, v := range firefoxList {
b, err := newFirefox(v.browserInfo, v.items)
if err != nil {
panic(err)
}
// b := v.New(v.browserInfo, v.items)
browsers = append(browsers, b...)
}
return browsers
}
// if choice, ok := browserList[name]; ok {
// b := choice.New(choice.browserInfo, choice.items)
// browsers = append(browsers, b)
// return browsers
// }
return nil
}
type chromium struct { type chromium struct {
browserInfo *browserInfo browserInfo *browserInfo
items []item items []item
itemPaths map[item]string itemPaths map[item]string
masterKey []byte
} }
func (c *chromium) GetProfilePath() string { func (c *chromium) GetProfilePath() string {
@ -57,17 +89,135 @@ type firefox struct {
browserInfo *browserInfo browserInfo *browserInfo
items []item items []item
itemPaths map[item]string itemPaths map[item]string
masterKey []byte multiItemPaths map[string]map[item]string
} }
// NewBrowser 根据浏览器信息生成 Browser Interface // NewBrowser 根据浏览器信息生成 Browser Interface
func newBrowser(browserInfo *browserInfo, items []item) *chromium { func newChromium(info *browserInfo, items []item) (*chromium, error) {
return &chromium{ c := &chromium{
browserInfo: browserInfo, browserInfo: info,
items: items,
}
itemsPaths, err := getChromiumItemAbsPath(c.browserInfo.profilePath, c.items)
if err != nil {
return nil, err
}
c.itemPaths = itemsPaths
return c, err
}
// newFirefox
func newFirefox(info *browserInfo, items []item) ([]*firefox, error) {
f := &firefox{
browserInfo: info,
items: items,
}
multiItemPaths, err := getFirefoxItemAbsPath(f.browserInfo.profilePath, f.items)
if err != nil {
panic(err)
}
var firefoxList []*firefox
for name, value := range multiItemPaths {
firefoxList = append(firefoxList, &firefox{
browserInfo: &browserInfo{
name: name,
masterKey: nil,
},
items: items, items: items,
itemPaths: value,
// multiItemPaths: value,
})
}
return firefoxList, nil
}
func getFirefoxItemAbsPath(profilePath string, items []item) (map[string]map[item]string, error) {
var multiItemPaths = make(map[string]map[item]string)
absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
err := filepath.Walk(absProfilePath, firefoxWalkFunc(items, multiItemPaths))
return multiItemPaths, err
}
func (f *firefox) copyItemFileToLocal() error {
for item, sourcePath := range f.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
// 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 {
return func(path string, info fs.FileInfo, err error) error {
for _, v := range items {
if info.Name() == v.DefaultName() {
parentDir := getParentDir(path)
if _, exist := multiItemPaths[parentDir]; exist {
multiItemPaths[parentDir][v] = path
} else {
multiItemPaths[parentDir] = map[item]string{v: path}
}
}
}
return err
} }
} }
func getParentDir(absPath string) string {
return filepath.Base(filepath.Dir(absPath))
}
func chromiumWalkFunc(items []item, itemPaths map[item]string) filepath.WalkFunc { func chromiumWalkFunc(items []item, itemPaths map[item]string) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error { return func(path string, info os.FileInfo, err error) error {
for _, item := range items { for _, item := range items {
@ -82,12 +232,11 @@ func chromiumWalkFunc(items []item, itemPaths map[item]string) filepath.WalkFunc
} }
} }
func (c *chromium) walkItemAbsPath() error { func getChromiumItemAbsPath(profilePath string, items []item) (map[item]string, error) {
var itemPaths = make(map[item]string) var itemPaths = make(map[item]string)
absProfilePath := path.Join(homeDir, filepath.Clean(c.browserInfo.profilePath)) absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
err := filepath.Walk(absProfilePath, chromiumWalkFunc(defaultChromiumItems, itemPaths)) err := filepath.Walk(absProfilePath, chromiumWalkFunc(items, itemPaths))
c.itemPaths = itemPaths return itemPaths, err
return err
} }
func (c *chromium) copyItemFileToLocal() error { func (c *chromium) copyItemFileToLocal() error {
@ -128,18 +277,50 @@ func (c *chromium) GetBrowsingData() []data.BrowsingData {
return browsingData return browsingData
} }
func (f *firefox) GetMasterKey() ([]byte, error) {
return f.browserInfo.masterKey, nil
}
func (f *firefox) GetBrowserName() string {
return f.browserInfo.name
}
func (f *firefox) GetBrowsingData() []data.BrowsingData {
var browsingData []data.BrowsingData
for item := range f.itemPaths {
d := item.NewBrowsingData()
if d != nil {
browsingData = append(browsingData, d)
}
}
return browsingData
}
type browserInfo struct { type browserInfo struct {
name string name string
storage string storage string
profilePath string profilePath string
masterKey string masterKey []byte
} }
const ( const (
chromeName = "Chrome" chromeName = "Chrome"
edgeName = "Edge" edgeName = "Edge"
firefoxName = "Firefox"
) )
var defaultFirefoxItems = []item{
firefoxKey4,
firefoxPassword,
firefoxCookie,
firefoxBookmark,
firefoxHistory,
firefoxDownload,
firefoxCreditCard,
firefoxLocalStorage,
firefoxExtension,
}
var defaultChromiumItems = []item{ var defaultChromiumItems = []item{
chromiumKey, chromiumKey,
chromiumPassword, chromiumPassword,
@ -147,7 +328,7 @@ var defaultChromiumItems = []item{
chromiumBookmark, chromiumBookmark,
chromiumHistory, chromiumHistory,
chromiumDownload, chromiumDownload,
chromiumCreditcard, chromiumCreditCard,
chromiumLocalStorage, chromiumLocalStorage,
chromiumExtension, chromiumExtension,
} }

@ -10,21 +10,30 @@ import (
) )
var ( var (
browserList = map[string]struct { chromiumList = map[string]struct {
browserInfo *browserInfo browserInfo *browserInfo
items []item items []item
New func(browser *browserInfo, items []item) *chromium // New func(browser *browserInfo, items []item) *firefox
}{ }{
"chrome": { "chrome": {
browserInfo: chromeInfo, browserInfo: chromeInfo,
items: defaultChromiumItems, items: defaultChromiumItems,
New: newBrowser, // New: newBrowser,
}, },
// "edge": { "edge": {
// browserInfo: edgeInfo, browserInfo: edgeInfo,
// items: defaultChromiumItems, items: defaultChromiumItems,
// New: newBrowser, // New: newBrowser,
// }, },
}
firefoxList = map[string]struct {
browserInfo *browserInfo
items []item
}{
"firefox": {
browserInfo: firefoxInfo,
items: defaultFirefoxItems,
},
} }
) )
@ -56,9 +65,8 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
var chromeSalt = []byte("saltysalt") var chromeSalt = []byte("saltysalt")
// @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.masterKey = key c.browserInfo.masterKey = key
return c.masterKey, nil return c.browserInfo.masterKey, nil
} }
var ( var (
@ -72,6 +80,10 @@ var (
storage: edgeStorageName, storage: edgeStorageName,
profilePath: edgeProfilePath, profilePath: edgeProfilePath,
} }
firefoxInfo = &browserInfo{
name: firefoxName,
profilePath: fireFoxProfilePath,
}
) )
const ( const (

@ -7,8 +7,8 @@ import (
"hack-browser-data/pkg/browser/outputter" "hack-browser-data/pkg/browser/outputter"
) )
func TestPickBrowsers(t *testing.T) { func TestPickChromium(t *testing.T) {
browsers := PickBrowsers("all") browsers := PickChromium("all")
filetype := "json" filetype := "json"
dir := "result" dir := "result"
output := outputter.NewOutPutter(filetype) output := outputter.NewOutPutter(filetype)
@ -16,9 +16,6 @@ func TestPickBrowsers(t *testing.T) {
panic(err) panic(err)
} }
for _, b := range browsers { for _, b := range browsers {
if err := b.walkItemAbsPath(); err != nil {
panic(err)
}
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)
@ -29,6 +26,7 @@ func TestPickBrowsers(t *testing.T) {
} }
browserName := b.GetBrowserName() browserName := b.GetBrowserName()
multiData := b.GetBrowsingData() multiData := b.GetBrowsingData()
// TODO: 优化获取 Data 逻辑
for _, data := range multiData { for _, data := range multiData {
if data == nil { if data == nil {
fmt.Println(data) fmt.Println(data)
@ -48,3 +46,39 @@ func TestPickBrowsers(t *testing.T) {
} }
} }
} }
func TestPickFirefox(t *testing.T) {
browsers := PickFirefox("all")
filetype := "json"
dir := "result"
output := outputter.NewOutPutter(filetype)
if err := output.MakeDir("result"); err != nil {
panic(err)
}
for _, b := range browsers {
fmt.Printf("%+v\n", b)
if err := b.copyItemFileToLocal(); err != nil {
panic(err)
}
masterKey, err := b.GetMasterKey()
if err != nil {
fmt.Println(err)
}
browserName := b.GetBrowserName()
multiData := b.GetBrowsingData()
// TODO: 优化获取 Data 逻辑
for _, data := range multiData {
if err := data.Parse(masterKey); err != nil {
fmt.Println(err)
}
filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), filetype)
file, err := output.CreateFile(dir, filename)
if err != nil {
panic(err)
}
if err := output.Write(data, file); err != nil {
panic(err)
}
}
}
}

@ -14,10 +14,13 @@ const (
YandexPassword = "Ya PassMan Data" YandexPassword = "Ya PassMan Data"
YandexCredit = "Ya Credit Cards" YandexCredit = "Ya Credit Cards"
FirefoxKey = "key4.db" FirefoxKey4 = "key4.db"
FirefoxCookie = "cookies.sqlite" FirefoxCookie = "cookies.sqlite"
FirefoxLogin = "logins.json" FirefoxPassword = "logins.json"
FirefoxData = "places.sqlite" FirefoxData = "places.sqlite"
UnknownItem = "unknown item"
UnSupportItem = "unsupport item"
) )
// item's renamed filename // item's renamed filename
@ -34,10 +37,11 @@ const (
YandexPasswordFilename = "YandexPasswordFilename" YandexPasswordFilename = "YandexPasswordFilename"
YandexCreditFilename = "YandexCreditFilename" YandexCreditFilename = "YandexCreditFilename"
// TODO: add all firefox's filename FirefoxKey4Filename = "FirefoxKey4DBFilename"
FirefoxKey4DBFilename = "FirefoxKey4DBFilename"
FirefoxCookieFilename = "FirefoxCookieFilename" FirefoxCookieFilename = "FirefoxCookieFilename"
FirefoxLoginFilename = "FirefoxLoginFilename" FirefoxPasswordFilename = "FirefoxPasswordFilename"
FirefoxDownloadFilename = "FirefoxDownloadFilename"
FirefoxHistoryFilename = "FirefoxHistoryFilename"
FirefoxBookmarkFilename = "FirefoxBookmarkFilename"
FirefoxDataFilename = "FirefoxDataFilename" FirefoxDataFilename = "FirefoxDataFilename"
) )

@ -1,6 +1,8 @@
package data package data
import ( import (
"database/sql"
"fmt"
"sort" "sort"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
@ -62,3 +64,49 @@ func getBookmarkChildren(value gjson.Result, w *ChromiumBookmark) (children gjso
func (c *ChromiumBookmark) Name() string { func (c *ChromiumBookmark) Name() string {
return "bookmark" return "bookmark"
} }
type FirefoxBookmark []bookmark
func (f *FirefoxBookmark) Parse(masterKey []byte) error {
var (
err error
keyDB *sql.DB
bookmarkRows *sql.Rows
)
keyDB, err = sql.Open("sqlite3", consts.FirefoxBookmarkFilename)
if err != nil {
return err
}
_, err = keyDB.Exec(closeJournalMode)
defer keyDB.Close()
bookmarkRows, err = keyDB.Query(queryFirefoxBookMark)
if err != nil {
return err
}
defer bookmarkRows.Close()
for bookmarkRows.Next() {
var (
id, bType, dateAdded int64
title, url string
)
if err = bookmarkRows.Scan(&id, &url, &bType, &dateAdded, &title); err != nil {
fmt.Println(err)
}
*f = append(*f, bookmark{
ID: id,
Name: title,
Type: utils.BookMarkType(bType),
URL: url,
DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
})
}
sort.Slice(*f, func(i, j int) bool {
return (*f)[i].DateAdded.After((*f)[j].DateAdded)
})
return nil
}
func (f *FirefoxBookmark) Name() string {
return "bookmark"
}

@ -1,7 +1,76 @@
package data package data
import "time"
type BrowsingData interface { type BrowsingData interface {
Parse(masterKey []byte) error Parse(masterKey []byte) error
Name() string Name() string
} }
const (
queryChromiumCredit = `SELECT guid, name_on_card, expiration_month, expiration_year, card_number_encrypted FROM credit_cards`
queryChromiumLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins`
queryChromiumHistory = `SELECT url, title, visit_count, last_visit_time FROM urls`
queryChromiumDownload = `SELECT target_path, tab_url, total_bytes, start_time, end_time, mime_type FROM downloads`
queryChromiumCookie = `SELECT name, encrypted_value, host_key, path, creation_utc, expires_utc, is_secure, is_httponly, has_expires, is_persistent FROM cookies`
queryFirefoxHistory = `SELECT id, url, last_visit_date, title, visit_count FROM moz_places where title not null`
queryFirefoxDownload = `SELECT place_id, GROUP_CONCAT(content), url, dateAdded FROM (SELECT * FROM moz_annos INNER JOIN moz_places ON moz_annos.place_id=moz_places.id) t GROUP BY place_id`
queryFirefoxBookMark = `SELECT id, url, type, dateAdded, title FROM (SELECT * FROM moz_bookmarks INNER JOIN moz_places ON moz_bookmarks.fk=moz_places.id)`
queryFirefoxCookie = `SELECT name, value, host, path, creationTime, expiry, isSecure, isHttpOnly FROM moz_cookies`
queryMetaData = `SELECT item1, item2 FROM metaData WHERE id = 'password'`
queryNssPrivate = `SELECT a11, a102 from nssPrivate`
closeJournalMode = `PRAGMA journal_mode=off`
)
type (
loginData struct {
UserName string
encryptPass []byte
encryptUser []byte
Password string
LoginUrl string
CreateDate time.Time
}
bookmark struct {
ID int64
Name string
Type string
URL string
DateAdded time.Time
}
cookie struct {
Host string
Path string
KeyName string
encryptValue []byte
Value string
IsSecure bool
IsHTTPOnly bool
HasExpire bool
IsPersistent bool
CreateDate time.Time
ExpireDate time.Time
}
history struct {
Title string
Url string
VisitCount int
LastVisitTime time.Time
}
download struct {
TargetPath string
Url string
TotalBytes int64
StartTime time.Time
EndTime time.Time
MimeType string
}
card struct {
GUID string
Name string
ExpirationYear string
ExpirationMonth string
CardNumber string
}
)

@ -8,6 +8,8 @@ import (
"hack-browser-data/pkg/browser/consts" "hack-browser-data/pkg/browser/consts"
"hack-browser-data/pkg/decrypter" "hack-browser-data/pkg/decrypter"
"hack-browser-data/utils" "hack-browser-data/utils"
_ "github.com/mattn/go-sqlite3"
) )
type ChromiumCookie []cookie type ChromiumCookie []cookie
@ -72,3 +74,43 @@ func (c *ChromiumCookie) Parse(masterKey []byte) error {
func (c *ChromiumCookie) Name() string { func (c *ChromiumCookie) Name() string {
return "cookie" return "cookie"
} }
type FirefoxCookie []cookie
func (f *FirefoxCookie) Parse(masterKey []byte) error {
cookieDB, err := sql.Open("sqlite3", consts.FirefoxCookieFilename)
if err != nil {
return err
}
defer cookieDB.Close()
rows, err := cookieDB.Query(queryFirefoxCookie)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var (
name, value, host, path string
isSecure, isHttpOnly int
creationTime, expiry int64
)
if err = rows.Scan(&name, &value, &host, &path, &creationTime, &expiry, &isSecure, &isHttpOnly); err != nil {
fmt.Println(err)
}
*f = append(*f, cookie{
KeyName: name,
Host: host,
Path: path,
IsSecure: utils.IntToBool(isSecure),
IsHTTPOnly: utils.IntToBool(isHttpOnly),
CreateDate: utils.TimeStampFormat(creationTime / 1000000),
ExpireDate: utils.TimeStampFormat(expiry),
Value: value,
})
}
return nil
}
func (f *FirefoxCookie) Name() string {
return "cookie"
}

@ -6,6 +6,8 @@ import (
"hack-browser-data/pkg/browser/consts" "hack-browser-data/pkg/browser/consts"
"hack-browser-data/pkg/decrypter" "hack-browser-data/pkg/decrypter"
_ "github.com/mattn/go-sqlite3"
) )
type ChromiumCreditCard []card type ChromiumCreditCard []card

@ -4,9 +4,14 @@ import (
"database/sql" "database/sql"
"fmt" "fmt"
"sort" "sort"
"strings"
"github.com/tidwall/gjson"
"hack-browser-data/pkg/browser/consts" "hack-browser-data/pkg/browser/consts"
"hack-browser-data/utils" "hack-browser-data/utils"
_ "github.com/mattn/go-sqlite3"
) )
type ChromiumDownload []download type ChromiumDownload []download
@ -49,3 +54,58 @@ func (c *ChromiumDownload) Parse(masterKey []byte) error {
func (c *ChromiumDownload) Name() string { func (c *ChromiumDownload) Name() string {
return "download" return "download"
} }
type FirefoxDownload []download
func (f *FirefoxDownload) Parse(masterKey []byte) error {
var (
err error
keyDB *sql.DB
downloadRows *sql.Rows
)
keyDB, err = sql.Open("sqlite3", consts.FirefoxDownloadFilename)
if err != nil {
return err
}
_, err = keyDB.Exec(closeJournalMode)
if err != nil {
return err
}
defer keyDB.Close()
downloadRows, err = keyDB.Query(queryFirefoxDownload)
if err != nil {
return err
}
defer downloadRows.Close()
for downloadRows.Next() {
var (
content, url string
placeID, dateAdded int64
)
if err = downloadRows.Scan(&placeID, &content, &url, &dateAdded); err != nil {
fmt.Println(err)
}
contentList := strings.Split(content, ",{")
if len(contentList) > 1 {
path := contentList[0]
json := "{" + contentList[1]
endTime := gjson.Get(json, "endTime")
fileSize := gjson.Get(json, "fileSize")
*f = append(*f, download{
TargetPath: path,
Url: url,
TotalBytes: fileSize.Int(),
StartTime: utils.TimeStampFormat(dateAdded / 1000000),
EndTime: utils.TimeStampFormat(endTime.Int() / 1000),
})
}
}
sort.Slice(*f, func(i, j int) bool {
return (*f)[i].TotalBytes < (*f)[j].TotalBytes
})
return nil
}
func (f *FirefoxDownload) Name() string {
return "download"
}

@ -7,6 +7,8 @@ import (
"hack-browser-data/pkg/browser/consts" "hack-browser-data/pkg/browser/consts"
"hack-browser-data/utils" "hack-browser-data/utils"
_ "github.com/mattn/go-sqlite3"
) )
type ChromiumHistory []history type ChromiumHistory []history
@ -49,3 +51,51 @@ func (c *ChromiumHistory) Parse(masterKey []byte) error {
func (c *ChromiumHistory) Name() string { func (c *ChromiumHistory) Name() string {
return "history" return "history"
} }
type FirefoxHistory []history
func (f *FirefoxHistory) Parse(masterKey []byte) error {
var (
err error
keyDB *sql.DB
historyRows *sql.Rows
)
keyDB, err = sql.Open("sqlite3", consts.FirefoxHistoryFilename)
if err != nil {
return err
}
_, err = keyDB.Exec(closeJournalMode)
if err != nil {
return err
}
defer keyDB.Close()
historyRows, err = keyDB.Query(queryFirefoxHistory)
if err != nil {
return err
}
defer historyRows.Close()
for historyRows.Next() {
var (
id, visitDate int64
url, title string
visitCount int
)
if err = historyRows.Scan(&id, &url, &visitDate, &title, &visitCount); err != nil {
fmt.Println(err)
}
*f = append(*f, history{
Title: title,
Url: url,
VisitCount: visitCount,
LastVisitTime: utils.TimeStampFormat(visitDate / 1000000),
})
}
sort.Slice(*f, func(i, j int) bool {
return (*f)[i].VisitCount < (*f)[j].VisitCount
})
return nil
}
func (f *FirefoxHistory) Name() string {
return "history"
}

@ -1,72 +0,0 @@
package data
import (
"time"
)
const (
queryChromiumCredit = `SELECT guid, name_on_card, expiration_month, expiration_year, card_number_encrypted FROM credit_cards`
queryChromiumLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins`
queryChromiumHistory = `SELECT url, title, visit_count, last_visit_time FROM urls`
queryChromiumDownload = `SELECT target_path, tab_url, total_bytes, start_time, end_time, mime_type FROM downloads`
queryChromiumCookie = `SELECT name, encrypted_value, host_key, path, creation_utc, expires_utc, is_secure, is_httponly, has_expires, is_persistent FROM cookies`
queryFirefoxHistory = `SELECT id, url, last_visit_date, title, visit_count FROM moz_places where title not null`
queryFirefoxDownload = `SELECT place_id, GROUP_CONCAT(content), url, dateAdded FROM (SELECT * FROM moz_annos INNER JOIN moz_places ON moz_annos.place_id=moz_places.id) t GROUP BY place_id`
queryFirefoxBookMark = `SELECT id, url, type, dateAdded, title FROM (SELECT * FROM moz_bookmarks INNER JOIN moz_places ON moz_bookmarks.fk=moz_places.id)`
queryFirefoxCookie = `SELECT name, value, host, path, creationTime, expiry, isSecure, isHttpOnly FROM moz_cookies`
queryMetaData = `SELECT item1, item2 FROM metaData WHERE id = 'password'`
queryNssPrivate = `SELECT a11, a102 from nssPrivate`
closeJournalMode = `PRAGMA journal_mode=off`
)
type (
loginData struct {
UserName string
encryptPass []byte
encryptUser []byte
Password string
LoginUrl string
CreateDate time.Time
}
bookmark struct {
ID int64
Name string
Type string
URL string
DateAdded time.Time
}
cookie struct {
Host string
Path string
KeyName string
encryptValue []byte
Value string
IsSecure bool
IsHTTPOnly bool
HasExpire bool
IsPersistent bool
CreateDate time.Time
ExpireDate time.Time
}
history struct {
Title string
Url string
VisitCount int
LastVisitTime time.Time
}
download struct {
TargetPath string
Url string
TotalBytes int64
StartTime time.Time
EndTime time.Time
MimeType string
}
card struct {
GUID string
Name string
ExpirationYear string
ExpirationMonth string
CardNumber string
}
)

@ -1,8 +1,11 @@
package data package data
import ( import (
"bytes"
"database/sql" "database/sql"
"encoding/base64"
"fmt" "fmt"
"io/ioutil"
"sort" "sort"
"time" "time"
@ -11,6 +14,7 @@ import (
"hack-browser-data/utils" "hack-browser-data/utils"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
"github.com/tidwall/gjson"
) )
type ChromiumPassword []loginData type ChromiumPassword []loginData
@ -73,9 +77,122 @@ func (c *ChromiumPassword) Name() string {
return "password" return "password"
} }
type firefoxPassword struct { type FirefoxPassword []loginData
func (f *FirefoxPassword) Parse(masterKey []byte) error {
globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey(consts.FirefoxKey4Filename)
if err != nil {
return err
}
metaPBE, err := decrypter.NewASN1PBE(metaBytes)
if err != nil {
return err
} }
func (c *firefoxPassword) Parse(masterKey []byte) error { k, err := metaPBE.Decrypt(globalSalt, masterKey)
if err != nil {
return err
}
keyLin := []byte{248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
if bytes.Contains(k, []byte("password-check")) {
m := bytes.Compare(nssA102, keyLin)
if m == 0 {
nssPBE, err := decrypter.NewASN1PBE(nssA11)
if err != nil {
return err
}
finallyKey, err := nssPBE.Decrypt(globalSalt, masterKey)
finallyKey = finallyKey[:24]
if err != nil {
return err
}
allLogin, err := getFirefoxLoginData(consts.FirefoxPasswordFilename)
if err != nil {
return err
}
for _, v := range allLogin {
userPBE, err := decrypter.NewASN1PBE(v.encryptUser)
if err != nil {
return err
}
pwdPBE, err := decrypter.NewASN1PBE(v.encryptPass)
if err != nil {
return err
}
user, err := userPBE.Decrypt(finallyKey, masterKey)
if err != nil {
return err
}
pwd, err := pwdPBE.Decrypt(finallyKey, masterKey)
if err != nil {
return err
}
*f = append(*f, loginData{
LoginUrl: v.LoginUrl,
UserName: string(decrypter.PKCS5UnPadding(user)),
Password: string(decrypter.PKCS5UnPadding(pwd)),
CreateDate: v.CreateDate,
})
}
}
}
sort.Slice(*f, func(i, j int) bool {
return (*f)[i].CreateDate.After((*f)[j].CreateDate)
})
return nil return nil
} }
func (f *FirefoxPassword) Name() string {
return "password"
}
func getFirefoxDecryptKey(key4file string) (item1, item2, a11, a102 []byte, err error) {
var (
keyDB *sql.DB
)
keyDB, err = sql.Open("sqlite3", key4file)
if err != nil {
return nil, nil, nil, nil, err
}
defer keyDB.Close()
if err = keyDB.QueryRow(queryMetaData).Scan(&item1, &item2); err != nil {
return nil, nil, nil, nil, err
}
if err = keyDB.QueryRow(queryNssPrivate).Scan(&a11, &a102); err != nil {
return nil, nil, nil, nil, err
}
return item1, item2, a11, a102, nil
}
func getFirefoxLoginData(loginJson string) (l []loginData, err error) {
s, err := ioutil.ReadFile(loginJson)
if err != nil {
return nil, err
}
h := gjson.GetBytes(s, "logins")
if h.Exists() {
for _, v := range h.Array() {
var (
m loginData
user []byte
pass []byte
)
m.LoginUrl = v.Get("formSubmitURL").String()
user, err = base64.StdEncoding.DecodeString(v.Get("encryptedUsername").String())
if err != nil {
return nil, err
}
pass, err = base64.StdEncoding.DecodeString(v.Get("encryptedPassword").String())
if err != nil {
return nil, err
}
m.encryptUser = user
m.encryptPass = pass
m.CreateDate = utils.TimeStampFormat(v.Get("timeCreated").Int() / 1000)
l = append(l, m)
}
}
return l, nil
}

@ -14,17 +14,20 @@ const (
chromiumBookmark chromiumBookmark
chromiumHistory chromiumHistory
chromiumDownload chromiumDownload
chromiumCreditcard chromiumCreditCard
chromiumLocalStorage chromiumLocalStorage
chromiumExtension chromiumExtension
yandexPassword
yandexCreditCard
firefoxKey4 firefoxKey4
firefoxPassword firefoxPassword
firefoxCookie firefoxCookie
firefoxBookmark firefoxBookmark
firefoxHistory firefoxHistory
firefoxDownload firefoxDownload
firefoxCreditcard firefoxCreditCard
firefoxLocalStorage firefoxLocalStorage
firefoxExtension firefoxExtension
) )
@ -43,18 +46,36 @@ func (i item) DefaultName() string {
return consts.ChromiumDownload return consts.ChromiumDownload
case chromiumLocalStorage: case chromiumLocalStorage:
return consts.ChromiumLocalStorage return consts.ChromiumLocalStorage
case chromiumCreditcard: case chromiumCreditCard:
return consts.ChromiumCredit return consts.ChromiumCredit
case chromiumExtension: case chromiumExtension:
return "unsupport item" return consts.UnknownItem
case chromiumHistory: case chromiumHistory:
return consts.ChromiumHistory return consts.ChromiumHistory
case yandexPassword:
return consts.YandexPassword
case yandexCreditCard:
return consts.YandexCredit
case firefoxKey4:
return consts.FirefoxKey4
case firefoxPassword: case firefoxPassword:
return consts.FirefoxLogin return consts.FirefoxPassword
case firefoxCookie: case firefoxCookie:
return consts.FirefoxCookie
case firefoxBookmark:
return consts.FirefoxData
case firefoxDownload:
return consts.FirefoxData return consts.FirefoxData
case firefoxLocalStorage:
return consts.UnSupportItem
case firefoxCreditCard:
return consts.UnSupportItem
case firefoxHistory:
return consts.FirefoxData
case firefoxExtension:
return consts.UnSupportItem
default: default:
return "unknown item" return consts.UnknownItem
} }
} }
@ -72,18 +93,32 @@ func (i item) FileName() string {
return consts.ChromiumDownloadFilename return consts.ChromiumDownloadFilename
case chromiumLocalStorage: case chromiumLocalStorage:
return consts.ChromiumLocalStorageFilename return consts.ChromiumLocalStorageFilename
case chromiumCreditcard: case chromiumCreditCard:
return consts.ChromiumCreditFilename return consts.ChromiumCreditFilename
case chromiumExtension:
return "unsupport item"
case chromiumHistory: case chromiumHistory:
return consts.ChromiumHistoryFilename return consts.ChromiumHistoryFilename
case chromiumExtension:
return consts.UnSupportItem
case firefoxKey4:
return consts.FirefoxKey4Filename
case firefoxPassword: case firefoxPassword:
return consts.FirefoxLoginFilename return consts.FirefoxPasswordFilename
case firefoxCookie: case firefoxCookie:
return consts.FirefoxDataFilename return consts.FirefoxCookieFilename
case firefoxBookmark:
return consts.FirefoxBookmarkFilename
case firefoxDownload:
return consts.FirefoxDownloadFilename
case firefoxLocalStorage:
return consts.UnSupportItem
case firefoxCreditCard:
return consts.UnSupportItem
case firefoxHistory:
return consts.FirefoxHistoryFilename
case firefoxExtension:
return consts.UnSupportItem
default: default:
return "unknown item" return consts.UnknownItem
} }
} }
@ -101,16 +136,22 @@ func (i item) NewBrowsingData() data.BrowsingData {
return &data.ChromiumDownload{} return &data.ChromiumDownload{}
case chromiumLocalStorage: case chromiumLocalStorage:
return nil return nil
case chromiumCreditcard: case chromiumCreditCard:
return &data.ChromiumCreditCard{} return &data.ChromiumCreditCard{}
case chromiumExtension: case chromiumExtension:
return nil return nil
case chromiumHistory: case chromiumHistory:
return &data.ChromiumHistory{} return &data.ChromiumHistory{}
case firefoxPassword: case firefoxPassword:
return nil return &data.FirefoxPassword{}
case firefoxCookie: case firefoxCookie:
return nil return &data.FirefoxCookie{}
case firefoxBookmark:
return &data.FirefoxBookmark{}
case firefoxDownload:
return &data.FirefoxDownload{}
case firefoxHistory:
return &data.FirefoxHistory{}
default: default:
return nil return nil
} }

Loading…
Cancel
Save