首页
社区
课程
招聘
[原创]解密教学第6章序列号方式之习题九分析
发表于: 2008-10-27 21:15 3503

[原创]解密教学第6章序列号方式之习题九分析

2008-10-27 21:15
3503
学完《加密解密三版》的第5章(常见的演示版保护技术),就把看雪论坛上的解密教学第6章第1小节中的习题做了一遍。发现自己对delphi或MFC的程序运行机制还是不太了解,部分还是借助OD动态分析才能确认,这让我很头疼。今天我把习题九的分析写出来,希望能给一些像我一样的小菜带来些帮助。同时也求助大侠们,帮我解解惑,在此万分感谢。

步骤一、运行程序查看提示信息
运行CRKME4.EXE,输入用户名yzlyzl,序列号123456,点击[check]按钮,跳出对话框提示“Bad Name or Serial Number ”。

步骤二、运行PEiD.exe查看该程序的实现语言
运行PEiD.exe,将CRKME4.EXE拉进来,可以看到提示“Borland Delphi 3.0”

步骤三、查找[check]按钮的点击事件的代码位置
运行资源文件ResHacker.exe,将CRKME4.EXE拉进来,定位[RCData]->[TFORM1]。查找[check]按钮,得到下面数据:
object Button1: TButton
    Left = -1
    Top = 98
    Width = 66
    Height = 23
    Caption = 'Check'
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clAqua
    Font.Height = -11
    Font.Name = 'MS Sans Serif'
    Font.Style = []
    ParentFont = False
    TabOrder = 0
    OnClick = Button1Click    //这里是按钮事件
end

打开二进制文本工具(这里我用的是UltraEdit91),将CRKME4.EXE拉进来,点击[查找]按钮,输入Button1Click,勾上[查找ASCII]。这样我们可以找到如下代码:
0002cc60h:73 65 31 43 6c 69 63 6b 13 00 d4 da 42 00 0c 42;selClick..在B..B
0002cc70h:75 74 74 6F 6e 31 43 6C 69 63 6B               ;utton1Click...

红色字体的上一个字节0C代表该字符长度,再上去4个字节代表该按钮事件的地址,即:0042dad4

(PS: 步骤三是看一些大侠的分析学上的,但是我不清楚为什么是这样。)
疑惑1:就是为什么说再上去四个字节就代表按钮事件的地址?如果大家都知道这个地方,那么这个地方不会被修改吗?如果被修改,那又怎么知道他的真实地址在哪里?

步骤四、用IDA加载CRKME4.EXE,定位0042dad4按钮事件
打开IDA,将CRKME4.EXE拖进来。因为这是Delphi3.0的程序,所以设置IDA的FLIRT(File->Load file->FLIRT signature file)为d3vcl。

在IDA上按键盘G,输入0042dad4,定位[Check]按钮事件

