NTFS文件系统数据恢复—-解析MFT表

  • Post author:
  • Post category:其他


http://blog.csdn.net/jha334201553/article/details/9089119


开始先说下DBR, DBR是继MBR 之后最先访问的地方,MBR利用int 13h 读取MBR并将之加载到物理地址0x7c00的地方. 然后将段地址:代码地址入栈后retf跳过去运行.




MBR利用BIOS中断int 13h读取数据加载到内存指定位置..传统的int 13h调用最多只能识别1024个磁头:




前面MBR讲解MBR的时候,有结构如下




/*+0x01*/   uchar    StartHead;         // 分区起始磁头号  (1磁头 = 63 扇区,取值 0~255 之间)




/*+0x02*/   uint16   StartSector:10;    // 启始柱面号 10位 (1柱面 = 255 磁头,取值 0~1023 之间)




/*+0x02*/   uint16   StartCylinder:6;   // 启始扇区号 6位 (取值 1 到 63 之间)




此结构可容纳最大值为FF FF FF (现在这个值基本都写成FE FF FF, 而废弃不用), 即最大能寻址的就是255柱面, 1023磁头, 63扇区,计算扇区个数为:




1023*255*63+255*63+63 = 16450623




再按每扇区 512 字节算, 那么它容量为  8 GB  ≈  512*16450623 B = 7.84 GB




传统的int 13h中断就受限于8G的限制, Microsoft等多家公司制定了int 13h扩展标准,让int 13h读写磁盘中断可以突破8G限制. 现在的计算机BIOS都是按扩展int 13h标准编写的代码.(具体详细内容可参考”扩展 int 13h规范”).




按MBR分区表里面的 SectionPrecedingPartition 逻辑扇区偏移(注意,这个逻辑扇区偏移是从0开始算的,读取出来值为63,而物理扇区是从1开始计算的,逻辑扇区转换物理扇区的时候必须+1才是正确的) 可以找到DBR的位置.可以看看winhex的显示


以下就偷懒不从MBR寻址分区的DBR了,而是直接打开盘符读取 (这样打开的第一个扇区就是DBR),这样做有个缺点,就是你用这个handle值将不能进行内存映射,只能一次多读取几个扇区来加快分析磁盘的速度(当前用的是一次读取20M数据然后分析)。



  1. HANDLE


    handle = CreateFile ( TEXT(


    “\\\\.\\C:”


    ) ,


  2. GENERIC_READ,

  3. FILE_SHARE_READ|FILE_SHARE_WRITE,

  4. NULL,

  5. OPEN_EXISTING,

  6. FILE_ATTRIBUTE_NORMAL,

  7. NULL);

DBR结构定义为(对照winhex模板信息查看):









  1. //





  2. //  NTFS 的DBR 数据结构





  3. //










  4. typedef




    struct


    _BIOS_PARAMETER_BLOCK {




  5. /*+0x0B*/


    uint16  BytesPerSector;


    // 字节/扇区一般为0x0200 即512





  6. /*+0x0D*/


    uchar   SectorsPerCluster;


    // 扇区/簇





  7. /*+0x0E*/


    uint16  ReservedSectors;


    // 保留扇区





  8. /*+0x0F*/


    uchar   Fats;


    //





  9. /*+0x11*/


    uint16  RootEntries;


    //





  10. /*+0x13*/


    uint16  Sectors;


    //





  11. /*+0x15*/


    uchar   Media;


    // 媒介描述





  12. /*+0x16*/


    uint16  SectorsPerFat;


    //





  13. /*+0x18*/


    uint16  SectorsPerTrack;


    // 扇区/磁轨





  14. /*+0x1A*/


    uint16  Heads;


    // 头





  15. /*+0x1C*/


    uint32  HiddenSectors;


    // 隐藏扇区





  16. /*+0x20*/


    uint32  LargeSectors;


    // checked when volume is mounted





  17. }BIOS_PARAMETER_BLOCK, *pBIOS_PARAMETER_BLOCK;



  18. typedef




    struct


    _NTFS_Boot_Sector{



  19. /*+0x00*/


    uchar    JmpCode[3];


    // 跳转指令





  20. /*+0x03*/




    char


    OemID[8];


    // 文件系统ID





  21. /*+0x0B*/


    BIOS_PARAMETER_BLOCK PackedBpb;


    // BPB





  22. /*+0x24*/


    uchar    Unused[4];


    // 未使用,总是为





  23. /*+0x28*/


    uint64   NumberSectors;


    // 扇区总数





  24. /*+0x30*/


    lcn      MftStartLcn;


    // 开始C# $MFT  (簇) 乘以 BIOS_PARAMETER_BLOCK.SectorsPerCluster 值得到扇区号





  25. /*+0x38*/


    lcn      Mft2StartLcn;


    // 开始C# $MFTMirr (簇)





  26. /*+0x40*/


    uchar    ClustersPerFileRecordSegment;


    // 文件记录大小指示器





  27. /*+0x41*/


    uchar   Reserved0[3];


    // 未使用





  28. /*+0x44*/


    uchar DefaultClustersPerIndexAllocationBuffer;


    // 簇/索引块





  29. /*+0x45*/


    uchar   Reserved1[3];


    // 未使用





  30. /*+0x48*/


    uint64  SerialNumber;


    // 64位序列号





  31. /*+0x50*/


    uint32  Checksum;


    // 校验和





  32. /*+0x54*/


    uchar   BootStrap[426];


    // 启动代码





  33. /*+0x1FE*/


    uint16  RecordEndSign;


    // 0xAA55 结束标记




  34. }NTFS_Boot_Sector, *pNTFS_Boot_Sector;


