線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:4516
推到 Plurk!
推到 Facebook!

Dr.eye , 譯點通 等螢幕抓字技術分析

 
8866
中階會員


發表:27
回覆:147
積分:69
註冊:2002-10-14

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-04-22 09:51:35 IP:61.222.xxx.xxx 未訂閱
我最近利用網路上有關如 Dr.eye 等有螢幕抓字功能的技術文章 , 進行實作 分析與可行性評估 , 結果發現這些文章所提的技術確實是可行的 !!!    於是我利用 VC++ 來實作一個小程式來證明它 , 其方法如下 :    1. 必需利用攔截 API 的方法 , 市面上提到的各種方法似乎都是可行的 . 2. 必需利用 HOOK 的技術 ( 要寫成 DLL 的方式 ) . 3. 此小程式進行了對 TextOut 函數的跟蹤 . 4. 進行文字串的抓取 .    結論 :        此小程式在 Win2000 上的成功率為 80 ~ 90 % ,在 XP 上為        50 ~ 60 左右 ! Win 98, ME 目前不準備實作測試 ! 而成功率        的提高可對攔截函數的總類加以擴大 , 應可再提高一些 ! 而        XP 的成功率偏低有可能是 , XP 的顯示方法函數不是我攔的        所致 ! 以上一些小心得希望對有興趣的網友減少一些時間的        浪費 !                       < >< >
附加檔案:48753_TextEye.zip
bruce0211
版主


發表:157
回覆:668
積分:279
註冊:2002-06-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-04-22 10:45:41 IP:211.21.xxx.xxx 未訂閱
長官    沒有 SourceCode 的程式 , 如何"對有興趣的網友減少一些時間的浪費" 既然也是參考別人的文章 , 提供自己的 SourceCode 應該也不為過 
suda
一般會員


發表:17
回覆:63
積分:16
註冊:2002-05-10

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-04-22 20:37:11 IP:218.175.xxx.xxx 未訂閱
聞得到,看得到,吃不到 啊~~~好餓呀!!!
jackalan
初階會員


發表:20
回覆:88
積分:36
註冊:2003-11-08

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-04-22 20:50:59 IP:218.2.xxx.xxx 未訂閱
KTOP是个学习交流的地方,不是个人成果展示,如果你真的希望帮助别人应该贡献你的代码,否则我不知道你准备如何帮助我们。可能我的看法也有问题,但却是我想说的,如果有什么不对请指教。 你的程式在WIN 9X下根本完全无效,XP下也不能达到50~60的成功率。
qoo1234
版主


發表:256
回覆:1167
積分:659
註冊:2003-02-24

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-04-22 21:16:10 IP:218.163.xxx.xxx 未訂閱
引言: KTOP是???交流的地方,不是?人成果展示,如果你真的希望?助?人????你的代?,否?我不知道你准?如何?助我?。可能我的看法也有??,但?是我想?的,如果有什么不??指教。 你的程式在WIN 9X下根本完全?效,XP下也不能?到50~60的成功率。
請 jackalan 大大 看看版規: 本站十大必刪文章 一、重覆發表有灌水之嫌 二、答非所問或描述不清楚 三、抄襲他人文章或發表而未具名引用,或轉載未得原作者同意之文章 四、涉及人身攻擊或不雅文字 五、涉及政治立場 六、索求原始碼、序號、破解、非法下載連結 七、貼錯版區或主題不明確 八、答題內容明顯抄襲或重覆前答題者內容 九、很明顯的作業問題或不將自己寫的有問題的程式片段貼上而要求答案的 十、站務組保留任何對 K.Top 有不良形響文章刪除與會員停權處分的權利 敬請大家尊重本站的規定,維護本站文章的品質! 網海無涯,學無止境!
8866
中階會員


發表:27
回覆:147
積分:69
註冊:2002-10-14

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-04-23 09:05:19 IP:61.222.xxx.xxx 未訂閱
喔 ! 才一個晚上就有這麼多的不滿 , 真是令我感到意外啊 !!!< >< > 首先我先回答各位的問題 :
japhenchen
高階會員


發表:51
回覆:444
積分:184
註冊:2003-07-23

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-04-23 10:30:42 IP:211.96.xxx.xxx 未訂閱
讓人捐款很好,可是我不喜歡這樣,讓人覺得這個技術還是要用條件交換才能得到,實在我很不以為然~~~~    這不是我自己寫的程式,當然,我目前對這也沒什麼研究,但是,我可以發起這個研究熱,我不希望這項技術,是大陸那里的人的專利!台灣加油唄 以下提供這個畫面取詞的程式範例,這里附上了DELPHI版本的原始程式跟滑鼠HOOK的DLL ,打開BPG,二個全BUILD起來,再執行EXE就可以了~~ http://www.tommstudio.com/newclub30/d_download.asp 藏私の禁止 發表人 - japhenchen 於 2004/04/23 10:33:44
8866
中階會員


發表:27
回覆:147
積分:69
註冊:2002-10-14

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-04-23 10:58:33 IP:61.222.xxx.xxx 未訂閱
1. "實在我很不以為然" ==> 你的這句話也真讓我感到無可奈何 !!! < >< >< > >< >< > >< >< > )
hahalin
版主


發表:295
回覆:1698
積分:823
註冊:2002-04-14

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-04-23 11:12:35 IP:61.222.xxx.xxx 未訂閱
改編自某信用卡廣告詞 得到soure code的代價,1200 贊助公益團體以及交流研究成果,無價 <<以上言論不代表ktop立場,如果疏漏之處懇請指教>>
japhenchen
高階會員


發表:51
回覆:444
積分:184
註冊:2003-07-23

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-04-23 11:28:11 IP:211.96.xxx.xxx 未訂閱
我希望行善之舉是出於自發及內心的善念,而非交換條件,後者的善念,可以很正當,也可能用來害人(像寫病毒、駭客程式),這樣是不是為善行造了業?受這善款的人也受業報,何善之有? 我們都把原始碼公開了,如果善者,自然會付出應該付的報酬,否則領受而不愿還,至少也不會造業啊,只是對不起內心而已 呵。。。多說了~~~~ 希望大家能研究出個所以然來,還能把成果再發揚光大,貢獻給新進學人,才不會對不起眾家前輩的貢獻囉 藏私の禁止
8866
中階會員


發表:27
回覆:147
積分:69
註冊:2002-10-14

發送簡訊給我
#11 引用回覆 回覆 發表時間:2004-04-23 12:03:35 IP:61.222.xxx.xxx 未訂閱
'這樣是不是為善行造了業' ==> 至少可以不用下到 18 層地獄 , 17 層即可 .                              < >< >< > '受這善款的人也受業報,何善之有' ==> 這種說法我不懂 ! 但至少幫造惡 之人減少些罪惡 , 也幫活的人好 過一些 . 想不到我的一時興起 , 竟也能引起眾人的回應 , 實使料未及的啊 ! 忽然也有些許的 '何處惹塵埃' 之覺矣 ! 哈 ... 妙 ... < >< >< >
bruce0211
版主


發表:157
回覆:668
積分:279
註冊:2002-06-13

發送簡訊給我
#12 引用回覆 回覆 發表時間:2004-04-23 16:24:30 IP:211.21.xxx.xxx 未訂閱
還是那句老話 '既然也是參考別人的文章 , 提供自己的 SourceCode 應該也不為過 " 只是說"不為過", 並非硬逼作者交出 SourceCode 至於扯到公益或其它條件交換.... 想太多了....
anpino
版主


