国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

如何封鎖您的(或打開別人的) Java 代碼

2019-11-18 14:45:49
字體:
供稿:網(wǎng)友

內(nèi)容:

什么是反編譯?
反匯編一個(gè)類文件
使用反編譯器
反編譯和對(duì)安全的威脅
針鋒相對(duì)的代碼模糊處理
這一領(lǐng)域的新成員
總結(jié)
參考資料
關(guān)于作者
評(píng)價(jià)本文


相關(guān)內(nèi)容:

讓您的軟件運(yùn)行:模糊安全性
java 和分布式目標(biāo)系統(tǒng)上的安全性研究




Java 代碼反編譯和模糊處理的完全指南
Greg Travis (mito@panix.com)
自由程序員,紐約

無論是修改許多網(wǎng)上開放源代碼庫(kù)中的代碼,還是調(diào)用常見的操作系統(tǒng)例行程序,您免不了要花一些時(shí)間去琢磨您沒有編寫過的代碼,而且您還可能沒有這些代碼的源文件。在開始調(diào)試代碼時(shí),您需要有一個(gè)好的 Java 反編譯器,并了解正確使用它的技術(shù)。同時(shí),您還要知道如何保護(hù)您自己的代碼不被窺視。為此,您還需了解有關(guān)代碼模糊處理的問題。在這篇有關(guān)打開和封鎖 Java 代碼的初學(xué)者指南中, Greg Travis 使用 Mocha、HoseMocha、jmangle 和 JODE 等流行工具中的示例,來循序漸進(jìn)地教你有關(guān)反匯編、反編譯和 Java 代碼模糊處理的基礎(chǔ)知識(shí)。
沒有比發(fā)現(xiàn)一個(gè)錯(cuò)誤,卻沒有源代碼就不能修改更令人沮喪的了。正是這個(gè)原因?qū)е铝?Java 反編譯器的出現(xiàn),它可以把編譯后的字節(jié)碼完全轉(zhuǎn)回成源代碼。盡管代碼反編譯器不只是針對(duì) Java 語(yǔ)言,但它從來沒有象在 Java 開發(fā)人員中那樣被公開地或廣泛地使用。

與反編譯針鋒相對(duì)的是模糊處理。假設(shè)反編譯人員能很輕易從編譯后的代碼中設(shè)法得到源代碼,那么要保護(hù)您的代碼和有價(jià)值的技術(shù)秘密就不是那么簡(jiǎn)單了。隨著 Java 反編譯器的普遍使用, Java 模糊處理器也同樣被普及,它的作用就似乎放一塊煙幕在您的代碼前面。反編譯和模糊處理在商業(yè)開發(fā)領(lǐng)域中引起了一場(chǎng)爭(zhēng)論 -- 爭(zhēng)論中的大部分都集中在了 Java 語(yǔ)言上。

在本文中,我將讓您了解代碼反編譯和模糊處理的具體過程,討論在這兩種技術(shù)之后的理論問題,同時(shí)簡(jiǎn)要地談到它們?cè)谏虡I(yè)編程領(lǐng)域中所引起的爭(zhēng)論。我還將介紹一些比較有名的反編譯器和模糊處理器(有商業(yè)的,也有開放源代碼的),并隨著文章的深入使用它們來創(chuàng)建一些實(shí)例。

什么是反編譯?
反編譯是一個(gè)將目標(biāo)代碼轉(zhuǎn)換成源代碼的過程。這應(yīng)該很清楚了,因?yàn)榫幾g是一個(gè)將源代碼轉(zhuǎn)換成目標(biāo)代碼的過程。但什么是目標(biāo)代碼呢?大體上的定義是:目標(biāo)代碼是一種用語(yǔ)言表示的代碼,這種語(yǔ)言能通過實(shí)機(jī)或虛擬機(jī)直接執(zhí)行。對(duì)于象 C 這樣的語(yǔ)言,目標(biāo)代碼通常運(yùn)行在硬件 CPU 上,而 Java 目標(biāo)代碼通常運(yùn)行在虛擬機(jī)上。