在读取DBR的时候,一些数据以后经常会用到,那么需要根据DBR里面的信息保存以后会用到的信息,下面定义一个常用的保存信息结构:



  1. // 保存 NTFS 的基本信息





  2. typedef




    struct


    _NTFS_INFO


  3. {

  4. uint32 BytesPerSector;

    // 每扇区的字节数




  5. uint32 SectorsPerCluster;

    // 每簇的扇区数




  6. uint32 BytesPerCluster;

    // 每簇的字节数




  7. uint64 SectorCount;

    // 扇区总数




  8. uint64 MftStart;

    // MFT表开始簇




  9. uint64 MftMirrStart;

    // MFT备份表开始簇




  10. uint32 BytesPerFileRecord;

    // 每个文件记录的字节数一般为512*2





  11. uint16 VolumeLabelLength;

    //  卷名长度,卷名从MFT第4个项0x60属性得到(与0x30属性相似)




  12. wchar VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH];

    // 卷名





  13. uint16 vcnlen;

  14. uchar vcn[VCN_LENTH];

  15. } NTFS_INFO, *PNTFS_INFO;


其中 MAXIMUM_VOLUE_LABEL_LENGTH定义为




  1. #define MAXIMUM_VOLUME_LABEL_LENGTH (32*sizeof(wchar))




NTFS_Boot_Sector .MftStartLcn*NTFS_Boot_Sector. PackedBpb .SectorsPerCluster得到MFT所在扇区号,这里为 786432*8 = 6291456扇区(字节偏移为 6291456*512= 3221225472 ( 十六进制0xC0000000))。然后MFT表里面的内容是根据簇号来读取数据的,那么可以定义一个根据簇号,读取数据的函数,如下形式:



  1. typedef




    struct


    _Partition_Stand_Post


  2. {


  3. HANDLE


    handle;


    // 分区句柄




  4. uint64 CluNnum;

    // 簇号




  5. uint32 BytesPerCluster;

    // 每簇字节




  6. uint64 CluCount;

    // 簇数量




  7. PNTFS_INFO NtfsInfo;

    // 指向NTFS_INFO 结构




  8. }Partition_Stand_Post, *pPartition_Stand_Post;



  9. // 按簇读取数据,





  10. // 传入 一个Partition_Stand_Post结构体指针,并指定buf,读取大小





  11. // 结果返回读取的数据指针





  12. PBYTE


    ReadClues(pPartition_Stand_Post post,


    PBYTE


    buf,


    DWORD


    lenth)


  13. {


  14. DWORD


    dwbytes = 0;


  15. LARGE_INTEGER li = {0};

  16. li.QuadPart = post->CluNnum*post->BytesPerCluster;

  17. SetFilePointer(post->handle, li.LowPart, &li.HighPart, FILE_BEGIN);

  18. ReadFile(post->handle, buf, lenth, &dwbytes, NULL);


  19. if


    (lenth == dwbytes)


  20. {


  21. return


    buf;


  22. }


  23. return


    NULL;


  24. }


下面先说MFT表的结构:

首先,看到的是头部,标记为”FILE”, 结构体如下定义:



  1. // 文件记录头





  2. typedef




    struct


    _FILE_RECORD_HEADER


  3. {


  4. /*+0x00*/


    uint32 Type;


    // 固定值’FILE’





  5. /*+0x04*/


    uint16 UsaOffset;


    // 更新序列号偏移, 与操作系统有关





  6. /*+0x06*/


    uint16 UsaCount;


    // 固定列表大小Size in words of Update Sequence Number & Array (S)





  7. /*+0x08*/


    uint64 Lsn;


    // 日志文件序列号(LSN)




  8. } FILE_RECORD_HEADER, *PFILE_RECORD_HEADER;



  9. // 文件记录体





  10. typedef




    struct


    _FILE_RECORD{



  11. /*+0x00*/


    FILE_RECORD_HEADER Ntfs;


    // MFT表头





  12. /*+0x10*/


    uint16  SequenceNumber;


    // 序列号(用于记录文件被反复使用的次数)





  13. /*+0x12*/


    uint16  LinkCount;


    // 硬连接数





  14. /*+0x14*/


    uint16  AttributeOffset;


    // 第一个属性偏移





  15. /*+0x16*/


    uint16  Flags;


    // falgs, 00表示删除文件,01表示正常文件,02表示删除目录,03表示正常目录





  16. /*+0x18*/


    uint32  BytesInUse;


    // 文件记录实时大小(字节) 当前MFT表项长度,到FFFFFF的长度+4





  17. /*+0x1C*/


    uint32  BytesAllocated;


    // 文件记录分配大小(字节)





  18. /*+0x20*/


    uint64  BaseFileRecord;


    // = 0 基础文件记录 File reference to the base FILE record





  19. /*+0x28*/


    uint16  NextAttributeNumber;


    // 下一个自由ID号





  20. /*+0x2A*/


    uint16  Pading;


    // 边界





  21. /*+0x2C*/


    uint32  MFTRecordNumber;


    // windows xp中使用,本MFT记录号





  22. /*+0x30*/


    uint32  MFTUseFlags;


    // MFT的使用标记




  23. }FILE_RECORD, *pFILE_RECORD;

这里主要关注的就是文件头大小(0x38)可以找到第一个属性地址,紧跟在后面的是文件类型,00表示被删除的文件,01表示正常文件,02表示删除目录,03表示正常目录.再后面就是这个MFT记录的数据大小(很奇怪,为什么数据大小是从头到0xFFFFFFFF的大小+4,这个值为什么不是直接从头到0xFFFFFFFF的大小呢?).

根据FILE头部数据找到下面的一个个属性,接下来分析的就是一个个属性了.


属性由属性头跟属性体组成,属性头的结构定义如下:



  1. // 属性头





  2. typedef




    struct




  3. {


  4. /*+0x00*/


    ATTRIBUTE_TYPE AttributeType;


    // 属性类型





  5. /*+0x04*/


    uint16 RecordLength;


    // 总长度(Header+body长度)





  6. /**0x06*/


    uint16 unknow0;



  7. /*+0x08*/


    uchar Nonresident;


    // 非常驻标志





  8. /*+0x09*/


    uchar NameLength;


    // 操作属性名长度






  9. // 0X0001为压缩标记





  10. // 0X4000为加密标记





  11. // 0X8000为系数文件标志





  12. /*+0x0A*/


    uint16 NameOffset;


    // 属性名偏移(从属性起始位置的偏移)





  13. // NameLength 如果不为零,则用这个值去寻址数据偏移





  14. /*+0x0C*/


    uint16 Flags;


    // ATTRIBUTE_xxx flags.





  15. /*+0x0E*/


    uint16 AttributeNumber;


    // The file-record-unique attribute instance number for this attribute.




  16. } ATTRIBUTE, *PATTRIBUTE;



  17. // 属性头





  18. typedef




    struct


    _RESIDENT_ATTRIBUTE


  19. {


  20. /*+0x00*/


    ATTRIBUTE Attribute;


    // 属性





  21. /*+0x10*/


    uint32 ValueLength;


    // Data部分长度





  22. /*+0x14*/


    uint16 ValueOffset;


    // Data内容起始偏移





  23. /*+0x16*/


    uchar Flags;


    // 索引标志





  24. /*+0x17*/


    uchar Padding0;


    // 填充




  25. } RESIDENT_ATTRIBUTE, *PRESIDENT_ATTRIBUTE;

其中

ATTRIBUTE_TYPE


是一个枚举类型,

