天天看點

PC微信逆向--實作消息防撤回

自從聊天軟體消息撤回功能問世後,對于撤回的消息,我們對它一直有種強烈的好奇感。“Ta剛撤回了什麼?是罵我的話?還是說喜歡我?還是把發給其他人的消息誤發給了我?好氣呀,都看不到了...”這是我們看到消息被撤回後的内心獨白。但是今天,看完了本篇文章你就可以說:

PC微信逆向--實作消息防撤回
我們看一下效果圖,撤回的消息被我們看到了,相當于防(防止)撤回
PC微信逆向--實作消息防撤回

好了,看完效果,接下來我們看一下怎麼找到它的位置,并用代碼hook它。

本文用到的軟體工具:

  • 微信 2.8.0.121
  • Cheat Engine 7.0(用于記憶體搜尋,下文簡稱CE)
  • Ollydbg吾愛破解版(用于動态調試,下文簡稱OD)
  • Visual Studio 2017(用于編寫Hook代碼,下文簡稱VS)

用CE打開微信程序

PC微信逆向--實作消息防撤回

用另一個微信号給在電腦登入的微信号随機發一條消息,勾選UTF-16選項,然後在CE中搜尋消息内容

PC微信逆向--實作消息防撤回

撤回消息,看到一條xml消息,輕按兩下它添加到位址清單

PC微信逆向--實作消息防撤回

打開OD,附加微信程序,用dd指令定位到上面的那個位址

PC微信逆向--實作消息防撤回

再給電腦登入那個微信号發一條消息,然後在上面那個位址下記憶體寫入斷點。為什麼是記憶體寫入斷點?因為我們上文親眼目睹了消息撤回後這個位址的字元串被改寫了。

下好斷點後再把消息撤回,此時斷點被觸發,微信被斷下,斷下後,删除記憶體斷點。在棧裡尋找我們想要的内容,看到一個包含撤回提示,wxid和撤回内容的call

PC微信逆向--實作消息防撤回

在反彙編視窗中跟随這個call,點選這個call,按F2在該call下斷點,按F9繼續運作。再給在電腦登入那個微信号發一條消息并撤回,該call斷下

PC微信逆向--實作消息防撤回

說明,這個call就是我們要找的消息撤回的位置,而且它有我們想要的資料

PC微信逆向--實作消息防撤回

找到了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也比較好找,像我這樣初學逆向的朋友可以嘗試自己找一下。視訊教程:https://www.bilibili.com/video/BV1WE411V7ff

繼續閱讀