feat:初版
This commit is contained in:
311
WechatHook/loader.py
Normal file
311
WechatHook/loader.py
Normal file
@@ -0,0 +1,311 @@
|
||||
"""
|
||||
NoveLoader - DLL 加载器和函数封装
|
||||
|
||||
基于个微大客户版 Loader.dll 的 Python 封装
|
||||
"""
|
||||
|
||||
import ctypes
|
||||
import os
|
||||
from ctypes import WinDLL, create_string_buffer, WINFUNCTYPE
|
||||
from typing import Callable
|
||||
from loguru import logger
|
||||
|
||||
|
||||
def c_string(data: str) -> ctypes.c_char_p:
|
||||
"""将 Python 字符串转换为 C 字符串"""
|
||||
return ctypes.c_char_p(data.encode('utf-8'))
|
||||
|
||||
|
||||
def create_shared_memory():
|
||||
"""创建共享内存(用于DLL通信)"""
|
||||
try:
|
||||
kernel32 = ctypes.WinDLL('kernel32')
|
||||
|
||||
# 创建文件映射
|
||||
file_handle = kernel32.CreateFileMappingA(
|
||||
-1,
|
||||
None,
|
||||
4, # PAGE_READWRITE
|
||||
0,
|
||||
33,
|
||||
"windows_shell_global__".encode('utf-8')
|
||||
)
|
||||
|
||||
if not file_handle:
|
||||
logger.warning("创建共享内存失败")
|
||||
return None, None
|
||||
|
||||
# 映射到内存
|
||||
data_address = kernel32.MapViewOfFile(
|
||||
file_handle,
|
||||
983071, # FILE_MAP_ALL_ACCESS
|
||||
0,
|
||||
0,
|
||||
0
|
||||
)
|
||||
|
||||
if not data_address:
|
||||
logger.warning("映射共享内存失败")
|
||||
kernel32.CloseHandle(file_handle)
|
||||
return None, None
|
||||
|
||||
# 写入Key数据
|
||||
key = "3101b223dca7715b0154924f0eeeee20".encode('utf-8')
|
||||
kernel32.RtlMoveMemory(data_address, key, len(key))
|
||||
|
||||
logger.success("共享内存创建成功")
|
||||
return file_handle, data_address
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"创建共享内存异常: {e}")
|
||||
return None, None
|
||||
|
||||
|
||||
class NoveLoader:
|
||||
"""
|
||||
Loader.dll 封装类
|
||||
|
||||
通过内存偏移调用 DLL 中的未导出函数
|
||||
"""
|
||||
|
||||
# 加载器模块基址
|
||||
loader_module_base: int = 0
|
||||
|
||||
# 函数偏移地址(基于 Loader.dll)
|
||||
_InitWeChatSocket: int = 0xB080
|
||||
_GetUserWeChatVersion: int = 0xCB80
|
||||
_InjectWeChat: int = 0xCC10
|
||||
_SendWeChatData: int = 0xAF90
|
||||
_DestroyWeChat: int = 0xC540
|
||||
_UseUtf8: int = 0xC680
|
||||
_InjectWeChat2: int = 0x14D7
|
||||
_InjectWeChatPid: int = 0xB750
|
||||
_InjectWeChatMultiOpen: int = 0x33B2
|
||||
|
||||
def __init__(self, loader_path: str):
|
||||
"""
|
||||
初始化 Loader
|
||||
|
||||
Args:
|
||||
loader_path: Loader.dll 的路径
|
||||
"""
|
||||
loader_path = os.path.realpath(loader_path)
|
||||
if not os.path.exists(loader_path):
|
||||
logger.error(f'Loader.dll 不存在: {loader_path}')
|
||||
raise FileNotFoundError(f'Loader.dll 不存在: {loader_path}')
|
||||
|
||||
logger.info(f"加载 Loader.dll: {loader_path}")
|
||||
loader_module = WinDLL(loader_path)
|
||||
self.loader_module_base = loader_module._handle
|
||||
|
||||
# 使用 UTF-8 编码
|
||||
self.UseUtf8()
|
||||
logger.success("Loader.dll 加载成功")
|
||||
|
||||
# 初始化回调
|
||||
from WechatHook.callbacks import (
|
||||
wechat_connect_callback,
|
||||
wechat_recv_callback,
|
||||
wechat_close_callback
|
||||
)
|
||||
self.InitWeChatSocket(
|
||||
wechat_connect_callback,
|
||||
wechat_recv_callback,
|
||||
wechat_close_callback
|
||||
)
|
||||
|
||||
def __get_non_exported_func(self, offset: int, arg_types, return_type):
|
||||
"""
|
||||
通过内存偏移获取未导出的函数
|
||||
|
||||
Args:
|
||||
offset: 函数相对于模块基址的偏移
|
||||
arg_types: 参数类型列表
|
||||
return_type: 返回值类型
|
||||
|
||||
Returns:
|
||||
可调用的函数对象
|
||||
"""
|
||||
func_addr = self.loader_module_base + offset
|
||||
if arg_types:
|
||||
func_type = ctypes.WINFUNCTYPE(return_type, *arg_types)
|
||||
else:
|
||||
func_type = ctypes.WINFUNCTYPE(return_type)
|
||||
return func_type(func_addr)
|
||||
|
||||
def InitWeChatSocket(
|
||||
self,
|
||||
connect_callback: Callable,
|
||||
recv_callback: Callable,
|
||||
close_callback: Callable
|
||||
) -> bool:
|
||||
"""
|
||||
初始化微信 Socket 回调
|
||||
|
||||
Args:
|
||||
connect_callback: 连接回调函数
|
||||
recv_callback: 接收消息回调函数
|
||||
close_callback: 断开连接回调函数
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
func = self.__get_non_exported_func(
|
||||
self._InitWeChatSocket,
|
||||
[ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p],
|
||||
ctypes.c_bool
|
||||
)
|
||||
result = func(connect_callback, recv_callback, close_callback)
|
||||
logger.info(f"InitWeChatSocket: {result}")
|
||||
return result
|
||||
|
||||
def GetUserWeChatVersion(self) -> str:
|
||||
"""
|
||||
获取用户电脑上安装的微信版本
|
||||
|
||||
Returns:
|
||||
微信版本号,如 "3.9.10.19"
|
||||
"""
|
||||
func = self.__get_non_exported_func(
|
||||
self._GetUserWeChatVersion,
|
||||
[ctypes.c_char_p],
|
||||
ctypes.c_bool
|
||||
)
|
||||
out = create_string_buffer(30)
|
||||
if func(out):
|
||||
version = out.value.decode('utf-8')
|
||||
logger.info(f"微信版本: {version}")
|
||||
return version
|
||||
else:
|
||||
logger.warning("获取微信版本失败")
|
||||
return ''
|
||||
|
||||
def InjectWeChat(self, dll_path: str) -> int:
|
||||
"""
|
||||
注入微信(智能多开)
|
||||
|
||||
Args:
|
||||
dll_path: Helper.dll 的路径
|
||||
|
||||
Returns:
|
||||
客户端 ID(进程 ID),失败返回 0
|
||||
"""
|
||||
dll_path = os.path.realpath(dll_path)
|
||||
if not os.path.exists(dll_path):
|
||||
logger.error(f'Helper.dll 不存在: {dll_path}')
|
||||
return 0
|
||||
|
||||
func = self.__get_non_exported_func(
|
||||
self._InjectWeChat,
|
||||
[ctypes.c_char_p],
|
||||
ctypes.c_uint32
|
||||
)
|
||||
client_id = func(c_string(dll_path))
|
||||
if client_id:
|
||||
logger.success(f"注入微信成功,客户端 ID: {client_id}")
|
||||
else:
|
||||
logger.error("注入微信失败")
|
||||
return client_id
|
||||
|
||||
def SendWeChatData(self, client_id: int, message: str) -> bool:
|
||||
"""
|
||||
向微信发送数据
|
||||
|
||||
Args:
|
||||
client_id: 客户端 ID
|
||||
message: JSON 格式的消息
|
||||
|
||||
Returns:
|
||||
是否发送成功
|
||||
"""
|
||||
func = self.__get_non_exported_func(
|
||||
self._SendWeChatData,
|
||||
[ctypes.c_uint32, ctypes.c_char_p],
|
||||
ctypes.c_bool
|
||||
)
|
||||
result = func(client_id, c_string(message))
|
||||
return result
|
||||
|
||||
def DestroyWeChat(self) -> bool:
|
||||
"""
|
||||
销毁微信连接
|
||||
|
||||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
func = self.__get_non_exported_func(
|
||||
self._DestroyWeChat,
|
||||
None,
|
||||
ctypes.c_bool
|
||||
)
|
||||
result = func()
|
||||
logger.info(f"DestroyWeChat: {result}")
|
||||
return result
|
||||
|
||||
def UseUtf8(self) -> bool:
|
||||
"""
|
||||
设置使用 UTF-8 编码
|
||||
|
||||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
func = self.__get_non_exported_func(
|
||||
self._UseUtf8,
|
||||
None,
|
||||
ctypes.c_bool
|
||||
)
|
||||
return func()
|
||||
|
||||
def InjectWeChat2(self, dll_path: str, exe_path: str) -> int:
|
||||
"""
|
||||
注入微信(指定微信路径)
|
||||
|
||||
Args:
|
||||
dll_path: Helper.dll 的路径
|
||||
exe_path: WeChat.exe 的路径
|
||||
|
||||
Returns:
|
||||
客户端 ID,失败返回 0
|
||||
"""
|
||||
func = self.__get_non_exported_func(
|
||||
self._InjectWeChat2,
|
||||
[ctypes.c_char_p, ctypes.c_char_p],
|
||||
ctypes.c_uint32
|
||||
)
|
||||
return func(c_string(dll_path), c_string(exe_path))
|
||||
|
||||
def InjectWeChatPid(self, pid: int, dll_path: str) -> int:
|
||||
"""
|
||||
注入指定的微信进程
|
||||
|
||||
Args:
|
||||
pid: 微信进程 ID
|
||||
dll_path: Helper.dll 的路径
|
||||
|
||||
Returns:
|
||||
客户端 ID,失败返回 0
|
||||
"""
|
||||
func = self.__get_non_exported_func(
|
||||
self._InjectWeChatPid,
|
||||
[ctypes.c_uint32, ctypes.c_char_p],
|
||||
ctypes.c_uint32
|
||||
)
|
||||
return func(pid, c_string(dll_path))
|
||||
|
||||
def InjectWeChatMultiOpen(self, dll_path: str, exe_path: str = "") -> int:
|
||||
"""
|
||||
多开一个新的微信进程并注入
|
||||
|
||||
Args:
|
||||
dll_path: Helper.dll 的路径
|
||||
exe_path: WeChat.exe 的路径(可选)
|
||||
|
||||
Returns:
|
||||
客户端 ID,失败返回 0
|
||||
"""
|
||||
func = self.__get_non_exported_func(
|
||||
self._InjectWeChatMultiOpen,
|
||||
[ctypes.c_char_p, ctypes.c_char_p],
|
||||
ctypes.c_uint32
|
||||
)
|
||||
return func(c_string(dll_path), c_string(exe_path) if exe_path else c_string(""))
|
||||
Reference in New Issue
Block a user