里面定义了可能出现的所有类型。查看这个结构主要是看AttributeType(上图中,染上绿色的为属性类型,跟在后面的的红色框框内数据为属性头+属性体的大小(这个值必须是大于0x10,小于512的,程序中必须判断),由这个值可以得到下一个属性的地址),这个类型是什么,然后再跟去类型定义的Data部分去解析下面的属性体。遍历属性的时候可以根据属性类型来判断是否已经到达结尾,如果属性类型为

0xFFFFFFFF

则表示已经到达末尾(注意遍历的时候还是要结合FILE头部指定的大小来遍历,这样程序健壮性好很多,还有如果属性头后面跟着的大小值小于0x10也要结束遍历,因为这时候这个MFT项已经不可靠了,再继续下去程序出错可能性比较大(0x00值可能出现死循环))。


属性类型定义,及各个类型属性的结构(缺少无关紧要的结构,其他结构可参考nt4里面的源码并对照winhex分析):



  1. // 属性类型定义





  2. typedef




    enum


    _ATTRIBUTE_TYPE


  3. {

  4. AttributeStandardInformation = 0x10,

  5. AttributeAttributeList = 0x20,

  6. AttributeFileName = 0x30,

  7. AttributeObjectId = 0x40,

  8. AttributeSecurityDescriptor = 0x50,

  9. AttributeVolumeName = 0x60,

  10. AttributeVolumeInformation = 0x70,

  11. AttributeData = 0x80,

  12. AttributeIndexRoot = 0x90,

  13. AttributeIndexAllocation = 0xA0,

  14. AttributeBitmap = 0xB0,

  15. AttributeReparsePoint = 0xC0,

  16. AttributeEAInformation = 0xD0,

  17. AttributeEA = 0xE0,

  18. AttributePropertySet = 0xF0,

  19. AttributeLoggedUtilityStream = 0x100

  20. } ATTRIBUTE_TYPE, *PATTRIBUTE_TYPE;



  21. // 基础信息ATTRIBUTE.AttributeType == 0x10





  22. typedef




    struct


    _STANDARD_INFORMATION


  23. {

  24. uint64 CreationTime;

    // 创建时间




  25. uint64 ChangeTime;

    // 修改时间




  26. uint64 LastWriteTime;

    // 最后写入时间




  27. uint64 LastAccessTime;

    // 最后访问时间




  28. uint32 FileAttribute;

    // 文件属性




  29. uint32 AlignmentOrReserved[3];

    //





  30. #if 0




  31. uint32 QuotaId;

  32. uint32 SecurityId;

  33. uint64 QuotaCharge;


  34. USN


    Usn;



  35. #endif




  36. } STANDARD_INFORMATION, *PSTANDARD_INFORMATION;




  37. // 属性列表ATTRIBUTE.AttributeType == 0x20





  38. typedef




    struct


    _ATTRIBUTE_LIST


  39. {

  40. ATTRIBUTE_TYPE AttributeType;

  41. uint16 Length;

  42. uchar NameLength;

  43. uchar NameOffset;

  44. uint64 StartVcn;

    // LowVcn




  45. uint64 FileReferenceNumber;

  46. uint16 AttributeNumber;

  47. uint16 AlignmentOrReserved[3];

  48. } ATTRIBUTE_LIST, *PATTRIBUTE_LIST;




  49. // 文件属性ATTRIBUTE.AttributeType == 0x30





  50. typedef




    struct




  51. {


  52. /*+0x00*/


    uint64 DirectoryFile:48;


    // 父目录记录号(前个字节)





  53. /*+0x06*/


    uint64 ReferenceNumber:16;


    // +序列号(与目录相关)





  54. /*+0x08*/


    uint64 CreationTime;


    // 文件创建时间





  55. /*+0x10*/


    uint64 ChangeTime;


    // 文件修改时间





  56. /*+0x18*/


    uint64 LastWriteTime;


    // MFT更新的时间





  57. /*+0x20*/


    uint64 LastAccessTime;


    // 最后一次访问时间





  58. /*+0x28*/


    uint64 AllocatedSize;


    // 文件分配大小





  59. /*+0x30*/


    uint64 DataSize;


    // 文件实际大小





  60. /*+0x38*/


    uint32 FileAttributes;


    // 标志,如目录\压缩\隐藏等





  61. /*+0x3C*/


    uint32 AlignmentOrReserved;


    // 用于EAS和重解析





  62. /*+0x40*/


    uchar NameLength;


    // 以字符计的文件名长度,没字节占用字节数由下一字节命名空间确定






  63. // 文件名命名空间, 0 POSIX大小写敏感,1 win32空间,2 DOS空间, 3 win32&DOS空间





  64. /*+0x41*/


    uchar NameType;



  65. /*+0x42*/


    wchar Name[1];


    // 以Unicode方式标识的文件名




  66. } FILENAME_ATTRIBUTE, *PFILENAME_ATTRIBUTE;



  67. // 数据流属性 ATTRIBUTE.AttributeType == 0x80





  68. typedef




    struct


    _NONRESIDENT_ATTRIBUTE


  69. {


  70. /*+0x00*/


    ATTRIBUTE Attribute;




  71. /*+0x10*/


    uint64 StartVcn;


    // LowVcn 起始VCN  起始簇号





  72. /*+0x18*/


    uint64 LastVcn;


    // HighVcn  结束VCN  结束簇号






  73. /*+0x20*/


    uint16 RunArrayOffset;


    // 数据运行的偏移





  74. /*+0x22*/


    uint16 CompressionUnit;


    // 压缩引擎





  75. /*+0x24*/


    uint32  Padding0;


    // 填充





  76. /*+0x28*/


    uint32  IndexedFlag;


    // 为属性值分配大小(按分配的簇的字节数计算)





  77. /*+0x30*/


    uint64 AllocatedSize;


    // 属性值实际大小





  78. /*+0x38*/


    uint64 DataSize;


    // 属性值压缩大小





  79. /*+0x40*/


    uint64 InitializedSize;


    // 实际数据大小





  80. /*+0x48*/


    uint64 CompressedSize;


    // 压缩后大小




  81. } NONRESIDENT_ATTRIBUTE, *PNONRESIDENT_ATTRIBUTE;


