稀物宝资源网

XiWuBao.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
龙之谷技术 龙之谷 龙之谷
查看: 72|回复: 0

由浅入深PE基础学习-菜鸟手动查询导出表、相对虚拟地址(RVA)与文件偏移地址转换(FOA)

[复制链接]

签到天数: 164 天

[LV.7]常住居民III

824

主题

850

帖子

862万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
8628814

最佳新人活跃会员热心会员推广达人宣传达人灌水之王突出贡献优秀版主荣誉管理论坛元老

发表于 2020-4-9 06:04:50 | 显示全部楼层 |阅读模式
0 前言
此篇文章想写如何通过工具手查导出表、PE文件代码编程过程中的原理。文笔不是很好,内容也是查阅了很多的资料后整合出来的。希望借此加深对PE文件格式的理解。因为了解PE文件格式知识点对于逆向破解还是病毒分析都是很重要的,且基于对PE文件格式的深入理解还可以延伸出更多非常有意思的攻防思维。
1 导出表查询工具
  • 1 ) dumpbin
VS自带的工具,有很多的功能。但用来查询程序的导出表也非常方便,使用例子如下:
dumpbin.exe /EXPORTS DEDemo.dll
  • 2 ) DLL Export Viewer (DLL导出表查看工具)
一款免费的dll查看工具,可以帮助查看DLL链接库文件中的输出函数,COM类型库及相应的偏移地址。
  • 3)010 Editor
十六进制编辑器010 Editor,有大量格式的解析模板,用EXE模板来解析二进制文件,辅助我们读懂和编辑。
  • 4)LordPE
LordPE是查看PE格式文件信息的工具,并且可以修改相关信息。里面有个位置计算器的功能可以用于计算相对虚拟地址(RVA)转换文件偏移地址(FOA)。
2 Windows导出表相关的结构2.1 导出表所处位置
在Visual Studio里有一个名为WINNT.H的头文件,里面定义了Windows系统里的PE内部结构。

PE结构中有一个NT头(IMAGE_NT_HEADERS NtHeader),NT头里包含了扩展头(IMAGE_OPTIONAL_HEADER),扩展头中包含数据目录表(IMAGE_DATA_DIRECTORY_ARRAY)。

扩展头定义:
2
4
6
8
10
12
14
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//

...省略....

//
// NT additional fields.
//

....省略...

     IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];  //数据目录表
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

IMAGE_NUMBEROF_DIRECTORY_ENTRIES是个宏定义,值是0x16。

宏定义:
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16

数据目录是一个有16个(WINNT.H中定义为IMAGE_NUMBEROF_DIRECTORY_ENTRIES)元素的结构数组。每个数组元素所指定的内容已经被预先定义好了。

WINNT.H文件中的这些IMAGE_DIRECTORY_ENTRY_xxx定义就是数据目录的索引(从0到15)。导出表相对虚拟地址(RVA)就在数据目录表中的第0个数组里。

数据目录表有两个结构体成员分别存有数据的相对虚拟地址和数据的大小,定义如下,:
2
4
6
typedef struct _IMAGE_DATA_DIRECTORY {

    DWORD   VirtualAddress; // 数据的相对虚拟地址(RVA)

    DWORD   Size;   // 数据的大小

} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

下表描述了每个IMAGE_DIRECTORY_ENTRY_xxx值每个数组的意义。