反編譯是困難的
正如以上所描述的,反編譯聽上去比較簡(jiǎn)單,但它實(shí)際上是非常困難的 -- 從本質(zhì)上說,它所包含的是根據(jù)小規(guī)模、低層次的行為來推斷大規(guī)模、高層次的行為。為了對(duì)此有個(gè)直觀的理解,我們把一個(gè)計(jì)算機(jī)程序看作是一個(gè)復(fù)雜的公司組織結(jié)構(gòu)。高層治理人員向他們的下屬下達(dá)類似“最大程度地提高技術(shù)生產(chǎn)能力”的命令,下屬們?cè)侔堰@些命令轉(zhuǎn)變成更具體的行動(dòng),例如安裝新的 xml 數(shù)據(jù)庫(kù)。

作為該公司的新雇員,您可能會(huì)問下屬他或她在做些什么,并得到回答,“我在安裝新的 XML 數(shù)據(jù)庫(kù)?!睆倪@句話中,您不可能推斷出其最終目的是最大程度地提高技術(shù)生產(chǎn)能力。究竟,最終目標(biāo)不盡相同,例如可能是分離供給鏈或累積消費(fèi)者的數(shù)據(jù)。

然而,假如屬于好奇心特強(qiáng)的那類人,您可能會(huì)再多問幾個(gè)問題,并讓公司中不同級(jí)別的下屬回答您的問題。最后,當(dāng)把所有的答案匯總后,您可能會(huì)猜到企業(yè)更大的目標(biāo)是最大程度地提高技術(shù)生產(chǎn)能力。

假如您把計(jì)算機(jī)程序的工作方式看作類似一個(gè)公司的組織結(jié)構(gòu),那么對(duì)于為什么反編譯代碼不是無關(guān)緊要的,以上的這個(gè)比方就會(huì)給你一個(gè)直接的感受。從比較理論化的角度來看,這兒要引用在該領(lǐng)域的杰出研究員 Cristina Cifuentes 對(duì)反編譯過程的描述:


任何一個(gè)二進(jìn)制改造工程都需要對(duì)存儲(chǔ)在二進(jìn)制文件中的代碼進(jìn)行反匯編。從理論上說,分離 von Neumann 上的數(shù)據(jù)和代碼就好象停機(jī)問題,因此完全的靜態(tài)翻譯是不可能的。然而,實(shí)際上可以使用不同技術(shù)來提高可被靜態(tài)翻譯的代碼的所占比例,或者采取可在運(yùn)行中被使用的動(dòng)態(tài)翻譯技術(shù)。
--"Binary Reengineering of Distributed Object Technology" (請(qǐng)參閱參考資料)

把目標(biāo)代碼轉(zhuǎn)換成源代碼并不是反編譯時(shí)碰到的唯一問題。一個(gè) Java 類文件潛在包含了一些不同類型的信息。知道類文件中可能包含了哪類信息對(duì)于了解您如何利用該信息以及對(duì)于信息作何種處理都是很重要的。這其實(shí)就是 Java 反匯編器所要做的。

反匯編一個(gè)類文件
Java 類文件的真正二進(jìn)制格式不是很重要。重要的是知道在那些字節(jié)中包含了哪些不同種類的信息。到了這一步,我們將利用多數(shù) JDK 都帶有的一個(gè)工具 -- javap。 javap 是一個(gè) Java 代碼反匯編器,它和反編譯器是不同的。反匯編器把機(jī)器可讀格式的目標(biāo)代碼(如清單 1 所示)轉(zhuǎn)換成人們可讀的代碼(如清單 2 所示)。

清單 1. 一個(gè)類文件的原始內(nèi)容
0000000 feca beba 0300 2d00 4200 0008 081f 3400
0000020 0008 073f 2c00 0007 0735 3600 0007 0737
0000040 3800 0007 0a39 0400 1500 000a 0007 0a15
0000060 0800 1600 000a 0008 0a17 0800 1800 0009
...




清單 2. javap 的輸出結(jié)果
Local variables for method void PRiv(int)
Foo this pc=0, length=35, slot=0
int argument pc=0, length=35, slot=1

Method void main(java.lang.String[])
0 new #4
3 invokespecial #10
6 return




請(qǐng)注重,清單 2 所示的并不是源代碼。該清單的第一部分列出了方法的局部變量;第二部分是匯編代碼,它也是人們可讀的目標(biāo)代碼。

一個(gè)類文件中的元素
javap 被用來反匯編或解包一個(gè)類文件。這里簡(jiǎn)要列出了可以通過使用 javap 進(jìn)行反匯編的 Java 類文件所包含的信息:

成員變量。每個(gè)類文件中包含了對(duì)應(yīng)于該類每個(gè)數(shù)據(jù)成員的所有名稱信息和類型信息。


