xaoyaoo / PyWxDump

获取微信信息;读取数据库,本地查看聊天记录并导出为csv、html等格式用于AI训练,自动回复等。支持多账户信息获取,支持所有微信版本。
Other
5.62k stars 917 forks source link

关于遍历找key (`def get_key(pid, db_path, addr_len):`) #102

Closed TaihouKai closed 4 months ago

TaihouKai commented 4 months ago

我自己手动写代码测试了这个遍历找key的get_key function:

void_p = ctypes.c_void_p
addr_len = 64
pid = 9092
pm = pymem.Pymem(pid)
module_name = "WeChatWin.dll"
MicroMsg_path = "MicroMsg.db"
MicroMsg_path = os.path.join("C:\\Users\\<USERNAME>\\Documents\\WeChat Files\\wxid_<ID>\\", "MSG", "MicroMsg.db")
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory

def read_key_bytes(h_process, address, address_len=8):
  # ... copy-paste

def verify_key(key, wx_db_path):
  # ... copy-paste

phone_type1 = "iphone\x00"
phone_type2 = "android\x00"
phone_type3 = "ipad\x00"

type1_addrs = pm.pattern_scan_module(phone_type1.encode(), module_name, return_multiple=True)
type2_addrs = pm.pattern_scan_module(phone_type2.encode(), module_name, return_multiple=True)
type3_addrs = pm.pattern_scan_module(phone_type3.encode(), module_name, return_multiple=True)
if type1_addrs == None or type2_addrs == None or type3_addrs == None:
    print("Error: pattern_scan_module failed")
    exit()

print(type1_addrs, type2_addrs, type3_addrs)

type_addrs = []
if len(type1_addrs) >= 2: type_addrs += type1_addrs
if len(type2_addrs) >= 2: type_addrs += type2_addrs
if len(type3_addrs) >= 2: type_addrs += type3_addrs
if len(type_addrs) == 0:
    print("Error: type_addrs is empty")
    exit()

type_addrs.sort()
print(type_addrs)

for i in type_addrs[::-1]:
    for j in range(i, i - 2000, -addr_len):
        key_bytes = read_key_bytes(pm.process_handle, j, addr_len)
        if key_bytes == "None":
            continue
        # print(key_bytes.hex())
        if verify_key(key_bytes, MicroMsg_path):
            key = key_bytes.hex()

print(key)

我发现addr_len=64的情况下找不到key,只有在addr_len=16或者8的情况下可以。 (我试过get_exe_bit,确实返回的是64) 请问这是为什么?

simoole commented 4 months ago

因为key是个32位的字节串

TaihouKai commented 4 months ago

因为key是个32位的字节串

感谢回复。如果按照代码里的话,get_exe_bit会返回64吧?(因为是64位的exe) 那样的话addr_len就得是64了……?

(get_wx_info.py)

addrLen = get_exe_bit(process.exe())
...
...
if rd['filePath'] != "None" and rd['key'] == "None" and not isKey:
    rd['key'] = get_key(rd['pid'], rd['filePath'], addrLen) 
xaoyaoo commented 4 months ago

这个和系统位数以及内存读写方式有关。 32位系统和64位系统,对内存读写单元大小不同。

TaihouKai commented 4 months ago

这个和系统位数以及内存读写方式有关。 32位系统和64位系统,对内存读写单元大小不同。

感谢回复。 这样的话,如果我要手动复现遍历,请问这个地方的for j in range(i, i - 2000, -addr_len):是不是该改成-int(addr_len/8),以匹配读写单元的大小(4/8 bytes)?我试了下,不改成/8的话在我的电脑上遍历不着key

for i in type_addrs[::-1]:
    for j in range(i, i - 2000, -addr_len):
        key_bytes = read_key_bytes(pm.process_handle, j, addr_len)
        if key_bytes == "None":
            continue
        # print(key_bytes.hex())
        if verify_key(key_bytes, MicroMsg_path):
            key = key_bytes.hex()
xaoyaoo commented 4 months ago

@TaihouKai 所以你已经有了结论。