以前写的一个QQ聊天记录解密时写的,加密解密就是麻烦
如需要QQTEA单元,参见上一篇文章
代码
{
/----------------------------------------------|
| QQ消息解密类 |
| Writeted By RYYD |
| Mail:ryyd@163.com |
----------------------------------------------/
}
unit QQMSG;
interface
uses ActiveX,Classes,Sysutils,QQTEA,Windows,StdCtrls,comobj,Axctrls,MD5,Dialogs;
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的内容
C2CMsgList:TStrings;//好友列表
SysMsgList:TStrings;//系统信息列表
DiscMsgList:TStrings;//组列表
GroupMsgList:TStrings;//群列表
TempSessionMsgList:TStrings;//临时消息列表
MobileMsgList:TStrings;//移动消息列表
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里获取完整的消息
public
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.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+PerM.Name+': '+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.
{
/----------------------------------------------|
| QQ消息解密类 |
| Writeted By RYYD |
| Mail:ryyd@163.com |
----------------------------------------------/
}
unit QQMSG;
interface
uses ActiveX,Classes,Sysutils,QQTEA,Windows,StdCtrls,comobj,Axctrls,MD5,Dialogs;
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的内容
C2CMsgList:TStrings;//好友列表
SysMsgList:TStrings;//系统信息列表
DiscMsgList:TStrings;//组列表
GroupMsgList:TStrings;//群列表
TempSessionMsgList:TStrings;//临时消息列表
MobileMsgList:TStrings;//移动消息列表
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里获取完整的消息
public
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.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+PerM.Name+': '+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.