• [反汇编练习] 160个CrackMe之011


    [反汇编练习] 160个CrackMe之011.

    本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注册机的东西。

    其中,文章中按照如下逻辑编排(解决如下问题):

    1、使用什么环境和工具

    2、程序分析

    3、思路分析和破解流程

    4、注册机的探索

    ----------------------------------

    提醒各位看客: 如果文章中的逻辑看不明白,那你一定是没有亲手操刀!OD中的跳转提示很强大,只要你跟踪了,不用怎么看代码就理解了!

    ----------------------------------

    1、工具和环境:

    WinXP SP3 + 52Pojie六周年纪念版OD + PEID + 汇编金手指。

    160个CrackMe的打包文件。

    下载地址: http://pan.baidu.com/s/1xUWOY 密码: jbnq

    注:

    1、Win7系统对于模块和程序开启了随机初始地址的功能,会给分析带来很大的负担,所以不建议使用Win7进行分析。

    2、以上工具都是在52PoJie论坛下的原版程序,NOD32不报毒,个人承诺绝对不会进行任何和木马病毒相关内容。

    wps_clip_image-880

    2、程序分析:

    想要破解一个程序,必须先了解这个程序。所以,在破解过程中,对最初程序的分析很重要,他可以帮助我们理解作者的目的和意图,特别是对于注册码的处理细节,从而方便我们反向跟踪和推导。

    和上一节一样,打开CHM,选择第11个Andrénalin.4,保存下来。运行程序,程序界面如下:

    wps_clip_image-32384

    3、思路分析和破解流程:

    随意点击几个数字,发现没有提示。但是我们可以在右侧的Status: UNREGISTRIERT,我们可以大胆地猜测,如果序列号正常,这个文本应该会变为成功一类的提示。没有什么线索,直接放到OD里进行分析

    1、使用PEID查下壳,Microsoft Visual Basic 5.0 / 6.0,没有壳。

    2、打开OD,将exe拖到OD当中,F9运行。

    3、由于找不到任何线索,我们还是用“最笨的”查找字符串办法,点击E图标,选中Andrénalin.4.exe,右键->Follow Entry,这样我们就进入了主模块。

    4、在反汇编窗口任意位置,右键->中文搜索引擎->智能搜索,发现了0-9的数字和很多类似0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C和REGISTRIERT的字符串。

    5、我们随意选择一个数字,双击进去发现都是类似如下的代码:

    00404439   . /7D 12         jge short 0040444D
    0040443B   . |68 A0000000   push 0xA0
    00404440   . |68 B81D4000   push 00401DB8
    00404445   . |56            push esi
    00404446   . |50            push eax
    00404447   . |FF15 2C104000 call dword ptr ds:[<&MSVBVM60.__vbaHresu>;  msvbvm60.__vbaHresultCheckObj
    0040444D   > 8B55 E8       mov edx,dword ptr ss:[ebp-0x18]
    00404450   .  8B37          mov esi,dword ptr ds:[edi]
    00404452   .  52            push edx
    00404453   .  68 1C1E4000   push 00401E1C                            ;  8
    00404458   .  FF15 28104000 call dword ptr ds:[<&MSVBVM60.__vbaStrCa>;  msvbvm60.__vbaStrCat
    0040445E   .  8BD0          mov edx,eax
    00404460   .  8D4D E4       lea ecx,dword ptr ss:[ebp-0x1C]
    00404463   .  FF15 BC104000 call dword ptr ds:[<&MSVBVM60.__vbaStrMo>;  msvbvm60.__vbaStrMove
    00404469   .  50            push eax
    0040446A   .  57            push edi
    0040446B   .  FF96 A4000000 call dword ptr ds:[esi+0xA4]
    00404471   .  85C0          test eax,eax
    00404473   .  DBE2          fclex
    00404475   .  7D 12         jge short 00404489

    上下查找,找不到任何与算法跳转相关的东西。

    6、字符串0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C和REGISTRIERT反而更像是注册码相关的东西,只是….这些注册码是不是有些多的太过了!

    7、选择第一个REGISTRIERT文本,双击进去,向上浏览代码。哇,似乎和之前的三个都一样啊!太好了,我们大概分析一下:

    00404A5B   .^E9 CFFEFFFF   jmp 0040492F
    00404A60   >  8D55 CC       lea edx,dword ptr ss:[ebp-0x34]
    00404A63   .  8D85 4CFFFFFF lea eax,dword ptr ss:[ebp-0xB4]
    00404A69   .  52            push edx
    00404A6A   .  50            push eax
    00404A6B   .  C785 54FFFFFF>mov dword ptr ss:[ebp-0xAC],00401E50     ;  0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C
    00404A75   .  C785 4CFFFFFF>mov dword ptr ss:[ebp-0xB4],0x8008       ;  // 修改eax指针的内容
    00404A7F   .  FF15 5C104000 call dword ptr ds:[<&MSVBVM60.__vbaVarTs>;  msvbvm60.__vbaVarTstEq // 字符串比较
    00404A85   .  66:85C0       test ax,ax
    00404A88   .  74 4C         je short 00404AD6                        ;  // 爆破的关键跳转
    00404A8A   .  8B45 08       mov eax,dword ptr ss:[ebp+0x8]
    00404A8D   .  50            push eax
    00404A8E   .  8B08          mov ecx,dword ptr ds:[eax]
    00404A90   .  FF91 38030000 call dword ptr ds:[ecx+0x338]
    00404A96   .  8D55 AC       lea edx,dword ptr ss:[ebp-0x54]
    00404A99   .  50            push eax
    00404A9A   .  52            push edx
    00404A9B   .  FF15 3C104000 call dword ptr ds:[<&MSVBVM60.__vbaObjSe>;  msvbvm60.__vbaObjSet
    00404AA1   .  8B08          mov ecx,dword ptr ds:[eax]
    00404AA3   .  68 BC1E4000   push 00401EBC                            ;  REGISTRIERT
    00404AA8   .  50            push eax
    00404AA9   .  8985 30FFFFFF mov dword ptr ss:[ebp-0xD0],eax
    00404AAF   .  FF51 54       call dword ptr ds:[ecx+0x54]

    哈哈, msvbvm60.__vbaVarTstEq 进行字符串比较test ax,ax和je short 00404AD6完成是否跳转的判断,爆破的关键就是这里啦!选中je语句,右键->Binary->Fill with NOPs。回到程序,神马?已经提示成功了!

    wps_clip_image-1465

    4、算法探索

    根据msvbvm60.__vbaVarTstEq进行文本比较,我们很容易想到就是通过一个算法生成饿了一个字符串,然后这个字符串与“0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C”进行比较,若果相等就成功。

    我们按照这个思路继续向上分析代码:

    004048FD   .  FF15 30104000 call dword ptr ds:[<&MSVBVM60.__vbaLenVa>;  msvbvm60.__vbaLenVar
    00404903   .  50            push eax                                 ;  // "12321"
    00404904   .  8D95 3CFFFFFF lea edx,dword ptr ss:[ebp-0xC4]
    0040490A   .  8D85 08FFFFFF lea eax,dword ptr ss:[ebp-0xF8]
    00404910   .  52            push edx                                 ;  1
    00404911   .  8D8D 18FFFFFF lea ecx,dword ptr ss:[ebp-0xE8]
    00404917   .  50            push eax                                 ;  // 5
    00404918   .  8D55 DC       lea edx,dword ptr ss:[ebp-0x24]          ;  UNICODE "0817E747D7A7D7C7F82836D74G47A7F7E7B7C7D826D817E7B7"
    0040491B   .  51            push ecx                                 ;  ecx=1
    0040491C   .  52            push edx                                 ;  0
    0040491D   .  FF15 38104000 call dword ptr ds:[<&MSVBVM60.__vbaVarFo>;  msvbvm60.__vbaVarForInit
    00404923   .  8B35 80104000 mov esi,dword ptr ds:[<&MSVBVM60.__vbaSt>;  msvbvm60.__vbaStrVarVal
    00404929   .  8B1D B4104000 mov ebx,dword ptr ds:[<&MSVBVM60.#617>]  ;  msvbvm60.rtcLeftCharVar
    0040492F   >  85C0          test eax,eax
    00404931   .  0F84 29010000 je 00404A60
    00404937   .  8D45 BC       lea eax,dword ptr ss:[ebp-0x44]
    0040493A   .  6A 01         push 0x1
    0040493C   .  8D4D 8C       lea ecx,dword ptr ss:[ebp-0x74]
    0040493F   .  50            push eax                                 ;  // '12321'
    00404940   .  51            push ecx                                 ;  // '1'
    00404941   .  FFD3          call ebx                                 ;  msvbvm60.rtcLeftCharVar
    00404943   .  8D55 8C       lea edx,dword ptr ss:[ebp-0x74]
    00404946   .  8D45 B0       lea eax,dword ptr ss:[ebp-0x50]
    00404949   .  52            push edx
    0040494A   .  50            push eax
    0040494B   .  FFD6          call esi                                 ;  msvbvm60.__vbaStrVarVal
    0040494D   .  50            push eax
    0040494E   .  FF15 D8104000 call dword ptr ds:[<&MSVBVM60.#581>]     ;  msvbvm60.rtcR8ValFromBstr
    00404954   .  DD9D 34FFFFFF fstp qword ptr ss:[ebp-0xCC]
    0040495A   .  8D4D 9C       lea ecx,dword ptr ss:[ebp-0x64]
    0040495D   .  8D55 DC       lea edx,dword ptr ss:[ebp-0x24]
    00404960   .  51            push ecx
    00404961   .  52            push edx
    00404962   .  C745 A4 01000>mov dword ptr ss:[ebp-0x5C],0x1
    00404969   .  C745 9C 02000>mov dword ptr ss:[ebp-0x64],0x2
    00404970   .  FF15 AC104000 call dword ptr ds:[<&MSVBVM60.__vbaI4Var>;  msvbvm60.__vbaI4Var
    00404976   .  50            push eax                                 ;  eax=1 2 3 4
    00404977   .  8D45 BC       lea eax,dword ptr ss:[ebp-0x44]
    0040497A   .  8D4D B8       lea ecx,dword ptr ss:[ebp-0x48]
    0040497D   .  50            push eax
    0040497E   .  51            push ecx
    0040497F   .  FFD6          call esi                                 ;  msvbvm60.__vbaStrVarVal
    00404981   .  50            push eax                                 ;  // '12321'
    00404982   .  FF15 4C104000 call dword ptr ds:[<&MSVBVM60.#631>]     ;  msvbvm60.rtcMidCharBstr
    00404988   .  8BD0          mov edx,eax
    0040498A   .  8D4D B4       lea ecx,dword ptr ss:[ebp-0x4C]
    0040498D   .  FF15 BC104000 call dword ptr ds:[<&MSVBVM60.__vbaStrMo>;  msvbvm60.__vbaStrMove
    00404993   .  50            push eax
    00404994   .  FF15 20104000 call dword ptr ds:[<&MSVBVM60.#516>]     ;  msvbvm60.rtcAnsiValueBstr
    0040499A   .  0FBFD0        movsx edx,ax                             ;  // 取字符的ansii,0x31 0x32 0x33 0x32
    0040499D   .  8995 FCFCFFFF mov dword ptr ss:[ebp-0x304],edx
    004049A3   .  C785 7CFFFFFF>mov dword ptr ss:[ebp-0x84],0x5
    004049AD   .  DB85 FCFCFFFF fild dword ptr ss:[ebp-0x304]            ;  // 转为浮点数,压栈st0
    004049B3   .  DD9D F4FCFFFF fstp qword ptr ss:[ebp-0x30C]            ;  // 出栈
    004049B9   .  DD85 F4FCFFFF fld qword ptr ss:[ebp-0x30C]             ;  // 浮点加载数,拉取数据
    004049BF   .  DC85 34FFFFFF fadd qword ptr ss:[ebp-0xCC]             ;  //从堆栈中弹出这二个操作数,然后把计算的“和”压入堆栈,即:ST=ST(1)+ST
    004049C5   .  DD5D 84       fstp qword ptr ss:[ebp-0x7C]             ;  // 出栈,50.0,51, 52,51
    004049C8   .  DFE0          fstsw ax                                 ;  // ax=0x100
    004049CA   .  A8 0D         test al,0xD                              ;  // 不知道为什么是和0xD比较,但是不用咱关心
    004049CC   .  0F85 FA1F0000 jnz 004069CC                             ;  跳到异常处理,正常不跳
    004049D2   .  8D85 7CFFFFFF lea eax,dword ptr ss:[ebp-0x84]
    004049D8   .  50            push eax
    004049D9   .  FF15 94104000 call dword ptr ds:[<&MSVBVM60.#572>]     ;  msvbvm60.rtcHexBstrFromVar
    004049DF   .  8D4D CC       lea ecx,dword ptr ss:[ebp-0x34]
    004049E2   .  8985 74FFFFFF mov dword ptr ss:[ebp-0x8C],eax
    004049E8   .  8D95 6CFFFFFF lea edx,dword ptr ss:[ebp-0x94]
    004049EE   .  51            push ecx                                 ;  // '0' '032'  // 上一次保存的值
    004049EF   .  8D85 5CFFFFFF lea eax,dword ptr ss:[ebp-0xA4]
    004049F5   .  52            push edx                                 ;  // '33' = 0x32 + 1  // 浮点数的hex值
    004049F6   .  50            push eax                                 ;  // '032'
    004049F7   .  C785 6CFFFFFF>mov dword ptr ss:[ebp-0x94],0x8
    00404A01   .  FF15 84104000 call dword ptr ds:[<&MSVBVM60.__vbaVarCa>;  msvbvm60.__vbaVarCat
    00404A07   .  8BD0          mov edx,eax                              ;  // '0323334'
    00404A09   .  8D4D CC       lea ecx,dword ptr ss:[ebp-0x34]
    00404A0C   .  FFD7          call edi                                 ;  msvbvm60.__vbaVarMove // 将结果存到[ebp-0x34]
    00404A0E   .  8D4D B0       lea ecx,dword ptr ss:[ebp-0x50]
    00404A11   .  8D55 B4       lea edx,dword ptr ss:[ebp-0x4C]
    00404A14   .  51            push ecx
    00404A15   .  8D45 B8       lea eax,dword ptr ss:[ebp-0x48]
    00404A18   .  52            push edx
    00404A19   .  50            push eax
    00404A1A   .  6A 03         push 0x3
    00404A1C   .  FF15 9C104000 call dword ptr ds:[<&MSVBVM60.__vbaFreeS>;  msvbvm60.__vbaFreeStrList
    00404A22   .  8D8D 6CFFFFFF lea ecx,dword ptr ss:[ebp-0x94]
    00404A28   .  8D95 7CFFFFFF lea edx,dword ptr ss:[ebp-0x84]
    00404A2E   .  51            push ecx
    00404A2F   .  8D45 8C       lea eax,dword ptr ss:[ebp-0x74]
    00404A32   .  52            push edx
    00404A33   .  8D4D 9C       lea ecx,dword ptr ss:[ebp-0x64]
    00404A36   .  50            push eax
    00404A37   .  51            push ecx
    00404A38   .  6A 04         push 0x4
    00404A3A   .  FF15 14104000 call dword ptr ds:[<&MSVBVM60.__vbaFreeV>;  msvbvm60.__vbaFreeVarList
    00404A40   .  83C4 24       add esp,0x24
    00404A43   .  8D95 08FFFFFF lea edx,dword ptr ss:[ebp-0xF8]
    00404A49   .  52            push edx
    00404A4A   .  8D85 18FFFFFF lea eax,dword ptr ss:[ebp-0xE8]
    00404A50   .  8D4D DC       lea ecx,dword ptr ss:[ebp-0x24]
    00404A53   .  50            push eax
    00404A54   .  51            push ecx
    00404A55   .  FF15 C8104000 call dword ptr ds:[<&MSVBVM60.__vbaVarFo>;  msvbvm60.__vbaVarForNext
    00404A5B   .^ E9 CFFEFFFF   jmp 0040492F
    00404A60   >  8D55 CC       lea edx,dword ptr ss:[ebp-0x34]
    00404A63   .  8D85 4CFFFFFF lea eax,dword ptr ss:[ebp-0xB4]
    00404A69   .  52            push edx
    00404A6A   .  50            push eax
    00404A6B   .  C785 54FFFFFF>mov dword ptr ss:[ebp-0xAC],00401E50     ;  0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C
    00404A75   .  C785 4CFFFFFF>mov dword ptr ss:[ebp-0xB4],0x8008       ;  // 修改eax指针的内容
    00404A7F   .  FF15 5C104000 call dword ptr ds:[<&MSVBVM60.__vbaVarTs>;  msvbvm60.__vbaVarTstEq // 字符串比较
    00404A85   .  66:85C0       test ax,ax
    00404A88   .  74 4C         je short 00404AD6                        ;  // 爆破的关键跳转
    00404A8A   .  8B45 08       mov eax,dword ptr ss:[ebp+0x8]
    00404A8D   .  50            push eax
    00404A8E   .  8B08          mov ecx,dword ptr ds:[eax]
    00404A90   .  FF91 38030000 call dword ptr ds:[ecx+0x338]
    00404A96   .  8D55 AC       lea edx,dword ptr ss:[ebp-0x54]
    00404A99   .  50            push eax
    00404A9A   .  52            push edx
    00404A9B   .  FF15 3C104000 call dword ptr ds:[<&MSVBVM60.__vbaObjSe>;  msvbvm60.__vbaObjSet
    00404AA1   .  8B08          mov ecx,dword ptr ds:[eax]
    00404AA3   .  68 BC1E4000   push 00401EBC                            ;  REGISTRIERT

    具体VB函数请参考前几节的说明,这里只针对算法部分分析。算法其实内容也很简单,就是在代码:

    00404994   .  FF15 20104000 call dword ptr ds:[<&MSVBVM60.#516>]     ;  msvbvm60.rtcAnsiValueBstr
    0040499A   .  0FBFD0        movsx edx,ax                             ;  // 取字符的ansii,0x31 0x32 0x33 0x32
    0040499D   .  8995 FCFCFFFF mov dword ptr ss:[ebp-0x304],edx
    004049A3   .  C785 7CFFFFFF>mov dword ptr ss:[ebp-0x84],0x5
    004049AD   .  DB85 FCFCFFFF fild dword ptr ss:[ebp-0x304]            ;  // 转为浮点数,压栈st0
    004049B3   .  DD9D F4FCFFFF fstp qword ptr ss:[ebp-0x30C]            ;  // 出栈
    004049B9   .  DD85 F4FCFFFF fld qword ptr ss:[ebp-0x30C]             ;  // 浮点加载数,拉取数据
    004049BF   .  DC85 34FFFFFF fadd qword ptr ss:[ebp-0xCC]             ;  //从堆栈中弹出这二个操作数,然后把计算的“和”压入堆栈,即:ST=ST(1)+ST
    004049C5   .  DD5D 84       fstp qword ptr ss:[ebp-0x7C]             ;  // 出栈,50.0,51, 52,51
    004049C8   .  DFE0          fstsw ax                                 ;  // ax=0x100
    004049CA   .  A8 0D         test al,0xD                              ;  // 不知道为什么是和0xD比较,但是不用咱关心
    004049CC   .  0F85 FA1F0000 jnz 004069CC                             ;  跳到异常处理,正常不跳
    004049D2   .  8D85 7CFFFFFF lea eax,dword ptr ss:[ebp-0x84]
    004049D8   .  50            push eax
    004049D9   .  FF15 94104000 call dword ptr ds:[<&MSVBVM60.#572>]     ;  msvbvm60.rtcHexBstrFromVar

    进行浮点数加法,具体内容是每个字符的ANSII码,加上一个固定的值1,然后格式化为开头为0,然后每个字符加之后的值格式化为2位十六进制文本,最后组合起来的文本与之前的固定文本进行比较,如果成功则注册成功!

    似乎很简单啊!我们尝试C/CPP反计算序列号:

    #include "stdafx.h"
    #include "iostream"
    
    int hex2int(char cAnsi)
    {
    	int nRet = '*';
    	if ( cAnsi >= '0' && cAnsi <= '9')
    	{
    		nRet = cAnsi - '0';
    	}else if ( cAnsi >= 'A' && cAnsi<= 'Z' )
    	{
    		nRet = cAnsi - 'A' + 10;
    	}else if ( cAnsi >= 'a' && cAnsi<= 'z' )
    	{
    		nRet = cAnsi - 'A' + 10;
    	}
    	return nRet;
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
    	char pCmp[] = "0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C"; // 第一个一定是0,不做处理
    	char pKey[100] = {0};
    	char cHex[3] = {0};
    	// 转换为整数,然后减一的值作为ANSII码组成字符串
    	int nLen = strlen(pCmp);
    	printf("Len: %d
    ",nLen);
    	int nCode = 0;
    	for( int i=0;i<nLen/2;i++ )
    	{
    		cHex[0] = pCmp[1+i*2];
    		cHex[1] = pCmp[1+i*2+1];
    		nCode = hex2int(pCmp[1+i*2])*0x10 + hex2int(pCmp[1+i*2+1]);
    		pKey[i] = nCode - 1; // 1,12,
    	}
    	printf("Key:%s
    ",pKey);
    
    	system("pause");
    	return 0;
    }

    计算出来一堆乱七八糟的文本,不管了,…..可是我们无法输入进去啊!坑啊!

    回想之前的步骤,是不是还有很多比较的文本和“REGISTR”字样的文本?好吧,我们也尝试一下….

    我直接说结果吧!他们的代码几乎就一样的,只是中间加的固定值不太一样,所以,我们多换几个(其实C/CPP中也已经试过了!),试过之后发现,还是无法计算出一个使0-9组成的字符串,真心无语了!

    到了这里,说实在的,真的没什么办法了!我的算法似乎也找到了,但是为什么不对呢?本着【相信CracMe作者,怀疑自己的态度】,到网上搜索还有没有更好的反汇编VB的程序,答案是:没有!

    但是,找到了一个可以跟踪VB事件的程序,叫做VB程序调试工具(SmartCheck),抱着试一试的态度,还真看出来了一些门道:

    wps_clip_image-1919

    wps_clip_image-9737

    wps_clip_image-13182

    建议感兴趣的自己去下一个看看,一定要再输入完成后停止捕捉事件,然后等待日志完成。拉到最后几个,随意选择一个事件,按照顺序查看,你会很惊奇地发现:

    比如我输入的注册码为12321,程序进行了如下步骤:

    1、 取第1个字符‘1’,转换为ANSII为0x31,然后加上1

    2、 取第2个字符‘2’,转换为ANSII为0x32,然后加上1

    3、 取第3个字符‘3’,转换为ANSII为0x33,然后加上1

    4、 取第4个字符‘2’,转换为ANSII为0x32,然后加上1

    5、 取第5个字符‘1’,转换为ANSII为0x31,然后加上1

    6、 取第1个字符‘1’,转换为ANSII为0x31,然后加上12

    7、 取第2个字符‘2’,转换为ANSII为0x32,然后加上12

    8、 取第3个字符‘3’,转换为ANSII为0x33,然后加上12

    …….

    然后每个字符都加上 123,再一次每个字符加上1232,再一次每个字符加上12321,结束。

    我们可以大胆地猜测,每次循环都将我们之前分析的算法使用上,进行字符串比较,然后相等的才是正确的注册码!

    我实在无语了!多么坑的作者才会做出这么OOXX的程序,反正按照这个思路我是找不到的。暴力遍历的思路是有的,但是一想到一共51个字符,算下来这个注册码应该的长度是25个数字或者*#号,我就有一种蛋蛋的忧伤!ByeBye 不伺候你了!活该被标记了一个大大的问号!

    BY 笨笨D幸福

  • 相关阅读:
    xScrapBook
    使用STL仿函数和判断式来降低复杂性并改善可读[转]
    C++ 开源程序库[转]
    资源泄漏的悲剧
    Excel导入的HDR=YES; IMEX=1详解
    largeint.lib
    共享刚写的简单DirectUI库 只实现了思想
    document.body.scrollTop的值总为零的解决办法
    CDCHandle谨慎使用
    C++中std::tr1::function和bind 组件的使用
  • 原文地址:https://www.cnblogs.com/bbdxf/p/3798188.html
Copyright © 2020-2023  润新知