關於Delphi/BCB程式中GetWindowTextA/GetDlgItemTextA斷點為何失效的簡單分析 (7千字)
VCL中標準的單行編輯控制元件TEdit和多行編輯控制元件TMemo在類樹中的派生關係如下:
TObject -> TPersistent -> TComponent -> TControl -> TWinControl -> TCustomEdit
-> TEdit
TObject -> TPersistent -> TComponent -> TControl -> TWinControl -> TCustomEdit
-> TCustomMemo -> TMemo
以TEdit為例,來看一下它是如何獲取控制元件中的字串的,把這個過程(也就是VCL內部處理訊息的過程)搞清楚了,就能夠知道該設什麼樣的斷點來監視這個獲得字串的過程,從而找到我們輸入的註冊碼在記憶體中的存放位置,進而可以透過BPM/BPR斷點來跟蹤對註冊碼的處理過程。
TEdit用來存放字串的屬性是Text,該屬性繼承自TControl。讀取該屬性的函式是私有函式GetText( )。
(以下程式碼來自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( )函式及相關函式的定義如下。可見,TControl最終是以WM_GETTEXTLENGTH和WM_GETTEXT訊息為引數直接調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( )是個virtual函式。TEdit和TCustomEdit未過載這個函式,而TWinControl過載了這個函式,但它並未處理WM_GETTEXT訊息,而是直接把該訊息傳遞給了父類的函式TControl.WndProc(
)。
//----------------------------------------------------------------------------------------------------
procedure TWinControl.WndProc(var Message: TMessage);
var
Form: TCustomForm;
KeyState: TKeyboardState;
WheelMsg: TCMMouseWheel;
begin
......
inherited WndProc(Message);
end;
//----------------------------------------------------------------------------------------------------
TControl.WndProc( )直接用Dispatch( )來分發該訊息。
//----------------------------------------------------------------------------------------------------
procedure TControl.WndProc(var Message: TMessage);
var
Form: TCustomForm;
begin
......
Dispatch(Message);
end;
//----------------------------------------------------------------------------------------------------------
由於WM_GETTEXT在TEdit中沒有對應的專門的處理函式,所以Dispatch( )最終會呼叫TEdit.DefaultHandler( ),這個方法是從TCustomEdit繼承來的,如此層層向上往父類分發,直到TControl.DefaultHandler(
)對WM_GETTEXT訊息進行了處理,它只是簡單地把TControl的私有變數FText複製到軟體提供的緩衝區中,所用到的函式只有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( )函式的實現,是用匯編寫的,沒有呼叫任何API函式。這就說明從進入TControl.GetText(
)開始,一直到WM_GETTEXT成功返回為止,沒有呼叫過任何Win32 API函式。所以常用的GetDlgItemTextA、GetWindowTextA斷點不生效是當然的。
//----------------------------------------------------------------------------------------------------------
function StrLen(const Str: PChar): Cardinal; assembler;
asm
MOV EDX,EDI
MOV EDI,EAX
MOV ECX,0FFFFFFFFH
XOR AL,AL
REPNE SCASB
MOV EAX,0FFFFFFFEH
SUB EAX,ECX
MOV EDI,EDX
end;
function StrLCopy(Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar;
assembler;
asm
PUSH EDI
PUSH ESI
PUSH EBX
MOV ESI,EAX
MOV EDI,EDX
MOV EBX,ECX
XOR AL,AL
TEST ECX,ECX
JZ @@1
REPNE SCASB
JNE @@1
INC ECX
@@1: SUB EBX,ECX
MOV EDI,ESI
MOV ESI,EDX
MOV EDX,EDI
MOV ECX,EBX
SHR ECX,2
REP MOVSD
MOV ECX,EBX
AND ECX,3
REP MOVSB
STOSB
MOV EAX,EDX
POP EBX
POP ESI
POP EDI
end;
//-------------------------------------------------------------------------------------------------------
那麼如何才能在VCL將使用者輸入的字串複製到軟體的緩衝區中時使SoftICE彈出來呢?一種辦法是先在軟體的記憶體中搜尋StrLCopy( )這個函式的機器碼(即其Signature),找到之後在其入口處設個斷點即可。實際上,你也可以在TControl.DefaultHandler(
)、TControl.GetText( )等函式的入口處設斷點,只要VCL在獲取TEdit.Text的過程中呼叫了該函式,當然呼叫的次數越少越好。
另外一種方法就是跟蹤FText何時被賦值,實際上就在上面的WM_SETTEXT處。
blowfish
相關文章
- 關於StyleXP反跟蹤程式碼的分析以及WinDbg簡單教學
(7千字)2015-11-15
- 關於Delphi中TRttiContext.FindType失效的問題2013-08-14Context
- 簡單方法避開斷點 (3千字)2003-03-02斷點
- delphi中關於字串的操作2011-09-15字串
- MySQL斷電恢復的一點簡單分析2017-09-14MySql
- 診斷與分析itpub壇友提出關於為何awr cpu usage非常高2014-08-19
- 簡單的斷點續傳2017-11-10斷點
- Delphi(BCB)中編譯器版本宏定義 (轉)2007-12-04編譯
- 關於兩個簡單問題的分析2016-05-26
- 關於gdb斷點的真相2014-06-08斷點
- 關於rac中的鎖簡單學習2013-10-28
- 一點小意思,掃雷作弊的delphi程式碼
(9千字)2015-11-15
- 關於《龍族幻想》的系統以及簡單分析2021-03-18
- 關於幾個簡單遊戲的CD保護破解。 (3千字)2001-01-05遊戲
- Delphi寫的讀狗程式的簡單逆向對比.2015-11-15
- Java斷點續傳(基於socket與RandomAccessFile的簡單實現)2019-05-09Java斷點randomMac
- Delphi中關於TApplication類的詳解 (轉)2008-01-06APP
- 簡單的一點總結:關於優惠券功能2018-02-01
- 使用Delphi,SDK編寫Windows簡單程式 (轉)2007-12-13Windows
- 關於BFC的簡單理解2019-04-05
- 關於RabbitMQ的簡單理解2021-02-04MQ
- 關於Delphi7的IntraWeb 編譯的Apache (DSO) 模組 (轉)2007-12-12Web編譯Apache
- PHP中關於foreach的簡單的用法總結2015-10-29PHP
- Delphi Variant 判斷是否為空2024-07-25
- 關於jQuery radio 選中失效的問題2016-03-01jQuery
- 關於http斷點續傳那點事2018-10-22HTTP斷點
- 關於查詢轉換的一些簡單分析(一)2014-11-26
- 關於查詢轉換的一些簡單分析(二)2014-12-01
- 關於查詢轉換的一些簡單分析(三)2014-11-29
- VS斷點除錯簡單筆記2020-12-21斷點除錯筆記
- 關於 PHP 框架的簡單思考2018-05-26PHP框架
- 關於GO反射的簡單定律2017-09-22Go反射
- 關於JSON的簡單使用2024-08-17JSON
- Delphi 中的 XMLDocument 類詳解(9) - 關於 HasChildNodes 與 IsTextElement2008-01-03XML
- 關於Delphi中預編譯指令的使用方法 (轉)2007-12-23編譯
- 關於java編寫斷點續傳中ftp的list命令問題2003-07-20Java斷點FTP
- 原來的控制元件delphi7裡何處尋? (轉)2008-01-21控制元件
- 關於ORA-12801,ORA-27090的簡單分析2015-02-26