QQ聊天记录快速备份 v0.9收藏

 

 

本程序由爱页工作室(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