發表:31
回覆:477
積分:231
註冊:2003-01-02

發送簡訊給我
#13 引用回覆 回覆 發表時間:2004-04-23 17:15:10 IP:218.32.xxx.xxx 未訂閱
各自有理。 程式源碼在法律上一切權利均屬源碼設計者/所屬公司所有, 包含智財權,著作權,發行權等等。 站在法律上而言,源碼持有者有權力決定分享方式, 是否公開源碼也屬於分享方式之一。 (所謂"分享方式"是指作品公開的範圍。) ------------------------------- 數學系是內功很強(邏輯/分析) 資工系是招式很多(程式技巧) 就像令狐沖
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#14 引用回覆 回覆 發表時間:2004-04-24 01:21:49 IP:61.71.xxx.xxx 未訂閱
請站長把這篇討論鎖起來吧! 我們實在不希望看到這麼好的論譠淪為口水之爭, 謝謝!
bruce0211
版主


發表:157
回覆:668
積分:279
註冊:2002-06-13

發送簡訊給我
#15 引用回覆 回覆 發表時間:2004-04-24 11:42:44 IP:218.164.xxx.xxx 未訂閱
會員發表區沒有提供 SOURCE CODE 的程式一堆 為何只有這篇有點爭議 ??    1.看作者的"說明內容"有點虛晃一招,令人失望之嫌   我早就知道攔截滑鼠要用 HOOK , HOOK 要寫成 DLL....   對我來說 , 這很難以看出這叫做 "心得"    2.jackalan 長官的確太火爆, 我們雖能提出自己的建議,但不能因此認定別人就應該怎樣怎樣 ...    3.我個人認為會員發表區應該只有兩大類的作品, (1).好用的工具發表(不含SOURCE CODE 無所謂),目的只在提供別人沒有或更方便的工具 (2)增進大家技術能力的作品範例或文章,而非蜻蜓點水式的說明 (3)如果只是測試或證明,沒有詳細技術說明的測試證明,不如直接去買一套易點通XP版來玩玩就可證明    4.對事不對人,既然扯到公益,現在社會很喜歡把"公益","法律"掛在嘴上,如果我們內心真的知道並了解真正的公益,那應該了解"取之社會,用之社會"也是一種公益,不是捐錢就叫公益,更不是較別人捐錢自己不捐,就叫支持公益,    有人天天高喊愛台灣,但你問那些在高速公路丟垃圾的人,到處吐槟郎汁的人,他愛不愛台灣.....以上只是看到本案例所延伸的想法,希望不要被認定為口水之爭 .... 回應文章內容 , 8866 長官沒有任何錯誤 , 大家也別再為難 8866 長官了,若大家真的對本篇內容有興趣, 也讓本篇討論不淪為口水之爭, 小弟找到幾個跟本篇相關且有建設性的資料 ,請參考    http://delphi.ktop.com.tw/topic.php?topic_id=22391 http://delphi.ktop.com.tw/topic.php?topic_id=32829 http://delphi.ktop.com.tw/topic.php?topic_id=19936 google 搜尋 "textout hook"     
     攔截 TEXTOUT HOOK 的參考資料
http://groups.google.com/groups?q=textout+hook&hl=en&lr=&ie=UTF-8&oe=UTF8&safe=off&selm=3A1951F2.DDF021B9@hotmail.com&rnum=2    library PigLatinDll;
uses
 Windows,
 SysUtils,
 Classes,
 HookTextUnit in 'HookTextUnit.pas';    function PigLatinWord(s: String): String;
Var start: String; Capitalize, AllCapitals: Boolean; i: Integer;
begin
 Result:=s;
 if length(s)<=1 then exit;
 Capitalize:=IsCharUpper(s[1]);
 AllCapitals:=True;
 for i:=1 to length(s) do begin
   if IsCharLower(s[i]) then begin
     AllCapitals:=False; break;
   end;
 end;
 start:=lowercase(copy(s,1,2));
 if (start[1]<'a') or (start[1]>'z') then exit;
 if (start[1] in ['a','e','i','o','u']) then start:='';
 if (start<>'ch') and (start<>'th') and (start<>'sh') and (start<>'wh')     and (start<>'qu') and (start<>'kn') and (start<>'wr') then
   delete(start,2,1);
 Result:=copy(s,length(start)+1,length(s))+start;
 if start='' then Result:=Result+'yay' else Result:=Result+'ay';
 if AllCapitals then result:=Uppercase(Result) else
 if Capitalize then result[1]:=Upcase(result[1]);
end;    function IntToRoman(n: Integer): String;
Var i, units, tens, hundreds, thousands: Integer;
begin
 If (n>=5000) or (n<=0) then Result:=IntToStr(n) else begin
   thousands:=n div 1000; n:=n mod 1000;
   hundreds:=n div 100; n:=n mod 100;
   tens:=n div 10; n:=n mod 10;
   units:=n;
   Result:='';
   for i:=1 to Thousands do begin
     Result:=Result+'M';
   end;
   Case Hundreds of
     1: Result:=Result+'C';
     2: Result:=Result+'CC';
     3: Result:=Result+'CCC';
     4: Result:=Result+'CD';
     5: Result:=Result+'D';
     6: Result:=Result+'DC';
     7: Result:=Result+'DCC';
     8: Result:=Result+'DCCC';
     9: Result:=Result+'CM';
   end;
   Case Tens of
     1: Result:=Result+'X';
     2: Result:=Result+'XX';
     3: Result:=Result+'XXX';
     4: Result:=Result+'XL';
     5: Result:=Result+'L';
     6: Result:=Result+'LX';
     7: Result:=Result+'LXX';
     8: Result:=Result+'LXXX';
     9: Result:=Result+'XC';
   end;
   Case Units of
     1: Result:=Result+'I';
     2: Result:=Result+'II';
     3: Result:=Result+'III';
     4: Result:=Result+'IV';
     5: Result:=Result+'V';
     6: Result:=Result+'VI';
     7: Result:=Result+'VII';
     8: Result:=Result+'VIII';
     9: Result:=Result+'IX';
   end;
 end;
end;    function LatinNumber(s: String): String;
Var n: Integer;
begin
 try
   n:=StrToInt(s);
   Result:=IntToRoman(n);
 except
   Result:=s;
 end;
end;    function Conv(s: String): String;
Var i: Integer; w: String;
begin
 Result:='';
 try
   if s='' then exit;
   i:=1;
   while (i<=length(s)) do begin
     while (i<=length(s)) and (s[i]<=' ') do begin
       Result:=Result+s[i];
       Inc(i);
     end;         // convert any numbers into latin numbers
     w:='';
     while (i<=length(s)) and (s[i]>='0') and (s[i]<='9') do begin
       w:=w+s[i];
       Inc(i);
     end;
     Result:=Result+LatinNumber(w);         // add any other symbols unchanged (for now)
     w:='';
     while (i<=length(s)) and not IsCharAlphaNumeric(s[i]) do begin
       w:=w+s[i];
       Inc(i);
     end;
     Result:=Result+w;         // convert whole words into pig latin
     w:='';
     while (i<=length(s)) and IsCharAlpha(s[i]) do begin
       w:=w+s[i];
       Inc(i);
     end;
     Result:=Result+PigLatinWord(w);
   end;
 except
 end;
end;    function GetMsgProc(code: integer; removal: integer; msg: Pointer):
Integer; stdcall;
begin
 Result:=0;
end;    Var HookHandle: THandle;    procedure StartHook; stdcall;
begin
 HookHandle:=SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, HInstance,
