找回密码
 注册
搜索
热搜: 回贴

ACProtect 1.22b脱壳手记----NOTEPAD.EXE,ACProtect,脱壳技术

2010-1-30 18:20| 发布者: admin| 查看: 76| 评论: 0|原作者: 青鸾峰


ACProtect 1.22b脱壳手记----NOTEPAD.EXE,ACProtect,脱壳技术
2008年06月23日 星期一 下午 04:58
ACProtect 1.22b脱壳手记----NOTEPAD.EXE





目标:NOTEPAD.EXE,自己用ACProtect 1.22b专业版加壳,Compress Opetions里选Opetion1,Advanced Opetions的六个选项全选;加壳前49.7 KB,加壳后143 KB



工具:OllyDbg Beta110b原版; ImportREC 1.6 FINAL



破解平台:Win2000SP4 Chinese



主要目的:跳过IAT加密,快速到达伪OEP,Replace Code的一些处理;

由于ASProtect的Stolen code已经被各位老大们搞的很透彻了,ACProtect的Stolen code的分析和修复没多大差别,所以我就不在罗嗦了(省的敲不少字呢,呵呵)



废话少说,开工

———————————————————————————————————



用OllyDbg加载目标后,忽略所有异常,用插件IsDebuggerPresent隐藏调试器标志,程序停在这:

01010000 > 60 PUSHAD

01010001 66:8BCA MOV CX,DX

01010004 87C8 XCHG EAX,ECX

01010006 41 INC ECX

01010007 72 01 JB SHORT NOTEPAD_.0101000A

01010009 43 INC EBX

0101000A 48 DEC EAX

0101000B FC CLD

0101000C 50 PUSH EAX

0101000D E8 01000000 CALL NOTEPAD_.01010013

01010012 7A 83 JPE SHORT NOTEPAD_.0100FF97

01010014 C40458 LES EAX,FWORD PTR DS:[EAX EBX*2]

01010017 66:8BEE MOV BP,SI

0101001A E8 01000000 CALL NOTEPAD_.01010020

. ;从开头到01010BB6都是壳的分段解密,可以看准

. ;每段循环结束位置0F85 xxFFFFFF,用F4直接跳到下一循环

.

.

.

.

01010BB6 4F DEC EDI

01010BB7 81F3 0503C769 XOR EBX,69C70305

01010BBD 68 4F460000 PUSH 464F

01010BC2 4E DEC ESI

01010BC3 59 POP ECX ;ECX=464Fh,这段循环解密的dword数

01010BC4 8B28 MOV EBP,DWORD PTR DS:[EAX] ;循环开始,这是一个大循环,解密了从01010BEA

01010BC6 03EB ADD EBP,EBX ;开始的(464Fh-1)*4=11938h字节

01010BC8 C1C5 12 ROL EBP,12

01010BCB 83C0 04 ADD EAX,4

01010BCE 0328 ADD EBP,DWORD PTR DS:[EAX]

01010BD0 83C0 FC ADD EAX,-4

01010BD3 8928 MOV DWORD PTR DS:[EAX],EBP

01010BD5 81F3 B2A9C00F XOR EBX,0FC0A9B2

01010BDB 81C0 04000000 ADD EAX,4

01010BE1 83E9 01 SUB ECX,1

01010BE4 ^ 0F85 DAFFFFFF JNZ NOTEPAD_.01010BC4

01010BEA 116C95 AB ADC DWORD PTR SS:[EBP EDX*4-55],EBP ;在这下硬件执行断点

01010BEE 53 PUSH EBX

01010BEF ^ 79 91 JNS SHORT NOTEPAD_.01010B82



上面的循环结束后01010BEA处变为

01010BEA /E9 A9180100 JMP NOTEPAD_.01022498 ;这个JMP远距离跳到壳真正开始工作的地方

01010BEF |0000 ADD BYTE PTR DS:[EAX],AL

01010BF1 |0000 ADD BYTE PTR DS:[EAX],AL

01010BF3 |0000 ADD BYTE PTR DS:[EAX],AL

01010BF5 |0000 ADD BYTE PTR DS:[EAX],AL

01010BF7 |0000 ADD BYTE PTR DS:[EAX],AL





在01010BEA上点右键,Folllow Dump->Selection,在内存窗口里搜索HEX:4D4D4D4D,找到如下:

