feat: add error warp

pull/83/head
ᴍᴏᴏɴD4ʀᴋ 4 years ago
parent 86d8e7e16e
commit 31419dc003
  1. 15
      cmd/cmd.go
  2. 31
      core/common/common.go
  3. 2
      log/log.go
  4. 40
      main.go
  5. 20
      utils/utils.go
  6. 21
      utils/utils_darwin.go
  7. 1
      utils/utils_linux.go
  8. 110
      utils/utils_windows.go

@ -6,7 +6,6 @@ import (
"hack-browser-data/utils" "hack-browser-data/utils"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -34,14 +33,7 @@ func Execute() {
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
log.InitLog() log.InitLog()
utils.MakeDir(exportDir) utils.MakeDir(exportDir)
switch runtime.GOOS {
case "darwin":
err := utils.InitChromeKey()
if err != nil {
}
case "windows":
}
var fileList []string var fileList []string
switch exportData { switch exportData {
case "all": case "all":
@ -49,7 +41,11 @@ func Execute() {
case "password", "cookie", "history", "bookmark": case "password", "cookie", "history", "bookmark":
fileList = utils.GetDBPath(exportData) fileList = utils.GetDBPath(exportData)
default: default:
log.Fatal("choose one all|password|cookie|history|bookmark") log.Fatal("choose one from all|password|cookie|history|bookmark")
}
err := utils.InitChromeKey()
if err != nil {
panic(err)
} }
for _, v := range fileList { for _, v := range fileList {
@ -72,7 +68,6 @@ func Execute() {
log.Error(err) log.Error(err)
} }
} }
return nil return nil
}, },
} }

