├── README.md ├── fridaApp.py └── lib ├── get_user.js ├── open_url.js ├── rev_msg.js ├── rev_web.js └── send_msg.js /README.md: -------------------------------------------------------------------------------- 1 | # wechatHookPython 2 | 可实现hook PC微信消息的实时接收处理。 3 | frida使用简单快捷。内部原理也是内联hook方式。 4 | 5 | ## 运行环境 6 | - 语言python 3.7 7 | - 微信PC版本 3.7.6.44 8 | - win10 9 | 10 | ## 使用方法 11 | 1. 安装frida框架 12 | > 在cmd中 13 | ``` 14 | pip install frida 15 | pip install frida-tools 16 | ``` 17 | 18 | 2. 运行fridaApp.py即可 19 | > 在cmd中 20 | ``` 21 | python friaApp.py 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /fridaApp.py: -------------------------------------------------------------------------------- 1 | 2 | baseaddr=0x673D9654 3 | hookaddr =0x66c80000 4 | offset = 0x759654 5 | 6 | import frida 7 | import sys 8 | import codecs 9 | 10 | 11 | def on_message(message, data): 12 | if message['payload']['wxid2'] is None: 13 | print('[个人消息]: ' + message['payload']['wxid'] + ': ' + message['payload']['content']) 14 | else: 15 | print('[群消息]: ' + message['payload']['wxid'] + ': ' + message['payload']['wxid2'] + ': ' + 16 | message['payload']['content']) 17 | 18 | 19 | def main(target_process): 20 | session = frida.attach(target_process) 21 | with codecs.open('lib/rev_msg.js', 'r', 'utf-8') as f: 22 | source = f.read() 23 | script = session.create_script(source) 24 | script.on('message', on_message) 25 | script.load() 26 | print("[!] Ctrl+D on UNIX, Ctrl+Z on Windows/cmd.exe to detach from instrumented program.\n\n") 27 | sys.stdin.read() 28 | session.detach() 29 | 30 | 31 | if __name__ == '__main__': 32 | main('wechat.exe') -------------------------------------------------------------------------------- /lib/get_user.js: -------------------------------------------------------------------------------- 1 | // 功能:用于获取当前聊天窗口的用户信息 2 | 3 | const hook_offset = "0x236dd0" 4 | var ModuleAddress = Process.findModuleByName('wechatwin.dll'); 5 | var hookAddress = ModuleAddress.base.add(hook_offset) 6 | 7 | const mmhead_offset = "0x128" 8 | 9 | Interceptor.attach(hookAddress, { 10 | onEnter: function (args) { 11 | var eax = this.context.eax; 12 | var p_eax = Memory.readPointer(eax); 13 | 14 | // wxid 15 | var wxid = Memory.readUtf16String(p_eax); 16 | 17 | // 自己定的微信id 18 | var n_wxid = Memory.readUtf16String(Memory.readPointer(eax.add('0x3C'))); 19 | 20 | // nickname 21 | var nickname = Memory.readUtf16String(Memory.readPointer(eax.add('0x84'))); 22 | 23 | // 备注名 24 | var note_nickname = Memory.readUtf16String(Memory.readPointer(eax.add('0x70'))); 25 | 26 | // 头像 27 | var mmhead = Memory.readUtf16String(Memory.readPointer(eax.add(mmhead_offset))); 28 | 29 | // CN 30 | var nation = Memory.readUtf16String(Memory.readPointer(eax.add('0x1c8'))); 31 | 32 | // 省 33 | var provinces = Memory.readUtf16String(Memory.readPointer(eax.add('0x1DC'))); 34 | 35 | // 市 36 | var city = Memory.readUtf16String(Memory.readPointer(eax.add('0x1F0'))); 37 | 38 | // 把消息传到方法 39 | send({'wxid': wxid,'n_wxid':n_wxid,'nickname':nickname,'note_nickname':note_nickname, 'mmhead': mmhead, 'nation': nation, 'provinces': provinces,'city':city}) 40 | } 41 | }) 42 | 43 | -------------------------------------------------------------------------------- /lib/open_url.js: -------------------------------------------------------------------------------- 1 | // 功能:用微信浏览器打开指定的url 2 | 3 | // call消息的地址 4 | const hook_offset = "0x1AAA30" //"0x237C9B" 5 | var ModuleAddress = Process.findModuleByName('wechatwin.dll'); 6 | var hookAddress = ModuleAddress.base.add(hook_offset) 7 | 8 | // edx+8 9 | var edx = Memory.alloc(1024); 10 | edx.add(0x8).writeUInt(0x2); 11 | 12 | // edx +34 13 | var url = "https://www.baidu.com"; 14 | var p_url = Memory.alloc(1024); 15 | p_url.writeUtf16String(url); 16 | edx.add(0x34).writePointer(p_url); 17 | edx.add(0x38).writeUInt(url.length); 18 | edx.add(0x3C).writeUInt(url.length); 19 | 20 | var p_edx = Memory.alloc(4); 21 | p_edx.writePointer(edx); 22 | 23 | var ecx = Memory.alloc(1024); 24 | var p_ecx = Memory.alloc(4); 25 | p_ecx.writePointer(ecx); 26 | 27 | 28 | // 写汇编 29 | const open_url = Memory.alloc(Process.pageSize); 30 | Memory.patchCode(open_url, 128, code => { 31 | const cw = new X86Writer(code, { pc: open_url }); 32 | cw.putPushNearPtr(p_edx); // push eax 33 | cw.putMovRegNearPtr('ecx',p_ecx) // exc 34 | cw.putCallAddress(hookAddress) 35 | // cw.putMovRegU32('al',0x1) // 不知道为什么报错,算了不搞了 36 | cw.putPopReg('esi'); 37 | cw.putMovRegReg('ecx','esi') 38 | cw.putPopReg('ebp'); 39 | cw.putRet(); 40 | cw.flush(); 41 | }) 42 | const call = new NativeFunction(open_url, 'void', []) 43 | console.log('call - address:',call); 44 | call() 45 | 46 | -------------------------------------------------------------------------------- /lib/rev_msg.js: -------------------------------------------------------------------------------- 1 | var ModuleAddress = Process.findModuleByName('wechatwin.dll'); 2 | //console.log('ModAdress:' + ModAddress.base); 3 | var hookAddress = ModuleAddress.base.add('0x759654') 4 | //console.log('hookAdress' + hookAddress.base) 5 | Interceptor.attach(hookAddress, { 6 | onEnter: function (args) { 7 | var edi = this.context.esi; 8 | var edi1 = Memory.readPointer(edi) 9 | // 发送消息类型 10 | var type = Memory.readPointer(edi1.add('0x38')).toInt32(); 11 | // 发送者微信id 12 | var wxid = Memory.readUtf16String(Memory.readPointer(edi1.add('0x48'))); 13 | // 发送消息内容 14 | var content = Memory.readUtf16String(Memory.readPointer(edi1.add('0x70'))); 15 | // 群聊时 发送人的wxid 16 | var wxid2 = Memory.readUtf16String(Memory.readPointer(edi1.add('0x174'))); 17 | 18 | // 把消息传到方法 19 | send({'wxid': wxid, 'content': content, 'wxid2': wxid2, 'type': type, 'self': self}) 20 | } 21 | }) -------------------------------------------------------------------------------- /lib/rev_web.js: -------------------------------------------------------------------------------- 1 | // 功能:获取微信内跳转打开的网页 2 | 3 | const receWebURL_offset = "0x68F558" 4 | 5 | var ModuleAddress = Process.findModuleByName('wechatwin.dll'); 6 | var hookAddress = ModuleAddress.base.add(receWebURL_offset) 7 | Interceptor.attach(hookAddress, { 8 | onEnter: function (args) { 9 | var edx = this.context.edx; 10 | var p_edx = Memory.readPointer(edx) 11 | // 微信浏览器的url 12 | var url = Memory.readUtf8String(p_edx); 13 | // 把消息传到方法 14 | send({'url': url,'p_edx':p_edx}) 15 | 16 | 17 | var eax = this.context.eax; 18 | var p_eax8 = Memory.readPointer(eax.add('0x8')) 19 | // 微信浏览器的url 20 | var url = Memory.readUtf8String(p_eax8); 21 | // 把消息传到方法 22 | send({'url': url,'p_eax8':p_eax8}) 23 | } 24 | }) -------------------------------------------------------------------------------- /lib/send_msg.js: -------------------------------------------------------------------------------- 1 | // 功能:发送消息hook 2 | 3 | // call消息的地址 4 | const hook_offset = "0x5CD2E0" //"0x237C9B" 5 | var ModuleAddress = Process.findModuleByName('wechatwin.dll'); 6 | var hookAddress = ModuleAddress.base.add(hook_offset) 7 | 8 | // 接收者结构体 wx_id,len(wx_id),len(wx_id) 9 | 10 | // 1. 申请12个字节 11 | var sturc_wxid = Memory.alloc(3*4) 12 | 13 | // 2. 写入wxid 14 | var wxid = 'filehelper' 15 | var p_wxid = Memory.allocUtf16String(wxid) 16 | sturc_wxid.writePointer(p_wxid) 17 | // 写长度 18 | sturc_wxid.add(0x4).writeUInt(wxid.length) 19 | sturc_wxid.add(0x8).writeUInt(wxid.length) 20 | var p_sturc_wxid = Memory.alloc(4) 21 | p_sturc_wxid.writePointer(sturc_wxid) 22 | 23 | 24 | // 发送内容的结构体 msg,len(msg),len(msg) 25 | // 3. 写发送文本内容 26 | var msg = 'nihao' 27 | var sturc_msg = Memory.alloc(3*4) 28 | var p_msg = Memory.allocUtf16String(msg) 29 | sturc_msg.writePointer(p_msg) 30 | 31 | // 写长度 32 | sturc_msg.add(0x4).writeUInt(msg.length) 33 | sturc_msg.add(0x8).writeUInt(msg.length) 34 | var p_sturc_msg = Memory.alloc(4) 35 | p_sturc_msg.writePointer(sturc_msg) 36 | 37 | // 写buffer 38 | var p_ecx = Memory.alloc(4) 39 | var buffer = Memory.alloc(1024) 40 | p_ecx.writePointer(buffer); 41 | 42 | // 写汇编 43 | const sendMsg_func = Memory.alloc(Process.pageSize); 44 | Memory.patchCode(sendMsg_func, 128, code => { 45 | const cw = new X86Writer(code, { pc: sendMsg_func }); 46 | 47 | cw.putPushU32(0) // esi+4 48 | 49 | cw.putPushU32(0) // 0x0 50 | cw.putPushU32(1) // 0x1 51 | cw.putPushU32(0) // eax 52 | cw.putPushNearPtr(p_sturc_msg) // edi 53 | 54 | cw.putMovRegNearPtr('edx',p_sturc_wxid) // edx wxid 55 | cw.putMovRegNearPtr('ecx',p_ecx) // exc 56 | 57 | cw.putCallAddress(hookAddress) 58 | cw.putAddRegImm('esp', 0x14) 59 | 60 | cw.putRet(); 61 | cw.flush(); 62 | }) 63 | const call = new NativeFunction(sendMsg_func, 'void', []) 64 | console.log('call - address:',call); 65 | call() 66 | 67 | --------------------------------------------------------------------------------