01010F19 4D 4D 4D 4D C5 73 FE FF D2 73 FE FF 00 00 00 00 MMMM舠?襰?....

01010F29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01010F39 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01010F49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01010F59 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................



01010F19就是ACProtect在后面开始处理Stolen code时放置0006FFF0(即OD刚加载程序时的EBP,一般程序多数是0012FFF0,NOTEPAD.EXE有点特殊),在01010F19下硬件访问断点,目的是快速到达处理Stolen code的地方





———————————————————————————————————



2.跳过IAT加密



在GetProcAddress入口处下硬件断点,也可以在GetProcAddress入口处跳过一字节后用F2下普通断点.F9运行,会在GetProcAddress上断下,堆栈显示的是GlobalAlloc,这是壳自己用到的API,一共23个,依次是

GlobalAlloc.GlobalFree.GetCurrentProcessId.CreateToolhelp32Snapshot.Process32First.Process32Next.CloseHandle.CreateFileA.TerminateProcess.IsDebuggerPresent.OpenProcess.ReadFile.WriteFile.FreeLibrary.GetTempPathA.UnhandledExceptionFilter.GetThreadContext.SetThreadContext.GetCurrentThread.EnumWindows.GetWindowTextA.GetClassNameA.PostMessageA

一直按F9运行,在处理过PostMessageA后,就开始处理程序的API,堆栈和寄存器都会有个较大的变化,断下后,是处IsProcessorFeaturePresent,Return to msvcrt.78001EAA,继续F9,直到堆栈第一次显示Return to NOTEPAD.XXXXX,这时处理的是FindTextW,取消GetProcAddress的硬件执行断点,Ctrl F9运行返回到壳里



PS:如果被加壳的程序是用Delphi或BCB写的话,在PostMessageA后处理的下一个API,堆栈显示就是返回到壳程序,但VC 的程序在处理完PostMessageA后还会由Kenrel调用GetProcAddress处理一些msvcrt,COMCTL32等里的一

些API,所以必须等处理完这些API后,在壳调用GetProcAddress处理程序原来的API时才能Ctrl F9返回到壳里



Ctrl F9运行返回后:

0102201B 53 PUSH EBX

0102201C FFB5 29DE4000 PUSH DWORD PTR SS:[EBP 40DE29]

01022022 FF95 80B04100 CALL DWORD PTR SS:[EBP 41B080] ;Call GetProcAddress

01022028 3B9D 31DE4000 CMP EBX,DWORD PTR SS:[EBP 40DE31];Ctrl F9返回到这里,EBP=00C0F000

0102202E 7C 0F JL SHORT NOTEPAD_.0102203F ;所以GetProcAddress的地址是

01022030 90 NOP ;EBP 41B080=102A080,记下这个地址!

01022031 90 NOP

01022032 90 NOP

01022033 90 NOP

01022034 60 PUSHAD

01022035 2BC0 SUB EAX,EAX

01022037 8803 MOV BYTE PTR DS:[EBX],AL

01022039 43 INC EBX

0102203A 3803 CMP BYTE PTR DS:[EBX],AL

0102203C ^ 75 F9 JNZ SHORT NOTEPAD_.01022037

0102203E 61 POPAD

0102203F 0BC0 OR EAX,EAX

01022041 ^ 0F84 21FFFFFF JE NOTEPAD_.01021F68 ;EAX=刚才GetProcAddress得到的API的入口

01022047 3B85 90B04100 CMP EAX,DWORD PTR SS:[EBP 41B090];EBP 41B090指向MessageBox

0102204D 75 0A JNZ SHORT NOTEPAD_.01022059 ;① 这里把得到的API入口与MessageBox

0102204F 90 NOP ;比较,相等就用壳的MessageBox来代替

01022050 90 NOP ;程序的MessageBox,把①处的JNZ改为JMP

01022051 90 NOP ;即可跳过ACProtect对MessageBox作的手脚

01022052 90 NOP

01022053 8D85 D4E34000 LEA EAX,DWORD PTR SS:[EBP 40E3D4]

01022059 56 PUSH ESI

0102205A FFB5 29DE4000 PUSH DWORD PTR SS:[EBP 40DE29]

01022060 5E POP ESI