經(jīng)過反匯編后的方法。類的每一個(gè)方法都是由一串虛擬機(jī)指令來表示的,并附帶它的類型簽名。


行號(hào)。每個(gè)方法中的每個(gè)節(jié)被映射到源代碼行,在可能的情況下,源代碼行來生成節(jié)。這使得實(shí)時(shí)系統(tǒng)和調(diào)試器能夠?yàn)樵谶\(yùn)行狀態(tài)的程序提供堆棧跟蹤。


局部變量名一旦方法被編譯了,這個(gè)方法的局部變量就不太需要名稱了,但是能通過對(duì) javac 編譯器使用 -g 選項(xiàng)來包含它們。這也使得實(shí)時(shí)系統(tǒng)和調(diào)試器能幫助您。

既然對(duì) Java 類文件的內(nèi)部情況已有所了解,讓我們看一下如何能轉(zhuǎn)換這些信息來達(dá)到我們的目的。

使用反編譯器
從概念上講,反編譯器使用起來非常簡(jiǎn)單。他就是把編譯器逆過來用:你給它 .class 文件,它還給你一個(gè)源代碼文件。

一些比較新的反編譯器有精致的圖形界面。但在一開始所舉的例子中,我們將使用的是 Mocha,它是第一個(gè)公開的可利用的反編譯器。在本文的最后,我會(huì)討論一下在 GPL 下一個(gè)較新的反編譯器。(請(qǐng)參閱參考資料,下載 Mocha 并獲取 Java 反編譯器的清單。)

讓我們假設(shè)在目錄中有一個(gè)名為 Foo.class 的類文件。用 Mocha 對(duì)它進(jìn)行反編譯非常簡(jiǎn)單,只要鍵入以下命令:


$ java mocha.Decompiler Foo.class




這會(huì)生成一個(gè)新的名為 Foo.mocha 的文件(Mocha 使用 Foo.mocha 這個(gè)名字以避免覆蓋原文件的源代碼)。這個(gè)新文件就是 Java 的源文件,并且假設(shè)一切順利的話,您現(xiàn)在就能正常地編譯它。只需把它重命名為 Foo.java 就可以開始了。

但是這兒有個(gè)問題:假如在一些您已經(jīng)有所改動(dòng)的代碼上運(yùn)行 Mocha,您會(huì)注重到它生成的代碼和源代碼不是完全一樣的。我舉個(gè)例子,這樣您能明白我的意思。清單 3 所示的原始源代碼是來自一個(gè)名為 Foo.java 的測(cè)試程序。

清單 3. Foo.java 的一小部分原始源代碼

private int member = 10;

public Foo() {
int local = returnInteger();
System.out.println( "foo constrUCtor" );
priv( local );
}




以下是 Mocha 生成的代碼

清單 4. Mocha 生成的 Foo.java 的源代碼

private int member;

public Foo()
{
member = 10;
int local = returnInteger();
System.out.println("foo constructor");
priv(local);
}




這兩個(gè)代碼片段的成員變量 member 被初始化為 10 的位置不同。在原始源代碼中,它在與聲明的同一行中被表示為一個(gè)初始值,而在被反編譯后的源代碼中,它在一個(gè)構(gòu)造符中被表示為一條賦值語(yǔ)句。反編譯后的代碼告訴我們一些有關(guān)源代碼被編譯的方法;即它的初始值是作為在構(gòu)造符中的賦值來被編譯的。通過觀察其反編譯后的輸出結(jié)果,您能了解到不少 Java 編譯器的工作方法。

反編譯是困難的:不斷重復(fù)
雖然 Mocha 的確可以反匯編您的目標(biāo)代碼,但它不會(huì)總是成功的。由于困難重重,沒有一個(gè)反編譯器能夠準(zhǔn)確無誤地翻譯出源代碼,而且每個(gè)反編譯器處理它們?cè)诜g過程中的漏洞的方式也不同。舉例來說,Mocha 有時(shí)在輸出準(zhǔn)確的循環(huán)構(gòu)造的結(jié)構(gòu)方面有一些問題。假如真的這樣,它會(huì)在最終輸出中使用偽 goto 語(yǔ)句,如清單 5 所示。

清單 5. Mocha 不能準(zhǔn)確地反編譯