图1 IMAGE_OPTIONAL_HEADER中数据目录表结构体数组含义
2.2 导出表结构
下面是导出表的数据结构定义说明:
2
4
6
8
10
12
14
16
18
20
22
24
typedef struct _IMAGE_EXPORT_DIRECTORY {

   DWORD Characteristics;    // 1)  保留,恒为0x00000000

   DWORD TimeDateStamp;      // 2)  时间戳,导出表创建的时间(GMT时间)

   WORD  MajorVersion;       // 3)  主版本号:导出表的主版本号

   WORD  MinorVersion;       // 4)  子版本号:导出表的子版本号

   DWORD Name;               // 5)  指向模块名称的RVA,指向模块名(导出表所在模块的名称)的ASCII字符的RVA

   DWORD Base;               // 6)  导出表用于输出导出函数序号值的基数: 导出函数序号 = 函数入口地址数组下标索引值 + 基数

   DWORD NumberOfFunctions;  // 7)  导出函数入口地址表的成员个数

   DWORD NumberOfNames;      // 8)  导出函数名称表中的成员个数

   DWORD AddressOfFunctions; // 9)  函数入口地址表的相对虚拟地址(RVA),每一个非0的项都对应一个被导出的函数名称或导出序号(序号+基数等于导出函数序号)

   DWORD AddressOfNames;     // 10) 函数名称表的相对虚拟地址(RVA),存储着指向导出函数名称的ASCII字符的RVA

   DWORD AddressOfNameOrdinals; // 11) 存储着函数入口地址表的数组下标索引值(序号表),跟导出函数名称表的成员顺序对应

} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;

  • (没用)Characteristics; 保留,恒为0x00000000
  • (没用)TimeDateStamp; 时间戳,导出表创建的时间(GMT时间)
  • (没用)MajorVersion; 主版本号:导出表的主版本号
  • (没用)MinorVersion; 子版本号:导出表的子版本号
  • (有用)Name; 指向模块名称的RVA,指向模块名(导出表所在模块的名称)的ASCII字符的RVA
  • (有用)Base; 导出表用于输出导出函数序号值的基数:函数入口地址数组下标索引值 = 导出函数序号-基数
  • (有用)NumberOfFunctions; 导出函数入口地址表的成员个数
  • (有用)NumberOfNames; 以函数名称导出的成员个数
  • (有用)AddressOfFunctions; 函数入口地址表的相对虚拟地址(RVA),每一个非0的项都对应一个被导出的函数名称或导出序号(序号+基数等于导出函数序号)
  • (有用)AddressOfNames; 函数名称表的相对虚拟地址(RVA),存储着指向导出函数名称的ASCII字符的RVA
  • (有用)AddressOfNameOrdinals; 存储着函数入口地址表的数组下标索引值(序号表),跟导出函数名称表的成员顺序对应
3 手动操作
本文旨在用于科普,大牛们可能要见笑了。手动操作部分借助工具010 Editor、LordPE先搞清楚PE结构的内容。涉及到相对虚拟地址(RVA)转换文件偏移地址(FOA)的地方都用LordPE自带功能转换。原理与代码后续贴出
3.1 010 Editor + LordPE 查找导出表位置
010 Edito通过EXE模板解析PE结构方法如下:
菜单 --> Templates --> Edit Template List


图2 模板使用

在线模板文件地址:

保存-模板-打开模板-F5运行,010 Editor会出来一个小窗口。


图3 010Editor多出来的小窗口

010 Editor EXE模板查看的顺序如下:
2
4
6
1)struct IMAGE_NT_HEADERS nt_headers[NT头]

2)struct IMAGE_OPTIONAL_HEADER32 OptionalHeader[可选头]

3)struct IMAGE_DATA_DIRECTORIES DataDirectory[目录表]

4)struct IMAGE_DATA_DIRECTORY Export[导出表]

下图中内容里对应的是导出表结构体中的VirtualAddress(导出表相对虚拟地址)和Size(导出表数据大小)两个数据结构体成员,010 Editor面板里蓝色高亮出来的数据就是导出表的相对虚拟地址和数据大小,对应IMAGE_DATA_DIRECTORY export结构体。


图4 利用010 Editor的EXE模板查看导出表两个数据结构体成员VirtualAddress和Size

在内存中数据是以“小尾方式”存放,“小尾方式”存放是以字节为单位,按照数据类型长度,低数据位排放在内存的低端,高数据排放在内存的高端。如0x00007ED0在内存中会被存储为D07E0000。通过上面的操作,我们已经知道导出表

对应IMAGE_DATA_DIRECTORY.VirtualAddress的相对虚拟地址是0x00007ED0

对应IMAGE_DATA_DIRECTORY.Size的大小是0x000001A4

这里的0x00007ED0是相对虚拟地址(RVA),用LordPE工具转换文件偏移地址(FOA)方法如下:

使用LordPE【位置计算器】功能模块-【PE编辑器】-【位置计算器】,将0x00007ED0(RVA)转换文件偏移得到0x00006ED0