步骤五、分析[check]按钮事件
代码如下:
CODE:0042DAD4 CheckClick      proc near               ; DATA XREF: CODE:0042D86Ao
CODE:0042DAD4
CODE:0042DAD4 var_8           = dword ptr -8
CODE:0042DAD4 var_4           = dword ptr -4
CODE:0042DAD4
CODE:0042DAD4                 push    ebp
CODE:0042DAD5                 mov     ebp, esp
CODE:0042DAD7                 push    0
CODE:0042DAD9                 push    0
CODE:0042DADB                 push    ebx
CODE:0042DADC                 push    esi
CODE:0042DADD                 push    edi
CODE:0042DADE                 mov     ebx, eax
CODE:0042DAE0                 mov     esi, offset unk_42F75C
CODE:0042DAE5                 mov     edi, offset unk_42F764
CODE:0042DAEA                 xor     eax, eax
CODE:0042DAEC                 push    ebp
CODE:0042DAED                 push    offset loc_42DD0E
CODE:0042DAF2                 push    dword ptr fs:[eax]
CODE:0042DAF5                 mov     fs:[eax], esp
CODE:0042DAF8                 mov     eax, 4
CODE:0042DAFD                 call    @@GetMem        ; __linkproc__ GetMem
CODE:0042DB02                 mov     ds:lpVolumeSerialNumber, eax
CODE:0042DB07                 push    0               ; nFileSystemNameSize
CODE:0042DB09                 push    0               ; lpFileSystemNameBuffer
CODE:0042DB0B                 push    offset FileSystemFlags ; lpFileSystemFlags
CODE:0042DB10                 push    offset MaximumComponentLength ; lpMaximumComponentLength
CODE:0042DB15                 mov     eax, ds:lpVolumeSerialNumber
CODE:0042DB1A                 push    eax             ; lpVolumeSerialNumber
CODE:0042DB1B                 push    0               ; nVolumeNameSize
CODE:0042DB1D                 push    0               ; lpVolumeNameBuffer
CODE:0042DB1F                 push    0               ; lpRootPathName
CODE:0042DB21                 call    GetVolumeInformationA
CODE:0042DB26                 mov     eax, ds:lpVolumeSerialNumber
CODE:0042DB2B                 mov     eax, [eax]
CODE:0042DB2D                 mov     ds:dword_42F750, eax
CODE:0042DB32                 lea     edx, [ebp+var_4]
CODE:0042DB35                 mov     eax, [ebx+1E0h] ; [ebx+1E0h]=Name控件
CODE:0042DB3B                 call    @TControl@GetText ; TControl::GetText
CODE:0042DB40                 cmp     [ebp+var_4], 0  ; [ebp+var_4]=Name的值
CODE:0042DB44                 jnz     short loc_42DB60 ; 未输入用户名则继续执行并提示出错!
CODE:0042DB46                 push    0
CODE:0042DB48                 mov     cx, word_42DD1C
CODE:0042DB4F                 mov     dl, 2
CODE:0042DB51                 mov     eax, offset aPleaseTypInYou ; "Please typ in your name !!"
CODE:0042DB56                 call    @MessageDlg
CODE:0042DB5B                 jmp     loc_42DCF0
CODE:0042DB60 ; ---------------------------------------------------------------------------
CODE:0042DB60
CODE:0042DB60 loc_42DB60:                             ; CODE XREF: CheckClick+70j
CODE:0042DB60                 lea     edx, [ebp+var_4]
CODE:0042DB63                 mov     eax, [ebx+1E0h] ; [ebx+1E0h]=Name控件
CODE:0042DB69                 call    @TControl@GetText ; TControl::GetText
CODE:0042DB6E                 mov     eax, [ebp+var_4]
CODE:0042DB71                 call    @@LStrLen       ; __linkproc__ LStrLen
CODE:0042DB76                 cmp     eax, 6
CODE:0042DB79                 jge     short loc_42DB95 ; 判断用户名长度是否小于6,小于则出错
CODE:0042DB7B                 push    0
CODE:0042DB7D                 mov     cx, word_42DD1C
CODE:0042DB84                 mov     dl, 2
CODE:0042DB86                 mov     eax, offset aTypeAtLeast6Ch ; "Type at least 6 chars for your name! !"
CODE:0042DB8B                 call    @MessageDlg
CODE:0042DB90                 jmp     loc_42DCF0
CODE:0042DB95 ; ---------------------------------------------------------------------------
CODE:0042DB95
CODE:0042DB95 loc_42DB95:                             ; CODE XREF: CheckClick+A5j
CODE:0042DB95                 lea     edx, [ebp+var_4]
CODE:0042DB98                 mov     eax, [ebx+1E4h] ; [ebx+1E4h]=Serial控件
CODE:0042DB9E                 call    @TControl@GetText ; TControl::GetText
CODE:0042DBA3                 cmp     [ebp+var_4], 0
CODE:0042DBA7                 jnz     short loc_42DBC3 ; 未输入序列号则继续执行并提示出错
CODE:0042DBA9                 push    0
CODE:0042DBAB                 mov     cx, word_42DD1C
CODE:0042DBB2                 mov     dl, 2
CODE:0042DBB4                 mov     eax, offset aPleaseEnterYou ; "Please enter your serial !"
CODE:0042DBB9                 call    @MessageDlg
CODE:0042DBBE                 jmp     loc_42DCF0
CODE:0042DBC3 ; ---------------------------------------------------------------------------
CODE:0042DBC3
CODE:0042DBC3 loc_42DBC3:                             ; CODE XREF: CheckClick+D3j
CODE:0042DBC3                 mov     eax, edi
CODE:0042DBC5                 call    @@LStrClr       ; __linkproc__ LStrClr
CODE:0042DBCA                 mov     dword ptr [esi], 2
CODE:0042DBD0
CODE:0042DBD0 loc_42DBD0:                             ; CODE XREF: CheckClick+12Bj
CODE:0042DBD0                 lea     edx, [ebp+var_4]
CODE:0042DBD3                 mov     eax, [ebx+1E0h] ; [ebx+1E0h]=Name控件
CODE:0042DBD9                 call    @TControl@GetText ; TControl::GetText
CODE:0042DBDE                 mov     eax, [ebp+var_4]
CODE:0042DBE1                 mov     edx, [esi]
CODE:0042DBE3                 movzx   eax, byte ptr [eax+edx-1] ; eax = Name[i+1]
CODE:0042DBE8                 lea     edx, [ebp+var_8]
CODE:0042DBEB                 call    @IntToStr
CODE:0042DBF0                 mov     edx, [ebp+var_8]
CODE:0042DBF3                 mov     eax, edi        ; 将各个字符转换为数字字符串连接到[edi]
CODE:0042DBF5                 call    @@LStrCat       ; __linkproc__ LStrCat
CODE:0042DBFA                 inc     dword ptr [esi] ; [esi]:2 ~ 6
CODE:0042DBFC                 cmp     dword ptr [esi], 7
CODE:0042DBFF                 jnz     short loc_42DBD0
CODE:0042DC01                 lea     eax, [ebp+var_8]
CODE:0042DC04                 push    eax
CODE:0042DC05                 mov     ecx, 3
CODE:0042DC0A                 mov     edx, 1
CODE:0042DC0F                 mov     eax, [edi]
CODE:0042DC11                 call    @@LStrCopy      ; 获取转换后的前三个字符,保存在[ebp+var_8]
CODE:0042DC16                 mov     eax, [ebp+var_8]
CODE:0042DC19                 call    @StrToInt
CODE:0042DC1E                 mov     ds:dword_42F758, eax ; 保存算子
CODE:0042DC23                 mov     eax, edi
CODE:0042DC25                 call    @@LStrClr       ; 清除字符串
CODE:0042DC2A                 mov     eax, ebx
CODE:0042DC2C                 call    sub_42D8E4      ; *dword_42F758 = (((*dword_42F758 * 6)/3 + 0x10)*2)*9 ^ 5
CODE:0042DC2C                                         ; *dword_42F750 = (((*dword_42F750 << 2)/3)^3) + 0x40
CODE:0042DC31                 mov     eax, ds:dword_42F750
CODE:0042DC36                 mov     ds:dword_42F750, eax
CODE:0042DC3B                 mov     eax, ebx
CODE:0042DC3D                 call    sub_42D934      ; *dword_42F758 = ((*dword_42F758 * 6 / 2) + 0x0D)*0x36;
CODE:0042DC3D                                         ; *dword_42F758 = (*dword_42F758 << 5) + *dword_42F758;
CODE:0042DC3D                                         ; *dword_42F758 = *dword_42F758 ^ 0x10;
CODE:0042DC3D                                         ;
CODE:0042DC3D                                         ; *dword_42F750 = (((*dword_42F750 * 6)/5)^0x25) + 0x27;
CODE:0042DC42                 mov     eax, ds:dword_42F758
CODE:0042DC47                 mov     ds:dword_42F758, eax
CODE:0042DC4C                 mov     eax, ebx
CODE:0042DC4E                 call    sub_42D988      ; *dword_42F758 = ((*dword_42F758 * 6)/3 + 0x0d)*6;
CODE:0042DC4E                                         ; *dword_42F758 = (*dword_42F758 * 0x59)^0x9;
CODE:0042DC4E                                         ;
CODE:0042DC4E                                         ; *dword_42F750 = ((*dword_42F750 * 5)^0x22)+3;
CODE:0042DC53                 mov     eax, ebx
CODE:0042DC55                 call    sub_42D9D8      ; int temp = *dword_42F758 % 2;
CODE:0042DC55                                         ;
CODE:0042DC55                                         ; *dword_42F758 = *dword_42F758 / 2;
CODE:0042DC55                                         ; if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + temp;
CODE:0042DC55                                         ; *dword_42F758 = ((*dword_42F758 + 0x10)*3)^6;
CODE:0042DC55                                         ;
CODE:0042DC55                                         ; *dword_42F750 = (((*dword_42F750 * 0x2B)/3)^3) + 0x22;
CODE:0042DC5A                 mov     eax, ds:dword_42F758
CODE:0042DC5F                 mov     ds:dword_42F758, eax
CODE:0042DC64                 mov     eax, ebx
CODE:0042DC66                 call    sub_42DA1C
CODE:0042DC6B                 mov     eax, ebx
CODE:0042DC6D                 call    sub_42DA28
CODE:0042DC72                 mov     eax, ds:dword_42F758
CODE:0042DC77                 mov     ds:dword_42F758, eax
CODE:0042DC7C                 mov     eax, ebx
CODE:0042DC7E                 call    sub_42DA34      ; int cf = *dword_42F758 & 0x1;
CODE:0042DC7E                                         ;
CODE:0042DC7E                                         ; *dword_42F758 = *dword_42F758 / 2;
CODE:0042DC7E                                         ; if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + cf;
CODE:0042DC7E                                         ; *dword_42F758 = (((*dword_42F758 + 1)*6)<<3)^6;
CODE:0042DC7E                                         ;
CODE:0042DC7E                                         ; *dword_42F750 = *dword_42F750 * 3;
CODE:0042DC7E                                         ; if(*dword_42F750 < 0) *dword_42F750 = *dword_42F750 + 3;
CODE:0042DC7E                                         ; *dword_42F750 = ((*dword_42F750 / 4)^0x22) + 4;
CODE:0042DC83                 mov     eax, ebx
CODE:0042DC85                 call    sub_42DA7C      ; [dword_42F750] = [dword_42F750] * 3
CODE:0042DC8A                 mov     eax, ebx
CODE:0042DC8C                 call    sub_42DA9C      ; *dword_42F758 = (*dword_42F758 ^ 2)*6;
CODE:0042DC8C                                         ; *dword_42F750 = (*dword_42F750 << 2)+4;
CODE:0042DC91                 mov     eax, ds:dword_42F750
CODE:0042DC96                 add     ds:dword_42F758, eax ; [dword_42F758] = [dword_42F758] + [dword_42F750]
CODE:0042DC9C                 lea     edx, [ebp+var_4]
CODE:0042DC9F                 mov     eax, [ebx+1E4h] ; 序列号
CODE:0042DCA5                 call    @TControl@GetText ; TControl::GetText
CODE:0042DCAA                 mov     eax, [ebp+var_4]
CODE:0042DCAD                 call    @StrToInt       ; 将输入的序列号转化为对应的数值
CODE:0042DCB2                 mov     ds:dword_42F760, eax
CODE:0042DCB7                 mov     eax, ds:dword_42F758
CODE:0042DCBC                 cmp     eax, ds:dword_42F760
CODE:0042DCC2                 jnz     short loc_42DCDB
CODE:0042DCC4                 push    0
CODE:0042DCC6                 mov     cx, word_42DD1C
CODE:0042DCCD                 mov     dl, 2
CODE:0042DCCF                 mov     eax, offset aGoodSerialThan ; "Good Serial, Thanks For trying this Cra"...
CODE:0042DCD4                 call    @MessageDlg
CODE:0042DCD9                 jmp     short loc_42DCF0
CODE:0042DCDB ; ---------------------------------------------------------------------------
CODE:0042DCDB
CODE:0042DCDB loc_42DCDB:                             ; CODE XREF: CheckClick+1EEj
CODE:0042DCDB                 push    0
CODE:0042DCDD                 mov     cx, word_42DD1C
CODE:0042DCE4                 mov     dl, 2
CODE:0042DCE6                 mov     eax, offset aBadNameOrSeria ; "Bad Name Or Serial Number !!!!!"
CODE:0042DCEB                 call    @MessageDlg
CODE:0042DCF0
CODE:0042DCF0 loc_42DCF0:                             ; CODE XREF: CheckClick+87j
CODE:0042DCF0                                         ; CheckClick+BCj ...
CODE:0042DCF0                 xor     eax, eax
CODE:0042DCF2                 pop     edx
CODE:0042DCF3                 pop     ecx
CODE:0042DCF4                 pop     ecx
CODE:0042DCF5                 mov     fs:[eax], edx
CODE:0042DCF8                 push    offset loc_42DD15
CODE:0042DCFD
CODE:0042DCFD loc_42DCFD:                             ; CODE XREF: CheckClick+23Fj
CODE:0042DCFD                 lea     eax, [ebp+var_8]
CODE:0042DD00                 call    @@LStrClr       ; __linkproc__ LStrClr
CODE:0042DD05                 lea     eax, [ebp+var_4]
CODE:0042DD08                 call    @@LStrClr       ; __linkproc__ LStrClr
CODE:0042DD0D                 retn
CODE:0042DD0E ; ---------------------------------------------------------------------------
CODE:0042DD0E
CODE:0042DD0E loc_42DD0E:                             ; DATA XREF: CheckClick+19o
CODE:0042DD0E                 jmp     @@HandleFinally ; __linkproc__ HandleFinally
CODE:0042DD13 ; ---------------------------------------------------------------------------
CODE:0042DD13                 jmp     short loc_42DCFD
CODE:0042DD15 ; ---------------------------------------------------------------------------
CODE:0042DD15
CODE:0042DD15 loc_42DD15:                             ; CODE XREF: CheckClick+239j
CODE:0042DD15                                         ; DATA XREF: CheckClick+224o
CODE:0042DD15                 pop     edi
CODE:0042DD16                 pop     esi
CODE:0042DD17                 pop     ebx
CODE:0042DD18                 pop     ecx
CODE:0042DD19                 pop     ecx
CODE:0042DD1A                 pop     ebp
CODE:0042DD1B                 retn
CODE:0042DD1B CheckClick      endp