0);
end;    procedure StopHook; stdcall;
begin
 UnhookWindowsHookEx(HookHandle);
end;    exports StartHook, StopHook;    begin
 HookTextOut(Conv);
end.    ====================================================    unit HookTextUnit;    interface
uses Windows, SysUtils, Classes, PEStuff;    type
 TConvertTextFunction = function(text: String): String;
 TTextOutA = function(hdc: HDC; x,y: Integer; text: PAnsiChar; len:
Integer): BOOL; stdcall;
 TTextOutW = function(hdc: HDC; x,y: Integer; text: PWideChar; len:
Integer): BOOL; stdcall;
 TExtTextOutA = function(hdc: HDC; x,y: Integer; Options: DWORD; Clip:
PRect;
                       text: PAnsiChar; len: Integer; dx: PInteger):
BOOL; stdcall;
 TExtTextOutW = function(hdc: HDC; x,y: Integer; Options: DWORD; Clip:
PRect;
                       text: PWideChar; len: Integer; dx: PInteger):
BOOL; stdcall;
 TDrawTextA = function(hdc: HDC; text: PAnsiChar; len: Integer; rect:
PRect;
                       format: DWORD): Integer; stdcall;
 TDrawTextW = function(hdc: HDC; text: PWideChar; len: Integer; rect:
PRect;
                       format: DWORD): Integer; stdcall;
 TDrawTextExA = function(hdc: HDC; text: PAnsiChar; len: Integer; rect:
PRect;
                       format: DWORD; DTParams: PDrawTextParams):
Integer; stdcall;
 TDrawTextExW = function(hdc: HDC; text: PWideChar; len: Integer; rect:
PRect;
                       format: DWORD; DTParams: PDrawTextParams):
Integer; stdcall;     TTabbedTextOutA = function(hdc: HDC; x,y: Integer; text: PAnsiChar;
len: Integer;
                        TabCount: Integer; TabPositions: PInteger;
TabOrigin: Integer): Integer; stdcall;
 TTabbedTextOutW = function(hdc: HDC; x,y: Integer; text: PWideChar;
len: Integer;
                        TabCount: Integer; TabPositions: PInteger;
TabOrigin: Integer): Integer; stdcall;
 TPolyTextOutA = function(hdc: HDC; pptxt: PPOLYTEXTA; count: Integer):
BOOL; stdcall;
 TPolyTextOutW = function(hdc: HDC; pptxt: PPOLYTEXTW; count: Integer):
BOOL; stdcall;     TGetTextExtentExPointA = function(hdc: HDC; text: PAnsiChar; len:
Integer;
                         maxExtent: Integer; Fit: PInteger; Dx:
PInteger; Size: Pointer): BOOL; stdcall;
 TGetTextExtentExPointW = function(hdc: HDC; text: PWideChar; len:
Integer;
                         maxExtent: Integer; Fit: PInteger; Dx:
PInteger; Size: Pointer): BOOL; stdcall;
 TGetTextExtentPoint32A = function(hdc: HDC; text: PAnsiChar; len:
Integer; Size: Pointer): BOOL; stdcall;
 TGetTextExtentPoint32W = function(hdc: HDC; text: PWideChar; len:
Integer; Size: Pointer): BOOL; stdcall;
 TGetTextExtentPointA = function(hdc: HDC; text: PAnsiChar; len:
Integer; Size: Pointer): BOOL; stdcall;
 TGetTextExtentPointW = function(hdc: HDC; text: PWideChar; len:
Integer; Size: Pointer): BOOL; stdcall;     PPointer = ^Pointer;     TImportCode = packed record
   JumpInstruction: Word; // should be $25FF
   AddressOfPointerToFunction: PPointer;
 end;
 PImportCode = ^TImportCode;    procedure HookTextOut(ConvertFunction: TConvertTextFunction);
procedure UnhookTextOut;    implementation    Var
 ConvertTextFunction: TConvertTextFunction = nil;
 OldTextOutA: TTextOutA = nil;
 OldTextOutW: TTextOutW = nil;
 OldExtTextOutA: TExtTextOutA = nil;
 OldExtTextOutW: TExtTextOutW = nil;
 OldDrawTextA: TDrawTextA = nil;
 OldDrawTextW: TDrawTextW = nil;
 OldDrawTextExA: TDrawTextExA = nil;
 OldDrawTextExW: TDrawTextExW = nil;
 OldTabbedTextOutA: TTabbedTextOutA = nil;
 OldTabbedTextOutW: TTabbedTextOutW = nil;
 OldPolyTextOutA: TPolyTextOutA = nil;
 OldPolyTextOutW: TPolyTextOutW = nil;
 OldGetTextExtentExPointA: TGetTextExtentExPointA = nil;
 OldGetTextExtentExPointW: TGetTextExtentExPointW = nil;
 OldGetTextExtentPoint32A: TGetTextExtentPoint32A = nil;
 OldGetTextExtentPoint32W: TGetTextExtentPoint32W = nil;
 OldGetTextExtentPointA: TGetTextExtentPointA = nil;
 OldGetTextExtentPointW: TGetTextExtentPointW = nil;    function StrLenW(s: PWideChar): Integer;
Var i: Integer;
begin
 if s=nil then begin
   Result:=0; exit;
 end;
 i:=0;
 try
   while (s[i]<>#0) do inc(i);
 except
 end;
 Result:=i;
end;    function NewTextOutA(hdc: HDC; x,y: Integer; text: PAnsiChar; len:
Integer): BOOL; stdcall;
Var s: String;
begin
 try
 if Len<0 then Len:=strlen(text);
   If Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len+1,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldTextOutA<>nil then
       Result:=OldTextOutA(hdc,x,y,PAnsiChar(s),length(s))
     else
       Result:=False;
   end else Result:=OldTextOutA(hdc,x,y,PAnsiChar(s),0);
 except
   Result:=False;
 end;
end;    function NewTextOutW(hdc: HDC; x,y: Integer; text: PWideChar; len:
Integer): BOOL; stdcall;
Var s: WideString;
begin
 try
 if Len<0 then Len:=strlenW(text);
   If Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len*2+2,0);
     Move(text^,s[1],len*2);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldTextOutW<>nil then
       Result:=OldTextOutW(hdc,x,y,PWideChar(s),length(s))
     else
       Result:=False;
   end else Result:=OldTextOutW(hdc,x,y,PWideChar(s),0);
 except
   Result:=False;
 end;
end;    function NewExtTextOutA(hdc: HDC; x,y: Integer; Options: DWORD; Clip:
PRect;
 text: PAnsiChar; len: Integer; dx: PInteger): BOOL; stdcall;
Var s: String;
begin
 try
   if Len<0 then Len:=strlen(text); // ???
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len+1,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then s:=ConvertTextFunction(s);
     if @OldExtTextOutA<>nil then    Result:=OldExtTextOutA(hdc,x,y,Options,Clip,PAnsiChar(s),length(s),dx)
     else Result:=False;
   end else Result:=OldExtTextOutA(hdc,x,y,Options,Clip,text,0,dx);
 except
   Result:=False;
 end;
end;    function NewExtTextOutW(hdc: HDC; x,y: Integer; Options: DWORD; Clip:
PRect;
 text: PWideChar; len: Integer; dx: PInteger): BOOL; stdcall;
