OD-困难重重的追踪消息断点

我是菜鸟,高手勿喷,谢谢,

最近逆向某捕鱼游戏,由于需求需要逆向他的封包数据,bp recv加给内存下断点,找到解密消息的地方(收包子线程里面),我要的是是怎们处理里封包,而不只是解密过程,接着向下追查,发现游戏先是把解密好的数据放在模块内存里面,然后给主线程(主窗口)发消息,告诉他,收到网络消息并给你解密好了,赶紧处理吧,发消息是使用的postmessage,窗口句柄参数是主窗口,消息ID0x4FF,以前看过郁金香的视频教程,好像可以用SPY++找到主窗口的窗口消息处理函数,在哪里下消息断点,一下就可以拦截了,无奈自己当时没有记录笔记,又找不到看的哪个视频,自己动手找窗口处理函数,找了半天还是不行,找不到哪个函数,只能百度了“OD消息断点”。大概收获如下:

http://blog.csdn.net/liujiayu2/article/details/51789282

按照教程,依然没有找到处理窗口消息的地方,哎,怪我太笨,,

无奈我只自己写个工程,简单逆向学习下,工程代码如下(只列举自己写的,很简单):

#define MSG_TEST 0x4FF
ON_MESSAGE(MSG_TEST, &Ctest2Dlg::msg)
#include "ClogFile.h"
LRESULT Ctest2Dlg::msg(WPARAM w, LPARAM l)
{
 
//输出字符串l
gConsoleLog.WriteLogInfo("%s",(char*)l);
 
return 0;
}
 
 
DWORD WINAPI func(LPVOID lpThreadParameter)
{
char *p = new char[20];
ZeroMemory(p, 20);
strcpy(p,"1234567890");
::PostMessage(AfxGetApp()->GetMainWnd()->m_hWnd, MSG_TEST, 0, (LPARAM)p);
 
return 0;
}
 
void Ctest2Dlg::OnBnClickedButton1()
{
// TODO: 在ú此?添?加ó控?件t通?知a处鋦理え?程ì序ò代洙?码?
CreateThread(NULL, 0, func, NULL, 0, NULL);
}

按照上面的教程依然没有找到我自己写的msg(WPARAM w, LPARAM l)函数体,于是我进下了一下小研究,

找到gConsoleLog.WriteLogInfo("%s",(char*)l);这句的反汇编代码,下断点,点击下按钮,让程序跑到断点出,看调用堆栈,如下:

 OD-困难重重的追踪消息断点_第1张图片

可以看到WinMain函数也在其中,这不是我们点击按按钮调用的,我们看到user32.DispatchMessageA

MSG(0x4FF)结构体,最终调用到了我们的msg(WPARAM w, LPARAM l)函数体,我决定亲自试一下,看看能不能调用到。

1.DispatchMessageA上下条件断点,[[esp+4]+4] == 0x4FF  (消息ID)

2.点击按钮,程序成功在DispatchMessageA处断下

3.F8单步走,走到user32.74E07BC5处的call,F7跟进去,因为堆栈是这么指示的

4.一直跟着堆栈走确实最终走到了msg(WPARAM w, LPARAM l)函数体

走到是走到了,这是一路走来真不容易,每个call里面都有几十个call,必须在指定的call跟进去,不能走过了,也不能早走,但是看看这些,全是在系统代码区,最终一走到用户代码区就正好到了我们想要的函数体,肯定有简便的方法吧,根据我们前面看到的文章(虽然没找到函数体,依然学到了东西)打开OD的内存窗口,找到可执行程序test2的代码段,.text

 OD-困难重重的追踪消息断点_第2张图片

右键F2下断点,这个断点表示,一旦程序运行了用户层代码,立即断下,并自动清除断点。

我们按照这个方法试下test2程序,

1.DispatchMessageA上下条件断点,[[esp+4]+4] == 0x4FF  (消息ID)

2.点击按钮,程序成功在DispatchMessageA处断下

3.test2.textF2断点,

4.F9运行程序

理论上来讲应该是直接就到了我们的msg(WPARAM w, LPARAM l)函数体,可惜,没到,到了下边这个地方

 OD-困难重重的追踪消息断点_第3张图片

瞬间心里难受,竟然有这种幺蛾子,怎么办?

冷静过后,我们思考下,到了这里时候,我们真正想到的地方msg(WPARAM w, LPARAM l)函数体,到过还是没到过?再来一变,这次在步骤3上面加上,在我们最终目的地加上断点,执行步骤4之后发现直接走到了上面截图的地方,还没到我们最后的目的地,那就接着往下走走呗,F8单步运行,发现程序运行到了系统领空,那就继续给test2.textF2断点,F9运行程序,到了下面,

 OD-困难重重的追踪消息断点_第4张图片

依然没有经过最终目的地,没事我们冲上面的步骤,经过再两次的重复,突然柳暗花明到了我们最终目的地,这是什么情况,我现在还是不清除,但是可以确定的是这种方式确实可以找到,我们最终的目的地,

 OD-困难重重的追踪消息断点_第5张图片

回想下我们看到的那几篇文章,发现他下的是TranslateMessage断点,我下的是DispatchMessageA断点,那咱就试试这个TranslateMessage断点法,经过测试,也可以找到最终的消息响应函数msg(WPARAM w, LPARAM l,历程和DispatchMessageA断点一样的。

有了上面的实战经验我们就开始弄弄我们的游戏,为方便描述,我重新写这个具体步骤:

 

1.DispatchMessageA上下条件断点,[[esp+4]+4] == 0x4FF  (消息ID)

2.点击按钮,程序成功在DispatchMessageA处断下

3.test2.textF2断点,

4.F9运行程序

5.程序断下,观看程序断的地方是不是最终想要的地方,是就结束,不是就执行F8,程序会再进入系统领空,

6.重复执行步骤345直到我们找到最终的处理消息的地方

 

肯能你会问了,你怎么知道到达用户端代码是不是我们最终想要的呢?说下最终的特征:

 OD-困难重重的追踪消息断点_第6张图片

 

上面截图是我们的测试工程,

特点1,进入的是一个完整的函数的头,不可能是函数体的半中间,更不可能是jmp指令

特点2,函数体有两个参数,其实就是postmessageWPARAM wLPARAM l,在TranslateMessage的时候就要注意这两个参数的值,钢筋函数体时,看下堆栈的第二个和第三只,应该就是两个参数(第一个参数是call产生的,表示要返回的地方

经过测试,哎,一直没到我们想要的地方,并且进入了一个死循环,研究发现这个循环是

收包->解密->派遣  ->收包->解密->派遣 ->收包->解密->派遣 这样死循环,怎么办?知道我把这篇文章命名为困难重重的原因了吧,,

 

我有点小不服气,以为运气原因,连续试了几次,每次,都是这样,我有陆续换了几个OD,都是这样,没办法只能想为什么会如此了。因为我们是下断点再加F9的找,这样可能会导致操作系统切换线程,切过去我们再单步走,走不出死循环了,差不多就是这个意思。

 

废话不大多说了,直接说我想到的解决方案:

我们发现系统领空就是两个dll的切换和调用,user32mfc100.同一个程序连续启动两次,把两个连接库加载到内存中的地址可能会变(变前16位,后16位不会变),这个我们知道的,和应用程序一样。我们拿我写的那个测试程序做多次实验,发现TranslateMessage调用到最终的消息响应函数,调用堆栈很相似,(相同是调用堆栈地址的后16位,不同的是前16位),这就说明其实执行代码和流程固定不变的。这是时可以猜测即使不同的程序TranslateMessage调用到最终的消息响应函数,执行代码和流程也应该是固定不变的。那如果是这样我们直接找到最后谁调用我们响应函数在哪里下断点就好了,就比如第一个图的mfc100.dll 502CF274这个地址,我们在这个地方下断点,端下来再直接F8就到了,

按照上面的思路,按照下面的步骤,就可以找到最终消息响应函数了,

1.在TranslateMessage上下条件断点,[[esp+4]+4] == 0x4FF  (消息ID)

2.找到最终调用test项目的响应函数的地方,下断点

3.F9,直接到步骤2断点的地方,

4.F8,到用户区的消息响应代码

 

如何在游戏中找到最终调用处理消息call的位置?

1.看测试项目中调用最后处理消息call的代码,如下(来自mfc100.dll的代码):

5833F590    51              push ecx

5833F591    50              push eax

5833F592    8BCF            mov ecx,edi

5833F594    FFD6            call esi                                 ; test2.Ctest2Dlg::msg

2.把我们的有游戏加载上来,直接在mfc100.dll找“所有命令序列”,把上面的汇编指令贴进去,正好只有一个,也不用排除了,

 

 

注意:

上面的步骤,也执行了F9,为什么没有切换线程?应该是同线程运行比线程切换快的多的原因吧。

 

  

 

你可能感兴趣的:(数据逆向)