疑惑2、
CODE:0042DB35                 mov     eax, [ebx+1E0h] ; [ebx+1E0h]=Name的文本控件
对于这段代码,我怎么知道它是代表哪个控件的呢?(这个我是用OD动态分析才知道的)


步骤六、编写注册机
代码如下:
#include <stdio.h>
#include <windows.h>

// by Yzl 2008-10-27

void sub_42D8E4(int *dword_42F758,int *dword_42F750)
{
        *dword_42F758 = (((*dword_42F758 * 6)/3 + 0x10)*2)*9;
        *dword_42F758 = *dword_42F758 ^ 5;
        *dword_42F750 = (((*dword_42F750 << 2)/3)^3) + 0x40;
}

void sub_42D934(int *dword_42F758,int *dword_42F750)
{
        int temp = (*dword_42F758 * 6) & 0x1;
       
        *dword_42F758 = (*dword_42F758 * 6) / 2;
        if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + temp;
        *dword_42F758 = (*dword_42F758 + 0x0D)*0x36;
        *dword_42F758 = (*dword_42F758 << 5) + *dword_42F758;
        *dword_42F758 = *dword_42F758 ^ 0x10;
       
        *dword_42F750 = (((*dword_42F750 * 6)/5)^0x25) + 0x27;
}

