Compare commits
2 Commits
feature/da
...
v0.0.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b64902ecb6 | ||
|
|
dc116c50bf |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,6 +27,5 @@ go.work.sum
|
||||
# syncthing files
|
||||
.stfolder
|
||||
|
||||
chatlog
|
||||
chatlog.exe# Added by goreleaser init:
|
||||
dist/
|
||||
|
||||
146
cmd/chatlog/cmd_dumpmemory.go
Normal file
146
cmd/chatlog/cmd_dumpmemory.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package chatlog
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/wechat"
|
||||
"github.com/sjzar/chatlog/internal/wechat/key/darwin/glance"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(dumpmemoryCmd)
|
||||
}
|
||||
|
||||
var dumpmemoryCmd = &cobra.Command{
|
||||
Use: "dumpmemory",
|
||||
Short: "dump memory",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if runtime.GOOS != "darwin" {
|
||||
log.Info().Msg("dump memory only support macOS")
|
||||
}
|
||||
|
||||
session := time.Now().Format("20060102150405")
|
||||
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("get current directory failed")
|
||||
return
|
||||
}
|
||||
log.Info().Msgf("current directory: %s", dir)
|
||||
|
||||
// step 1. check pid
|
||||
if err = wechat.Load(); err != nil {
|
||||
log.Fatal().Err(err).Msg("load wechat failed")
|
||||
return
|
||||
}
|
||||
accounts := wechat.GetAccounts()
|
||||
if len(accounts) == 0 {
|
||||
log.Fatal().Msg("no wechat account found")
|
||||
return
|
||||
}
|
||||
|
||||
log.Info().Msgf("found %d wechat account", len(accounts))
|
||||
for i, a := range accounts {
|
||||
log.Info().Msgf("%d. %s %d %s", i, a.FullVersion, a.PID, a.DataDir)
|
||||
}
|
||||
|
||||
// step 2. dump memory
|
||||
account := accounts[0]
|
||||
file := fmt.Sprintf("wechat_%s_%d_%s.bin", account.FullVersion, account.PID, session)
|
||||
path := filepath.Join(dir, file)
|
||||
log.Info().Msgf("dumping memory to %s", path)
|
||||
|
||||
g := glance.NewGlance(account.PID)
|
||||
b, err := g.Read()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("read memory failed")
|
||||
return
|
||||
}
|
||||
|
||||
if err = os.WriteFile(path, b, 0644); err != nil {
|
||||
log.Fatal().Err(err).Msg("write memory failed")
|
||||
return
|
||||
}
|
||||
|
||||
log.Info().Msg("dump memory success")
|
||||
|
||||
// step 3. copy encrypted database file
|
||||
dbFile := "db_storage/session/session.db"
|
||||
if account.Version == 3 {
|
||||
dbFile = "Session/session_new.db"
|
||||
}
|
||||
from := filepath.Join(account.DataDir, dbFile)
|
||||
to := filepath.Join(dir, fmt.Sprintf("wechat_%s_%d_session.db", account.FullVersion, account.PID))
|
||||
|
||||
log.Info().Msgf("copying %s to %s", from, to)
|
||||
b, err = os.ReadFile(from)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("read session.db failed")
|
||||
return
|
||||
}
|
||||
if err = os.WriteFile(to, b, 0644); err != nil {
|
||||
log.Fatal().Err(err).Msg("write session.db failed")
|
||||
return
|
||||
}
|
||||
log.Info().Msg("copy session.db success")
|
||||
|
||||
// step 4. package
|
||||
zipFile := fmt.Sprintf("wechat_%s_%d_%s.zip", account.FullVersion, account.PID, session)
|
||||
zipPath := filepath.Join(dir, zipFile)
|
||||
log.Info().Msgf("packaging to %s", zipPath)
|
||||
|
||||
zf, err := os.Create(zipPath)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("create zip file failed")
|
||||
return
|
||||
}
|
||||
defer zf.Close()
|
||||
|
||||
zw := zip.NewWriter(zf)
|
||||
|
||||
for _, file := range []string{file, to} {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("open file failed")
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
info, err := f.Stat()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("get file info failed")
|
||||
return
|
||||
}
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("create zip file info header failed")
|
||||
return
|
||||
}
|
||||
header.Name = filepath.Base(file)
|
||||
header.Method = zip.Deflate
|
||||
writer, err := zw.CreateHeader(header)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("create zip file header failed")
|
||||
return
|
||||
}
|
||||
if _, err = io.Copy(writer, f); err != nil {
|
||||
log.Fatal().Err(err).Msg("copy file to zip failed")
|
||||
return
|
||||
}
|
||||
}
|
||||
if err = zw.Close(); err != nil {
|
||||
log.Fatal().Err(err).Msg("close zip writer failed")
|
||||
return
|
||||
}
|
||||
|
||||
log.Info().Msgf("package success, please send %s to developer", zipPath)
|
||||
},
|
||||
}
|
||||
@@ -74,6 +74,16 @@ func (c *Context) SwitchHistory(account string) {
|
||||
c.WorkDir = history.WorkDir
|
||||
c.HTTPEnabled = history.HTTPEnabled
|
||||
c.HTTPAddr = history.HTTPAddr
|
||||
} else {
|
||||
c.Account = ""
|
||||
c.Platform = ""
|
||||
c.Version = 0
|
||||
c.FullVersion = ""
|
||||
c.DataKey = ""
|
||||
c.DataDir = ""
|
||||
c.WorkDir = ""
|
||||
c.HTTPEnabled = false
|
||||
c.HTTPAddr = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
V3ProcessName = "WeChat"
|
||||
V4ProcessName = "Weixin"
|
||||
V3DBFile = "Message/msg_0.db"
|
||||
V4DBFile = "db_storage/message/message_0.db"
|
||||
ProcessNameOfficial = "WeChat"
|
||||
ProcessNameBeta = "Weixin"
|
||||
V3DBFile = "Message/msg_0.db"
|
||||
V4DBFile = "db_storage/session/session.db"
|
||||
)
|
||||
|
||||
// Detector 实现 macOS 平台的进程检测器
|
||||
@@ -40,7 +40,7 @@ func (d *Detector) FindProcesses() ([]*model.Process, error) {
|
||||
var result []*model.Process
|
||||
for _, p := range processes {
|
||||
name, err := p.Name()
|
||||
if err != nil || (name != V3ProcessName && name != V4ProcessName) {
|
||||
if err != nil || (name != ProcessNameOfficial && name != ProcessNameBeta) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user