⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qqmsg.pas

📁 一个小的Delphi的QQ消息浏览工具
💻 PAS
字号:


unit QQMSG;

interface

uses ActiveX,Classes,Sysutils,QQTEA,Windows,StdCtrls,comobj,Axctrls,MD5,Dialogs,StrUtils;

type
  IntType=array of Integer;
  PerMSG=record
    Content:string;
    Time:TDateTime;
    Name:string;
    Group:string;
  end;
  MSGType=(C2CMsg,SysMsg,DiscMsg,GroupMsg,TempSessionMsg,MobileMsg);
  TQQMSG=class
    private
      QQ:string;//用来存储QQ号
      FileName:string;//用来存储消息文件名
      RootStorage:IStorage; //用来储存结构化文件的根文件
      Key:ByteType;//全局解密KEY
      QQHash:ByteType; //存储QQ号的Hash Byte数组
      MatrixData:ByteType;//存储Matrix.db的内容

      procedure GetMatrixData;//得到MatrixData数据
      function GetRealByte(Des:ByteType):ByteType; //得到一个Byte数组去除了0后的真实数组
      procedure GetKey;//得到全局解密KEY
      procedure GetQQHash;//得到QQ号的Hash Byte数组;
      function GetByteString(InByte:ByteType):string;overload;//得到二进制BYTE数组的字符串形式
      function GetByteString(InByte:ByteType;InBegin:Integer;InLen:Integer):string;overload;//得到二进制BYTE数组的字符串形式
      procedure GetRootStorage;//得到根文件
      procedure GetList;//得到所有的列表
      function GetBS(InByte:ByteType):string;
      function GetIntegerFromFourByte(a1:Byte;a2:Byte;a3:Byte;a4:Byte):Integer;
      function GetRealMessage(InByte:ByteType;InMSGType:MSGType):PerMSG;//从解密后的某条Byte里获取完整的消息
      function AscToChr(Src:string):string;//Ascii to char

    public
      C2CMsgList:TStrings;//好友列表
      SysMsgList:TStrings;//系统信息列表
      DiscMsgList:TStrings;//组列表
      GroupMsgList:TStrings;//群列表
      TempSessionMsgList:TStrings;//临时消息列表
      MobileMsgList:TStrings;//移动消息列表

      function GetMSG(InMSGType:MSGtype;Number:string):string;//得到全部的消息;
      procedure Print;
      constructor Create(InFileName:string;InQQ:string); //构造函数,传入参数为结构化文件的文件名以及QQ号码
  end;
implementation

uses MainUnit;


function TQQMSG.GetRealMessage(InByte: ByteType;InMSGType: MSGType):PerMSG;
var
  DateTime:TDateTime;
  Position:Integer;
  NameLength:Integer;
  Name:string;
  MSGLength:Integer;
  MSG:string;
  GroupLength:Integer;
  Group:string;
  TempByteData:ByteType;
begin
  Position:=4;
  DateTime:=EncodeDate(1970,1,1)+EncodeTime(0,0,0,0);
  DateTime:=DateTime+GetIntegerFromFourByte(InByte[0],InByte[1],InByte[2],InByte[3])/24/3600;
  case InMSGType of
    C2CMsg:Position:=Position+1;
    SysMsg:Position:=Position+4;
    DiscMsg:Position:=Position+1;
    GroupMsg:Position:=Position+8;
    TempSessionMsg:Position:=Position+9;
    MobileMsg:Position:=Position+1;
  end;
  if InMSGType=TempSessionMsg then
  begin
    GroupLength:=GetIntegerFromFourByte(InByte[Position],InByte[Position+1],InByte[Position+2],InByte[Position+3]);
    Position:=Position+4;
    //Group:=GetByteString(InByte,Position,GroupLength);
    SetLength(TempByteData,GroupLength);
    CopyMemory(@TempByteData[0],@InByte[Position],GroupLength);
    Group:=GetBS(TempByteData);
    Position:=Position+GroupLength;  
  end;
  NameLength:=GetIntegerFromFourByte(InByte[Position],InByte[Position+1],InByte[Position+2],InByte[Position+3]);
  Position:=Position+4;
  //Name:=GetByteString(InByte,Position,NameLength);
  SetLength(TempByteData,NameLength);
  CopyMemory(@TempByteData[0],@InByte[Position],NameLength);
  Name:=GetBS(TempByteData);
  Position:=Position+NameLength;
  MSGLength:=GetIntegerFromFourByte(InByte[Position],InByte[Position+1],InByte[Position+2],InByte[Position+3]);
  Position:=Position+4;
  //MSG:=GetByteString(InByte,Position,MSGLength);
  SetLength(TempByteData,MSGLength);
  CopyMemory(@TempByteData[0],@InByte[Position],MSGLength);
  MSG:=GetBS(TempByteData);
  Result.Content:=MSG;
  Result.Time:=DateTime;
  Result.Name:=Name;
  Result.Group:=Group;
