各位老爷看官好。
最近在研究企微hook c++源码 改python源码。
目前注入是会了,注入的脚本也能被调用,主要是读取消息内容不会用。
不知道有没有大佬会这个。
企业微信4.1.2.6014版本 。
https://dldir1.qq.com/wework/work_weixin/WeCom_4.1.2.6014.exe
有大佬会的话,可以改一下代码实现读取消息内容。
后续我会放出来所有源码提供给能改的人。一起探讨研究院。
有兴趣可以加群研究。QQ群:684380330
目前放出来的是PC发送消息回调
注入地址 : 基址 + 0x3C12D57
贴上python 代码:
import frida
import sys
import pymem
# 目标函数的入口地址
def calculate_address(process_id, address_expression: str) -> int:
"""
计算地址表达式的函数
:param pid: 目标进程的PID
:param address_expression: 包含模块地址和偏移地址的表达式,例如 "module_address+offset",或者只包含模块地址的情况
:return: 计算后的地址值,如果表达式无效,则返回None
"""
if not isinstance(process_id, int) or not isinstance(address_expression, str):
print(1)
print("Error: Invalid input parameters.")
return None
if '+' in address_expression:
print(2)
module_address, offset = address_expression.split('+')
offset = int(offset, 16) # 将偏移地址转换为整数类型
else:
print(3)
module_address = address_expression
offset = 0
try:
process = pymem.Pymem(process_id)
except pymem.exception.ProcessNotFound:
print(f"Error: Process with PID {process_id} not found.")
return None
module_base = None
print(4)
for module in process.list_modules():
print(5)
if module.name == module_address:
module_base = module.lpBaseOfDll
break
if not module_base:
print(6)
print(f"Error: Module {module_address} not found.")
return None
final_address = module_base + offset
return final_address
# 目标进程名称或进程ID
target_process_name = "WXWork.exe"
# 通过目标进程名称或进程ID连接到目标进程
# session = frida.attach(target_process_name)
session = frida.attach(12624)
# process = pymem.Pymem('WXWork.exe')
# module = pymem.process.module_from_name(process.process_handle, 'WXWork.exe').lpBaseOfDll
# print("企业微信基址:",module)
# root_addr = pymem.memory.read_int(process.process_handle, module + 0x325AD0)
# print(root_addr)
# print(hex(root_addr))
#
# root_addr = pymem.memory.read_int(process.process_handle, root_addr)
# print(root_addr)
# 获取进程ID
pid = session._impl.pid
print(pid)
# 在目标进程中加载Frida脚本
target_address = calculate_address(pid, 'WXWork.exe+3BAC9EE')
# 创建Frida脚本
script_code = """
Interceptor.attach(ptr(%s), {
onEnter: function (args) {
console.log('目标函数被调用!');
var arg_num = 5
for (var i = 0; i < arg_num; i++) {
console.log('arg[' + i + ']: ' + args[i].toString());
}
},
onLeave: function (retval) {
console.log('目标函数执行完毕!');
console.log('返回值:', retval);
}
});
""" % hex(target_address)
script = session.create_script(script_code)
# 定义消息处理函数
def on_message(message, data):
print("1231")
print(message)
print(data)
if 'payload' in message:
print(message['payload'])
# 注册消息处理函数
script.on('message', on_message)
# 加载并运行Frida脚本
script.load()
try:
# 保持会话持续运行
sys.stdin.read()
except KeyboardInterrupt:
pass
finally:
# 释放资源
session.detach()
放出来C++代码供大佬研究:
//hookPc发送消息打印
void HookRecvPcMsg()
{
if (NULL == RecvPcHookEntity) {
RecvPcHookEntity = new EVInlineReplaceHook();
}
//hook地址
DWORD hookAdd = getWxWorkAddBase() + 0x3C12D57;
//hook回调地址
LPVOID jmpAddress = &decRecvPcMsg;
BYTE JmpCode[5] = { 0 };
// E9 11051111(这里是跳转的地方这个地方不是一个代码地址 而是根据hook地址和跳转的代码地址的距离计算出来的)
JmpCode[0] = 0xE9; //jmp的硬编等于0xE9
//跳转地址减去hook地址-5就等于你的 地址硬编码
*(DWORD*)&JmpCode[1] = (DWORD)jmpAddress - hookAdd - HOOK_LEN;//5
BOOL state = RecvPcHookEntity->StartReplace(hookAdd, JmpCode, 5);
if (state == TRUE) {
// DbgPrintf(_T("[REPLACE_HOOK] hook消息成功"));
P_LOG_INFO("[HookRecvPcMsg_REPLACE_HOOK] hook消息成功", __FILE__, __LINE__);
}
}
//消息hook打印
DWORD recvPcMsgEax = { 0 };
DWORD recvPcMsgCallAdd = { 0 };
DWORD recvPcMsgJmp = { 0 };
void __declspec(naked) decRecvPcMsg() {
__asm {
pushad
mov recvPcMsgEax, eax
}
RecvPcMsgRes(recvPcMsgEax);
recvPcMsgCallAdd = getWxWorkAddBase() + 0x3BAC9EE;
recvPcMsgJmp = getWxWorkAddBase() + 0x3C12D57 + 0x5;
__asm {
popad
call recvPcMsgCallAdd
jmp recvPcMsgJmp
}
}
//获取微信模块基址
DWORD getWxWorkAddBase()
{
DWORD wechatWinBaseAddress = (DWORD)LoadLibrary(L"WXWork.exe");
return wechatWinBaseAddress;
}