├── README.md ├── WxDump.exe ├── comm ├── Getinfo.go ├── Getinfo_Wxfile.go ├── Getinfo_Wxid.go ├── Getinfo_Wxinfo.go ├── Getinfo_Wxkey.go ├── ModuleDeal.go ├── PackageToZip.go ├── WX_OFFS.json ├── Wxdecrypto.go └── config.go ├── go.mod ├── go.sum ├── img.png ├── img_1.png ├── img_2.png └── main.go /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmluZw/WxDump/339d4a47f03e43b2e244430d2c24b4bc3d035719/README.md -------------------------------------------------------------------------------- /WxDump.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmluZw/WxDump/339d4a47f03e43b2e244430d2c24b4bc3d035719/WxDump.exe -------------------------------------------------------------------------------- /comm/Getinfo.go: -------------------------------------------------------------------------------- 1 | package comm 2 | -------------------------------------------------------------------------------- /comm/Getinfo_Wxfile.go: -------------------------------------------------------------------------------- 1 | package comm 2 | 3 | //V1.0.0 4 | //By cmluZw 2024-08-12 5 | 6 | import ( 7 | "io/ioutil" 8 | "os" 9 | "path/filepath" 10 | "runtime" 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | // 获取微信文件路径 16 | func GetFilePath(wxid string) string { 17 | wDir := "MyDocument:" 18 | isWDir := false 19 | 20 | if wxid == "" { 21 | return "None" 22 | } 23 | 24 | // 尝试从注册表获取微信路径 25 | if runtime.GOOS == "windows" { 26 | key, err := OpenKey(syscall.HKEY_CURRENT_USER, `Software\Tencent\WeChat`, syscall.KEY_READ) 27 | if err == nil { 28 | defer CloseKey(key) 29 | value, err := QueryValueEx(key, "FileSavePath") //这是找出是否修改过文件路径,比如我这里就是D:\weixin\file,没修改过这里就是MyDocument 30 | if err == nil { //从注册表中找出路径 31 | wDir = value 32 | isWDir = true 33 | } 34 | } 35 | } 36 | 37 | // 如果没有找到路径,尝试从环境变量获取 38 | if !isWDir { 39 | userProfile := os.Getenv("USERPROFILE") 40 | path3ebffe94 := filepath.Join(userProfile, "AppData", "Roaming", "Tencent", "WeChat", "All Users", "config", "3ebffe94.ini") //这个文件是直接存储微信路径的配置文件 41 | wDir = readFile(path3ebffe94) 42 | if wDir != "" { 43 | isWDir = true 44 | } 45 | } 46 | 47 | // 如果仍然没有找到路径,尝试从用户文档路径获取 48 | if wDir == "MyDocument:" { 49 | documentsPath := os.Getenv("USERPROFILE") 50 | wDir = filepath.Join(documentsPath, "Documents") 51 | } 52 | 53 | msgDir := filepath.Join(wDir, "WeChat Files") 54 | 55 | s, _ := os.Stat(msgDir) 56 | if wxid == "all" && s.IsDir() { 57 | return msgDir 58 | } 59 | 60 | filePath := filepath.Join(msgDir, wxid) 61 | if _, err := os.Stat(filePath); os.IsNotExist(err) { 62 | return "None" 63 | } 64 | return filePath 65 | 66 | } 67 | 68 | //注册表操作 69 | 70 | // 定义一个结构体来模拟Python中的字典 71 | type RegistryKey struct { 72 | handle syscall.Handle 73 | } 74 | 75 | // 定义一个函数来打开注册表键 76 | func OpenKey(root syscall.Handle, path string, access uint32) (*RegistryKey, error) { 77 | var key syscall.Handle 78 | err := syscall.RegOpenKeyEx(root, syscall.StringToUTF16Ptr(path), 0, access, &key) 79 | if err != nil { 80 | return nil, err 81 | } 82 | return &RegistryKey{handle: key}, nil 83 | } 84 | 85 | // 定义一个函数来查询注册表值 86 | func QueryValueEx(key *RegistryKey, valueName string) (string, error) { 87 | var dataType uint32 88 | var data []uint16 89 | var dataSize uint32 90 | err := syscall.RegQueryValueEx(key.handle, syscall.StringToUTF16Ptr(valueName), nil, &dataType, nil, &dataSize) 91 | if err != nil { 92 | return "", err 93 | } 94 | data = make([]uint16, dataSize/2) 95 | err = syscall.RegQueryValueEx(key.handle, syscall.StringToUTF16Ptr(valueName), nil, &dataType, (*byte)(unsafe.Pointer(&data[0])), &dataSize) 96 | if err != nil { 97 | return "", err 98 | } 99 | return syscall.UTF16ToString(data), nil 100 | } 101 | 102 | // 定义一个函数来关闭注册表键 103 | func CloseKey(key *RegistryKey) error { 104 | return syscall.RegCloseKey(key.handle) 105 | } 106 | 107 | func readFile(filePath string) string { 108 | // 打开文件 109 | file, err := os.Open(filePath) 110 | if err != nil { 111 | return "" 112 | } 113 | defer file.Close() // 确保在函数结束时关闭文件 114 | 115 | // 读取文件内容 116 | contents, err := ioutil.ReadAll(file) 117 | if err != nil { 118 | return "" 119 | } 120 | 121 | return string(contents) 122 | } 123 | -------------------------------------------------------------------------------- /comm/Getinfo_Wxid.go: -------------------------------------------------------------------------------- 1 | package comm 2 | 3 | //V1.0.0 4 | //By cmluZw 2024-08-12 5 | 6 | import ( 7 | "bytes" 8 | "fmt" 9 | "golang.org/x/sys/windows" 10 | "syscall" 11 | "unsafe" 12 | ) 13 | 14 | // 定义需要的Windows API函数 15 | var ( 16 | kernel32 = syscall.NewLazyDLL("kernel32.dll") 17 | virtualQueryEx = kernel32.NewProc("VirtualQueryEx") 18 | readProcessMemory = kernel32.NewProc("ReadProcessMemory") 19 | ) 20 | 21 | // MEMORY_BASIC_INFORMATION结构体定义 22 | type MEMORY_BASIC_INFORMATION struct { 23 | BaseAddress uintptr 24 | AllocationBase uintptr 25 | AllocationProtect uint32 26 | RegionSize uintptr 27 | State uint32 28 | Protect uint32 29 | Type uint32 30 | } 31 | 32 | func patternScanAll(handle syscall.Handle, pattern []byte, returnMultiple bool, findNum int) ([]uintptr, error) { 33 | var found []uintptr 34 | nextRegion := uintptr(0) 35 | userSpaceLimit := uintptr(0x7FFFFFFF0000) 36 | if unsafe.Sizeof(uintptr(0)) == 4 { 37 | userSpaceLimit = 0x7fff0000 38 | } 39 | 40 | for nextRegion < userSpaceLimit { 41 | mbi := MEMORY_BASIC_INFORMATION{} 42 | mbiSize := unsafe.Sizeof(mbi) 43 | ret, _, _ := virtualQueryEx.Call(uintptr(handle), nextRegion, uintptr(unsafe.Pointer(&mbi)), mbiSize) 44 | if ret == 0 { 45 | break 46 | } 47 | 48 | // 如果是可读内存区域 49 | if mbi.State == windows.MEM_COMMIT && (mbi.Protect == syscall.PAGE_READWRITE || mbi.Protect == syscall.PAGE_EXECUTE_READWRITE) { 50 | pageFound := scanPatternPage(handle, mbi.BaseAddress, mbi.RegionSize, pattern, returnMultiple) 51 | if !returnMultiple && len(pageFound) > 0 { 52 | return pageFound, nil 53 | } 54 | if len(pageFound) > 0 { 55 | found = append(found, pageFound...) 56 | } 57 | if len(found) > findNum { 58 | break 59 | } 60 | } 61 | 62 | nextRegion = mbi.BaseAddress + mbi.RegionSize 63 | } 64 | 65 | return found, nil 66 | } 67 | 68 | func scanPatternPage(handle syscall.Handle, baseAddr uintptr, regionSize uintptr, pattern []byte, returnMultiple bool) []uintptr { 69 | var found []uintptr 70 | buffer := make([]byte, regionSize) 71 | read := 0 72 | ret, _, _ := readProcessMemory.Call(uintptr(handle), baseAddr, uintptr(unsafe.Pointer(&buffer[0])), uintptr(regionSize), uintptr(unsafe.Pointer(&read))) 73 | if ret == 0 { 74 | return found 75 | } 76 | 77 | for i := 0; i < len(buffer)-len(pattern); i++ { 78 | if bytes.Equal(buffer[i:i+len(pattern)], pattern) { 79 | found = append(found, baseAddr+uintptr(i)) 80 | if !returnMultiple { 81 | break 82 | } 83 | } 84 | } 85 | 86 | return found 87 | } 88 | 89 | func getInfoWxid(hProcess syscall.Handle) (string, error) { 90 | findNum := 100 91 | addrs, err := patternScanAll(hProcess, []byte(`\Msg\FTSContact`), true, findNum) 92 | if err != nil { 93 | return "None", err 94 | } 95 | wxids := make([]string, 0) 96 | for _, addr := range addrs { 97 | array := make([]byte, 80) 98 | read := 0 99 | ret, _, _ := readProcessMemory.Call(uintptr(hProcess), addr-30, uintptr(unsafe.Pointer(&array[0])), 80, uintptr(unsafe.Pointer(&read))) 100 | if ret == 0 { 101 | return "None", nil 102 | } 103 | array = bytes.Split(array, []byte(`\Msg`))[0] // 处理前缀 104 | parts := bytes.Split(array, []byte(`\`)) // 分割字节切片 105 | lastPart := parts[len(parts)-1] // 获取最后一部分 106 | wxid := string(lastPart) // 将最后一部分转换为字符串 107 | wxids = append(wxids, wxid) 108 | } 109 | if len(wxids) == 0 { 110 | return "None", nil 111 | } 112 | return mostCommonString(wxids), nil 113 | } 114 | 115 | func mostCommonString(arr []string) string { 116 | freqMap := make(map[string]int) 117 | maxFreq := 0 118 | mostCommon := "" 119 | for _, str := range arr { 120 | freqMap[str]++ 121 | if freqMap[str] > maxFreq { 122 | maxFreq = freqMap[str] 123 | mostCommon = str 124 | } 125 | } 126 | return mostCommon 127 | } 128 | 129 | func Get_result() string { 130 | process, _ := GetWeChatProcess() 131 | wechatProcessHandle, _ := windows.OpenProcess(0x1F0FFF, false, process.ProcessID) //原来0x1F0FFF是PROCESS_ALL_ACCESS 132 | handle := syscall.Handle(wechatProcessHandle) 133 | // 示例调用 134 | //handle := syscall.Handle(0x1234) // 假设这是一个有效的进程句柄 135 | wxid, err := getInfoWxid(handle) 136 | if err != nil { 137 | fmt.Println("Error:", err) 138 | } 139 | return wxid 140 | } 141 | -------------------------------------------------------------------------------- /comm/Getinfo_Wxinfo.go: -------------------------------------------------------------------------------- 1 | package comm 2 | 3 | //V1.0.0 4 | //By cmluZw 2024-08-12 5 | 6 | import ( 7 | "encoding/hex" 8 | "fmt" 9 | "golang.org/x/sys/windows" 10 | "strings" 11 | "unsafe" 12 | ) 13 | 14 | // 获取微信进程对象,包含进程ID、进程句柄和Module列表 15 | func GetWeChatProcess() (windows.ProcessEntry32, error) { 16 | var process windows.ProcessEntry32 17 | process.Size = uint32(unsafe.Sizeof(process)) 18 | snapshot, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) 19 | if err != nil { 20 | return process, err 21 | } 22 | defer windows.CloseHandle(snapshot) 23 | for { 24 | err = windows.Process32Next(snapshot, &process) 25 | if err != nil { 26 | return process, err 27 | } 28 | if windows.UTF16ToString(process.ExeFile[:]) == "WeChat.exe" { 29 | return process, nil 30 | } 31 | } 32 | } 33 | 34 | // 获取微信进程的WeChatWin.dll模块对象,包含模块基址、模块大小和模块路径() 35 | func GetWeChatWinModule(process windows.ProcessEntry32) (windows.ModuleEntry32, error) { 36 | var module windows.ModuleEntry32 37 | module.Size = uint32(unsafe.Sizeof(module)) 38 | snapshot, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE, process.ProcessID) 39 | if err != nil { 40 | return module, err 41 | } 42 | defer windows.CloseHandle(snapshot) 43 | for { 44 | err = windows.Module32Next(snapshot, &module) 45 | if err != nil { 46 | return module, err 47 | } 48 | if windows.UTF16ToString(module.Module[:]) == "WeChatWin.dll" { 49 | return module, nil 50 | } 51 | } 52 | } 53 | 54 | // 通过模块获取版本号 c#代码为:string FileVersion = processModule.FileVersionInfo.FileVersion;转成go代码如下 55 | func GetVersion(module windows.ModuleEntry32) (string, error) { 56 | image, imgErr := windows.LoadLibraryEx(windows.UTF16ToString(module.ExePath[:]), 0, windows.LOAD_LIBRARY_AS_DATAFILE) 57 | if imgErr != nil { 58 | return "", fmt.Errorf("LoadLibraryEx error: %v", imgErr) 59 | } 60 | resInfo, infoErr := windows.FindResource(image, windows.ResourceID(1), windows.RT_VERSION) 61 | if infoErr != nil { 62 | return "", fmt.Errorf("FindResource error: %v", infoErr) 63 | } 64 | resData, dataErr := windows.LoadResourceData(image, resInfo) 65 | if dataErr != nil { 66 | return "", fmt.Errorf("LoadResourceData error: %v", dataErr) 67 | } 68 | var info *windows.VS_FIXEDFILEINFO 69 | size := uint32(unsafe.Sizeof(*info)) 70 | err := windows.VerQueryValue(unsafe.Pointer(&resData[0]), `\`, unsafe.Pointer(&info), &size) 71 | if err != nil { 72 | return "", fmt.Errorf("VerQueryValue error: %v", err) 73 | } 74 | // 从低位到高位,分别为主版本号、次版本号、修订号、编译号 75 | version := fmt.Sprintf("%d.%d.%d.%d", info.FileVersionMS>>16, info.FileVersionMS&0xffff, info.FileVersionLS>>16, info.FileVersionLS&0xffff) 76 | return version, nil 77 | } 78 | 79 | // 获取微信数据:入参为微信进程句柄,偏移地址,返回值为昵称和错误信息 80 | func GetWeChatData(process windows.Handle, offset uintptr, nSize int) (string, error) { 81 | var buffer = make([]byte, nSize) 82 | err := windows.ReadProcessMemory(process, offset, &buffer[0], uintptr(nSize), nil) 83 | if err != nil { 84 | return "", err 85 | } 86 | // 声明一个字节数组,暂时为空 87 | var textBytes []byte = nil 88 | for _, v := range buffer { 89 | if v == 0 { 90 | break 91 | } 92 | textBytes = append(textBytes, v) 93 | } 94 | // 返回utf8编码的字符串 95 | return string(textBytes), nil 96 | } 97 | 98 | // 获取微信key:入参为微信进程句柄,偏移地址,返回值为key和错误信息 99 | func GetWeChatKey(process windows.Handle, offset uintptr) (string, error) { 100 | var buffer = make([]byte, 4) 101 | err := windows.ReadProcessMemory(process, offset, &buffer[0], 4, nil) 102 | if err != nil { 103 | return "", err 104 | } 105 | var num = 32 106 | var buffer2 = make([]byte, num) 107 | // c# 代码(IntPtr)(((int)array[3] << 24) + ((int)array[2] << 16) + ((int)array[1] << 8) + (int)array[0]);转成go代码如下 108 | offset2 := uintptr((int(buffer[3]) << 24) + (int(buffer[2]) << 16) + (int(buffer[1]) << 8) + int(buffer[0])) 109 | err = windows.ReadProcessMemory(process, offset2, &buffer2[0], uintptr(num), nil) 110 | if err != nil { 111 | return "", err 112 | } 113 | // 将byte数组转成hex字符串,并转成大写 114 | key := hex.EncodeToString(buffer2) 115 | key = strings.ToUpper(key) 116 | return key, nil 117 | } 118 | 119 | func GetWeChatKey64(process windows.Handle, offset uintptr) (string, error) { 120 | var buffer = make([]byte, 8) 121 | err := windows.ReadProcessMemory(process, offset, &buffer[0], 8, nil) 122 | if err != nil { 123 | return "", err 124 | } 125 | var num = 32 126 | var buffer2 = make([]byte, num) 127 | offset2 := uintptr( 128 | (uint64(buffer[7]) << 56) + (uint64(buffer[6]) << 48) + (uint64(buffer[5]) << 40) + (uint64(buffer[4]) << 32) + 129 | (uint64(buffer[3]) << 24) + (uint64(buffer[2]) << 16) + (uint64(buffer[1]) << 8) + (uint64(buffer[0]) << 0)) 130 | err = windows.ReadProcessMemory(process, offset2, &buffer2[0], uintptr(num), nil) 131 | if err != nil { 132 | return "", err 133 | } 134 | // 将byte数组转成hex字符串,并转成大写 135 | key := hex.EncodeToString(buffer2) 136 | key = strings.ToUpper(key) 137 | return key, nil 138 | } 139 | 140 | func Get_info() (bool, string, string, string) { 141 | is_normal := false 142 | versionList := Get_version_list() 143 | process, _ := GetWeChatProcess() 144 | module, _ := GetWeChatWinModule(process) 145 | base_addr := module.ModBaseAddr 146 | version, _ := GetVersion(module) 147 | fmt.Println("当前微信版本: ", version) 148 | wechatProcessHandle, _ := windows.OpenProcess(0x1F0FFF, false, process.ProcessID) //原来0x1F0FFF是PROCESS_ALL_ACCESS 149 | //version = "3.9.8.25" 150 | if len(versionList[version]) == 0 { 151 | fmt.Println("微信版本范围超过已有配置") 152 | return false, "", "", "" 153 | } 154 | 155 | nickName, err := GetWeChatData(wechatProcessHandle, base_addr+uintptr(versionList[version][0]), 64) 156 | if err != nil { 157 | fmt.Println("Error:", err) 158 | return false, "", "", "" 159 | } 160 | account, err := GetWeChatData(wechatProcessHandle, base_addr+uintptr(versionList[version][1]), 32) 161 | if err != nil { 162 | fmt.Println("Error:", err) 163 | return false, "", "", "" 164 | } 165 | fmt.Println(nickName, account) 166 | key, err := GetWeChatKey64(wechatProcessHandle, base_addr+uintptr(versionList[version][4])) 167 | if err != nil { 168 | fmt.Println("Error:", err) 169 | return false, "", "", "" 170 | } 171 | if len(key) == 0 { 172 | fmt.Println("找不到key") 173 | return false, nickName, account, key 174 | } 175 | is_normal = true 176 | return is_normal, nickName, account, key 177 | } 178 | -------------------------------------------------------------------------------- /comm/Getinfo_Wxkey.go: -------------------------------------------------------------------------------- 1 | package comm 2 | 3 | //V1.0.0 4 | //By cmluZw 2024-08-12 5 | 6 | import ( 7 | "crypto/hmac" 8 | "crypto/sha1" 9 | "encoding/binary" 10 | "encoding/hex" 11 | "fmt" 12 | "golang.org/x/crypto/pbkdf2" 13 | "golang.org/x/sys/windows" 14 | "io/ioutil" 15 | "os" 16 | "syscall" 17 | "unsafe" 18 | ) 19 | 20 | func patternScanModule(pid uint32, moduleName string, pattern []byte, returnMultiple bool) ([]uintptr, error) { 21 | hProcess, err := syscall.OpenProcess(0x1F0FFF, false, pid) 22 | if err != nil { 23 | return nil, fmt.Errorf("failed to open process: %v", err) 24 | } 25 | defer syscall.CloseHandle(hProcess) 26 | 27 | moduleBaseAddress, moduleSize, err := getModuleInfo(pid, moduleName) //返回WeChatWin.dll的基址 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | moduleData, err := readProcessMemoryBytes(hProcess, moduleBaseAddress, int(moduleSize)) //读取WeChatWin.dll里的内存 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | positions := searchPattern(moduleData, pattern) //在内存中搜索对应模块 38 | 39 | if len(positions) == 0 { 40 | return nil, nil 41 | } 42 | 43 | var results []uintptr 44 | for _, pos := range positions { 45 | results = append(results, moduleBaseAddress+uintptr(pos)) //返回搜索到的模块的地址 46 | if !returnMultiple { 47 | break 48 | } 49 | } 50 | return results, nil 51 | } 52 | 53 | func encodeString(s string) []byte { 54 | return append([]byte(s), 0) 55 | } 56 | 57 | //// ReadKeyBytes reads key bytes from a given memory address 58 | //func readKeyBytes(hProcess syscall.Handle, address uintptr, addressLen int) ([]byte, error) { 59 | // // Create a byte slice to hold the address 60 | // array := make([]byte, addressLen) 61 | // 62 | // // Read memory at the given address 63 | // read := 0 64 | // ret, _, _ := readProcessMemory.Call( 65 | // uintptr(hProcess), 66 | // address, 67 | // uintptr(unsafe.Pointer(&array[0])), 68 | // uintptr(addressLen), 69 | // uintptr(unsafe.Pointer(&read)), 70 | // ) 71 | // if ret == 0 { 72 | // return nil, fmt.Errorf("failed to read process memory") 73 | // } 74 | // 75 | // // Convert the byte array to an integer address in little-endian format 76 | // keyAddress := binary.LittleEndian.Uint64(array) 77 | // 78 | // // Read the key at the new address 79 | // key := make([]byte, 32) 80 | // ret, _, _ = readProcessMemory.Call( 81 | // uintptr(hProcess), 82 | // uintptr(keyAddress), 83 | // uintptr(unsafe.Pointer(&key[0])), 84 | // uintptr(32), 85 | // uintptr(unsafe.Pointer(&read)), 86 | // ) 87 | // if ret == 0 { 88 | // return nil, fmt.Errorf("failed to read process memory") 89 | // } 90 | // 91 | // return key, nil 92 | //} 93 | 94 | func readKeyBytes(hProcess syscall.Handle, address uintptr, addressLen int) ([]byte, error) { 95 | array := make([]byte, addressLen) 96 | read := 0 97 | ret, _, _ := readProcessMemory.Call(uintptr(hProcess), address, uintptr(unsafe.Pointer(&array[0])), uintptr(addressLen), uintptr(unsafe.Pointer(&read))) 98 | if ret == 0 { 99 | return nil, fmt.Errorf("failed to read process memory") 100 | } 101 | //address = uintptr(array[0]) 这段代码是原先的,直接调用的是array[0],运行起来key为None, 102 | address = uintptr(binary.LittleEndian.Uint64(array)) //这行代码将一个字节数组 array 解释为一个 64 位的小端序(little-endian)的无符号整数 (uint64)。 103 | key := make([]byte, 32) 104 | ret, _, _ = readProcessMemory.Call(uintptr(hProcess), address, uintptr(unsafe.Pointer(&key[0])), uintptr(32), uintptr(unsafe.Pointer(&read))) 105 | if ret == 0 { 106 | return nil, fmt.Errorf("failed to read process memory") 107 | } 108 | return key, nil 109 | } 110 | 111 | func verifyKey(key []byte, wxDbPath string) bool { 112 | if wxDbPath == "" || wxDbPath == "none" { 113 | return true 114 | } 115 | const KEY_SIZE = 32 116 | const DEFAULT_PAGESIZE = 4096 117 | const DEFAULT_ITER = 64000 118 | 119 | file, err := os.Open(wxDbPath) 120 | if err != nil { 121 | return false 122 | } 123 | defer file.Close() 124 | 125 | blist := make([]byte, 5000) 126 | _, err = file.Read(blist) 127 | if err != nil { 128 | return false 129 | } 130 | 131 | salt := blist[:16] 132 | byteKey := pbkdf2.Key(key, salt, DEFAULT_ITER, KEY_SIZE, sha1.New) 133 | first := blist[16:DEFAULT_PAGESIZE] 134 | 135 | macSalt := make([]byte, 16) 136 | for i := range salt { 137 | macSalt[i] = salt[i] ^ 0x3A 138 | } 139 | macKey := pbkdf2.Key(byteKey, macSalt, 2, KEY_SIZE, sha1.New) 140 | 141 | hashMac := hmac.New(sha1.New, macKey) 142 | hashMac.Write(first[:len(first)-32]) 143 | hashMac.Write([]byte{0x01, 0x00, 0x00, 0x00}) 144 | 145 | return hmac.Equal(hashMac.Sum(nil), first[len(first)-32:len(first)-12]) 146 | } 147 | 148 | func GetKey(dbPath string, addrLen int) (string, error) { 149 | fmt.Println("正在通过内存读取的形式获取key....") 150 | process, _ := GetWeChatProcess() 151 | pid := uint32(process.ProcessID) // 示例进程ID,需要实际的进程ID 152 | moduleName := "WeChatWin.dll" 153 | 154 | phoneType1 := "iphone\x00" 155 | phoneType2 := "android\x00" 156 | phoneType3 := "ipad\x00" 157 | 158 | encodedPhoneType1 := encodeString(phoneType1) 159 | encodedPhoneType2 := encodeString(phoneType2) 160 | encodedPhoneType3 := encodeString(phoneType3) 161 | 162 | microMsgPath := fmt.Sprintf("%s\\MSG\\MicroMsg.db", dbPath) 163 | 164 | type1Addrs, err := patternScanModule(pid, moduleName, encodedPhoneType1, true) 165 | if err != nil { 166 | return "None", err 167 | } 168 | type2Addrs, err := patternScanModule(pid, moduleName, encodedPhoneType2, true) 169 | if err != nil { 170 | return "None", err 171 | } 172 | type3Addrs, err := patternScanModule(pid, moduleName, encodedPhoneType3, true) 173 | if err != nil { 174 | return "None", err 175 | } 176 | 177 | typeAddrs := type1Addrs 178 | if len(typeAddrs) < 2 { 179 | typeAddrs = type2Addrs 180 | } 181 | if len(typeAddrs) < 2 { 182 | typeAddrs = type3Addrs 183 | } 184 | 185 | if len(typeAddrs) < 2 { 186 | return "None", nil 187 | } 188 | hProcess, err := windows.OpenProcess(0x1F0FFF, false, pid) 189 | if err != nil { 190 | return "None", fmt.Errorf("failed to open process: %v", err) 191 | } 192 | //defer windows.CloseHandle(hProcess) 193 | Handle := syscall.Handle(hProcess) 194 | for i := len(typeAddrs) - 1; i >= 0; i-- { //从后往前遍历 195 | for j := typeAddrs[i]; j > typeAddrs[i]-2000; j -= uintptr(addrLen) { //从后往前开始,从高地址往低地址,从内存上来说是向下搜索,从搜索出来的基址开始遍历整个基址,遍历2kb,每次步长8kb 196 | keyBytes, err := readKeyBytes(Handle, j, addrLen) //在搜索出来的基址下面2kb的地方找key 197 | if err != nil || keyBytes == nil { 198 | continue 199 | } 200 | if dbPath != "None" && verifyKey(keyBytes, microMsgPath) { //验证key通过就是这个key,key和hmackey不一样,HMAC的密钥是刚提到的解密密钥和16字节盐值异或0x3a的值通过PKCS5_PBKF2_HMAC1密钥扩展算法迭代2次计算得到的 201 | saveKeyToFile(keyBytes, "./key.txt") 202 | return hex.EncodeToString(keyBytes), nil 203 | } 204 | } 205 | } 206 | return "None", nil 207 | } 208 | 209 | func saveKeyToFile(keyBytes []byte, filePath string) error { 210 | keyHex := hex.EncodeToString(keyBytes) 211 | 212 | // Write the key to a file 213 | err := ioutil.WriteFile(filePath, []byte(keyHex), 0644) 214 | if err != nil { 215 | return fmt.Errorf("failed to write key to file: %v", err) 216 | } 217 | return nil 218 | } 219 | 220 | //func main() { 221 | // wxid := comm.Get_result() 222 | // filepath := "D:\\weixin\\file\\WeChat Files\\" + string(wxid) 223 | // dbPath := filepath 224 | // addrLen := 8 225 | // key, err := getKey(dbPath, addrLen) 226 | // if err != nil { 227 | // fmt.Println("Error:", err) 228 | // } else { 229 | // fmt.Println("Key:", key) 230 | // } 231 | //} 232 | -------------------------------------------------------------------------------- /comm/ModuleDeal.go: -------------------------------------------------------------------------------- 1 | package comm 2 | 3 | //V1.0.0 4 | //By cmluZw 2024-08-12 5 | 6 | import ( 7 | "bytes" 8 | "fmt" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | var ( 14 | createToolhelp32Snapshot = kernel32.NewProc("CreateToolhelp32Snapshot") 15 | module32First = kernel32.NewProc("Module32FirstW") 16 | module32Next = kernel32.NewProc("Module32NextW") 17 | closeHandle = kernel32.NewProc("CloseHandle") 18 | TH32CS_SNAPMODULE = 0x00000008 19 | TH32CS_SNAPMODULE32 = 0x00000010 20 | ) 21 | 22 | type MODULEENTRY32 struct { 23 | Size uint32 24 | ModuleID uint32 25 | ProcessID uint32 26 | GlobalUsage uint32 27 | ProccntUsage uint32 28 | modBaseAddr uintptr 29 | ModBaseSize uint32 30 | hModule syscall.Handle 31 | ModuleName [256]uint16 32 | ExePath [260]uint16 33 | } 34 | 35 | func getModuleInfo(pid uint32, moduleName string) (uintptr, uintptr, error) { 36 | snapshot, _, _ := createToolhelp32Snapshot.Call(0x00000008, uintptr(pid)) 37 | if snapshot == uintptr(syscall.InvalidHandle) { 38 | return 0, 0, fmt.Errorf("failed to create snapshot") 39 | } 40 | defer closeHandle.Call(snapshot) 41 | 42 | var mod MODULEENTRY32 43 | mod.Size = uint32(unsafe.Sizeof(mod)) 44 | 45 | ret, _, _ := module32First.Call(snapshot, uintptr(unsafe.Pointer(&mod))) 46 | for ret != 0 { 47 | name := syscall.UTF16ToString(mod.ModuleName[:]) 48 | if name == moduleName { 49 | return mod.modBaseAddr, uintptr(mod.ModBaseSize), nil 50 | } 51 | ret, _, _ = module32Next.Call(snapshot, uintptr(unsafe.Pointer(&mod))) 52 | } 53 | 54 | return 0, 0, fmt.Errorf("module %s not found", moduleName) 55 | } 56 | 57 | func readProcessMemoryBytes(hProcess syscall.Handle, address uintptr, size int) ([]byte, error) { 58 | data := make([]byte, size) 59 | read := 0 60 | ret, _, _ := readProcessMemory.Call(uintptr(hProcess), address, uintptr(unsafe.Pointer(&data[0])), uintptr(size), uintptr(unsafe.Pointer(&read))) 61 | if ret == 0 { 62 | return nil, fmt.Errorf("failed to read process memory") 63 | } 64 | return data, nil 65 | } 66 | 67 | func searchPattern(data []byte, pattern []byte) []int { 68 | var positions []int 69 | for i := 0; i < len(data)-len(pattern); i++ { 70 | if bytes.Equal(data[i:i+len(pattern)], pattern) { 71 | positions = append(positions, i) 72 | } 73 | } 74 | return positions 75 | } 76 | 77 | func PatternScanModule(pid uint32, moduleName string, pattern []byte, returnMultiple bool) ([]uintptr, error) { 78 | //这里使用了0x1F0FFF替换了原本的syscall.PROCESS_ALL_ACCESS 79 | hProcess, err := syscall.OpenProcess(0x1F0FFF, false, pid) 80 | if err != nil { 81 | return nil, fmt.Errorf("failed to open process: %v", err) 82 | } 83 | defer syscall.CloseHandle(hProcess) 84 | 85 | moduleBaseAddress, moduleSize, err := getModuleInfo(pid, moduleName) 86 | if err != nil { 87 | return nil, err 88 | } 89 | 90 | moduleData, err := readProcessMemoryBytes(hProcess, moduleBaseAddress, int(moduleSize)) 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | positions := searchPattern(moduleData, pattern) 96 | if len(positions) == 0 { 97 | return nil, nil 98 | } 99 | 100 | var results []uintptr 101 | for _, pos := range positions { 102 | results = append(results, moduleBaseAddress+uintptr(pos)) 103 | if !returnMultiple { 104 | break 105 | } 106 | } 107 | 108 | return results, nil 109 | } 110 | -------------------------------------------------------------------------------- /comm/PackageToZip.go: -------------------------------------------------------------------------------- 1 | package comm 2 | 3 | import ( 4 | "archive/zip" 5 | "fmt" 6 | "io" 7 | "os" 8 | "path/filepath" 9 | ) 10 | 11 | // 将文件压缩成 ZIP 文件 12 | func ZipFile(srcPath, zipPath string) error { 13 | // 创建一个 ZIP 文件 14 | zipFile, err := os.Create(zipPath) 15 | if err != nil { 16 | return fmt.Errorf("failed to create zip file: %w", err) 17 | } 18 | defer zipFile.Close() 19 | 20 | // 创建一个新的 zip.Writer 对象 21 | zipWriter := zip.NewWriter(zipFile) 22 | defer zipWriter.Close() 23 | 24 | // 打开待压缩的文件 25 | file, err := os.Open(srcPath) 26 | if err != nil { 27 | return fmt.Errorf("failed to open file: %w", err) 28 | } 29 | defer file.Close() 30 | 31 | // 在 ZIP 中创建一个新文件 32 | zipEntryWriter, err := zipWriter.Create(filepath.Base(srcPath)) 33 | if err != nil { 34 | return fmt.Errorf("failed to create zip entry: %w", err) 35 | } 36 | 37 | // 将原始文件内容复制到 ZIP 文件中 38 | _, err = io.Copy(zipEntryWriter, file) 39 | if err != nil { 40 | return fmt.Errorf("failed to copy file contents to zip: %w", err) 41 | } 42 | 43 | fmt.Printf("Successfully zipped: %s to %s\n", srcPath, zipPath) 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /comm/WX_OFFS.json: -------------------------------------------------------------------------------- 1 | { 2 | "3.2.1.154": [ 3 | 328121948, 4 | 328122328, 5 | 328123056, 6 | 328121976, 7 | 328123020, 8 | 0 9 | ], 10 | "3.3.0.115": [ 11 | 31323364, 12 | 31323744, 13 | 31324472, 14 | 31323392, 15 | 31324436, 16 | 0 17 | ], 18 | "3.3.0.84": [ 19 | 31315212, 20 | 31315592, 21 | 31316320, 22 | 31315240, 23 | 31316284, 24 | 0 25 | ], 26 | "3.3.0.93": [ 27 | 31323364, 28 | 31323744, 29 | 31324472, 30 | 31323392, 31 | 31324436, 32 | 0 33 | ], 34 | "3.3.5.34": [ 35 | 30603028, 36 | 30603408, 37 | 30604120, 38 | 30603056, 39 | 30604100, 40 | 0 41 | ], 42 | "3.3.5.42": [ 43 | 30603012, 44 | 30603392, 45 | 30604120, 46 | 30603040, 47 | 30604084, 48 | 0 49 | ], 50 | "3.3.5.46": [ 51 | 30578372, 52 | 30578752, 53 | 30579480, 54 | 30578400, 55 | 30579444, 56 | 0 57 | ], 58 | "3.4.0.37": [ 59 | 31608116, 60 | 31608496, 61 | 31609224, 62 | 31608144, 63 | 31609188, 64 | 0 65 | ], 66 | "3.4.0.38": [ 67 | 31604044, 68 | 31604424, 69 | 31605152, 70 | 31604072, 71 | 31605116, 72 | 0 73 | ], 74 | "3.4.0.50": [ 75 | 31688500, 76 | 31688880, 77 | 31689608, 78 | 31688528, 79 | 31689572, 80 | 0 81 | ], 82 | "3.4.0.54": [ 83 | 31700852, 84 | 31701248, 85 | 31700920, 86 | 31700880, 87 | 31701924, 88 | 0 89 | ], 90 | "3.4.5.27": [ 91 | 32133788, 92 | 32134168, 93 | 32134896, 94 | 32133816, 95 | 32134860, 96 | 0 97 | ], 98 | "3.4.5.45": [ 99 | 32147012, 100 | 32147392, 101 | 32147064, 102 | 32147040, 103 | 32148084, 104 | 0 105 | ], 106 | "3.5.0.20": [ 107 | 35494484, 108 | 35494864, 109 | 35494536, 110 | 35494512, 111 | 35495556, 112 | 0 113 | ], 114 | "3.5.0.29": [ 115 | 35507980, 116 | 35508360, 117 | 35508032, 118 | 35508008, 119 | 35509052, 120 | 0 121 | ], 122 | "3.5.0.33": [ 123 | 35512140, 124 | 35512520, 125 | 35512192, 126 | 35512168, 127 | 35513212, 128 | 0 129 | ], 130 | "3.5.0.39": [ 131 | 35516236, 132 | 35516616, 133 | 35516288, 134 | 35516264, 135 | 35517308, 136 | 0 137 | ], 138 | "3.5.0.42": [ 139 | 35512140, 140 | 35512520, 141 | 35512192, 142 | 35512168, 143 | 35513212, 144 | 0 145 | ], 146 | "3.5.0.44": [ 147 | 35510836, 148 | 35511216, 149 | 35510896, 150 | 35510864, 151 | 35511908, 152 | 0 153 | ], 154 | "3.5.0.46": [ 155 | 35506740, 156 | 35507120, 157 | 35506800, 158 | 35506768, 159 | 35507812, 160 | 0 161 | ], 162 | "3.6.0.18": [ 163 | 35842996, 164 | 35843376, 165 | 35843048, 166 | 35843024, 167 | 35844068, 168 | 0 169 | ], 170 | "3.6.5.7": [ 171 | 35864356, 172 | 35864736, 173 | 35864408, 174 | 35864384, 175 | 35865428, 176 | 0 177 | ], 178 | "3.6.5.16": [ 179 | 35909428, 180 | 35909808, 181 | 35909480, 182 | 35909456, 183 | 35910500, 184 | 0 185 | ], 186 | "3.7.0.26": [ 187 | 37105908, 188 | 37106288, 189 | 37105960, 190 | 37105936, 191 | 37106980, 192 | 0 193 | ], 194 | "3.7.0.29": [ 195 | 37105908, 196 | 37106288, 197 | 37105960, 198 | 37105936, 199 | 37106980, 200 | 0 201 | ], 202 | "3.7.0.30": [ 203 | 37118196, 204 | 37118576, 205 | 37118248, 206 | 37118224, 207 | 37119268, 208 | 0 209 | ], 210 | "3.7.5.11": [ 211 | 37883280, 212 | 37884088, 213 | 37883136, 214 | 37883008, 215 | 37884052, 216 | 0 217 | ], 218 | "3.7.5.23": [ 219 | 37895736, 220 | 37896544, 221 | 37895592, 222 | 37883008, 223 | 37896508, 224 | 0 225 | ], 226 | "3.7.5.27": [ 227 | 37895736, 228 | 37896544, 229 | 37895592, 230 | 37895464, 231 | 37896508, 232 | 0 233 | ], 234 | "3.7.5.31": [ 235 | 37903928, 236 | 37904736, 237 | 37903784, 238 | 37903656, 239 | 37904700, 240 | 0 241 | ], 242 | "3.7.6.24": [ 243 | 38978840, 244 | 38979648, 245 | 38978696, 246 | 38978604, 247 | 38979612, 248 | 0 249 | ], 250 | "3.7.6.29": [ 251 | 38986376, 252 | 38987184, 253 | 38986232, 254 | 38986104, 255 | 38987148, 256 | 0 257 | ], 258 | "3.7.6.44": [ 259 | 39016520, 260 | 39017328, 261 | 39016376, 262 | 38986104, 263 | 39017292, 264 | 0 265 | ], 266 | "3.8.0.31": [ 267 | 46064088, 268 | 46064912, 269 | 46063944, 270 | 38986104, 271 | 46064876, 272 | 0 273 | ], 274 | "3.8.0.33": [ 275 | 46059992, 276 | 46060816, 277 | 46059848, 278 | 38986104, 279 | 46060780, 280 | 0 281 | ], 282 | "3.8.0.41": [ 283 | 46064024, 284 | 46064848, 285 | 46063880, 286 | 38986104, 287 | 46064812, 288 | 0 289 | ], 290 | "3.8.1.26": [ 291 | 46409448, 292 | 46410272, 293 | 46409304, 294 | 38986104, 295 | 46410236, 296 | 0 297 | ], 298 | "3.9.0.28": [ 299 | 48418376, 300 | 48419280, 301 | 48418232, 302 | 38986104, 303 | 48419244, 304 | 0 305 | ], 306 | "3.9.2.23": [ 307 | 50320784, 308 | 50321712, 309 | 50320640, 310 | 38986104, 311 | 50321676, 312 | 50592864 313 | ], 314 | "3.9.2.26": [ 315 | 50329040, 316 | 50329968, 317 | 50328896, 318 | 38986104, 319 | 50329932, 320 | 0 321 | ], 322 | "3.9.5.81": [ 323 | 61650872, 324 | 61652208, 325 | 61650680, 326 | 0, 327 | 61652144, 328 | 0 329 | ], 330 | "3.9.5.91": [ 331 | 61654904, 332 | 61656240, 333 | 61654712, 334 | 38986104, 335 | 61656176, 336 | 61677112 337 | ], 338 | "3.9.6.19": [ 339 | 61997688, 340 | 61997464, 341 | 61997496, 342 | 38986104, 343 | 61998960, 344 | 0 345 | ], 346 | "3.9.6.33": [ 347 | 62030600, 348 | 62031936, 349 | 62030408, 350 | 0, 351 | 62031872, 352 | 0 353 | ], 354 | "3.9.7.15": [ 355 | 63482696, 356 | 63484032, 357 | 63482504, 358 | 0, 359 | 63483968, 360 | 0 361 | ], 362 | "3.9.7.25": [ 363 | 63482760, 364 | 63484096, 365 | 63482568, 366 | 0, 367 | 63484032, 368 | 0 369 | ], 370 | "3.9.7.29": [ 371 | 63486984, 372 | 63488320, 373 | 63486792, 374 | 0, 375 | 63488256, 376 | 63488352 377 | ], 378 | "3.9.8.15": [ 379 | 64996632, 380 | 64997968, 381 | 64996440, 382 | 0, 383 | 64997904, 384 | 65011632 385 | ], 386 | "3.9.8.25": [ 387 | 65000920, 388 | 0, 389 | 65000728, 390 | 0, 391 | 0, 392 | 0 393 | ], 394 | "3.9.9.27": [ 395 | 68065304, 396 | 0, 397 | 68065112, 398 | 0, 399 | 68066576 400 | ], 401 | "3.9.9.35": [ 402 | 68065304, 403 | 0, 404 | 68065112, 405 | 0, 406 | 68066576 407 | ], 408 | "3.9.9.148": [ 409 | 69043224, 410 | 69044560, 411 | 69043032, 412 | 0, 413 | 0 414 | ], 415 | "3.9.5.65": [ 416 | 61642744, 417 | 61644080, 418 | 61644081, 419 | 0, 420 | 61644016 421 | ], 422 | "3.9.9.38": [ 423 | 68070104, 424 | 68071440, 425 | 68069912, 426 | 0, 427 | 68071376 428 | ], 429 | "3.9.9.147": [ 430 | 76731445, 431 | 0, 432 | 69043032, 433 | 0, 434 | 0 435 | ], 436 | "3.6.0.0": [ 437 | 35842996, 438 | 35844104, 439 | 35843048, 440 | 0, 441 | 0 442 | ], 443 | "3.9.9.43": [ 444 | 68065944, 445 | 68067280, 446 | 68065752, 447 | 0, 448 | 68067216 449 | ], 450 | "3.9.9.143": [ 451 | 69035096, 452 | 69036432, 453 | 69034904, 454 | 0, 455 | 69036368 456 | ], 457 | "3.3.0.0": [ 458 | 31082900, 459 | 31083928, 460 | 31082952, 461 | 0, 462 | 0 463 | ], 464 | "3.9.9.25": [ 465 | 68065304, 466 | 0, 467 | 68065112, 468 | 0, 469 | 68066576 470 | ], 471 | "3.9.8.11": [ 472 | 0, 473 | 0, 474 | 0, 475 | 0, 476 | 64998160 477 | ], 478 | "3.9.9.16": [ 479 | 68060952, 480 | 0, 481 | 0, 482 | 0, 483 | 68062224 484 | ], 485 | "3.9.6.24": [ 486 | 62022264, 487 | 62044248, 488 | 62022072, 489 | 0, 490 | 62023536 491 | ], 492 | "3.9.9.34": [ 493 | 56102304, 494 | 56118252, 495 | 56102160, 496 | 0, 497 | 0 498 | ], 499 | "3.9.6.39": [ 500 | 0, 501 | 63280064, 502 | 63278536, 503 | 0, 504 | 63280000 505 | ], 506 | "3.9.7.28": [ 507 | 52433824, 508 | 52434792, 509 | 52434793, 510 | 0, 511 | 0 512 | ], 513 | "3.9.8.137": [ 514 | 65894869, 515 | 65909760, 516 | 65908232, 517 | 0, 518 | 65909696 519 | ], 520 | "3.9.5.25": [ 521 | 61530888, 522 | 0, 523 | 61530696, 524 | 0, 525 | 61532160 526 | ], 527 | "3.9.5.80": [ 528 | 50681672, 529 | 50682640, 530 | 50682641, 531 | 0, 532 | 0 533 | ], 534 | "3.7.6.45": [ 535 | 39016456, 536 | 0, 537 | 39016312, 538 | 0, 539 | 0 540 | ], 541 | "3.5.0.0": [ 542 | 35507848, 543 | 35507848, 544 | 35506800, 545 | 0, 546 | 0 547 | ], 548 | "3.9.8.9": [ 549 | 65001112, 550 | 65002448, 551 | 0, 552 | 0, 553 | 65002384 554 | ], 555 | "3.9.6.47": [ 556 | 0, 557 | 63288512, 558 | 63286984, 559 | 0, 560 | 0 561 | ], 562 | "3.9.8.8": [ 563 | 64996952, 564 | 0, 565 | 64996760, 566 | 0, 567 | 64998224 568 | ], 569 | "3.9.6.43": [ 570 | 63283144, 571 | 63284480, 572 | 63282952, 573 | 0, 574 | 0 575 | ], 576 | "3.9.0.22": [ 577 | 48405896, 578 | 48406800, 579 | 48405752, 580 | 0, 581 | 0 582 | ], 583 | "3.7.6.43": [ 584 | 39016456, 585 | 39261580, 586 | 39016312, 587 | 0, 588 | 0 589 | ], 590 | "3.0.0.0": [ 591 | 25834908, 592 | 25846332, 593 | 25834960, 594 | 0, 595 | 0 596 | ], 597 | "3.7.0.23": [ 598 | 37105844, 599 | 37106952, 600 | 37105896, 601 | 0, 602 | 0 603 | ], 604 | "3.9.6.8": [ 605 | 61960264, 606 | 61961600, 607 | 0, 608 | 0, 609 | 61961536 610 | ], 611 | "3.9.5.55": [ 612 | 61589448, 613 | 61590784, 614 | 61589256, 615 | 0, 616 | 61590720 617 | ], 618 | "3.9.8.27": [ 619 | 65000920, 620 | 65002256, 621 | 65000728, 622 | 0, 623 | 65002192 624 | ], 625 | "2.4.5.1": [ 626 | 27329425, 627 | 24589520, 628 | 24588544, 629 | 0, 630 | 0 631 | ], 632 | "3.9.6.37": [ 633 | 63287160, 634 | 63310040, 635 | 63286968, 636 | 0, 637 | 63288432 638 | ], 639 | "3.9.5.77": [ 640 | 61652272, 641 | 61652272, 642 | 61650744, 643 | 0, 644 | 61652208 645 | ], 646 | "3.9.9.13": [ 647 | 68044888, 648 | 68069384, 649 | 68044696, 650 | 0, 651 | 68046160 652 | ], 653 | "3.9.5.39": [ 654 | 0, 655 | 0, 656 | 0, 657 | 0, 658 | 61565216 659 | ], 660 | "3.9.6.17": [ 661 | 61972568, 662 | 61973904, 663 | 61972376, 664 | 0, 665 | 61973840 666 | ], 667 | "3.9.9.11": [ 668 | 0, 669 | 0, 670 | 68032344, 671 | 0, 672 | 68033808 673 | ], 674 | "3.2.1.0": [ 675 | 0, 676 | 28123056, 677 | 28122080, 678 | 0, 679 | 0 680 | ], 681 | "3.8.1.25": [ 682 | 0, 683 | 0, 684 | 46405272, 685 | 0, 686 | 0 687 | ], 688 | "3.9.6.29": [ 689 | 0, 690 | 62052520, 691 | 62030344, 692 | 0, 693 | 62031808 694 | ], 695 | "3.9.8.12": [ 696 | 53479320, 697 | 53480288, 698 | 53479176, 699 | 0, 700 | 0 701 | ], 702 | "3.9.5.73": [ 703 | 61650872, 704 | 61652208, 705 | 0, 706 | 0, 707 | 61652144 708 | ], 709 | "3.9.1.25": [ 710 | 48634640, 711 | 48635544, 712 | 48634496, 713 | 0, 714 | 0 715 | ], 716 | "3.8.0.29": [ 717 | 50910714, 718 | 0, 719 | 46060689, 720 | 0, 721 | 0 722 | ], 723 | "3.9.9.22": [ 724 | 56102304, 725 | 0, 726 | 56102160, 727 | 0, 728 | 0 729 | ], 730 | "3.9.10.10": [ 731 | 102868520, 732 | 102869856, 733 | 102868328, 734 | 0, 735 | 102869792 736 | ], 737 | "3.8.0.18": [ 738 | 46043224, 739 | 46044048, 740 | 46043080, 741 | 0, 742 | 0 743 | ], 744 | "3.9.10.13": [ 745 | 0, 746 | 0, 747 | 95125416, 748 | 0, 749 | 0 750 | ], 751 | "3.9.10.18": [ 752 | 95129640, 753 | 95130976, 754 | 95129448, 755 | 0, 756 | 0 757 | ], 758 | "3.9.10.11": [ 759 | 102868456, 760 | 102869792, 761 | 102868264, 762 | 0, 763 | 0 764 | ], 765 | "3.9.7.14": [ 766 | 0, 767 | 0, 768 | 63478408, 769 | 0, 770 | 63479872 771 | ], 772 | "3.9.10.19": [ 773 | 95129768, 774 | 0, 775 | 95129576, 776 | 0, 777 | 95131192 778 | ], 779 | "3.7.6.38": [ 780 | 39016136, 781 | 0, 782 | 39015992, 783 | 0, 784 | 0 785 | ], 786 | "3.9.10.9": [ 787 | 102868712, 788 | 102870048, 789 | 102868520, 790 | 0, 791 | 102869984 792 | ], 793 | "3.9.10.16": [ 794 | 71305680, 795 | 71306648, 796 | 71305536, 797 | 0, 798 | 0 799 | ], 800 | "3.9.0.26": [ 801 | 48405896, 802 | 0, 803 | 48405752, 804 | 0, 805 | 0 806 | ], 807 | "3.9.7.13": [ 808 | 63474296, 809 | 63475632, 810 | 63474104, 811 | 0, 812 | 63475568 813 | ], 814 | "3.8.0.15": [ 815 | 46014616, 816 | 0, 817 | 46014472, 818 | 0, 819 | 0 820 | ], 821 | "3.9.10.25": [ 822 | 95135256, 823 | 95136592, 824 | 95135064, 825 | 0, 826 | 95136528 827 | ], 828 | "3.9.10.27": [ 829 | 95125656, 830 | 95126992, 831 | 95125464, 832 | 0, 833 | 95126928 834 | ], 835 | "3.8.0.27": [ 836 | 50268814, 837 | 46060496, 838 | 46060497, 839 | 0, 840 | 0 841 | ], 842 | "3.9.10.26": [ 843 | 71305744, 844 | 71306712, 845 | 71305600, 846 | 0, 847 | 0 848 | ], 849 | "3.9.11.7": [ 850 | 93459160, 851 | 93460496, 852 | 93458968, 853 | 0, 854 | 0 855 | ], 856 | "3.9.11.5": [ 857 | 93456272, 858 | 93456272, 859 | 93454744, 860 | 0, 861 | 0 862 | ], 863 | "3.9.11.8": [ 864 | 93454872, 865 | 93456208, 866 | 93454680, 867 | 0, 868 | 93456144 869 | ], 870 | "3.9.11.9": [ 871 | 93463000, 872 | 93464336, 873 | 93462808, 874 | 0, 875 | 93464272 876 | ], 877 | "3.9.11.13": [ 878 | 93546264, 879 | 93547600, 880 | 93547603, 881 | 0, 882 | 93547536 883 | ], 884 | "3.9.11.15": [ 885 | 93550360, 886 | 93551696, 887 | 93550168, 888 | 0, 889 | 93551632 890 | ], 891 | "3.9.11.17": [ 892 | 93550360, 893 | 0, 894 | 93550168, 895 | 0, 896 | 93551632 897 | ], 898 | "3.9.6.13": [ 899 | 0, 900 | 0, 901 | 0, 902 | 0, 903 | 61965584 904 | ], 905 | "3.9.6.124": [ 906 | 62034888, 907 | 0, 908 | 62034696, 909 | 0, 910 | 62036160 911 | ], 912 | "3.9.11.19": [ 913 | 93550296, 914 | 93551632, 915 | 93550104, 916 | 0, 917 | 93551568 918 | ], 919 | "3.9.11.16": [ 920 | 69861360, 921 | 69862328, 922 | 69861216, 923 | 0, 924 | 0 925 | ], 926 | "3.9.11.18": [ 927 | 69861296, 928 | 69862264, 929 | 69861152, 930 | 0, 931 | 0 932 | ], 933 | "3.9.11.23": [ 934 | 93701208, 935 | 93725072, 936 | 93701016, 937 | 0, 938 | 0 939 | ], 940 | "3.7.5.25": [ 941 | 37899832, 942 | 37900640, 943 | 37899688, 944 | 0, 945 | 0 946 | ], 947 | "3.9.11.25": [ 948 | 93701080, 949 | 93702416, 950 | 93700888, 951 | 0, 952 | 0 953 | ], 954 | "3.9.11.24": [ 955 | 69992304, 956 | 69993272, 957 | 0, 958 | 0, 959 | 0 960 | ], 961 | "3.9.0.18": [ 962 | 48385208, 963 | 48386112, 964 | 48385064, 965 | 0, 966 | 0 967 | ], 968 | "3.9.7.24": [ 969 | 0, 970 | 52434792, 971 | 52433680, 972 | 0, 973 | 30689842 974 | ], 975 | "3.9.12.4": [ 976 | 93809448, 977 | 0, 978 | 93809256, 979 | 0, 980 | 93810720 981 | ], 982 | "3.9.12.9": [ 983 | 93815072, 984 | 93815072, 985 | 93813544, 986 | 0, 987 | 93815008 988 | ], 989 | "3.9.12.11": [ 990 | 93810784, 991 | 93810784, 992 | 93809256, 993 | 0, 994 | 93810720 995 | ], 996 | "3.9.11.33": [ 997 | 0, 998 | 93702416, 999 | 0, 1000 | 0, 1001 | 93702352 1002 | ], 1003 | "3.9.12.15": [ 1004 | 93813544, 1005 | 0, 1006 | 93813352, 1007 | 0, 1008 | 93814968 1009 | ], 1010 | "3.9.12.14": [ 1011 | 70045856, 1012 | 70046824, 1013 | 70045712, 1014 | 0, 1015 | 0 1016 | ], 1017 | "3.9.12.17": [ 1018 | 93834984, 1019 | 93859856, 1020 | 93834792, 1021 | 0, 1022 | 93836256 1023 | ], 1024 | "3.9.12.16": [ 1025 | 70066720, 1026 | 70067688, 1027 | 70066576, 1028 | 0, 1029 | 0 1030 | ], 1031 | "3.9.12.19": [ 1032 | 93839144, 1033 | 93840480, 1034 | 93838952, 1035 | 0, 1036 | 93840416 1037 | ], 1038 | "3.9.5.51": [ 1039 | 0, 1040 | 61590400, 1041 | 61588872, 1042 | 0, 1043 | 61590336 1044 | ], 1045 | "3.8.1.14": [ 1046 | 46379944, 1047 | 46380768, 1048 | 46379800, 1049 | 0, 1050 | 0 1051 | ], 1052 | "3.9.0.21": [ 1053 | 48406800, 1054 | 48406800, 1055 | 48405752, 1056 | 0, 1057 | 0 1058 | ], 1059 | "3.9.12.1469": [ 1060 | 86719912, 1061 | 86721248, 1062 | 86721251, 1063 | 0, 1064 | 0 1065 | ], 1066 | "3.9.8.24": [ 1067 | 0, 1068 | 0, 1069 | 53479176, 1070 | 0, 1071 | 0 1072 | ], 1073 | "3.9.12.29": [ 1074 | 94516712, 1075 | 94518048, 1076 | 94516520, 1077 | 0, 1078 | 94517984 1079 | ], 1080 | "3.9.12.31": [ 1081 | 94516904, 1082 | 94518240, 1083 | 94516712, 1084 | 0, 1085 | 94518176 1086 | ], 1087 | "3.9.12.37": [ 1088 | 94520808, 1089 | 94522144, 1090 | 94522146, 1091 | 0, 1092 | 94522080 1093 | ], 1094 | "3.9.12.45": [ 1095 | 0, 1096 | 0, 1097 | 0, 1098 | 0, 1099 | 94505056 1100 | ], 1101 | "3.9.12.51": [ 1102 | 94555176, 1103 | 94556512, 1104 | 94554984, 1105 | 0, 1106 | 94556448 1107 | ] 1108 | 1109 | } -------------------------------------------------------------------------------- /comm/Wxdecrypto.go: -------------------------------------------------------------------------------- 1 | package comm 2 | 3 | //V1.0.0 4 | //By cmluZw 2024-08-12 5 | 6 | import ( 7 | "bytes" 8 | "crypto/aes" 9 | "crypto/cipher" 10 | "crypto/hmac" 11 | "crypto/sha1" 12 | "encoding/hex" 13 | "fmt" 14 | "io" 15 | "io/ioutil" 16 | "os" 17 | "path/filepath" 18 | "strings" 19 | 20 | "golang.org/x/crypto/pbkdf2" 21 | ) 22 | 23 | const ( 24 | SQLITE_FILE_HEADER = "SQLite format 3\x00" 25 | IV_SIZE = 16 26 | HMAC_SHA1_SIZE = 20 27 | KEY_SIZE = 32 28 | DEFAULT_PAGESIZE = 4096 29 | DEFAULT_ITER = 64000 30 | CurrentPath = "./" 31 | ) 32 | 33 | func Decrypt(key string, filePath string, decryptedPath string) error { 34 | password, err := hex.DecodeString(strings.Replace(key, " ", "", -1)) 35 | // fmt.Println(password) 36 | if err != nil { 37 | return err 38 | } 39 | file, err := os.Open(filePath) 40 | if err != nil { 41 | return err 42 | } 43 | defer file.Close() 44 | blist, err := ioutil.ReadAll(file) 45 | if err != nil { 46 | return err 47 | } 48 | salt := blist[:16] 49 | byteKey := pbkdf2.Key(password, salt, DEFAULT_ITER, KEY_SIZE, sha1.New) 50 | first := blist[16:DEFAULT_PAGESIZE] 51 | mac_salt := make([]byte, 16) 52 | for i := 0; i < 16; i++ { 53 | mac_salt[i] = salt[i] ^ 58 54 | } 55 | mac_key := pbkdf2.Key(byteKey, mac_salt, 2, KEY_SIZE, sha1.New) 56 | hash_mac := hmac.New(sha1.New, mac_key) 57 | hash_mac.Write(first[:len(first)-32]) 58 | hash_mac.Write([]byte{1, 0, 0, 0}) 59 | if bytes.Equal(hash_mac.Sum(nil), first[len(first)-32:len(first)-12]) { 60 | fmt.Println("Decryption Success") 61 | } else { 62 | fmt.Println("Password Error") 63 | } 64 | 65 | // 将python代码:blist = [blist[i:i + DEFAULT_PAGESIZE] for i in range(DEFAULT_PAGESIZE, len(blist), DEFAULT_PAGESIZE)] 转成go语言 66 | newblist := make([][]byte, 0) 67 | for i := DEFAULT_PAGESIZE; i < len(blist); i += DEFAULT_PAGESIZE { 68 | newblist = append(newblist, blist[i:i+DEFAULT_PAGESIZE]) 69 | } 70 | 71 | // 将文件写入decryptePath 72 | deFile, err := os.OpenFile(decryptedPath, os.O_CREATE|os.O_WRONLY, 0666) 73 | if err != nil { 74 | return err 75 | } 76 | defer deFile.Close() 77 | deFile.Write([]byte(SQLITE_FILE_HEADER)) 78 | t, err := aes.NewCipher(byteKey) 79 | if err != nil { 80 | return err 81 | } 82 | iv := first[len(first)-48 : len(first)-32] 83 | blockMode := cipher.NewCBCDecrypter(t, iv) 84 | decrypted := make([]byte, len(first)-48) 85 | blockMode.CryptBlocks(decrypted, first[:len(first)-48]) 86 | deFile.Write(decrypted) 87 | deFile.Write(first[len(first)-48:]) 88 | 89 | for _, i := range newblist { 90 | t, err := aes.NewCipher(byteKey) 91 | if err != nil { 92 | return err 93 | } 94 | blockMode := cipher.NewCBCDecrypter(t, i[len(i)-48:len(i)-32]) 95 | decrypted := make([]byte, len(i)-48) 96 | blockMode.CryptBlocks(decrypted, i[:len(i)-48]) 97 | deFile.Write(decrypted) 98 | deFile.Write(i[len(i)-48:]) 99 | } 100 | return nil 101 | } 102 | 103 | // 将文件复制出来 104 | 105 | func CopyFile(src, dst string) error { 106 | // 判断源文件是否存在 107 | _, err := os.Stat(src) 108 | if err != nil { 109 | return err 110 | } 111 | // 读取源文件 112 | srcFile, err := os.Open(src) 113 | if err != nil { 114 | return err 115 | } 116 | defer srcFile.Close() 117 | // 创建目标文件 118 | dstFile, err := os.Create(dst) 119 | if err != nil { 120 | return err 121 | } 122 | defer dstFile.Close() 123 | // 拷贝文件 124 | _, err = io.Copy(dstFile, srcFile) 125 | if err != nil { 126 | return err 127 | } 128 | return nil 129 | } 130 | 131 | // 复制微信的数据文件 132 | func CopyMsgDb(dataDir string) error { 133 | // 判断目录是否存在 134 | _, err := os.Stat(dataDir) 135 | if err != nil { 136 | return err 137 | } 138 | // 判断运行目录是否存在tmp目录没有则创建 139 | _, err = os.Stat(CurrentPath + "\\tmp") 140 | if err != nil { 141 | err = os.Mkdir(CurrentPath+"\\tmp", os.ModePerm) 142 | if err != nil { 143 | return err 144 | } 145 | } 146 | // 正则匹配,将所有MSG数字.db文件拷贝到tmp目录,不扫描子目录 147 | err = filepath.Walk(dataDir, func(path string, info os.FileInfo, err error) error { 148 | if err != nil { 149 | return err 150 | } 151 | if ok, _ := filepath.Match("MSG*.db", info.Name()); ok { 152 | err = CopyFile(path, CurrentPath+"\\tmp\\"+info.Name()) 153 | if err != nil { 154 | return err 155 | } 156 | } 157 | // 复制MicroMsg.db到tmp目录 158 | if ok, _ := filepath.Match("MicroMsg.db", info.Name()); ok { 159 | err = CopyFile(path, CurrentPath+"\\tmp\\"+info.Name()) 160 | if err != nil { 161 | return err 162 | } 163 | } 164 | return nil 165 | }) 166 | if err != nil { 167 | return err 168 | } 169 | // 如果不存在decrypted目录则创建 170 | _, err = os.Stat(CurrentPath + "\\decrypted") 171 | if err != nil { 172 | err = os.Mkdir(CurrentPath+"\\decrypted", os.ModePerm) 173 | if err != nil { 174 | return err 175 | } 176 | } 177 | 178 | return nil 179 | } 180 | 181 | // 解密微信数据库 182 | func DecryptDb(key string) error { 183 | // 判断tmp目录是否存在 184 | _, err := os.Stat(CurrentPath + "\\tmp") 185 | if err != nil { 186 | return err 187 | } 188 | // 判断decrypted目录是否存在 189 | _, err = os.Stat(CurrentPath + "\\decrypted") 190 | if err != nil { 191 | return err 192 | } 193 | // 正则匹配,将所有MSG数字.db文件解密到decrypted目录,不扫描子目录 194 | err = filepath.Walk(CurrentPath+"\\tmp", func(path string, info os.FileInfo, err error) error { 195 | if err != nil { 196 | return err 197 | } 198 | if ok, _ := filepath.Match("*.db", info.Name()); ok { 199 | err = Decrypt(key, path, CurrentPath+"\\decrypted\\"+info.Name()) 200 | if err != nil { 201 | return err 202 | } 203 | } 204 | return nil 205 | }) 206 | if err != nil { 207 | return err 208 | } 209 | return nil 210 | } 211 | -------------------------------------------------------------------------------- /comm/config.go: -------------------------------------------------------------------------------- 1 | package comm 2 | 3 | //V1.0.0 4 | //By cmluZw 2024-08-12 5 | 6 | import ( 7 | _ "embed" 8 | "encoding/json" 9 | "fmt" 10 | "golang.org/x/sys/windows" 11 | ) 12 | 13 | //搬运:https://github.com/LC044/WeChatMsg/blob/master/app/decrypt/version_list.json 14 | 15 | //go:embed WX_OFFS.json 16 | var versionListData []byte 17 | 18 | var PROCESS_ALL_ACCESS = uint32( 19 | windows.PROCESS_QUERY_INFORMATION | 20 | windows.PROCESS_VM_READ | 21 | windows.PROCESS_VM_WRITE | 22 | windows.PROCESS_VM_OPERATION | 23 | windows.PROCESS_CREATE_THREAD | 24 | windows.PROCESS_DUP_HANDLE | 25 | windows.PROCESS_TERMINATE | 26 | windows.PROCESS_SUSPEND_RESUME | 27 | windows.PROCESS_SET_QUOTA | 28 | windows.PROCESS_SET_INFORMATION | 29 | windows.PROCESS_QUERY_LIMITED_INFORMATION) 30 | 31 | // 支持自动获取数据的版本号 32 | var SupportAutoGetDataVersionList = []string{ 33 | //"3.9.10.16", 34 | "3.9.12.17", 35 | } 36 | 37 | type versionList struct { 38 | Versions map[string][]int 39 | } 40 | 41 | //微信名 42 | //0 43 | //手机号 44 | 45 | func Get_version_list() map[string][]int { 46 | // 定义一个map变量用于存储解析后的JSON数据 47 | var versionList map[string][]int 48 | 49 | // 解析嵌入的JSON数据到map 50 | err := json.Unmarshal(versionListData, &versionList) 51 | if err != nil { 52 | fmt.Printf("Error decoding JSON: %v\n", err) 53 | return nil 54 | } 55 | return versionList 56 | // 打印versionList查看结果 57 | //fmt.Printf("%+v\n", versionList["2.4.5.1"]) 58 | } 59 | 60 | ////从version_list.json中读取版本和偏移量 61 | // 62 | //func Get_version_list() map[string][]int { 63 | // // 设置JSON文件路径 64 | // VERSION_LIST_PATH := "./comm/version_list.json" 65 | // 66 | // // 读取JSON文件内容 67 | // fileContent, err := ioutil.ReadFile(VERSION_LIST_PATH) 68 | // if err != nil { 69 | // fmt.Printf("Error reading file '%s': %v\n", VERSION_LIST_PATH, err) 70 | // return nil 71 | // } 72 | // 73 | // // 定义一个map变量用于存储解析后的JSON数据 74 | // var versionList map[string][]int 75 | // 76 | // // 解析JSON数据到map 77 | // err = json.Unmarshal(fileContent, &versionList) 78 | // if err != nil { 79 | // fmt.Printf("Error decoding JSON: %v\n", err) 80 | // return nil 81 | // } 82 | // return versionList 83 | // // 打印versionList查看结果 84 | // //fmt.Printf("%+v\n", versionList["2.4.5.1"]) 85 | //} 86 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module WxDump 2 | 3 | go 1.22.1 4 | 5 | require ( 6 | golang.org/x/crypto v0.26.0 7 | golang.org/x/sys v0.30.0 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= 2 | golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= 3 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= 4 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 5 | -------------------------------------------------------------------------------- /img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmluZw/WxDump/339d4a47f03e43b2e244430d2c24b4bc3d035719/img.png -------------------------------------------------------------------------------- /img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmluZw/WxDump/339d4a47f03e43b2e244430d2c24b4bc3d035719/img_1.png -------------------------------------------------------------------------------- /img_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmluZw/WxDump/339d4a47f03e43b2e244430d2c24b4bc3d035719/img_2.png -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "WxDump/comm" 5 | "fmt" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | ) 10 | 11 | func main() { 12 | var key = "" 13 | wxid := comm.Get_result() 14 | dbPath := comm.GetFilePath(wxid) 15 | addrLen := 8 16 | is_normal, nickName, account, key_tmp := comm.Get_info() 17 | if is_normal != true { 18 | key_tmp, err := comm.GetKey(dbPath, addrLen) 19 | if (err != nil) || (key_tmp == "None") { 20 | fmt.Println("Error:", err) 21 | return 22 | } else { 23 | fmt.Println("Key:", key_tmp) 24 | } 25 | key = key_tmp 26 | } else { 27 | fmt.Println("nickName:", nickName) 28 | fmt.Println("account:", account) 29 | fmt.Println("Key:", key_tmp) 30 | key = key_tmp 31 | } 32 | comm.CopyMsgDb(dbPath) 33 | comm.DecryptDb(key) 34 | 35 | // 将解密后的文件打包成 ZIP 36 | CurrentPath, err := os.Getwd() 37 | if err != nil { 38 | log.Fatalf("Failed to get current directory: %v", err) 39 | } 40 | 41 | // decrypted 目录路径 42 | decryptedPath := filepath.Join(CurrentPath, "decrypted") 43 | 44 | // 读取 decrypted 目录下的所有文件 45 | files, err := os.ReadDir(decryptedPath) 46 | if err != nil { 47 | log.Fatalf("Failed to read directory: %v", err) 48 | } 49 | 50 | // 遍历文件 51 | for _, file := range files { 52 | if !file.IsDir() { // 只处理文件 53 | fmt.Println("Found file:", file.Name()) 54 | comm.ZipFile(decryptedPath+"/"+file.Name(), decryptedPath+"/"+file.Name()+".zip") 55 | } 56 | } 57 | } 58 | --------------------------------------------------------------------------------