以下特别要说明就是数据恢复中要使用的一些结构


0x30 AttributeFileName属性

(如果文件名很长,那么有多个0x30属性,一个记录短文件名,一个记录长文件名),记录了很多文件信息,可能使用到的有文件创建时间、文件修改时间、最后写入时间、文件最后一次访问时间。这里面的几个值相当于用

GetFileTime 或者GetFileInformationByHandle

得到的几个FILETIME值,可以调用


FileTimeToSystemTime



转换时间。其中DataSize

为实际文件使用的大小,在0x80属性中寻找簇恢复数据的时候会用到这个值。最后就是wchar的文件名,此名在cmd中显示需用

WideCharToMultiByte

转换后用

printf

显示,如果用

wprintf

显示中文会出现乱码问题。数据恢复的时候如果需要目录结构可由此属性中的


DirectoryFile



值得到,此值为父目录的记录号(相对于$MFT

元所在扇区的偏移,即:$MFT + DirectoryFile*2)例如:




上图,父目录号为0x0000000002A4

,从DBR中得到$MFT起始簇为786432(上面图一簇为8扇区),则父目录的MFT表项扇区为: 786432*8+0x0000000002A4*2 = 6292808,再查看6292808扇区:



所以这个文件为 X:\windows\notepad.exe(

其中X表示为根目录,具体看前面CreateFile参数值是什么了).


0x80 AttributeData属性( 注意:如果是目录的话, 此结构属性是0xA0 )

如果有多个0x80属性,则应该认为这个文件里面存在数据流文件,数据流表示形式为”0x30记录文件名:流文件名”,并且在explorer浏览中查看不到这个文件,NTFS刚出来的时候,文件流属性进程被病毒作者使用,比如如果要将hack.exe数据加到 1.txt 数据流里面,那么可以如下方式:



  1. void


    CrateDataStream()


  2. {


  3. HANDLE


    hfile = CreateFile(  TEXT(


    “1.txt:DataStream.exe”


    ),


    //1.txt中数据流名字为DataStream.exe(随意取的)




  4. GENERIC_WRITE,

  5. 0,

  6. NULL,

  7. CREATE_ALWAYS,

  8. FILE_ATTRIBUTE_NORMAL,

  9. NULL);


  10. if


    (hfile == INVALID_HANDLE_VALUE)


  11. {


  12. return


    ;


    // 打开文件错误




  13. }


  14. HANDLE


    hExeFile = CreateFile(   TEXT(


    “hack.exe”


    ),


  15. GENERIC_READ,

  16. 0,

  17. NULL,

  18. OPEN_EXISTING,

  19. FILE_ATTRIBUTE_NORMAL,

  20. NULL);


  21. if


    (hExeFile == INVALID_HANDLE_VALUE)


  22. {

  23. CloseHandle(hfile);


  24. return


    ;


    // 打开文件错误




  25. }


  26. DWORD


    dwsize = GetFileSize(hExeFile, NULL);



  27. BYTE


    * buf =


    new




    BYTE


    [dwsize];



  28. DWORD


    wbytes;


  29. ReadFile(hExeFile, buf, dwsize, &wbytes, NULL);

  30. WriteFile(hfile, buf, wbytes, &wbytes, NULL);

  31. CloseHandle(hExeFile);

  32. CloseHandle(hfile);

  33. }