end;

function TQQMSG.GetIntegerFromFourByte(a1: Byte; a2: Byte; a3: Byte; a4: Byte):Integer;
var
  TempByte:array[1..4] of Byte;
begin
  TempByte[1]:=a1;
  TempByte[2]:=a2;
  TempByte[3]:=a3;
  TempByte[4]:=a4;
  CopyMemory(@Result,@TempByte[1],4);
end;

function TQQMSG.GetBS(InByte: ByteType):string;
var
  i: Integer;
begin
  for i := 0 to Length(InByte) - 1 do Result:=Result+' '+IntToStr(InByte[i]);
end;

function TQQMSG.AscToChr(Src:string):string;
var
  i:Integer;
  s: string;
  list: TStringList;
begin
  Result:='';
  i:= Pos('19 21',Src);
  if i<>0 then
  begin
    Src:=MidStr(Src,0,i-1);
  end;
  
  s := StringReplace(Src, chr(32), chr(13) + chr(10), [rfReplaceAll]);
  list := TStringList.Create;
  list.Text := s;
  for i := 1 to list.Count-1 do
  begin
      Result:=Result+chr(StrToInt(list.Strings[i]));
  end;

end;

function TQQMSG.GetMSG(InMSGType: MSGType; Number: string):string;
var
  OpenString:string;
  TempStorage:IStorage;
  MSGStorage:IStorage;
  TempStream:IStream;
  TempOutOleStream:TOlestream;
  TempOutStream:TMemoryStream;
  Index,Data:ByteType;
  FileLen,Num:Integer;
  Pos,Len:array of Integer;
  i,t:Integer;
  TempOutString:string;
  TempData,TempMSG:ByteType;
  TempDecrypter:TQQTEA;
  Position,EndPosition:Integer;
  j: Integer;
  TempDateTime:TDateTime;
  PerM:PerMSG;
  TempStringList:TStrings;
  TempString:string;
begin
  TempOutString:='';
  TempDecrypter:=TQQTEA.Create;
  case InMSGType of
    C2CMsg:OpenString:='C2CMsg';
    SysMsg:OpenString:='SysMsg';
    DiscMsg:OpenString:='DiscMsg';
    GroupMsg:OpenString:='GroupMsg';
    TempSessionMsg:OpenString:='TempSessionMsg';
    MobileMsg:OpenString:='MobileMsg';
  end;
  
  OleCheck(RootStorage.OpenStorage(StringToOleStr(OpenString),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,nil,0,TempStorage));
  OleCheck(TempStorage.OpenStorage(StringToOleStr(Number),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,nil,0,MSGStorage));
  OleCheck(MSGStorage.OpenStream(StringToOleStr('Index.msj'),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,0,TempStream));
  TempOutOleStream:=TOleStream.Create(TempStream);
  TempOutStream:=TMemoryStream.Create;
  TempOutStream.Size:=0;
  TempOutStream.CopyFrom(TempOutOleStream,TempOutOleStream.Size);
  TempOutOleStream.Free;
  TempOutStream.Position:=0;
  SetLength(Index,TempOutStream.Size);
  for i:=0 to length(Index)-1 do Index[i]:=0;
  TempOutStream.ReadBuffer(Index[0],TempOutStream.size);
  TempOutStream.Free;
  
  OleCheck(MSGStorage.OpenStream(StringToOleStr('Data.msj'),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,0,TempStream));
  TempOutOleStream:=TOleStream.Create(TempStream);
  TempOutStream:=TMemoryStream.Create;
  TempOutStream.Size:=0;
  TempOutStream.CopyFrom(TempOutOleStream,TempOutOleStream.Size);
  TempOutOleStream.Free;
  TempOutStream.Position:=0;
  SetLength(Data,TempOutStream.Size);
  for i:=0 to length(Data)-1 do Data[i]:=0;
  TempOutStream.ReadBuffer(Data[0],TempOutStream.size);
  TempOutStream.Free;

  FileLen:=Length(Index);
  Num:=Trunc(FileLen/4);
  SetLength(Pos,Num+1);
  t:=0;i:=0;
  while i<Length(Index) do
  begin
    CopyMemory(@pos[t],@Index[i],4);
    i:=i+4;
    t:=t+1;
  end;
  FileLen:=Length(Data);
  SetLength(Len,Num);
  pos[Num]:=fileLen;
  for i:=0 to Num-1 do
  begin
    len[i]:= pos[i+1]-pos[i];
  end;

  TempStringList:=TStringList.Create;
  for i :=0 to Num - 1 do
  begin
    TempString:='';
    Position:=Pos[i];
    SetLength(TempData,Len[i]);
    CopyMemory(@TempData[0],@Data[Position],Len[i]);
    TempMSG:=TempDecrypter.DeCrypt(TempData,Key);
    PerM:=GetRealMessage(TempMSG,InMSGType);
    TempString:=TempString+DateTimeToStr(PerM.Time);
    TempString:=TempString+#13+#10;
    TempString:=TempString+AscToChr(PerM.Name)+': '+AscToChr(PerM.Content);
    TempStringList.Add(TempString);
    TempStringList.Add('');
  end;
  Result:=TempStringList.Text;
  TempDecrypter.Destroy;