01022061 39B5 FA234000 CMP DWORD PTR SS:[EBP 4023FA],ESI

01022067 74 15 JE SHORT NOTEPAD_.0102207E

01022069 90 NOP

0102206A 90 NOP

0102206B 90 NOP

0102206C 90 NOP

0102206D 39B5 FE234000 CMP DWORD PTR SS:[EBP 4023FE],ESI

01022073 74 09 JE SHORT NOTEPAD_.0102207E

01022075 90 NOP

01022076 90 NOP

01022077 90 NOP

01022078 90 NOP

01022079 EB 63 JMP SHORT NOTEPAD_.010220DE

0102207B 90 NOP

0102207C 90 NOP

0102207D 90 NOP

0102207E 80BD 90304100 00 CMP BYTE PTR SS:[EBP 413090],0

01022085 74 57 JE SHORT NOTEPAD_.010220DE

01022087 90 NOP

01022088 90 NOP

01022089 90 NOP

0102208A 90 NOP

0102208B EB 07 JMP SHORT NOTEPAD_.01022094

0102208D 90 NOP

0102208E 90 NOP

0102208F 90 NOP

01022090 0100 ADD DWORD PTR DS:[EAX],EAX

01022092 0000 ADD BYTE PTR DS:[EAX],AL

01022094 8BB5 F6DE4000 MOV ESI,DWORD PTR SS:[EBP 40DEF6] ;EBP 40DEF6指向Acpr要转移API的地方

0102209A 83C6 0D ADD ESI,0D

0102209D 81EE EA1B4000 SUB ESI,401BEA

010220A3 2BF5 SUB ESI,EBP

010220A5 83FE 00 CMP ESI,0

010220A8 7F 34 JG SHORT NOTEPAD_.010220DE ;② 不跳就把API转移到[EBP 40DEF6]

010220AA 90 NOP ;所以把②处的JG改为JMP即可跳过Acpr

010220AB 90 NOP ;对IAT的加密!

010220AC 90 NOP

010220AD 90 NOP

010220AE 8BB5 F6DE4000 MOV ESI,DWORD PTR SS:[EBP 40DEF6]

010220B4 53 PUSH EBX

010220B5 50 PUSH EAX

010220B6 E8 CABCFFFF CALL NOTEPAD_.0101DD85

010220BB 8BD8 MOV EBX,EAX

010220BD 58 POP EAX

010220BE 33C3 XOR EAX,EBX

010220C0 C606 68 MOV BYTE PTR DS:[ESI],68

010220C3 8946 01 MOV DWORD PTR DS:[ESI 1],EAX

010220C6 C746 05 81342400 MOV DWORD PTR DS:[ESI 5],243481

010220CD 895E 08 MOV DWORD PTR DS:[ESI 8],EBX

010220D0 C646 0C C3 MOV BYTE PTR DS:[ESI C],0C3

010220D4 5B POP EBX

010220D5 8BC6 MOV EAX,ESI

010220D7 8385 F6DE4000 0D ADD DWORD PTR SS:[EBP 40DEF6],0D

010220DE 5E POP ESI

010220DF 8907 MOV DWORD PTR DS:[EDI],EAX ;③ 这里把API写入正确的IAT里

010220E1 8385 2DDE4000 04 ADD DWORD PTR SS:[EBP 40DE2D],4 ;d EDI 就可以看到程序原本的

010220E8 ^ E9 C6FEFFFF JMP NOTEPAD_.01021FB3 ;IAT跳转表

010220ED 83C6 14 ADD ESI,14

010220F0 8B95 31DE4000 MOV EDX,DWORD PTR SS:[EBP 40DE31]

010220F6 ^ E9 28FEFFFF JMP NOTEPAD_.01021F23

010220FB 60 PUSHAD \;④ 上面的①②改掉后,用F4直接运行到这里

010220FC E8 00000000 CALL NOTEPAD_.01022101 |;也可下硬件断点,F9运行,断下后

01022101 5E POP ESI |;再把①②处改会原来的代码.

01022102 83EE 06 SUB ESI,6 |;一定要改回去,不然壳会在最后

01022105 B9 09020000 MOV ECX,209 |;效验并解密伪OEP处代码时出错!

0102210A 29CE SUB ESI,ECX |

0102210C BA BAA8FF62 MOV EDX,62FFA8BA |

