PyWxDump/pywxdump/wx_info/utils.py

145 lines
4.1 KiB
Python
Raw Normal View History

2023-12-25 16:12:39 +08:00
# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name: utils.py
# Description:
# Author: xaoyaoo
# Date: 2023/12/25
# -------------------------------------------------------------------------------
2024-06-03 18:23:25 +08:00
import os
2023-12-25 16:12:39 +08:00
import re
import sys
import hmac
2024-06-05 13:35:20 +08:00
import traceback
2024-05-18 16:35:54 +08:00
import pymem
2023-12-25 16:12:39 +08:00
import hashlib
2024-05-18 16:35:54 +08:00
from win32com.client import Dispatch
2023-12-25 16:12:39 +08:00
2024-06-05 13:33:16 +08:00
def info_error(func):
"""
错误处理装饰器
:param func:
:return:
"""
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
2024-06-05 13:35:20 +08:00
traceback_data = traceback.format_exc()
rdata = f"{traceback_data}"
print(f"info_error: \n{rdata}")
2024-06-05 13:33:16 +08:00
return "None"
return wrapper
2023-12-25 16:12:39 +08:00
def verify_key(key, wx_db_path):
2024-05-18 16:35:54 +08:00
"""
验证key是否正确
"""
2023-12-25 16:12:39 +08:00
KEY_SIZE = 32
DEFAULT_PAGESIZE = 4096
DEFAULT_ITER = 64000
with open(wx_db_path, "rb") as file:
blist = file.read(5000)
salt = blist[:16]
2024-05-18 16:35:54 +08:00
pk = hashlib.pbkdf2_hmac("sha1", key, salt, DEFAULT_ITER, KEY_SIZE)
2023-12-25 16:12:39 +08:00
first = blist[16:DEFAULT_PAGESIZE]
mac_salt = bytes([(salt[i] ^ 58) for i in range(16)])
2024-05-18 16:35:54 +08:00
pk = hashlib.pbkdf2_hmac("sha1", pk, mac_salt, 2, KEY_SIZE)
hash_mac = hmac.new(pk, first[:-32], hashlib.sha1)
2023-12-25 16:12:39 +08:00
hash_mac.update(b'\x01\x00\x00\x00')
if hash_mac.digest() != first[-32:-12]:
return False
return True
2024-06-05 13:35:20 +08:00
@info_error
2023-12-25 16:12:39 +08:00
def get_exe_version(file_path):
"""
获取 PE 文件的版本号
:param file_path: PE 文件路径(可执行文件)
:return: 如果遇到错误则返回
"""
2024-06-03 18:23:25 +08:00
if not os.path.exists(file_path):
return "None"
2023-12-25 16:12:39 +08:00
file_version = Dispatch("Scripting.FileSystemObject").GetFileVersion(file_path)
return file_version
def find_all(c: bytes, string: bytes, base_addr=0):
"""
查找字符串中所有子串的位置
:param c: 子串 b'123'
:param string: 字符串 b'123456789123'
:return:
"""
return [base_addr + m.start() for m in re.finditer(re.escape(c), string)]
def get_exe_bit(file_path):
"""
2024-05-18 16:35:54 +08:00
# 获取exe文件的位数
PE 文件的位数: 32 位或 64
2023-12-25 16:12:39 +08:00
:param file_path: PE 文件路径(可执行文件)
:return: 如果遇到错误则返回 64
"""
try:
with open(file_path, 'rb') as f:
dos_header = f.read(2)
if dos_header != b'MZ':
print('get exe bit error: Invalid PE file')
return 64
# Seek to the offset of the PE signature
f.seek(60)
pe_offset_bytes = f.read(4)
pe_offset = int.from_bytes(pe_offset_bytes, byteorder='little')
# Seek to the Machine field in the PE header
f.seek(pe_offset + 4)
machine_bytes = f.read(2)
machine = int.from_bytes(machine_bytes, byteorder='little')
if machine == 0x14c:
return 32
elif machine == 0x8664:
return 64
else:
print('get exe bit error: Unknown architecture: %s' % hex(machine))
return 64
except IOError:
print('get exe bit error: File not found or cannot be opened')
return 64
def pattern_scan_all(handle, pattern, *, return_multiple=False, find_num=100):
2024-05-18 16:35:54 +08:00
"""
扫描内存中所有匹配的模式
:param handle: 进程句柄
:param pattern: 模式
:param return_multiple: 是否返回所有匹配
:param find_num: 最多查找数量
"""
2023-12-25 16:12:39 +08:00
next_region = 0
found = []
user_space_limit = 0x7FFFFFFF0000 if sys.maxsize > 2 ** 32 else 0x7fff0000
while next_region < user_space_limit:
try:
next_region, page_found = pymem.pattern.scan_pattern_page(
handle,
next_region,
pattern,
return_multiple=return_multiple
)
except Exception as e:
print(e)
break
if not return_multiple and page_found:
return page_found
if page_found:
found += page_found
if len(found) > find_num:
break
return found