图5 使用LordPE计算出文件偏移得到0x00006ED0

0x00006ED0指向导出表数据结构(IMAGE_EXPORT_DIRECTORY)的位置,010Editor解析如图6所示,导出表数据结构具体的字段含义已经在《2.2 导出表结构》中注明。参照图标注如下:


图6 0x00006ED0指向位置为导出表数据,导出表结构体标注

其中比较有用的是
2
4
6
8
10
12
1) Name;  指向模块名称的RVA,指向模块名(导出表所在模块的名称)的ASCII字符的RVA

2) Base;  导出表用于输出导出函数序号值的基数:函数入口地址数组下标索引值 = 导出函数序号-基数

3) NumberOfFunctions; 导出函数入口地址表的成员个数

4) NumberOfNames; 以函数名称导出的函数个数

5) AddressOfFunctions;函数入口地址表的相对虚拟地址(RVA),每一个非0的项都对应一个被导出的函数名称或导出序号(序号+基数等于导出函数序号)

6) AddressOfNames;函数名称表的相对虚拟地址(RVA),存储着指向导出函数名称的ASCII字符的RVA

7) AddressOfNameOrdinals; 存储着函数入口地址表的数组下标索引值(序号表),跟导出函数名称表的成员顺序对应

导出表数据结构(IMAGE_EXPORT_DIRECTORY)的相对虚拟地址为:
2
4
6
8
10
12
IMAGE_EXPORT_DIRECTORY.Name  == 0x00007F20

IMAGE_EXPORT_DIRECTORY.Base  == 0x00000001

IMAGE_EXPORT_DIRECTORY.NumberOfFunctions == 0x00000004

IMAGE_EXPORT_DIRECTORY.NumberOfNames == 0x00000004

IMAGE_EXPORT_DIRECTORY.AddressOfFunctions== 0x00007EF8

IMAGE_EXPORT_DIRECTORY.AddressOfNames== 0x00007F08

IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals == 0x00007F18

通过以上数据可以知道导出表用于输出API函数索引值的基数为0x00000001。所有导出函数中的成员个数有4个,以导出名称导出的函数个数有4个。

接下来使用LordPE的【位置计算器】功能逐个计算出指向模块函数名称、函数地址表、函数名称地址表、导出序列号的相对虚拟地址(RVA)得出文件偏移(FOA):
IMAGE_EXPORT_DIRECTORY.Name == 0x00007F20 转换为 00006F20 //指向导出表文件名的字符串
IMAGE_EXPORT_DIRECTORY.AddressOfFunctions == 0x00007EF8 转换为 00006EF8 //导出函数入口地址表
IMAGE_EXPORT_DIRECTORY.AddressOfNames == 0x00007F08 转换为 00006F08 //导出函数名称地址表
IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals == 0x00007F18 转换为 00006F18 //导出函数名称表位置对应,存储着指向函数入口地址序号表的索引
3.1.1 IMAGE_EXPORT_DIRECTORY.Name
0x00007F20 转换为 00006F20,指向导出表Name字段,内容存储的是模块函数名称的ASCII字符,测试用的DLL名称如下:
PEDemo.dll


图7 指向导出文件名的字符串
3.1.2 IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
0x00007EF8 转换成文件偏移地址为 00006EF8,这个地址对应的结构体成员是AddressOfFunctions,AddressOfFunctions指向的是所有导出函数地址表的RVA地址,有多少个地址根据NumberOfFunctions的值得出。

再使用LordPE【位置计算器】功能通过RVA转换为FOA,查看所有导出函数地址表,得到以下的导出函数地址:
2
4
6
000010E6  --> 序号为[0]

00001087  --> 序号为[1]

0000108C  --> 序号为[2]

00009138  --> 序号为[3]


图8 IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
3.1.3 IMAGE_EXPORT_DIRECTORY.AddressOfNames
0x00007F08 转换成文件偏移地址为 00006F08,这个地址对应的结构体成员是AddressOfNames,这个成员表存储的是导出函数名字RVA。

因为前面根据NumberOfFunctions的值已经知道这个DLL里有4个导出函数,然后利用010Editor定位到文件偏移处00006F08的位置。里面存储的是4个导出函数名称对应的RVA地址。根据各个RVA转换成FOA。得到地址如下:

这里需要注意结构体里存储的是存放导出函数名称的RVA,要得到存储的导出函数名称的ASCII还要多转换一层RVA。


图9 存储着导出函数名称的RVA

RVA转换FOA如下:
2
4
6
0x00007F2B 转换FOA为 00006F2B

0x00007F37 转换FOA为 00006F37

0x00007F44 转换FOA为 00006F44

0x00007F51 转换FOA为 00006F51

使用010Editor查看00006F2B 、00006F37 、00006F44、00006F51可以看到其实每个函数的名称存放位置是连续的,使用00进行了隔断。

指向导出函数名称表RVA,AddressOfNames字段的值如下:
2
4
6
fnPEDemoFun  

fnPEDemoFunA

fnPEDemoFunB

nPEDemo


图10 指向导出表文件名的字符串

然后导出函数名称表存储的其实是指向真实函数字符串的RVA地址,转换前的对应关系如下图。


图11 导出函数名称地址表
3.1.4 IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
0x00007F18 转换成文件偏移地址为 00006F18,这个地址对应的结构体成员是IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals。


图12 序号表

这张表与导出函数名称地址表的顺序对应,存储着指向函数入口地址表的索引值(序号表,起始值从0开始)。编程的时候为DWORD类型,但却是WORD类型,因为只有2字节。对应的导出函数名称关系如下:
2
4
6
fnPEDemoFun   ---> 00 00

fnPEDemoFunA  ---> 01 00

fnPEDemoFunB  ---> 02 00

nPEDemo       ---> 03 00

AddressOfFunctions为函数入口地址,AddressOfNames为导出函数名,AddressOfNameOrdinals存储着函数入口地址表的数组下标索引值(序号表),用三张表的数据进行对比,结构就更清晰了,关系表如下:


图13 序号对应关系

根据导出函数序号 = 函数入口地址序号 + 基数,已知Base基数数为1,计算如下:
2
4
6
000010E6  序号[0] + 基数[1] = 导出序号为[1]

00001087  序号[1] + 基数[1] = 导出序号为[2]

0000108C  序号[2] + 基数[1] = 导出序号为[3]

00009138  序号[3] + 基数[1] = 导出序号为[4]

函数名称与函数入口地址表数组下标索引序号对应,计算如下:
2
4
6
fnPEDemoFun   ---> 00 00 --->对应函数入口地址[000010E6]

fnPEDemoFunA  ---> 01 00 --->对应函数入口地址[00001087]

fnPEDemoFunB  ---> 02 00 --->对应函数入口地址[0000108C]

nPEDemo       ---> 03 00 --->对应函数入口地址[00009138]

3.1.5 小结
AddressOfNames中保存着一组RVA,每个RVA指向一个字符串,即导出的函数名。与导出的函数名对应的是AddressOfNameOrdinals中对应的项。AddressOfNameOrdinals是一张设计得非常巧妙的一张表,让我们很方便的利用这张表按导出函数名称查找对应函数入口地址和按函数入口地址查找对应导出函数名称。
  • 按导出函数名称查找对应函数入口地址
1、获取已函数地址表的个数,NumberOfFunctions为4

2、获取以名称导出的函数个数,NumberOfNames为4

3、获取函数名称的地址

4、获取函数序号表的值

5、导出函数名与AddressOfNameOrdinals(函数序号表)的顺序对应

6、序号表存储的序号值是函数入口地址表的数组下标索引值

例子:我们已经知道3个函数名称Func1、Func2、Func3对应的序号值为0、2、3。那么函数地址表的第1、3、4的RVA(相对虚拟地址)就是有函数名称导出的函数入口地址,因为数组下标索引值由0起始计算。
  • 按函数入口地址查找对应导出函数名称
1、获取已函数地址表的个数,NumberOfFunctions为4

2、获取以名称导出的函数个数,NumberOfNames为4

3、获取函数名称的地址

4、获取函数序号表的值

5、导出函数名与AddressOfNameOrdinals(函数序号表)的顺序相互对应

