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反编译而来)

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Collections;
  6. using System.IO;
  7. using System.Runtime.InteropServices;
  8. using System.Security;

  9. namespace RelatedObjects.Storage
  10. {
  11.     [ComImport, SuppressUnmanagedCodeSecurity, Guid("0000000B-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  12.     public interface IStorage
  13.     {
  14.         [return: MarshalAs(UnmanagedType.Interface)]
  15.         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);
  16.         [return: MarshalAs(UnmanagedType.Interface)]
  17.         UCOMIStream OpenStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr reserved1, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved2);
  18.         [return: MarshalAs(UnmanagedType.Interface)]
  19.         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);
  20.         [return: MarshalAs(UnmanagedType.Interface)]
  21.         IStorage OpenStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr pstgPriority, [In, MarshalAs(UnmanagedType.U4)] int grfMode, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.U4)] int reserved);
  22.         void CopyTo(int ciidExclude, [In, MarshalAs(UnmanagedType.LPArray)] Guid[] rgiidExclude, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.Interface)] IStorage pstgDest);
  23.         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);
  24.         void Commit(int grfCommitFlags);
  25.         void Revert();
  26.         int EnumElements([In, MarshalAs(UnmanagedType.U4)] int reserved1, IntPtr reserved2, [In, MarshalAs(UnmanagedType.U4)] int reserved3, [MarshalAs(UnmanagedType.Interface)] out IEnumSTATSTG ppenum);
  27.         void DestroyElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsName);
  28.         void RenameElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsOldName, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName);
  29.         void SetElementTimes([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In] FILETIME pctime, [In] FILETIME patime, [In] FILETIME pmtime);
  30.         void SetClass(ref Guid clsid);
  31.         void SetStateBits(int grfStateBits, int grfMask);
  32.         int Stat(out STATSTG pStatStg, int grfStatFlag);
  33.     }

  34.     [ComImport, Guid("0000000D-0000-0000-C000-000000000046"), SuppressUnmanagedCodeSecurity, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  35.     public interface IEnumSTATSTG
  36.     {
  37.         [PreserveSig]
  38.         int Next(int celt, out STATSTG rgVar, out int pceltFetched);
  39.         [PreserveSig]
  40.         int Skip(int celt);
  41.         [PreserveSig]
  42.         int Reset();
  43.         int Clone(out IEnumSTATSTG newEnum);
  44.     }

  45.     public class Ole32
  46.     {
  47.         // Methods
  48.         [DllImport("Ole32.dll")]
  49.         public static extern int StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)] string wcsName, IStorage pstgPriority, int grfMode, IntPtr snbExclude, int reserved, out IStorage storage);
  50.     }

  51.     public class IStorageWrapper : IBaseStorageWrapper
  52.     {
  53.         // Methods
  54.         public IStorageWrapper(string workPath)
  55.         {
  56.             Ole32.StgOpenStorage(workPath, null, 0x10, IntPtr.Zero, 0, out this.storage);
  57.             IBaseStorageWrapper.BaseUrl = workPath;
  58.             STATSTG pStatStg = new STATSTG();
  59.             base.storage.Stat(out pStatStg, 1);
  60.             base.EnumIStorageObject(base.storage);
  61.             
  62.         }
  63.     }

  64.     public class IBaseStorageWrapper
  65.     {
  66.         // Fields
  67.         private static string baseUrl;
  68.         public FileObjects foCollection = new FileObjects();
  69.         protected IStorage storage;

  70.         // Methods
  71.         protected void EnumIStorageObject(IStorage stgArgument)
  72.         {
  73.             this.EnumIStorageObject(stgArgument, "");
  74.         }

  75.         protected void EnumIStorageObject(IStorage stgArgument, string BasePath)
  76.         {
  77.             IEnumSTATSTG mstatstg;
  78.             STATSTG statstg;
  79.             int num;
  80.             stgArgument.EnumElements(0, IntPtr.Zero, 0, out mstatstg);
  81.             mstatstg.Reset();
  82.             while (mstatstg.Next(1, out statstg, out num) == 0)
  83.             {
  84.                 FileObjects.FileObject fo = new FileObjects.FileObject();
  85.                 fo.FileType = statstg.type;
  86.                 switch (statstg.type)
  87.                 {
  88.                     case 1:
  89.                         {
  90.                             IStorage storage = stgArgument.OpenStorage(statstg.pwcsName, IntPtr.Zero, 0x10, IntPtr.Zero, 0);
  91.                             if (storage != null)
  92.                             {
  93.                                 string basePath = BasePath + statstg.pwcsName.ToString();
  94.                                 fo.FileStorage = storage;
  95.                                 fo.FilePath = BasePath;
  96.                                 fo.FileName = statstg.pwcsName.ToString();
  97.                                 this.foCollection.Add(fo);
  98.                                 this.EnumIStorageObject(storage, basePath);
  99.                             }
  100.                             break;
  101.                         }
  102.                     case 2:
  103.                         {
  104.                             UCOMIStream stream = stgArgument.OpenStream(statstg.pwcsName, IntPtr.Zero, 0x10, 0);
  105.                             fo.FilePath = BasePath;
  106.                             fo.FileName = statstg.pwcsName.ToString();
  107.                             fo.FileStream = stream;
  108.                             this.foCollection.Add(fo);
  109.                             break;
  110.                         }
  111.                     case 3:
  112.                         Console.WriteLine("[Property:ILockBytes] Ignoring...");
  113.                         break;

  114.                     case 4:
  115.                         Console.WriteLine("[Property:IProperty] Ignoring...");
  116.                         break;

  117.                     default:
  118.                         Console.WriteLine("Unknown object, skipping and continuing...");
  119.                         break;
  120.                 }
  121.                 if (statstg.type == 1)
  122.                 {
  123.                     Console.WriteLine("Type: STORAGE");
  124.                 }
  125.             }
  126.         }

  127.         // Properties
  128.         public static string BaseUrl
  129.         {
  130.             get
  131.             {
  132.                 return baseUrl;
  133.             }
  134.             set
  135.             {
  136.                 baseUrl = "mk:@MSITStore:" + value + "::/";
  137.             }
  138.         }

  139.         // Nested Types
  140.         public class FileObjects : CollectionBase
  141.         {
  142.             // Methods
  143.             public void Add(FileObject fo)
  144.             {
  145.                 base.List.Add(fo);
  146.             }

  147.             public FileObject Item(int index)
  148.             {
  149.                 return (FileObject)base.List[index];
  150.             }

  151.             public void Remove(int index)
  152.             {
  153.                 if ((index < (base.Count - 1)) && (index > 0))
  154.                 {
  155.                     base.List.RemoveAt(index);
  156.                 }
  157.             }

  158.             // Nested Types
  159.             public class FileObject : Stream
  160.             {
  161.                 // Fields
  162.                 private string fileName;
  163.                 private string filePath;
  164.                 private IStorage fileStorage;
  165.                 private UCOMIStream fileStream;
  166.                 private int fileType;
  167.                 private string fileUrl;

  168.                 // Methods
  169.                 public override void Close()
  170.                 {
  171.                     if (this.fileStream != null)
  172.                     {
  173.                         this.fileStream.Commit(0);
  174.                         Marshal.ReleaseComObject(this.fileStream);
  175.                         this.fileStream = null;
  176.                         GC.SuppressFinalize(this);
  177.                     }
  178.                 }

  179.                 public override void Flush()
  180.                 {
  181.                     if (this.fileStream == null)
  182.                     {
  183.                         throw new ObjectDisposedException("theStream");
  184.                     }
  185.                     this.fileStream.Commit(0);
  186.                 }

  187.                 public override int Read(byte[] buffer, int offset, int count)
  188.                 {
  189.                     if (this.fileStream == null)
  190.                     {
  191.                         throw new ObjectDisposedException("theStream");
  192.                     }
  193.                     int length = 0;
  194.                     object obj2 = length;
  195.                     GCHandle handle = new GCHandle();
  196.                     try
  197.                     {
  198.                         handle = GCHandle.Alloc(obj2, GCHandleType.Pinned);
  199.                         IntPtr pcbRead = handle.AddrOfPinnedObject();
  200.                         if (offset != 0)
  201.                         {
  202.                             byte[] pv = new byte[count - 1];
  203.                             this.fileStream.Read(pv, count, pcbRead);
  204.                             length = (int)obj2;
  205.                             Array.Copy(pv, 0, buffer, offset, length);
  206.                             return length;
  207.                         }
  208.                         this.fileStream.Read(buffer, count, pcbRead);
  209.                         length = (int)obj2;
  210.                     }
  211.                     finally
  212.                     {
  213.                         if (handle.IsAllocated)
  214.                         {
  215.                             handle.Free();
  216.                         }
  217.                     }
  218.                     return length;
  219.                 }

  220.                 public string ReadFromFile()
  221.                 {
  222.                     int num;
  223.                     if (this.fileStream == null)
  224.                     {
  225.                         throw new ObjectDisposedException("theStream");
  226.                     }
  227.                     Stream stream = new MemoryStream();
  228.                     byte[] buffer = new byte[this.Length];
  229.                     this.Seek(0L, SeekOrigin.Begin);
  230.                     while ((num = this.Read(buffer, 0, 0x400)) > 0)
  231.                     {
  232.                         stream.Write(buffer, 0, num);
  233.                     }
  234.                     stream.Seek(0L, SeekOrigin.Begin);
  235.                     StreamReader reader = new StreamReader(stream);
  236.                     return reader.ReadToEnd().ToString();
  237.                 }

  238.                 public void Save(string FileName)
  239.                 {
  240.                     int num;
  241.                     if (this.fileStream == null)
  242.                     {
  243.                         throw new ObjectDisposedException("theStream");
  244.                     }
  245.                     byte[] buffer = new byte[this.Length];
  246.                     this.Seek(0L, SeekOrigin.Begin);
  247.                     Stream stream = File.OpenWrite(FileName);
  248.                     while ((num = this.Read(buffer, 0, 0x400)) > 0)
  249.                     {
  250.                         stream.Write(buffer, 0, num);
  251.                     }
  252.                     stream.Close();
  253.                 }

  254.                 public override long Seek(long offset, SeekOrigin origin)
  255.                 {
  256.                     if (this.fileStream == null)
  257.                     {
  258.                         throw new ObjectDisposedException("theStream");
  259.                     }
  260.                     long num = 0L;
  261.                     object obj2 = num;
  262.                     GCHandle handle = new GCHandle();
  263.                     try
  264.                     {
  265.                         handle = GCHandle.Alloc(obj2, GCHandleType.Pinned);
  266.                         IntPtr plibNewPosition = handle.AddrOfPinnedObject();
  267.                         this.fileStream.Seek(offset, (int)origin, plibNewPosition);
  268.                         num = (long)obj2;
  269.                     }
  270.                     finally
  271.                     {
  272.                         if (handle.IsAllocated)
  273.                         {
  274.                             handle.Free();
  275.                         }
  276.                     }
  277.                     return num;
  278.                 }

  279.                 public override void SetLength(long Value)
  280.                 {
  281.                     if (this.fileStream == null)
  282.                     {
  283.                         throw new ObjectDisposedException("theStream");
  284.                     }
  285.                     this.fileStream.SetSize(Value);
  286.                 }

  287.                 public override void Write(byte[] buffer, int offset, int count)
  288.                 {
  289.                     if (this.fileStream == null)
  290.                     {
  291.                         throw new ObjectDisposedException("theStream");
  292.                     }
  293.                     if (offset != 0)
  294.                     {
  295.                         int length = buffer.Length - offset;
  296.                         byte[] destinationArray = new byte[length];
  297.                         Array.Copy(buffer, offset, destinationArray, 0, length);
  298.                         this.fileStream.Write(destinationArray, length, IntPtr.Zero);
  299.                     }
  300.                     else
  301.                     {
  302.                         this.fileStream.Write(buffer, count, IntPtr.Zero);
  303.                     }
  304.                 }

  305.                 // Properties
  306.                 public override bool CanRead
  307.                 {
  308.                     get
  309.                     {
  310.                         return (this.fileStream != null);
  311.                     }
  312.                 }

  313.                 public override bool CanSeek
  314.                 {
  315.                     get
  316.                     {
  317.                         return true;
  318.                     }
  319.                 }

  320.                 public override bool CanWrite
  321.                 {
  322.                     get
  323.                     {
  324.                         return true;
  325.                     }
  326.                 }

  327.                 public string FileName
  328.                 {
  329.                     get
  330.                     {
  331.                         return this.fileName;
  332.                     }
  333.                     set
  334.                     {
  335.                         this.fileName = value;
  336.                     }
  337.                 }

  338.                 public string FilePath
  339.                 {
  340.                     get
  341.                     {
  342.                         return this.filePath;
  343.                     }
  344.                     set
  345.                     {
  346.                         this.filePath = value;
  347.                     }
  348.                 }

  349.                 public IStorage FileStorage
  350.                 {
  351.                     get
  352.                     {
  353.                         return this.fileStorage;
  354.                     }
  355.                     set
  356.                     {
  357.                         this.fileStorage = value;
  358.                     }
  359.                 }

  360.                 public UCOMIStream FileStream
  361.                 {
  362.                     get
  363.                     {
  364.                         return this.fileStream;
  365.                     }
  366.                     set
  367.                     {
  368.                         this.fileStream = value;
  369.                     }
  370.                 }

  371.                 public int FileType
  372.                 {
  373.                     get
  374.                     {
  375.                         return this.fileType;
  376.                     }
  377.                     set
  378.                     {
  379.                         this.fileType = value;
  380.                     }
  381.                 }

  382.                 public string FileUrl
  383.                 {
  384.                     get
  385.                     {
  386.                         return (IBaseStorageWrapper.BaseUrl + this.FilePath.Replace(@"/", "/") + "/" + this.FileName);
  387.                     }
  388.                     set
  389.                     {
  390.                         this.fileUrl = value;
  391.                     }
  392.                 }

  393.                 public override long Length
  394.                 {
  395.                     get
  396.                     {
  397.                         STATSTG statstg;
  398.                         if (this.fileStream == null)
  399.                         {
  400.                             throw new ObjectDisposedException("theStream");
  401.                         }
  402.                         this.fileStream.Stat(out statstg, 1);
  403.                         return statstg.cbSize;
  404.                     }
  405.                 }

  406.                 public override long Position
  407.                 {
  408.                     get
  409.                     {
  410.                         return this.Seek(0L, SeekOrigin.Current);
  411.                     }
  412.                     set
  413.                     {
  414.                         this.Seek(value, SeekOrigin.Begin);
  415.                     }
  416.                 }
  417.             }
  418.         }
  419.     }

  420.  

  421. }