Var s: WideString;
begin
 try
   if Len<0 then Len:=strlenW(text);
   If Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len*2+2,0);
     Move(text^,s[1],len*2);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldExtTextOutW<>nil then    Result:=OldExtTextOutW(hdc,x,y,Options,Clip,PWideChar(s),length(s),dx)
     else Result:=False;
   end else Result:=OldExtTextOutW(hdc,x,y,Options,Clip,text,0,dx);
 except
   Result:=False;
 end;
end;    function NewDrawTextA(hdc: HDC; text: PAnsiChar; len: Integer; rect:
PRect;
 format: DWORD): Integer; stdcall;
Var s: String;
begin
 try
   if Len<0 then Len:=strlen(text); // ???
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len+1,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldDrawTextA<>nil then
       Result:=OldDrawTextA(hdc,PAnsiChar(s),length(s),rect,format)
     else Result:=0;
   end else Result:=OldDrawTextA(hdc,text,0,rect,format);
 except
   Result:=0;
 end;
end;    function NewDrawTextW(hdc: HDC; text: PWideChar; len: Integer; rect:
PRect;
 format: DWORD): Integer; stdcall;
Var s: WideString;
begin
 try
   if Len<0 then Len:=strlenW(text);
   if len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len*2+2,0);
     Move(text^,s[1],len*2);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldDrawTextW<>nil then
       Result:=OldDrawTextW(hdc,PWideChar(s),length(s),rect,format)
     else Result:=0;
   end else Result:=OldDrawTextW(hdc,text,0,rect,format);
 except
   Result:=0;
 end;
end;    function NewDrawTextExA(hdc: HDC; text: PAnsiChar; len: Integer; rect:
PRect;
 format: DWORD; DTParams: PDrawTextParams): Integer; stdcall;
Var s: String;
begin
 try
   if Len<0 then Len:=strlen(text);
   if len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len+1,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldDrawTextExA<>nil then    Result:=OldDrawTextExA(hdc,PAnsiChar(s),length(s),rect,format,DTParams)
     else Result:=0;
   end else Result:=OldDrawTextExA(hdc,text,0,rect,format,DTParams);
 except
   Result:=0;
 end;
end;    function NewDrawTextExW(hdc: HDC; text: PWideChar; len: Integer; rect:
PRect;
 format: DWORD; DTParams: PDrawTextParams): Integer; stdcall;
Var s: WideString;
begin
 try
   if Len<0 then Len:=strlenW(text);
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len*2+2,0);
     Move(text^,s[1],len*2);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldDrawTextExW<>nil then    Result:=OldDrawTextExW(hdc,PWideChar(s),length(s),rect,format,DTParams)
     else Result:=0;
   end else Result:=OldDrawTextExW(hdc,text,0,rect,format,DTParams);
 except
   Result:=0;
 end;
end;    function NewTabbedTextOutA(hdc: HDC; x,y: Integer; text: PAnsiChar; len:
Integer;
                        TabCount: Integer; TabPositions: PInteger;
TabOrigin: Integer): Integer; stdcall;
Var s: AnsiString;
begin
 try
   if Len<0 then Len:=strlen(text);
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len+1,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldTabbedTextOutA<>nil then    Result:=OldTabbedTextOutA(hdc,x,y,PAnsiChar(s),length(s),TabCount,TabPositions,TabOrigin)         else Result:=0;
   end else
Result:=OldTabbedTextOutA(hdc,x,y,text,0,TabCount,TabPositions,TabOrigin);     except
   Result:=0;
 end;
end;    function NewTabbedTextOutW(hdc: HDC; x,y: Integer; text: PWideChar; len:
Integer;
                        TabCount: Integer; TabPositions: PInteger;
TabOrigin: Integer): Integer; stdcall;
Var s: WideString;
begin
 try
   if Len<0 then Len:=strlenW(text);
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len*2+2,0);
     Move(text^,s[1],len*2);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldTabbedTextOutW<>nil then    Result:=OldTabbedTextOutW(hdc,x,y,PWideChar(s),length(s),TabCount,TabPositions,TabOrigin)         else Result:=0;
   end else
Result:=OldTabbedTextOutW(hdc,x,y,text,0,TabCount,TabPositions,TabOrigin);     except
   Result:=0;
 end;
end;    function NewPolyTextOutA(hdc: HDC; pptxt: PPOLYTEXTA; count: Integer):
BOOL; stdcall;
Var s: String; i: Integer; ppnew: PPOLYTEXTA;
begin
 ppnew:=nil;
 try
   Result:=False;
   if Count<0 then exit;
   if Count=0 then begin Result:=True; exit; end;
   GetMem(ppnew,count*sizeof(TPOLYTEXTA));
   For i:=1 to count do begin
     ppnew^:=pptxt^;
     if ppnew^.n<0 then ppnew^.n:=strlen(ppnew^.PAnsiChar);
     if ppnew^.n>0 then begin
       SetLength(s,ppnew^.n);
       FillChar(s[1],ppnew^.n+1,0);
       Move(ppnew^.PAnsiChar,s[1],ppnew^.n);
       if @ConvertTextFunction<>nil then
         s:=ConvertTextFunction(s);
       ppnew^.PAnsiChar:=PAnsiChar(s);
       ppnew^.n:=length(s);
       if @OldPolyTextOutA<>nil then
         Result:=OldPolyTextOutA(hdc,ppnew,1);
     end;
     Inc(pptxt);
   end;
 except
   Result:=False;
 end;
 if ppnew<>nil then FreeMem(ppnew);
end;    function NewPolyTextOutW(hdc: HDC; pptxt: PPOLYTEXTW; count: Integer):
BOOL; stdcall;
begin
 Result:=OldPolyTextOutW(hdc,pptxt,count);
end;    function NewGetTextExtentExPointA(hdc: HDC; text: PAnsiChar; len:
Integer;
       maxExtent: Integer; Fit: PInteger; Dx: PInteger; Size: Pointer):
BOOL; stdcall;
Var s: AnsiString;
begin
 try
   if Len<0 then Len:=strlen(text);
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len+1,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldGetTextExtentExPointA<>nil then    Result:=OldGetTextExtentExPointA(hdc,PAnsiChar(s),length(s),maxExtent,Fit,Dx,Size)         else Result:=False;
   end else
Result:=OldGetTextExtentExPointA(hdc,text,0,maxExtent,Fit,Dx,Size);
 except
   Result:=False;
 end;
end;    Function NewGetTextExtentExPointW(hdc: HDC; text: PWideChar; len:
Integer;
 maxExtent: Integer; Fit: PInteger; Dx: PInteger; Size: Pointer): BOOL;
stdcall;
Var s: WideString;
begin
 try
   if Len<0 then Len:=strlenW(text);
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len*2+2,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldGetTextExtentExPointW<>nil then    Result:=OldGetTextExtentExPointW(hdc,PWideChar(s),length(s),maxExtent,Fit,Dx,Size)         else Result:=False;
   end else
Result:=OldGetTextExtentExPointW(hdc,text,0,maxExtent,Fit,Dx,Size);
 except
   Result:=False;
 end;
end;
function NewGetTextExtentPoint32A(hdc: HDC; text: PAnsiChar; len:
Integer; Size: Pointer): BOOL; stdcall;
Var s: AnsiString;
begin
 try
   if Len<0 then Len:=strlen(text);
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len+1,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldGetTextExtentPoint32A<>nil then    Result:=OldGetTextExtentPoint32A(hdc,PAnsiChar(s),length(s),Size)
     else Result:=False;
   end else Result:=OldGetTextExtentPoint32A(hdc,text,0,Size);
 except
   Result:=False;
 end;