void sub_42D988(int *dword_42F758,int *dword_42F750)
{
        *dword_42F758 = ((*dword_42F758 * 6)/3 + 0x0d)*6;
        *dword_42F758 = (*dword_42F758 * 0x59)^0x9;
       
        *dword_42F750 = ((*dword_42F750 * 5)^0x22)+3;
}

void sub_42D9D8(int *dword_42F758,int *dword_42F750)
{
        int temp = *dword_42F758 & 0x1;
       
        *dword_42F758 = *dword_42F758 / 2;       
        if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + temp;
        *dword_42F758 = ((*dword_42F758 + 0x10)*3)^6;
       
        *dword_42F750 = (((*dword_42F750 * 0x2B)/3)^3) + 0x22;       
}

void sub_42DA34(int *dword_42F758,int *dword_42F750)
{
        int cf = *dword_42F758 & 0x1;
       
        *dword_42F758 = *dword_42F758 / 2;
        if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + cf;
        *dword_42F758 = (((*dword_42F758 + 1)*6)<<3)^6;
       
        *dword_42F750 = *dword_42F750 * 3;
        if(*dword_42F750 < 0) *dword_42F750 = *dword_42F750 + 3;
        *dword_42F750 = ((*dword_42F750 / 4)^0x22) + 4;       
}