QQMsgMgr.cs -- 从vbvan处修改而来,主要修改了一直占用MsgEx.db的毛病

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.IO;
  5. using System.Text;
  6. using RelatedObjects.Storage;

  7. namespace QQBackup
  8. {
  9.     public enum QQMsgType
  10.     {
  11.         BIM, C2C, Group, Sys, Mobile, TempSession //Disc
  12.     }

  13.     class QQMsgMgr
  14.     {
  15.         private static readonly int s_MsgTypeNum = (int)QQMsgType.TempSession + 1;
  16.         private static readonly string[] s_MsgName = new string[] {
  17.             "BIMMsg""C2CMsg""GroupMsg""SysMsg""MobileMsg""TempSessionMsg"
  18.         };
  19.         private IStorageWrapper m_Storage;
  20.         private byte[] m_Password;

  21.         private List<string>[] m_MsgList = new List<string>[s_MsgTypeNum];

  22.         public void Open(string QQID)
  23.         {
  24.             Open(QQID, null);
  25.         }

  26.         public void Open(string QQID, string QQPath)
  27.         {
  28.             if (QQPath == null)
  29.             {
  30.                 using (Microsoft.Win32.RegistryKey reg = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"Software/Tencent/QQ"))
  31.                 {
  32.                     QQPath = reg.GetValue("Install"as string;
  33.                 }
  34.                 if (QQPath == nullreturn;
  35.             }

  36.             for (int i = 0; i < m_MsgList.Length; ++i)
  37.             {
  38.                 m_MsgList[i] = new List<string>();
  39.             }
  40.             m_Storage = null;
  41.             m_Password = null;

  42.             m_Storage = new IStorageWrapper(QQPath + QQID + @"/MsgEx.db");
  43.             m_Password = QQMsgMgr.GetGlobalPass(m_Storage, QQID);
  44.             
  45.             if (m_Password == null) m_Storage = null;

  46.             foreach (IBaseStorageWrapper.FileObjects.FileObject fileObject in m_Storage.foCollection)
  47.             {
  48.                 if (fileObject.FileType == 1)
  49.                 {
  50.                     for (int i = 0; i < m_MsgList.Length; ++i)
  51.                     {
  52.                         if (fileObject.FilePath == s_MsgName[i])
  53.                         {
  54.                             m_MsgList[i].Add(fileObject.FileName);
  55.                         }
  56.                     }
  57.                 }
  58.             }
  59.         }

  60.         public void OutputMsg()
  61.         {
  62.             for (int i = 0; i < s_MsgTypeNum; ++i)
  63.             {
  64.                 OutputMsg((QQMsgType)i);
  65.             }
  66.         }

  67.         public void OutputMsg(QQMsgType type)
  68.         {
  69.             if (m_Storage == nullreturn;
  70.             if (m_Password == nullreturn;

  71.             int typeIndex = (int)type;
  72.             if (typeIndex < 0 || typeIndex >= s_MsgTypeNum)
  73.             {
  74.                 throw new ArgumentException("Invalid QQMsgType""type");
  75.             }

  76.             string filePath = s_MsgName[typeIndex] + "//";
  77.             Directory.CreateDirectory(filePath);

  78.             foreach (string QQID in m_MsgList[typeIndex])
  79.             {
  80.                 string fileName = filePath + QQID + ".txt";
  81.                 OutputMsg(type, QQID, fileName);
  82.             }
  83.         }

  84.         public void OutputMsg(QQMsgType type, string QQID)
  85.         {
  86.             if (m_Storage == nullreturn;
  87.             if (m_Password == nullreturn;

  88.             int typeIndex = (int)type;
  89.             if (typeIndex < 0 || typeIndex >= s_MsgTypeNum)
  90.             {
  91.                 throw new ArgumentException("Invalid QQMsgType""type");
  92.             }

  93.             string filePath = s_MsgName[typeIndex] + "//";
  94.             Directory.CreateDirectory(filePath);

  95.             string fileName = filePath + QQID + ".txt";
  96.             OutputMsg(type, QQID, fileName);
  97.         }

  98.         private void OutputMsg(QQMsgType type, string QQID, string fileName)
  99.         {
  100.             string msgPath = s_MsgName[(int)type] + QQID;
  101.             IList<byte[]> msgList = QQMsgMgr.DecryptMsg(m_Storage, msgPath, m_Password);
  102.             Encoding encoding = Encoding.GetEncoding(936);

  103.             using (FileStream fs = new FileStream(fileName, FileMode.Create))
  104.             {
  105.                 using (StreamWriter sw = new StreamWriter(fs))
  106.                 {
  107.                     for (int i = 0; i < msgList.Count; ++i)
  108.                     {
  109.                         using (MemoryStream ms = new MemoryStream(msgList[i]))
  110.                         {
  111.                             using (BinaryReader br = new BinaryReader(ms, Encoding.GetEncoding(936)))
  112.                             {
  113. #if false
  114.                                 fs.Write(msgList[i], 0, msgList[i].Length);
  115. #else
  116.                                 int ticks = br.ReadInt32();
  117.                                 DateTime time = new DateTime(1970, 1, 1) + new TimeSpan(0, 0, ticks);
  118.                                 switch (type)
  119.                                 {
  120.                                     case QQMsgType.BIM:
  121.                                     case QQMsgType.C2C:
  122.                                     case QQMsgType.Mobile:
  123.                                         ms.Seek(1, SeekOrigin.Current);
  124.                                         break;
  125.                                     case QQMsgType.Group:
  126.                                         ms.Seek(8, SeekOrigin.Current);
  127.                                         break;
  128.                                     case QQMsgType.Sys:
  129.                                         ms.Seek(4, SeekOrigin.Current);
  130.                                         break;
  131.                                     case QQMsgType.TempSession: //?
  132.                                         ms.Seek(9, SeekOrigin.Current);
  133.                                         break;
  134.                                 }
  135.                                 if (type == QQMsgType.TempSession)
  136.                                 {
  137.                                     int gLen = br.ReadInt32();
  138.                                     string groupName = encoding.GetString(br.ReadBytes(gLen));
  139.                                     if (groupName.Length > 0) sw.WriteLine("{0}", groupName);
  140.                                 }
  141.                                 int nLen = br.ReadInt32();
  142.                                 string id = encoding.GetString(br.ReadBytes(nLen));
  143.                                 sw.WriteLine("{0}: {1}", id, time.ToString());
  144.                                 int cLen = br.ReadInt32();
  145.                                 string msg = encoding.GetString(br.ReadBytes(cLen));
  146.                                 //msg=msg.Replace("/n", Environment.NewLine);
  147.                                 msg = msg.Replace(new string(new char[] { (char)21 }), "(图片)");
  148.                                 msg = msg.Replace(new string(new char[] { (char)20 }), "(表情)");
  149.                                 char[] t = msg.ToCharArray();
  150.                                 msg=msg.Split((char)19)[0];
  151.                                 msg = msg.Replace("/n", Environment.NewLine);
  152.                                 sw.WriteLine(msg);
  153.                                 sw.WriteLine();
  154. #endif
  155.                             }
  156.                         }
  157.                     }
  158.                     sw.Close();
  159.                 }
  160.                 fs.Close();
  161.             }
  162.             
  163.         }

  164.         public void OutputFileList()
  165.         {
  166.             if (m_Storage == nullreturn;

  167.             Dictionary<stringlong> dic = new Dictionary<stringlong>();
  168.             foreach (IBaseStorageWrapper.FileObjects.FileObject fileObject in m_Storage.foCollection)
  169.             {
  170.                 if (fileObject.FileType == 2 && fileObject.FileName == "Index.msj")
  171.                 {
  172.                     dic[fileObject.FilePath] = fileObject.Length / 4;
  173.                 }
  174.             }

  175.             for (int i = 0; i < m_MsgList.Length; ++i)
  176.             {
  177.                 Console.WriteLine("{0}", s_MsgName[i]);
  178.                 foreach (string ID in m_MsgList[i])
  179.                 {
  180.                     Console.WriteLine("/t{0}: {1}", ID, dic[s_MsgName[i] + ID]);
  181.                 }
  182.             }
  183.         }

  184.         private static IBaseStorageWrapper.FileObjects.FileObject GetStorageFileObject(IStorageWrapper iw, string path, string fileName)
  185.         {
  186.             foreach (IBaseStorageWrapper.FileObjects.FileObject fileObject in iw.foCollection)
  187.             {
  188.                 if (fileObject.CanRead)
  189.                 {
  190.                     if (fileObject.FilePath == path && fileObject.FileName == fileName) return fileObject;
  191.                 }
  192.             }
  193.             return null;
  194.         }
  195.         
  196.         private static byte[] Decrypt(byte[] src, byte[] pass, long offset)
  197.         {
  198.             RedQ.QQCrypt decryptor = new RedQ.QQCrypt();
  199.             return decryptor.QQ_Decrypt(src, pass, offset);
  200.         }

  201.         private static IList<byte[]> DecryptMsg(IStorageWrapper iw, string path, byte[] pass)
  202.         {
  203.             List<byte[]> msgList = new List<byte[]>();

  204.             int num = 0;
  205.             int[] pos = null;
  206.             int[] len = null;
  207.             using (IBaseStorageWrapper.FileObjects.FileObject fileObject = GetStorageFileObject(iw, path, "Index.msj"))
  208.             {
  209.                 if (fileObject == nullreturn msgList;
  210.                 int fileLen = (int)fileObject.Length;
  211.                 num = fileLen / 4;
  212.                 pos = new int[num + 1];
  213.                 using (BinaryReader br = new BinaryReader(fileObject))
  214.                 {
  215.                     for (int i = 0; i < num; ++i)
  216.                     {
  217.                         pos[i] = br.ReadInt32();
  218.                     }
  219.                 }
  220.             }
  221.             using (IBaseStorageWrapper.FileObjects.FileObject fileObject = GetStorageFileObject(iw, path, "Data.msj"))
  222.             {
  223.                 if (fileObject != null)
  224.                 {
  225.                     int fileLen = (int)fileObject.Length;
  226.                     len = new int[num];
  227.                     pos[num] = fileLen;
  228.                     for (int i = 0; i < num; ++i)
  229.                     {
  230.                         len[i] = pos[i + 1] - pos[i];
  231.                     }
  232.                     using (BinaryReader br = new BinaryReader(fileObject))
  233.                     {
  234.                         for (int i = 0; i < num; ++i)
  235.                         {
  236.                             fileObject.Seek(pos[i], SeekOrigin.Begin);
  237.                             byte[] data = br.ReadBytes(len[i]);
  238.                             byte[] msg = Decrypt(data, pass, 0);
  239.                             msgList.Add(msg);
  240.                         }
  241.                     }
  242.                 }
  243.             }
  244.             return msgList;
  245.         }

  246.         private static byte[] GetGlobalPass(IStorageWrapper iw, string QQID)
  247.         {
  248.             System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
  249.             byte[] dataID = new byte[QQID.Length];
  250.             for (int i = 0; i < QQID.Length; ++i) dataID[i] = (byte)(QQID[i]);
  251.             byte[] hashID = md5.ComputeHash(dataID);
  252.             IBaseStorageWrapper.FileObjects.FileObject fileObject = GetStorageFileObject(iw, "Matrix""Matrix.db");
  253.             if (fileObject != null)
  254.             {
  255.                 using (BinaryReader br = new BinaryReader(fileObject))
  256.                 {
  257.                     byte[] data = br.ReadBytes((int)fileObject.Length);
  258.                     long len = data.Length;
  259.                     if (len < 6 || data[0] != 0x51 || data[1] != 0x44) return null;
  260.                     if (len >= 32768) return null;

  261.                     bool bl = false;
  262.                     int i = 6;
  263.                     while (i < len)
  264.                     {
  265.                         bl = false;
  266.                         byte type = data[i++];
  267.                         if (i + 2 > len) break;
  268.                         int len1 = data[i] + data[i + 1] * 256;
  269.                         byte xor1 = (byte)(data[i] ^ data[i + 1]);
  270.                         i += 2;
  271.                         if (i + len1 > len) break;
  272.                         for (int j = 0; j < len1; ++j) data[i + j] = (byte)(~(data[i + j] ^ xor1));
  273.                         if (len1 == 3 && data[i] == 0x43 && data[i + 1] == 0x52 && data[i + 2] == 0x4B)
  274.                         {
  275.                             bl = true;
  276.                         }
  277.                         i += len1;

  278.                         if (type > 7) break;
  279.                         if (i + 4 > len) break;
  280.                         int len2 = data[i] + data[i + 1] * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 * 256 * 256;
  281.                         byte xor2 = (byte)(data[i] ^ data[i + 1]);
  282.                         i += 4;
  283.                         if (i + len2 > len) break;
  284.                         if (type == 6 || type == 7)
  285.                         {
  286.                             for (int j = 0; j < len2; ++j) data[i + j] = (byte)(~(data[i + j] ^ xor2));
  287.                         }
  288.                         if (bl && len2 == 0x20)
  289.                         {
  290.                             byte[] dataT = new byte[len2];
  291.                             for (int j = 0; j < len2; ++j) dataT[j] = data[i + j];
  292.                             return Decrypt(dataT, hashID, 0);
  293.                         }
  294.                         i += len2;
  295.                     }
  296.                     if (i != len) return null;
  297.                 }
  298.             }
  299.             return null;
  300.         }

  301.         public void Close(string QQID) {
  302.             if (m_Storage == null)
  303.             {
  304.                 return;
  305.             }
  306.             else {
  307.                 m_Storage = null;

  308.             }
  309.         }
  310.     }
  311. }

QQCrypt.cs -- 原封未动,直接copy过来的

  1. using System;

  2. namespace RedQ
  3. {
  4.     /**//// <summary>
  5.     /// QQ Msg En/DeCrypt Class
  6.     /// Writen By Red_angelX On 2006.9.13
  7.     /// </summary>
  8.     public class QQCrypt
  9.     {    
  10.         //QQ TEA-16 Encrypt/Decrypt Class 
  11.         // 
  12.         // 
  13.         //And also LumaQQ//s source code 
  14.         //  CopyRight:No CopyRight^_^ 
  15.         //  Author : Red_angelX     
  16.         //  NetWork is Free,Tencent is ****!
  17.         // 
  18.         //Class Begin 
  19.         //AD:Find Job!!,If you Want Give me a Job,Content Me!!

  20.         //Copied & translated from LumaQQ//s source code          `From LumaQQ///s source code: 
  21.         private byte[] Plain;                                   //指向当前的明文块 
  22.         private byte[] prePlain ;                               //指向前面一个明文块 
  23.         private byte[] Out;                                     //输出的密文或者明文 
  24.         private long Crypt, preCrypt;                           //当前加密的密文位置和上一次加密的密文块位置,他们相差8 
  25.         private long Pos;                                       //当前处理的加密解密块的位置 
  26.         private long padding;                                   //填充数 
  27.         private byte[] Key = new byte[16];                      //密钥 
  28.         private bool Header;                                    //用于加密时,表示当前是否是第一个8字节块,因为加密算法 
  29.                                                                 //是反馈的,但是最开始的8个字节没有反馈可用,所有需要标 
  30.                                                                 //明这种情况 
  31.         private long contextStart;                              //这个表示当前解密开始的位置,之所以要这么一个变量是为了 
  32.                                                                 //避免当解密到最后时后面已经没有数据,这时候就会出错,这 
  33.                                                                 //个变量就是用来判断这种情况免得出错 
  34.         public QQCrypt()
  35.         {
  36.             //
  37.             // TODO: 在此处添加构造函数逻辑
  38.             //
  39.         }
  40.         

  41.         //Push 数据
  42.         byte[] CopyMemory(byte[] arr,int arr_index,long input)  //lenth = 4
  43.         {
  44.             if(arr_index+4 > arr.Length)
  45.             {
  46.                 // 不能执行
  47.                 return arr;
  48.             }

  49.             arr[arr_index+3]=(byte)((input & 0xff000000) >> 24);
  50.             arr[arr_index+2]=(byte)((input & 0x00ff0000) >> 16);
  51.             arr[arr_index+1]=(byte)((input & 0x0000ff00) >> 8);
  52.             arr[arr_index]=(byte)(input & 0x000000ff);

  53.             arr[arr_index] &= 0xff;
  54.             arr[arr_index+1] &= 0xff;
  55.             arr[arr_index+2] &= 0xff;
  56.             arr[arr_index+3] &= 0xff;

  57.             return arr;
  58.         }

  59.         long CopyMemory(long Out,byte[] arr,int arr_index)
  60.         {
  61.             if(arr_index+4 > arr.Length)
  62.             {
  63.                 return Out;
  64.                 //不能执行
  65.             }

  66.             long x1 = arr[arr_index+3] << 24;
  67.             long x2 = arr[arr_index+2] << 16;
  68.             long x3 = arr[arr_index+1] << 8;
  69.             long x4 = arr[arr_index];

  70.             long o = x1 | x2 | x3 | x4;
  71.             o &= 0xffffffff;
  72.             return o;
  73.         }

  74.         long getUnsignedInt(byte[] arrayIn, int offset,int len /**//*Default is 4*/
  75.         {

  76.             long ret = 0;
  77.             int end = 0;
  78.             if (len > 8)
  79.                 end = offset + 8;
  80.             else
  81.                 end = offset + len;
  82.             for (int i = offset; i < end; i++) 
  83.             {
  84.                 ret <<= 8;
  85.                 ret |= arrayIn[i] & 0xff;
  86.             }
  87.             return (ret & 0xffffffff) | (ret >> 32);
  88.         }

  89.         long Rand()
  90.         {
  91.             Random rd = new Random();
  92.             long ret;
  93.             ret = rd.Next() + (rd.Next() % 1024);
  94.             return ret;
  95.         }

  96.         private byte[] Decipher(byte[] arrayIn,byte[] arrayKey,long offset)
  97.         {
  98.             //long Y,z,a,b,c,d;
  99.             long sum,delta;
  100.             //Y=z=a=b=c=d=0;
  101.             byte[] tmpArray = new byte[24];
  102.             byte[] tmpOut = new byte[8];
  103.             if(arrayIn.Length < 8)
  104.             {
  105.                 // Error:return
  106.                 return tmpOut;
  107.             }
  108.             if(arrayKey.Length < 16)
  109.             {
  110.                 // Error:return
  111.                 return tmpOut;
  112.             }
  113.             sum = 0xE3779B90; 
  114.             sum = sum & 0xFFFFFFFF; 
  115.             delta = 0x9E3779B9; 
  116.             delta = delta & 0xFFFFFFFF; 
  117.             /**//*tmpArray[3] = arrayIn[offset]; 
  118.             tmpArray[2] = arrayIn[offset + 1]; 
  119.             tmpArray[1] = arrayIn[offset + 2]; 
  120.             tmpArray[0] = arrayIn[offset + 3]; 
  121.             tmpArray[7] = arrayIn[offset + 4]; 
  122.             tmpArray[6] = arrayIn[offset + 5]; 
  123.             tmpArray[5] = arrayIn[offset + 6]; 
  124.             tmpArray[4] = arrayIn[offset + 7]; 
  125.             tmpArray[11] = arrayKey[0]; 
  126.             tmpArray[10] = arrayKey[1]; 
  127.             tmpArray[9] = arrayKey[2]; 
  128.             tmpArray[8] = arrayKey[3]; 
  129.             tmpArray[15] = arrayKey[4]; 
  130.             tmpArray[14] = arrayKey[5]; 
  131.             tmpArray[13] = arrayKey[6]; 
  132.             tmpArray[12] = arrayKey[7]; 
  133.             tmpArray[19] = arrayKey[8]; 
  134.             tmpArray[18] = arrayKey[9]; 
  135.             tmpArray[17] = arrayKey[10]; 
  136.             tmpArray[16] = arrayKey[11]; 
  137.             tmpArray[23] = arrayKey[12]; 
  138.             tmpArray[22] = arrayKey[13]; 
  139.             tmpArray[21] = arrayKey[14]; 
  140.             tmpArray[20] = arrayKey[15]; 
  141.             Y=CopyMemory(Y,tmpArray,0);    
  142.             z=CopyMemory(z,tmpArray,4);
  143.             a=CopyMemory(a,tmpArray,8);
  144.             b=CopyMemory(b,tmpArray,12);
  145.             c=CopyMemory(c,tmpArray,16);
  146.             d=CopyMemory(d,tmpArray,20);*/
  147.             long Y = getUnsignedInt(arrayIn, (int)offset, 4);
  148.             long z = getUnsignedInt(arrayIn, (int)offset + 4, 4);
  149.             long a = getUnsignedInt(arrayKey, 0, 4);
  150.             long b = getUnsignedInt(arrayKey, 4, 4);
  151.             long c = getUnsignedInt(arrayKey, 8, 4);
  152.             long d = getUnsignedInt(arrayKey, 12, 4);
  153.             for(int i=1;i<=16;i++)
  154.             {
  155.                 z -= ((Y<<4)+c) ^ (Y+sum) ^ ((Y>>5)+d);
  156.                 z &= 0xFFFFFFFF;
  157.                 Y -= ((z<<4)+a) ^ (z+sum) ^ ((z>>5)+b);
  158.                 Y &= 0xFFFFFFFF;
  159.                 sum -= delta;
  160.                 sum &= 0xFFFFFFFF; 
  161.             }

  162.             tmpArray = CopyMemory(tmpArray,0,Y);
  163.             tmpArray = CopyMemory(tmpArray,4,z);
  164.             tmpOut[0] = tmpArray[3]; 
  165.             tmpOut[1] = tmpArray[2]; 
  166.             tmpOut[2] = tmpArray[1]; 
  167.             tmpOut[3] = tmpArray[0]; 
  168.             tmpOut[4] = tmpArray[7]; 
  169.             tmpOut[5] = tmpArray[6]; 
  170.             tmpOut[6] = tmpArray[5]; 
  171.             tmpOut[7] = tmpArray[4]; 

  172.             return tmpOut;    
  173.         }

  174.         private byte[] Decipher(byte[] arrayIn,byte[] arrayKey)
  175.         {
  176.             return Decipher(arrayIn,arrayKey,0);
  177.         }

  178.         private byte[] Encipher(byte[] arrayIn,byte[] arrayKey,long offset)
  179.         {
  180.             byte[] tmpOut = new byte[8];
  181.             byte[] tmpArray = new byte[24];
  182.             //long Y,z,a,b,c,d;
  183.             //Y=z=a=b=c=d=0;
  184.             long sum,delta;
  185.             if(arrayIn.Length < 8)
  186.             {
  187.                 // Error:
  188.                 return tmpOut;
  189.             }
  190.             if(arrayKey.Length < 16)
  191.             {
  192.                 // Error:
  193.                 return tmpOut;
  194.             }
  195.             sum = 0;
  196.             delta = 0x9E3779B9;
  197.             delta &= 0xFFFFFFFF;

  198.             /**//*tmpArray[3] = arrayIn[offset]; 
  199.             tmpArray[2] = arrayIn[offset + 1]; 
  200.             tmpArray[1] = arrayIn[offset + 2]; 
  201.             tmpArray[0] = arrayIn[offset + 3]; 
  202.             tmpArray[7] = arrayIn[offset + 4]; 
  203.             tmpArray[6] = arrayIn[offset + 5]; 
  204.             tmpArray[5] = arrayIn[offset + 6]; 
  205.             tmpArray[4] = arrayIn[offset + 7]; 
  206.             tmpArray[11] = arrayKey[0]; 
  207.             tmpArray[10] = arrayKey[1]; 
  208.             tmpArray[9] = arrayKey[2]; 
  209.             tmpArray[8] = arrayKey[3]; 
  210.             tmpArray[15] = arrayKey[4]; 
  211.             tmpArray[14] = arrayKey[5]; 
  212.             tmpArray[13] = arrayKey[6]; 
  213.             tmpArray[12] = arrayKey[7]; 
  214.             tmpArray[19] = arrayKey[8];
  215.             tmpArray[18] = arrayKey[9]; 
  216.             tmpArray[17] = arrayKey[10]; 
  217.             tmpArray[16] = arrayKey[11]; 
  218.             tmpArray[23] = arrayKey[12]; 
  219.             tmpArray[22] = arrayKey[13]; 
  220.             tmpArray[21] = arrayKey[14]; 
  221.             tmpArray[20] = arrayKey[15]; 

  222.             Y=CopyMemory(Y,tmpArray,0);
  223.             z=CopyMemory(z,tmpArray,4);
  224.             a=CopyMemory(a,tmpArray,8);
  225.             b=CopyMemory(b,tmpArray,12);
  226.             c=CopyMemory(c,tmpArray,16);
  227.             d=CopyMemory(d,tmpArray,20);*/

  228.             long Y = getUnsignedInt(arrayIn, (int)offset, 4);
  229.             long z = getUnsignedInt(arrayIn, (int)offset + 4, 4);
  230.             long a = getUnsignedInt(arrayKey, 0, 4);
  231.             long b = getUnsignedInt(arrayKey, 4, 4);
  232.             long c = getUnsignedInt(arrayKey, 8, 4);
  233.             long d = getUnsignedInt(arrayKey, 12, 4);

  234.             for(int i=1;i<=16;i++)
  235.             {
  236.                 sum += delta;
  237.                 sum &= 0xFFFFFFFF;
  238.                 Y += ((z<<4)+a) ^ (z+sum) ^ ((z>>5)+b);
  239.                 Y &= 0xFFFFFFFF;
  240.                 z += ((Y<<4)+c) ^ (Y+sum) ^ ((Y>>5)+d);
  241.                 z &= 0xFFFFFFFF;
  242.             }

  243.             tmpArray = CopyMemory(tmpArray,0,Y);
  244.             tmpArray = CopyMemory(tmpArray,4,z);

  245.             tmpOut[0] = tmpArray[3]; 
  246.             tmpOut[1] = tmpArray[2]; 
  247.             tmpOut[2] = tmpArray[1];
  248.             tmpOut[3] = tmpArray[0]; 
  249.             tmpOut[4] = tmpArray[7]; 
  250.             tmpOut[5] = tmpArray[6]; 
  251.             tmpOut[6] = tmpArray[5]; 
  252.             tmpOut[7] = tmpArray[4]; 
  253.         
  254.             return tmpOut;
  255.         }
  256.         

  257.         private byte[] Encipher(byte[] arrayIn,byte[] arrayKey)
  258.         {
  259.             return Encipher(arrayIn,arrayKey,0);
  260.         }
  261.         
  262.         private void Encrypt8Bytes()
  263.         {
  264.             byte[] Crypted;
  265.             for(Pos=0;Pos<=7;Pos++)
  266.             {
  267.                 if(this.Header == true)
  268.                 {
  269.                     Plain[Pos] = (byte)(Plain[Pos] ^ prePlain[Pos]);
  270.                 }
  271.                 else
  272.                 {
  273.                     Plain[Pos] = (byte)(Plain[Pos] ^ Out[preCrypt + Pos]);
  274.                 }
  275.             }
  276.             Crypted = Encipher(Plain,Key);
  277.             
  278.             for(int i=0;i<=7;i++)
  279.             {
  280.                 Out[Crypt + i] = (byte)Crypted[i];
  281.             }
  282.             
  283.             for(Pos=0;Pos<=7;Pos++)
  284.             {
  285.                 Out[Crypt + Pos] = (byte)(Out[Crypt + Pos] ^ prePlain[Pos]);
  286.             }            
  287.             Plain.CopyTo(prePlain,0);
  288.             preCrypt = Crypt;
  289.             Crypt = Crypt + 8;
  290.             Pos = 0;
  291.             Header = false;
  292.         }

  293.         private bool Decrypt8Bytes(byte[] arrayIn,long offset)
  294.         {
  295.             long lngTemp;
  296.             for(Pos=0;Pos<=7;Pos++)
  297.             {
  298.                 if(this.contextStart+Pos > arrayIn.Length-1) 
  299.                 {
  300.                     return true;
  301.                 }
  302.                 prePlain[Pos] = (byte)(prePlain[Pos] ^ arrayIn[offset+Crypt+Pos]);
  303.             }
  304.             try
  305.             {
  306.                 prePlain = this.Decipher(prePlain,Key);
  307.             }
  308.             catch
  309.             {
  310.                 return false;
  311.             }
  312.             lngTemp = prePlain.Length - 1;
  313.             contextStart += 8;
  314.             Crypt+=8;
  315.             Pos = 0;
  316.             return true;
  317.         }

  318.         private bool Decrypt8Bytes(byte[] arrayIn)
  319.         {
  320.             return Decrypt8Bytes(arrayIn,0);
  321.         }


  322.         #region Public Methods!

  323.         /**//// <summary>
  324.         /// QQ TEA 加密函数
  325.         /// </summary>
  326.         /// <param name="arrayIn">要加密的字串</param>
  327.         /// <param name="arrayKey">密钥</param>
  328.         /// <param name="offset">偏移</param>
  329.         /// <returns></returns>
  330.         public byte[] QQ_Encrypt(byte[] arrayIn,byte[] arrayKey,long offset)
  331.         {
  332.             Plain = new byte[8];
  333.             prePlain = new byte[8];
  334.             long l;
  335.             Pos = 1;
  336.             padding = 0;
  337.             Crypt = preCrypt = 0;
  338.             arrayKey.CopyTo(Key,0);    // Key Must Be 16 Length!
  339.             Header = true;
  340.             Pos = 2;
  341.             //计算头部填充字节数
  342.             Pos = (arrayIn.Length+10) % 8;
  343.             if(Pos != 0)
  344.                 Pos = 8-Pos;
  345.             //输出长度
  346.             Out = new byte[arrayIn.Length+Pos+10];
  347.             //把POS存到PLAIN的第一个字节
  348.             //0xf8后面3位是空的,正好给Pos
  349.             Plain[0] = (byte)((Rand() & 0xf8) | Pos);
  350.             //用随机数填充1到Pos的内容
  351.             for(int i=1;i<=Pos;i++)
  352.             {
  353.                 Plain[i] = (byte)(Rand() & 0xff);
  354.             }
  355.             Pos++;
  356.             padding = 1;

  357.             //继续填充两个字节随机数,满8字节就加密
  358.             while(padding < 3)
  359.             {
  360.                 if( Pos < 8)
  361.                 {
  362.                     Plain[Pos] = (byte)(Rand() & 0xff);
  363.                     padding++;
  364.                     Pos++;
  365.                 }
  366.                 else if(Pos == 8)
  367.                 {
  368.                     this.Encrypt8Bytes();
  369.                 }
  370.             }

  371.             int I = (int)offset;
  372.             l = 0;
  373.             //明文内容,满8字节加密到读完
  374.             l = arrayIn.Length;
  375.             while ( l > 0)
  376.             {
  377.                 if(Pos<8)
  378.                 {
  379.                     Plain[Pos] = arrayIn[I];
  380.                     I++;
  381.                     Pos++;
  382.                     l--;
  383.                 }
  384.                 else if(Pos == 8)
  385.                 {
  386.                     this.Encrypt8Bytes();
  387.                 }
  388.             }

  389.             //末尾填充0,保证是8的倍数
  390.             padding = 1;
  391.             while(padding < 9)      
  392.             {
  393.                 if(Pos<8)
  394.                 {
  395.                     Plain[Pos] = 0;
  396.                     Pos++;
  397.                     padding++;
  398.                 }
  399.                 else if(Pos == 8)
  400.                 {
  401.                     this.Encrypt8Bytes();
  402.                 }
  403.             }

  404.             return Out;
  405.         }


  406.         public byte[] QQ_Encrypt(byte[] arrayIn,byte[] arrayKey)
  407.         {
  408.             return QQ_Encrypt(arrayIn,arrayKey,0);
  409.         }

  410.         /**//// <summary>
  411.         ///  QQ TEA 解密函数
  412.         /// </summary>
  413.         /// <param name="arrayIn">要解密字串</param>
  414.         /// <param name="arrayKey">密钥</param>
  415.         /// <param name="offset">偏移</param>
  416.         /// <returns></returns>
  417.         public byte[] QQ_Decrypt(byte[] arrayIn,byte[] arrayKey,long offset)
  418.         {
  419.             byte[] error = new byte[0];
  420.             //检查是否是8的倍数至少16字节
  421.             if(arrayIn.Length < 16 || (arrayIn.Length % 8 != 0))
  422.             {
  423.                 //Return What?
  424.                 return error;
  425.             }
  426.             if(arrayKey.Length != 16)
  427.             {
  428.                 //Return What?
  429.                 return error;
  430.             }
  431.             byte[] m;
  432.             long I,Count;
  433.             m= new byte[offset+8];
  434.             arrayKey.CopyTo(Key,0);
  435.             Crypt = preCrypt = 0;
  436.             //计算消息头部,明文开始的偏移,解密第一字节和7相与得到
  437.             prePlain = this.Decipher(arrayIn,arrayKey,offset);
  438.             Pos = prePlain[0] & 7;
  439.             //计算明文长度
  440.             Count = arrayIn.Length - Pos - 10;
  441.             if(Count <= 0)
  442.             {
  443.                 //Return What?
  444.                 return error;
  445.             }
  446.             Out = new byte[Count];
  447.             preCrypt = 0;
  448.             Crypt = 8;
  449.             this.contextStart = 8;
  450.             Pos++;
  451.             padding = 1;
  452.             //跳过头部
  453.             while(padding < 3)
  454.             {
  455.                 if(Pos<8)
  456.                 {
  457.                     Pos++;
  458.                     padding++;
  459.                 }
  460.                 else if(Pos==8)
  461.                 {
  462.                     for(int i=0;i<m.Length;i++)
  463.                         m[i]=arrayIn[i];
  464.                     if(this.Decrypt8Bytes(arrayIn,offset) == false)
  465.                     {
  466.                         //Return What?
  467.                         return error;
  468.                     }
  469.                 }
  470.             }

  471.             //解密明文
  472.             I=0;
  473.             while(Count != 0)
  474.             {
  475.                 if(Pos<8)
  476.                 {
  477.                     Out[I] = (byte)(m[offset+preCrypt+Pos] ^ prePlain[Pos]);
  478.                     I++;
  479.                     Count--;
  480.                     Pos++;
  481.                 }
  482.                 else if(Pos == 8)
  483.                 {
  484.                     m = arrayIn;
  485.                     preCrypt = Crypt - 8;
  486.                     if(this.Decrypt8Bytes(arrayIn,offset) == false)
  487.                     {
  488.                         //Return What?
  489.                         return error;
  490.                     }
  491.                 }
  492.             }

  493.             //最后的解密部分,检查尾部是不是0
  494.             for(padding=1;padding<=7;padding++)
  495.             {
  496.                 if(Pos<8)
  497.                 {
  498.                     if( (m[offset+preCrypt+Pos] ^ prePlain[Pos]) != 0 )
  499.                     {
  500.                         //Return What?
  501.                         return error;
  502.                     }
  503.                     Pos++;
  504.                 }
  505.                 else if(Pos == 8)
  506.                 {
  507.                     for(int i=0;i<m.Length;i++)
  508.                         m[i] = arrayIn[i];
  509.                     preCrypt = Crypt;
  510.                     if(this.Decrypt8Bytes(arrayIn,offset) == false)
  511.                     {
  512.                         //Return What?
  513.                         return error;
  514.                     }
  515.                 }
  516.             }
  517.             return Out;
  518.         }

  519.         public byte[] QQ_Decrypt(byte[] arrayIn,byte[] arrayKey)
  520.         {
  521.             return QQ_Decrypt(arrayIn,arrayKey,0);
  522.         }
  523.         #endregion
  524.     }
  525. }

另外还有发邮件的代码就不发了,简单的调用cdosys.dll发的,还有调用rar.exe的也很简单,就几行代码,不贴了,自己反编译吧,我没混淆~~


不想直接发源码是讨厌很多人拿去改掉我的名字和网址就当自己的“原创”了。。。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值