end;    function NewGetTextExtentPoint32W(hdc: HDC; text: PWideChar; len:
Integer; Size: Pointer): BOOL; stdcall;
Var s: WideString;
begin
 try
   if Len<0 then Len:=strlenW(text);
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len*2+2,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldGetTextExtentPoint32W<>nil then    Result:=OldGetTextExtentPoint32W(hdc,PWideChar(s),length(s),Size)
     else Result:=False;
   end else Result:=OldGetTextExtentPoint32W(hdc,text,0,Size);
 except
   Result:=False;
 end;
end;    function NewGetTextExtentPointA(hdc: HDC; text: PAnsiChar; len: Integer;
Size: Pointer): BOOL; stdcall;
Var s: AnsiString;
begin
 try
   if Len<0 then Len:=strlen(text);
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len+1,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldGetTextExtentPointA<>nil then
       Result:=OldGetTextExtentPointA(hdc,PAnsiChar(s),length(s),Size)
     else Result:=False;
   end else Result:=OldGetTextExtentPointA(hdc,text,0,Size);
 except
   Result:=False;
 end;
end;    function NewGetTextExtentPointW(hdc: HDC; text: PWideChar; len: Integer;
Size: Pointer): BOOL; stdcall;
Var s: WideString;
begin
 try
   if Len<0 then Len:=strlenW(text);
   if Len>0 then begin
     SetLength(s,len);
     FillChar(s[1],len*2+2,0);
     Move(text^,s[1],len);
     if @ConvertTextFunction<>nil then
       s:=ConvertTextFunction(s);
     if @OldGetTextExtentPoint32W<>nil then
       Result:=OldGetTextExtentPointW(hdc,PWideChar(s),length(s),Size)
     else Result:=False;
   end else Result:=OldGetTextExtentPointW(hdc,text,0,Size);
 except
   Result:=False;
 end;
end;    function PointerToFunctionAddress(Code: Pointer): PPointer;
Var func: PImportCode;
begin
 Result:=nil;
 if Code=nil then exit;
 try
   func:=code;
   if (func.JumpInstruction=$25FF) then begin
     Result:=func.AddressOfPointerToFunction;
   end;
 except
   Result:=nil;
 end;
end;    function FinalFunctionAddress(Code: Pointer): Pointer;
Var func: PImportCode;
begin
 Result:=Code;
 if Code=nil then exit;
 try
   func:=code;
   if (func.JumpInstruction=$25FF) then begin
     Result:=func.AddressOfPointerToFunction^;
   end;
 except
   Result:=nil;
 end;
end;    Function PatchAddress(OldFunc, NewFunc: Pointer): Integer;
Var BeenDone: TList;    Function PatchAddressInModule(hModule: THandle; OldFunc, NewFunc:
Pointer): Integer;
Var Dos: PImageDosHeader; NT: PImageNTHeaders;
ImportDesc: PImage_Import_Entry; rva: DWORD;
Func: PPointer; DLL: String; f: Pointer; written: DWORD;
begin
 Result:=0;
 Dos:=Pointer(hModule);
 if BeenDone.IndexOf(Dos)>=0 then exit;
 BeenDone.Add(Dos);
 OldFunc:=FinalFunctionAddress(OldFunc);
 if IsBadReadPtr(Dos,SizeOf(TImageDosHeader)) then exit;
 if Dos.e_magic<>IMAGE_DOS_SIGNATURE then exit;
 NT :=Pointer(Integer(Dos) + dos._lfanew);
//  if IsBadReadPtr(NT,SizeOf(TImageNtHeaders)) then exit;    RVA:=NT^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;     if RVA=0 then exit;
 ImportDesc := pointer(integer(Dos)+RVA);
 While (ImportDesc^.Name<>0) do begin
   DLL:=PChar(Integer(Dos)+ImportDesc^.Name);
   PatchAddressInModule(GetModuleHandle(PChar(DLL)),OldFunc,NewFunc);
   Func:=Pointer(Integer(DOS)+ImportDesc.LookupTable);
   While Func^<>nil do begin
     f:=FinalFunctionAddress(Func^);
     if f=OldFunc then begin
       WriteProcessMemory(GetCurrentProcess,Func,@NewFunc,4,written);
       If Written>0 then Inc(Result);
     end;
     Inc(Func);
   end;
   Inc(ImportDesc);
 end;
end;    begin
 BeenDone:=TList.Create;
 try
   Result:=PatchAddressInModule(GetModuleHandle(nil),OldFunc,NewFunc);
 finally
   BeenDone.Free;
 end;
end;    procedure HookTextOut(ConvertFunction: TConvertTextFunction);
begin
 if @OldTextOutA=nil then
   @OldTextOutA:=FinalFunctionAddress(@TextOutA);
 if @OldTextOutW=nil then
   @OldTextOutW:=FinalFunctionAddress(@TextOutW);     if @OldExtTextOutA=nil then
   @OldExtTextOutA:=FinalFunctionAddress(@ExtTextOutA);
 if @OldExtTextOutW=nil then
   @OldExtTextOutW:=FinalFunctionAddress(@ExtTextOutW);     if @OldDrawTextA=nil then
   @OldDrawTextA:=FinalFunctionAddress(@DrawTextA);
 if @OldDrawTextW=nil then
   @OldDrawTextW:=FinalFunctionAddress(@DrawTextW);     if @OldDrawTextExA=nil then
   @OldDrawTextExA:=FinalFunctionAddress(@DrawTextExA);
 if @OldDrawTextExW=nil then
   @OldDrawTextExW:=FinalFunctionAddress(@DrawTextExW);     if @OldTabbedTextOutA=nil then
   @OldTabbedTextOutA:=FinalFunctionAddress(@TabbedTextOutA);
 if @OldTabbedTextOutW=nil then
   @OldTabbedTextOutW:=FinalFunctionAddress(@TabbedTextOutW);     if @OldPolyTextOutA=nil then
   @OldPolyTextOutA:=FinalFunctionAddress(@PolyTextOutA);
 if @OldPolyTextOutW=nil then
   @OldPolyTextOutW:=FinalFunctionAddress(@PolyTextOutW);     if @OldGetTextExtentExPointA=nil then    @OldGetTextExtentExPointA:=FinalFunctionAddress(@GetTextExtentExPointA);     if @OldGetTextExtentExPointW=nil then
@OldGetTextExtentExPointW:=FinalFunctionAddress(@GetTextExtentExPointW);     if @OldGetTextExtentPoint32A=nil then    @OldGetTextExtentPoint32A:=FinalFunctionAddress(@GetTextExtentPoint32A);     if @OldGetTextExtentPoint32W=nil then    @OldGetTextExtentPoint32W:=FinalFunctionAddress(@GetTextExtentPoint32W);     if @OldGetTextExtentPointA=nil then
   @OldGetTextExtentPointA:=FinalFunctionAddress(@GetTextExtentPointA);     if @OldGetTextExtentPointW=nil then
   @OldGetTextExtentPointW:=FinalFunctionAddress(@GetTextExtentPointW);     @ConvertTextFunction:=@ConvertFunction;     PatchAddress(@OldTextOutA, @NewTextOutA);
 PatchAddress(@OldTextOutW, @NewTextOutW);
 PatchAddress(@OldExtTextOutA, @NewExtTextOutA);
 PatchAddress(@OldExtTextOutW, @NewExtTextOutW);
 PatchAddress(@OldDrawTextA, @NewDrawTextA);
 PatchAddress(@OldDrawTextW, @NewDrawTextW);
 PatchAddress(@OldDrawTextExA, @NewDrawTextExA);
 PatchAddress(@OldDrawTextExW, @NewDrawTextExW);
 PatchAddress(@OldTabbedTextOutA, @NewTabbedTextOutA);
 PatchAddress(@OldTabbedTextOutW, @NewTabbedTextOutW);
 PatchAddress(@OldPolyTextOutA, @NewPolyTextOutA);
 PatchAddress(@OldPolyTextOutW, @NewPolyTextOutW);
 PatchAddress(@OldGetTextExtentExPointA, @NewGetTextExtentExPointA);
 PatchAddress(@OldGetTextExtentExPointW, @NewGetTextExtentExPointW);
 PatchAddress(@OldGetTextExtentPoint32A, @NewGetTextExtentPoint32A);
 PatchAddress(@OldGetTextExtentPoint32W, @NewGetTextExtentPoint32W);
 PatchAddress(@OldGetTextExtentPointA, @NewGetTextExtentPointA);
 PatchAddress(@OldGetTextExtentPointW, @NewGetTextExtentPointW);