if (i1 == i3) goto 214 else 138;
j3 = getSegment(i3).getZOrder();
if (j1 != 1) goto 177 else 154;
if (j3 > k2 && (!k1 j3 < j2)) goto 203 else 173;
eXPression 0
if (j3 < k2 && (!k1 j3 > j2)) goto 203 else 196;
expression 0
if == goto 201
continue;
i2 = i3;




撇開 Mocha 的問題不談,反編譯器在通常情況下還是能比較準(zhǔn)確地翻譯出源代碼。一旦知道了某一反編譯器的弱點(diǎn),您可以手工分析和轉(zhuǎn)換反編譯后的代碼,以使它們能較準(zhǔn)確地符合原始源代碼。隨著反編譯器正變得越來越出色,我們又碰到了另外一個(gè)問題:假如您不想讓任何人能反編譯您的代碼,那該怎么辦呢?

反編譯和對(duì)安全的威脅
雖然,大部分的代碼反編譯是完全正大光明的,但事實(shí)是一個(gè)優(yōu)秀的反匯編器是軟件侵權(quán)的必需工具之一。正因如此,尤其對(duì)于在商業(yè)和不開放源代碼領(lǐng)域中的開發(fā)人員來說,便宜的(或免費(fèi)的) Java 代碼反匯編工具的存在是一個(gè)嚴(yán)重的問題。

就語(yǔ)言本身而言, 由于其相對(duì)簡(jiǎn)單的 Java 虛擬機(jī)(與真實(shí)的微處理器相比)和其寫得很規(guī)范的字節(jié)碼格式, Java 代碼非常輕易反匯編。而這隨著 Java 語(yǔ)言在 Web 開發(fā)平臺(tái)上的日益普及,已經(jīng)在商業(yè)開發(fā)領(lǐng)域引起了很多爭(zhēng)議。自從 Mocha 于 1996 年首次發(fā)布以來,一些在保護(hù)它們的源代碼方面有過投資的公司和個(gè)人一直在為 Java 反編譯器大吵大鬧。

實(shí)際上,當(dāng) Mocha 第一次發(fā)布時(shí),它的作者 Hanpeter van Vliet 曾被一些公司的訴訟威脅過(請(qǐng)參閱參考資料)。起初,他把反編譯器從他的網(wǎng)站上移去,但是他后來以 Crema 的形式提供了一個(gè)更好的解決方案。Crema 是一個(gè) Java 模糊處理器,它完全對(duì)立于 Mocha。

自 Crema 發(fā)布以來,許多 Java 模糊處理器開始出現(xiàn),其中一些是商業(yè)的,也有一些是開放源代碼的。正如您看到的那樣,一個(gè)好的 Java 模糊處理器可以在很大程度上保護(hù)您的 Java 代碼。

針鋒相對(duì)的代碼模糊處理
代碼模糊處理字面上的意思就是模糊處理您代碼的行為。Java 模糊處理器用不易察覺的方法改變程序,以致于它的運(yùn)行對(duì) JVM 來說是一模一樣的,但它使得試圖理解程序的人更加迷惑了。

讓我們看一下當(dāng)反匯編器碰到經(jīng)過模糊處理后的代碼會(huì)發(fā)生什么情況。清單 6 顯示了 Mocha 在嘗試反匯編被一種名為 jmangle 的工具模糊處理的 Java 代碼后的結(jié)果。請(qǐng)注重以下的一小段程序和我們?cè)谇懊媲鍐沃惺褂玫氖窍嗤?,盡管乍一看,您肯定不會(huì)這么認(rèn)為。

清單 6. 經(jīng)過 jmangle 模糊處理的代碼
public Foo()
{
jm2 = 10;
int i = jm0();
System.out.println("foo constructor");
jm1(i);
}




象 jmangle 這樣的模糊處理器把許多變量名和方法名(有時(shí)甚至是類名和包的名稱)轉(zhuǎn)換成沒有意義的字符串。這樣就使得人們難以閱讀程序,但對(duì)于 JVM 來說,其在本質(zhì)上和原來的程序是一樣的。

變得卑鄙
所有的模糊處理器都要使標(biāo)記變得沒有意義,但他們所做的不僅僅是這些。Crema 之所以臭名昭著是因?yàn)樗昧嗽S多卑鄙的手段來阻止反匯編,并且有許多在已經(jīng)出現(xiàn)的模糊處理器中,紛紛仿效它。