01022111 C1E9 02 SHR ECX,2 |

01022114 83E9 02 SUB ECX,2 |

01022117 83F9 00 CMP ECX,0 |

0102211A 7C 1A JL SHORT NOTEPAD_.01022136 |

0102211C 8B048E MOV EAX,DWORD PTR DS:[ESI ECX*4] |

0102211F 8B5C8E 04 MOV EBX,DWORD PTR DS:[ESI ECX*4 4] |

01022123 2BC3 SUB EAX,EBX |

01022125 C1C8 1F ROR EAX,1F |

01022128 33C2 XOR EAX,EDX |

0102212A 81C2 D82567EC ADD EDX,EC6725D8 |

01022130 89048E MOV DWORD PTR DS:[ESI ECX*4],EAX |

01022133 49 DEC ECX |

01022134 ^ EB E1 JMP SHORT NOTEPAD_.01022117 /;这段循环是把010220F6前的代码

01022136 61 POPAD ;恢复加密,这样的循环在Acpr里

01022137 61 POPAD ;随处可见,每段解密后的执行代码后

01022138 C3 RETN ;都会有这样的恢复加密的循环



PS:在③处d edi后,可以在内存窗口里随便找一个字节,把它随便改成别的值,然后再改会原来的值,这样OD就会把之后写入该内存页所有的值用红色高亮显示,在④处断下后,在内存窗口里找到最前面的用红色显示的值,它的地址就是IAT了!我这里看到的是01001000,用ImportREC得到输入表时RAV里填的就是01001000-01000000=1000





———————————————————————————————————



3.快速到达处理Stolen code的地方



我们已经在01010F19下了硬件访问断点,在做完上面的处理后,按F9运行,就会直接断在开始处理Stolen code的地方,如下

.

.

.

.

010236D1 61 POPAD

010236D2 56 PUSH ESI

010236D3 BE E50E0101 MOV ESI,NOTEPAD_.01010EE5

010236D8 890E MOV DWORD PTR DS:[ESI],ECX

010236DA 5E POP ESI

010236DB FF35 E50E0101 PUSH DWORD PTR DS:[1010EE5]

010236E1 893C24 MOV DWORD PTR SS:[ESP],EDI

010236E4 57 PUSH EDI

010236E5 BF 190F0101 MOV EDI,NOTEPAD_.01010F19

010236EA 893D E10E0101 MOV DWORD PTR DS:[1010EE1],EDI

010236F0 5F POP EDI

010236F1 FF35 E10E0101 PUSH DWORD PTR DS:[1010EE1] ; NOTEPAD_.01010F19

010236F7 8B3C24 MOV EDI,DWORD PTR SS:[ESP]

010236FA 8F05 DD0E0101 POP DWORD PTR DS:[1010EDD] ; NOTEPAD_.01010F19

01023700 892F MOV DWORD PTR DS:[EDI],EBP ;EDI=01010F19

01023702 8B3C24 MOV EDI,DWORD PTR SS:[ESP] ;断在这儿

01023705 8F05 F90E0101 POP DWORD PTR DS:[1010EF9]

0102370B FF35 190F0101 PUSH DWORD PTR DS:[1010F19]

01023711 8925 150F0101 MOV DWORD PTR DS:[1010F15],ESP

01023717 893D BD0E0101 MOV DWORD PTR DS:[1010EBD],EDI

0102371D 90 NOP

0102371E 90 NOP

0102371F 60 PUSHAD

01023720 50 PUSH EAX

01023721 E8 01000000 CALL NOTEPAD_.01023727

.

.

.

.

从这段代码起Acpr开始处理Stolen code,具体的Stolen code我不是很在行,几位老大已经分析的清晰透彻了.

Acpr对Stolen code处理的代码是分段解密后再执行的,因为我们前面在这个内存页里改过数据,所以所有重新写入的代码都是用红色高亮显示了,这就给我们用F4快速执行过解密代码带来了方便,具体方法是在最后一句高亮显示的代码开始向上找0F85 xxFFFFFF(JNZ xxxxxxxx)远程跳转语句,然后F4到它下面的一句上,有的0F85 xxFFFFFF的语句会因为它前后的代码环境而不被OD显示出来,这是可以Crtl G到0F85 xxFFFFFF的地址,也可以找到高亮显示的最后一个E8 010000 或EB 01,然后F4到其上,再F7几步就可以看到0F85 xxFFFFFF(JNZ xxxxxxxx)了