end;



procedure TQQMSG.GetList;
var
  EnumStatStg:IEnumStatStg;
  StatStg:TStatStg;
  TempStorage:IStorage;
begin
  OleCheck(RootStorage.OpenStorage(StringToOleStr('C2CMsg'),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,nil,0,TempStorage));
  OleCheck(TempStorage.EnumElements(0,nil,0,EnumStatStg));
  while EnumStatStg.Next(1,StatStg,nil)=S_Ok do
  begin
    C2CMsgList.Add(StatStg.pwcsName);
  end;

  OleCheck(RootStorage.OpenStorage(StringToOleStr('SysMsg'),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,nil,0,TempStorage));
  OleCheck(TempStorage.EnumElements(0,nil,0,EnumStatStg));
  while EnumStatStg.Next(1,StatStg,nil)=S_Ok do
  begin
    SysMsgList.Add(StatStg.pwcsName);
  end;

  {OleCheck(RootStorage.OpenStorage(StringToOleStr('DiscMsg'),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,nil,0,TempStorage));
  OleCheck(TempStorage.EnumElements(0,nil,0,EnumStatStg));
  while EnumStatStg.Next(1,StatStg,nil)=S_Ok do
  begin
    DiscMsgList.Add(StatStg.pwcsName);
  end;           }

  OleCheck(RootStorage.OpenStorage(StringToOleStr('GroupMsg'),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,nil,0,TempStorage));
  OleCheck(TempStorage.EnumElements(0,nil,0,EnumStatStg));
  while EnumStatStg.Next(1,StatStg,nil)=S_Ok do
  begin
    GroupMsgList.Add(StatStg.pwcsName);
  end;

  OleCheck(RootStorage.OpenStorage(StringToOleStr('TempSessionMsg'),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,nil,0,TempStorage));
  OleCheck(TempStorage.EnumElements(0,nil,0,EnumStatStg));
  while EnumStatStg.Next(1,StatStg,nil)=S_Ok do
  begin
    TempSessionMsgList.Add(StatStg.pwcsName);
  end;   
end;

procedure TQQMSG.GetRootStorage;
begin
  if FileExists(FileName) then
  begin
    OleCheck(StgOpenStorage(StringToOleStr(FileName),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,nil,0,RootStorage));
  end;
end;

function TQQMSG.GetByteString(InByte: ByteType):string;
var
  TempStringStream:TStringStream;
begin
  TempStringStream:=TStringStream.Create('');
  TempStringStream.WriteBuffer(InByte[0],Length(InByte));
  Result:=TempStringStream.DataString;
  TempStringStream.Free;
end;

function TQQMSG.GetByteString(InByte: ByteType; InBegin: Integer; InLen: Integer):string;
var
  TempStringStream:TStringStream;
begin
  TempStringStream:=TStringStream.Create('');
  TempStringStream.WriteBuffer(InByte[InBegin],InLen);
  Result:=TempStringStream.DataString;
  TempStringStream.Free;
end;

procedure TQQMSG.Print;
var
  i:Integer;
  TempString:string;
begin
  for i := 0 to Length(Key) - 1 do
  begin
    TempString:=TempString+inttostr(Key[i])+' ';
  end;
  MainUnit.MainForm.Caption:=TempString;
end;

constructor TQQMSG.Create(InFileName: string; InQQ: string);
begin
  C2CMsgList:=TStringList.Create;
  SysMsgList:=TStringList.Create;
  DiscMsgList:=TStringList.Create;
  GroupMsgList:=TStringList.Create;
  TempSessionMsgList:=TStringList.Create;
  MobileMsgList:=TStringList.Create;
  QQ:=InQQ;
  FileName:=InFileName;
  GetRootStorage;
  GetList;
  GetKey;
