ã¢ãã¿ãŒã®ã¿ã¹ã¯ã¯åçŽã§ã-å®éã«ã¯ããªãã¶ãŒããŒã§ããããããŒãžã£ãŒãšããŠæ©èœããããšãã§ããŸããããã¢ãã¿ãŒãã翻蚳ããããã®ãªãã·ã§ã³ã®1ã€ã¯ã¡ã³ã¿ãŒã§ãã ãŸããç¶æ³ãåæããŠé©åãªçµè«ãåŒãåºãããšãã§ããäžé£ã®ããŒã¿ãæäŸãããšããã¿ã¹ã¯ãæããã§ãã
çŸä»£ã®ãœãããŠã§ã¢ã§ã¯ãã¢ãã¿ãŒã¯ã»ãŒã©ãã«ã§ããããŸããããšãã°ãåãPunto Switcherã¯åæ³çãªã¢ãã¿ãŒã®å žåçãªäŸã§ãã ã»ãšãã©ãã¹ãŠã®ãŠã€ã«ã¹å¯Ÿçããã°ã©ã ã¯ã¢ãã¿ãŒããããã¡ã€ã©ãŒã§ãããç§ã¯ã¡ã€ã³ããŒã«ãããã§ãããããã¬ãŒã«ã€ããŠã話ããŠããŸããããããã¬ãŒã¯ã¢ãã¿ãŒã§ããããŸãã
ããªã±ãŒãã®è£åŽã«ã¯ãæªæã®ãããœãããŠã§ã¢ã®å±±å šäœã衚瀺ãããŸããããã®äžéšã¯ç£èŠã䜿çšããŠäž»ãªç®æšãéæããããšã奜ã¿ãŸãã ãããããããã«ã€ããŠã¯ä»ã§ã¯ãããŸãã...
çŸæç¹ã§ã¯ãã€ã³ã¿ãŒãããã«ã¯éåžžã«å€ãã®ãœãããŠã§ã¢æ©èœã¢ãã¿ãŒã®äŸããããŸãããã»ãšãã©ã®å Žåãã€ã³ããŒãããŒãã«ãç·šéããããšã«ãã£ãŠã€ã³ã¿ãŒã»ãããããããã€ã³ã¿ãŒã»ãããããæ©èœã®éå§æã«ã€ã³ã¿ãŒã»ãã¿ãŒãã€ã³ã¹ããŒã«ãããšèããããŠããŸãïŒããããã¹ãã©ã€ã·ã³ã°ïŒã ãããããããã®è³æã¯å ¥æå¯èœã§ãããæã«ã¯é£è§£ãªèšèªã§æžãããŠãããããéçºè ãå©ããªãããšããããŸãããŸãã察象åéã«ç²ŸéããŠããªãéçºè ã«ãšã£ãŠç解ã§ããªããæèããå€ããã³ãŒãã®äžéšãè¡šãããšãããããŸãã
å æãã€ã³ã¿ãŒã»ãã¿ãŒãæ£ããå®è£ ããæ¹æ³ãå°ãã人ãäœäººãæ¥ãŠãäŸãžã®ãªã³ã¯ã¯å®éã«ã¯åœ¹ã«ç«ããªãã£ãã®ã§ãæåãããã¹ãŠãåãŸãªããã°ãªããŸããã§ããã ãããä»ã§ã¯ãååæè¡ã«å¯ŸåŠãå§ããã°ããã®äººã ãééããäž»ãªééãã«æ°ä»ããŠããŸãã
ãã®çµæã次åãã¹ãŠã説æããªãããã«ãç§ã¯ã¬ãã¥ãŒèšäºãäœæãããä»çµã¿ãã«ã€ããŠå¯èœãªéãç°¡åãªèšèªã§ãã¹ãŠã説æããããšããããšã«ããŸããã
1.ã¢ãã¿ãŒã®æ¬è³ª
ã¢ãã¿ãŒã®äž»ãªã¿ã¹ã¯ã¯ããããå¶åŸ¡ããæ©èœãžã®å¶åŸ¡ã®ç§»è¡ã«ã€ããŠåŠç¿ããããšãã§ããŸãã
ãã®ããã«ãå ã®é¢æ°ã®åŒã³åºããã€ã³ã¿ãŒã»ããããããã®ããŸããŸãªãªãã·ã§ã³ã䜿çšããããã®å¶åŸ¡ã®å©ããåããŠãã€ã³ã¿ãŒã»ãããã³ãã©ãŒãïŒãŸãã¯ããã䟿å©ãªãã€ã³ã¿ãŒã»ãã¿ãŒãïŒã«å¶åŸ¡ã転éãããŸãã
ã€ã³ã¿ãŒã»ãããããé¢æ°ãã©ããããã¯ãã€ã³ã¿ãŒã»ãã¿ãŒã®å®è£ ã«ããã«äŸåããŸãã åŒã³åºãã®ãã©ã¡ãŒã¿ãŒããã°ã«è¡šç€ºããå¿ èŠã«å¿ããŠãä»ã®ãã©ã¡ãŒã¿ãŒãããšãã°ãçµæãåŒã³åºãã¹ã¿ãã¯ã®ã¹ããŒã¿ã¹ãªã©ã衚瀺ã§ããŸãã äž»ãªãã®ã¯ãã³ã³ãããŒã«ããšãããšã§ãã
ç§ã¯ããªããã»ãšãã©èªåã§é¢æ°ããã¯ãæžãããšãã»ãŒä¿èšŒãããŠãããšèšãããšãã§ããŸãã ããã¯ãOOPã®æŠå¿µã«ãã£ãŠéåžžã«ä¿é²ãããŸãã ä»®æ³ã¡ãœãããŸãã¯åçã¡ãœããããªãŒããŒã©ã€ãããã¯ã©ã¹ã¯ãã¢ãã¿ãŒã®ç£èŠäžã§æ¢ã«åŒã³åºãããšãã§ããŸãã å®éããªãŒããŒã©ã€ãã«ãã£ãŠãããã¯ãããã¡ãœããã¯ãã€ã³ã¿ãŒã»ãããããé¢æ°ã®æçµçãªãã³ãã©ãŒã§ãããå®éã«å éšã§ã©ã®ããã«æ©èœããããèããå¿ èŠãããããŸãããå ã®ã¡ãœãããåŒã³åºãããšã§åé¡ãçããããšã¯ãããŸããã ã³ã³ãã€ã©ã¯ãã§ã«ãã¹ãŠãè¡ã£ãŠããŸãã
ããããããå°ãæ·±ãæãäžããªããã°ãªããŸããã ããšãã°ãéçã¡ãœããã§ã¯ããã®ãããªãã©ãŒã«ã¹ã¯ééããªããªãããã®ãããªãªãŒããŒã©ãããå¿ èŠãªå Žåã¯ããã¹ãŠèªåã§è¡ãå¿ èŠããããŸãã ãã ããç£èŠã«çŽæ¥é²ãåã«ãååãã³ãã©ãŒã®å®è£ ãç解ããå¿ èŠããããŸãã
2.ååãã³ãã©ãŒã®æ£ãã宣èš
é¢æ°ã®ã€ã³ã¿ãŒã»ãããéå§ããåã«ããã®åŒã³åºãã®ãã©ã¡ãŒã¿ãŒãšåŒã³åºãèŠåãæ£ç¢ºã«ç¥ãå¿ èŠããããŸãã ã€ãŸããããšãã°MessageBoxAãã€ã³ã¿ãŒã»ããããå Žåãå ã®é¢æ°ã®ä»£ããã«æ©èœããã€ã³ã¿ãŒã»ãã¿ãŒã¯æ¬¡ã®åœ¢åŒã«ãªã£ãŠããå¿ èŠããããŸãã
function InterceptedMessageBoxA(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; begin // TODO... end;
ã€ãŸããã€ã³ã¿ãŒã»ãããã³ãã©ãŒã®ãã©ã¡ãŒã¿ãŒãšåŒã³åºãèŠåïŒstdcall / cdeclãªã©ïŒã¯ãå ã®é¢æ°ãšæ£ç¢ºã«äžèŽããå¿ èŠããããŸãã ãããè¡ãããªãå Žåããã³ãã©ãŒãåŒã³åºããåŸã«ãšã©ãŒãçºçããããšãã»ãŒä¿èšŒãããŸãã
äž»ã«äŸ¿å®äžãæ£ãããã³ãã©ãŒå®£èšãå¿ èŠã§ãã ãã¡ããæžãããšãã§ããããã«ãã®ãããªãã³ãã©ããããŸãïŒ
procedure InterceptedFunc; begin // TODO... end;
ãã ãããã®å Žåãã¢ã»ã³ãã©ãŒã®æ¿å ¥ã䜿çšããŠãåæãšãã©ã¡ãŒã¿ãŒã®æ°ãèæ ®ããŠãåŒã³åºããã©ã¡ãŒã¿ãŒãååŸããåŒã³åºããæ£ããçµäºããå¿ èŠããããŸãã
ã¯ã©ã¹ã¡ãœããã®åœ¢åŒã§å®è£ ãããé¢æ°/ããã·ãŒãžã£ã®ã€ã³ã¿ãŒã»ãã¿ãŒã®å®è£ ã«ã¯ãããããªãã¥ã¢ã³ã¹ããããŸãã
TApplication.MessageBoxãã€ã³ã¿ãŒã»ãããããšããŸãããã
ã€ã³ã¿ãŒã»ãããã³ãã©ãã¯ã©ã¹ã¡ãœãããšããŠå®è£ ãããŠããå Žåããã®å®£èšã¯å ã®é¢æ°ã®ããã«ãªããŸãã
function TTestClas.InterceptedApplicationMessageBox( const Text, Caption: PChar; Flags: Longint): Integer; begin // TODO... end;
ã€ã³ã¿ãŒã»ãã¿ãŒãç¬ç«ããé¢æ°ã§ããå Žåããã®å®è£ ã¯å°ãç°ãªããŸãã
function InterceptedApplicationMessageBox( Self: TObject; const Text, Caption: PChar; Flags: Longint): Integer; begin // TODO... end;
ãã³ãã©ãŒã®å®£èšã«ããããã®ãããªéãã¯ãã¯ã©ã¹ã¡ãœããã®æåã®ãã©ã¡ãŒã¿ãŒãæ瀺çã«å®£èšãããŠããªãå€æ°Selfã§ãããšããäºå®ã«ãããã®ã§ãã
ãšããã§ãããšãã°æ¬¡ã®ããã«ãæåã®ã€ã³ã¿ãŒã»ãã¿ãŒã§ç¹å®ã®å€æ°ã®ã¯ã©ã¹åãååŸããããšãããšã
function TTestClas.InterceptedApplicationMessageBox( const Text, Caption: PChar; Flags: Longint): Integer; begin ShowMessage(Self.ClassName); end;
...次ã«ãTTestClassã§ã¯ãªããTApplicationãšããããã¹ãã衚瀺ãããŸãã Selfãã©ã¡ãŒã¿ãŒã«ã¯ãã€ã³ã¿ãŒã»ãã¿ãŒãå®è£ ãããŠããã¯ã©ã¹ã«é¢ããããŒã¿ã§ã¯ãªããå ã®ã¯ã©ã¹ã«é¢ããããŒã¿ãå«ãŸããŸãã
ååãšããŠãã€ã³ã¿ãŒã»ãããã³ãã©ã®å®£èšã«ã€ããŠç¥ã£ãŠããå¿ èŠãããã®ã¯ããã ãã§ããããã§ãé¢æ°ãã€ã³ã¿ãŒã»ããããããŸããŸãªæ¹æ³ãæ€èšããããšãã§ããŸãã
3.ãŠã£ã³ããŠããã·ãŒãžã£ã®ãµãã¯ã©ã¹å
é·ãéãæè¡çãªéšåãéå§ããå Žæãéžæããæçµçã«ã¯ææžåãããæè¡ã«å°å¿µããããšã«ããŸããã 確ãã«ããªãå¥ã®èªè»¢è»ãçºæããã®ã-ç°¡åã«æ²ããããšãã§ããŸãã
VCLãæ¬è³ªçã«APIã®åãªãã©ãããŒã§ããããšã¯ãããªãã«ãšã£ãŠç§å¯ã§ã¯ãªããšæããŸãã ãã©ãŒã äžã®ã»ãšãã©ã®èŠèŠèŠçŽ ãšãã©ãŒã èªäœã¯ãŠã£ã³ããŠã§ãããä»ã®ãã©ã¡ãŒã¿ãŒã®äžã§ããŠã£ã³ããŠããã·ãŒãžã£ãæã£ãŠããŸãã ããã°ã©ããŒããŠã£ã³ããŠã®æšæºåäœãå€æŽããå¿ èŠãããã¿ã¹ã¯ãæã£ãŠããå Žåããµãã¯ã©ã¹åãé©çšãããŠã£ã³ããŠããã·ãŒãžã£ãã³ãã©ãŒãèªåã®ãã®ã«çœ®ãæããŠãå¿ èŠãªæ©èœãå®è£ ããŸãã
ãã®ææ³ã¯éåžžã«äžè¬çã§ãããDelphiã§ç¬èªã®ã³ã³ãããŒã«ãå®è£ ããå Žåãã»ãšãã©ã®å Žåãã°ããŒãã«TWinControl.MainWndProcãã³ãã©ãŒã§ãã¹ãŠã®ãŠã£ã³ããŠã®ãŠã£ã³ããŠããã·ãŒãžã£ãéè€ããçµæã«ééããŸãã ããã¯ãã¡ãã»ãŒãž+ã¡ãã»ãŒãžå®æ°ãæå®ããããšã§ã³ãŒãå ã®ç¹å®ã®ã¡ãã»ãŒãžããããã¯ããããä»®æ³WndProcããã³DefaultHandlerã§äœæ¥ãããããããšãã§ãããéåžžã«äŸ¿å©ãªãœãªã¥ãŒã·ã§ã³ã§ãã
ãã®ã¡ãœããã®äžè¬çãªèª¬æã¯ã次ã®ãªã³ã¯ã«ãããŸãã ãŠã£ã³ããŠã®ãµãã¯ã©ã¹å
å®è£ ã¢ã«ãŽãªãºã ã¯ã5ã€ã®ãã€ã³ãã®åœ¢åŒã§è¡šãããšãã§ããŸãã
- å ã®ãŠã£ã³ããŠããã·ãŒãžã£ã®ã¢ãã¬ã¹ãååŸãã
- ãã³ãã©ãŒãã¢ã¯ã»ã¹ã§ããå Žæã«ä¿åãã
- æ°ãããŠã£ã³ããŠããã·ãŒãžã£ãã³ãã©ãŒã®å²ãåœãŠ
- ã€ã³ã¿ãŒã»ãã¿ãŒã³ãŒã«ã®åŠçïŒãã°èšé²/ã³ãŒã«ãã©ã¡ãŒã¿ãŒã®å€æŽãªã©ïŒ
- å¿ èŠã«å¿ããŠãå€ããã³ãã©ãŒã®ã¢ãã¬ã¹ãååŸããŠåŒã³åºããŸãã
ã³ãŒãã®åœ¢åŒã§ã¯ããã¹ãŠãéåžžã«åçŽã«èŠããŸãã
unit uSubClass; interface uses Windows, Messages, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} function MainFormSubclassProc(hwnd: THandle; uMsg: UINT; wParam: WPARAM; lParam: WPARAM): LRESULT; stdcall; var OldWndProc: Pointer; begin if uMsg = WM_WINDOWPOSCHANGING then PWindowPos(lParam)^.flags := PWindowPos(lParam)^.flags or SWP_NOSIZE or SWP_NOMOVE; OldWndProc := Pointer(GetWindowLong(hwnd, GWL_USERDATA)); Result := CallWindowProc(OldWndProc, hwnd, uMsg, wParam, lParam); end; procedure TForm1.Button1Click(Sender: TObject); var OldWndProc: THandle; begin OldWndProc := GetWindowLong(Handle, GWL_WNDPROC); SetWindowLong(Handle, GWL_USERDATA, OldWndProc); SetWindowLong(Handle, GWL_WNDPROC, Integer(@MainFormSubclassProc)); MessageBox(Handle, ' ', PChar(Application.Title), MB_ICONINFORMATION); end; end.
ãã®äŸã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ã¡ã€ã³ãã©ãŒã ã®ãŠã£ã³ããŠããã·ãŒãžã£ã眮ãæããããŸãã
å€ãããã·ãŒãžã£ã®ã¢ãã¬ã¹ã¯ãå®æ°GWL_USERDATAãä»ããŠã¢ã¯ã»ã¹ããããŠãŒã¶ãŒãŠã£ã³ããŠãããã¡ãŒã«æ ŒçŽãããŸãã
æ°ããMainFormSubclassProcãã³ãã©ãŒãåŒã³åºããããšãã¡ãã»ãŒãžã³ãŒãããã§ãã¯ãããŸãã ãã®ã¡ãã»ãŒãžããŠã£ã³ããŠã®ãµã€ãºå€æŽãŸãã¯åº§æšã«é¢ãããã®ã§ããå Žåããã©ã°SWP_NOSIZEããã³SWP_NOMOVEãèšå®ããããšã«ããããã®æ©èœããããã¯ãããŸãã
ãã®ã¢ããªã±ãŒã·ã§ã³ãå®è¡ããŠãã¿ã³ãã¯ãªãã¯ããã¡ã€ã³ãã©ãŒã ã®ãµã€ãºãå€æŽããŠã¿ãŠãã ããã ããªãã¯æåããŸããã
å°ããªãã¥ã¢ã³ã¹ ïŒãã®ã³ãŒãã§ã¯ãäºéã®éè€ãã§ãã¯ã¯ãããŸããã ããäžåºŠãã¿ã³ãã¯ãªãã¯ãããšãã¹ã¿ãã¯ãªãŒããŒãããŒã«é¢ãããšã©ãŒãçºçããŸãã ããã¯ããŠã£ã³ããŠããã·ãŒãžã£ã®2çªç®ã®ãªãŒããŒã©ããã§ãå€ãã¢ãã¬ã¹ãåä¿¡ãããšãMainFormSubclassProcãã³ãã©ãŒã®åãã¢ãã¬ã¹ãè¿ããããããCallWindowProcã®æåã®åŒã³åºãã§ç¡éã«ãŒãã«å ¥ãããã§ãã ç§ãã¡ã¯èªåèªèº«ãåŒã³åºãããã®åºå£ã¯ãªãŒããŒãããŒã«ãã£ãŠçºçããŸãã
ã¢ããªã±ãŒã·ã§ã³ ïŒãã®ååãªãã·ã§ã³ã¯ãWindowsã§ã®ã¿äœ¿çšã§ããŸãã ãã€ã¢ãã°ã§ã¯ãå®æ°DWL_DLGPROCã䜿çšããå¿ èŠããããŸãã
ãã®çµæ ãã¢ãã¿ãŒã®æŠå¿µã®ãã¬ãŒã ã¯ãŒã¯å ã§ãå¶åŸ¡ãããé¢æ°ãšããŠã®å€ããŠã£ã³ããŠããã·ãŒãžã£ãå¶åŸ¡ãããé¢æ°ã«éããããã¹ãŠã®ããŒã¿ãã¢ãã¿ãŒããæ°ããMainFormSubclassProcãã³ãã©ãŒãã¢ãã¿ãŒã«ãªããŸãã ãã®äžã§ããã¹ãŠã®ãã©ã¡ãŒã¿ãŒããã°ã«èšé²ããããŒã¿ãåŒã³åºãåã«ããŒã¿ã眮ãæãããããŸã£ããåŒã³åºããªãããšã§å€ããã³ãã©ãŒã®åäœãå¶åŸ¡ããç¬èªã®åäœãå®è£ ã§ããŸãã
æ®å¿µãªããããã®ã³ãŒãã¯ã¢ããªã±ãŒã·ã§ã³ã®ãŠã£ã³ããŠã§ã®ã¿æ©èœããŸãã ãã¡ãããããæ£ç¢ºã«ã¯ãä»ã®äººã®ã¢ããªã±ãŒã·ã§ã³ãããŠã£ã³ããŠãã³ãã«ãååŸããäžèšãšåãæ¹æ³ã§æ°ããã€ã³ã¿ãŒã»ãã¿ãŒãå²ãåœãŠãããšãã§ããŸãããããã¯äœãè¯ãçµæã«ãªããªãããã§ãã ãã®å Žåãã¢ãã¬ã¹ç©ºéã«ããæ°ãããã³ãã©ãŒã®ã¢ãã¬ã¹ã瀺ããŸãããã®ã¢ãã¬ã¹ã®èŠç¥ãã¬äººã«ã¯å®å šã«ç°ãªãã³ãŒãããããŸãïŒãŸãããŸãã¯äžè¬çã«ãã®ã¡ã¢ãªã®äžéšã¯å²ãåœãŠãããªããããããŸããïŒãããã¯å¥ã®ããã»ã¹ã®çªç¶ã®æ»ã«ã€ãªããå¯èœæ§ããããŸãã
ãããé²ãã«ã¯ãäœããã®æ¹æ³ã§ã€ã³ã¿ãŒã»ãã¿ãŒã³ãŒããä»ã®èª°ãã®ããã»ã¹ã«é 眮ãããã®åŸã§ã®ã¿çœ®æãè¡ãå¿ èŠããããŸãã ããã¯ããã€ãã®æ¹æ³ã§è¡ãããŸãããå°ãåŸã§ãããã«çŠç¹ãåœãŠãŸã...
4. VMTããŒãã«ã®ç·šéã«ããååã
ååãšããŠãããã¯ã€ã³ã¿ãŒã»ããã®éåžžã«ãŸããªãªãã·ã§ã³ã§ãããèãããããã¹ãŠã®æ¹æ³ã«ã€ããŠèª¬æããããšã«ããã®ã§ããããèæ ®ããå¿ èŠããããŸãã
ãããããç¹å®ã®ã³ã³ãããŒã«ã®åäœãå®å šã«æºè¶³ã§ããç¶æ³ã«åºããããããšããããŸãããããã§ã¯å°ãæ¬ ããŠããŸãã åé¡ã解決ããã«ã¯ãéåžžã察å¿ããä»®æ³ã¡ãœããããªãŒããŒã©ããããåé¡ã¯ã©ã¹ã«çžç¶äººãèšè¿°ããã³ã³ãããŒã«ã®ç®çã®åäœãèšè¿°ããå¿ èŠããããŸãã ãããããããéåžžã«é 延ããŠããå Žåãããã¯ãå¿ èŠãªã¡ãœãããå€éšãããããã¯ããã ãã§ãç¶æ¿è ãå®è£ ããã«å®çŸã§ããŸãã
次ã®äŸã§ã¯ããã©ãŒã ã®ãµã€ãºãå€æŽããããšãã«åŒã³åºãããTForm.CanResizeã¡ãœããããªãŒããŒã©ã€ãããæ¹æ³ã瀺ããŸãã ã³ãŒãã®ã¿ã¹ã¯ã¯ããã©ãŒã ã®å¹ ã500ãã¯ã»ã«ãè¶ ããŠå€æŽãããªãããã«ããããšã§ãã
ãã¡ããããã®äŸã§ã¯ãæåã«ç®æšãéæããããã«å€æ°ã®ãã€ãã¹ããããOnResizeãã³ãã©ãŒããããã¯ã§ããŸãã次ã«ãCanResizeãTFormãããªãŒããŒã©ããããããããã®å€æŽã¯ãããžã§ã¯ãå ã®ãã¹ãŠã®ãã©ãŒã ã«åœ±é¿ããŸããã圌ãšäŸã¯åœŒã®ã¿ã¹ã¯ã§ããã®æ©äŒã瀺ããŠãã ããã
ã¢ããªã±ãŒã·ã§ã³ ïŒãã®ã€ã³ã¿ãŒã»ãããªãã·ã§ã³ã¯ãä»®æ³ã¯ã©ã¹ã¡ãœããã«ã®ã¿äœ¿çšã§ããç¬èªã®PEãã¡ã€ã«ã®ãã¬ãŒã ã¯ãŒã¯å ã§ã®ã¿äœ¿çšã§ããŸãã ãã®ã³ãŒããã©ã€ãã©ãªã«é 眮ãããã®æ¹æ³ã§ã¡ã€ã³ã¢ããªã±ãŒã·ã§ã³ããã¡ãœãããã€ã³ã¿ãŒã»ããããããšããŠããTFormã¢ããªã±ãŒã·ã§ã³ãšTFormã©ã€ãã©ãªã¯ç°ãªãã¯ã©ã¹ã§ãããããäœãæ©èœããŸããã
ã³ãŒãã¯æ¬¡ã®ãšããã§ãã
unit uVMT; interface uses Windows, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} function NewCanResizeHandler(Self: TObject; var NewWidth, NewHeight: Integer): Boolean; begin Result := True; if NewWidth > 500 then NewWidth := 500; end; procedure TForm1.Button1Click(Sender: TObject); var VMTAddr: PPointer; OldProtect: Cardinal; begin asm mov eax, Self mov eax, [eax] // VMT add eax, VMTOFFSET TForm.CanResize // TForm.CanResize mov VMTAddr, eax end; // VirtualProtect(VMTAddr, 4, PAGE_EXECUTE_READWRITE, OldProtect); try // VMTAddr^ := @NewCanResizeHandler; finally // VirtualProtect(Pointer(VMTAddr), 4, OldProtect, OldProtect); FlushInstructionCache(GetCurrentProcess, VMTAddr, 4); end; if Width > 500 then Width := 500; MessageBox(Handle, ' 500 ', PChar(Application.Title), MB_ICONINFORMATION); end; end.
ãã詳现ã«ïŒ
1.ååãã³ãã©ãŒã®å®£èšã¯ããã®èšäºã®2çªç®ã®ã»ã¯ã·ã§ã³ã§èª¬æãããã¥ã¢ã³ã¹ãèæ ®ããŠè¡ãããŸããïŒSelfãã©ã¡ãŒã¿ãŒã衚瀺ãããŸããïŒã
2. Delphiãã«ãã§èª¬æãããŠãããææžåãããVMTOFFSETãã£ã¬ã¯ãã£ããã€ã³ã¿ãŒã»ããã«äœ¿çšãããŸãã
ããã«åœŒå¥³ã®èª¬æã®ããéšåããããŸãïŒ
è¿œå ã®2ã€ã®ãã£ã¬ã¯ãã£ãã«ãããã¢ã»ã³ããªã³ãŒãã¯åçã¡ãœãããšä»®æ³ã¡ãœããã«ã¢ã¯ã»ã¹ã§ããŸãïŒVMTOFFSETãšDMTINDEXã
VMTOFFSETã¯ãä»®æ³ã¡ãœããããŒãã«ïŒVMTïŒã®å é ãããä»®æ³ã¡ãœããåŒæ°ã®ä»®æ³ã¡ãœãããã€ã³ã¿ãŒããŒãã«ãšã³ããªã®ãªãã»ããããã€ãåäœã§ååŸããŸãã ãã®ãã£ã¬ã¯ãã£ãã«ã¯ãTExample.VirtualMethodãªã©ãã¡ãœããåããã©ã¡ãŒã¿ãŒãšããŠå«ãå®å šã«æå®ãããã¯ã©ã¹åãå¿ èŠã§ãã
説æããæãããªããã«ããã®ã¿ã¹ã¯ã¯ãä»®æ³ã¡ãœããããŒãã«ïŒVMTïŒã®å é ã«å¯Ÿããä»®æ³ã¡ãœããã®ã¢ãã¬ã¹ãžã®ãªãã»ãããè¿ãããšã§ãã VMTããŒãã«ã®éå§ã¯ãSelfãã©ã¡ãŒã¿ãŒã«ãã£ãŠçŽæ¥ç€ºãããŸãã ã€ãŸãããããã³ãŒãã®åœ¢åŒã§è¡šããšã次ã®ããã«ãªããŸãã
VMT := Pointer(Self)^;
3.ã¢ã»ã³ãã©ã䜿çšããŠã¡ãœããã®ã¢ãã¬ã¹ãžã®ãã€ã³ã¿ãæ¿å ¥ãããšãä»®æ³ã¡ãœããã®æ°ãããã³ãã©ã®ã¢ãã¬ã¹ã«çœ®ãæããããŸãã
4.眮æã¯ãéåžžã¯æžã蟌ã¿æš©éã®ãªãã¡ã¢ãªããŒãžã«ããã¢ããªã±ãŒã·ã§ã³ã³ãŒãã§è¡ãããããïŒéåžžããããã¯èªã¿åãæš©ãšå®è¡æš©ã§ãïŒãæžã蟌ã¿æš©éã¯æ°ãããã³ãã©ãŒã®äºçŽåã«èšå®ãããŸãã
ããŠãäŸãå®è¡ããŠãã®åäœã確èªããŠãã ããã
ã芧ã®ãšãããå®éã«ã¯ãæåã®äŸãšã»ãŒåãæé ããã¹ãŠå®è¡ããŸããã ç£èŠãããŠããé¢æ°ã®ã¢ãã¬ã¹ãåãåããå ã®ã¡ãœããã®ãã©ã¡ãŒã¿ãŒã管çãããŠããæ°ãããã³ãã©ãŒã®ã¢ãã¬ã¹ã«çœ®ãæããŸãã å ã®ãã³ãã©ãŒïŒ inheritedã®ã¢ããã°ïŒãåŒã³åºãã³ãŒããæäŸããŸããã ããã«ããããããããã®ååæ¹æ³ã¯ãèŠéãåºããããã ãã«ç€ºãããŠãããæŠéã¢ããªã±ãŒã·ã§ã³ã§ã®å®è£ ã«ã¯éåžžã«æãŸãããããŸããã
VMTã®ç·šéã®ååãç解ããã®ãé£ããå Žåã¯ã Hallvard Vassbotnã«ãããã®èšäºãèªãããšããå§ãããŸããã¡ãœããã¯ã³ã³ãã€ã©ãŒå®è£ ãåŒã³åºããŸãã
ãŸãã¯ã Alexander Alekseevã芪åã«æäŸããç¿»èš³ïŒ ã³ã³ãã€ã©ã«ããã¡ãœããåŒã³åºãã®å®è£ ã
åçã¯ã©ã¹ã¡ãœãããã€ã³ã¿ãŒã»ãããããªãã·ã§ã³ã«ã€ããŠã¯æ€èšããŸããããååã¯ã»ãŒåãã§ãã
5.ã€ã³ããŒãããŒãã«ã®ç·šéã«ããåå
ã€ã³ããŒãããŒãã«ãšã¯äœã§ããã ã¢ããªã±ãŒã·ã§ã³ãäœæããé¢æ°ã®APIãåŒã³åºããšãã¢ããªã±ãŒã·ã§ã³ã¯äœããã®æ¹æ³ã§ãã®é¢æ°ã®ã¢ãã¬ã¹ãèšç®ããŠãå¶åŸ¡ã転éããå¿ èŠããããŸãã ã»ãšãã©ã®é¢æ°ã¯ãããšãã°æ¬¡ã®ããã«éçã«å®£èšãããŸãã
{$EXTERNALSYM MessageBox} function MessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall; ... function MessageBox; external user32 name 'MessageBoxA';
ããã¯ãMessageBoxé¢æ°ã®åŒã³åºãã®å®å šãªå®£èšãšãããåŒã³åºãåæãæ瀺çã«ç€ºããŸãã ãã®æ å ±ã¯ãã³ã³ãã€ã©ãŒãé¢æ°ãåŒã³åºããšãã«ã¹ã¿ãã¯ãé©åã«èª¿æŽããããã«å¿ èŠã§ãã ãŸããé¢æ°ãå®è£ ãããŠããã©ã€ãã©ãªã®ååãšãšã¯ã¹ããŒããããã©ã€ãã©ãªã®ååã瀺ããŸãã
ã芧ã®ãšãããé¢æ°ã®ã¢ãã¬ã¹ã¯ããã«ãããŸãããé¢æ°ããšã¯ã¹ããŒãããã©ã€ãã©ãªã¯ä»»æã®ã¢ãã¬ã¹ã«ããŒãã§ããã»ãšãã©ã®å Žåãåããã»ã¹ã§åãé¢æ°ã®ã¢ãã¬ã¹ãç°ãªããããé¢æ°ã®ã¢ãã¬ã¹ã¯ãããŸããã 確ãã«ãããã«ã¯ããããªãã¥ã¢ã³ã¹ããããŸããuser32.dllãkernel32.dllãããã³ntdll.dllã©ã€ãã©ãªã¯ããã¹ãŠã®ããã»ã¹ã«å¯ŸããŠåºå®ã¢ãã¬ã¹ïŒå°ãªããšã32ãããã·ã¹ãã ïŒã§ããŒããããŸããããšã«ããç¹å®ã®éçã¢ãã¬ã¹ã«äŸåããªãã§ãã ããã
ã¢ããªã±ãŒã·ã§ã³ãã³ã³ãã€ã«ãããšãéçã«å®£èšãããé¢æ°ã«é¢ããæ å ±ãã€ã³ããŒãããŒãã«ã®æ¬äœã«é 眮ãããŸãã ã¢ããªã±ãŒã·ã§ã³ãèµ·åããããšãããŒããŒã¯ãã®ããŒãã«ãåæããããã«ç€ºãããŠããã©ã€ãã©ãªãããŒãããã©ã€ãã©ãªãšã¯ã¹ããŒãããŒãã«ã«åºã¥ããŠãã¢ããªã±ãŒã·ã§ã³ã€ã³ããŒãããŒãã«ã®å¯Ÿå¿ãããã£ãŒã«ãã«é 眮ãããŠããé¢æ°ã®å®éã®ã¢ãã¬ã¹ãèŠã€ããŸãã
ã€ã³ããŒãããŒãã«ãã©ã®ããã«æ©èœãããã«ã€ããŠã®äžè¬çãªèª¬æã¯ãMatt Pitrekã®èšäºã Peering Inside the PEïŒA Tour of the Win32 Portable Executable File Formatãã«ãããŸãã
ãªããžã§ã¯ããã¡ã€ã«ã®REããã³COFF圢åŒã® RSDNã§ç¿»èš³ãå©çšã§ããŸã ã
ããã«æ å ±ãå¿ èŠãªå Žåã¯ã次ã®èšäºãã芧ãã ããïŒ PEã ã¬ãã¹ã³6. Iczelionã«èµ·å ããã€ã³ããŒãããŒãã« ã
ãã®æ å ±ã§äœãã§ããã®ã§ããããïŒ ã€ã³ã¿ãŒã»ãããã³ãã©ãŒãå²ãåœãŠãã®ã¯ç°¡åã§ããããŒããŒã«ãã£ãŠèšç®ãããã¢ãã¬ã¹ããã³ãã©ãŒã®ã¢ãã¬ã¹ã«å€æŽããã ãã§ããã®åŸã€ã³ã¿ãŒã»ããã¯æå¹ãšèŠãªãããŸãã
ã¢ããªã±ãŒã·ã§ã³ ïŒãã®ã€ã³ã¿ãŒã»ãããªãã·ã§ã³ã¯ãéçãªã³ã¯ã®ããAPIé¢æ°ã«ã®ã¿äœ¿çšãããŸãã
å ã®é¢æ°ã®ã¢ãã¬ã¹ãæ€çŽ¢ããã€ã³ã¿ãŒã»ãã¿ãŒã®ã¢ãã¬ã¹ã«çœ®ãæããã«ã¯ã次ã®é¢æ°ãèšè¿°ããŸãã
function ReplaceIATEntry(const OldProc, NewProc: FARPROC): Boolean; var ImportEntry: PImageImportDescriptor; Thunk: PImageThunkData; Protect: DWORD; ImageBase: Cardinal; DOSHeader: PImageDosHeader; NTHeader: PImageNtHeaders; begin Result := False; if OldProc = nil then Exit; if NewProc = nil then Exit; ImageBase := GetModuleHandle(nil); // DOSHeader := PImageDosHeader(ImageBase); NTHeader := PImageNtHeaders(DWORD(DOSHeader) + DWORD(DOSHeader^._lfanew)); ImportEntry := PImageImportDescriptor(DWORD(ImageBase) + DWORD(NTHeader^.OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); // ... while ImportEntry^.Name <> 0 do begin Thunk := PImageThunkData(DWORD(ImageBase) + DWORD(ImportEntry^.FirstThunk)); // ... ... while Pointer(Thunk^._function) <> nil do begin // ... . if Pointer(Thunk^._function) = OldProc then begin // if VirtualProtect(@Thunk^._function, SizeOf(DWORD), PAGE_EXECUTE_READWRITE, Protect) then try // ... //Thunk^._function := DWORD(NewProc); // ... . InterlockedExchange(Integer(Thunk^._function), Integer(NewProc)); Result := True; finally VirtualProtect(@Thunk^._function, SizeOf(DWORD), Protect, Protect); FlushInstructionCache(GetCurrentProcess, @Thunk^._function, SizeOf(DWORD)); end; end else Inc(PAnsiChar(Thunk), SizeOf(TImageThunkData32)); end; ImportEntry := Pointer(Integer(ImportEntry) + SizeOf(TImageImportDescriptor)); end; end;
GetModuleHandleïŒnilïŒã€ã¡ãŒãžããŒã¹ã³ãŒãã瀺ãããã«ãçŸåšã®å®è¡å¯èœãã¡ã€ã«ã®æ¬æã®ã€ã³ããŒãããŒãã«ãä¿®æ£ããŸãã ã€ã³ã¿ãŒã»ãã¿ãŒã¢ãã¬ã¹ã®çŽæ¥èšå®ã¯ãInterlockedExchangeãåŒã³åºãããšã§ã¢ãããã¯ã«å®è¡ãããŸãã ããã¯ããªãããªã±ãŒããªãã€ã³ãã§ãããã€ã³ã¿ãŒã»ãã¿ãŒã®ã¢ãã¬ã¹ãå€æŽãããã®ç¹å®ã®æ¹æ³ã®çç±ã«ã€ããŠã¯å°ãåŸã§æ¢ããŸãã
ãã®é¢æ°ãåŒã³åºãäŸãæžãã ãã§ãã
æ°ãããããžã§ã¯ããäœæããã¡ã€ã³ãã©ãŒã ã«ãã¿ã³ãé 眮ããReplaceIATEntryé¢æ°ã®å®è£ ãèšè¿°ããŠããã次ã®ã³ãŒããè¿œå ããŸãã
var OrigAddr: Pointer = nil; function InterceptedMessageBoxA(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; type TOrigMessageBoxA = function(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var S: AnsiString; begin S := AnsiString('Function interepted. Original message: ' + lpText); Result := TOrigMessageBoxA(OrigAddr)(Wnd, PAnsiChar(S), lpCaption, uType); end; procedure TForm1.FormCreate(Sender: TObject); begin OrigAddr := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); ReplaceIATEntry(OrigAddr, @InterceptedMessageBoxA); end; procedure TForm1.Button1Click(Sender: TObject); begin MessageBoxA(0, 'Test Message', nil, 0); end;
ããã§ã¯ããã©ãŒã ã³ã³ã¹ãã©ã¯ã¿ãŒãMessageBoxAé¢æ°ã®ã€ã³ã¿ãŒã»ãããèšå®ããã€ã³ã¿ãŒã»ããã®æäœã瀺ãããã«ãã¿ã³ãã³ãã©ãŒã§MessageBoxAåŒã³åºããè¡ãããŸãã
ã€ã³ã¿ãŒã»ãããã³ãã©ãŒèªäœã¯éåžžã«åçŽã§ãã ã€ã³ããŒãããŒãã«ã®ãšã³ããªã®ã¿ãå€æŽãããå ã®é¢æ°ã®æ¬äœã¯ä¿®æ£ãããŠããªããããå ã®é¢æ°ã«å¶åŸ¡ã移ãã«ã¯ãOrigAddrå€æ°ã«æ ŒçŽãããŠããé¢æ°ã®ä»¥åã«æ ŒçŽãããã¢ãã¬ã¹ãåŒã³åºãã ãã§ååã§ãã
å°ããªãã¥ã¢ã³ã¹ããããŸã ïŒ
éçé¢æ°ã¯ãé 延ã€ã³ããŒãã»ã¯ã·ã§ã³ã«ãããŸãã ãã®å®£èšã¯éåžžã«ç°¡åã§ãããµã³ãã«ã³ãŒãã次ã®ããã«å°ãå€æŽããŠã¿ãŸãããã
function DelayedMessageBoxA(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; external user32 name 'MessageBoxA' delayed; procedure TForm1.Button1Click(Sender: TObject); begin DelayedMessageBoxA(0, 'Test Message', nil, 0); end;
DelayedMessageBoxAé¢æ°ã¯ãå®éã«ã¯åãMessageBoxAã§ãã
ãã ããã delayed ããã©ã¡ãŒã¿ãŒã¯ãdelayed importã»ã¯ã·ã§ã³ã§ãã®é¢æ°ã®åŒã³åºããèšé²ããŸãã
ãã¥ã¢ã³ã¹ ïŒã é 延 ããã©ã¡ãŒã¿ã¯ãDelphiã®ä»¥åã®ããŒãžã§ã³ã§ã¯äœ¿çšã§ããªãããããã®èšäºã®ãã¢äŸã§ã¯ããã®ã³ãŒãã¯èŠã€ãããŸããã
äžèšã§å®è£ ãããã€ã³ã¿ãŒã»ãã¿ãŒã¯ã€ã³ããŒãããŒãã«ã§ã®ã¿å€æŽãè¡ãããããã®æ¹æ³ã§å®£èšãããé¢æ°åŒã³åºãã¯å¶åŸ¡ãããŸããã ãããè¡ãã«ã¯ãIMAGE DIRECTORY_ENTRY DELAYED IMPORTãç·šéããå¿ èŠããããŸãã
ãã®èšäºã§ã¯ãé 延ã€ã³ããŒãã®ããŒãã«ãç·šéãããªãã·ã§ã³ãèæ ®ããŠããŸãããååãšããŠãèå³æ·±ãããšã¯äœããããŸãããååã¯åŸæ¥ã®ã€ã³ããŒããšåãã§ããããã«ç°ãªãæ§é ã䜿çšãããŸãã ïŒèå³ã®ããæ¹ã¯ããã®ã€ã³ã¿ãŒã»ãã¿ãŒã®å®è£ ã宿é¡ãšèŠãªããŸã:)ã
6.ãšã¯ã¹ããŒãããŒãã«ã®ç·šéã«ããååã
ã€ã³ããŒãããŒãã«ãšé 延ã€ã³ããŒãã®ç·šéã¯ãéçã«å®£èšãããé¢æ°ã«ã¯é©ããŠããŸãããåçãªå®£èšãšé¢æ°åŒã³åºãã«å¯ŸããŠã¯æ©èœããŸããã
å¹³æãªèšèªã®å Žåãåã®äŸã«å¥ã®ãã¿ã³ãè¿œå ããŠããã³ãã©ãŒã«æ¬¡ã®ã³ãŒããèšè¿°ããŠãã ããã
procedure TForm1.Button2Click(Sender: TObject); type TOrigMessageBoxA = function(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var OrigMessageBoxA: TOrigMessageBoxA; begin @OrigMessageBoxA := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); OrigMessageBoxA(0, 'Test Message', nil, 0); end;
ãã¿ã³ãæŒããšãã€ã³ã¿ãŒã»ãã¿ãŒãæ©èœããªãã£ãããšãããããŸãã å®éã®ãšãããGetProcAddressé¢æ°ã¯ãã€ã³ããŒãããŒãã«ããã€ãã¹ããŠé¢æ°ã®ã¢ãã¬ã¹ãåãåããã©ã€ãã©ãªãšã¯ã¹ããŒãããŒãã«ã«çŠç¹ãåœãŠãããšã«ãªã£ãŠããŸãã
äžèšã®ã¡ãœããã«ãã£ãŠåŒã³åºãããé¢æ°ã«ã€ã³ã¿ãŒã»ãããã³ãã©ãŒã匷å¶çã«å¿çãããã«ã¯ãå¿ èŠãªã©ã€ãã©ãªã®ãšã¯ã¹ããŒãããŒãã«ãçŽæ¥å€æŽããå¿ èŠããããŸãã
ç°¡åã«èšãã°ããšã¯ã¹ããŒãããŒãã«ã«ã¯ãPEãã¡ã€ã«ã«ãã£ãŠãšã¯ã¹ããŒããããé¢æ°ããã®ååãã€ã³ããã¯ã¹ïŒåºæ°ïŒãããã³é¢æ°ã®ã¢ãã¬ã¹ã«é¢ããæ å ±ãå«ãŸããŠããŸããäžéšã®é¢æ°ã¯ã€ã³ããã¯ã¹ã«ãã£ãŠã®ã¿ãšã¯ã¹ããŒããããååã¯ãããŸããããã®ãããªå Žåããããã®é¢æ°ãžã®ã¢ã¯ã»ã¹ã¯ã€ã³ããã¯ã¹ãä»ããŠã®ã¿è¡ãããŸãã
ãšã¯ã¹ããŒãããŒãã«ã®äœæ¥ã®äžè¬çãªèª¬æã¯ãMatt Pitrekã«ããåãèšäºã«ãããŸãã
ããã«æ å ±ãå¿ èŠãªå Žåã¯ã次ã®èšäºãã芧ãã ããïŒ
PEãã¬ãã¹ã³7. Iczelionã«èµ·å ããããŒãã«ã®ãšã¯ã¹ããŒãã
ã¢ããªã±ãŒã·ã§ã³ïŒãã®ã€ã³ã¿ãŒã»ãããªãã·ã§ã³ã¯ãåçã«åŒã³åºãããAPIé¢æ°ã«ã®ã¿äœ¿çšãããŸãã
次ã®äŸã¯ãã€ã³ã¿ãŒã»ãã¿ãŒã®ã¢ãã¬ã¹ãèšå®ããé¢æ°ã®ããããªå€æŽãé€ããŠãå®éã«ã¯åã®äŸãšå€ãããŸãããå®éã«ã¯ã³ãŒãèªäœïŒ
unit uEAT; interface uses Windows, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} uses DeclaredTypes; function ReplaceEATEntry(const DllName: string; OldProc, NewProc: FARPROC): Boolean; var ImageBase: Cardinal; DOSHeader: PImageDosHeader; NTHeader: PImageNtHeaders; ExportDirectory: PImageExportDirectory; pFuntionAddr: PDWORD; OrdinalCursor: PWORD; Ordinal, Protect: DWORD; FuntionAddr: FARPROC; I: Integer; begin Result := False; if OldProc = nil then Exit; if NewProc = nil then Exit; ImageBase := GetModuleHandle(PChar(DllName)); // DOSHeader := PImageDosHeader(ImageBase); NTHeader := PImageNtHeaders(DWORD(DOSHeader) + DWORD(DOSHeader^._lfanew)); ExportDirectory := PImageExportDirectory(DWORD(ImageBase) + DWORD(NTHeader^.OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)); I := 1; // OrdinalCursor := Pointer(ImageBase + DWORD(ExportDirectory^.AddressOfNameOrdinals)); while I < Integer(ExportDirectory^.NumberOfNames) do begin // Ordinal := OrdinalCursor^; // FuntionAddr := Pointer(ImageBase + DWORD(ExportDirectory^.AddressOfFunctions)); FuntionAddr := Pointer(ImageBase + PDWORD(DWORD(FuntionAddr) + Ordinal * 4)^); // , ? if FuntionAddr = OldProc then begin // , , pFuntionAddr := PDWORD(ImageBase + DWORD(ExportDirectory^.AddressOfFunctions) + Ordinal * 4); // hInstance NewProc := Pointer(DWORD(NewProc) - ImageBase); // if VirtualProtect(pFuntionAddr, SizeOf(DWORD), PAGE_EXECUTE_READWRITE, Protect) then try // ... //pFuntionAddr^ := Integer(NewProc); // ... . InterlockedExchange(Integer(PImageThunkData(pFuntionAddr)^._function), Integer(NewProc)); Result := True; finally VirtualProtect(pFuntionAddr, SizeOf(DWORD), Protect, Protect); FlushInstructionCache(GetCurrentProcess, pFuntionAddr, SizeOf(DWORD)); end; Break; end; Inc(I); Inc(OrdinalCursor); end; end; var OrigAddr: Pointer = nil; function InterceptedMessageBoxA(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; type TOrigMessageBoxA = function(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var S: AnsiString; begin S := AnsiString('Function interepted. Original message: ' + lpText); Result := TOrigMessageBoxA(OrigAddr)(Wnd, PAnsiChar(S), lpCaption, uType); end; procedure TForm1.FormCreate(Sender: TObject); begin OrigAddr := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); ReplaceEATEntry(user32, OrigAddr, @InterceptedMessageBoxA); end; procedure TForm1.Button1Click(Sender: TObject); type TOrigMessageBoxA = function(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var OrigMessageBoxA: TOrigMessageBoxA; begin @OrigMessageBoxA := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); OrigMessageBoxA(0, 'Test Message', nil, 0); end; end.
ã€ã³ããŒãããŒãã«ãç·šéããå Žåã®ããã«ãé¢æ°æ¬äœã¯å€æŽãããŸããããããã£ãŠãå ã®ã³ã³ãããŒã«ãå¶åŸ¡ããã«ã¯ãå€ãã¢ãã¬ã¹ãåŒã³åºãã ãã§ååã§ãã
7.é¢æ°ãšã³ããªãã€ã³ãã®ã¹ãã©ã€ã·ã³ã°ã€ã³ã¿ãŒã»ããã
ã¹ãã©ã€ã·ã³ã°ã¯ãã€ã³ã¿ãŒã»ãããèšå®ããæãå¹ççãªæ¹æ³ã§ããããã¯ãã€ã³ã¿ãŒã»ãããããé¢æ°ã®éå§æã«ãã€ã³ã¿ãŒã»ãããã³ãã©ãŒãžã®ç§»è¡ã®asmã³ãŒãã5ã6ïŒãŸãã¯ãã以äžïŒãã€ãã®ãµã€ãºã«èšå®ãããŠãããšããäºå®ããæããŸãã以åã®ã€ã³ã¿ãŒã»ãã¿ãŒã®ã€ã³ã¹ããŒã«ãªãã·ã§ã³ãšã¯ç°ãªãããã®æ¹æ³ã¯ã©ã®ç°å¢ã§ã䜿çšã§ããŸããéçãä»®æ³ãåçã¯ã©ã¹ã¡ãœãããAPIé¢æ°ãããã³åºæ¬çã«ã¯ãã¹ãŠãã€ã³ã¿ãŒã»ããã§ããŸããïŒ
ã¹ãã©ã€ã·ã³ã°ã䜿çšããå ŽåãAPIé¢æ°ã®å®£èšæ¹æ³ãéçãŸãã¯åçã«åŒã³åºãããããšã¯é¢ä¿ãããŸãããé¢æ°æ¬äœã®å é ã§ãã€ã³ã¿ãŒã»ããã³ãŒããåŒã³åºãããã£ããããŸãã
確ãã«ããããã¯ãã¹ãŠãã®æ¹æ³ã®å©ç¹ã§ããããã€ãã¹ãå§ãŸããŸãã
ãŸããé¢æ°ã®æ¬äœãå€æŽãããã€ã³ã¿ãŒã»ãã·ã§ã³ãã³ãã©ãŒããå ã®é¢æ°ãåŒã³åºãããã«ãæåã«è©°ãŸã£ããã€ãã埩å ããå¿ èŠããããŸããå®è¡ãå®äºããããã€ã³ã¿ãŒã»ããasmã³ãŒãããã®å Žæã«è¿ããŸãã
次ã«ãã€ã³ã¿ãŒã»ããã³ãŒããåé€ãããæç¹ã§ãå¶åŸ¡ãããé¢æ°ãå¥ã®ã¹ã¬ããããåŒã³åºãããšãã§ãããã®åŒã³åºãããã¬ãŒã¹ã§ããŸããã
第äžã«ãããã«æªãããšãèµ·ããå¯èœæ§ããããŸã-ã€ã³ã¿ãŒã»ããã³ãŒãã埩å ãŸãã¯åé€ããŠé¢æ°ããããŒãå€æŽããæç¹ã§ãå¥ã®ã¹ã¬ããããå¶åŸ¡ãããé¢æ°ãåŒã³åºãããšãã§ããŸãã 5ãã€ã以äžãæžã蟌ãããšã¯ã¢ãããã¯æäœã§ã¯ãªããããããæç¹ã§ãéåžžã®ã³ãŒãã§ã¯ãªãããŽããé¢æ°ã®å é ã«ãããŸãããã®çµæããã®å ŽåãåŒã³åºãå ã®ã¹ã¬ããã®åŽ©å£ãçºçããå¯èœæ§ããããŸããéåžžã®asmã³ãŒãã®ä»£ããã«ãã¬ããŒãžã³ãŒããå®è¡ãããŸãã
å Žåã«ãã£ãŠã¯ããã®åäœãåé¿ã§ããŸãããããã«ã€ããŠã¯åŸã§è©³ãã説æããŸãã
ã€ã³ã¿ãŒã»ããã³ãŒãèªäœã«ã€ããŠå°ã説æããŸããã€ãŸããã©ãããæ¥ãã®ã§ããããã
asmã€ã³ã¿ãŒã»ããã³ãŒããåœä»€ã®å é ã«èšè¿°ããŠããããšãã°ãJMP 100ããšããè¡ãããã«èšè¿°ããããšã«ã¯ãªããŸãããããã»ããµãŒã¯ã¢ã»ã³ãã©ãŒã«ã€ããŠã¯äœãç¥ããŸãããããã·ã³ã³ãŒãã«ã€ããŠã¯ç¥ã£ãŠããŸãããããã£ãŠãéçºè ã¯ã䜿çšããã€ã³ã¿ãŒã»ãã¿ãŒã®å ·äœçãªèšèšã決å®ããåŸããããããã»ããµãŒãç解ã§ãããã·ã³ã³ãŒãã«å€æããå¿ èŠããããŸããããã¯ãé¢æ°ã®å é ã«é 眮ãããŸãã
å®éãããªãè€éã«èãããŸãããããã¯ãããããã®ãšåããããç°¡åã§ãããã®ããã«ãã€ã³ãã«ã®ããã¥ã¢ã«ã圹ç«ã¡ãŸãããã®ããã¥ã¢ã«ãããã€ã³ã¿ãŒã»ãã¿ãŒã§å¿ èŠãªã·ãŒã±ã³ã¹ãçæããããã«äœ¿çšãããåœä»€ã®ãªãã³ãŒããèŠã€ããããšãã§ããŸãã asm insertã«å¿ èŠãªã³ãŒããæžãã ãã§ãã³ã³ãã€ã©ãŒãç§ã®ããã«çæãããã·ã³ã³ãŒãã®çš®é¡ã確èªããã ãã§ãããã«ç°¡åã«ãªããŸãã
å®å šã«æ確ã§ãªãå Žåã¯ãæãäžè¬çãªã€ã³ã¿ãŒã»ãã¿ãŒãªãã·ã§ã³ã®ããã€ããèŠãŠã¿ãŸãããã
1. JMP NEAR OFFSET
5ãã€ãã®åœä»€ãæåã®ãã€ãã¯JMP NEAR rel32åœä»€ã®ãªãã³ãŒãã§ãã$ E9ã§ããæ®ãã®4ã€ã¯OFFSETãã©ã¡ãŒã¿ãŒã§ãã
OFFSETã¯ã次ã®åŒã«åŸã£ãŠèšç®ãããŸããOFFSET = DestinationAddr-CurrentAddr-åœä»€ãã·ã³ã®ã³ãŒããµã€ãº
DestinationAddrã¯ã€ã³ã¿ãŒã»ãããã³ãã©ã®ã¢ãã¬ã¹ã§ã
CurrentAddrã¯ãJMP NEAR OFFSETåœä»€ãé 眮ãããã¢ãã¬ã¹
ã§ããã³ãŒãã®åœ¢åŒã¯æ¬¡ã®ããã«ãªããŸãã
procedure SliceNearJmp(OldProc, NewProc: FARPROC); var SpliceRec: packed record JmpOpcode: Byte; Offset: DWORD; end; Tmp: DWORD; begin SpliceRec.JmpOpcode := $E9; SpliceRec.Offset := DWORD(NewProc) - DWORD(OldProc) - SizeOf(SpliceRec); VirtualProtect(OldProc, SizeOf(SpliceRec), PAGE_EXECUTE_READWRITE, OldProtect); Move(SpliceRec, OldProc^, SizeOf(SpliceRec)); VirtualProtect(OldProc, SizeOf(SpliceRec), OldProtect, OldProtect); end;
2. PUSH ADDR + RET
6ãã€ãåœä»€ãæåã®ãã€ãã¯$ 68ã§ãããã¯PUSH imm32åœä»€ã®ãªãã³ãŒãã§ãã次ã®4ãã€ãã¯ADDRãã©ã¡ãŒã¿ãŒã§ãã
ã€ãŸãããã®äžé£ã®æ瀺ã¯ç°¡åã«æ©èœããŸããæåã®PUSHåœä»€ã¯ADDRãžã£ã³ãã¢ãã¬ã¹ãã¹ã¿ãã¯ã«ããã·ã¥ãã2çªç®ã®RETåœä»€ã¯ã¹ã¿ãã¯ã®å³åŽã«ããæå®ãããã¢ãã¬ã¹ã«ãžã£ã³ãããŸãã
ã³ãŒãã®åœ¢åŒã§ã¯ã次ã®ããã«ãªããŸãã
procedure SlicePushRet(OldProc, NewProc: FARPROC); var SpliceRec: packed record PushOpcode: Byte; Offset: FARPROC; RetOpcode: Byte; end; begin SpliceRec.PushOpcode := $68; SpliceRec.Offset := NewProc; SpliceRec.RetOpcode := $C3; VirtualProtect(OldProc, SizeOf(SpliceRec), PAGE_EXECUTE_READWRITE, OldProtect); Move(SpliceRec, OldProc^, SizeOf(SpliceRec)); VirtualProtect(OldProc, SizeOf(SpliceRec), OldProtect, OldProtect); end;
ååãšããŠãäž¡æ¹ã®ãªãã·ã§ã³ã«ã¯çåœæš©ãããããã䜿çšãããŸããããããäž¡æ¹ãšãå®å šã§ã¯ãããŸããã
MOV EAXãADDR + JMP EAXãšãã2ã€ã®åœä»€ã®ã€ã³ã¿ãŒã»ãã¿ãŒããªã¢ã³ãããããŸãããã®7ãã€ãã®æ§é ã¯ãFASTCALLèŠåã䜿çšããŠé¢æ°ãã€ã³ã¿ãŒã»ããããããã«äœ¿çšããå Žåãé©åãªãœãªã¥ãŒã·ã§ã³ã§ã¯ãããŸãããäºå®ãDelphiã§ã¯ãã®åæãããã©ã«ãã§äœ¿çšããããã®ç¹åŸŽã¯ãé¢æ°ã®æåã®3ã€ã®ãã©ã¡ãŒã¿ãŒãã¬ãžã¹ã¿EAXãECXãããã³EDXã«é 眮ãããããšã§ãããã®ã¿ã€ãã®ã€ã³ã¿ãŒã»ãã¿ãŒãé©çšãããšãEAXã¬ãžã¹ã¿ãŒã«å ¥ããã©ã¡ãŒã¿ãŒã¯äžæžããããŸãããããã£ãŠããã®ãªãã·ã§ã³ã¯èæ ®ããŸããã
次ã«ããã®ãããªã€ã³ã¿ãŒã»ãã¿ãŒã䜿çšããããšã®å®å šæ§ã«ã€ããŠèª¬æããŸããã€ã³ã¿ãŒã»ããããé¢æ°ãHotPatchã¡ã«ããºã ã䜿çšããªãããšã確å®ãªå Žåã«ã®ã¿ãã€ã³ã¿ãŒã»ããã«äžèšã®2ã€ã®ãªãã·ã§ã³ã䜿çšããããšããå§ãããŸãã
äºå®ãã¬ãã¢ã³ãã®ã¹ã¿ããã¯ããšã³ããªãã€ã³ãã®æ¥ç¶ãããå®å šã«ããããã®å°ããªæãç©ŽãæäŸããŠãããŸããããããŠãã¯ãããHotPatchããšåŒã°ã
ãŸã:) èŠããã«ãéã¢ã»ã³ãã©ãŒã§MSããã©ã€ãã©ãªãéããšãåAPIé¢æ°ã®æ¬äœã®åã«5ã€ã®NOPåœä»€ããããé¢æ°æ¬äœã¯äœãããªãMOV EDIãEDIïŒããã«ãã€ãPUSH xxxïŒ
æåã®5ã€ã®åœä»€ã®ãµã€ãºã«ããã代ããã«JMP NEAR OFFSETåœä»€ã³ãŒããèšè¿°ããããšãã§ããŸããããã«ãèšé²æã«ã¯ãé¢æ°èªäœã¯å€æŽãããŸããããã®åœä»€ãèšè¿°ããåŸãé¢æ°ã®æåã®2ãã€ããã¢ãããã¯ã«å€æŽãã代ããã«JMP SHORT -7åœä»€ã®2ãã€ãã®ãã·ã³ã³ãŒãïŒ$ EBãš$ F9ãã€ãïŒãè¿œå ã§ããŸãã
HotPachã®ãµã³ãã«ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
procedure SliceHotPath(OldProc, NewProc: FARPROC); var SpliceRec: packed record JmpOpcode: Byte; Offset: DWORD; end; NopAddr: Pointer; OldProtect: DWORD; begin SpliceRec.JmpOpcode := $E9; NopAddr := PAnsiChar(OldProc) - SizeOf(SpliceRec); SpliceRec.Offset := DWORD(NewProc) - DWORD(NopAddr) - SizeOf(SpliceRec); VirtualProtect(NopAddr, 7, PAGE_EXECUTE_READWRITE, OldProtect); Move(SpliceRec, NopAddr^, SizeOf(SpliceRec)); asm mov ax, $F9EB mov ecx, OldProc lock xchg word ptr [ecx], ax end; VirtualProtect(NopAddr, 7, OldProtect, OldProtect); end;
ãã®ãããªã€ã³ã¿ãŒã»ãã¿ãŒãç¡å¹ã«ããã«ã¯ãæåã®2ãã€ãåœä»€ãè¿ãã ãã§ååã§ãããã€ã³ã¿ãŒã»ãã¿ãŒæ¬äœãžã®ãžã£ã³ãèªäœãè¡ãããæ®ãã®5ãã€ããåŠçããå¿ èŠã¯ãããŸããã
æ®å¿µãªãããéåžžã®é¢æ°ã§ã¯ãHotPachã¡ãœããã䜿çšããŠã€ã³ã¿ãŒã»ããããããšã¯ã§ããŸãããé¢æ°ã®åã«å¿ èŠãªç©ºãã¹ããŒã¹ããªãããã§ãã圌ãã«ãšã£ãŠã¯ããããã®æåã®2ã€ã®èæ ®ããããªãã·ã§ã³ã®1ã€ãé©åã§ãã
ãã ããã©ã€ãã©ãªãHotPatchçšã«æºåããå¿ èŠãããå Žåã¯ã次ã®æ瀺ã«æ £ããããšãã§ããŸããCreate Hotpatchable Image Trueãããã¯MS VCå°çšã§ãã
3ã€ã®ã€ã³ã¿ãŒã»ããã®äŸã¯ãã¹ãŠãµã³ãã«ã³ãŒãã§ããã€ã³ã¿ãŒã»ããã³ãŒããã€ã³ã¹ããŒã«ãããç¬éã®ã¿ã衚瀺ããŸããã€ã³ã¿ãŒã»ãã¿ãŒãå®å šã«åäœãããã«ã¯ãã€ã³ã¿ãŒã»ãã¿ãŒãã€ã³ã¹ããŒã«ããåã«ã©ããã«ä¿åããå¿ èŠãããå ã®é¢æ°ã®å ã®ã³ãŒãã埩å ããå¿ èŠããããŸãã
次ã«ãæåã®æ¹æ³ã§ååã瀺ããŸãããããè¡ãã«ã¯ãæ°ãããããžã§ã¯ããäœæããã¡ã€ã³ãã©ãŒã ã«ãã¿ã³ãé 眮ããŠã次ã®ã³ãŒããèšè¿°ããå¿ èŠããããŸãã
unit uNearJmpSplice; interface uses Windows, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} type // JMP NEAR OFFSET TNearJmpSpliceRec = packed record JmpOpcode: Byte; Offset: DWORD; end; // JMP NEAR OFFSET TNearJmpSpliceData = packed record FuncAddr: FARPROC; OldData: TNearJmpSpliceRec; NewData: TNearJmpSpliceRec; end; var NearJmpSpliceRec: TNearJmpSpliceData; // procedure SpliceNearJmp(FuncAddr: Pointer; NewData: TNearJmpSpliceRec); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, SizeOf(TNearJmpSpliceRec), PAGE_EXECUTE_READWRITE, OldProtect); try // !!! Move(NewData, FuncAddr^, SizeOf(TNearJmpSpliceRec)); finally VirtualProtect(FuncAddr, SizeOf(TNearJmpSpliceRec), OldProtect, OldProtect); FlushInstructionCache(GetCurrentProcess, FuncAddr, SizeOf(TNearJmpSpliceRec)); end; end; // MessageBoxA function InterceptedMessageBoxA(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var S: AnsiString; begin // SpliceNearJmp(NearJmpSpliceRec.FuncAddr, NearJmpSpliceRec.OldData); try // S := AnsiString('Function interepted. Original message: ' + lpText); Result := MessageBoxA(Wnd, PAnsiChar(S), lpCaption, uType); finally // SpliceNearJmp(NearJmpSpliceRec.FuncAddr, NearJmpSpliceRec.NewData); end; end; procedure InitNearJmpSpliceRec; begin // NearJmpSpliceRec.FuncAddr := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); // , Move(NearJmpSpliceRec.FuncAddr^, NearJmpSpliceRec.OldData, SizeOf(TNearJmpSpliceRec)); // JMP NEAR NearJmpSpliceRec.NewData.JmpOpcode := $E9; // NearJmpSpliceRec.NewData.Offset := PAnsiChar(@InterceptedMessageBoxA) - PAnsiChar(NearJmpSpliceRec.FuncAddr) - SizeOf(TNearJmpSpliceRec); end; procedure TForm1.FormCreate(Sender: TObject); begin // InitNearJmpSpliceRec; // MessageBoxA SpliceNearJmp(NearJmpSpliceRec.FuncAddr, NearJmpSpliceRec.NewData); end; procedure TForm1.Button1Click(Sender: TObject); begin MessageBoxA(0, 'Test MessageBoxA Message', nil, 0); end; end.
TNearJmpSpliceRecæ§é ã¯ãååã³ãŒãã«ãã£ãŠåŠšå®³ããããã€ãã«é¢ããæ å ±ãæ ŒçŽããããã«äœ¿çšãããŸããåãæ§é ãã€ã³ã¿ãŒã»ããã³ãŒããã¹ã³ãŒãã®ä¿åã«äœ¿çšãããŸãã
確ç«ãããã€ã³ã¿ãŒã»ããã«é¢ããäžè¬æ å ±ã¯TNearJmpSpliceDataæ§é ã«æ ŒçŽãããŸãããã®æ§é ã«ã¯ãå ã®é¢æ°ããŒã¿ãšã€ã³ã¿ãŒã»ãã¿ãŒã«é¢ãã2ã€ã®ãã£ãŒã«ãã«å ããŠãé¢æ°ã®ã¢ãã¬ã¹ãæ ŒçŽãããŸãã
æåã«ãInitNearJmpSpliceRecããã·ãŒãžã£ã§ãã®æ§é äœãåæåããããã®åŸãSpliceNearJmpããã·ãŒãžã£ã䜿çšããŠã€ã³ã¿ãŒã»ãã·ã§ã³ã³ãŒããèšå®ãããŸãã
ãã¿ã³ãæŒããããšãInterceptedMessageBoxAã€ã³ã¿ãŒã»ãããã³ãã©ãŒãåŒã³åºãããå ã®é¢æ°ã®åŒã³åºãåŸã«ã€ã³ã¿ãŒã»ãã¿ãŒãåé€ããã埩å ãããŸãã
PUSH ADDR + RETã䜿çšããŠ2çªç®ã®æ¹æ³ã§ã€ã³ã¿ãŒã»ãããè¡ãå ŽåãTNearJmpSpliceRecæ§é äœã®èª¬æãšInitNearJmpSpliceRecæ§é äœã®åæåæé ããããã«å€æŽããå¿ èŠããããŸããä»ã®ãã¹ãŠã¯åããŸãŸã§ãã
ããŠããããã€ã³ã¿ãŒã»ããã³ãŒãã3çªç®ã®æ¹æ³ïŒHotPatchçµç±ïŒã§ã©ã®ããã«èŠãããã§ãã
ããã次ã®2ã€ã®ç« ã§äœ¿çšããŸããç¹°ãè¿ãã«ãªããªãããã«ãå¥ã®ã¢ãžã¥ãŒã«ã«é 眮ããããã§ãã
unit CommonHotPatch; interface uses Windows; const LOCK_JMP_OPKODE: Word = $F9EB; type // JMP NEAR OFFSET TNearJmpSpliceRec = packed record JmpOpcode: Byte; Offset: DWORD; end; THotPachSpliceData = packed record FuncAddr: FARPROC; SpliceRec: TNearJmpSpliceRec; LockJmp: Word; end; var HotPathSpliceRec: THotPachSpliceData; procedure InitHotPatchSpliceRec; procedure SpliceNearJmp(FuncAddr: Pointer; NewData: TNearJmpSpliceRec); procedure SpliceLockJmp(FuncAddr: Pointer; NewData: Word); implementation // procedure SpliceNearJmp(FuncAddr: Pointer; NewData: TNearJmpSpliceRec); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, SizeOf(TNearJmpSpliceRec), PAGE_EXECUTE_READWRITE, OldProtect); try Move(NewData, FuncAddr^, SizeOf(TNearJmpSpliceRec)); finally VirtualProtect(FuncAddr, SizeOf(TNearJmpSpliceRec), OldProtect, OldProtect); FlushInstructionCache(GetCurrentProcess, FuncAddr, SizeOf(TNearJmpSpliceRec)); end; end; // procedure SpliceLockJmp(FuncAddr: Pointer; NewData: Word); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, 2, PAGE_EXECUTE_READWRITE, OldProtect); try asm mov ax, NewData mov ecx, FuncAddr lock xchg word ptr [ecx], ax end; finally VirtualProtect(FuncAddr, 2, OldProtect, OldProtect); FlushInstructionCache(GetCurrentProcess, FuncAddr, 2); end; end; function InterceptedMessageBoxA(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var S: AnsiString; begin // SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); try // S := AnsiString('Function interepted. Original message: ' + lpText); Result := MessageBoxA(Wnd, PAnsiChar(S), lpCaption, uType); finally // SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); end; end; procedure InitHotPatchSpliceRec; begin // HotPathSpliceRec.FuncAddr := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); // , Move(HotPathSpliceRec.FuncAddr^, HotPathSpliceRec.LockJmp, 2); // JMP NEAR HotPathSpliceRec.SpliceRec.JmpOpcode := $E9; // HotPathSpliceRec.SpliceRec.Offset := PAnsiChar(@InterceptedMessageBoxA) + 5 - PAnsiChar(HotPathSpliceRec.FuncAddr) - SizeOf(TNearJmpSpliceRec); end; end.
ã¢ããªã±ãŒã·ã§ã³ã§ãã®ã¢ãžã¥ãŒã«ã䜿çšããã®ã¯æãç°¡åã§ãã
unit uHotPachSplice; interface uses Windows, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation uses CommonHotPatch; {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin // InitHotPatchSpliceRec; // NOP- SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - 5, HotPathSpliceRec.SpliceRec); // MessageBoxW SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); end; procedure TForm1.Button1Click(Sender: TObject); const TestStr: AnsiString = 'Test MessageBoxA Message'; begin MessageBoxA(0, PAnsiChar(TestStr), nil, 0); end; end.
2çªç®ã®ã³ãŒãã¯èª¬æãªãã§æ®ããŸããã€ã³ã¿ãŒã»ããã®ä»¥åã®ããŒãžã§ã³ãšã®éãã¯ãããããã§ãã
8.ãã©ããã®ã€ã³ã¹ããŒã«ã«ããã©ã€ãã©ãªã®å®è£ ã
äžèšã®ãã¹ãŠã¯ãããŒã«ã«ã¢ããªã±ãŒã·ã§ã³ã§ã®ã€ã³ã¿ãŒã»ããã«é¢é£ããŠããŸãããéçºè ãä»ã®èª°ãã®ããã»ã¹ã§ã€ã³ã¿ãŒã»ããããå¿ èŠãããæ£ç¢ºãã瀺ããŠããŸãã
ã€ã³ã¿ãŒã»ãã¿ãŒã¯ãæãè€éãªãã®ãããããã€ãã®æ¹æ³ã§å¥ã®ããã»ã¹ã®æ¬äœã«ã€ã³ã¿ãŒã»ãã¿ãŒãé 眮ã§ããŸã-VirtualAllocExãä»ããŠå¿ èŠãªã¡ã¢ãªãããã¯ãéžæããã€ã³ã¿ãŒã»ãã¿ãŒã³ãŒãããã®äžã«æžã蟌ãïŒç§ã¯ãããèæ ®ããŸããïŒ
ã€ã³ã¿ãŒã»ãã¿ãŒãå®è£ ããæãç°¡åãªæ¹æ³ã¯ãã°ããŒãã«ãã©ããã«ãã£ãŠãšã€ãªã¢ã³ã¢ãã¬ã¹ç©ºéã«ããŒããããã©ã€ãã©ãªãŒã®æ¬äœã«ã€ã³ã¿ãŒã»ãã¿ãŒã³ãŒããé 眮ããããšã§ãã
ã©ã€ãã©ãªããŒããŒã®ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
program hook_loader; {$APPTYPE CONSOLE} uses Windows; var hLib: THandle; HookProcAddr: Pointer; HookHandle: HHOOK; begin hLib := LoadLibrary('hook_splice_lib.dll'); try HookProcAddr := GetProcAddress(hLib, 'HookProc'); Writeln('MessageBoxA intercepted, press ENTER to resume...'); HookHandle := SetWindowsHookEx(WH_GETMESSAGE, HookProcAddr, hLib, 0); Readln; UnhookWindowsHookEx(HookHandle); finally FreeLibrary(hLib); end; end.
SetWindowsHookExé¢æ°ãå®è¡ããããšããã«ãã°ããŒãã«ãã©ãããã€ã³ã¹ããŒã«ãããŸãããã®ãã³ãã©ãŒã¯hook_splice_lib.dllã©ã€ãã©ãªã«ãããŸãããã®ã©ã€ãã©ãªã¯ãGetMessageé¢æ°ãŸãã¯PeekMessageé¢æ°ãåŒã³åºãããšã«ãããã¡ãã»ãŒãžãã¥ãŒã§åäœãããã¹ãŠã®ããã»ã¹ã«èªåçã«ããŒããããŸãã
ã©ã€ãã©ãªã³ãŒãã¯ãäžèšã®ååã®äŸã®ãããããã»ãŒç¹°ãè¿ããŸãã
library hook_splice_lib; uses Windows, CommonHotPatch in '..\common\CommonHotPatch.pas'; {$R *.res} procedure DLLEntryPoint(dwReason: DWORD); begin case dwReason of DLL_PROCESS_ATTACH: begin // InitHotPatchSpliceRec; // NOP- SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - 5, HotPathSpliceRec.SpliceRec); // MessageBoxW SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); end; DLL_PROCESS_DETACH: begin // SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); end; end; end; function HookProc(Code: Integer; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall; begin Result := CallNextHookEx(0, Code, WParam, LParam); end; exports HookProc; begin DLLProc := @DLLEntryPoint; DLLEntryPoint(DLL_PROCESS_ATTACH); end.
éãã¯æå°éã§ããã©ã€ãã©ãªæ¬äœã«ã¯ãã€ã³ã¿ãŒã»ããã³ãŒãèªäœã«å ããŠãããã¯ããã¯é¢æ°HookProcãå®è£ ãããŠããããã¥ãŒå ã®æ¬¡ã®ããã¯ãåŒã³åºãã ãã§ãã WH_GETMESSAGEãã©ãããæ£ããæ©èœããããã«ã®ã¿å¿ èŠã§ãã
ã€ã³ã¿ãŒã»ãã¿ãŒã¯ãDLL_PROCESS_ATTACHã®ããŒãã®éç¥ãåä¿¡ãããšDLLEntryPointã«ã€ã³ã¹ããŒã«ãããDLL_PROCESS_DETACHã®ã¢ã³ããŒãã®éç¥ãåä¿¡ãããšã€ã³ã¿ãŒã»ãã¿ãŒã¯åé€ãããŸãã
DLLProcã®ãªãŒããŒã©ããã³ãŒãã«ã€ããŠå°ã説æããŸããå®éããã®ããã·ãŒãžã£ã®ãªãŒããŒã©ããã¯ãDLL_PROCESS_DETACHéç¥ãåä¿¡ããããã®1ã€ã®ã¿ã察象ãšããŠããŸããå®éãã³ãŒããå¶åŸ¡ãåãåã£ããšããDLL_PROCESS_ATTACHéç¥ã¯æ¢ã«ã©ã€ãã©ãªã«æž¡ãããŠãããDLLProcå ã§åŠçãããŠããŸããDLLEntryPointåŒã³åºãïŒDLL_PROCESS_ATTACHïŒã¯ãåºæ¬çã«æ¢ã«åä¿¡ããåŒã³åºããè€è£œããã ãã§ãããã ããã©ã€ãã©ãªãã¢ã³ããŒãããããšãDLLProcã¯æ¢ã«DLLEntryPointãã³ãã©ãŒã«å€æŽãããŠãããã¢ã³ããŒãã«é¢ããéç¥ãå±ããŸããããã§ãã€ã³ã¿ãŒã»ãã¿ãŒãåæå解é€ããããã«å¿ èŠãªã¢ã¯ã·ã§ã³ãå®è¡ã§ããŸãã
9.ãªã¢ãŒãããã»ã¹ã§ã¹ã¬ãããäœæããŠã©ã€ãã©ãªããããã€ããŸãã
ã©ã€ãã©ãªããã¹ãŠã®ããã»ã¹ã«ã°ããŒãã«ã«å°å ¥ããããšã¯ããã°ãã°æ£åœåãããŸãããç¹å®ã®ããã»ã¹ã§ç¹å®ã®IPAãååãããå Žåãä»ã®äººã«æ°ãåãããŠãæå³ããããŸãããããã«ãå Žåã«ãã£ãŠã¯ããã©ãããã€ã³ã¹ããŒã«ãããŠããã«ããããããããã©ãããããªã¬ãŒããããã«å¿ èŠãªã¢ã¯ã·ã§ã³ãå®è¡ããªããããã©ã€ãã©ãªãå¿ èŠãªããã»ã¹ã«ããŒããããªãå ŽåããããŸããäŸãšããŠããã®ã³ã³ãœãŒã«ã¢ããªã±ãŒã·ã§ã³ãèŠãŠã¿ãŸãããã
program test_console8; {$APPTYPE CONSOLE} uses Windows; begin Writeln('Press enter to show message...'); Readln; MessageBoxA(0, 'First message', '', 0); Writeln('Press enter to show message...'); Readln; MessageBoxA(0, 'Second message', '', 0); end.
éåžžãã³ã³ãœãŒã«ã¢ããªã±ãŒã·ã§ã³ã¯ã¡ãã»ãŒãžãã¥ãŒã§åäœãããã«ãŒã«ãšããŠGetMessageãŸãã¯PeekMessageé¢æ°ã®åŒã³åºãã䜿çšããªããããæåã®ã¡ãã»ãŒãžã衚瀺ãããŠããã€ã³ã¿ãŒã»ãããããŸããã
ããããããã«ããããããã2çªç®ã®ã¡ãã»ãŒãžã¯ç¢ºç«ããããã©ããã«ãã£ãŠã€ã³ã¿ãŒã»ãããããŸããå®éã«ã¯ãæåã®ã¡ãã»ãŒãžããã¯ã¹ïŒããã³ä»ã®ã¡ãã»ãŒãžããã¯ã¹ïŒã衚瀺ããããã«ãã¡ãã»ãŒãžãã¥ãŒãåŒãç¶ã䜿çšããïŒå®éã«ã¯ã¢ãŒãã«ãŠã£ã³ããŠã衚瀺ãããããïŒãã©ã€ãã©ãªã衚瀺ããããšãã«ããŒããããããã2çªç®ã®MessageBoxåŒã³åºãã®ã€ã³ã¿ãŒã»ããã説æãããŸãã
ãã®åäœïŒã³ã³ãœãŒã«ã§æåã®MessageBoxåŒã³åºããã€ã³ã¿ãŒã»ããã§ããªãããšïŒãåé¿ããããã«ãããã»ã¹èå¥åïŒPIDïŒãèªèããŠãã©ã€ãã©ãªã匷å¶çã«ããŒãã§ããŸãã
ã€ã³ã¿ãŒã»ãã¿ãŒãåããã©ã€ãã©ãªãŒã¯ã以åã®ãã®ãšã»ãŒåããŸãŸã§ãå¯äžã®å€æŽç¹ã¯ãHookProcãã©ãããã³ãã©ãŒã®ä»£ããã«ã次ã®åœ¢åŒã®ã©ã€ãã©ãªãŒã¢ã³ããŒãé¢æ°ãå®è£ ããããšã§ãã
procedure SelfUnload(lpParametr: Pointer); stdcall; begin FreeLibraryAndExitThread(HInstance, 0); end; exports SelfUnload;
ã©ã€ãã©ãªã®å®è£ ã¯ã次ã®ã³ãŒãã§å®è¡ãããŸãã
const DllName = 'thread_splice_lib.dll'; function InjectLib(ProcessID: Integer): Boolean; var Process: HWND; ThreadRtn: FARPROC; DllPath: AnsiString; RemoteDll: Pointer; BytesWriten: DWORD; Thread: DWORD; ThreadId: DWORD; begin Result := False; // Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE, True, ProcessID); if Process = 0 then Exit; try // DllPath := AnsiString(ExtractFilePath(ParamStr(0)) + DLLName) + #0; RemoteDll := VirtualAllocEx(Process, nil, Length(DllPath), MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE); if RemoteDll = nil then Exit; try // if not WriteProcessMemory(Process, RemoteDll, PChar(DllPath), Length(DllPath), BytesWriten) then Exit; if BytesWriten <> DWORD(Length(DllPath)) then Exit; // Kernel32.dll ThreadRtn := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'LoadLibraryA'); if ThreadRtn = nil then Exit; // Thread := CreateRemoteThread(Process, nil, 0, ThreadRtn, RemoteDll, 0, ThreadId); if Thread = 0 then Exit; try // ... Result := WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0; finally CloseHandle(Thread); end; finally VirtualFreeEx(Process, RemoteDll, 0, MEM_RELEASE); end; finally CloseHandle(Process); end; end;
ãã®æ¹æ³ã®åçã¯ãªãã¿ãŒã«ãã£ãŠèª¬æãããã®ã§ãç§ã¯ããã«ãã ãããªãã
ãŸããã¢ã³ããŒãããã«ã¯ã次ã®ã³ãŒããå®è£ ããå¿ èŠããããŸãã
function ResumeLib(ProcessID: Integer): Boolean; var hLibHandle: THandle; hModuleSnap: THandle; ModuleEntry: TModuleEntry32; OpCodeData: Word; Process: HWND; BytesWriten: DWORD; Thread: DWORD; ThreadId: DWORD; ExitCode: DWORD; PLibHandle: PDWORD; OpCode: PWORD; CurrUnloadAddrOffset: DWORD; UnloadAddrOffset: DWORD; begin Result := False; // hLibHandle := LoadLibrary(PChar(DLLName)); try UnloadAddrOffset := DWORD(GetProcAddress(hLibHandle, 'SelfUnload')) - hLibHandle; if UnloadAddrOffset = -hLibHandle then Exit; finally FreeLibrary(hLibHandle); end; // hModuleSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessID); if hModuleSnap <> INVALID_HANDLE_VALUE then try FillChar(ModuleEntry, SizeOf(TModuleEntry32), #0); ModuleEntry.dwSize := SizeOf(TModuleEntry32); if not Module32First(hModuleSnap, ModuleEntry) then Exit; repeat if AnsiUpperCase(ModuleEntry.szModule) = AnsiUpperCase(DLLName) then begin // CurrUnloadAddrOffset := ModuleEntry.hModule + UnloadAddrOffset; Break; end; until not Module32Next(hModuleSnap, ModuleEntry); finally CloseHandle(hModuleSnap); end; // Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE, True, ProcessID); if Process = 0 then Exit; try // jmp [ebx] OpCode := VirtualAllocEx(Process, nil, 2, MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE); if OpCode = nil then Exit; try OpCodeData := $23FF; if not WriteProcessMemory(Process, OpCode, @OpCodeData, 2, BytesWriten) then Exit; // ( EBX ) PLibHandle := VirtualAllocEx(Process, nil, 4, MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE); if PLibHandle = nil then Exit; try if not WriteProcessMemory(Process, PLibHandle, @CurrUnloadAddrOffset, 4, BytesWriten) then Exit; // Thread := CreateRemoteThread(Process, nil, 0, OpCode, PLibHandle, 0, ThreadId); if Thread = 0 then Exit; try // ... if (WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0) then if GetExitCodeThread(Thread, ExitCode) then Result := ExitCode = 0; finally CloseHandle(Thread); end; finally VirtualFreeEx(Process, PLibHandle, 0, MEM_RELEASE); end; finally VirtualFreeEx(Process, OpCode, 0, MEM_RELEASE); end; finally CloseHandle(Process); end; end;
ããã§ã¯ãWindows 2000ããWindows 7ãŸã§ã®è¡ã§æ©èœããææžåãããŠããªãã¡ã«ããºã ã1ã€äœ¿çšããŸãïŒ8ã€ã§ã¯ãã§ãã¯ããŸããã§ããããããžãã¯ã¯åãã§ãïŒãå®éãCreateRemoteThreadé¢æ°ã®lpParameterãã©ã¡ãŒã¿ãŒã«æž¡ãããå€ã¯ããªã¢ãŒãã¢ããªã±ãŒã·ã§ã³ã§ã¹ã¬ãããéå§ããããšãåžžã«EBXã¬ãžã¹ã¿ã«é 眮ãããŸãããã®ã³ãŒãã®ã¿ã¹ã¯ã¯ãã¹ã¬ããããªã¢ãŒãããã»ã¹ã§äœæ¥ãéå§ããJMP [EBX]åœä»€ãé 眮ããããšã§ããSelfUnloadããã·ãŒãžã£ã®ã¢ãã¬ã¹ãEBXã«ããå Žåãå¶åŸ¡ã¯ããã«è»¢éãããŸããããã®ããã·ãŒãžã£å ã§ã¯ãã©ã€ãã©ãªãã¢ã³ããŒãããŠçŸåšã®ã¹ã¬ãããéããããã®ã³ãŒããæ¢ã«å®è£ ãããŠããŸãã
ãã¡ãããSelfUnloadé¢æ°ããçŽæ¥ã¢ã³ããŒãã¡ã«ããºã ãçŽæ¥éå§ããããšãã§ããŸããããã®ç¬éãèŠãããã£ãã®ã§ãããŸãscãããªãã§ãã ãã:)
10.ã¢ãã¿ãªã³ã°
å®çšçãªéšåã§ã¯ãå°ãçè«çã«çµãã£ããšã¿ãªããŸãã
ã€ã³ã¿ãŒã»ãããããé¢æ°ã®åŒã³åºããæ£ãããã°ã«èšé²ããæ¹æ³ã«ã€ããŠã¯ãäžè¬çãªçãã¯ãããŸããããäžè¬çãªæšå¥šäºé ã¯ãããŸãã
ãŸããã©ã®ãã©ã¡ãŒã¿ãŒããã°ã«èšé²ãããã決å®ãã次ã®ã°ã«ãŒãã«åé¡ããå¿ èŠããããŸãã
- çä¿¡ãã©ã¡ãŒã¿ãŒã¯ãã€ã³ã¿ãŒã»ãã¿ãŒã§å ã®é¢æ°ãåŒã³åºããããŸã§åžžã«èšé²ãããŸãã
- çºä¿¡ãã©ã¡ãŒã¿ãŒã¯ãå ã®ã€ã³ã¿ãŒã»ãããããé¢æ°ãåŒã³åºããåŸã«åžžã«ãã°ã«èšé²ãããŸãã
- ãã©ã¡ãŒã¿ãŒãIN / OUTãšããŠå®£èšãããŠããå Žåãäºéãã°ã«èšé²ããŸãã
çç±ã¯ããããŸããããç§ã®ãåŠçãã¯ãã®ç¹ã«ã®ã£ã°ãæ±ããŠããŸããã圌ãã¯åžžã«ãã°ã®é åºãæ··ä¹±ãããReadFileãåŒã³åºãåã«ãã°ãåŒã³åºããããŒã¿ãããã¡ã®äžè¶³ã«é©ããŸããã
ããŠãæåã®ç¹ã§ããå°ã-é¢æ°ãåŒã³åºãåã«åžžã«çä¿¡ããŒã¿ã®ãã®ã³ã°ãè¡ããŸããããããªããšãWriteFileã«è»¢éããããããã¡ããã®åŒã³åºããåŠçãããã©ã€ãã«ãã£ãŠãããã«å€æŽããããšããäºå®ã«ééããŸãã
11.èŠçŽ
ããã¯ãããããååææ³ã®èª¬æã§çµäºãã䟡å€ããããŸããã¯ããå®éã«ã¯å®éã«ã¯æ®ã£ãŠããŸãããã³ã¢ã§ååã®æ¹æ³ã説æããããšã«ã¯æå³ããããŸãããããã¯ãã§ã«Delphiã³ãã¥ããã£åãã®èšäºã§ã¯ãªãããªãŒããŒãããŒæã®ååã«é¢ããããªãã¯ãèæ ®ããŸãããåçãã®ãã®ã説æããã®ã«æéãããããããçç±ãšããããã©ã®ããã«ãæ©èœãããã
èæ ®ãããŠããªãå¯äžã®ãã¥ã¢ã³ã¹ã¯ãHotPatchã䜿çšãããšãã«ã€ã³ã¿ãŒã»ãããæ®ã£ãŠããŸãããã€ãŸããã€ã³ã¿ãŒã»ãã¿ãŒãåé€ããå¿ èŠã¯å¿ ããããªããäžèŠãªãžã§ã¹ãã£ãŒãªãã§å®è¡ã§ããŸãã
ããããæ®å¿µãªããšã«ããã®ãã¥ã¢ã³ã¹å šäœã説æãããã¢ã¢ããªã±ãŒã·ã§ã³ãæºåããæéããããŸããã§ããããŸããäžå¿ èŠã«è³æã®éãå¢ãããããªãã£ãã®ã§ããã®ç¹ã«ã€ããŠã¯èšäºã®åŸåã§èª¬æããŸãã
å®éãããããã®ãããã¯ã§äŒãããã£ãããšã®ãã¹ãŠã§ãããã®ç¥èãã©ã®ããã«é©çšãããã¯ããªã次第ã§ããã¯ãããã¡ããããã®æ å ±ã¯ããŸããŸãªæªæã®ãããã®ã®éçºã«é©çšã§ããããšãç解ããŠããŸãããããæçšãªãœãããŠã§ã¢ã«äœ¿çšããããšãã§ããŸããç¹ã«ãç§ã¯éåžžããã©ãŠã¶ãééãããã©ãã£ãã¯ãåæãããããªäºçŽ°ãªã¿ã¹ã¯ã«ã€ã³ã¿ãŒã»ããã䜿çšããŸãã空ãæéã«èªåã§å®è£ ã§ããã®ã«ãåãæ©èœãæäŸãããœãããŠã§ã¢ã«äœçŸãã«ãæ¯æãã®ã¯ãªãã§ããïŒãã®ãªã³ã¯
ã§èšäºã®äŸãèŠãããšãã§ããŸããæåããç£èŠãã¢ã¬ã¯ãµã³ããŒïŒã©ãŠãŒ_ïŒããŒã°ã«2013幎1æ