吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3961|回复: 31
上一主题 下一主题
收起左侧

[调试逆向] 微信逆向:hook 强制输出调试信息

  [复制链接]
跳转到指定楼层
楼主
kn0sky 发表于 2024-7-2 09:34 回帖奖励
本帖最后由 kn0sky 于 2024-7-3 19:50 编辑

本文仅用于学习研究,请勿用于非法用途和商业用途!如因此产生任何法律纠纷,均与作者无关!

环境准备

  • wechat x64版本
  • x64dbg
  • ida 或者 ghidra
  • debugview++
  • Visual Studio 2022

定位调试信息函数

对于大型软件来说,由于其庞大复杂的功能,为了开发人员更好的定位 bug,会输出调试信息辅助调试,对于逆向来说,有调试信息也会有助于更好的定位功能点

调试信息一般是固定格式的字符串,例如:日期 - 功能 - 函数名 - 文件名

定位调试信息的方法:找到固定格式大量出现的字符串,然后都点进去看看是不是同一个函数

对于微信来说,在查看核心模块wechatwin.dll的时候,就会看到很多疑似调试信息的伪代码,例如:(这里我进行了函数重命名)

    log_message(
      2,
      (__int64)"D:\\Tools\\agent\\workspace\\MicroMsgWindowsV3911\\MicroMsgWin\\01_ui\\chatroom\\ChatMsgList.cpp",
      35,
      (__int64)"ChatMsgList::InsertChatItem",
      "ChatMsgList",
      "InsertChatItem msg svrid : %d, pre localid : %d",
      &v13,
      &v12,
      v17,
      &v16,
      &v15,
      &v14);

后来调试发现,确实是这个函数在拼接调试信息,但是没有打印出来,这里应该是微信禁用了调试信息的输出

既然如此,那就手动打印调试信息吧,hook 该函数获取调试信息进行手动打印输出

还有一个思路找日志函数(参考资料[0]),搜索代码文件的.cpp后缀

分析 hook 点

参考资料[0]找的日志信息位于日志函数执行时候的栈信息,要实现从栈中拿数据,只需要写dll注入,hook有数据的那个地方,读取栈指针去读取内容

但是我是个懒人,能自动就不想手动,hook库detours似乎只能hook函数开头的位置(hook其他地方之后,补的指令有问题)

所以就找找内部某个函数的参数或者返回值是否满足我的要求:具有完整的日志信息

完整伪代码:

void log_message(
        int a1,
        __int64 a2,
        int a3,
        __int64 a4,
        const char *a5,
        const char *a6,
        __int128 *a7,
        __int128 *a8,
        __int128 *a9,
        __int128 *a10,
        __int128 *a11,
        __int128 *a12,
        ...)
{
  __int128 *v15; // rax
  __int64 v16; // rcx
  const char *v17; // rsi
  int v18; // ecx
  __int64 v19; // r9
  __int128 *v20; // r8
  char *v21; // rdi
  __int64 v22; // rdi
  _BYTE *v23; // rdx
  DWORD CurrentThreadId; // [rsp+50h] [rbp-B0h]
  int v26; // [rsp+80h] [rbp-80h] BYREF
  char *v27; // [rsp+88h] [rbp-78h]
  __int64 v28; // [rsp+90h] [rbp-70h]
  __int64 v29; // [rsp+98h] [rbp-68h]
  int v30; // [rsp+A0h] [rbp-60h]
  char v31[12]; // [rsp+A4h] [rbp-5Ch] BYREF
  __int64 v32; // [rsp+B0h] [rbp-50h]
  __int64 v33; // [rsp+B8h] [rbp-48h]
  __int64 v34; // [rsp+C0h] [rbp-40h]
  struct _SYSTEMTIME SystemTime; // [rsp+D0h] [rbp-30h] BYREF
  void *Src; // [rsp+E0h] [rbp-20h] BYREF
  int v37; // [rsp+E8h] [rbp-18h]
  int v38; // [rsp+ECh] [rbp-14h]
  char v39[4104]; // [rsp+F0h] [rbp-10h] BYREF
  __int128 v40[6]; // [rsp+10F8h] [rbp+FF8h] BYREF
  int v41; // [rsp+1158h] [rbp+1058h]
  int v42; // [rsp+115Ch] [rbp+105Ch]
  __int128 v43[6]; // [rsp+1160h] [rbp+1060h] BYREF
  char Buffer[16]; // [rsp+11C0h] [rbp+10C0h] BYREF
  __int128 v45; // [rsp+11D0h] [rbp+10D0h]
  __int128 v46; // [rsp+11E0h] [rbp+10E0h]
  __int128 v47; // [rsp+11F0h] [rbp+10F0h]
  char v48[256]; // [rsp+1200h] [rbp+1100h] BYREF

  if ( sub_183CEBBD0(a1) )
  {
    v15 = v40;
    v16 = 6i64;
    do
    {
      *(_BYTE *)v15++ = -1;
      --v16;
    }
    while ( v16 );
    v39[0] = 0;
    Src = v39;
    v38 = 4096;
    v17 = 0i64;
    v37 = 0;
    v41 = 0;
    v18 = 0;
    v42 = 0;
    v43[0] = *a7;
    v43[1] = *a8;
    v43[2] = *a9;
    v43[3] = *a10;
    v43[4] = *a11;
    v43[5] = *a12;
    v19 = 0i64;
    v20 = v43;
    do
    {
      if ( *(_BYTE *)v20 == 0xFF )
        break;
      v40[v18] = *v20;
      v18 = ++v42;
      ++v19;
      ++v20;
    }
    while ( v19 < 6 );
    sub_18260E7A0(&Src, a6, v20, v19);
    sub_18260E3B0((__int64)&Src, 1);
    if ( Src )
      *((_BYTE *)Src + v37++) = 10;
    GetLocalTime(&SystemTime);
    v21 = (&off_184F54F80)[a1 % 5];
    CurrentThreadId = GetCurrentThreadId();
    snprintf(
      v48,
      (const char *const)0x100,
      "(%d-%d-%d:%d:%02d:%02d:%03d %05d)-%s/%s:",
      SystemTime.wYear,
      SystemTime.wMonth,
      SystemTime.wDay,
      SystemTime.wHour,
      SystemTime.wMinute,
      SystemTime.wSecond,
      SystemTime.wMilliseconds,
      CurrentThreadId,
      v21,
      a5);
    if ( v48[0] )
    {
      v22 = -1i64;
      do
        ++v22;
      while ( v48[v22] );
      sub_18260E3B0((__int64)&Src, v22);
      v23 = Src;
      if ( Src )
      {
        memmove((char *)Src + (int)v22, Src, v37 + 1);
        memmove(Src, v48, (int)v22);
        v37 += v22;
        v23 = Src;
        v17 = (char *)Src + (int)v22;
      }
    }
    else
    {
      v23 = Src;
    }
    v23[v37] = 0;
    v26 = a1;
    *(_OWORD *)Buffer = 0i64;
    v45 = 0i64;
    v46 = 0i64;
    v47 = 0i64;
    snprintf(Buffer, (const char *const)0x40, "%s%s", "MMPC_", a5);
    v27 = Buffer;
    v28 = a2;
    v29 = a4;
    v30 = a3;
    sub_183CF40E0(v31, 0i64);
    v32 = sub_183CF41C0();
    v33 = sub_183CF4230();
    v34 = sub_183CF41B0();
    sub_183CEBC10((__int64)&v26, v17);
    if ( Src != v39 )
      free(Src);
  }
}

中间有snprintf的拼接字符串,完整的日志信息在这后面,分析代码可以看到,日志信息保存在了Src变量里,而这个v39也是来自Src变量

一般来说,一个函数的前面都是在为功能做准备,做好准备后执行,最后的函数就很可疑:sub_183CEBC10,但是劫持这里没法从参数中获得完整日志信息,只能获得部分

经过分析,看反汇编:

.text:000000018260F0C4                 nop
.text:000000018260F0C5                 lea     rax, [rbp+1250h+var_1260] ; v39
.text:000000018260F0C9                 mov     rcx, [rbp+1250h+Src] ; Block
.text:000000018260F0CD                 cmp     rcx, rax
.text:000000018260F0D0                 jz      short loc_18260F0D7
.text:000000018260F0D2                 call    free
.text:000000018260F0D7
.text:000000018260F0D7 loc_18260F0D7:                          ; CODE XREF: log_message+56↑j
.text:000000018260F0D7                                         ; log_message+320↑j
.text:000000018260F0D7                 mov     rcx, [rbp+1250h+var_50]
.text:000000018260F0DE                 xor     rcx, rsp        ; StackCookie
.text:000000018260F0E1                 call    __security_check_cookie
.text:000000018260F0E6                 add     rsp, 1318h
.text:000000018260F0ED                 pop     r15
.text:000000018260F0EF                 pop     r14
.text:000000018260F0F1                 pop     r13
.text:000000018260F0F3                 pop     r12
.text:000000018260F0F5                 pop     rdi
.text:000000018260F0F6                 pop     rsi
.text:000000018260F0F7                 pop     rbx
.text:000000018260F0F8                 pop     rbp
.text:000000018260F0F9                 retn

log_message 函数的末尾有一个比较,v39和Src变量的比较,比较完成之后,如果相同就返回

这里log_message函数的类型是void,无返回值,但实际返回的时候,rax的值是Src指针,其实是返回了东西的,这个Src指针指向局部变量,很快就会被覆盖

所以这里的思路是,直接hook log_message函数,执行log_message函数,拿到返回值,复制走返回值的字符串,然后OutputDebugStringA打印调试信息

代码实现(核心)

定义函数原型定成返回char*来接收指针

接收到之后立马复制走里面的数据避免被覆盖,因为该指针指向的栈数组的生命周期已经结束了,数据随时有被覆盖的风险

然后这里的异常处理是为了应对一些特殊情况:

  • 返回空,例如:NULL
  • 返回非指针数据,例如:1
#include "pch.h"
#include "selHook.h"

typedef char*(__fastcall* _log_message)(
    int a1,
    __int64 a2,
    int a3,
    __int64 a4,
    const char* a5,
    const char* a6,
    __int128* a7,
    __int128* a8,
    __int128* a9,
    __int128* a10,
    __int128* a11,
    __int128* a12
    );

_log_message flog_message;
char* __fastcall Mylog_message(
    int a1,
    __int64 a2,
    int a3,
    __int64 a4,
    const char* a5,
    const char* a6,
    __int128* a7,
    __int128* a8,
    __int128* a9,
    __int128* a10,
    __int128* a11,
    __int128* a12
) {
    char* tmp = flog_message(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
    __try {
        if (tmp == NULL) return NULL;
        int len = strlen(tmp);
        char log[0x1000];
        strncpy_s(log, tmp, len < 0x1000 ? len : 0x1000);
        OutputDebugStringA(log);
        return tmp;

    }
    __except(1){
        return NULL;
    }
}

void SetHook() {
    HMODULE hMod = GetModuleHandleA("WeChatWin.dll");
    flog_message = (_log_message)((unsigned long long)hMod + FUNCTION_log);

    // Initiate the detours hooks
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());

    // Set our hooks
    DetourAttach(&(PVOID&)flog_message, Mylog_message);

    // Apply our hooks
    LONG error = DetourTransactionCommit();
    if (error != NO_ERROR)
    {
        printf("Failed to commit hooks\n");
        exit(1);
    }

}

实现效果

使用debugview++接收调试信息,得到完整调试信息:

1        0.000000        20528        WeChat.exe        (2024-7-2:9:21:34:058 01924)-i/LoginWnd:click login btn
2        0.003215        20528        WeChat.exe        (2024-7-2:9:21:34:058 01924)-i/QRCodeLoginMgr:killTimer
3        0.003371        20528        WeChat.exe        (2024-7-2:9:21:34:058 01924)-i/NetScenePushLoginURL:new NetScenePushLoginURL (id:5)
4        0.008051        20528        WeChat.exe        (2024-7-2:9:21:34:068 01924)-i/NetScenePushLoginURL:doSceneImpl(id:5)
5        0.008201        20528        WeChat.exe        (2024-7-2:9:21:34:068 01924)-i/QRCodeLoginMgr:qrCodeLogin mgr reset()
6        0.008337        20528        WeChat.exe        (2024-7-2:9:21:34:068 01924)-i/WCSMgr:Start Get CCData is Need Verify File Sign : 0
7        0.022331        20528        WeChat.exe        (2024-7-2:9:21:34:085 01924)-i/WCSMgr:Finish Get CCData cost : 17
8        0.022471        20528        WeChat.exe        (2024-7-2:9:21:34:085 01924)-i/WCSMgr:data size : 2826 md5 :b0c72a2b6f30e98bb6d7c9217faa1489
9        0.022644        20528        WeChat.exe        (2024-7-2:9:21:34:085 01924)-i/NetSceneBase:in send NetScenePushLoginURL(id:5)
10        0.023630        20528        WeChat.exe        (2024-7-2:9:21:34:085 32620)-i/EcdhInfo:getLoginEcdh. use ml cert.
11        0.025080        20528        WeChat.exe        (2024-7-2:9:21:34:088 32620)-i/NetSceneBase:EncodeHybirdEncryptPack,1
12        0.025254        20528        WeChat.exe        (2024-7-2:9:21:34:088 32620)-i/NetSceneBaseEx:out NetScenePushLoginURL::req2Buf size:3889, id:5
13        0.267871        20528        WeChat.exe        (2024-7-2:9:21:34:328 32620)-i/NetSceneBaseEx:decoede with random key
14        0.268586        20528        WeChat.exe        (2024-7-2:9:21:34:328 32620)-i/NetSceneBaseEx:out NetScenePushLoginURL::buf2Resp unpackSize: 128, id:5
15        0.268842        20528        WeChat.exe        (2024-7-2:9:21:34:328 32620)-i/WinMarsMgr:onGYNetEnd sceneID:5 errType:0  errCode:0
16        0.270117        20528        WeChat.exe        (2024-7-2:9:21:34:328 01924)-i/NetScenePushLoginURL:onGYNetEnd(errType:0, errCode:0, sceneID:5)
17        0.271740        20528        WeChat.exe        (2024-7-2:9:21:34:328 01924)-i/NetScenePushLoginURL:scene: 0, flag: 0, alertCode:0
18        0.272301        20528        WeChat.exe        (2024-7-2:9:21:34:328 01924)-i/NetScenePushLoginURL:pushLoginURL success, UUID = 略 , checkTime = 15锛?m_expiredTime = 290
19        0.273595        20528        WeChat.exe        (2024-7-2:9:21:34:328 01924)-i/NetScenePushLoginURL:~NetScenePushLoginURL (id:5)
20        0.275985        20528        WeChat.exe        (2024-7-2:9:21:34:338 01924)-i/LoginWnd:ON_NETSCENE_PUSH_LOGIN_URL_SUCCESS
21        0.276295        20528        WeChat.exe        (2024-7-2:9:21:34:340 01924)-i/QRCodeLoginMgr:delayCheck
22        0.276557        20528        WeChat.exe        (2024-7-2:9:21:34:340 01924)-i/Utils:get UILanguage from Sys. 2052
23        1.708338        20528        WeChat.exe        (2024-7-2:9:21:35:772 32620)-i/WinMarsMgr:onNotify seq:default-longlink  cmd:231
24        1.708593        20528        WeChat.exe        (2024-7-2:9:21:35:772 32620)-i/NotifyMgr:Receive a LOGIN_QRCOCE_NOTIFY
25        1.708720        20528        WeChat.exe        (2024-7-2:9:21:35:772 32620)-i/NotifyMgr:Decrypt qrcode notify Pack Success!
26        1.709628        20528        WeChat.exe        (2024-7-2:9:21:35:773 01924)-i/LoginWnd:qrCodeScaned
27        1.709775        20528        WeChat.exe        (2024-7-2:9:21:35:773 01924)-i/LoginWnd:scan status = 1
28        1.709900        20528        WeChat.exe        (2024-7-2:9:21:35:773 01924)-i/AccountService:phone type = 
29        1.710002        20528        WeChat.exe        (2024-7-2:9:21:35:773 01924)-i/QRCodeLoginMgr:PhoneVersion 0
30        1.710126        20528        WeChat.exe        (2024-7-2:9:21:35:773 01924)-i/QRCodeLoginMgr:URL Expired Time = 0
31        15.276283        20528        WeChat.exe        (2024-7-2:9:21:49:338 01924)-i/QRCodeLoginMgr:OnCheckQrCodeTimerCallback
32        15.277088        20528        WeChat.exe        (2024-7-2:9:21:49:338 01924)-i/NetSceneCheckLoginQRCode:new NetSceneCheckLoginQRCode (id:6)
33        15.277392        20528        WeChat.exe        (2024-7-2:9:21:49:338 01924)-i/EcdhInfo:getLoginEcdh. use ml cert.
34        15.277678        20528        WeChat.exe        (2024-7-2:9:21:49:338 01924)-i/NetSceneBase:in send NetSceneCheckLoginQRCode(id:6)
35        15.278189        20528        WeChat.exe        (2024-7-2:9:21:49:338 32620)-i/EcdhInfo:getLoginEcdh. use ml cert.
36        15.279678        20528        WeChat.exe        (2024-7-2:9:21:49:338 32620)-i/NetSceneBase:EncodeHybirdEncryptPack,1
37        15.279953        20528        WeChat.exe        (2024-7-2:9:21:49:338 32620)-i/NetSceneBaseEx:out NetSceneCheckLoginQRCode::req2Buf size:337, id:6
38        15.469843        20528        WeChat.exe        (2024-7-2:9:21:49:534 32620)-i/NetSceneBaseEx:decoede with random key
39        15.470510        20528        WeChat.exe        (2024-7-2:9:21:49:535 32620)-i/NetSceneBaseEx:out NetSceneCheckLoginQRCode::buf2Resp unpackSize: 228, id:6
40        15.470759        20528        WeChat.exe        (2024-7-2:9:21:49:535 32620)-i/WinMarsMgr:onGYNetEnd sceneID:6 errType:0  errCode:0
41        15.470942        20528        WeChat.exe        (2024-7-2:9:21:49:535 01924)-i/NetSceneCheckLoginQRCode:onGYNetEnd(errType:0, errCode:0, sceneID:6)
42        15.472293        20528        WeChat.exe        (2024-7-2:9:21:49:535 01924)-i/NetSceneCheckLoginQRCode:status:1, hdimg:http://wx.q (略)
43        15.472516        20528        WeChat.exe        (2024-7-2:9:21:49:537 01924)-i/NetSceneCheckLoginQRCode:~NetSceneCheckLoginQRCode (id:6)
44        15.472720        20528        WeChat.exe        (2024-7-2:9:21:49:537 01924)-i/LoginWnd:qrCodeScaned
45        15.472987        20528        WeChat.exe        (2024-7-2:9:21:49:537 01924)-i/LoginWnd:scan status = 1
46        15.473246        20528        WeChat.exe        (2024-7-2:9:21:49:537 01924)-i/AccountService:phone type = 
47        15.473421        20528        WeChat.exe        (2024-7-2:9:21:49:537 01924)-i/QRCodeLoginMgr:PhoneVersion 0
48        15.473767        20528        WeChat.exe        (2024-7-2:9:21:49:537 01924)-i/QRCodeLoginMgr:URL Expired Time = 0
49        15.473978        20528        WeChat.exe        (2024-7-2:9:21:49:538 01924)-i/QRCodeLoginMgr:delayCheck

参考资料

免费评分

参与人数 7威望 +1 吾爱币 +28 热心值 +7 收起 理由
熊猫拍板砖 + 1 + 1 我很赞同!
allspark + 1 + 1 用心讨论,共获提升!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
梦入神机 + 3 + 1 我很赞同!
gouzi123 + 1 + 1 谢谢@Thanks!
rookie12138 + 1 + 1 热心回复!
yp17792351859 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
Ericky 发表于 2024-7-2 10:08
成功完成了踩缝纫机的第一步,开log
沙发
wasm2023 发表于 2024-7-2 09:40
3#
lduml 发表于 2024-7-2 10:01
5#
xiaofan1990 发表于 2024-7-2 10:25
多谢分享,学习
6#
yinxing 发表于 2024-7-2 10:41
期待楼主一系列的微信逆向教程
7#
 楼主| kn0sky 发表于 2024-7-2 10:42 |楼主
Ericky 发表于 2024-7-2 10:08
成功完成了踩缝纫机的第一步,开log

啊这...真的吗
8#
NMCchan 发表于 2024-7-2 10:45
是大佬 来学习一下
9#
y524180101 发表于 2024-7-2 10:49
厉害呀厉害呀厉害呀
10#
尹铭 发表于 2024-7-2 10:50
膜拜大佬~
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 17:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表