end;

function TQQMSG.GetRealByte(Des:ByteType):ByteType;
var
  l:Integer;
begin
  for l := 0 to Length(Des) - 1 do
  begin
    if Des[l]=0 then Break;
  end;
  SetLength(Des,l);
  SetLength(Result,length(Des));
  CopyMemory(@Result[0],@Des[0],Length(Des));
end;

procedure TQQMSG.GetQQHash;
var
  TempMD5:MD5Digest;
begin
  TempMD5:=MD5String(QQ);
  SetLength(QQHash,Length(TempMD5));
  CopyMemory(@QQHash[0],@TempMD5[0],Length(TempMD5));  
end;

procedure TQQMSG.GetKey;
var
  Len,Len1,Len2:Integer;
  bl:Boolean;
  i,j:Integer;
  typeB,xor1,xor2:Byte;
  dataT,TempByte:ByteType;
  TempDecrypter:TQQTEA;
begin
  GetQQHash;
  GetMatrixData;
  TempDecrypter:=TQQTEA.Create;
  Len:=Length(MatrixData);
  if ((Len<6) or (MatrixData[0] <> $51) or (MatrixData[1] <> $44)) then
  begin
    Key:=nil;
    Exit;
  end;
  if Len >= 32768 then
  begin
    Key:=nil;
    Exit;
  end;
  bl:=false;
  i:=6;
  while i<Len do
  begin
    bl:=False;
    typeb:=MatrixData[i];
    i:=i+1;
    if (i + 2) > len then Break;
    Len1:=MatrixData[i]+MatrixData[i+1]*256;
    xor1:=Byte(MatrixData[i] xor MatrixData[i+1]);
    i:=i+2;
    if (i+len1)>Len then Break;
    for j := 0 to Len1-1do
    begin
      MatrixData[i+j]:=Byte(not(MatrixData[i+j] xor xor1));
    end;
    if (Len1=3) and (MatrixData[i]=$43) and (MatrixData[i+1]=$52) and (MatrixData[i+2]=$4B) then
    begin
      bl:=true;
    end;
    i:=i+len1;
    if typeB > 7 then break;
    if (i + 4)> len then break;
    len2:= MatrixData[i] + MatrixData[i + 1] * 256 + MatrixData[i + 2] * 256 * 256 + MatrixData[i + 3] * 256 * 256 * 256;
    xor2:=byte(MatrixData[i] xor MatrixData[i + 1]);
    i:=i+4;
    if (i + len2) > len then break;
    if ((typeB=6) or (typeB=7)) then
    begin
      for j := 0 to len2-1 do
      begin
        MatrixData[i+j]:=Byte(not(MatrixData[i+j] xor xor2));
      end;
    end;
    if (bl and (len2=$20)) then
    begin
      SetLength(dataT,len2);
      for j := 0 to Len2-1 do dataT[j]:=MatrixData[i+j];
      TempByte:=TempDecrypter.Decrypt(dataT,QQHash);
      SetLength(Key,Length(TempByte));
      CopyMemory(@Key[0],@TempByte[0],Length(TempByte));
      Exit; 
    end;
    i:=i+len2;
  end;
  if (i<>len) then
  begin
    Key:=nil;
    exit;
  end;
end;

procedure TQQMSG.GetMatrixData;
var
  i:Integer;
  MatrixStroage:IStorage;
  MatrixDBFileStream:IStream;
  TempOutOleStream:TOlestream;
  TempOutStream:TMemoryStream;
begin
  OleCheck(RootStorage.OpenStorage(StringToOleStr('Matrix'),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,nil,0,MatrixStroage));
  OleCheck(MatrixStroage.OpenStream(StringToOleStr('Matrix.db'),nil,STGM_READWRITE or STGM_SHARE_EXCLUSIVE,0,MatrixDBFileStream));
  TempOutOleStream:=TOleStream.Create(MatrixDBFileStream);
  TempOutStream:=TMemoryStream.Create;
  TempOutStream.Size:=0;
  TempOutStream.CopyFrom(TempOutOleStream,TempOutOleStream.Size);
  TempOutOleStream.Free;
  TempOutStream.Position:=0;
  SetLength(MatrixData,TempOutStream.Size);
  for i:=0 to length(MatrixData)-1 do MatrixData[i]:=0;
  TempOutStream.ReadBuffer(MatrixData[0],TempOutStream.size);
  TempOutStream.Free;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -