自从聊天软件消息撤回功能问世后,对于撤回的消息,我们对它一直有种强烈的好奇感。“Ta刚撤回了什么?是骂我的话?还是说喜欢我?还是把发给其他人的消息误发给了我?好气呀,都看不到了...”这是我们看到消息被撤回后的内心独白。但是今天,看完了本篇文章你就可以说:

我们看一下效果图,撤回的消息被我们看到了,相当于防(防止)撤回

好了,看完效果,接下来我们看一下怎么找到它的位置,并用代码hook它。

本文用到的软件工具:

  • 微信 2.8.0.121
  • Cheat Engine 7.0(用于内存搜索,下文简称CE)
  • Ollydbg吾爱破解版(用于动态调试,下文简称OD)
  • Visual Studio 2017(用于编写Hook代码,下文简称VS)

用CE打开微信进程

用另一个微信号给在电脑登录的微信号随机发一条消息,勾选UTF-16选项,然后在CE中搜索消息内容

撤回消息,看到一条xml消息,双击它添加到地址列表

打开OD,附加微信进程,用dd命令定位到上面的那个地址

再给电脑登录那个微信号发一条消息,然后在上面那个地址下内存写入断点。为什么是内存写入断点?因为我们上文亲眼目睹了消息撤回后这个地址的字符串被改写了。

下好断点后再把消息撤回,此时断点被触发,微信被断下,断下后,删除内存断点。在栈里寻找我们想要的内容,看到一个包含撤回提示wxid撤回内容的call

在反汇编窗口中跟随这个call,点击这个call,按F2在该call下断点,按F9继续运行。再给在电脑登录那个微信号发一条消息并撤回,该call断下

说明,这个call就是我们要找的消息撤回的位置,而且它有我们想要的数据

找到了call,来整理一下该call的数据,数据都是存在栈里,所以有:

  • esp + 0x4 :撤回消息的提示
  • esp + 0x50 : 撤回消息人的wxid
  • esp + 0x78 : 撤回消息的内容

接下来编写一个dll,来hook这个call,读取esp偏移地址的数据。

在VS创建一个dll项目,核心代码如下:

#include "resource.h"
#include "hook.h"
#include "module.h"
#include <wchar.h>
INT_PTR CALLBACK Dlgproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void DlgThread(HMODULE hInstance); #define REVOCK_CALL_RVA 0x28c33f
#define REVOCK_CALL_TARGET_RVA 0x28ccd0 DWORD revockCallVA = 0;
DWORD revockCallTargetVA = 0;
DWORD revockCallJmpBackVA = 0; DWORD wechatWinAddr = 0;
BYTE backCode[5]; HWND m_dialog_hwnd;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(DlgThread), hModule, 0, NULL);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
} void OnRevock(DWORD esp) {
wchar_t *tips = *(wchar_t **)(esp + 0x4);
wchar_t *msg = *(wchar_t **)(esp + 0x78);
if (NULL != tips) {
WCHAR buffer[0x8192];
wchar_t* pos = wcsstr(tips, L"撤回了一条消息");
if (pos!= NULL && NULL != msg) {
swprintf_s(buffer, L"%s,内容:%s",tips, msg);
SetDlgItemText(m_dialog_hwnd, IDC_EDIT1, buffer);
}
} }
DWORD tEsp = 0;
_declspec(naked) void _OnRevock() {
__asm {
mov tEsp, esp
pushad
}
OnRevock(tEsp);
__asm {
popad
call revockCallTargetVA
jmp revockCallJmpBackVA
}
} void DlgThread(HMODULE hInstance) {
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, Dlgproc);
} INT_PTR CALLBACK Dlgproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG: {
m_dialog_hwnd = hWnd;
wechatWinAddr = GetWxModuleAddress();
revockCallVA = wechatWinAddr + REVOCK_CALL_RVA;
revockCallTargetVA = wechatWinAddr + REVOCK_CALL_TARGET_RVA; revockCallJmpBackVA = revockCallVA + 5;
StartHook5(wechatWinAddr+REVOCK_CALL_RVA,backCode,_OnRevock);
}
break;
case WM_CLOSE:
Unhook5(wechatWinAddr + REVOCK_CALL_RVA, backCode);
EndDialog(hWnd, TRUE);
break;
}
return 0;
}

Hook相关代码:

int StartHook5(DWORD hookAddr, BYTE backCode[5], void(*FuncBeCall)()) {
DWORD jmpAddr = (DWORD)FuncBeCall - (hookAddr + 5); BYTE jmpCode[5];
*(jmpCode + 0) = 0xE9;
*(DWORD *)(jmpCode + 1) = jmpAddr;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, GetCurrentProcessId());
//备份被替换的
if (ReadProcessMemory(hProcess, (LPVOID)hookAddr, backCode, 5, NULL) == 0) {
return -1;
}
//写入jmp指令
if (WriteProcessMemory(hProcess, (LPVOID)hookAddr, jmpCode, 5, NULL) == 0) {
return -1;
} return 0;
} int Unhook5(DWORD hookAddr, BYTE backCode[5]) {
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, GetCurrentProcessId());
if (WriteProcessMemory(hProcess, (LPVOID)hookAddr, backCode, 5, NULL) == 0) {
return -1;
}
return 0;
}

代码写完后,生成dll,把它注入到微信进程,防撤回消息就能实现了。

总结:微信版本一直会变化,相应的hook地址也会改变,但是有了这个思路,它更新版本,我们也能快速的找到call。这个消息撤回的call也比较好找,像我这样初学逆向的朋友可以尝试自己找一下。

