解码雅虎通(yahoo messenger)聊天记录

February 10th, 2009 | Tags:

 

Yahoo Messenger 的聊天记录是登录到相应账户以后才可以查看的,记录内容保存在  Program Files\Yahoo!\Messenger\Profiles\YourYahooId\Archive\Messages 中,每个联系人的聊天记录保存在一个以该联系人 yahoo id 命名的文件夹中,每天一个文件,内容是经过加密的。

如果你遗忘了你的 yahoo id 密码且无法取回的话你就没有办法查看聊天记录了,当我遇到这种情况就打算跟踪一下 Yahoo Messenger 的加密或者解密算法。

登录 Yahoo Messenger, 查看聊天存档,在左边选中一个联系人,你可以看到右上方的列表中显示日期,选定一个日期消息内容就显示在右下方的视图中。用 OllyDbg 附加到 YM 进程, 在 Kernel32.CreateFileW 下断点,继续运行程序,点击一个日期,断点命中,查看调用堆栈,我使用的版本的 YM 在子程序 sub_004D53A7 中调用 CreateFileW,禁止 CreateFileW 的断点,在 004D53A7 重新下断。

我们先看一下这个函数的开头部分:

sub_004d53a7

该函数最后一个压栈的参数是 push esi, 随后判断了 [esi+38] 是否为 0, 如果为 0 则调用 CreateFileA, 否则跳转, 推测 该子程序是某个类的一个方法,esi 是当前实例的起始地址,[esi+38] 应该是该类的一个成员变量 HANDLE hFile, 如果这个句柄为 NULL 则打开文件,否则跳过,继续读取文件内容,单步到 FileName 处可以看到正是保存我们要打开的那天的记录文件。

继续单步,

