Yahoo messenger のメッセージアーカイブをダンプする
思うところがあり、Yahoo messengerのメッセージアーカイブの解析をしてみました。
動機としては
- オフラインでも見れた方が便利かも
- googleデスクトップ検索に引っかかるとなおよし
といったところですか。
類似ソフトを探してみたところ
http://yammy.sourceforge.net/
がヒットしました。
このソフトの困った点は
- .NETとかいうよくわからないフレームワークを使っている。何それ?
- C#とかいう訳の分からない言語で書かれている。何語?
- 日本語の扱いが怪しいらしい
まずはデータの解析を。ま、いろいろ悩んだのですが割愛。
結局よく分からず、Yammyをカンニングすることにしました。
ソースコードが含まれていたので見てみたところ、ソースの拡張子がcsなのが萎えます。
デコード処理はすぐに見つかったのでCでファイルにダンプするプログラムを
即席で作ってみました。
結局IDをキーとしたXOR暗号のようでした。
以下ソース(見づらいですが)。
ライセンスは「無責任ライセンス1.0」ということで。
使用法はCコンパイラ(ANSI)で下記ソースをコンパイル、
自分のID, 相手のIDを指定してやるとOK。
標準入力から読みとった暗号化されたアーカイブデータを
標準出力でテキストデータとして書き出します。
どうやら文字コードはutf-8らしいですが、よくわからず。
gcc -o imdump imdump.c
./imdump MY_ID YOUR_ID < archive.dat > im.txt
cygwinのgccで確認してみました(Borlandのcでもいいはず)。
最新ぽいYahoo Messengerのメッセージ、およびカンファレンスの
アーカイブファイルを処理してみたところ、
めでたくテキストでダンプできました(軽く感動)。
メッセンジャーの設定でメッセージアーカイブを有効にするのを
お忘れなく。
Program filesの下のYahoo Messenger関係のディレクトリの下に
メッセージアーカイブのデータディレクトリがあるはず。
なんとか.datとかいう名前のファイルが出来ていると思うので。
/**
* @file imdump.c
*
* Yahoo IMのアーカイブをダンプする
* ひとまずgdsに引っかかるようにしてみて実運用
*
* 引数
* 1: 自分のユーザーID
* 2: 相手のユーザーID
*
* @author pa.
* @version $Rev:$
*/
/* Copyright (c) 2006, pa */
#include "stdio.h"
#include "time.h"
/* ユーザーID初期値 */
#define USER_ID "default"
#define USER_ID_LEN 7
/* メッセージ格納バッファサイズ */
#define BUF_SIZE 2048
static char* key = USER_ID;
static int keylen = USER_ID_LEN;
static char* rid = "other";
static void printdata(FILE *fp, char *user, time_t time, char *msg);
/**
* スタートアップ関数
*
* @param argc コマンドライン引数
* @param argv
*
* @return 0
*/
#define STS_TIME 0
#define STS_RESV 1
#define STS_USR 2
#define STS_LEN 3
#define STS_DATA 4
#define STS_IDLEN 5
#define STS_ID 6
int main(int argc, char *argv[])
{
int ch, outch;
int status = STS_TIME;
int col = 0;
int time = 0;
int user = 0;
int datalen = 0;
int unknowndata = 0;
int idlen = 0;
time_t timestamp; /* いらないような気もするが */
char msg[BUF_SIZE+1];
char *msgp;
char msg_rid[256]; /* 発言者のユーザーID */
char *mridp;
/*
覚書
argv[0] プログラムのパス
argv[1]... 引数
argc プログラムのパスを含めた引数個数
*/
/* 引数チェック */
if(argc > 1){
key = argv[1];
keylen = strlen(key);
}
if(argc > 2){
rid = argv[2];
}
msgp = msg;
mridp = msg_rid;
ch = getc(stdin);
while(ch != EOF){
switch(status){
case STS_TIME:
time |= (ch&0xff) << (8*col);
if(col == 3){
/* ここで時間出力か */
//printf("time: %d\n", time); // debug
status = STS_RESV;
col = 0;
}else{
col++;
}
break;
case STS_RESV:
unknowndata |= (ch&0xff) << (8*col);
if(col == 3){
//printf("?: %x\n", unknowndata); // debug
status = STS_USR;
col = 0;
}else{
col++;
}
break;
case STS_USR:
user |= (ch&0xff) << (8*col);
if(col == 3){
//printf("user: %d\n", user); // debug
status = STS_LEN;
col = 0;
}else{
col++;
}
break;
case STS_LEN:
datalen |= (ch&0xff) << (8*col);
if(col == 3){
//printf("len: %d\n", datalen); // debug
status = (datalen)?(STS_DATA):(STS_IDLEN);
col = 0;
}else{
col++;
}
break;
case STS_DATA:
outch = ch ^ (key[col%keylen]);
//printf("ch: %02x, key: %02x, out: %02x\n",
// ch, key[col%keylen], outch); // debug
/* putc(outch, stdout); */
if(col < BUF_SIZE){
*msgp++ = outch;
}
if(col == (datalen-1)){
*msgp = '\0';
//fprintf(stdout, "\n"); // debug
status = STS_IDLEN;
col = 0;
}else{
col++;
}
break;
case STS_IDLEN:
idlen |= (ch&0xff) << (8*col);
if(col == 3){
//printf("IDlen: %d\nID:", idlen); // debug
if(idlen){
col = 0;
status = STS_ID;
}else{
//printf("\n"); // debug
printdata(stdout, (user)?(rid):(key), time, msg);
status = STS_TIME;
col = 0;
time = 0;
user = 0;
datalen = 0;
unknowndata = 0;
idlen = 0;
msgp = msg;
mridp = msg_rid;
msg[0] = '\0';
msg_rid[0] = '\0';
}
}else{
col++;
}
break;
case STS_ID:
//putc(ch, stdout); // debug
*mridp++ = ch;
if(col == (idlen-1)){
// fprintf(stdout, "\n"); // debug
*mridp = '\0';
printdata(stdout, (user)?(msg_rid):(key), time, msg);
status = STS_TIME;
col = 0;
time = 0;
user = 0;
datalen = 0;
unknowndata = 0;
idlen = 0;
msgp = msg;
mridp = msg_rid;
msg[0] = '\0';
msg_rid[0] = '\0';
}else{
col++;
}
break;
default:
break;
}
ch = getc(stdin);
}
return 0;
}
/**
* メッセージを1件出力する
*
* @param fp 出力先ファイルポインタ
* @param user 発言ユーザー名、ヌル終端
* @param time 時刻
* @param msg メッセージ(UTF-8)、ヌル終端
*/
static void printdata(FILE *fp, char *user, time_t time, char *msg)
{
struct tm *tm_p;
fprintf(fp, "%s ", user);
tm_p = localtime(&time);
fprintf(fp, "(%02d:%02d:%02d): ",tm_p->tm_hour,tm_p->tm_min,tm_p->tm_sec);
fprintf(fp, "%s\n", msg);
}
ダンプしたテキストデータをGDSのテキストプラグインで
読み込めば、Google デスクトップ検索でMessengerの
ログが検索できる・・・・はずがうまくいかず。
なんでだろうね。
nkfかなんかで変換してやるといいのかも。
ちなみにGDSのプラグインにすでにYahoo Messenger用のものが
あるらしいのですが、こちらも.NETらしく。
GDSプラグインデビューも考えてみる?
P.S.
上記ソースコードはMeadow + face2htmlにて作成。
なかなか良い。

0 Comments:
Post a Comment
<< Home