@ -47,18 +47,18 @@ type (
History []*History History []*History
} }
LoginData struct { LoginData struct {
UserName string `json:"user_name"` UserName string
encryptPass []byte EncryptPass []byte
Password string `json:"password"` Password string
LoginUrl string `json:"login_url"` LoginUrl string
CreateDate time.Time `json:"create_date"` CreateDate time.Time
} }
Bookmarks struct { Bookmarks struct {
ID string `json:"id"` ID string
DateAdded time.Time `json:"date_added"` DateAdded time.Time
URL string `json:"url"` URL string
Name string `json:"name"` Name string
Type string `json:"type"` Type string
} }
Cookies struct { Cookies struct {
KeyName string KeyName string
@ -262,14 +262,11 @@ func parseLogin() {
err = rows.Scan(&url, &username, &pwd, &create) err = rows.Scan(&url, &username, &pwd, &create)
login = &LoginData{ login = &LoginData{
UserName: username, UserName: username,
encryptPass: pwd, EncryptPass: pwd,
LoginUrl: url, LoginUrl: url,
CreateDate: utils.TimeEpochFormat(create), CreateDate: utils.TimeEpochFormat(create),
} }
if len(pwd) > 3 { password, err = utils.DecryptChromePass(pwd)
// remove prefix 'v10'
password, err = utils.Aes128CBCDecrypt(pwd[3:])
}
login.Password = password login.Password = password
if err != nil { if err != nil {
log.Println(err) log.Println(err)
@ -319,10 +316,8 @@ func parseCookie() {
CreateDate: utils.TimeEpochFormat(createDate), CreateDate: utils.TimeEpochFormat(createDate),
ExpireDate: utils.TimeEpochFormat(expireDate), ExpireDate: utils.TimeEpochFormat(expireDate),
} }
if len(encryptValue) > 3 {
// remove prefix 'v10' // remove prefix 'v10'
value, err = utils.Aes128CBCDecrypt(encryptValue[3:]) value, err = utils.DecryptChromePass(encryptValue)
}
cookies.Value = value cookies.Value = value
cookieList = append(cookieList, cookies) cookieList = append(cookieList, cookies)
} }

@ -43,7 +43,7 @@ func newCore(level string) zapcore.Core {
MessageKey: "msg", MessageKey: "msg",
StacktraceKey: "stacktrace", StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding, LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalColorLevelEncoder, EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder, EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder, // EncodeDuration: zapcore.SecondsDurationEncoder, //
EncodeCaller: zapcore.ShortCallerEncoder, EncodeCaller: zapcore.ShortCallerEncoder,

@ -1,49 +1,9 @@
package main package main
import ( import (
"encoding/json"
"fmt"
"hack-browser-data/cmd" "hack-browser-data/cmd"
"hack-browser-data/core/common"
"hack-browser-data/log"
"hack-browser-data/utils"
"path/filepath"
"runtime"
) )
func main() { func main() {
cmd.Execute() cmd.Execute()
} }
func parse() {
osName := runtime.GOOS
switch osName {
case "darwin":
err := utils.InitChromeKey()
if err != nil {
log.Println(err)
panic("init chrome key failed")
}
case "windows":
fmt.Println("Windows")
}
chromePath := utils.GetDBPath(utils.LoginData, utils.History, utils.Bookmarks, utils.Cookies)
for _, v := range chromePath {
dst := filepath.Base(v)
err := utils.CopyDB(v, dst)
if err != nil {
log.Println(err)
continue
}
common.ParseDB(dst)
}
fmt.Println("bookmarks", len(common.FullData.Bookmarks))
fmt.Println("cookies", len(common.FullData.Cookies))
fmt.Println("login data", len(common.FullData.LoginData))
fmt.Println("history", len(common.FullData.History))
d, err := json.MarshalIndent(common.FullData.Bookmarks, "", "\t")
err = utils.WriteFile("data.json", d)
if err != nil {
log.Println(err)
}
}

@ -1,6 +1,7 @@
package utils package utils
import ( import (
"errors"
"fmt" "fmt"
"hack-browser-data/log" "hack-browser-data/log"
"io/ioutil" "io/ioutil"
@ -11,6 +12,23 @@ import (
"time" "time"
) )
var (
passwordIsEmpty = errors.New("decrypt fail, password is empty")
)
type DecryptError struct {
err error
msg string
}
func (e *DecryptError) Error() string {
return fmt.Sprintf("%s: %s", e.msg, e.err)
}
func (e *DecryptError) Unwrap() error {
return e.err
}
const ( const (
LoginData = "Login Data" LoginData = "Login Data"
History = "History" History = "History"
@ -49,7 +67,7 @@ func IntToBool(a int) bool {
func TimeEpochFormat(epoch int64) time.Time { func TimeEpochFormat(epoch int64) time.Time {
maxTime := int64(99633311740000000) maxTime := int64(99633311740000000)
if epoch > maxTime{ if epoch > maxTime {
epoch = maxTime epoch = maxTime
} }
t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC) t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)

@ -6,6 +6,7 @@ import (
"crypto/cipher" "crypto/cipher"
"crypto/sha1" "crypto/sha1"
"errors" "errors"
"fmt"
"hack-browser-data/log" "hack-browser-data/log"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -22,7 +23,6 @@ var (
command = []string{"security", "find-generic-password", "-wa", "Chrome"} command = []string{"security", "find-generic-password", "-wa", "Chrome"}
chromeSalt = []byte("saltysalt") chromeSalt = []byte("saltysalt")
chromeKey []byte chromeKey []byte
chromePass []byte
) )
func GetDBPath(dbName ...string) (dbFile []string) { func GetDBPath(dbName ...string) (dbFile []string) {
@ -58,16 +58,27 @@ func InitChromeKey() error {
log.Println(err) log.Println(err)
} }
temp := stdout.Bytes() temp := stdout.Bytes()
chromePass = temp[:len(temp)-1] chromePass := temp[:len(temp)-1]
decryptPass(chromePass) decryptChromeKey(chromePass)
return err return err
} }
func decryptPass(chromePass []byte) { func decryptChromeKey(chromePass []byte) {
chromeKey = pbkdf2.Key(chromePass, chromeSalt, 1003, 16, sha1.New) chromeKey = pbkdf2.Key(chromePass, chromeSalt, 1003, 16, sha1.New)
} }
func Aes128CBCDecrypt(encryptPass []byte) (string, error) { func DecryptChromePass(encryptPass []byte) (string, error) {
if len(encryptPass) > 3 {
return aes128CBCDecrypt(encryptPass[3:])
} else {
return "", &DecryptError{
err: passwordIsEmpty,
msg: fmt.Sprintf("password is %s", string(encryptPass)),
}
}
}
func aes128CBCDecrypt(encryptPass []byte) (string, error) {
if len(chromeKey) == 0 { if len(chromeKey) == 0 {
return "", nil return "", nil
} }

@ -0,0 +1 @@
package utils

@ -1,26 +1,118 @@
package utils package utils
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"hack-browser-data/log"
"os"
"path/filepath"
"syscall"
"unsafe"
"github.com/tidwall/gjson"
)
const ( const (
winChromeDir = "/Users/*/Library/Application Support/Google/Chrome/*/" winChromeKeyDir = "/AppData/Local/Google/Chrome/User Data/Local State"
winChromeDir = "/AppData/Local/Google/Chrome/User Data/*/"
)
var (
chromeKey []byte
) )
func GetDBPath(dbName string) string { func InitChromeKey() error {
s, err := filepath.Glob(winChromeDir + dbName) chromeKeyPath := os.Getenv("USERPROFILE") + winChromeKeyDir
keyFile, err := ReadFile(chromeKeyPath)
if err != nil {
log.Error(err)
return err
}
s := gjson.Get(keyFile, "os_crypt.encrypted_key").String()
masterKey, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return err
}
chromeKey, err = decryptStringWithDPAPI(masterKey[5:])
return err
}
func GetDBPath(dbName ...string) (dbFile []string) {
var dbPath []string
chromeDBPath := os.Getenv("USERPROFILE") + winChromeDir
for _, v := range dbName {
dbPath = append(dbPath, chromeDBPath+v)
}
for _, v := range dbPath {
s, err := filepath.Glob(v)
if err != nil && len(s) == 0 { if err != nil && len(s) == 0 {
panic(err) continue
}
if len(s) > 0 {
log.Debugf("Find %s File Success", v)
log.Debugf("%s file location is %s", v, s[0])
dbFile = append(dbFile, s[0])
}
}
return dbFile
}
func DecryptChromePass(encryptPass []byte) (string, error) {
if len(encryptPass) > 15 {
// remove prefix 'v10'
return aesGCMDecrypt(encryptPass[15:], chromeKey, encryptPass[3:15])
} else {
return "", passwordIsEmpty
} }
return s[0]
} }
func AesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) { // chromium > 80 https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_win.cc
func aesGCMDecrypt(crypted, key, nounce []byte) (string, error) {
block, err := aes.NewCipher(key) block, err := aes.NewCipher(key)
if err != nil { if err != nil {
return nil, err return "", err
} }
blockMode, _ := cipher.NewGCM(block) blockMode, _ := cipher.NewGCM(block)
origData, err := blockMode.Open(nil, nounce, crypted, nil) origData, err := blockMode.Open(nil, nounce, crypted, nil)
if err != nil{ if err != nil {
return "", err
}
return string(origData), nil
}
type DataBlob struct {
cbData uint32
pbData *byte
}
func NewBlob(d []byte) *DataBlob {
if len(d) == 0 {
return &DataBlob{}
}
return &DataBlob{
pbData: &d[0],
cbData: uint32(len(d)),
}
}
func (b *DataBlob) ToByteArray() []byte {
d := make([]byte, b.cbData)
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
return d
}
// chrome < 80 https://chromium.googlesource.com/chromium/src/+/76f496a7235c3432983421402951d73905c8be96/components/os_crypt/os_crypt_win.cc#82
func decryptStringWithDPAPI(data []byte) ([]byte, error) {
dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
dllKernel := syscall.NewLazyDLL("Kernel32.dll")
procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
procLocalFree := dllKernel.NewProc("LocalFree")
var outBlob DataBlob
r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
if r == 0 {
return nil, err return nil, err
} }
return origData, nil defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
return outBlob.ToByteArray(), nil
} }

Loading…
Cancel
Save