6、遍历函数入口地址的数组索引值与AddressOfNameOrdinals(函数序号表)的实际内容值(非数组下标索引值)对比

7、如果函数入口地址的数组索引值与序号表内的存储内容相同,那么与函数序号表数组索引值顺序对应的函数名称就是函数入口地址对应的导出函数名称。

    • 得到导出序号

当函数是以序号方式导出的,查找的时候直接用函数入口地址序号加上基数(Base)就等于导出函数序号了。

逆向推回来,就是导出函数序号减去基数就得到函数入口地址(AddressOfFunctions)的顺序了,也就是数组下标索引值。

【导出函数序号】 = 【函数入口地址序号】+【基数】

【函数入口地址序号】 = 【导出函数序号】-【基数】

参考图:


图14 AddressOfFunctions、AddressOfNames、AddressOfNameOrdinals关系图
3.2 PE工具查看
印证自己查询的是不是正确,可以通过VS自带的dumpbin工具或是 DLL Export Viewer这类工具查看。
dumpbin.exe查看如下:
2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
Crogram Files (x86)Microsoft Visual Studio 14.0VCin>dumpbin.exe /EXPORTS dEDemo.dll
Microsoft (R) COFF/PE Dumper Version 14.00.24210.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file dEDemo.dll

File Type: DLL

  Section contains the following exports for PEDemo.dll

    00000000 characteristics
    59948A34 time date stamp Thu Aug 17 02:08:52 2017
        0.00 version
           1 ordinal base
           4 number of functions
           4 number of names

    ordinal hint RVA      name

          1    0 000010E6 fnPEDemoFun = @ILT+225(_fnPEDemoFun)
          2    1 00001087 fnPEDemoFunA = @ILT+130(_fnPEDemoFunA)
          3    2 0000108C fnPEDemoFunB = @ILT+135(_fnPEDemoFunB)
          4    3 00009138 nPEDemo = _nPEDemo

  Summary

        1000 .00cfg
        1000 .data
        1000 .gfids
        1000 .idata
        3000 .rdata
        1000 .reloc
        1000 .rsrc
        5000 .text

DLL Export Viewer (DLL导出表查看工具)

图15 DLL导出表查看工具结果
4 相对虚拟地址(RVA)转文件偏移(FOA)
前面的章节使用工具进行手动查看导出表,而这一节则是查阅了大量网上的文章然后汇总而成的笔记。希望可以给大家带来一些帮助!

术语:
  • RVA:RVA 是相对虚拟地址(Relative Virtual Address)的缩写,它是文件映射到内存中的“相对地址”。
  • FOA:FOA是文件偏移地址(File Offest Address)的缩写,它是文件在磁盘上存放时相对文件开头的偏移地址。

4.1 转换公式
LordPE的位置偏移功能的确很方便,但始终还是要熟悉原理,才能写出操作PE的代码。

有一条公式可以帮助我们很方便的计算出文件偏移的位置。
文件偏移(磁盘文件的位置 FOA)=相对虚拟地址(任意RVA)-该区段相对虚拟地址(RVA)+该区段的文件偏移(offset)

要转换的相对虚拟地址会落在一个区段中是因为每个偏移,不管是在文件中,还是在内存中,它们距离区段开始位置的距离总是相等的。

该区段相对虚拟地址(RVA) <--对应--> IMAGE_SECTION_HEADER.VirtualAddress

该区段的文件偏移(offset) <--对应--> IMAGE_SECTION_HEADER.PointerToRawData

在写代码前我们首先弄清楚基本概念。


图16 PE文件映射到虚拟内存

根据上图看出,区段装入内存之后的偏移与文件偏移是存在差异的。所以当我们进行文件偏移与虚拟内存地址之间换算时,首先要得出所转换的地址在第几区段内。每个区段的含义如下。