一種常用的模糊處理代碼的方法是用一個(gè)非法的字符串來替代類文件中的標(biāo)記,這比使用沒有意義的字符串更進(jìn)了一步。替代的有可能是一個(gè)要害字,例如 private,或者甚至是象 *** 這樣沒有意義的標(biāo)記。一些虛擬機(jī) -- 尤其在瀏覽器中 -- 對(duì)這些古怪的用法不會(huì)作出合法的反應(yīng)。從技術(shù)上說,一個(gè)象 = 這樣的變量與 Java 的規(guī)范是相反的;一些虛擬機(jī)可以忽略它,而另一些不可以這樣。

Crema 放置炸彈
按字面意思,Crema 使用的另一個(gè)計(jì)策就是炸彈。Crema 具有完全關(guān)閉 Mocha 的能力。它在編譯后的代碼中添加一個(gè)小“炸彈”,導(dǎo)致 Mocha 在試圖反編譯代碼時(shí)崩潰。

可惜,Crema 已經(jīng)沒有了,但有一種名為 HoseMocha 的工具是專門為關(guān)閉 Mocha 而設(shè)計(jì)的。為了了解 HoseMocha 是如何工作的,我們將使用 javap,這個(gè)值得信賴的反匯編器。清單 7 所示的是 HoseMocha 放置炸彈前的代碼。

清單 7. 放置炸彈前的代碼
Method void main(java.lang.String[])
0 new #4
3 invokespecial #10
6 return




以下是 HoseMocha 處理后的代碼。

清單 8. 放置炸彈后的代碼
Method void main(java.lang.String[])
0 new #4
3 invokespecial #10
6 return
7 pop




您看到那顆炸彈嗎?請(qǐng)注重現(xiàn)在這個(gè)程序在返回后面有一條 pop 語(yǔ)句。等一下 -- 一個(gè)函數(shù)在返回之后還能做什么嗎?很顯然,它不能,而這就是要害所在。在返回語(yǔ)句后放一條指令確保了它不會(huì)被執(zhí)行。您這兒所見的是根本不可能被反匯編的。因?yàn)樗鼪]有對(duì)應(yīng)任何可能的 Java 源代碼,所以也就沒有任何意義。

但為什么這一個(gè)小小的障礙就能導(dǎo)致 Mocha 崩潰呢? Mocha 可以只是簡(jiǎn)單地忽略它,或發(fā)一條警告信息并繼續(xù)下去。盡管 Mocha 對(duì)于此類炸彈的脆弱性可以被認(rèn)為是一個(gè)程序錯(cuò)誤,但更有可能的是 van Vliet 為了回應(yīng)對(duì) Mocha 的攻擊而故意設(shè)置的。

到此為止,我們已經(jīng)了解了較老的反匯編工具和模糊處理工具 -- 雖然有點(diǎn)過時(shí),但還是比較出色的。但是,類似工具在這幾年已經(jīng)變得更加成熟,尤其在圖形界面方面更是如此。在本文的最后,我們看一下一個(gè)較新的反匯編器,僅僅讓您有個(gè)大致的概念。

這一領(lǐng)域的新成員
在過去的五年中,不僅僅是反匯編和模糊處理的技術(shù)越來越復(fù)雜,而且這些工具的界面也更加華麗。在最近出現(xiàn)的反匯編器中,有幾個(gè)能讓您瀏覽 .class 文件的目錄并且只要單擊一下,就能對(duì)它們進(jìn)行反匯編。

JODE (Java 優(yōu)化和反編譯環(huán)境)就是這樣一個(gè)程序。在命令行中鍵入 .jar 文件的名稱, JODE 就會(huì)答應(yīng)您圖形化地瀏覽它的類,并自動(dòng)反匯編每個(gè)類以讓您查看。這非凡有助于通過 Java SDK 提供的庫(kù)來查找源代碼。簡(jiǎn)單地鍵入以下命令:


$ java jode.swingui.Main --classpath [path to your Java SDK]/jre/lib/rt.jar




您就會(huì)得到如圖 1 所示的對(duì)文件的完整翻譯。

圖 1. JODE: 一種反匯編器
http://www-900.ibm.com/developerWorks/cn/java/j-obfus/jode.gif

請(qǐng)參閱參考資料,獲取更有用的工具的清單。

