Skip to content

Commit

Permalink
feat: 添加敏感信息导出功能
Browse files Browse the repository at this point in the history
  • Loading branch information
Ackites committed Aug 24, 2024
1 parent f6c5c19 commit d9293bd
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 5 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
- [x] Hook小程序,动态调试,开启小程序F12
- [x] 重新打包wxapkg,可破解小程序
- [x] 监听将要打包的文件夹,并自动打包
- [x] 敏感数据导出
- [ ] 支持小游戏
- [ ] 敏感数据导出

### 工程结构还原

Expand Down Expand Up @@ -130,7 +130,7 @@
## 用法

> -id=<输入AppID> -in=<输入文件1,输入文件2> 或 -in=<输入目录> -out=<输出目录>
> [-ext=<文件后缀>] [-restore] [-pretty] [-noClean] [-help] [-hook] [-save] [-repack=<输入目录>] [-watch]
> [-ext=<文件后缀>] [-restore] [-pretty] [-noClean] [-help] [-hook] [-save] [-repack=<输入目录>] [-watch] [-sensitive]
### 参数说明
- `-id string`
Expand Down Expand Up @@ -165,6 +165,8 @@
- **注意:目前仅支持一次打包一个文件,同时仅支持未被解析的源文件(未使用-restore)**
- `-watch`
- 是否监听将要打包的文件夹,并自动打包,默认不监听
- `-sensitive`
- 是否导出敏感数据,默认不导出
- `-help`
- 显示帮助信息

Expand Down
3 changes: 2 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/Ackites/KillWxapkg/internal/restore"
)