end;    procedure UnhookTextOut;
begin
 If @OldTextOutA<>nil then begin
   PatchAddress(@NewTextOutA, @OldTextOutA);
   PatchAddress(@NewTextOutW, @OldTextOutW);
   PatchAddress(@NewExtTextOutA, @OldExtTextOutA);
   PatchAddress(@NewExtTextOutW, @OldExtTextOutW);
   PatchAddress(@NewDrawTextA, @OldDrawTextA);
   PatchAddress(@NewDrawTextW, @OldDrawTextW);
   PatchAddress(@NewDrawTextExA, @OldDrawTextExA);
   PatchAddress(@NewDrawTextExW, @OldDrawTextExW);
   PatchAddress(@NewTabbedTextOutA, @OldTabbedTextOutA);
   PatchAddress(@NewTabbedTextOutW, @OldTabbedTextOutW);
   PatchAddress(@NewPolyTextOutA, @OldPolyTextOutA);
   PatchAddress(@NewPolyTextOutW, @OldPolyTextOutW);
   PatchAddress(@NewGetTextExtentExPointA, @OldGetTextExtentExPointA);
   PatchAddress(@NewGetTextExtentExPointW, @OldGetTextExtentExPointW);
   PatchAddress(@NewGetTextExtentPoint32A, @OldGetTextExtentPoint32A);
   PatchAddress(@NewGetTextExtentPoint32W, @OldGetTextExtentPoint32W);
   PatchAddress(@NewGetTextExtentPointA, @OldGetTextExtentPointA);
   PatchAddress(@NewGetTextExtentPointW, @OldGetTextExtentPointW);
 end;
end;    initialization
finalization
 UnhookTextOut;
end.    ===================================================
unit PEStuff;    interface
uses Windows;    type
 PImageDosHeader = ^TImageDosHeader;
 _IMAGE_DOS_HEADER = packed record      { DOS .EXE
header                  }
     e_magic: Word;                     { Magic
number                     }
     e_cblp: Word;                      { Bytes on last page of
file       }
     e_cp: Word;                        { Pages in
file                    }
     e_crlc: Word;                      {
Relocations                      }
     e_cparhdr: Word;                   { Size of header in
paragraphs     }
     e_minalloc: Word;                  { Minimum extra paragraphs
needed  }
     e_maxalloc: Word;                  { Maximum extra paragraphs
needed  }
     e_ss: Word;                        { Initial (relative) SS
value      }
     e_sp: Word;                        { Initial SP
value                 }
     e_csum: Word;                      {
Checksum                         }
     e_ip: Word;                        { Initial IP
value                 }
     e_cs: Word;                        { Initial (relative) CS
value      }
     e_lfarlc: Word;                    { File address of relocation
table }
     e_ovno: Word;                      { Overlay
number                   }
     e_res: array [0..3] of Word;       { Reserved
words                   }
     e_oemid: Word;                     { OEM identifier (for
e_oeminfo)   }
     e_oeminfo: Word;                   { OEM information; e_oemid
specific}
     e_res2: array [0..9] of Word;      { Reserved
words                   }
     _lfanew: LongInt;                  { File address of new exe
header   }
 end;
 TImageDosHeader = _IMAGE_DOS_HEADER;     PIMAGE_FILE_HEADER = ^IMAGE_FILE_HEADER;
 IMAGE_FILE_HEADER = packed record
   Machine              : WORD;
   NumberOfSections     : WORD;
   TimeDateStamp        : DWORD;
   PointerToSymbolTable : DWORD;
   NumberOfSymbols      : DWORD;
   SizeOfOptionalHeader : WORD;
   Characteristics      : WORD;
 end;
 PIMAGE_DATA_DIRECTORY = ^IMAGE_DATA_DIRECTORY;
 IMAGE_DATA_DIRECTORY = packed record
   VirtualAddress  : DWORD;
   Size            : DWORD;
 end;     PIMAGE_SECTION_HEADER = ^IMAGE_SECTION_HEADER;
 IMAGE_SECTION_HEADER = packed record
   Name            : packed array [0..IMAGE_SIZEOF_SHORT_NAME-1] of
Char;
   VirtualSize : DWORD; // or VirtualSize (union);
   VirtualAddress  : DWORD;
   SizeOfRawData   : DWORD;
   PointerToRawData : DWORD;
   PointerToRelocations : DWORD;
   PointerToLinenumbers : DWORD;
   NumberOfRelocations : WORD;
   NumberOfLinenumbers : WORD;
   Characteristics : DWORD;
 end;     PIMAGE_OPTIONAL_HEADER = ^IMAGE_OPTIONAL_HEADER;
 IMAGE_OPTIONAL_HEADER = packed record
  { Standard fields. }
   Magic           : WORD;
   MajorLinkerVersion : Byte;
   MinorLinkerVersion : Byte;
   SizeOfCode      : DWORD;
   SizeOfInitializedData : DWORD;
   SizeOfUninitializedData : DWORD;
   AddressOfEntryPoint : DWORD;
   BaseOfCode      : DWORD;
   BaseOfData      : DWORD;
  { NT additional fields. }
   ImageBase       : DWORD;
   SectionAlignment : DWORD;
   FileAlignment   : DWORD;
   MajorOperatingSystemVersion : WORD;
   MinorOperatingSystemVersion : WORD;
   MajorImageVersion : WORD;
   MinorImageVersion : WORD;
   MajorSubsystemVersion : WORD;
   MinorSubsystemVersion : WORD;
   Reserved1       : DWORD;
   SizeOfImage     : DWORD;
   SizeOfHeaders   : DWORD;
   CheckSum        : DWORD;
   Subsystem       : WORD;
   DllCharacteristics : WORD;
   SizeOfStackReserve : DWORD;
   SizeOfStackCommit : DWORD;
   SizeOfHeapReserve : DWORD;
   SizeOfHeapCommit : DWORD;
   LoaderFlags     : DWORD;
   NumberOfRvaAndSizes : DWORD;
   DataDirectory   : packed array
