Compare commits
2 Commits
fix/v4disp
...
feature/ms
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d92e974ce6 | ||
|
|
4250057ba8 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,5 +27,6 @@ go.work.sum
|
|||||||
# syncthing files
|
# syncthing files
|
||||||
.stfolder
|
.stfolder
|
||||||
|
|
||||||
|
chatlog
|
||||||
chatlog.exe# Added by goreleaser init:
|
chatlog.exe# Added by goreleaser init:
|
||||||
dist/
|
dist/
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
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)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -22,8 +22,6 @@ func initLog(cmd *cobra.Command, args []string) {
|
|||||||
if Debug {
|
if Debug {
|
||||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initTuiLog(cmd *cobra.Command, args []string) {
|
func initTuiLog(cmd *cobra.Command, args []string) {
|
||||||
|
|||||||
@@ -74,16 +74,6 @@ func (c *Context) SwitchHistory(account string) {
|
|||||||
c.WorkDir = history.WorkDir
|
c.WorkDir = history.WorkDir
|
||||||
c.HTTPEnabled = history.HTTPEnabled
|
c.HTTPEnabled = history.HTTPEnabled
|
||||||
c.HTTPAddr = history.HTTPAddr
|
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 = ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,17 +20,9 @@ func (c *ChatRoomV4) Wrap() *ChatRoom {
|
|||||||
users = ParseRoomData(c.ExtBuffer)
|
users = ParseRoomData(c.ExtBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
user2DisplayName := make(map[string]string, len(users))
|
|
||||||
for _, user := range users {
|
|
||||||
if user.DisplayName != "" {
|
|
||||||
user2DisplayName[user.UserName] = user.DisplayName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ChatRoom{
|
return &ChatRoom{
|
||||||
Name: c.UserName,
|
Name: c.UserName,
|
||||||
Owner: c.Owner,
|
Owner: c.Owner,
|
||||||
Users: users,
|
Users: users,
|
||||||
User2DisplayName: user2DisplayName,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,17 +15,13 @@ type Validator struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewValidator 创建一个仅用于验证的验证器
|
// NewValidator 创建一个仅用于验证的验证器
|
||||||
func NewValidator(platform string, version int, dataDir string) (*Validator, error) {
|
func NewValidator(dataDir string, platform string, version int) (*Validator, error) {
|
||||||
dbFile := GetSimpleDBFile(platform, version)
|
|
||||||
dbPath := filepath.Join(dataDir + "/" + dbFile)
|
|
||||||
return NewValidatorWithFile(platform, version, dbPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewValidatorWithFile(platform string, version int, dbPath string) (*Validator, error) {
|
|
||||||
decryptor, err := NewDecryptor(platform, version)
|
decryptor, err := NewDecryptor(platform, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
dbFile := GetSimpleDBFile(platform, version)
|
||||||
|
dbPath := filepath.Join(dataDir + "/" + dbFile)
|
||||||
d, err := common.OpenDBFile(dbPath, decryptor.GetPageSize())
|
d, err := common.OpenDBFile(dbPath, decryptor.GetPageSize())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -19,22 +19,12 @@ const (
|
|||||||
MaxWorkersV3 = 8
|
MaxWorkersV3 = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
var V3KeyPatterns = []KeyPatternInfo{
|
|
||||||
{
|
|
||||||
Pattern: []byte{0x72, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x69, 0x33, 0x32},
|
|
||||||
Offset: 24,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
type V3Extractor struct {
|
type V3Extractor struct {
|
||||||
validator *decrypt.Validator
|
validator *decrypt.Validator
|
||||||
keyPatterns []KeyPatternInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewV3Extractor() *V3Extractor {
|
func NewV3Extractor() *V3Extractor {
|
||||||
return &V3Extractor{
|
return &V3Extractor{}
|
||||||
keyPatterns: V3KeyPatterns,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *V3Extractor) Extract(ctx context.Context, proc *model.Process) (string, error) {
|
func (e *V3Extractor) Extract(ctx context.Context, proc *model.Process) (string, error) {
|
||||||
@@ -137,6 +127,7 @@ func (e *V3Extractor) findMemory(ctx context.Context, pid uint32, memoryChannel
|
|||||||
|
|
||||||
// worker processes memory regions to find V3 version key
|
// worker processes memory regions to find V3 version key
|
||||||
func (e *V3Extractor) worker(ctx context.Context, memoryChannel <-chan []byte, resultChannel chan<- string) {
|
func (e *V3Extractor) worker(ctx context.Context, memoryChannel <-chan []byte, resultChannel chan<- string) {
|
||||||
|
keyPattern := []byte{0x72, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x69, 0x33, 0x32}
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@@ -146,58 +137,49 @@ func (e *V3Extractor) worker(ctx context.Context, memoryChannel <-chan []byte, r
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if key, ok := e.SearchKey(ctx, memory); ok {
|
index := len(memory)
|
||||||
|
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case resultChannel <- key:
|
case <-ctx.Done():
|
||||||
|
return // Exit if context cancelled
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *V3Extractor) SearchKey(ctx context.Context, memory []byte) (string, bool) {
|
log.Debug().Msgf("Searching for V3 key in memory region, size: %d bytes", len(memory))
|
||||||
for _, keyPattern := range e.keyPatterns {
|
|
||||||
index := len(memory)
|
|
||||||
|
|
||||||
for {
|
// Find pattern from end to beginning
|
||||||
select {
|
index = bytes.LastIndex(memory[:index], keyPattern)
|
||||||
case <-ctx.Done():
|
if index == -1 {
|
||||||
return "", false
|
break // No more matches found
|
||||||
default:
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Find pattern from end to beginning
|
log.Debug().Msgf("Found potential V3 key pattern in memory region, index: %d", index)
|
||||||
index = bytes.LastIndex(memory[:index], keyPattern.Pattern)
|
|
||||||
if index == -1 {
|
// For V3, the key is 32 bytes and starts right after the pattern
|
||||||
break // No more matches found
|
if index+24+32 > len(memory) {
|
||||||
}
|
index -= 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the key data, which is right after the pattern and 32 bytes long
|
||||||
|
keyOffset := index + 24
|
||||||
|
keyData := memory[keyOffset : keyOffset+32]
|
||||||
|
|
||||||
|
// Validate key against database header
|
||||||
|
if e.validator.Validate(keyData) {
|
||||||
|
select {
|
||||||
|
case resultChannel <- hex.EncodeToString(keyData):
|
||||||
|
log.Debug().Msg("Key found: " + hex.EncodeToString(keyData))
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we have enough space for the key
|
|
||||||
keyOffset := index + keyPattern.Offset
|
|
||||||
if keyOffset < 0 || keyOffset+32 > len(memory) {
|
|
||||||
index -= 1
|
index -= 1
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the key data, which is 32 bytes long
|
|
||||||
keyData := memory[keyOffset : keyOffset+32]
|
|
||||||
|
|
||||||
// Validate key against database header
|
|
||||||
if e.validator.Validate(keyData) {
|
|
||||||
log.Debug().
|
|
||||||
Str("pattern", hex.EncodeToString(keyPattern.Pattern)).
|
|
||||||
Int("offset", keyPattern.Offset).
|
|
||||||
Str("key", hex.EncodeToString(keyData)).
|
|
||||||
Msg("Key found")
|
|
||||||
return hex.EncodeToString(keyData), true
|
|
||||||
}
|
|
||||||
|
|
||||||
index -= 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *V3Extractor) SetValidate(validator *decrypt.Validator) {
|
func (e *V3Extractor) SetValidate(validator *decrypt.Validator) {
|
||||||
|
|||||||
@@ -19,26 +19,12 @@ const (
|
|||||||
MaxWorkers = 8
|
MaxWorkers = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
var V4KeyPatterns = []KeyPatternInfo{
|
|
||||||
{
|
|
||||||
Pattern: []byte{0x20, 0x66, 0x74, 0x73, 0x35, 0x28, 0x25, 0x00},
|
|
||||||
Offset: 16,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pattern: []byte{0x20, 0x66, 0x74, 0x73, 0x35, 0x28, 0x25, 0x00},
|
|
||||||
Offset: -80,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
type V4Extractor struct {
|
type V4Extractor struct {
|
||||||
validator *decrypt.Validator
|
validator *decrypt.Validator
|
||||||
keyPatterns []KeyPatternInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewV4Extractor() *V4Extractor {
|
func NewV4Extractor() *V4Extractor {
|
||||||
return &V4Extractor{
|
return &V4Extractor{}
|
||||||
keyPatterns: V4KeyPatterns,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *V4Extractor) Extract(ctx context.Context, proc *model.Process) (string, error) {
|
func (e *V4Extractor) Extract(ctx context.Context, proc *model.Process) (string, error) {
|
||||||
@@ -141,6 +127,8 @@ func (e *V4Extractor) findMemory(ctx context.Context, pid uint32, memoryChannel
|
|||||||
|
|
||||||
// worker processes memory regions to find V4 version key
|
// worker processes memory regions to find V4 version key
|
||||||
func (e *V4Extractor) worker(ctx context.Context, memoryChannel <-chan []byte, resultChannel chan<- string) {
|
func (e *V4Extractor) worker(ctx context.Context, memoryChannel <-chan []byte, resultChannel chan<- string) {
|
||||||
|
keyPattern := []byte{0x20, 0x66, 0x74, 0x73, 0x35, 0x28, 0x25, 0x00}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@@ -150,65 +138,47 @@ func (e *V4Extractor) worker(ctx context.Context, memoryChannel <-chan []byte, r
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if key, ok := e.SearchKey(ctx, memory); ok {
|
index := len(memory)
|
||||||
|
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case resultChannel <- key:
|
case <-ctx.Done():
|
||||||
|
return // Exit if context cancelled
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *V4Extractor) SearchKey(ctx context.Context, memory []byte) (string, bool) {
|
// Find pattern from end to beginning
|
||||||
for _, keyPattern := range e.keyPatterns {
|
index = bytes.LastIndex(memory[:index], keyPattern)
|
||||||
index := len(memory)
|
if index == -1 {
|
||||||
|
break // No more matches found
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
// Check if we have enough space for the key
|
||||||
select {
|
if index+16+32 > len(memory) {
|
||||||
case <-ctx.Done():
|
index -= 1
|
||||||
return "", false
|
continue
|
||||||
default:
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Find pattern from end to beginning
|
// Extract the key data, which is 16 bytes after the pattern and 32 bytes long
|
||||||
index = bytes.LastIndex(memory[:index], keyPattern.Pattern)
|
keyOffset := index + 16
|
||||||
if index == -1 {
|
keyData := memory[keyOffset : keyOffset+32]
|
||||||
break // No more matches found
|
|
||||||
}
|
// Validate key against database header
|
||||||
|
if e.validator.Validate(keyData) {
|
||||||
|
select {
|
||||||
|
case resultChannel <- hex.EncodeToString(keyData):
|
||||||
|
log.Debug().Msg("Key found: " + hex.EncodeToString(keyData))
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we have enough space for the key
|
|
||||||
keyOffset := index + keyPattern.Offset
|
|
||||||
if keyOffset < 0 || keyOffset+32 > len(memory) {
|
|
||||||
index -= 1
|
index -= 1
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the key data, which is 16 bytes after the pattern and 32 bytes long
|
|
||||||
keyData := memory[keyOffset : keyOffset+32]
|
|
||||||
|
|
||||||
// Validate key against database header
|
|
||||||
if e.validator.Validate(keyData) {
|
|
||||||
log.Debug().
|
|
||||||
Str("pattern", hex.EncodeToString(keyPattern.Pattern)).
|
|
||||||
Int("offset", keyPattern.Offset).
|
|
||||||
Str("key", hex.EncodeToString(keyData)).
|
|
||||||
Msg("Key found")
|
|
||||||
return hex.EncodeToString(keyData), true
|
|
||||||
}
|
|
||||||
|
|
||||||
index -= 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *V4Extractor) SetValidate(validator *decrypt.Validator) {
|
func (e *V4Extractor) SetValidate(validator *decrypt.Validator) {
|
||||||
e.validator = validator
|
e.validator = validator
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyPatternInfo struct {
|
|
||||||
Pattern []byte
|
|
||||||
Offset int
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ type Extractor interface {
|
|||||||
// Extract 从进程中提取密钥
|
// Extract 从进程中提取密钥
|
||||||
Extract(ctx context.Context, proc *model.Process) (string, error)
|
Extract(ctx context.Context, proc *model.Process) (string, error)
|
||||||
|
|
||||||
// SearchKey 在内存中搜索密钥
|
|
||||||
SearchKey(ctx context.Context, memory []byte) (string, bool)
|
|
||||||
|
|
||||||
SetValidate(validator *decrypt.Validator)
|
SetValidate(validator *decrypt.Validator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package windows
|
package windows
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sjzar/chatlog/internal/wechat/decrypt"
|
"github.com/sjzar/chatlog/internal/wechat/decrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,11 +12,6 @@ func NewV3Extractor() *V3Extractor {
|
|||||||
return &V3Extractor{}
|
return &V3Extractor{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *V3Extractor) SearchKey(ctx context.Context, memory []byte) (string, bool) {
|
|
||||||
// TODO : Implement the key search logic for V3
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *V3Extractor) SetValidate(validator *decrypt.Validator) {
|
func (e *V3Extractor) SetValidate(validator *decrypt.Validator) {
|
||||||
e.validator = validator
|
e.validator = validator
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package windows
|
package windows
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sjzar/chatlog/internal/wechat/decrypt"
|
"github.com/sjzar/chatlog/internal/wechat/decrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,11 +12,6 @@ func NewV4Extractor() *V4Extractor {
|
|||||||
return &V4Extractor{}
|
return &V4Extractor{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *V4Extractor) SearchKey(ctx context.Context, memory []byte) (string, bool) {
|
|
||||||
// TODO : Implement the key search logic for V4
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *V4Extractor) SetValidate(validator *decrypt.Validator) {
|
func (e *V4Extractor) SetValidate(validator *decrypt.Validator) {
|
||||||
e.validator = validator
|
e.validator = validator
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProcessNameOfficial = "WeChat"
|
V3ProcessName = "WeChat"
|
||||||
ProcessNameBeta = "Weixin"
|
V4ProcessName = "Weixin"
|
||||||
V3DBFile = "Message/msg_0.db"
|
V3DBFile = "Message/msg_0.db"
|
||||||
V4DBFile = "db_storage/session/session.db"
|
V4DBFile = "db_storage/message/message_0.db"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Detector 实现 macOS 平台的进程检测器
|
// Detector 实现 macOS 平台的进程检测器
|
||||||
@@ -40,7 +40,7 @@ func (d *Detector) FindProcesses() ([]*model.Process, error) {
|
|||||||
var result []*model.Process
|
var result []*model.Process
|
||||||
for _, p := range processes {
|
for _, p := range processes {
|
||||||
name, err := p.Name()
|
name, err := p.Name()
|
||||||
if err != nil || (name != ProcessNameOfficial && name != ProcessNameBeta) {
|
if err != nil || (name != V3ProcessName && name != V4ProcessName) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ func (a *Account) GetKey(ctx context.Context) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
validator, err := decrypt.NewValidator(process.Platform, process.Version, process.DataDir)
|
validator, err := decrypt.NewValidator(process.DataDir, process.Platform, process.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user