void sub_42DA7C(int *dword_42F758,int *dword_42F750)
{
        *dword_42F750 = *dword_42F750 * 3;
       
        printf("dword_42F758=0x%X\n",*dword_42F758);
        printf("dword_42F750=0x%X\n",*dword_42F750);
}

void sub_42DA9C(int *dword_42F758,int *dword_42F750)
{
        *dword_42F758 = (*dword_42F758 ^ 2)*6;
        *dword_42F750 = (*dword_42F750 << 2)+4;
               
        printf("dword_42F758=0x%X\n",*dword_42F758);
        printf("dword_42F750=0x%X\n",*dword_42F750);
}

void KeyGen(char *name, int len /*= 7*/)
{
        DWORD fileSystemFlags,maximumComponentLength,volumeSerialNumber;
        int i = 2,dword_42F758,dword_42F750;
        char buf1[128] = {0};
        char buf2[128] = {0};
       
        GetVolumeInformation(0,0,0,&volumeSerialNumber,
                                &maximumComponentLength,&fileSystemFlags,0,0);
                               
        dword_42F750 = volumeSerialNumber;
       
        for(; i < 7; i ++)
        {
                sprintf(buf1,"%d",name[i - 1]);
                strcat(buf2,buf1);
        }       
        sscanf(buf2,"%3d",&dword_42F758);
       
        sub_42D8E4(&dword_42F758,&dword_42F750);
        sub_42D934(&dword_42F758,&dword_42F750);
        sub_42D988(&dword_42F758,&dword_42F750);
        sub_42D9D8(&dword_42F758,&dword_42F750);
        sub_42DA34(&dword_42F758,&dword_42F750);
        sub_42DA7C(&dword_42F758,&dword_42F750);
        sub_42DA9C(&dword_42F758,&dword_42F750);
       
        printf("name=%s,serial=%d",name,dword_42F758 + dword_42F750);
}