处理Stolen code的前几段代码都是对堆栈的处理,要是不分析Stolen code的话可以不用管,但是后面几段因为会包含到程序OEP的Call,如果执行这些Call的话,就有可能因为执行了Replace Code而改变程序的数据结构.

我的处理方法是把这些Call先nop掉,在执行完nop后,在把Call的代码恢复回去,例如:下面代码执行到①处CALL DWORD PTR DS:[100115C] 时把它先用nop填充掉,等走完nop后再把CALL DWORD PTR DS:[100115C]写回去,但②③会用到EAX指针,我们跳过了Call,所以到②和③时会出错,于是一不做二不休,把②③的代码也按刚才的方法干掉





01028D7E /E9 04000000 JMP NOTEPAD_.01028D87

01028D83 |66:BD 27CC MOV BP,0CC27

01028D87 \61 POPAD

01028D88 FF15 5C110001 CALL DWORD PTR DS:[100115C] ; msvcrt.__p__fmode ①

01028D8E 891D 110F0101 MOV DWORD PTR DS:[1010F11],EBX

01028D94 FF35 110F0101 PUSH DWORD PTR DS:[1010F11]

01028D9A C705 0D0F0101 4>MOV DWORD PTR DS:[1010F0D],NOTEPAD_.010088>

01028DA4 8B1D 0D0F0101 MOV EBX,DWORD PTR DS:[1010F0D] ; NOTEPAD_.010065D0

01028DAA 8B0B MOV ECX,DWORD PTR DS:[EBX]

01028DAC 8B1C24 MOV EBX,DWORD PTR SS:[ESP]

01028DAF 8F05 090F0101 POP DWORD PTR DS:[1010F09]

01028DB5 8908 MOV DWORD PTR DS:[EAX],ECX ;②

01028DB7 FF15 4C110001 CALL DWORD PTR DS:[100114C] ; msvcrt.__p__commode

01028DBD 53 PUSH EBX

01028DBE 893424 MOV DWORD PTR SS:[ESP],ESI

01028DC1 57 PUSH EDI

01028DC2 BF 40880001 MOV EDI,NOTEPAD_.01008840

01028DC7 8BF7 MOV ESI,EDI

01028DC9 5F POP EDI

01028DCA 8B16 MOV EDX,DWORD PTR DS:[ESI]

01028DCC 8B3424 MOV ESI,DWORD PTR SS:[ESP]

01028DCF 8F05 050F0101 POP DWORD PTR DS:[1010F05]

01028DD5 8910 MOV DWORD PTR DS:[EAX],EDX ;③

01028DD7 90 NOP

01028DD8 60 PUSHAD

01028DD9 E8 01000000 CALL NOTEPAD_.01028DDF



PS:每段处理Stolen code的代码前总要走好几段解密代码,鼠标滚轮费的紧啊,偶的食指也隐隐作痛了 越往后走F4就越要甚用,不然一不小心就会跟飞,不放心的话最好用F7步入,最后来到下面:



01029A80 E8 6245FFFF CALL NOTEPAD_.0101DFE7 ;EBP=00C0F000

01029A85 8DB5 80B04100 LEA ESI,DWORD PTR SS:[EBP 41B080] ;EBP 41B080=102A080,就是前面我们

01029A8B 8DBD 1EE34000 LEA EDI,DWORD PTR SS:[EBP 40E31E] ;记下的GetProcAddress的地址!

01029A91 B9 05000000 MOV ECX,5

01029A96 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]

01029A98 40 INC EAX ;这里把包含GetProcAddress在内

01029A99 EB 01 JMP SHORT NOTEPAD_.01029A9C ;的5个API地址Copy到[101D31E]



这5个API是壳的IAT里的,依次是GetProcAddress.GetModuleHandleA.LoadLibraryA.ExitProcess.MessageBoxA

这段之后再经过一段解密代码就到了壳解密伪OEP处代码并跳向伪OEP的地方,所以如果要快速到达伪OEP,就可以在前面我们得到GetProcAddress的地址时,在它上面下硬件访问断点!



经过一段解密代码后来到这里:



01029C3E 66:C1DF 4D RCR DI,4D