PC微信逆向--实现消息防撤回的更多相关文章

  1. Python实现微信消息防撤回

    微信(WeChat)是腾讯公司于2011年1月21日推出的一款社交软件,8年时间微信做到日活10亿,日消息量450亿.在此期间微信也推出了不少的功能如:“摇一摇”.“漂流瓶”.“朋友圈”.“附近的人” ...

  2. macOS 版微信小助手,支持微信多开、防撤回、远程控制mac、自动回复等等

    微信小助手 GitHub大牛提供的微信小助手是一款插件,该插件具备多开.防撤回.免手机认证登录.自动回复.远程控制自己的 macOS.群发等众多功能 GitHub网址:https://github.c ...

  3. Python_20行代码实现微信消息防撤回(简易版)

    学习了一下如何用python实现微信消息的防撤回, 主要思路就是: 时时监控微信,将对方发送的消息缓存下来 如果对方撤回了消息,就将该缓存信息发送给文件传输助手 但其实这功能,基本上毫无意义,看到别人 ...

  4. Python之微信消息防撤回

    #!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = 'jiangwenwen' import itchat from itchat. ...

  5. 电脑微信电脑PC 多开/防撤回 补丁

    简介 经常使用微信电脑版的用户都会发现一个蛋疼的事情,那就是微信PC版不支持多开,也就是不能同时登陆多个账号,这对于需要在电脑上登陆多个微信账号的朋友来说肯定是极其的不方便.另外有的时候别人撤回了一些 ...

  6. 我已经看到了,撤回也没用了(PC微信防撤回补丁)

    前两天看 GitHub 发现一个有趣的项目,PC微信防撤回补丁,本着研究学习的目的,在看过源码,一顿疯狂操作之后,了解了其原理是基于修改 wechatwin.dll 达到防撤回的. 于是乎,自己动手玩 ...

  7. PC端微信防撤回功能分析

    1.打开PC端微信的安装目录,有一个WeChatWin.dll文件,微信的所有功能基本上都在这个文件中了 2.OD打开,搜索字符串revokemsg(撤回消息,掌握一门外语是多么的重要啊!!!),在所 ...

  8. 记录实践PC端微信防撤回实现过程(基于3.1.0.67版本)

    利用OD实现对PC端微信防撤回功能的实现 文章最后有一键补丁工具哦~ 准备工具 1.OD 2.PC微信客户端(3.1.0.67) 过程 1.运行微信客户端,不需要登录 2.运行OD,左上角选择附加进程 ...

  9. [软件逆向]实战Mac系统下的软件分析+Mac QQ和微信的防撤回

      0x00  一点废话 最近因为Mac软件收费的比较多,所以买了几款正版软件,但是有的软件卖的有点贵,买了感觉不值,不买吧,又觉得不方便,用别人的吧,又怕不安全.于是我就买了正版的Hopper Di ...

随机推荐

  1. redis 为什么是单线程,为什么速度快。

    redis 5中存储方式 String.List.Set.Hash.ZSet这5种 数据库的工作模式按存储方式可分为: 硬盘数据库和内存数据库.Redis 将数据储存在内存里面,读写数据的时候都不会受 ...

  2. ASP.Net Core 3.0 中使用JWT认证

    JWT认证简单介绍     关于Jwt的介绍网上很多,此处不在赘述,我们主要看看jwt的结构.     JWT主要由三部分组成,如下: HEADER.PAYLOAD.SIGNATURE HEADER包 ...

  3. 初级程序员如何一分钟?解决一个BUG

    博主说明 -- 重要.重要.重要的事情说三遍 写这篇文章是主要锻炼写博客的能力以及记录自己的成长经历,要是写的不对欢迎大佬评论指正,同时希望对大家有所帮助.然后我写博客尽量简洁+图片+宏观的方式,便于 ...

  4. C#中的结构体和对象区别

    经常听到有朋友在讨论C#中的结构与类有什么区别.正好这几日闲来无事,自己总结一下,希望大家指点. 1. 首先是语法定义上的区别啦,这个就不用多说了.定义类使用关键字class 定义结构使用关键字str ...

  5. Scala实践11

    1.1泛型类 泛型类是将类型作为参数的类.它们对集合类特别有用. 定义泛类型:泛型类将类型作为方括号内的参数[].一种惯例是使用字母A作为类型参数标识符,但是可以使用任何参数名称. class Sta ...

  6. C++Primer第五版 6.1节练习

    练习6.1:实参和形参的区别是什么? 通俗解释: 实参是形参的初始值.编译器能以任意可行的顺序对实参求值.实参的类型必须与对应的形参类型匹配. 详解1) 形参变量只有在函数被调用时才会分配内存,调用结 ...

  7. 字符串转hash

    #include<bits/stdc++.h> using namespace std; unsigned hash[]; ; int ans; int main() { ;k<=; ...

  8. CF 558 C

    Amr loves Chemistry, and specially doing experiments. He is preparing for a new interesting experime ...

  9. electron教程(番外篇二): 使用TypeScript版本的electron, VSCode调试TypeScript, TS版本的ESLint

    我的electron教程系列 electron教程(一): electron的安装和项目的创建 electron教程(番外篇一): 开发环境及插件, VSCode调试, ESLint + Google ...

  10. python3文件操作

    文件操作的过程 1)打开 2)操作 3)关闭 1.写(清空写入) # f = open(file='test', mode='w', encoding='utf-8') # 第一种情况 # f.wri ...