[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of IMAGE_DATA_DIRECTORY;
   Sections: packed array [0..9999] of IMAGE_SECTION_HEADER;
 end;     PIMAGE_NT_HEADERS = ^IMAGE_NT_HEADERS;
 IMAGE_NT_HEADERS = packed record
   Signature       : DWORD;
   FileHeader      : IMAGE_FILE_HEADER;
   OptionalHeader  : IMAGE_OPTIONAL_HEADER;
 end;
 PImageNtHeaders = PIMAGE_NT_HEADERS;
 TImageNtHeaders = IMAGE_NT_HEADERS;    {  PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;
 IMAGE_IMPORT_DESCRIPTOR = packed record
   Characteristics: DWORD; // or original first thunk // 0 for
terminating null import descriptor // RVA to original unbound IAT
   TimeDateStamp: DWORD; // 0 if not bound,
                         // -1 if bound, and real date\time stamp
                         //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
(new BIND)
                         // O.W. date/time stamp of DLL bound to (Old
BIND)
   Name: DWORD;
   FirstThunk: DWORD;  // PIMAGE_THUNK_DATA // RVA to IAT (if bound
this IAT has actual addresses)
   ForwarderChain: DWORD; // -1 if no forwarders
 end;
 TImageImportDescriptor = IMAGE_IMPORT_DESCRIPTOR;
 PImageImportDescriptor = PIMAGE_IMPORT_DESCRIPTOR;}     PIMAGE_IMPORT_BY_NAME = ^IMAGE_IMPORT_BY_NAME;
 IMAGE_IMPORT_BY_NAME = record
   Hint: Word;
   Name: Array[0..0] of Char;
 end;     PIMAGE_THUNK_DATA = ^IMAGE_THUNK_DATA;
 IMAGE_THUNK_DATA = record
   Whatever: DWORD;
 end;     PImage_Import_Entry = ^Image_Import_Entry;
 Image_Import_Entry = record
   Characteristics: DWORD;
   TimeDateStamp: DWORD;
   MajorVersion: Word;
   MinorVersion: Word;
   Name: DWORD;
   LookupTable: DWORD;
 end;    const
IMAGE_DOS_SIGNATURE     =   $5A4D;      // MZ
IMAGE_OS2_SIGNATURE     =   $454E;      // NE
IMAGE_OS2_SIGNATURE_LE  =   $454C;      // LE
IMAGE_VXD_SIGNATURE     =   $454C;      // LE
IMAGE_NT_SIGNATURE      =   $00004550;  // PE00    implementation    end.    =================================================
Create a new project with one form, with two buttons.
=================================================    unit PigLatinUnit;    interface    uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, forms,
Dialogs,
 StdCtrls;    type
 Tform1 = class(Tform)
   Button1: TButton;
   Button2
        
qoo1234
版主


發表:256
回覆:1167
積分:659
註冊:2003-02-24

發送簡訊給我
#16 引用回覆 回覆 發表時間:2004-04-24 22:17:25 IP:218.163.xxx.xxx 未訂閱
bruce0211 版主-提供的攔截 TEXTOUT HOOK 的參考資料(原始碼整理) http://delphi.ktop.com.tw/topic.php?TOPIC_ID=48943    網海無涯,學無止境!
8866
中階會員


發表:27
回覆:147
積分:69
註冊:2002-10-14

發送簡訊給我
#17 引用回覆 回覆 發表時間:2004-04-25 14:22:29 IP:218.168.xxx.xxx 未訂閱
1. '這很難以看出這叫做 "心得"'  ==> 請原諒我的無知 , 在此之前我根本                                     不知道要用此 HOOK 相關技術 , 只                                     是看一些資料後 , 才興起把它實作                                     看看 , '驗證' 看看是否可行 !                                         2. 'jackalan 長官的確太火爆' ==> 這也沒什麼 , 一個民主的社會本來就有                                  許多意見 , 看多聽多就沒什麼了 .    3. '而非蜻蜓點水式的說明'  ==> 我原想把自己驗證的結果 '說出來' , 畢竟                                網路上那些文章的想法與做法是有許多的                                '不確定性' , 自己沒玩過怎知道行不行呢 ?                                再者希望引起對這題目有興趣的同好 , 相互                                討論 , 研究 .                         4. "公益" ==> 我沒想過 , 只是一個單純的出發點而已 !    5. '大家也別再為難 8866 長官了' ==> 沒這嚴重 , 只是大家各自表述自己的                                     意見罷了 .     6. '請站長把這篇討論鎖起來吧!' ==> 這點建議也不錯 , 只是我不認為以上                                    各位的發言是 '口水之爭' !!!  >< >< > 發表人 -
8866
中階會員


發表:27
回覆:147
積分:69
註冊:2002-10-14

發送簡訊給我
#18 引用回覆 回覆 發表時間:2004-04-25 14:29:22 IP:218.168.xxx.xxx 未訂閱
引言: bruce0211 版主-提供的攔截 TEXTOUT HOOK 的參考資料(原始碼整理) http://delphi.ktop.com.tw/topic.php?TOPIC_ID=48943 網海無涯,學無止境!
能否有哪位能人異士 , 來提供此範例程式的測試報告 , 以及此種方法的 優劣 ! 分享給各位讀者 (PS : 我不懂 Delphi 語法 ) . 謝謝 . 發表人 -
jackalan
初階會員


發表:20
回覆:88
積分:36
註冊:2003-11-08

發送簡訊給我
#19 引用回覆 回覆 發表時間:2004-04-25 20:21:23 IP:221.226.xxx.xxx 未訂閱
真是抱歉,没想到我只是发表一下自己真实的想法就触犯了版规,并说了云云。我并无任何语言攻击,也许是我的语气太过强烈了,可能我就是有什么放不到心里的人,以后我会注意的。但有点我还是想说说,看到大家的回应后我更多的是感受到欣慰,我希望KTOP也像媒体一样(因为对我来说KTOP的确是学习DELPHI的最好媒体),每个人都能有言论自由,很多东西都是在争论中得到结果的。 qoo1234先生,不要动不动就拿版规来,相信在KTOP里的人这点觉悟还是有的,如果一有反面意见就拿版规来,我觉得应该学习的是您。按照您的意思是不是什么反面意见都不能提,只要有人发表文章就要双手赞成?否则就要版规处置,对于我刚说了不到两句就拿出版规来,我感到非常失望。 我的看法依然不变,8866您的这篇文章如果从标题看实在是太过实了,何为技術分析?别的不想多说了,总之关于"只是驗證網路上的那些文章是否 "可行" "实在荒谬。 至于“畢竟 1200 元對你一個已經有工作的人 , 實在也不是一種負擔不是嗎 ???”我没有意见,但请不要挂上“捐款”的名义,好像多名正言顺似的。1200不是多不多的问题,KTOP还是交流的地方吗?KTOP中好的文章和程序数不胜数,如果人人都挂个“捐款”才能得到原代码,那还有什么交流而言。是不是对公开要求“捐款”,也应该上个KTOP版规呢? 發表人 - jackalan 於 2004/04/25 21:37:36
liki
一般會員


發表:2
回覆:4
積分:6
註冊:2003-08-22

