轉貼:“金山詞霸”螢幕取詞技術揭密(討論稿) (17千字)
“金山詞霸”螢幕取詞技術揭密(討論稿)
主題 螢幕取詞技術系列講座(一)
作者 亦東
很多人對這個問題感興趣。
原因是這項技術讓人感覺很神奇,也很有商業價值。
現在詞典市場金山詞霸佔了絕對優勢,所以再做字典也沒什麼前途了。我就是這麼認為的,所以我雖然掌握了這項技術,卻沒去做字典軟體。只做了一個和詞霸相似的軟體自己用,本來想拿出來做共享軟體,但我的詞庫是“偷”來的,而且詞彙不多,所以也就算了,詞庫太小,只能取詞有什麼用呢?而且詞霸有共享版的。
但既然很多人想了解這項技術,我也不會保留。我準備分多次講述這項技術的所有細節。
大約每週一兩次。想知道的人就常常來看看吧!
一.基礎知識
首先想編這種程式需要一些基礎知識。
會用Vc++,包括16/32位。
精通Windows API特別是GDI,KERNEL部分。
懂組合語言,會用softice除錯程式,因為這種程式最好用softice除錯。
二.基本原理
在Window 3.x時代,windows系統提供的字元輸出函式只有很少的幾個。
TextOut
ExtTextOut
DrawText
......
其中DrawText最終是用ExtTextOut實現的。
所以Windows的所有字元輸出都是由呼叫TextOut和ExtTextOut實現的。因此,如果你可以修改這兩個函式的入口,讓程式先呼叫你自己的一個函式再呼叫系統的字元輸出,你就可以得到Windows所有輸出的字元了。
到了Windows95時代,原理基本沒變,但是95比3.x要複雜。開始的時候,一些在windows3.x下編寫的取詞軟體仍然可以是使用。但是後來出了個IE4,結果很多詞典軟體就因為不支援IE4而被淘汰了,但同時也給一些軟體創造了機會,如金山詞霸。其實IE4的問題並不複雜,只不過它的輸出的是unicode字元,是用TextOutW和ExtTextOutW輸出的。知道了這一點,只要也擷取就可以了。不過實現方法複雜一點,以後會有詳細講解。現在又出了個IE5,結果詞霸也不好用了,微軟真是#^@#$%$*&^&#@#@..........
我研究後找到了一種解決辦法,但還有些問題,有時會取錯,正在繼續研究,希望大家共同探討。
另外還有WindowsNT,原理也是一樣,只是實現方法和95下完全不同。
三.技術要點
要實現取詞,主要要解決以下技術問題。
1.擷取API入口,獲得API的引數。
2.安全地潛入Windows內部,良好地相容Windows的各個版本
3.計算滑鼠所在的單詞和字母。
4.如果你在Window95下,做32位程式,還涉及Windows32/16混合程式設計的技術。
今天先到這裡吧!最好準備一份softice for 95/98和金山詞霸,讓我們先來分析一下別人是怎麼做的。
歡迎與我聯絡
E-Mail:yeedong@163.net
Guest 1999-04-30 16:00:48
請問用VC自己的DEBUGGER不行嗎?為什麼要用SOFTICE? 我沒用過SOFTICE,它有什麼特別之處嗎?
葫蘆 1999-04-30 19:15:03
本人對這個問題也有興趣,以前研究過16位版本截獲TextOut和ExtTextOut的過程;
但對金山詞霸,用Softice跟蹤,發現SetWindowsHookEx在程式裝載時就安裝了滑鼠鉤子,暫停取字/恢復取字只是設定的內部變數,但本人發現金山詞霸並沒有象16位版本那樣修改TextOut和ExtTextOut。
蒼蠅 (555021552) 1999-05-02 08:56:57
有哪位大蝦願意先介紹一下SOFTICE?
蟑螂 1999-05-04 13:58:22
把金山詞霸的cjktl95.dll用tdump分析可以看到它根本用的不是hook,而是用了一些kernel32.dll中的Win32 SDK裡沒有包含的函式,使用這些函式來替換改寫原先的幾個GDI函式。看來是Win95未公開的一些東西。有些人知道,為什麼不肯說出來呢?未必見得多麼高深!
葫蘆 1999-05-05 23:28:07
你可能沒有研究過它的目的碼,怎麼能斷言沒有使用hook呢? 其實金山詞霸一執行就安裝了滑鼠鉤子。
亦東 1999-05-07 09:52:42
未必見得多麼高深?
你知道有些人是怎麼知道這些Win95未公開的東西的嗎?你不會是以為微軟偷偷告訴他們的吧?其實他們大多和我一樣是用softice自己跟蹤Win95跟出來的。
還有你從cjktl95.dll裡tdump出的未公開函式和hook無關,那是做別的用的。
setwindowshook在user裡
亦東 1999-05-10 16:16:14
從cjktl95.dll裡tdump出的未公開函式和32位和16位之間的互調有關。
主題 螢幕取詞技術系列講座(二)
作者 亦東
很抱歉讓大家久等了!
我看了一些人的回帖,發現很多人對取詞的原理還是不太清楚。
首先我來解釋一下hook問題。詞霸中的確用到了hook,而且他用了兩種hook其中一種是Windows標準hook,透過SetWindowHook安裝一個回撥函式,它安裝了一個滑鼠hook,是為了可以及時響應滑鼠的訊息用的和取詞沒太大關係。
另一種鉤子是API鉤子,這才是取詞的核心技術所在。他在TextOut等函式的開頭寫了一個jmp語句,跳轉到自己的程式碼裡。
你用softice看不到這個跳轉語句是因為它只在取詞的一瞬間才存在,平時是沒有的。
你可以在TextOut開頭設一個讀寫斷點
bpm textout
再取詞,就會找到詞霸用來寫鉤子的程式碼了。
/**********************************
所以我在次強調,想學這種技術一定要懂組合語言和熟練使用softice.
**********************************/
至於從cjktl95中dump出來的未公開函式是和Windows32/16混合程式設計有關的,以後我會提到他們。
我先來講述取詞的過程,
0 判斷滑鼠是否在一個地方停留了一段時間
1 取得滑鼠當前位置
2 以滑鼠位置為中心生成一個矩形
3 掛上API鉤子
4 讓這個矩形產生重畫訊息
5 在鉤子裡等輸出字元
6 計算滑鼠在哪個單詞上面,把這個單詞儲存下來
7 如果得到單詞則摘掉API鉤子,在一段時間後,無論是否得到單詞都摘掉API鉤子
8 用單詞查詞庫,顯示解釋框。
很多步驟實現起來都有一些難度,所以在中國可以做一個完善的取詞詞典的人屈指可數。
其中0,1,2,7,8比較簡單就不提了。
先說如何掛鉤子:
所謂鉤子其實就是在WindowsAPI入口寫一個JMP XXXX:XXXX語句,跳轉到自己的程式碼裡。
步驟如下:
1.取得Windows API入口,用GetProcAddress實現
2.儲存API入口的前五個位元組,因為JMP是0xEA,地址是4個位元組
3.寫入跳轉語句
這步最複雜
Windows的程式碼段本來是不可以寫的,但是Microsoft給自己留了個後門。
有一個未公開函式是AllocCsToDsAlias,
UINT WINAPI ALLOCCSTODSALIAS(UINT);
你可以取到這個函式的入口,把API的程式碼段的選擇符(要是不知道什麼是選擇符,就先去學學保護模式程式設計吧)傳給他,他會返回一個可寫的資料段選擇符。這個選擇符用完要釋放的。用新選擇符和API入口的偏移量合成一個指標就可以寫windows的程式碼段了。
這就是取詞技術的最核心的東東,不止取詞,連外掛中文平臺全屏漢化都是使用的這種技術。現在知道為什麼這麼簡單的幾句話卻很少知道了吧?因為太多的產品使用他,太多的公司靠他賺錢了。
這些公司和產品有:中文之星,四通利方,南極星,金山詞霸,實達銘泰的東方快車,roboword,譯典通,即時漢化專家等等等等。。。。還有至少20多家小公司。他們的具體實現雖然不同,但大致原理是相同的。
我這些都是隨手寫的,也沒有提綱之類的東西,以後如果有機會我會整理一下,大家先湊合著看吧!xixi...
葫蘆 1999-05-06 14:52:30
你說的這個技術是16位的,至少金山詞霸III沒有采用16位的AllocCsToDsAlias函式,也根本沒有修改TextOut開始的語句為JMP XXXXXXXX。softice本人非常精通,是絕對不會錯的!
葫蘆 1999-05-06 15:38:40
誰假冒吾名,壞吾名聲?!本人在此鄭重宣佈,以上貼子非本人所發!
經過跟蹤分析,金山詞霸III確實修改了TextOut的入口為轉跳到自身程式碼的JMP XXXXXXXX語句,只是修改沒有呼叫AllocCsToDsAlias,也不是在取字時才去修改,而是常常修改(估計是在Timer中進行的)。
亦東 1999-05-06 17:25:23
我說過詞霸裡用AllocCsToDsAlias了嗎?
我是說AllocCsToDsAlias,的確可以用,但詞霸裡是用DPMI的Int 31做的,其實本質是一樣的,你用softice跟一下就知道了
bpint 31 設一箇中斷斷點。
實際上我至少有五種方法寫Windows程式碼段
我介紹使用AllocCsToDsAlias是因為這種方法最簡單,其他方法要麻煩得多。
詞霸用int 31來做是出於相容性的考慮,
AllocCsToDsAlias畢竟不是公開函式,但DPMI卻是標準。
詞霸在你滑鼠在某一點停留超過200ms時就會取詞,所以他有一個定時器,會經常修改API入口。
看來“假”葫蘆只是自以為非常精通softice.
mao 1999-05-06 19:29:28
在微軟的MSDN中有一個程式,包含了全部的Source code, 名字好象叫"Inject" 或 stealth什麼的,忘了。提供了一個很完善的hook任何一個windows函式的功能。對win16完全適用,在win95下也有用,但NT下不行。
建議大家去找找這個例子看看會很有幫助。
此外有本清華出的微軟的Advanced Windows也介紹了具體的方法。
建議亦東干脆把source code給open出來,讓有興趣的朋友用起來更方便,把取詞技術可發展的應用發揚光大!
亦東 1999-05-07 09:40:56
我不主張“把取詞技術可發展的應用發揚光大”,這也是我掌握了這項技術一年多才公開它的原因。我公開它並不是想讓大家都來做字典軟體,相反我希望不要再有人做字典了,現在做字典的人已經太多了。看到某種軟體有利可圖,大家就一哄而上,這種惡性競爭對中國軟體業的發展是極其有害的。我公開他的目的是希望提高大家的程式設計水平。你會發現在研究這項技術的過程中你的程式設計水平和對Windows的理解程度會有質的飛躍,我本人就從中獲益匪淺。
MSDN中是有這樣的程式碼。
甚至有一個叫ProcHook.Dll,提供SetProcAddress之類的函式,但是沒有原始碼。原始碼在1994年的 MSJ 上很難弄到的。
原始碼我會分幾次公開,每次會有詳細的說明。
想要原始碼的人,準備一份VC++1.52或Borland C++,最好還有softice,下次我會給出一段程式碼,教你如何修改Windows的程式碼。
老冒 (555036) 1999-05-07 11:56:46
如果認為螢幕取詞的應用就是做字典,就大錯特錯了。其實關於攔劫windows api的東東早就在93年的Undocument Windows上公開過了。
其實Adobe的Adobe Type Manager在Windows 3.0的時代就透過這種辦法實現了漂亮的字型. (現在有TTF不需要ATM了)
MSDN上的那個東東是有全部source和sample, 我抓下來編譯過。是1996年夏天的一張MSDN Level 2光碟上的,現在也不知擱哪裡了,有興趣的朋友自己找去吧。
還是open 完整的source好,很多朋友其實只要用這項技術,並不太想知道細節,不是嗎.
亦東 1999-05-07 13:28:19
這種技術不是做字典全屏漢化就是外掛語言平臺,自從王志東使用它以來,就沒用來編過其他軟體,也許有但我不知道。
原來有那麼多書和其他資料上都有這種技術的資料還有例子,到是我孤陋寡聞了,以為大家都不知道,在這裡給大家講一些眾所周知的東西。回去我要好好研究一下,看看Rasir
Dex的詞霸是從那裡抄的。
我不知道某項技術中細節是不是重要,如果很多人只想用而不想自己編,那麼樓下那50多個回帖是怎麼回是?
老冒 1999-05-07 13:54:18
呵呵,你可千萬要堅持把講座做下去,否則那50多個回應的哥們企不要把我給痛扁了...:)
俺已兩年多不碰底層技術的,這方面很落後啦...俺可應付不了這麼多熱切的求知朋友,亦東要頂住呵!
歡迎和俺多多交流探導!
P.S. 亦東大俠目前何方高就? 正在忙什麼專案?交流交流
亦東 1999-05-07 17:46:06
沒什麼正經事做,到處瞎混呢!
葫蘆 1999-05-08 21:50:29
我對此持否定觀點,不要自作聰明,以為AllocCsToDsAlias就是能用的,其實AllocCsToDsAlias只是16位的Windows用的函式,32位的Win95程式不能使用此函式,不信你在VC
5.0或6.0中可以試試。
另外,int 31h也不是說能用就能拿來用的,在Windows 3.x下使用是沒有問題的(本人還有這方面的文章發表),但在Win95下隨意使用會產生GP錯,主要原因是32位並不支援DPMI直接呼叫,不知亦東先生對此有沒有研究,就在此發表諸多理論!本人就先請問:32位程式如何呼叫16位函式或動態庫你懂不懂?
葫蘆 1999-05-09 02:39:10
上面的這個帖子並沒有攻擊誰的意思,只是希望大家探討問題都要本著認真的態度,不要不懂裝懂,至少有一點大家要清楚:32位的程式根本不能使用 int 31h,呼叫16位的動態庫Kernel中的AllocCsToDsAlias也並不是件簡單的事。
nn_zdm (555031742) 1999-05-09 16:35:35
使用hook函式,可用的功能並非只是做字典全屏漢化和外掛語言平臺。使用hook可以除錯程式,就象你們說的softice其本身也是使用了hook函式。
nn_zdm (555031742) 1999-05-09 16:42:05
另外hook函式還可以使用在遊戲修改工具中,本人就開發過此類工具。《整人專家》估計也是使用這種方法。當然還有另外兩種方法。
亦東 1999-05-10 16:10:59
你們說的都有道理。
但hook有兩種,一種是Windows標準鉤子,透過SetWindowshook掛。
另一種是非標準的,透過在API入口寫JMP XXXXXXXX來實現的。
softice的鉤子更高階,他都掛到VXD上了。
從32為程式碼呼叫16位DLL碰巧我會。
打倒米D國主義!!!
瓜果 1999-05-10 17:07:00
誰知道在哪能搞到SOFTICE,我以前從未用過它!
葫蘆 1999-05-10 21:39:46
願繼續拜讀你以後的講座。
SOFTICE嗎?光碟上很多,有for DOS, for Windows95, for Windows NT 各個版本。
孫瑋 (555031339) 1999-05-11 11:08:35
能否將 si for NT 上傳到 10.82.46.33
(使用 ftp) user: haotao
pass: haotao123
tommy 1999-05-11 11:34:11
http://www.swww.com.cn/htm/down/others/main.html 可以下載
亦東 1999-05-11 14:01:19
最近忙於反美,暫時沒時間再寫了,過些時間才行,下次我會給出原始碼。
最新訊息,美國海軍被黑了。
http://www.nctsw.navy.mil/
打倒米D國主義!!!
黃金獅子 1999-05-12 13:19:32
我對各位大蝦的討論深感興趣。
有幾個問題想請教:
1.AllocCsToDsAlias 在32-bit下呼叫是否採用Thunk?
2.32-bit 下是否有類似function?
3.Jeffrey Richter的"Advanced Windows"裡Remote Thread 的Thread Stack來遠端注入DLL函式,因此不需上述Function.
4.我有MSJ 1994-1的ProcHook.dll的source code,不知用於WinNT需如何改動.
5.總而言之,有無WinNT下hook API的source code,請告知.
(我還有Softice 3.24 for Win95, 3.25 for WinNT.)
--這個主題很好
鼴鼠 1999-05-14 09:41:20
請大蝦給我發一份MSJ 1994-1的ProcHool.dll的source code, 我現在急需這方面的資料。謝謝!!
Email Address: yanshg@263.net
下面是一個Australia人的API hook軟體, 它是基於VxD技術。
Molten Home Page:
http://ourworld.compuserve.com/homepages/molten
黃金獅子 1999-05-14 14:34:54
在Win95和NT上,可透過WriteProcessMemory()直接寫Code Segment.(原來以為"advanced Windows" 調CreateRemoteThread(),是因為WriteProcessMemory()只能寫程式碼段和堆疊段)
阿濤 1999-05-14 19:45:05
如何亦東老兄要分步公佈是PROCHOOK的程式碼就不必了,這個程式的程式碼很容易搞到,只須到MSJ的站點上查一下就可找到。
亦東 1999-05-14 21:44:39
大家到msj的大海里去撈針好了。
在95你WriteProcessMemory 寫kernel user gdi試試,一定失敗。
調CreateRemoteThread並不是為了寫程式碼段,有別的用途,是為了在其他程式裡分配記憶體。回去再好好看看“advanced Windows" 最好用一個程式試試,你就明白了。
其實在NT4.0調CreateRemoteThread是沒必要的,這是為了相容NT3.51.
nn_zdm (555031742) 1999-05-18 13:57:48
利用CreateRemoteThread()函式,在WinNT4.0中使用很有用,它是在winNT中闖過程式邊界的三種辦法之一,在WinNT中,使用它可以進行遠端除錯,及修改他人程式碼.
nn_zdm (555031742) 1999-05-18 14:07:17
在winNT中用WriteProcessMemory()寫code
程式碼是可以的,win95沒試過,但MSDN上說是可以的.不過,可能沒什麼用,因為CreateRemoteThread()函式只在winNT中有用.
如:
WriteProcessMemory(...,"LoadLibrary(...,"mydll.dll",..).
CreateRemoteThread(...)
nn_zdm (555031742) 1999-05-18 14:14:19
上面寫漏了,應是
WriteProcessMemory(...,"LoadLibrary(...,"mydll.dll",..). ");
CreateRemoteThread(...) ;
主題 關於螢幕取詞的討論(三)
作者 亦東
讓大家久等,很抱歉,前些時候工作忙硬碟又壞了,太不幸了。
這回來點真格的。
我們們以擷取TextOut為例。
下面是程式碼:
//擷取TextOut
typedef UINT (WINAPI* ALLOCCSTODSALIAS)(UINT);
ALLOCCSTODSALIAS AllocCsToDsAlias;
BYTE NewValue[5];//儲存新的入口程式碼
BYTE OldValue[5];//API原來的入口程式碼
unsigned char * Address=NULL;//可寫的API入口地址
UINT DsSelector=NULL;//指向API入口的可寫的選擇符
WORD OffSetEntry=NULL;//API的偏移量
BOOL bHookAlready = FALSE; //是否掛鉤子的標誌
BOOL InitHook()
{
HMODULE hKernel,hGdi;
hKernel = GetModuleHandle("Kernel");
if(hKernel==NULL)
return FALSE;
AllocCsToDsAlias = (ALLOCCSTODSALIAS)GetProcAddress(hKernel,"AllocCsToDsAlias");//這是未公開的API所以要這樣取地址
if(AllocCsToDsAlias==NULL)
return FALSE;
hGdi = GetModuleHandle("Gdi");
if(hmGdi==NULL)
return FALSE;
FARPROC Entry = GetProcAddress(hGdi,"TextOut");
if(Entry==NULL)
return FALSE;
OffSetEntry = (WORD)(FP_OFF(Entry));//取得API程式碼段的選擇符
DsSelector = AllocCsToDsAlias(FP_SEG(Entry));//分配一個等同的可寫的選擇符
Address = (unsigned char*)MK_FP(DsSelector,OffSetEntry);//合成地址
NewValue[0]=0xEA;
*((DWORD*)(NewValue+1)) = (DWORD)MyTextOut;
OldValue[0]=Address[0];
*((DWORD*)(OldValue+1)) = *((DWORD*)(Address+1));
}
BOOL ClearHook()
{
if(bHookAlready)
HookOff();
FreeSelector(DsSelector);
}
BOOL HookOn()
{
if(!bHookAlready){
for(int i=0;i<5;i++){
Address[i]=NewValue[i];
}
bHookAlready=TRUE;
}
}
BOOL HookOff()
{
if(bHookAlready){
for(int i=0;i<5;i++){
Address[i]=OldValue[i];
}
bHookAlready=FALSE;
}
}
//鉤子函式,一定要和API有相同的引數和宣告
BOOL WINAPI MyTextOut(HDC hdc,int nXStart,int nYStart,LPCSTR lpszString,UINT
cbString)
{
BOOL ret;
HookOff();
ret = TextOut(hdc,nXStart,nYStart,lpszString,cbString);//調原來的TextOut
HookOn();
return ret;
}
上面的程式碼是一個最簡單的掛API鉤子的例子,我要提醒大家的是,這段程式碼是我憑記憶寫的,我以前的程式碼丟了,我沒有編譯測試過
因為我沒有VC++1.52.所以程式碼可能會有錯。
建議使用Borland c++,按16位編譯。
如果用VC++1.52,則要改個選項
在VC++1.52的Option裡,有個記憶體模式的設定,選大模式,和"DS!=SS DS Load on Function entry.",切記,否則會系統崩潰。
有什麼不明白的可以給我寫信
yeedong@163.net
Guest 1999-05-21 22:20:47
你這是16為的地址存取模式吧
你看這個MK_FP,win32不用了,
而且GetProcAddress(hKernel,"AllocCsToDsAlias")
這個API有用嗎?
sorry
Guest 1999-05-21 22:31:47
亦東,想請教一個問題,
win32下,每個process有
自己的地址空間,process
A得到process B 的一個視窗C的handle,這個
handle的值 等於process B自己得到的window C 的handle值 嗎?
我想應該不相等,但系統是如何轉換的呢?(比如process A 向
window C 發訊息,系統如何
知道process A 裡的handle 和process B 裡的
handle 都是指的window C)
. 是不是用duplicatehandle()?
(宣告,我是真的不知道
相關文章
- 金山詞霸取詞pdf檔案問題2010-03-08
- 螢幕取詞核心內幕 (轉)2007-12-03
- 滑鼠螢幕取詞技術的原理和實現 (轉)2007-12-25
- 滑鼠螢幕取詞 原理 (轉)2007-12-07
- 金山詞霸網路版2017-11-15
- 螢幕取詞技術實現原理與關鍵原始碼2018-01-17原始碼
- 金山詞霸網路版薦2009-05-21
- 金山詞霸在IE呼叫的PDF檔案取詞問題(摘自sothic)2010-12-06
- 讓金山詞霸在Acrobat Reader最新版中取詞 (491字)2001-01-15BAT
- 有道雲詞典--翻譯/螢幕取詞翻譯2020-12-12
- js劃詞翻譯、螢幕取詞,取詞位置獲取(真正解決定位問題)2021-01-03JS
- 中文搜尋引擎技術揭密:中文分詞2020-04-05中文分詞
- 金山詞霸企業版VS谷歌版2008-08-14谷歌
- linux系統下可以螢幕取詞的詞典安裝2014-05-05Linux
- 安裝金山詞霸20072008-04-14
- [技術討論]網路交流模式的變遷——概要稿2009-09-22模式
- IT技術新名詞2010-08-15
- 中文分詞技術2020-09-18中文分詞
- Wine 的安裝和配置,以及wine下執行金山詞霸和中文輸入法!(轉)2007-08-09
- 金山愛詞霸網站被掛馬上網學英語需注意2019-05-14網站
- 金山詞霸2009牛津with SP3完全破解版(含全部本地詞庫和語音包)2012-04-16
- 技術名詞解釋2018-03-29
- 花旗隊分詞技術2012-05-07分詞
- 卡巴斯基和金山詞霸衝突的解決辦法(兩種方法)2008-04-12
- [技術討論]需求應該找誰來獲取2008-05-29
- 純技術貼:討論一個現實中的需求的架構2008-12-03架構
- 資訊化技術討論組2007-07-17
- Presentation Prompter for Mac(mac螢幕提詞器) v5.4.2啟用版2023-11-08Mac
- mac螢幕提詞器:Presentation Prompter for Mac v5.4.2啟用版2023-11-30Mac
- [技術討論]關於低耦合開發的討論2012-11-09
- 1.2 分詞技術與演算法2019-11-19分詞演算法
- 語音技術——關鍵詞搜尋2020-09-12
- NLP第3章 中文分詞技術2018-06-25中文分詞
- 技術類書籍中的形容詞2013-01-08
- 技術討論 | 如何利用Microsoft Edge漏洞獲取本地檔案?2018-09-07ROS
- IT新詞 (轉)2007-12-07
- “聲討”高雲的《jQuery技術內幕》2014-04-09jQuery
- “軟體工程版”網友行為守則(討論稿) (轉)2008-05-12軟體工程