01029C42 E8 A043FFFF CALL NOTEPAD_.0101DFE7

01029C47 8B85 E4AC4100 MOV EAX,DWORD PTR SS:[EBP 41ACE4]

01029C4D 0385 31DE4000 ADD EAX,DWORD PTR SS:[EBP 40DE31]

01029C53 8985 E4AC4100 MOV DWORD PTR SS:[EBP 41ACE4],EAX

01029C59 E8 8943FFFF CALL NOTEPAD_.0101DFE7

01029C5E C685 A1AC4100 E8 MOV BYTE PTR SS:[EBP 41ACA1],0E8

01029C65 E8 7D43FFFF CALL NOTEPAD_.0101DFE7

01029C6A C785 A2AC4100 FF>MOV DWORD PTR SS:[EBP 41ACA2],25FF

01029C74 8D85 E4AC4100 LEA EAX,DWORD PTR SS:[EBP 41ACE4]

01029C7A 8985 A4AC4100 MOV DWORD PTR SS:[EBP 41ACA4],EAX

01029C80 E8 6243FFFF CALL NOTEPAD_.0101DFE7

01029C85 8DBD 80AA4100 LEA EDI,DWORD PTR SS:[EBP 41AA80]

01029C8B 8D8D 96AC4100 LEA ECX,DWORD PTR SS:[EBP 41AC96]

01029C91 2BCF SUB ECX,EDI

01029C93 C1E9 02 SHR ECX,2

01029C96 E8 EA40FFFF CALL NOTEPAD_.0101DD85 ;\这个循环解密出伪OEP处的代码

01029C9B AB STOS DWORD PTR ES:[EDI] ;|如果前面改掉的代码不及时恢复的

01029C9C ^ E2 F8 LOOPD SHORT NOTEPAD_.01029C96 ;/话,这里就会解密错误

01029C9E 61 POPAD

01029C9F EB 01 JMP SHORT NOTEPAD_.01029CA2



01029CA2 - FF25 E49C0201 JMP DWORD PTR DS:[1029CE4] ; NOTEPAD_.0100649F 飞向伪OEP!



到达伪OEP后就可以dump出程序,运行ImportREC,OEP填入伪OEP=0000649F,RAV填入前面得到的00001000,Size填入1000,Get Import,即可得到完整的API,把Invalid的FThunk全部Delete掉,按默认选项,选中Add new section ,Fix Dump,OK!



PS:有的程序在填入伪OEP后,IAT AutoSearch会可能得不到IAT的RAV



可惜的是NOTEPAD.EXE本身太小,Acpr居然没有Replace Code,我是一边脱壳一边写的,程序Dump出后,才发现没有Replace Code,实在可惜.其实,在伪OEP Dump出的程序已经包含了解密Replace Code的代码和数据表,修复IAT,Stolen code和OEP后程序就可以正常运行.当然,要把脱壳后的程序修复的接近完美的话,也可以自己手工修复所有的Replace Code



PS:Acpr的Stolen code有点儿局限,有些由Delphi和BCB写的程序的原OEP处是EB 10 JMP xxxxxxxx的跳转语句,例如OllyDbg,这时Acpr就不会Stolen code.我本来是想把OllyDbgBeta110b的主程序加壳当试练品,可Acpr没Stolen code,只好换NOTEPAD.EXE了



———————————————————————————————————



后记:

上次写破文是在5个月前,那时就怀疑自己的表达是否清楚合理,现在就更没把握了,还请各位看了不要笑话.国内软件用Acpr加壳的不多,不知道是因为没有破版放出,还是对Acpr没有信心,关于Acpr的破文就更少了.与之成鲜明对比的是Aspr,ASProtect 1.23RC4和1.30也不见有破版广泛流传(我自己就没有1.23 RC4的可用版,1.30见都没见过 555~),但用其加壳的程序比比皆是(1.30我不敢说,但加1.23 RC4的确实不少),破文更是扑天盖地.现在Acpr的破版在一月之内接连放出,不知道局面是否会有所改变



thl0057

04.04.01

于 HD



上一次由thl0057于2004-4-01 周四, 下午10:57修改,总共修改了6次


最新评论

QQ|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )

GMT+8, 2024-9-29 21:32 , Processed in 0.280770 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

返回顶部