標(biāo) 題:關(guān)于Delphi/BCB程序中GetWindowTextA/GetDlgItemTextA斷點(diǎn)為何失效的簡(jiǎn)單分析 (7千字)
發(fā)信人:blowfish
時(shí) 間:2001-12-28 17:02:39
詳細(xì)信息:
VCL中標(biāo)準(zhǔn)的單行編輯控件TEdit和多行編輯控件TMemo在類樹(shù)中的派生關(guān)系如下:
TObject -> TPersistent -> TComponent -> TControl -> TWinControl -> TCustomEdit -> TEdit
TObject -> TPersistent -> TComponent -> TControl -> TWinControl -> TCustomEdit -> TCustomMemo -> TMemo
以TEdit為例,來(lái)看一下它是如何獲取控件中的字符串的,把這個(gè)過(guò)程(也就是VCL內(nèi)部處理消息的過(guò)程)搞清楚了,就能夠知道該設(shè)什么樣的斷點(diǎn)來(lái)監(jiān)視這個(gè)獲得字符串的過(guò)程,從而找到我們輸入的注冊(cè)碼在內(nèi)存中的存放位置,進(jìn)而可以通過(guò)BPM/BPR斷點(diǎn)來(lái)跟蹤對(duì)注冊(cè)碼的處理過(guò)程,
斷點(diǎn)為何失效的簡(jiǎn)單分析
。TEdit用來(lái)存放字符串的屬性是Text,該屬性繼承自TControl。讀取該屬性的函數(shù)是私有函數(shù)GetText( )。
(以下代碼來(lái)自VCL的源碼stdctrls.pas、control.pas、system.pas、sysutils.pas)
//----------------------------------------------------------------------------------------------------
TWndMethod = procedure(var Message: TMessage) of object;
TControl = class(TComponent)
private
FWindowProc: TWndMethod;
FText: PChar;
function GetText: TCaption;
procedure SetText(const Value: TCaption);
......
protected
property Text: TCaption read GetText write SetText;
procedure WndProc(var Message: TMessage); virtual;
......
public
function GetTextBuf(Buffer: PChar; BufSize: Integer): Integer;
function GetTextLen: Integer;
procedure SetTextBuf(Buffer: PChar);
function Perform(Msg: Cardinal; WParam LParam: Longint): Longint;
property WindowProc: TWndMethod read FWindowProc write FWindowProc;
......
end;
//----------------------------------------------------------------------------------------------------
GetText( )函數(shù)及相關(guān)函數(shù)的定義如下?梢(jiàn),TControl最終是以WM_GETTEXTLENGTH和WM_GETTEXT消息為參數(shù)直接調(diào)WndProc( )的。
//----------------------------------------------------------------------------------------------------
function TControl.GetText: TCaption;
var
Len: Integer;
begin
Len := GetTextLen;
SetString(Result PChar(nil) Len);
if Len <> 0 then GetTextBuf(Pointer(Result) Len + 1);
end;
function TControl.GetTextLen: Integer;
begin
Result := Perform(WM_GETTEXTLENGTH 0 0);
end;
function TControl.GetTextBuf(Buffer: PChar; BufSize: Integer): Integer;
begin
Result := Perform(WM_GETTEXT BufSize Longint(Buffer));
end;
procedure TControl.SetTextBuf(Buffer: PChar);
begin
Perform(WM_SETTEXT 0 Longint(Buffer));
Perform(CM_TEXTCHANGED 0 0);
end;
procedure TControl.SetText(const Value: TCaption);
begin
if GetText <> Value then SetTextBuf(PChar(Value));
end;
function TControl.Perform(Msg: Cardinal; WParam LParam: Longint): Longint;
var
Message: TMessage;
begin
Message.Msg := Msg;
Message.WParam := WParam;
Message.LParam := LParam;
Message.Result := 0;
if Self <> nil then WindowProc(Message);
Result := Message.Result;
end;
constructor TControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FWindowProc := WndProc;
......
end;
//----------------------------------------------------------------------------------------------------
WndProc( )是個(gè)virtual函數(shù)。TEdit和TCustomEdit未重載這個(gè)函數(shù),而TWinControl重載了這個(gè)函數(shù),但它并未處理WM_GETTEXT消息,而是直接把該消息傳遞給了父類的函數(shù)TControl.WndProc( )。
//----------------------------------------------------------------------------------------------------
procedure TWinControl.WndProc(var Message: TMessage);
var
Form. TCustomForm;
KeyState: TKeyboardState;
WheelMsg: TCMMouseWheel;
begin
......
inherited WndProc(Message);
end;
//----------------------------------------------------------------------------------------------------
TControl.WndProc( )直接用Dispatch( )來(lái)分發(fā)該消息,
電腦資料
《斷點(diǎn)為何失效的簡(jiǎn)單分析》(http://www.msguai.com)。//----------------------------------------------------------------------------------------------------
procedure TControl.WndProc(var Message: TMessage);
var
Form. TCustomForm;
begin
......
Dispatch(Message);
end;
//----------------------------------------------------------------------------------------------------------
由于WM_GETTEXT在TEdit中沒(méi)有對(duì)應(yīng)的專門的處理函數(shù),所以Dispatch( )最終會(huì)調(diào)用TEdit.DefaultHandler( ),這個(gè)方法是從TCustomEdit繼承來(lái)的,如此層層向上往父類分發(fā),直到TControl.DefaultHandler( )對(duì)WM_GETTEXT消息進(jìn)行了處理,它只是簡(jiǎn)單地把TControl的私有變量FText拷貝到軟件提供的緩沖區(qū)中,所用到的函數(shù)只有StrLen( )、StrLCopy( )。
//----------------------------------------------------------------------------------------------------------
procedure TControl.DefaultHandler(var Message);
var
P: PChar;
begin
with TMessage(Message) do
case Msg of
WM_GETTEXT:
begin
if FText <> nil then P := FText else P := '';
Result := StrLen(StrLCopy(PChar(LParam) P WParam - 1));
end;
WM_GETTEXTLENGTH:
if FText = nil then Result := 0 else Result := StrLen(FText);
WM_SETTEXT:
begin
P := StrNew(PChar(LParam));
StrDispose(FText);
FText := P;
SendDockNotification(Msg WParam LParam);
end;
end;
end;
//----------------------------------------------------------------------------------------------------------
看一下sysutils.pas中的StrLen( )、StrLCopy( )函數(shù)的實(shí)現(xiàn),是用匯編寫的,沒(méi)有調(diào)用任何API函數(shù)。這就說(shuō)明從進(jìn)入TControl.GetText( )開(kāi)始,一直到WM_GETTEXT成功返回為止,沒(méi)有調(diào)用過(guò)任何Win32 API函數(shù)。所以常用的GetDlgItemTextA、GetWindowTextA斷點(diǎn)不生效是當(dāng)然的。
//----------------------------------------------------------------------------------------------------------
function StrLen(const Str: PChar): Cardinal; assembler;
asm
MOV EDXEDI
MOV EDIEAX
MOV ECX0FFFFFFFFH
XOR ALAL
REPNE SCASB
MOV EAX0FFFFFFFEH
SUB EAXECX
MOV EDIEDX
end;
function StrLCopy(Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar; assembler;
asm
PUSH EDI
PUSH ESI
PUSH EBX
MOV ESIEAX
MOV EDIEDX
MOV EBXECX
XOR ALAL
TEST ECXECX
JZ @@1
REPNE SCASB
JNE @@1
INC ECX
@@1: SUB EBXECX
MOV EDIESI
MOV ESIEDX
MOV EDXEDI
MOV ECXEBX
SHR ECX2
REP MOVSD
MOV ECXEBX
AND ECX3
REP MOVSB
STOSB
MOV EAXEDX
POP EBX
POP ESI
POP EDI
end;
//-------------------------------------------------------------------------------------------------------
那么如何才能在VCL將用戶輸入的字符串拷貝到軟件的緩沖區(qū)中時(shí)使SoftICE彈出來(lái)呢?一種辦法是先在軟件的內(nèi)存中搜索StrLCopy( )這個(gè)函數(shù)的機(jī)器碼(即其Signature),找到之后在其入口處設(shè)個(gè)斷點(diǎn)即可。實(shí)際上,你也可以在TControl.DefaultHandler( )、TControl.GetText( )等函數(shù)的入口處設(shè)斷點(diǎn),只要VCL在獲取TEdit.Text的過(guò)程中調(diào)用了該函數(shù),當(dāng)然調(diào)用的次數(shù)越少越好。
另外一種方法就是跟蹤FText何時(shí)被賦值,實(shí)際上就在上面的WM_SETTEXT處。
blowfish
--------------------------------------------------------------------------------