發送簡訊給我
#20 引用回覆 回覆 發表時間:2004-04-26 01:28:23 IP:218.163.xxx.xxx 未訂閱
Hook Win32 API 的應用研究之四:螢幕取詞 用過金山詞霸吧?用過的人一定對它的螢幕取詞功能印象很深刻,因為這種功能使翻譯程序更加簡便快捷,螢幕取詞是金山詞霸的核心技術之一。 大家有沒有想過這樣神奇的功能是如何實現的呢?經歷過DOS年代系統設計的人可能知道,螢幕上顯示的字元是存放在顯存裡的,每個坐標的字元對應顯存的一個特定的現存單元存儲的字元,直接操作顯存,就可以進行字元的顯示和讀取,若WINDOWS是這樣就好了,可惜事實上相去甚遠。那WINDOWS的字元是怎樣顯示的呢?WINDOWS是圖形界面,顯示的最小單位是像素(Pixel),上面的所有東西都是"畫"上去的,當然也包括了字元,也就沒有什麼字元顯存的概念了。沒有了直接操作顯存而獲得螢幕上字元內容的辦法了,那還有什麼方法呢? 讓我們來設身處地地想想看,假如我們要在自己的程式中顯示一個字串,我們會怎樣做呢?不要回答是MessageBox(),我們不是指的這種"顯示"方法,我指的是最低階的方法,也就是直接操作DC的方法,我想一般就是調用上面提到過的Win32 API函數TextOut()了,當然,還有類似的一些其它函數,例如:ExtTextOut()、DrawText()、DrawTextEx()等等。好了,找到點眉目了,我們來看看這些函數的參數能提供哪些信息,這裡只列出TextOut()函數的定義,其它的函數基本都包含這些參數,另外提供了更多的附加選項而已,請查閱MSDN相關文檔: BOOL TextOut( HDC hdc, // 設備上下文引用 int nXStart, // 開始繪製字串的位置的x坐標 int nYStart, // 開始繪製字串的位置的y坐標 LPCTSTR lpString, // 指向字串的指標 int cbString // 指明要繪製多少個字元 ); 我們看到,坐標和內容都有了,這不正是我們想要的信息嗎?只要Hook住這個函數,這些信息不都唾手可得了嗎?於是祭出Hook大法來做個實驗:先隨便用VC的嚮導開闢一個單文檔應用程式,在OnDraw()函數里調用TextOut()在某個位置隨便輸出一個字串(不論是調用pDC->TextOut(...)或者是::TextOut(...)都一樣,CDC類只不過把TextOut()封裝了一下而已),然後在OnInitialUpdate()裡設置Hook(用現成的庫),鉤住TextOut(),截獲TextOut之後,讓TextOut()輸出另外一個字串而不輸出原來的字串。還要記住在OnDestroy()裡解除Hook。最後編譯連接,測試程式。你會發現不僅是你調用TextOut()輸出的地方的字串被替換了,而且連才旦、對話框等等有字的地方也變了,在實驗成功之餘,是不是個意外的收穫?其實WINDOWS內部的大多數文字輸出也是調用了TextOut()函數來實現的。現在水落石出了,我們只要Hook住文字輸出函數,包括我上面提到的和沒有提到的函數,就能截獲螢幕上文字輸出的坐標和內容等等信息,只要我們一一作記錄,並加以分析轉換,跟鼠標的位置進行比較,我們就能得到螢幕上某個位置的文字內容是什麼了,要翻譯怎麼的,就看你的了,這就是螢幕取詞,雖然實際上實現的程序並不像說得那麼簡單。 出了詞霸的螢幕取詞,還有一些動態中文化、外掛中文平台之類的軟體,也是基於這種技術的,現在看來,它們是不是已經不再神秘了? 發表人 - liki 於 2004/04/26 01:33:46
8866
中階會員


發表:27
回覆:147
積分:69
註冊:2002-10-14

發送簡訊給我
#21 引用回覆 回覆 發表時間:2004-04-26 09:12:45 IP:61.222.xxx.xxx 未訂閱
1. 8866您的这篇文章如果从标题看实在是太过实了,何为技術分析 ?? Ans : 把 '自己' 的所見所聞的實驗結果與大家討論 , 並盼望能有更高竿 的建議改進自己的做法 ! 2. 别的不想多说了,总之关于"只是驗證網路上的那些文章是否 "可行" "实在 荒谬 ! Ans : 難道你沒聽過 '盡信書不如無書' 的說法嗎 ? 我實在對於你的用詞 感到極度的 '無奈' ! 3. 但请不要挂上“捐款”的名义,好像多名正言顺似的. Ans : 捐不捐是每個人的自由 , 我也有我自己的判斷 ! 4. KTOP还是交流的地方吗 ? Ans : 交流並不是只有 Source code 喔 ! 還包掛文件 , 心得 , 實驗結 果 , 心情故事 等 ... 5. 我會建議站長把此討論給刪掉 ! 避免一些激烈的言論影響讀者的心情 .
jackalan
初階會員


發表:20
回覆:88
積分:36
註冊:2003-11-08

發送簡訊給我
#22 引用回覆 回覆 發表時間:2004-04-26 10:13:01 IP:202.102.xxx.xxx 未訂閱
不要用什么“極度的 '無奈'”,“捐不捐是每個人的自由 , 我也有我自己的判斷 !”、“交流並不是只有 Source code 喔 ! 還包掛文件 , 心得 , 實驗結 果 , 心情故事”来回应问题,去读读你对所有发表人的评论,好像大家都错了似了。    “交流並不是只有 Source code 喔 ! 還包掛文件 , 心得 , 實驗結 果 , 心情故事”我很赞成,但还是请搞清楚什么叫“心得”什么叫“實驗結 果”,发个所谓的“實驗結果”就让人“捐款”就是你“捐不捐是每個人的自由 , 我也有我自己的判斷 !”的理由吗?如果这个就是帮助别人的话,相信想作帮人的人就太多了。    也强烈建议版主删除这篇文章,口水仗不想再打了,以后不对这类文章发表意见就是,什么人才能进步,相信是能接受意见的人。不知道是我肚量太小还是什么的,每个人的每个反面意见你都做了“批示”,就算我们错了吧,“實驗結果”继续、“捐款”继续。。。 至于谁会“影響讀者的心情”,大家会有公论。。。 發表人 -
shieh2700
高階會員


發表:0
回覆:127
積分:100
註冊:2002-06-13

發送簡訊給我
#23 引用回覆 回覆 發表時間:2004-04-26 10:36:05 IP:61.216.xxx.xxx 未訂閱
引言: 長官 沒有 SourceCode 的程式 , 如何"對有興趣的網友減少一些時間的浪費" 既然也是參考別人的文章 , 提供自己的 SourceCode 應該也不為過 < face="Verdana, Arial, Helvetica"> 長官: 由您先前的大作中得知, 您似乎是在開發 POS 系統 http://delphi.ktop.com.tw/topic.php?TOPIC_ID=19269 您近期有提供或開放完整 POS 系統 Source Code 的計劃嗎? 我想大家應該會很期待的... 發表人 - shieh2700 於 2004/04/26 10:37:55
8866
中階會員


發表:27
回覆:147
積分:69
註冊:2002-10-14

發送簡訊給我
#24 引用回覆 回覆 發表時間:2004-04-26 10:43:38 IP:61.222.xxx.xxx 未訂閱
想不到一篇文章惹的大家的不悅 ! 在此獻上最高的歉意 , 也盼此文章的 討論告一個段落 .
領航天使
站長


發表:12216
回覆:4186
積分:4084
註冊:2001-07-25

發送簡訊給我
#25 引用回覆 回覆 發表時間:2004-04-26 13:27:44 IP:192.168.xxx.xxx 未訂閱
站長個人認為: 1.公不公開原始碼,完全由作者自行決定,請尊重原作者決定,也不用勉強別人公開! 2.再簡單的程式也有可能會是別人可以參考的地方,畢竟我們也都是從簡單的程式開始寫起吧! 為了避免一再爭論不休,本篇上鎖! ~~~Delphi K.Top討論區站長~~~
------
~~~Delphi K.Top討論區站長~~~
系統時間:2024-04-24 4:28:47
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!