mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
update to v0.4.1, support export local storage
Merge pull request #125 from moonD4rk/dev
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
[中文说明](https://github.com/moonD4rk/HackBrowserData/blob/master/README_ZH.md)
|
||||
|
||||
`HackBrowserData` is an open-source tool that could help you decrypt data ( password|bookmark|cookie|history|credit card|downloads link ) from the browser. It supports the most popular browsers on the market and runs on Windows, macOS and Linux.
|
||||
`HackBrowserData` is an open-source tool that could help you decrypt data ( password|bookmark|cookie|history|credit card|download link|local storage ) from the browser. It supports the most popular browsers on the market and runs on Windows, macOS and Linux.
|
||||
|
||||
> Disclaimer: This tool is limited to security research only, and the user assumes all legal and related responsibilities arising from its use! The author assumes no legal responsibility!
|
||||
|
||||
@@ -103,7 +103,7 @@ Need install target OS's `gcc` library, here's an example of use `Mac` building
|
||||
```shell
|
||||
brew install mingw-w64
|
||||
|
||||
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC="x86_64-w64-mingw32-gcc" go build
|
||||
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc go build
|
||||
```
|
||||
|
||||
#### For Linux
|
||||
@@ -129,7 +129,7 @@ USAGE:
|
||||
Github Link: https://github.com/moonD4rk/HackBrowserData
|
||||
|
||||
VERSION:
|
||||
0.4.0
|
||||
0.4.1
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--verbose, --vv verbose (default: false)
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# HackBrowserData
|
||||
|
||||
`HackBrowserData` 是一个浏览器数据(密码 | 历史记录 | Cookie | 书签 | 信用卡 | 下载记录)的导出工具,支持全平台主流浏览器。
|
||||
`HackBrowserData` 是一个浏览器数据(密码 | 历史记录 | Cookie | 书签 | 信用卡 | 下载记录|local Storage)的导出工具,支持全平台主流浏览器。
|
||||
|
||||
|
||||
> 免责声明:此工具仅限于安全研究,用户承担因使用此工具而导致的所有法律和相关责任!作者不承担任何法律责任!
|
||||
@@ -99,7 +99,7 @@ $ CGO_ENABLED=1 go build
|
||||
``` shell
|
||||
brew install mingw-w64
|
||||
|
||||
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC="x86_64-w64-mingw32-gcc" go build
|
||||
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc go build
|
||||
```
|
||||
|
||||
#### Linux
|
||||
@@ -124,7 +124,7 @@ USAGE:
|
||||
Github Link: https://github.com/moonD4rk/HackBrowserData
|
||||
|
||||
VERSION:
|
||||
0.4.0
|
||||
0.4.1
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--verbose, --vv verbose (default: false)
|
||||
|
||||
@@ -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.0",
|
||||
Version: "0.4.1",
|
||||
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"},
|
||||
@@ -49,7 +49,6 @@ func Execute() {
|
||||
browsers []browser.Browser
|
||||
err error
|
||||
)
|
||||
log.Debugf("browser: %s", browserName)
|
||||
browsers, err = browser.PickBrowser(browserName, profilePath)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
|
||||
@@ -9,7 +9,9 @@ require (
|
||||
github.com/gookit/slog v0.2.2-0.20220415153407-dd89ed7b0448
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/mattn/go-sqlite3 v1.14.9
|
||||
github.com/otiai10/copy v1.7.0
|
||||
github.com/ppacher/go-dbus-keyring v1.0.1
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/tidwall/gjson v1.9.3
|
||||
github.com/urfave/cli/v2 v2.4.0
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||
@@ -18,6 +20,7 @@ require (
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
|
||||
github.com/gookit/goutil v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
|
||||
@@ -4,11 +4,15 @@ github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 h1:ptTza/LLPmfRtmz77X+6J61Wyf5e1hz5xYMvRk/hkE4=
|
||||
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw=
|
||||
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
|
||||
@@ -16,6 +20,8 @@ github.com/gookit/goutil v0.5.0 h1:SrbfjqZ8iprxJOfKZVT0yGJ4/82afr4Qa0RQwON19I4=
|
||||
github.com/gookit/goutil v0.5.0/go.mod h1:pq1eTibwb2wN96jrci0xy7xogWzzo9CihOQJEAvz4yQ=
|
||||
github.com/gookit/slog v0.2.2-0.20220415153407-dd89ed7b0448 h1:7kNDAgYDAu/5X+PbFfzGToaKJiDcghKv7B4XOGosrPM=
|
||||
github.com/gookit/slog v0.2.2-0.20220415153407-dd89ed7b0448/go.mod h1:9Sh1Utw3LVG0kqN++ankdfrCVQ7yixKDL1+YrYvIulU=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
@@ -27,6 +33,18 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
|
||||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI=
|
||||
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/ppacher/go-dbus-keyring v1.0.1 h1:dM4dMfP5w9MxY+foFHCQiN7izEGpFdKr3tZeMGmvqD0=
|
||||
@@ -38,6 +56,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tidwall/gjson v1.9.3 h1:hqzS9wAHMO+KVBBkLxYdkEeeFHuqr95GfClRLKlgK0E=
|
||||
github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
@@ -56,7 +76,11 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+Wr
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd h1:zVFyTKZN/Q7mNRWSs1GOYnHM9NiFSJ54YVRsD0rNWT4=
|
||||
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -65,7 +89,14 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"hack-browser-data/internal/browingdata/creditcard"
|
||||
"hack-browser-data/internal/browingdata/download"
|
||||
"hack-browser-data/internal/browingdata/history"
|
||||
"hack-browser-data/internal/browingdata/localstorage"
|
||||
"hack-browser-data/internal/browingdata/password"
|
||||
"hack-browser-data/internal/item"
|
||||
"hack-browser-data/internal/log"
|
||||
@@ -15,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
Sources map[item.Item]Source
|
||||
sources map[item.Item]Source
|
||||
}
|
||||
|
||||
type Source interface {
|
||||
@@ -26,7 +27,7 @@ type Source interface {
|
||||
|
||||
func New(sources []item.Item) *Data {
|
||||
bd := &Data{
|
||||
Sources: make(map[item.Item]Source),
|
||||
sources: make(map[item.Item]Source),
|
||||
}
|
||||
bd.addSource(sources)
|
||||
return bd
|
||||
@@ -34,9 +35,9 @@ func New(sources []item.Item) *Data {
|
||||
|
||||
func (d *Data) Recovery(masterKey []byte) error {
|
||||
|
||||
for _, source := range d.Sources {
|
||||
for _, source := range d.sources {
|
||||
if err := source.Parse(masterKey); err != nil {
|
||||
log.Error(err)
|
||||
log.Errorf("parse %s error %s", source.Name(), err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -45,16 +46,16 @@ func (d *Data) Recovery(masterKey []byte) error {
|
||||
func (d *Data) Output(dir, browserName, flag string) {
|
||||
output := NewOutPutter(flag)
|
||||
|
||||
for _, source := range d.Sources {
|
||||
for _, source := range d.sources {
|
||||
|
||||
filename := fileutil.Filename(browserName, source.Name(), output.Ext())
|
||||
|
||||
f, err := output.CreateFile(dir, filename)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Errorf("create file error %s", err)
|
||||
}
|
||||
if err := output.Write(source, f); err != nil {
|
||||
log.Error(err)
|
||||
log.Errorf("%s write to file %s error %s", source.Name(), filename, err.Error())
|
||||
}
|
||||
log.Noticef("output to file %s success", path.Join(dir, filename))
|
||||
}
|
||||
@@ -64,31 +65,35 @@ func (d *Data) addSource(Sources []item.Item) {
|
||||
for _, source := range Sources {
|
||||
switch source {
|
||||
case item.ChromiumPassword:
|
||||
d.Sources[source] = &password.ChromiumPassword{}
|
||||
d.sources[source] = &password.ChromiumPassword{}
|
||||
case item.ChromiumCookie:
|
||||
d.Sources[source] = &cookie.ChromiumCookie{}
|
||||
d.sources[source] = &cookie.ChromiumCookie{}
|
||||
case item.ChromiumBookmark:
|
||||
d.Sources[source] = &bookmark.ChromiumBookmark{}
|
||||
d.sources[source] = &bookmark.ChromiumBookmark{}
|
||||
case item.ChromiumHistory:
|
||||
d.Sources[source] = &history.ChromiumHistory{}
|
||||
d.sources[source] = &history.ChromiumHistory{}
|
||||
case item.ChromiumDownload:
|
||||
d.Sources[source] = &download.ChromiumDownload{}
|
||||
d.sources[source] = &download.ChromiumDownload{}
|
||||
case item.ChromiumCreditCard:
|
||||
d.Sources[source] = &creditcard.ChromiumCreditCard{}
|
||||
d.sources[source] = &creditcard.ChromiumCreditCard{}
|
||||
case item.ChromiumLocalStorage:
|
||||
d.sources[source] = &localstorage.ChromiumLocalStorage{}
|
||||
case item.YandexPassword:
|
||||
d.Sources[source] = &password.YandexPassword{}
|
||||
d.sources[source] = &password.YandexPassword{}
|
||||
case item.YandexCreditCard:
|
||||
d.Sources[source] = &creditcard.YandexCreditCard{}
|
||||
d.sources[source] = &creditcard.YandexCreditCard{}
|
||||
case item.FirefoxPassword:
|
||||
d.Sources[source] = &password.FirefoxPassword{}
|
||||
d.sources[source] = &password.FirefoxPassword{}
|
||||
case item.FirefoxCookie:
|
||||
d.Sources[source] = &cookie.FirefoxCookie{}
|
||||
d.sources[source] = &cookie.FirefoxCookie{}
|
||||
case item.FirefoxBookmark:
|
||||
d.Sources[source] = &bookmark.FirefoxBookmark{}
|
||||
d.sources[source] = &bookmark.FirefoxBookmark{}
|
||||
case item.FirefoxHistory:
|
||||
d.Sources[source] = &history.FirefoxHistory{}
|
||||
d.sources[source] = &history.FirefoxHistory{}
|
||||
case item.FirefoxDownload:
|
||||
d.Sources[source] = &download.FirefoxDownload{}
|
||||
d.sources[source] = &download.FirefoxDownload{}
|
||||
case item.FirefoxLocalStorage:
|
||||
d.sources[source] = &localstorage.FirefoxLocalStorage{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package localstorage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
|
||||
"hack-browser-data/internal/item"
|
||||
"hack-browser-data/internal/log"
|
||||
"hack-browser-data/internal/utils/typeutil"
|
||||
)
|
||||
|
||||
type ChromiumLocalStorage []storage
|
||||
|
||||
type storage struct {
|
||||
IsMeta bool
|
||||
URL string
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
func (c *ChromiumLocalStorage) Parse(masterKey []byte) error {
|
||||
db, err := leveldb.OpenFile(item.TempChromiumLocalStorage, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(item.TempChromiumLocalStorage)
|
||||
// log.Info("parsing local storage now")
|
||||
defer db.Close()
|
||||
|
||||
iter := db.NewIterator(nil, nil)
|
||||
for iter.Next() {
|
||||
key := iter.Key()
|
||||
value := iter.Value()
|
||||
// don't parse value upper than 5kB
|
||||
if len(value) > 1024*5 {
|
||||
continue
|
||||
}
|
||||
var s = new(storage)
|
||||
s.fillKey(key)
|
||||
s.fillValue(value)
|
||||
// don't save meta data
|
||||
if s.IsMeta {
|
||||
continue
|
||||
}
|
||||
*c = append(*c, *s)
|
||||
}
|
||||
iter.Release()
|
||||
err = iter.Error()
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *ChromiumLocalStorage) Name() string {
|
||||
return "localStorage"
|
||||
}
|
||||
|
||||
func (s *storage) fillKey(b []byte) {
|
||||
keys := bytes.Split(b, []byte("\x00"))
|
||||
if len(keys) == 1 && bytes.HasPrefix(keys[0], []byte("META:")) {
|
||||
s.IsMeta = true
|
||||
s.fillMetaHeader(keys[0])
|
||||
}
|
||||
if len(keys) == 2 && bytes.HasPrefix(keys[0], []byte("_")) {
|
||||
s.fillHeader(keys[0], keys[1])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *storage) fillMetaHeader(b []byte) {
|
||||
s.URL = string(bytes.Trim(b, "META:"))
|
||||
}
|
||||
|
||||
func (s *storage) fillHeader(url, key []byte) {
|
||||
s.URL = string(bytes.Trim(url, "_"))
|
||||
s.Key = string(bytes.Trim(key, "\x01"))
|
||||
}
|
||||
|
||||
// fillValue fills value of the storage
|
||||
// TODO: support unicode charter
|
||||
func (s *storage) fillValue(b []byte) {
|
||||
t := fmt.Sprintf("%c", b)
|
||||
m := strings.NewReplacer(" ", "", "\x00", "", "\x01", "").Replace(t)
|
||||
s.Value = m
|
||||
}
|
||||
|
||||
type FirefoxLocalStorage []storage
|
||||
|
||||
const (
|
||||
queryFirefoxHistory = `SELECT originKey, key, value FROM webappsstore2`
|
||||
closeJournalMode = `PRAGMA journal_mode=off`
|
||||
)
|
||||
|
||||
func (f *FirefoxLocalStorage) Parse(masterKey []byte) error {
|
||||
db, err := sql.Open("sqlite3", item.TempFirefoxLocalStorage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(item.TempFirefoxLocalStorage)
|
||||
defer db.Close()
|
||||
_, err = db.Exec(closeJournalMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
rows, err := db.Query(queryFirefoxHistory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var (
|
||||
originKey, key, value string
|
||||
)
|
||||
if err = rows.Scan(&originKey, &key, &value); err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
var s = new(storage)
|
||||
s.fillFirefox(originKey, key, value)
|
||||
*f = append(*f, *s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *storage) fillFirefox(originKey, key, value string) {
|
||||
// originKey = moc.buhtig.:https:443
|
||||
p := strings.Split(originKey, ":")
|
||||
h := typeutil.Reverse([]byte(p[0]))
|
||||
if bytes.HasPrefix(h, []byte(".")) {
|
||||
h = h[1:]
|
||||
}
|
||||
if len(p) == 3 {
|
||||
s.URL = fmt.Sprintf("%s://%s:%s", p[1], string(h), p[2])
|
||||
}
|
||||
s.Key = key
|
||||
s.Value = value
|
||||
}
|
||||
|
||||
func (f *FirefoxLocalStorage) Name() string {
|
||||
return "localStorage"
|
||||
}
|
||||
@@ -46,12 +46,11 @@ func pickChromium(name, profile string) []Browser {
|
||||
log.Noticef("find browser %s success", b.Name())
|
||||
browsers = append(browsers, b)
|
||||
} else {
|
||||
// TODO: show which browser find failed
|
||||
if strings.Contains(err.Error(), "profile folder is not exist") {
|
||||
if err == chromium.ErrProfilePathNotFound {
|
||||
log.Errorf("find browser %s failed, profile folder is not exist, maybe not installed", v.name)
|
||||
continue
|
||||
} else {
|
||||
log.Errorf("new chromium error:", err)
|
||||
log.Errorf("new chromium error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,10 +61,11 @@ func pickChromium(name, profile string) []Browser {
|
||||
}
|
||||
b, err := chromium.New(c.name, c.storage, profile, c.items)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "profile folder is not exist") {
|
||||
if err == chromium.ErrProfilePathNotFound {
|
||||
log.Fatalf("find browser %s failed, profile folder is not exist, maybe not installed", c.name)
|
||||
} else {
|
||||
log.Fatalf("new chromium error:", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
browsers = append(browsers, b)
|
||||
@@ -89,13 +89,12 @@ func pickFirefox(name, profile string) []Browser {
|
||||
browsers = append(browsers, b)
|
||||
}
|
||||
} else {
|
||||
if strings.Contains(err.Error(), "profile folder is not exist") {
|
||||
if err == firefox.ErrProfilePathNotFound {
|
||||
log.Errorf("find browser firefox %s failed, profile folder is not exist", v.name)
|
||||
} else {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return browsers
|
||||
}
|
||||
@@ -128,9 +127,5 @@ const (
|
||||
coccocName = "CocCoc"
|
||||
yandexName = "Yandex"
|
||||
|
||||
firefoxName = "Firefox"
|
||||
firefoxBetaName = "Firefox Beta"
|
||||
firefoxDevName = "Firefox Dev"
|
||||
firefoxNightlyName = "Firefox Nightly"
|
||||
firefoxESRName = "Firefox ESR"
|
||||
firefoxName = "Firefox"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package chromium
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -22,6 +22,10 @@ type chromium struct {
|
||||
itemPaths map[item.Item]string
|
||||
}
|
||||
|
||||
var (
|
||||
ErrProfilePathNotFound = errors.New("profile path not found")
|
||||
)
|
||||
|
||||
// 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) {
|
||||
c := &chromium{
|
||||
@@ -30,7 +34,7 @@ func New(name, storage, profilePath string, items []item.Item) (*chromium, error
|
||||
}
|
||||
// TODO: Handle file path is not exist
|
||||
if !fileutil.FolderExists(profilePath) {
|
||||
return nil, fmt.Errorf("%s profile folder is not exist: %s", name, profilePath)
|
||||
return nil, ErrProfilePathNotFound
|
||||
}
|
||||
itemsPaths, err := c.getItemPath(profilePath, items)
|
||||
if err != nil {
|
||||
@@ -67,16 +71,21 @@ func (c *chromium) BrowsingData() (*browingdata.Data, error) {
|
||||
|
||||
func (c *chromium) copyItemToLocal() error {
|
||||
for i, path := range c.itemPaths {
|
||||
// var dstFilename = item.TempName()
|
||||
var filename = i.String()
|
||||
// TODO: Handle read file error
|
||||
d, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(filename, d, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
if fileutil.FolderExists(path) {
|
||||
if err := fileutil.CopyDir(path, i.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
var filename = i.String()
|
||||
// TODO: Handle read file error
|
||||
d, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(filename, d, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -87,7 +96,11 @@ func (c *chromium) getItemPath(profilePath string, items []item.Item) (map[item.
|
||||
parentDir := fileutil.ParentDir(profilePath)
|
||||
baseDir := fileutil.BaseDir(profilePath)
|
||||
err := filepath.Walk(parentDir, chromiumWalkFunc(items, itemPaths, baseDir))
|
||||
return itemPaths, err
|
||||
if err != nil {
|
||||
return itemPaths, err
|
||||
}
|
||||
fillLocalStoragePath(itemPaths, item.ChromiumLocalStorage)
|
||||
return itemPaths, nil
|
||||
}
|
||||
|
||||
func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string, baseDir string) filepath.WalkFunc {
|
||||
@@ -106,3 +119,12 @@ func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string, baseDir
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func fillLocalStoragePath(itemPaths map[item.Item]string, storage item.Item) {
|
||||
if p, ok := itemPaths[item.ChromiumHistory]; ok {
|
||||
lsp := filepath.Join(filepath.Dir(p), storage.FileName())
|
||||
if fileutil.FolderExists(lsp) {
|
||||
itemPaths[item.ChromiumLocalStorage] = lsp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package firefox
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"hack-browser-data/internal/browingdata"
|
||||
"hack-browser-data/internal/item"
|
||||
"hack-browser-data/internal/log"
|
||||
"hack-browser-data/internal/utils/fileutil"
|
||||
"hack-browser-data/internal/utils/typeutil"
|
||||
)
|
||||
@@ -23,10 +22,14 @@ type firefox struct {
|
||||
itemPaths map[item.Item]string
|
||||
}
|
||||
|
||||
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) {
|
||||
if !fileutil.FolderExists(profilePath) {
|
||||
return nil, fmt.Errorf("%s profile folder is not exist: %s", name, profilePath)
|
||||
return nil, ErrProfilePathNotFound
|
||||
}
|
||||
f := &firefox{
|
||||
name: name,
|
||||
@@ -36,10 +39,6 @@ func New(name, storage, profilePath string, items []item.Item) ([]*firefox, erro
|
||||
}
|
||||
multiItemPaths, err := f.getMultiItemPath(f.profilePath, f.items)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "profile folder is not exist") {
|
||||
log.Error(err)
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var firefoxList []*firefox
|
||||
|
||||
@@ -9,15 +9,16 @@ const (
|
||||
fileChromiumDownload = "History"
|
||||
fileChromiumCookie = "Cookies"
|
||||
fileChromiumBookmark = "Bookmarks"
|
||||
fileChromiumLocalStorage = "chromiumLocalStorage"
|
||||
fileChromiumLocalStorage = "Local Storage/leveldb"
|
||||
|
||||
fileYandexPassword = "Ya Passman Data"
|
||||
fileYandexCredit = "Ya Credit Cards"
|
||||
|
||||
fileFirefoxKey4 = "key4.db"
|
||||
fileFirefoxCookie = "cookies.sqlite"
|
||||
fileFirefoxPassword = "logins.json"
|
||||
fileFirefoxData = "places.sqlite"
|
||||
fileFirefoxKey4 = "key4.db"
|
||||
fileFirefoxCookie = "cookies.sqlite"
|
||||
fileFirefoxPassword = "logins.json"
|
||||
fileFirefoxData = "places.sqlite"
|
||||
fileFirefoxLocalStorage = "webappsstore.sqlite"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -45,7 +46,7 @@ const (
|
||||
TempFirefoxBookmark = "firefoxBookmark"
|
||||
TempFirefoxHistory = "firefoxHistory"
|
||||
TempFirefoxDownload = "firefoxDownload"
|
||||
TempFirefoxLocalStorage = "firefoxLocalStorage"
|
||||
TempFirefoxCreditCard = ""
|
||||
TempFirefoxLocalStorage = ""
|
||||
TempFirefoxExtension = ""
|
||||
)
|
||||
|
||||
@@ -62,7 +62,7 @@ func (i Item) FileName() string {
|
||||
case FirefoxDownload:
|
||||
return fileFirefoxData
|
||||
case FirefoxLocalStorage:
|
||||
return UnsupportedItem
|
||||
return fileFirefoxLocalStorage
|
||||
case FirefoxCreditCard:
|
||||
return UnsupportedItem
|
||||
case FirefoxHistory:
|
||||
@@ -111,7 +111,7 @@ func (i Item) String() string {
|
||||
case FirefoxHistory:
|
||||
return TempFirefoxHistory
|
||||
case FirefoxLocalStorage:
|
||||
return UnsupportedItem
|
||||
return TempFirefoxLocalStorage
|
||||
case FirefoxCreditCard:
|
||||
return UnsupportedItem
|
||||
case FirefoxExtension:
|
||||
@@ -139,9 +139,9 @@ var DefaultYandex = []Item{
|
||||
ChromiumBookmark,
|
||||
ChromiumHistory,
|
||||
ChromiumDownload,
|
||||
ChromiumLocalStorage,
|
||||
ChromiumExtension,
|
||||
YandexPassword,
|
||||
ChromiumLocalStorage,
|
||||
YandexCreditCard,
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,9 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"hack-browser-data/internal/item"
|
||||
"hack-browser-data/internal/log"
|
||||
|
||||
cp "github.com/otiai10/copy"
|
||||
)
|
||||
|
||||
// FileExists checks if the file exists in the provided path
|
||||
@@ -44,22 +45,8 @@ func ReadFile(filename string) (string, error) {
|
||||
return string(s), err
|
||||
}
|
||||
|
||||
// CopyItemToLocal copies the file from the provided path to the local path
|
||||
func CopyItemToLocal(itemPaths map[item.Item]string) error {
|
||||
for i, p := range itemPaths {
|
||||
// var dstFilename = item.TempName()
|
||||
var filename = i.String()
|
||||
// TODO: Handle read file error
|
||||
d, err := ioutil.ReadFile(p)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
err = ioutil.WriteFile(filename, d, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func CopyDir(src, dst string) error {
|
||||
return cp.Copy(src, dst)
|
||||
}
|
||||
|
||||
func Filename(browser, item, ext string) string {
|
||||
@@ -68,7 +55,7 @@ func Filename(browser, item, ext string) string {
|
||||
}
|
||||
|
||||
func ParentDir(p string) string {
|
||||
return filepath.Dir(p)
|
||||
return filepath.Dir(filepath.Clean(p))
|
||||
}
|
||||
|
||||
func BaseDir(p string) string {
|
||||
|
||||
@@ -23,6 +23,14 @@ func IntToBool[T constraints.Signed](a T) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func Reverse[T any](s []T) []T {
|
||||
var h = make([]T, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
h[i] = s[len(s)-i-1]
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func TimeStamp(stamp int64) time.Time {
|
||||
s := time.Unix(stamp, 0)
|
||||
if s.Local().Year() > 9999 {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package typeutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
reverseTestCases = [][]any{
|
||||
[]any{1, 2, 3, 4, 5},
|
||||
[]any{"1", "2", "3", "4", "5"},
|
||||
[]any{"1", 2, "3", "4", 5},
|
||||
}
|
||||
)
|
||||
|
||||
func TestReverse(t *testing.T) {
|
||||
for _, ts := range reverseTestCases {
|
||||
h := Reverse(ts)
|
||||
for i := 0; i < len(ts); i++ {
|
||||
if h[len(h)-i-1] != ts[i] {
|
||||
t.Errorf("reverse failed %v != %v", h, ts)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user