4.1.1 区段名称约定
  • .text代码段,此区段内的数据全部为代码
  • .data可读写的数据段,此区段内存放全局变量或静态变量
  • .rdata只读数据区段
  • .idara导入数据区段,此区段内存放导入表信息
  • .edata导出数据区段,次区段内存放导出表信息
  • .rsrc 资源区段,此区段内存放应用程序会用到的所有资源,如图标、菜单等
  • .bss未初始化数据
  • .crt此区段包含用于支持C++运行时库(CRT)所添加的数据
  • .tls此区段包含用于支持通过_declspec(thread)声明的线程局部存储变量的数据
  • .reloc此区段包含重定位信息
  • .sdata此区段包含相对于可被全局指针定位的可读写数据
  • .srdata此区段包含相对于可被全局指针定位的只读数据
  • .pdata此区段包含异常表
  • ....等

4.1.2 区段表结构

重新温习区段表(IMAGE_SECTION_HEADER)结构,如下所示:
2
4
6
8
10
12
14
16
18
20
22
24
26
28
typedef struct _IMAGE_SECTION_HEADER {

    BYTEName[IMAGE_SIZEOF_SHORT_NAME];  // 1)区段名

    union {

        DWORD   PhysicalAddress;

        DWORD   VirtualSize;

    } Misc;                            // 2)区段大小

    DWORD   VirtualAddress;            // 3)区段的RVA地址

    DWORD   SizeOfRawData;             // 4)文件中的区段对齐大小

    DWORD   PointerToRawData;          // 5)区段在文件中的偏移

    DWORD   PointerToRelocations;      // 6)重定位的偏移(用于OBJ文件)

    DWORD   PointerToLinenumbers;      // 7)行号表的偏移(用于调试)

    WORDNumberOfRelocations;           // 8)重定位表项数量(用于OBJ文件)

    WORDNumberOfLinenumbers;           // 9)行号表项数量

    DWORD   Characteristics;           // 10)区段的属性

} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

LordPE中的显示关系


图17 LordPE中的显示关系
2
4
6
Voffset   == IMAGE_SECTION_HEADER.VirtualAddress   //区段的RVA地址

VSize     == IMAGE_SECTION_HEADER.Misc             //区段的物理地址大小

Roffset   == IMAGE_SECTION_HEADER.PointerToRawData //区段在文件中的偏移

RSize     == IMAGE_SECTION_HEADER.SizeOfRawData    //文件中的区段对齐大小

代码例子

RVA是不变的,对比RVA在哪个区段内。找到RVA所在区段,然后计算出这个RVA到区段在内存中的开始位置的距离。

编程思路:
  • 步骤1:循环扫描区块表得出每个区块在内存中的起始 RVA(根据IMAGE_SECTION_HEADER 中的VirtualAddress 字段),并根据区块的大小(根据IMAGE_SECTION_HEADER 中的SizeOfRawData 字段)算出区块的结束 RVA(两者相加即可),最后判断目标 RVA 是否落在该区块内。
  • 步骤2:通过步骤1定位目标 RVA 处于具体的某个区块中后,那么用目标 RVA 减去该区块的起始 RVA ,这样就能得到目标 RVA 相对于起始地址的偏移量 RVA2.
  • 步骤3:在区块表中获取该区块在文件中所处的偏移地址(根据IMAGE_SECTION_HEADER 中的PointerToRawData 字段), 将这个偏移值加上步骤2得到的 RVA2 值,就得到了真正的文件偏移地址。

[table=98%,rgb(27, 36, 38)]
[tr][td]2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
36
38
40
42
44
46
48
50
52
54
56
[/td][td]
查询代码用了C++和Python两种语言实现,由于我习惯写很多注释,就不去分块进行代码讲解了,代码如下:

C++实现代码:
[table=98%,rgb(27, 36, 38)]
[tr][td]2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
36
38
40
42
44
46
48
50
52
54
56
58
60
62
64
66
68
70
72
74
76
78
80
82
84
86
88
90
92
94
96
98
100
102
104
106
108
110
112
114
116
118
120
122
124
126
128
130
132
134
136
138
140
142
144
146
148
150
152
154
156
158
160
162
164
166
168
170
172
174
176
178
180
182
184
186
188
190
192
194
196
198
200
202
204
206
208
210
212
214
216
218
220
222
224
226
228
229[/font%
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋| XiWuBao.com ( 琼ICP备19002752号-1 )

GMT+8, 2020-8-8 02:34 , Processed in 0.346464 second(s), 43 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc. 技术支持 by 稀物宝设计.

快速回复 返回顶部 返回列表