func Execute(appID, input, outputDir, fileExt string, restoreDir bool, pretty bool, noClean bool, save bool) {
func Execute(appID, input, outputDir, fileExt string, restoreDir bool, pretty bool, noClean bool, save bool, sensitive bool) {
// 存储配置
configManager := NewSharedConfigManager()
configManager.Set("appID", appID)
Expand All @@ -20,6 +20,7 @@ func Execute(appID, input, outputDir, fileExt string, restoreDir bool, pretty bo
configManager.Set("pretty", pretty)
configManager.Set("noClean", noClean)
configManager.Set("save", save)
configManager.Set("sensitive", sensitive)

inputFiles := ParseInput(input, fileExt)

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
golang.org/x/crypto v0.26.0
golang.org/x/net v0.28.0
golang.org/x/text v0.17.0
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,9 @@ golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
101 changes: 101 additions & 0 deletions internal/key/key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package key

import (
"fmt"
"os"
"path/filepath"

"gopkg.in/yaml.v3"
)

type Rule struct {
Id string `yaml:"id"`
Enabled bool `yaml:"enabled"`
Pattern string `yaml:"pattern"`
}

type Rules struct {
Rules []Rule `yaml:"rules"`
}

func init() {
configDir := "config"
configFile := filepath.Join(configDir, "rule.yaml")

if _, err := os.Stat(configFile); os.IsNotExist(err) {
if err := os.MkdirAll(configDir, 0755); err != nil {
fmt.Printf("Error creating config directory: %v\n", err)
return
}
CreateConfigFile()
}
}

func ReadRuleFile() (*Rules, error) {
configFile := filepath.Join("config", "rule.yaml")
file, err := os.ReadFile(configFile)
if err != nil {
return nil, fmt.Errorf("error reading rule file: %v", err)
}

var rules Rules
if err := yaml.Unmarshal(file, &rules); err != nil {
return nil, fmt.Errorf("error unmarshalling rule file: %v", err)
}

return &rules, nil
}

func CreateConfigFile() {
configFile := filepath.Join("config", "rule.yaml")
defaultRules := Rules{
Rules: []Rule{
{Id: "domain", Enabled: false, Pattern: ""},
{Id: "path", Enabled: false, Pattern: ""},
{Id: "domain_url", Enabled: false, Pattern: ""},
{Id: "ip", Enabled: false, Pattern: ""},
{Id: "ip_url", Enabled: false, Pattern: `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`},
{Id: "email", Enabled: true, Pattern: `\b[A-Za-z0-9._\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,61}\b`},
{Id: "id_card", Enabled: true, Pattern: `\b([1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])\b`},
{Id: "phone", Enabled: true, Pattern: `\b1[3-9]\d{9}\b`},
{Id: "jwt_token", Enabled: true, Pattern: `eyJ[A-Za-z0-9_/+\-]{10,}={0,2}\.[A-Za-z0-9_/+\-\\]{15,}={0,2}\.[A-Za-z0-9_/+\-\\]{10,}={0,2}`},
{Id: "Aliyun_AK_ID", Enabled: true, Pattern: `\bLTAI[A-Za-z\d]{12,30}\b`},
{Id: "QCloud_AK_ID", Enabled: true, Pattern: `\bAKID[A-Za-z\d]{13,40}\b`},
{Id: "JDCloud_AK_ID", Enabled: true, Pattern: `\bJDC_[0-9A-Z]{25,40}\b`},
{Id: "AWS_AK_ID", Enabled: true, Pattern: `["''](?:A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}["'']`},
{Id: "VolcanoEngine_AK_ID", Enabled: true, Pattern: `\b(?:AKLT|AKTP)[a-zA-Z0-9]{35,50}\b`},
{Id: "Kingsoft_AK_ID", Enabled: true, Pattern: `\bAKLT[a-zA-Z0-9-_]{16,28}\b`},
{Id: "GCP_AK_ID", Enabled: true, Pattern: `\bAIza[0-9A-Za-z_\-]{35}\b`},
{Id: "secret_key", Enabled: true, Pattern: ""},
{Id: "bearer_token", Enabled: true, Pattern: `\b[Bb]earer\s+[a-zA-Z0-9\-=._+/\\]{20,500}\b`},
{Id: "basic_token", Enabled: true, Pattern: `\b[Bb]asic\s+[A-Za-z0-9+/]{18,}={0,2}\b`},
{Id: "auth_token", Enabled: true, Pattern: `["''\[]*[Aa]uthorization["''\]]*\s*[:=]\s*[''"]?\b(?:[Tt]oken\s+)?[a-zA-Z0-9\-_+/]{20,500}[''"]?`},
{Id: "private_key", Enabled: true, Pattern: `-----\s*?BEGIN[ A-Z0-9_-]*?PRIVATE KEY\s*?-----[a-zA-Z0-9\/\n\r=+]*-----\s*?END[ A-Z0-9_-]*? PRIVATE KEY\s*?-----`},
{Id: "gitlab_v2_token", Enabled: true, Pattern: `\b(glpat-[a-zA-Z0-9\-=_]{20,22})\b`},
{Id: "github_token", Enabled: true, Pattern: `\b((?:ghp|gho|ghu|ghs|ghr|github_pat)_[a-zA-Z0-9_]{36,255})\b`},
{Id: "qcloud_api_gateway_appkey", Enabled: true, Pattern: `\bAPID[a-zA-Z0-9]{32,42}\b`},
{Id: "wechat_appid", Enabled: true, Pattern: `["''](wx[a-z0-9]{15,18})["'']`},
{Id: "wechat_corpid", Enabled: true, Pattern: `["''](ww[a-z0-9]{15,18})["'']`},
{Id: "wechat_id", Enabled: true, Pattern: `["''](gh_[a-z0-9]{11,13})["'']`},
{Id: "password", Enabled: true, Pattern: `(?i)(?:admin_?pass|password|[a-z]{3,15}_?password|user_?pass|user_?pwd|admin_?pwd)\\?['"]*\s*[:=]\s*\\?['"][a-z0-9!@#$%&*]{5,50}\\?['"]`},
{Id: "wechat_webhookurl", Enabled: true, Pattern: `\bhttps://qyapi.weixin.qq.com/cgi-bin/webhook/send\?key=[a-zA-Z0-9\-]{25,50}\b`},
{Id: "dingtalk_webhookurl", Enabled: true, Pattern: `\bhttps://oapi.dingtalk.com/robot/send\?access_token=[a-z0-9]{50,80}\b`},
{Id: "feishu_webhookurl", Enabled: true, Pattern: `\bhttps://open.feishu.cn/open-apis/bot/v2/hook/[a-z0-9\-]{25,50}\b`},
{Id: "slack_webhookurl", Enabled: true, Pattern: `\bhttps://hooks.slack.com/services/[a-zA-Z0-9\-_]{6,12}/[a-zA-Z0-9\-_]{6,12}/[a-zA-Z0-9\-_]{15,24}\b`},
{Id: "grafana_api_key", Enabled: true, Pattern: `\beyJrIjoi[a-zA-Z0-9\-_+/]{50,100}={0,2}\b`},
{Id: "grafana_cloud_api_token", Enabled: true, Pattern: `\bglc_[A-Za-z0-9\-_+/]{32,200}={0,2}\b`},
{Id: "grafana_service_account_token", Enabled: true, Pattern: `\bglsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8}\b`},
{Id: "app_key", Enabled: true, Pattern: `\b(?:VUE|APP|REACT)_[A-Z_0-9]{1,15}_(?:KEY|PASS|PASSWORD|TOKEN|APIKEY)['"]*[:=]"(?:[A-Za-z0-9_\-]{15,50}|[a-z0-9/+]{50,100}==?)"`},
},
}

data, err := yaml.Marshal(&defaultRules)
if err != nil {
fmt.Printf("Error marshalling default rules: %v\n", err)
return
}

if err := os.WriteFile(configFile, data, 0755); err != nil {
fmt.Printf("Error writing default rule file: %v\n", err)
}
}
82 changes: 82 additions & 0 deletions internal/key/match.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package key

import (
"encoding/json"
"fmt"
"os"
"regexp"
"strings"
"sync"
)

var (
rulesInstance *Rules
once sync.Once
jsonMutex sync.Mutex
)

func getRulesInstance() (*Rules, error) {
var err error
once.Do(func() {
rulesInstance, err = ReadRuleFile()
})
return rulesInstance, err
}

func MatchRules(input string) error {
rules, err := getRulesInstance()
if err != nil {
return fmt.Errorf("%v", err)
}

for _, rule := range rules.Rules {
if rule.Enabled {
re, err := regexp.Compile(rule.Pattern)
if err != nil {
return fmt.Errorf("failed to compile regex for rule %s: %v", rule.Id, err)
}
matches := re.FindAllStringSubmatch(input, -1)
for _, match := range matches {
if len(match) > 0 {
if strings.TrimSpace(match[0]) == "" {
continue
}
err := appendToJSON(rule.Id, match[0])
if err != nil {
return fmt.Errorf("failed to append to JSON: %v", err)
}
}
}
}
}

return nil
}

func appendToJSON(ruleId, matchedContent string) error {
jsonMutex.Lock()
defer jsonMutex.Unlock()

file, err := os.OpenFile("sensitive_data.json", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("failed to open JSON file: %v", err)
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
fmt.Printf("failed to close JSON file: %v", err)
}
}(file)

record := map[string]string{
"rule_id": ruleId,
"content": matchedContent,
}

encoder := json.NewEncoder(file)
if err := encoder.Encode(record); err != nil {
return fmt.Errorf("failed to write to JSON file: %v", err)
}

return nil
}
16 changes: 16 additions & 0 deletions internal/unpack/unpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
"path/filepath"
"sync"

"github.com/Ackites/KillWxapkg/internal/key"

"github.com/Ackites/KillWxapkg/internal/config"

formatter2 "github.com/Ackites/KillWxapkg/internal/formatter"
)

Expand Down Expand Up @@ -221,5 +225,17 @@ func processFile(outputDir string, file WxapkgFile, reader io.ReaderAt, bufferPo
return fmt.Errorf("写入文件失败: %w", err)
}

configManager := config.NewSharedConfigManager()
if sensitive, ok := configManager.Get("sensitive"); ok {
if p, o := sensitive.(bool); o {
if p {
// 查找敏感信息
if err := key.MatchRules(string(content)); err != nil {
return fmt.Errorf("%v", err)
}
}
}
}

return nil
}
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var (
save bool
repack string
watch bool
sensitive bool
)

