本程序由爱页工作室(www.ayeah.net)使用C#在VS2008上开发
目前发布第一版v0.9
有以下功能:
1、输入QQ号码提取所有聊天记录为TXT文件(包括普通聊天记录、群聊天记录、临时会话。。。)
2、一键打包成rar(自动调用rar.exe)
3、发送到邮箱中做备份(使用SMTP)
其它说明:
本程序需要.net framework 2.0以上版本运行库
本程序为绿色版,不用安装,不写注册表,解压到任意目录即用,可自动识别QQ所在目录
聊天记录导出不需要密码,对于本地消息加密的MsgEX.DB暂未测试。
本程序只作聊天记录备份之用,请勿用于偷窥他人隐私。
点击这里下载
ayeah
2008.12.03
爱页工作室
www.ayeah.net
参考了以下内容:
1、解密QQ消息文件格式
http://blog.csdn.net/vbvan/archive/2007/12/14/1937440.aspx
2、Decompiling CHM (help) files with C#
http://www.codeproject.com/csharp/decompilingchm.asp?print=true
3、Google,CSDN,Google….
Storage.cs(从RelatedObjects.Storage.dll反编译而来)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
namespace RelatedObjects.Storage
{
[ComImport, SuppressUnmanagedCodeSecurity, Guid("0000000B-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStorage
{
[return: MarshalAs(UnmanagedType.Interface)]
UCOMIStream CreateStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2);
[return: MarshalAs(UnmanagedType.Interface)]
UCOMIStream OpenStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr reserved1, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved2);
[return: MarshalAs(UnmanagedType.Interface)]
IStorage CreateStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2);
[return: MarshalAs(UnmanagedType.Interface)]
IStorage OpenStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr pstgPriority, [In, MarshalAs(UnmanagedType.U4)] int grfMode, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.U4)] int reserved);
void CopyTo(int ciidExclude, [In, MarshalAs(UnmanagedType.LPArray)] Guid[] rgiidExclude, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.Interface)] IStorage pstgDest);
void MoveElementTo([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.Interface)] IStorage pstgDest, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName, [In, MarshalAs(UnmanagedType.U4)] int grfFlags);
void Commit(int grfCommitFlags);
void Revert();
int EnumElements([In, MarshalAs(UnmanagedType.U4)] int reserved1, IntPtr reserved2, [In, MarshalAs(UnmanagedType.U4)] int reserved3, [MarshalAs(UnmanagedType.Interface)] out IEnumSTATSTG ppenum);
void DestroyElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsName);
void RenameElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsOldName, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName);
void SetElementTimes([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In] FILETIME pctime, [In] FILETIME patime, [In] FILETIME pmtime);
void SetClass(ref Guid clsid);
void SetStateBits(int grfStateBits, int grfMask);
int Stat(out STATSTG pStatStg, int grfStatFlag);
}
[ComImport, Guid("0000000D-0000-0000-C000-000000000046"), SuppressUnmanagedCodeSecurity, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumSTATSTG
{
[PreserveSig]
int Next(int celt, out STATSTG rgVar, out int pceltFetched);
[PreserveSig]
int Skip(int celt);
[PreserveSig]
int Reset();
int Clone(out IEnumSTATSTG newEnum);
}
public class Ole32
{
// Methods
[DllImport("Ole32.dll")]
public static extern int StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)] string wcsName, IStorage pstgPriority, int grfMode, IntPtr snbExclude, int reserved, out IStorage storage);
}
public class IStorageWrapper : IBaseStorageWrapper
{
// Methods
public IStorageWrapper(string workPath)
{
Ole32.StgOpenStorage(workPath, null, 0x10, IntPtr.Zero, 0, out this.storage);
IBaseStorageWrapper.BaseUrl = workPath;
STATSTG pStatStg = new STATSTG();
base.storage.Stat(out pStatStg, 1);
base.EnumIStorageObject(base.storage);
}
}
public class IBaseStorageWrapper
{
// Fields
private static string baseUrl;
public FileObjects foCollection = new FileObjects();
protected IStorage storage;
// Methods
protected void EnumIStorageObject(IStorage stgArgument)
{
this.EnumIStorageObject(stgArgument, "");
}
protected void EnumIStorageObject(IStorage stgArgument, string BasePath)
{
IEnumSTATSTG mstatstg;
STATSTG statstg;
int num;
stgArgument.EnumElements(0, IntPtr.Zero, 0, out mstatstg);
mstatstg.Reset();
while (mstatstg.Next(1, out statstg, out num) == 0)
{
FileObjects.FileObject fo = new FileObjects.FileObject();
fo.FileType = statstg.type;
switch (statstg.type)
{
case 1:
{
IStorage storage = stgArgument.OpenStorage(statstg.pwcsName, IntPtr.Zero, 0x10, IntPtr.Zero, 0);
if (storage != null)
{
string basePath = BasePath + statstg.pwcsName.ToString();
fo.FileStorage = storage;
fo.FilePath = BasePath;
fo.FileName = statstg.pwcsName.ToString();
this.foCollection.Add(fo);
this.EnumIStorageObject(storage, basePath);
}
break;
}
case 2:
{
UCOMIStream stream = stgArgument.OpenStream(statstg.pwcsName, IntPtr.Zero, 0x10, 0);
fo.FilePath = BasePath;
fo.FileName = statstg.pwcsName.ToString();
fo.FileStream = stream;
this.foCollection.Add(fo);
break;
}
case 3:
Console.WriteLine("[Property:ILockBytes] Ignoring…");
break;
case 4:
Console.WriteLine("[Property:IProperty] Ignoring…");
break;
default:
Console.WriteLine("Unknown object, skipping and continuing…");
break;
}
if (statstg.type == 1)
{
Console.WriteLine("Type: STORAGE");
}
}
}
// Properties
public static string BaseUrl
{
get
{
return baseUrl;
}
set
{
baseUrl = "mk:@MSITStore:" + value + "::/";
}
}
// Nested Types
public class FileObjects : CollectionBase
{
// Methods
public void Add(FileObject fo)
{
base.List.Add(fo);
}
public FileObject Item(int index)
{
return (FileObject)base.List[index];
}
public void Remove(int index)
{
if ((index < (base.Count – 1)) && (index > 0))
{
base.List.RemoveAt(index);
}
}
// Nested Types
public class FileObject : Stream
{
// Fields
private string fileName;
private string filePath;
private IStorage fileStorage;
private UCOMIStream fileStream;
private int fileType;
private string fileUrl;
// Methods
public override void Close()
{
if (this.fileStream != null)
{
this.fileStream.Commit(0);
Marshal.ReleaseComObject(this.fileStream);
this.fileStream = null;
GC.SuppressFinalize(this);
}
}
public override void Flush()
{
if (this.fileStream == null)
{
throw new ObjectDisposedException("theStream");
}
this.fileStream.Commit(0);
}
public override int Read(byte[] buffer, int offset, int count)
{
if (this.fileStream == null)
{
throw new ObjectDisposedException("theStream");
}
int length = 0;
object obj2 = length;
GCHandle handle = new GCHandle();
try
{
handle = GCHandle.Alloc(obj2, GCHandleType.Pinned);
IntPtr pcbRead = handle.AddrOfPinnedObject();
if (offset != 0)
{
byte[] pv = new byte[count – 1];
this.fileStream.Read(pv, count, pcbRead);
length = (int)obj2;
Array.Copy(pv, 0, buffer, offset, length);
return length;
}
this.fileStream.Read(buffer, count, pcbRead);
length = (int)obj2;
}
finally
{
if (handle.IsAllocated)
{
handle.Free();
}
}
return length;
}
public string ReadFromFile()
{
int num;
if (this.fileStream == null)
{
throw new ObjectDisposedException("theStream");
}
Stream stream = new MemoryStream();
byte[] buffer = new byte[this.Length];
this.Seek(0L, SeekOrigin.Begin);
while ((num = this.Read(buffer, 0, 0x400)) > 0)
{
stream.Write(buffer, 0, num);
}
stream.Seek(0L, SeekOrigin.Begin);
StreamReader reader = new StreamReader(stream);
return reader.ReadToEnd().ToString();
}
public void Save(string FileName)
{
int num;
if (this.fileStream == null)
{
throw new ObjectDisposedException("theStream");
}
byte[] buffer = new byte[this.Length];
this.Seek(0L, SeekOrigin.Begin);
Stream stream = File.OpenWrite(FileName);
while ((num = this.Read(buffer, 0, 0x400)) > 0)
{
stream.Write(buffer, 0, num);
}
stream.Close();
}
public override long Seek(long offset, SeekOrigin origin)
{
if (this.fileStream == null)
{
throw new ObjectDisposedException("theStream");
}
long num = 0L;
object obj2 = num;
GCHandle handle = new GCHandle();
try
{
handle = GCHandle.Alloc(obj2, GCHandleType.Pinned);
IntPtr plibNewPosition = handle.AddrOfPinnedObject();
this.fileStream.Seek(offset, (int)origin, plibNewPosition);
num = (long)obj2;
}
finally
{
if (handle.IsAllocated)
{
handle.Free();
}
}
return num;
}
public override void SetLength(long Value)
{
if (this.fileStream == null)
{
throw new ObjectDisposedException("theStream");
}
this.fileStream.SetSize(Value);
}
public override void Write(byte[] buffer, int offset, int count)
{
if (this.fileStream == null)
{
throw new ObjectDisposedException("theStream");
}
if (offset != 0)
{
int length = buffer.Length – offset;
byte[] destinationArray = new byte[length];
Array.Copy(buffer, offset, destinationArray, 0, length);
this.fileStream.Write(destinationArray, length, IntPtr.Zero);
}
else
{
this.fileStream.Write(buffer, count, IntPtr.Zero);
}
}
// Properties
public override bool CanRead
{
get
{
return (this.fileStream != null);
}
}
public override bool CanSeek
{
get
{
return true;
}
}
public override bool CanWrite
{
get
{
return true;
}
}
public string FileName
{
get
{
return this.fileName;
}
set
{
this.fileName = value;
}
}
public string FilePath
{
get
{
return this.filePath;
}
set
{
this.filePath = value;
}
}
public IStorage FileStorage
{
get
{
return this.fileStorage;
}
set
{
this.fileStorage = value;
}
}
public UCOMIStream FileStream
{
get
{
return this.fileStream;
}
set
{
this.fileStream = value;
}
}
public int FileType
{
get
{
return this.fileType;
}
set
{
this.fileType = value;
}
}
public string FileUrl
{
get
{
return (IBaseStorageWrapper.BaseUrl + this.FilePath.Replace(@"/", "/") + "/" + this.FileName);
}
set
{
this.fileUrl = value;
}
}
public override long Length
{
get
{
STATSTG statstg;
if (this.fileStream == null)
{
throw new ObjectDisposedException("theStream");
}
this.fileStream.Stat(out statstg, 1);
return statstg.cbSize;
}
}
public override long Position
{
get
{
return this.Seek(0L, SeekOrigin.Current);
}
set
{
this.Seek(value, SeekOrigin.Begin);
}
}
}
}
}
}
QQMsgMgr.cs — 从vbvan处修改而来,主要修改了一直占用MsgEx.db的毛病
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using RelatedObjects.Storage;
namespace QQBackup
{
public enum QQMsgType
{
BIM, C2C, Group, Sys, Mobile, TempSession //Disc
}
class QQMsgMgr
{
private static readonly int s_MsgTypeNum = (int)QQMsgType.TempSession + 1;
private static readonly string[] s_MsgName = new string[] {
"BIMMsg", "C2CMsg", "GroupMsg", "SysMsg", "MobileMsg", "TempSessionMsg"
};
private IStorageWrapper m_Storage;
private byte[] m_Password;
private List<string>[] m_MsgList = new List<string>[s_MsgTypeNum];
public void Open(string QQID)
{
Open(QQID, null);
}
public void Open(string QQID, string QQPath)
{
if (QQPath == null)
{
using (Microsoft.Win32.RegistryKey reg = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"Software/Tencent/QQ"))
{
QQPath = reg.GetValue("Install") as string;
}
if (QQPath == null) return;
}
for (int i = 0; i < m_MsgList.Length; ++i)
{
m_MsgList[i] = new List<string>();
}
m_Storage = null;
m_Password = null;
m_Storage = new IStorageWrapper(QQPath + QQID + @"/MsgEx.db");
m_Password = QQMsgMgr.GetGlobalPass(m_Storage, QQID);
if (m_Password == null) m_Storage = null;
foreach (IBaseStorageWrapper.FileObjects.FileObject fileObject in m_Storage.foCollection)
{
if (fileObject.FileType == 1)
{
for (int i = 0; i < m_MsgList.Length; ++i)
{
if (fileObject.FilePath == s_MsgName[i])
{
m_MsgList[i].Add(fileObject.FileName);
}
}
}
}
}
public void OutputMsg()
{
for (int i = 0; i < s_MsgTypeNum; ++i)
{
OutputMsg((QQMsgType)i);
}
}
public void OutputMsg(QQMsgType type)
{
if (m_Storage == null) return;
if (m_Password == null) return;
int typeIndex = (int)type;
if (typeIndex < 0 || typeIndex >= s_MsgTypeNum)
{
throw new ArgumentException("Invalid QQMsgType", "type");
}
string filePath = s_MsgName[typeIndex] + "//";
Directory.CreateDirectory(filePath);
foreach (string QQID in m_MsgList[typeIndex])
{
string fileName = filePath + QQID + ".txt";
OutputMsg(type, QQID, fileName);
}
}
public void OutputMsg(QQMsgType type, string QQID)
{
if (m_Storage == null) return;
if (m_Password == null) return;
int typeIndex = (int)type;
if (typeIndex < 0 || typeIndex >= s_MsgTypeNum)
{
throw new ArgumentException("Invalid QQMsgType", "type");
}
string filePath = s_MsgName[typeIndex] + "//";
Directory.CreateDirectory(filePath);
string fileName = filePath + QQID + ".txt";
OutputMsg(type, QQID, fileName);
}
private void OutputMsg(QQMsgType type, string QQID, string fileName)
{
string msgPath = s_MsgName[(int)type] + QQID;
IList<byte[]> msgList = QQMsgMgr.DecryptMsg(m_Storage, msgPath, m_Password);
Encoding encoding = Encoding.GetEncoding(936);
using (FileStream fs = new FileStream(fileName, FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(fs))
{
for (int i = 0; i < msgList.Count; ++i)
{
using (MemoryStream ms = new MemoryStream(msgList[i]))
{
using (BinaryReader br = new BinaryReader(ms, Encoding.GetEncoding(936)))
{
#if false
fs.Write(msgList[i], 0, msgList[i].Length);
#else
int ticks = br.ReadInt32();
DateTime time = new DateTime(1970, 1, 1) + new TimeSpan(0, 0, ticks);
switch (type)
{
case QQMsgType.BIM:
case QQMsgType.C2C:
case QQMsgType.Mobile:
ms.Seek(1, SeekOrigin.Current);
break;
case QQMsgType.Group:
ms.Seek(8, SeekOrigin.Current);
break;
case QQMsgType.Sys:
ms.Seek(4, SeekOrigin.Current);
break;
case QQMsgType.TempSession: //?
ms.Seek(9, SeekOrigin.Current);
break;
}
if (type == QQMsgType.TempSession)
{
int gLen = br.ReadInt32();
string groupName = encoding.GetString(br.ReadBytes(gLen));
if (groupName.Length > 0) sw.WriteLine("{0}", groupName);
}
int nLen = br.ReadInt32();
string id = encoding.GetString(br.ReadBytes(nLen));
sw.WriteLine("{0}: {1}", id, time.ToString());
int cLen = br.ReadInt32();
string msg = encoding.GetString(br.ReadBytes(cLen));
//msg=msg.Replace("/n", Environment.NewLine);
msg = msg.Replace(new string(new char[] { (char)21 }), "(图片)");
msg = msg.Replace(new string(new char[] { (char)20 }), "(表情)");
char[] t = msg.ToCharArray();
msg=msg.Split((char)19)[0];
msg = msg.Replace("/n", Environment.NewLine);
sw.WriteLine(msg);
sw.WriteLine();
#endif
}
}
}
sw.Close();
}
fs.Close();
}
}
public void OutputFileList()
{
if (m_Storage == null) return;
Dictionary<string, long> dic = new Dictionary<string, long>();
foreach (IBaseStorageWrapper.FileObjects.FileObject fileObject in m_Storage.foCollection)
{
if (fileObject.FileType == 2 && fileObject.FileName == "Index.msj")
{
dic[fileObject.FilePath] = fileObject.Length / 4;
}
}
for (int i = 0; i < m_MsgList.Length; ++i)
{
Console.WriteLine("{0}", s_MsgName[i]);
foreach (string ID in m_MsgList[i])
{
Console.WriteLine("/t{0}: {1}", ID, dic[s_MsgName[i] + ID]);
}
}
}
private static IBaseStorageWrapper.FileObjects.FileObject GetStorageFileObject(IStorageWrapper iw, string path, string fileName)
{
foreach (IBaseStorageWrapper.FileObjects.FileObject fileObject in iw.foCollection)
{
if (fileObject.CanRead)
{
if (fileObject.FilePath == path && fileObject.FileName == fileName) return fileObject;
}
}
return null;
}
private static byte[] Decrypt(byte[] src, byte[] pass, long offset)
{
RedQ.QQCrypt decryptor = new RedQ.QQCrypt();
return decryptor.QQ_Decrypt(src, pass, offset);
}
private static IList<byte[]> DecryptMsg(IStorageWrapper iw, string path, byte[] pass)
{
List<byte[]> msgList = new List<byte[]>();
int num = 0;
int[] pos = null;
int[] len = null;
using (IBaseStorageWrapper.FileObjects.FileObject fileObject = GetStorageFileObject(iw, path, "Index.msj"))
{
if (fileObject == null) return msgList;
int fileLen = (int)fileObject.Length;
num = fileLen / 4;
pos = new int[num + 1];
using (BinaryReader br = new BinaryReader(fileObject))
{
for (int i = 0; i < num; ++i)
{
pos[i] = br.ReadInt32();
}
}
}
using (IBaseStorageWrapper.FileObjects.FileObject fileObject = GetStorageFileObject(iw, path, "Data.msj"))
{
if (fileObject != null)
{
int fileLen = (int)fileObject.Length;
len = new int[num];
pos[num] = fileLen;
for (int i = 0; i < num; ++i)
{
len[i] = pos[i + 1] – pos[i];
}
using (BinaryReader br = new BinaryReader(fileObject))
{
for (int i = 0; i < num; ++i)
{
fileObject.Seek(pos[i], SeekOrigin.Begin);
byte[] data = br.ReadBytes(len[i]);
byte[] msg = Decrypt(data, pass, 0);
msgList.Add(msg);
}
}
}
}
return msgList;
}
private static byte[] GetGlobalPass(IStorageWrapper iw, string QQID)
{
System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] dataID = new byte[QQID.Length];
for (int i = 0; i < QQID.Length; ++i) dataID[i] = (byte)(QQID[i]);
byte[] hashID = md5.ComputeHash(dataID);
IBaseStorageWrapper.FileObjects.FileObject fileObject = GetStorageFileObject(iw, "Matrix", "Matrix.db");
if (fileObject != null)
{
using (BinaryReader br = new BinaryReader(fileObject))
{
byte[] data = br.ReadBytes((int)fileObject.Length);
long len = data.Length;
if (len < 6 || data[0] != 0x51 || data[1] != 0x44) return null;
if (len >= 32768) return null;
bool bl = false;
int i = 6;
while (i < len)
{
bl = false;
byte type = data[i++];
if (i + 2 > len) break;
int len1 = data[i] + data[i + 1] * 256;
byte xor1 = (byte)(data[i] ^ data[i + 1]);
i += 2;
if (i + len1 > len) break;
for (int j = 0; j < len1; ++j) data[i + j] = (byte)(~(data[i + j] ^ xor1));
if (len1 == 3 && data[i] == 0x43 && data[i + 1] == 0x52 && data[i + 2] == 0x4B)
{
bl = true;
}
i += len1;
if (type > 7) break;
if (i + 4 > len) break;
int len2 = data[i] + data[i + 1] * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 * 256 * 256;
byte xor2 = (byte)(data[i] ^ data[i + 1]);
i += 4;
if (i + len2 > len) break;
if (type == 6 || type == 7)
{
for (int j = 0; j < len2; ++j) data[i + j] = (byte)(~(data[i + j] ^ xor2));
}
if (bl && len2 == 0x20)
{
byte[] dataT = new byte[len2];
for (int j = 0; j < len2; ++j) dataT[j] = data[i + j];
return Decrypt(dataT, hashID, 0);
}
i += len2;
}
if (i != len) return null;
}
}
return null;
}
public void Close(string QQID) {
if (m_Storage == null)
{
return;
}
else {
m_Storage = null;
}
}
}
}
QQCrypt.cs — 原封未动,直接copy过来的
using System;
namespace RedQ
{
/** <summary>
/// QQ Msg En/DeCrypt Class
/// Writen By Red_angelX On 2006.9.13
/// </summary>
public class QQCrypt
{
//QQ TEA-16 Encrypt/Decrypt Class
//
//
//And also LumaQQ//s source code
// CopyRight:No CopyRight^_^
// Author : Red_angelX
// NetWork is Free,Tencent is ****!
//
//Class Begin
//AD:Find Job!!,If you Want Give me a Job,Content Me!!
//Copied & translated from LumaQQ//s source code `From LumaQQ///s source code:
private byte[] Plain; //指向当前的明文块
private byte[] prePlain ; //指向前面一个明文块
private byte[] Out; //输出的密文或者明文
private long Crypt, preCrypt; //当前加密的密文位置和上一次加密的密文块位置,他们相差8
private long Pos; //当前处理的加密解密块的位置
private long padding; //填充数
private byte[] Key = new byte[16]; //密钥
private bool Header; //用于加密时,表示当前是否是第一个8字节块,因为加密算法
//是反馈的,但是最开始的8个字节没有反馈可用,所有需要标
//明这种情况
private long contextStart; //这个表示当前解密开始的位置,之所以要这么一个变量是为了
//避免当解密到最后时后面已经没有数据,这时候就会出错,这
//个变量就是用来判断这种情况免得出错
public QQCrypt()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
//Push 数据
byte[] CopyMemory(byte[] arr,int arr_index,long input) //lenth = 4
{
if(arr_index+4 > arr.Length)
{
// 不能执行
return arr;
}
arr[arr_index+3]=(byte)((input & 0xff000000) >> 24);
arr[arr_index+2]=(byte)((input & 0x00ff0000) >> 16);
arr[arr_index+1]=(byte)((input & 0x0000ff00) >> 8);
arr[arr_index]=(byte)(input & 0x000000ff);
arr[arr_index] &= 0xff;
arr[arr_index+1] &= 0xff;
arr[arr_index+2] &= 0xff;
arr[arr_index+3] &= 0xff;
return arr;
}
long CopyMemory(long Out,byte[] arr,int arr_index)
{
if(arr_index+4 > arr.Length)
{
return Out;
//不能执行
}
long x1 = arr[arr_index+3] << 24;
long x2 = arr[arr_index+2] << 16;
long x3 = arr[arr_index+1] << 8;
long x4 = arr[arr_index];
long o = x1 | x2 | x3 | x4;
o &= 0xffffffff;
return o;
}
long getUnsignedInt(byte[] arrayIn, int offset,int len /**//*Default is 4*/)
{
long ret = 0;
int end = 0;
if (len > 8)
end = offset + 8;
else
end = offset + len;
for (int i = offset; i < end; i++)
{
ret <<= 8;
ret |= arrayIn[i] & 0xff;
}
return (ret & 0xffffffff) | (ret >> 32);
}
long Rand()
{
Random rd = new Random();
long ret;
ret = rd.Next() + (rd.Next() % 1024);
return ret;
}
private byte[] Decipher(byte[] arrayIn,byte[] arrayKey,long offset)
{
//long Y,z,a,b,c,d;
long sum,delta;
//Y=z=a=b=c=d=0;
byte[] tmpArray = new byte[24];
byte[] tmpOut = new byte[8];
if(arrayIn.Length < 8)
{
// Error:return
return tmpOut;
}
if(arrayKey.Length < 16)
{
// Error:return
return tmpOut;
}
sum = 0xE3779B90;
sum = sum & 0xFFFFFFFF;
delta = 0x9E3779B9;
delta = delta & 0xFFFFFFFF;
/**//*tmpArray[3] = arrayIn[offset];
tmpArray[2] = arrayIn[offset + 1];
tmpArray[1] = arrayIn[offset + 2];
tmpArray[0] = arrayIn[offset + 3];
tmpArray[7] = arrayIn[offset + 4];
tmpArray[6] = arrayIn[offset + 5];
tmpArray[5] = arrayIn[offset + 6];
tmpArray[4] = arrayIn[offset + 7];
tmpArray[11] = arrayKey[0];
tmpArray[10] = arrayKey[1];
tmpArray[9] = arrayKey[2];
tmpArray[8] = arrayKey[3];
tmpArray[15] = arrayKey[4];
tmpArray[14] = arrayKey[5];
tmpArray[13] = arrayKey[6];
tmpArray[12] = arrayKey[7];
tmpArray[19] = arrayKey[8];
tmpArray[18] = arrayKey[9];
tmpArray[17] = arrayKey[10];
tmpArray[16] = arrayKey[11];
tmpArray[23] = arrayKey[12];
tmpArray[22] = arrayKey[13];
tmpArray[21] = arrayKey[14];
tmpArray[20] = arrayKey[15];
Y=CopyMemory(Y,tmpArray,0);
z=CopyMemory(z,tmpArray,4);
a=CopyMemory(a,tmpArray,8);
b=CopyMemory(b,tmpArray,12);
c=CopyMemory(c,tmpArray,16);
d=CopyMemory(d,tmpArray,20);*/
long Y = getUnsignedInt(arrayIn, (int)offset, 4);
long z = getUnsignedInt(arrayIn, (int)offset + 4, 4);
long a = getUnsignedInt(arrayKey, 0, 4);
long b = getUnsignedInt(arrayKey, 4, 4);
long c = getUnsignedInt(arrayKey, 8, 4);
long d = getUnsignedInt(arrayKey, 12, 4);
for(int i=1;i<=16;i++)
{
z -= ((Y<<4)+c) ^ (Y+sum) ^ ((Y>>5)+d);
z &= 0xFFFFFFFF;
Y -= ((z<<4)+a) ^ (z+sum) ^ ((z>>5)+b);
Y &= 0xFFFFFFFF;
sum -= delta;
sum &= 0xFFFFFFFF;
}
tmpArray = CopyMemory(tmpArray,0,Y);
tmpArray = CopyMemory(tmpArray,4,z);
tmpOut[0] = tmpArray[3];
tmpOut[1] = tmpArray[2];
tmpOut[2] = tmpArray[1];
tmpOut[3] = tmpArray[0];
tmpOut[4] = tmpArray[7];
tmpOut[5] = tmpArray[6];
tmpOut[6] = tmpArray[5];
tmpOut[7] = tmpArray[4];
return tmpOut;
}
private byte[] Decipher(byte[] arrayIn,byte[] arrayKey)
{
return Decipher(arrayIn,arrayKey,0);
}
private byte[] Encipher(byte[] arrayIn,byte[] arrayKey,long offset)
{
byte[] tmpOut = new byte[8];
byte[] tmpArray = new byte[24];
//long Y,z,a,b,c,d;
//Y=z=a=b=c=d=0;
long sum,delta;
if(arrayIn.Length < 8)
{
// Error:
return tmpOut;
}
if(arrayKey.Length < 16)
{
// Error:
return tmpOut;
}
sum = 0;
delta = 0x9E3779B9;
delta &= 0xFFFFFFFF;
/**//*tmpArray[3] = arrayIn[offset];
tmpArray[2] = arrayIn[offset + 1];
tmpArray[1] = arrayIn[offset + 2];
tmpArray[0] = arrayIn[offset + 3];
tmpArray[7] = arrayIn[offset + 4];
tmpArray[6] = arrayIn[offset + 5];
tmpArray[5] = arrayIn[offset + 6];
tmpArray[4] = arrayIn[offset + 7];
tmpArray[11] = arrayKey[0];
tmpArray[10] = arrayKey[1];
tmpArray[9] = arrayKey[2];
tmpArray[8] = arrayKey[3];
tmpArray[15] = arrayKey[4];
tmpArray[14] = arrayKey[5];
tmpArray[13] = arrayKey[6];
tmpArray[12] = arrayKey[7];
tmpArray[19] = arrayKey[8];
tmpArray[18] = arrayKey[9];
tmpArray[17] = arrayKey[10];
tmpArray[16] = arrayKey[11];
tmpArray[23] = arrayKey[12];
tmpArray[22] = arrayKey[13];
tmpArray[21] = arrayKey[14];
tmpArray[20] = arrayKey[15];
Y=CopyMemory(Y,tmpArray,0);
z=CopyMemory(z,tmpArray,4);
a=CopyMemory(a,tmpArray,8);
b=CopyMemory(b,tmpArray,12);
c=CopyMemory(c,tmpArray,16);
d=CopyMemory(d,tmpArray,20);*/
long Y = getUnsignedInt(arrayIn, (int)offset, 4);
long z = getUnsignedInt(arrayIn, (int)offset + 4, 4);
long a = getUnsignedInt(arrayKey, 0, 4);
long b = getUnsignedInt(arrayKey, 4, 4);
long c = getUnsignedInt(arrayKey, 8, 4);
long d = getUnsignedInt(arrayKey, 12, 4);
for(int i=1;i<=16;i++)
{
sum += delta;
sum &= 0xFFFFFFFF;
Y += ((z<<4)+a) ^ (z+sum) ^ ((z>>5)+b);
Y &= 0xFFFFFFFF;
z += ((Y<<4)+c) ^ (Y+sum) ^ ((Y>>5)+d);
z &= 0xFFFFFFFF;
}
tmpArray = CopyMemory(tmpArray,0,Y);
tmpArray = CopyMemory(tmpArray,4,z);
tmpOut[0] = tmpArray[3];
tmpOut[1] = tmpArray[2];
tmpOut[2] = tmpArray[1];
tmpOut[3] = tmpArray[0];
tmpOut[4] = tmpArray[7];
tmpOut[5] = tmpArray[6];
tmpOut[6] = tmpArray[5];
tmpOut[7] = tmpArray[4];
return tmpOut;
}
private byte[] Encipher(byte[] arrayIn,byte[] arrayKey)
{
return Encipher(arrayIn,arrayKey,0);
}
private void Encrypt8Bytes()
{
byte[] Crypted;
for(Pos=0;Pos<=7;Pos++)
{
if(this.Header == true)
{
Plain[Pos] = (byte)(Plain[Pos] ^ prePlain[Pos]);
}
else
{
Plain[Pos] = (byte)(Plain[Pos] ^ Out[preCrypt + Pos]);
}
}
Crypted = Encipher(Plain,Key);
for(int i=0;i<=7;i++)
{
Out[Crypt + i] = (byte)Crypted[i];
}
for(Pos=0;Pos<=7;Pos++)
{
Out[Crypt + Pos] = (byte)(Out[Crypt + Pos] ^ prePlain[Pos]);
}
Plain.CopyTo(prePlain,0);
preCrypt = Crypt;
Crypt = Crypt + 8;
Pos = 0;
Header = false;
}
private bool Decrypt8Bytes(byte[] arrayIn,long offset)
{
long lngTemp;
for(Pos=0;Pos<=7;Pos++)
{
if(this.contextStart+Pos > arrayIn.Length-1)
{
return true;
}
prePlain[Pos] = (byte)(prePlain[Pos] ^ arrayIn[offset+Crypt+Pos]);
}
try
{
prePlain = this.Decipher(prePlain,Key);
}
catch
{
return false;
}
lngTemp = prePlain.Length – 1;
contextStart += 8;
Crypt+=8;
Pos = 0;
return true;
}
private bool Decrypt8Bytes(byte[] arrayIn)
{
return Decrypt8Bytes(arrayIn,0);
}
#region Public Methods!
/** <summary>
/// QQ TEA 加密函数
/// </summary>
/// <param name="arrayIn">要加密的字串</param>
/// <param name="arrayKey">密钥</param>
/// <param name="offset">偏移</param>
/// <returns></returns>
public byte[] QQ_Encrypt(byte[] arrayIn,byte[] arrayKey,long offset)
{
Plain = new byte[8];
prePlain = new byte[8];
long l;
Pos = 1;
padding = 0;
Crypt = preCrypt = 0;
arrayKey.CopyTo(Key,0); // Key Must Be 16 Length!
Header = true;
Pos = 2;
//计算头部填充字节数
Pos = (arrayIn.Length+10) % 8;
if(Pos != 0)
Pos = 8-Pos;
//输出长度
Out = new byte[arrayIn.Length+Pos+10];
//把POS存到PLAIN的第一个字节
//0xf8后面3位是空的,正好给Pos
Plain[0] = (byte)((Rand() & 0xf8) | Pos);
//用随机数填充1到Pos的内容
for(int i=1;i<=Pos;i++)
{
Plain[i] = (byte)(Rand() & 0xff);
}
Pos++;
padding = 1;
//继续填充两个字节随机数,满8字节就加密
while(padding < 3)
{
if( Pos < 8)
{
Plain[Pos] = (byte)(Rand() & 0xff);
padding++;
Pos++;
}
else if(Pos == 8)
{
this.Encrypt8Bytes();
}
}
int I = (int)offset;
l = 0;
//明文内容,满8字节加密到读完
l = arrayIn.Length;
while ( l > 0)
{
if(Pos<8)
{
Plain[Pos] = arrayIn[I];
I++;
Pos++;
l–;
}
else if(Pos == 8)
{
this.Encrypt8Bytes();
}
}
//末尾填充0,保证是8的倍数
padding = 1;
while(padding < 9)
{
if(Pos<8)
{
Plain[Pos] = 0;
Pos++;
padding++;
}
else if(Pos == 8)
{
this.Encrypt8Bytes();
}
}
return Out;
}
public byte[] QQ_Encrypt(byte[] arrayIn,byte[] arrayKey)
{
return QQ_Encrypt(arrayIn,arrayKey,0);
}
/** <summary>
/// QQ TEA 解密函数
/// </summary>
/// <param name="arrayIn">要解密字串</param>
/// <param name="arrayKey">密钥</param>
/// <param name="offset">偏移</param>
/// <returns></returns>
public byte[] QQ_Decrypt(byte[] arrayIn,byte[] arrayKey,long offset)
{
byte[] error = new byte[0];
//检查是否是8的倍数至少16字节
if(arrayIn.Length < 16 || (arrayIn.Length % 8 != 0))
{
//Return What?
return error;
}
if(arrayKey.Length != 16)
{
//Return What?
return error;
}
byte[] m;
long I,Count;
m= new byte[offset+8];
arrayKey.CopyTo(Key,0);
Crypt = preCrypt = 0;
//计算消息头部,明文开始的偏移,解密第一字节和7相与得到
prePlain = this.Decipher(arrayIn,arrayKey,offset);
Pos = prePlain[0] & 7;
//计算明文长度
Count = arrayIn.Length – Pos – 10;
if(Count <= 0)
{
//Return What?
return error;
}
Out = new byte[Count];
preCrypt = 0;
Crypt = 8;
this.contextStart = 8;
Pos++;
padding = 1;
//跳过头部
while(padding < 3)
{
if(Pos<8)
{
Pos++;
padding++;
}
else if(Pos==8)
{
for(int i=0;i<m.Length;i++)
m[i]=arrayIn[i];
if(this.Decrypt8Bytes(arrayIn,offset) == false)
{
//Return What?
return error;
}
}
}
//解密明文
I=0;
while(Count != 0)
{
if(Pos<8)
{
Out[I] = (byte)(m[offset+preCrypt+Pos] ^ prePlain[Pos]);
I++;
Count–;
Pos++;
}
else if(Pos == 8)
{
m = arrayIn;
preCrypt = Crypt – 8;
if(this.Decrypt8Bytes(arrayIn,offset) == false)
{
//Return What?
return error;
}
}
}
//最后的解密部分,检查尾部是不是0
for(padding=1;padding<=7;padding++)
{
if(Pos<8)
{
if( (m[offset+preCrypt+Pos] ^ prePlain[Pos]) != 0 )
{
//Return What?
return error;
}
Pos++;
}
else if(Pos == 8)
{
for(int i=0;i<m.Length;i++)
m[i] = arrayIn[i];
preCrypt = Crypt;
if(this.Decrypt8Bytes(arrayIn,offset) == false)
{
//Return What?
return error;
}
}
}
return Out;
}
public byte[] QQ_Decrypt(byte[] arrayIn,byte[] arrayKey)
{
return QQ_Decrypt(arrayIn,arrayKey,0);
}
#endregion
}
}
另外还有发邮件的代码就不发了,简单的调用cdosys.dll发的,还有调用rar.exe的也很简单,就几行代码,不贴了,自己反编译吧,我没混淆~~
不想直接发源码是讨厌很多人拿去改掉我的名字和网址就当自己的“原创”了。。。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/superayeah/archive/2008/12/05/3454813.aspx