004D53DC  |.  83F8 FF       cmp     eax, -1
004D53DF  |.  8946 38       mov     dword ptr [esi+38], eax
004D53E2  |.  75 07         jnz     short 004D53EB
004D53E4  |.  33C0          xor     eax, eax
004D53E6  |.  E9 33010000   jmp     004D551E
004D53EB  |>  53            push    ebx                         ; /Origin
004D53EC  |.  53            push    ebx                         ; |pOffsetHi
004D53ED  |.  53            push    ebx                         ; |OffsetLo
004D53EE  |.  50            push    eax                         ; |hFile
004D53EF  |.  FF15 10D37900 call    dword ptr [<&KERNEL32.SetFi>; \SetFilePointer

  如果成功打开文件则将文件指针指向文件头

004D53F5  |> \57            push    edi
004D53F6  |.  8B3D C8D27900 mov     edi, dword ptr [<&KERNEL32.>;  kernel32.ReadFile
004D53FC  |.  53            push    ebx                         ; /pOverlapped
004D53FD  |.  8D45 08       lea     eax, dword ptr [ebp+8]      ; |
004D5400  |.  50            push    eax                         ; |pBytesRead
004D5401  |.  6A 04         push    4                           ; |BytesToRead = 4
004D5403  |.  FF75 0C       push    dword ptr [ebp+C]           ; |Buffer
004D5406  |.  895D 08       mov     dword ptr [ebp+8], ebx      ; |
004D5409  |.  FF76 38       push    dword ptr [esi+38]          ; |hFile
004D540C  |.  899D 78F7FFFF mov     dword ptr [ebp-888], ebx    ; |
004D5412  |.  899D 74F7FFFF mov     dword ptr [ebp-88C], ebx    ; |
004D5418  |.  FFD7          call    edi                         ; \ReadFile

读取 4 个字节, 应该是个 DWORD 吧,下面它判断了一下读取到的字节长度,如果是 0 则 关闭文件句柄 (这里就是判断文件是否已经结束了),否则跳转到 004D5432 连续三次读取 4 个字节,又三个 DWORD

004D541A  |.  395D 08       cmp     dword ptr [ebp+8], ebx
004D541D  |.  75 13         jnz     short 004D5432
004D541F  |.  FF76 38       push    dword ptr [esi+38]          ; /hObject
004D5422  |.  FF15 1CD37900 call    dword ptr [<&KERNEL32.Close>; \CloseHandle
004D5428  |.  895E 38       mov     dword ptr [esi+38], ebx
004D542B  |.  33C0          xor     eax, eax
004D542D  |.  E9 EB000000   jmp     004D551D
004D5432  |>  53            push    ebx
004D5433  |.  8D45 08       lea     eax, dword ptr [ebp+8]
004D5436  |.  50            push    eax
004D5437  |.  6A 04         push    4
004D5439  |.  FF75 10       push    dword ptr [ebp+10]
004D543C  |.  FF76 38       push    dword ptr [esi+38]
004D543F  |.  FFD7          call    edi                         ;  kernel32.ReadFile
。。。 。。。

————————————————- 以上已经读取 4 个 DWORD 的分割线 —————————————————–

004D5463  |.  B8 FF070000   mov     eax, 7FF
004D5468  |.  3985 78F7FFFF cmp     dword ptr [ebp-888], eax
004D546E  |.  76 06         jbe     short 004D5476
004D5470  |.  8985 78F7FFFF mov     dword ptr [ebp-888], eax
004D5476  |>  53            push    ebx
004D5477  |.  8D45 08       lea     eax, dword ptr [ebp+8]
004D547A  |.  50            push    eax
004D547B  |.  FFB5 78F7FFFF push    dword ptr [ebp-888] // ReadFile 的第三个参数就是前面最后一个读取到的 DWORD 值
004D5481  |.  8D85 7CF7FFFF lea     eax, dword ptr [ebp-884]
004D5487  |.  50            push    eax
004D5488  |.  FF76 38       push    dword ptr [esi+38]
004D548B  |.  FFD7          call    edi                         ;  kernel32.ReadFile

读取到的第四个 整数 和 0x7FF 作了一个比较 , 如果小于等于则跳转 jbe short 004D5476,否则 mov dword ptr[ebp-888], eax 将其赋值为 0x7FF (2047),看起来像是什么?这条消息的长度了,果然下面读取了此长度的内容,到这里我们大致就搞清楚了 YM archive 文件的格式,每个 Section 有 16 个字节的头部,即4个双字,最后一个 DWORD 是该 Section 中具体聊天内容的长度。

————————————————- 已经获得聊天内容数据的分割线 —————————————————–
 

004D54A0  |.  50            push    eax
004D54A1  |.  FFB5 78F7FFFF push    dword ptr [ebp-888]
004D54A7  |.  8D85 7CF7FFFF lea     eax, dword ptr [ebp-884]
004D54AD  |.  50            push    eax
004D54AE  |.  8BCE          mov     ecx, esi
004D54B0  |.  E8 45F9FFFF   call    004D4DFA

呵呵,把读取到的聊天内容压栈 调用子程序 004D4DFA, 要解密了???  等等看见什么了,你的 yahooid 被压栈了(后来知道你的 yahoo id 就是解密用的 key), 跟进 004D4DFA

————————————————- 快下班了,休息一下,未完待续的分割线 —————————————————–

大清老早的起来准备完成准备完成这篇博客,发现家里电脑上的 Yahoo Messenger 已经被我删掉了,也懒得再装,没汇编给你看了,就瞧瞧我用 c++ 实现的 sub_004D4DFA 吧,

 

void Decode(BYTE *buffer, int bufferLen, char* key)
{
	int keylen = strlen(key);
	int idx = 0;
	char outbuffer[0xff];
 
	do 
	{
		char c = (char)buffer[idx];
		c ^= key[idx % keylen];
		outbuffer[idx] = c;
		idx++;
	} while (idx &lt; bufferLen);
 
	char test[0xff] = {0};
	WCHAR wtest[0xff] = {0};
	MultiByteToWideChar (CP_UTF8, 0, outbuffer, 0xff, wtest, 0xff); //转换一下,否则中文乱码
	WideCharToMultiByte(CP_ACP, 0, wtest, 0xff, test, 0xff, 0, false);
 
	printf(&quot;%s\n&quot;, test);
}

其实加密就是这么简单了,把聊天内容字符串和你的 yahoo id 逐个字节异或,超出 yahoo id 长度后再从 id 的首字符开始。

一开始没有写 字符串类型转换那两句,解密出来的内容里中文是乱码,转换一下用 printf 输出就可以了。

一个 section 就是对话中的一句话,前面的其他3个 DWORD 分别是 聊天双方的 数字 id 和该消息的发送时间,读完一个 section 再读下一个,直至文件结束。

 

=============== 罪恶的聊天记录 :),虎头蛇尾的完结线,Felix 090211 7:00 ===============

更多有趣日志

    1. 游客
      August 12th, 2009 at 10:03
      Reply | Quote | #1

      才看到具体分析,昨天还在其他文章上留言要具体分析呢,哈。我去试试,厉害。

      Reply

      fangxiaojun reply on February 25th, 2010 11:27:

      Yahoo 聊天记录解码器 可以的把完整的代码发我看下吗?
      我正在C++  给这样的程序~~ 非常感谢~
      fangxiao_jun@126.com

      Reply

      Felix reply on February 26th, 2010 10:37:

      最后我是用 C# 写了一个有 GUI 的。

      Reply

    2. chen
      March 4th, 2010 at 15:12
      Reply | Quote | #2

      你好,很佩服看到你的分析文章。
      同问,能参考下你的代码吗?
      chen@chen@yahoo.cn

      Reply

    3. Desert
      March 5th, 2010 at 02:29
      Reply | Quote | #3

      版主,我急需一个这样的程序,或者我把.dat文件给你,你帮我解码,请联系我下,QQ:26896864 谢谢了!!!

      Reply

    4. March 28th, 2010 at 22:44
      Reply | Quote | #4

      来过,踩下,博主思想不错,哈哈!~

      Reply