int main(int argc,char **argv)
{
        if(argc != 2)
        {
                printf("Usage: KeyGen [username]");
                return 1;
        }
        if(strlen(argv[1]) <= 5)
        {
                printf("Username'Length must be greater than 5");
                return 1;       
        }
        KeyGen(argv[1],strlen(argv[1]));
       
        return 0;
}

编译:
cl KeyGen.c

运行
KeyGen yzlyzl

得到
name=yzlyzl,serial=-850023320

疑惑3、其中一段Delphi程序的实现不是特别理解,求助一下大家:
CODE:00403544 @@LStrClr       proc near               ; CODE XREF: __linkproc__ LStrFromPCharLen+23p
CODE:00403544                                         ; __linkproc__ LStrFromPWCharLen+16p ...
CODE:00403544                 mov     edx, [eax]
CODE:00403546                 test    edx, edx
CODE:00403548                 jz      short locret_403565
CODE:0040354A                 mov     dword ptr [eax], 0
CODE:00403550                 mov     ecx, [edx-8]            //为什么这么做,什么意思?
CODE:00403553                 dec     ecx
CODE:00403554                 jl      short locret_403565
CODE:00403556                 mov     [edx-8], ecx
CODE:00403559                 jnz     short locret_403565
CODE:0040355B                 push    eax
CODE:0040355C                 lea     eax, [edx-8]
CODE:0040355F                 call    @@FreeMem       ; __linkproc__ FreeMem
CODE:00403564                 pop     eax
CODE:00403565
CODE:00403565 locret_403565:                          ; CODE XREF: __linkproc__ LStrClr+4j
CODE:00403565                                         ; __linkproc__ LStrClr+10j ...
CODE:00403565                 retn
CODE:00403565 @@LStrClr       endp

最后:感觉自己对Delphi程序的分析过于依赖IDA的FLIRT来理解它内置的函数,即便如此,有时看到一些内置函数还是感觉云里雾里,不知道有没有好的资料可以针对Delphi进行更系统的研究?谢谢大家。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//