結(jié)論
無論選擇使用象 Mocha 或 HoseMocha 這樣的經(jīng)典工具,還是樂于親自研究一下更新的工具,您都應(yīng)把這篇文章作為您學(xué)習(xí) Java 反匯編和模糊處理的起點(diǎn)。在此,請(qǐng)瀏覽一下在參考資料中所提供的許多鏈接,試著使用其中的一些工具,并預(yù)備以后不斷磨練自己的技術(shù)。盡管有許多爭(zhēng)議,反匯編和模糊處理的技術(shù)如今依然存在,并且在今后的幾年中只會(huì)變得更加成熟和完善。

Resources

雖然 Mocha 已經(jīng)過時(shí),但使用起來要比較有趣,而且偶然會(huì)有一些用處。


正如在它之前的 Crema,HoseMocha 制造一個(gè)阻止 Mocha 工作的炸彈。


Borland 的 JBuilder 據(jù)說是基于原來 Crema 的代碼。


請(qǐng)查看 jmangle。


SourceForge 如今擁有 JODE,它可以在 GPL 下獲得。


WingDis 是另一個(gè)流行的商業(yè)反編譯器。


Blackdown 列出了許多在 linux 上的 Java 開發(fā)工具,包括 JAD、它被認(rèn)為是“最快的 Java 反匯編器”。


Zelix KlassMaster 是一個(gè)作為模糊處理器工作的商業(yè)類文件查看工具。


Marc Meurrens 的 Java 代碼工程是一個(gè)出色的網(wǎng)站,涵蓋了匯編器、反匯編器、模糊處理器及相關(guān)信息。


反匯編和反匯編器是另一個(gè)包羅萬象的頁(yè)面,有許多軟件和研究論文的有用鏈接。


Cristina Cifuentes 維護(hù)著反匯編頁(yè)面,有許多有關(guān)反匯編的理論和實(shí)際工作的信息,包括一個(gè)名為 dcc 的 C 反匯編器。


已故的 Maurice Halstead 被許多人認(rèn)為是反匯編之父。請(qǐng)閱讀有關(guān)他從 1960 年至 1976 年領(lǐng)導(dǎo)的反匯編項(xiàng)目的信息。


請(qǐng)參閱“Java 反編譯器比較”(JavaWorld,1997 年 7 月),這里有對(duì) Java 反匯編器的大范圍回顧。


請(qǐng)閱讀 Hanpeter van Vliet 的原始反匯編器宣言 (Web Techniques,1997 年 9 月)。


IBM 蘇黎世研究實(shí)驗(yàn)室在安全性和 Java 加密技術(shù)上投入了大量資源。


請(qǐng)閱讀 IBM 是如何研究 Java 安全性和分布式目標(biāo)系統(tǒng)。


在 “讓您的軟件運(yùn)行:模糊安全性” (developerWorks,2000 年 10 月)中,作者 Gary McGraw 和 John Viega 討論了試圖在運(yùn)行軟件時(shí)實(shí)現(xiàn)保密。


請(qǐng)不要錯(cuò)過 developerWorks 在這重要領(lǐng)域的安全性專題。


McGraw 和 Felten 的經(jīng)典著作 Securing Java, 2nd Edition (John Wiley & Sons, 1999)的第 6 章有關(guān)于 Java 反匯編器的更多信息。



關(guān)于作者
Greg Travis 是一名居住在紐約的自由程序員。他對(duì)計(jì)算機(jī)的愛好可以追溯到 "The Bionic Woman" 中的這樣一段情節(jié),Jamie 試圖逃離一幢其燈光和門都被邪惡的人工智能所控制的大樓,而且人工智能還通過擴(kuò)音器嘲弄她。Greg 堅(jiān)定地認(rèn)為當(dāng)計(jì)算機(jī)程序工作時(shí),它是完全一致的。可通過 mito@panix.com 聯(lián)系 Greg。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 乐陵市| 沙洋县| 烟台市| 尤溪县| 贵阳市| 德昌县| 龙游县| 朝阳市| 双鸭山市| 龙胜| 田阳县| 丰顺县| 临高县| 龙泉市| 平潭县| 新宁县| 古蔺县| 启东市| 临澧县| 丰镇市| 长治县| 阿尔山市| 临江市| 榆中县| 卢湾区| 漠河县| 常州市| 桃江县| 汶川县| 麦盖提县| 河东区| 凉城县| 忻城县| 通海县| 瑞安市| 焦作市| 瑞安市| 玉龙| 宜春市| 岳阳市| 夏河县|