func init() {
Expand All @@ -36,6 +37,7 @@ func init() {
flag.BoolVar(&save, "save", false, "是否保存解密后的文件")
flag.StringVar(&repack, "repack", "", "重新打包wxapkg文件")
flag.BoolVar(&watch, "watch", false, "是否监听将要打包的文件夹,并自动打包")
flag.BoolVar(&sensitive, "sensitive", false, "是否获取敏感数据")
}

func main() {
Expand Down Expand Up @@ -67,12 +69,12 @@ func main() {
}

if appID == "" || input == "" {
fmt.Println("使用方法: program -id=<AppID> -in=<输入文件1,输入文件2> 或 -in=<输入目录> -out=<输出目录> [-ext=<文件后缀>] [-restore] [-pretty] [-noClean] [-hook] [-save] [-repack=<输入目录>] [-watch]")
fmt.Println("使用方法: program -id=<AppID> -in=<输入文件1,输入文件2> 或 -in=<输入目录> -out=<输出目录> [-ext=<文件后缀>] [-restore] [-pretty] [-noClean] [-hook] [-save] [-repack=<输入目录>] [-watch] [-sensitive]")
flag.PrintDefaults()
fmt.Println()
return
}

// 执行命令
cmd.Execute(appID, input, outputDir, fileExt, restoreDir, pretty, noClean, save)
cmd.Execute(appID, input, outputDir, fileExt, restoreDir, pretty, noClean, save, sensitive)
}

0 comments on commit d9293bd

Please sign in to comment.