一般是病毒作者将这个 1.txt 添加到压缩文件(高级里面选上保存文件流数据), 然后搞成自解压包, 在解压后命令中写入1.txt: DataStream.exe, 在用户双击解压的时候就会运行里面的数据流程序。不过现在杀毒软件对这种数据流病毒基本都能杀了。

再说数据恢复的关键点:数据内容由

NONRESIDENT_ATTRIBUTE. RunArrayOffset


偏移指定DATA

数据地址。如果属性头 ATTRIBUTE.

Nonresident


标记为1

表示非常驻,则下面会解析怎么需要解析DATA部分, 如果为0则表示DATA就是文件内容, 比如一个txt文件里面记录的数据很少, 则此标记为0, 记事本里面数据就保存在DATA中。上图因为查看的是MFT自身,$MFT比较特殊,非常驻属性设置成0(即FALSE)但是却要像非常驻属性一样去分析。




上图蓝色的部分,


看不太清数据,原始数据如下:





最开始的数据为32,其中高4bits表示数据起始簇地址占用字节数,后4bits为数据大小(簇个数)占用字节数..

这里要特别注意,第一个起始簇信息是无符号的,后面第二个开始就是相对于前面一个簇的偏移,是有正负的,查了很多资料,这点基本上都没提及,这也是数据恢复最容易出错的地方,辛辛苦苦写好了程序,一测试发现恢复出来的数据有问题。


上面第一个扇区地址为52604144(0x64559E*8,相对去当前分区的扇区偏移),第二个扇区地址为(0x64559E – 0x 77)*8  =  6575399 扇区(这里值0x89为-119)。

恢复数据的时候可以根据簇大小读取文件,然后保存,再根据前面的

NONRESIDENT_ATTRIBUTE. DataSize


值去

SetFilePointer


设置文件大小继而调用

SetEndOfFile

定义一个结构体表示这个结构:



  1. typedef




    struct


    _VCN_FLASH


  2. {

  3. uchar VcnLen:4;

    // 簇流长度 *8*512 才是得到的文件字节数




  4. uchar StartVcnLen:4;

    // 簇流起始位置–簇号





  5. uchar Data[1];

    // 簇流长度&Data + 簇流起始位置&Data+VcnLen 数据部分




  6. }VCN_FLASH, *PVCN_FLASH;


再定义2个函数计算有符号与无符号数:



  1. uint64 make_uint64(uchar* buf,


    int


    lenth)


  2. {

  3. int64 ui=0;


  4. if


    (lenth > 8)


  5. {


  6. return


    (int64)0;


  7. }



  8. for


    (


    int


    i=0; i<lenth; i++)


  9. {

  10. ui = (buf[i]<<8*i)|ui;

  11. }


  12. return


    ui;


  13. }



  14. int64 make_int64(uchar* buf,

    int


    lenth)


  15. {

  16. int64 ui=0;


  17. if


    (lenth > 8)


  18. {


  19. return


    (int64)0;


  20. }



  21. for


    (


    int


    i=0; i<lenth; i++)


  22. {

  23. ui = (buf[i]<<8*i)|ui;

  24. }



  25. // 判断符号位,为负则需减取反





  26. if


    (buf[lenth-1] >= 0x80)


  27. {

  28. int64 xorval = 0;


  29. for


    (i=0; i<lenth; i++)


  30. {

  31. xorval = xorval|(0xFF<<8*i);

  32. }

  33. ui = -((ui – 1)^xorval);

  34. }


  35. return


    ui;


  36. }


0x90  AttributeIndexRoot  属性 ( 目录索引B+树结构 )

这个属性,我也不是很清楚,等弄清楚了,再接着完善……………..