自从聊天软件消息撤回功能问世后, 对于撤回的消息, 我们对它一直有种强烈的好奇感."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. 在 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 tEax = 0;
- DWORD tEcx = 0;
- DWORD tEdx = 0;
- DWORD tEbx = 0;
- DWORD tEsp = 0;
- DWORD tEbp = 0;
- DWORD tEsi = 0;
- DWORD tEdi = 0;
- _declspec(naked) void _OnRevock() {
- __asm {
- mov tEax, eax
- mov tEcx, ecx
- mov tEdx, edx
- mov tEbx, ebx
- mov tEsp, esp
- mov tEbp, ebp
- mov tEsi, esi
- mov tEdi, edi
- }
- OnRevock(tEsp);
- __asm {
- mov eax, tEax
- mov ecx, tEcx
- mov edx, tEdx
- mov ebx, tEbx
- mov esp, tEsp
- mov ebp, tEbp
- mov esi, tEsi
- mov edi, tEdi
- 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;
- }
代码写完后, 生成 dll, 把它注入到微信进程, 防撤回消息就能实现了.
总结: 微信版本一直会变化, 相应的 hook 地址也会改变, 但是有了这个思路, 它更新版本, 我们也能快速的找到 call. 这个消息撤回的 call 也比较好找, 像我这样初学逆向的朋友可以尝试自己找一下.
来源: https://www.cnblogs.com/luoyesiqiu/p/12318993.html