確ãã«ããã®äžã«èæ ®ãããŠããªã2ã€ã®äžå¿«ãªç¶æ³ãæ®ããŸããã
1.ãã©ãããåé€ãããæç¹ã§ãã€ã³ã¿ãŒã»ãããããé¢æ°ãåŒã³åºããŸãã
2. 2ã€ã®ç°ãªãã¹ã¬ããããã®ã€ã³ã¿ãŒã»ãããããé¢æ°ã®åæåŒã³åºãã
æåã®ã±ãŒã¹ã§ã¯ãã€ã³ã¿ãŒã»ãã¿ãŒãã€ã³ã¹ããŒã«ããããã°ã©ããŒã¯å šäœåãèŠãããšãã§ããŸããã äžéšã®ããŒã¿ã¯åœŒãééããŸãã
2çªç®ã®ã±ãŒã¹ã¯ãã€ã³ã¿ãŒã»ãã¿ãŒãã€ã³ã¹ããŒã«ãããŠããã¢ããªã±ãŒã·ã§ã³ãèœã¡ããŸã§ãããæ·±å»ãªçµæãããããæãããããŸãã
ãããã®ç¶æ³ã¯äž¡æ¹ãšããã¹ãã©ã€ã·ã³ã°ã䜿çšãããŠããå Žåã«ã®ã¿çºçããŸãã ã€ã³ããŒã/ãšã¯ã¹ããŒãããŒãã«ãªã©ãéããŠã€ã³ã¿ãŒã»ãããããå Žå ã€ã³ã¿ãŒã»ãããããé¢æ°ã®ããã£ã®å€æŽã¯çºçããªããããã€ã³ã¿ãŒã»ããã®ãããã®ãªãã·ã§ã³ã¯é床ã®ããã£ã®åããå¿ èŠãšããŸããã
ãã®èšäºã§ã¯ãHopPatchçšã«æºåãããé¢æ°ã®ãšã³ããªãã€ã³ãã®ã¹ãã©ã€ã·ã³ã°ã«ã€ããŠãããã«è©³ãã調ã¹ãŸãã ãããã®é¢æ°ã¯ãäžèšã®ãšã©ãŒãåé¿ããæ¹æ³ãæäŸããŸãã
JMP NEAR OFFSETãŸãã¯PUSH ADDR + RETïŒãããã®ãšã©ãŒã«å¯ŸããŠæãè匱ãªïŒã«ããã¹ãã©ã€ã·ã³ã°ã¯èæ ®ãããŸããã è¯ãæ¹æ³ã§ã¯ãé·ãã®éã¢ã»ã³ãã©ãŒãå®è£ ããã«ããã®ãªãã·ã§ã³ãå¿ èŠã«å¿ããŠã€ã³ã¿ãŒã»ããããããšã¯ã§ããŸããã
1. CreateWindowExWãžã®åŒã³åºããã€ã³ã¿ãŒã»ããããã¢ããªã±ãŒã·ã§ã³ãå®è£ ããŸã
ãŸããã€ã³ã¿ãŒã»ããã解é€ãããæç¹ã§ã€ã³ã¿ãŒã»ãããããé¢æ°ã®åŒã³åºããçºçããå¯èœæ§ããããããAPIãã€ã³ã¿ãŒã»ãããããšãã«ããŒã¿ã®æ倱ãæ確ã«ç€ºãã¢ããªã±ãŒã·ã§ã³ãæºåããŸãã
æ°ãããããžã§ã¯ããäœæããTMemoãTOpenDialogãTButtonã®3ã€ã®èŠçŽ ãã¡ã€ã³ãã©ãŒã ã«é 眮ããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®æ¬è³ªïŒãã¿ã³ãã¯ãªãã¯ããããšãã€ã³ã¿ãŒã»ãããCreateWindowExWé¢æ°ã«èšå®ããããã€ã¢ãã°ã衚瀺ãããŸãã ãã€ã¢ãã°ãéããåŸãTMemoã¯ãã€ã¢ãã°ã«ãã£ãŠäœæããããã¹ãŠã®ãŠã£ã³ããŠã«é¢ããæ å ±ã衚瀺ããŸãã
ãããè¡ãã«ã¯ã åã®èšäºã®ã³ãŒãã®äžéšãã€ãŸã次ã®ãã®ãå¿ èŠã§ãã
1.ååã®ããã®åãšå®æ°ã®å®£èšïŒ
const LOCK_JMP_OPKODE: Word = $F9EB; JMP_OPKODE: Word = $E9; type // JMP NEAR OFFSET TNearJmpSpliceRec = packed record JmpOpcode: Byte; Offset: DWORD; end; THotPachSpliceData = packed record FuncAddr: FARPROC; SpliceRec: TNearJmpSpliceRec; LockJmp: Word; end; const NearJmpSpliceRecSize = SizeOf(TNearJmpSpliceRec); LockJmpOpcodeSize = SizeOf(Word);
2. NEAR JMPããã³ã¢ãããã¯ã¬ã³ãŒãã£ã³ã°SHORT JMPãèšé²ããæé
// procedure SpliceNearJmp(FuncAddr: Pointer; NewData: TNearJmpSpliceRec); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, NearJmpSpliceRecSize, PAGE_EXECUTE_READWRITE, OldProtect); try Move(NewData, FuncAddr^, NearJmpSpliceRecSize); finally VirtualProtect(FuncAddr, NearJmpSpliceRecSize, OldProtect, OldProtect); end; end; // procedure SpliceLockJmp(FuncAddr: Pointer; NewData: Word); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, LockJmpOpcodeSize, PAGE_EXECUTE_READWRITE, OldProtect); try asm mov ax, NewData mov ecx, FuncAddr lock xchg word ptr [ecx], ax end; finally VirtualProtect(FuncAddr, LockJmpOpcodeSize, OldProtect, OldProtect); end; end;
3. THotPachSpliceDataæ§é äœã®åæåããããã«å€æŽ
// procedure InitHotPatchSpliceRec(const LibraryName, FunctionName: string; InterceptHandler: Pointer; out HotPathSpliceRec: THotPachSpliceData); begin // HotPathSpliceRec.FuncAddr := GetProcAddress(GetModuleHandle(PChar(LibraryName)), PChar(FunctionName)); // , Move(HotPathSpliceRec.FuncAddr^, HotPathSpliceRec.LockJmp, LockJmpOpcodeSize); // JMP NEAR HotPathSpliceRec.SpliceRec.JmpOpcode := JMP_OPKODE; // ( NearJmpSpliceRecSize , // .. ) HotPathSpliceRec.SpliceRec.Offset := PAnsiChar(InterceptHandler) - PAnsiChar(HotPathSpliceRec.FuncAddr); end;
ãã®ã³ãŒãã¯ãã¹ãŠå¥åã®SpliceHelperã¢ãžã¥ãŒã«ã«é 眮ãããŸãã次ã®ç« ã§å¿ èŠã«ãªããŸãã
ã¡ã€ã³ãã©ãŒã ã«ç§»ããŸãããã2ã€ã®ã°ããŒãã«å€æ°ãå¿ èŠã§ãã
var HotPathSpliceRec: THotPachSpliceData; WindowList: TStringList;
HotPathSpliceRecå€æ°ã«ã¯ãã€ã³ã¿ãŒã»ãã¿ãŒã«é¢ããæ å ±ãå«ãŸããŸãã 2çªç®ã«ã¯ãäœæããããŠã£ã³ããŠã®ãªã¹ããå«ãŸããŸãã
ãã©ãŒã ã³ã³ã¹ãã©ã¯ã¿ãŒã§ãTHotPachSpliceDataæ§é äœãåæåããŸãã
procedure TForm1.FormCreate(Sender: TObject); begin // InitHotPatchSpliceRec(user32, 'CreateWindowExW', @InterceptedCreateWindowExW, HotPathSpliceRec); // NOP- SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - NearJmpSpliceRecSize, HotPathSpliceRec.SpliceRec); end;
å ã®é¢æ°ã®ä»£ããã«åŒã³åºãããã€ã³ã¿ãŒã»ãã¿ãŒé¢æ°ãäœæããŸãã
function InterceptedCreateWindowExW(dwExStyle: DWORD; lpClassName: PWideChar; lpWindowName: PWideChar; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND; stdcall; var S: string; Index: Integer; begin // SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); try // Index := -1; if not IsBadReadPtr(lpClassName, 1) then begin S := 'ClassName: ' + string(lpClassName); S := IntToStr(WindowList.Count + 1) + ': ' + S; Index := WindowList.Add(S); end; // Result := CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); // if Index >= 0 then begin S := S + ', handle: ' + IntToStr(Result); WindowList[Index] := S; end; finally // SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); end; end;
ãããŠããã¿ã³ãã³ãã©ãå®è£ ããããã«æåŸã«æ®ããŸãã
procedure TForm1.Button1Click(Sender: TObject); begin // CreateWindowExW SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); try // WindowList := TStringList.Create; try // OpenDialog1.Execute; // Memo1.Lines.Text := WindowList.Text; finally WindowList.Free; end; finally // SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); end; end;
ãã¹ãŠã®æºåãæŽã£ãããããã°ã©ã ãå®è¡ããããšãã§ããŸãã
ãã®ç« ã§å®è£ ãããŠããã³ãŒãã«ã€ããŠã¯è©³ãã説æããŸããã åã®èšäºã§è©³ãã説æãã以äžã®ãã®ã§ãããããäžåºŠãã€ã³ãããŠãæå³ããããŸããã
ããã°ã©ã ãå®è¡ãããã¿ã³ãã¯ãªãã¯ããŠãããã£ã³ã»ã«ããã¿ã³ãã¯ãªãã¯ããŠãã€ã¢ãã°ãéããŸãã次ã®ããã«ãªããŸãã

ãããã£ãŠãéåžžã®TOpenDialogãéããšãããŸããŸãªã¯ã©ã¹ã®14ã®ãŠã£ã³ããŠãäœæãããããšãããããŸããã
ããã§ã¯ãå®éã«ããã§ãããã©ããã確èªããŸãããã
2.ã¢ããªã±ãŒã·ã§ã³ãŠã£ã³ããŠã®ããªãŒã衚瀺ããããã®è£å©ãŠãŒãã£ãªãã£ãäœæããŸãã
ã€ã³ã¿ãŒã»ãã¿ãŒã®åäœã確èªããã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ãŠã£ã³ããŠã®çŸåšã®ãªã¹ãã衚瀺ã§ãããµãŒãããŒãã£ã®ãŠãŒãã£ãªãã£ã䜿çšããŠãã€ã³ã¿ãŒã»ãã¿ãŒã§åä¿¡ãããã¹ãŠã®æ å ±ã確èªããå¿ èŠããããŸãã
ãã¡ãããSpy ++ãªã©ã®ãµãŒãããŒãã£ããã°ã©ã ã䜿çšã§ããŸãããç§ãã¡ã¯ããã°ã©ããªã®ã§ãç¹ã«å®è£ ããæéãå®ãã®ã§ãèªåã§å®è£ ããå¿ èŠããããŸãã
æ°ãããããžã§ã¯ããäœæããTTreeViewãã¡ã€ã³ãã©ãŒã ã«é 眮ããŠããã次ã®ã³ãŒããå®è£ ããŸãã
type TdlgWindowTree = class(TForm) WindowTreeView: TTreeView; procedure FormCreate(Sender: TObject); private procedure Sys_Windows_Tree(Node: TTreeNode; AHandle: HWND; ALevel: Integer); end; ... procedure TdlgWindowTree.FormCreate(Sender: TObject); begin Sys_Windows_Tree(nil, GetDesktopWindow, 0); end; procedure TdlgWindowTree.Sys_Windows_Tree(Node: TTreeNode; AHandle: HWND; ALevel: Integer); type TRootNodeData = record Node: TTreeNode; PID: Cardinal; end; var szClassName, szCaption, szLayoutName: array[0..MAXCHAR - 1] of Char; szFileName : array[0..MAX_PATH - 1] of Char; Result: String; PID, TID: Cardinal; I: Integer; RootItems: array of TRootNodeData; IsNew: Boolean; begin // while AHandle <> 0 do begin // GetClassName(AHandle, szClassName, MAXCHAR); // ( Caption) GetWindowText(AHandle, szCaption, MAXCHAR); // if GetWindowModuleFilename(AHandle, szFileName, SizeOf(szFileName)) = 0 then FillChar(szFileName, 256, #0); TID := GetWindowThreadProcessId(AHandle, PID); // AttachThreadInput(GetCurrentThreadId, TID, True); VerLanguageName(GetKeyboardLayout(TID) and $FFFF, szLayoutName, MAXCHAR); AttachThreadInput(GetCurrentThreadId, TID, False); // Result := Format('%s [%s] Caption = %s, Handle = %d, Layout = %s', [String(szClassName), String(szFileName), String(szCaption), AHandle, String(szLayoutName)]); // if ALevel in [0..1] then begin IsNew := True; for I := 0 to Length(RootItems) - 1 do if RootItems[I].PID = PID then begin Node := RootItems[I].Node; IsNew := False; Break; end; if IsNew then begin SetLength(RootItems, Length(RootItems) + 1); RootItems[Length(RootItems) - 1].PID := PID; RootItems[Length(RootItems) - 1].Node := WindowTreeView.Items.AddChild(nil, 'PID: ' + IntToStr(PID)); Node := RootItems[Length(RootItems) - 1].Node; end; end; // Sys_Windows_Tree(WindowTreeView.Items.AddChild(Node, Result), GetWindow(AHandle, GW_CHILD), ALevel + 1); // ( ) AHandle := GetNextWindow(AHandle, GW_HWNDNEXT); end; end;
å®éã«ã¯ãå®è¡ã®ããã«ãã¹ãŠãå®è¡ã§ããŸãã

3.çµæãåæãã
次ã«ãäž¡æ¹ã®ããã°ã©ã ã®çµæãæ¯èŒããŸãã 次ã®ããã«ããŸãã
1.ã€ã³ã¿ãŒã»ãã¿ãŒã§ããã°ã©ã ãå®è¡ãããã€ã¢ãã°ã衚瀺ãããã¿ã³ãã¯ãªãã¯ããŸãã
2. 2çªç®ã®ç« ãããŠãŒãã£ãªãã£ãå®è¡ããŸã
3.æåã®ããã°ã©ã ã®ãã€ã¢ãã°ãéããŠãã€ã³ã¿ãŒã»ããããããŠã£ã³ããŠã«é¢ããçµæãååŸããŸãã
ç§ãã¡ã¯èŠãŸãïŒ

Auto-Suggest DropDownã¯ã©ã¹ã®ãŠã£ã³ããŠã¯èµ€ã§åŒ·èª¿è¡šç€ºãããŠããŸãããããäœã§ããããèŠãŠã¿ãŸãããã

ããããããã«4ã€ã®ãŠã£ã³ããŠã2ã€ã®ã¹ã¯ããŒã«ããŒãListViewãå«ãŸããŠãããSysHeader32ã®åãä¿æããŠããŸãã ããããããã¯ãã§ã«èå³æ·±ãã§ãã äž¡æ¹ã®ã¢ããªã±ãŒã·ã§ã³ã®ãŠã£ã³ããŠãã³ãã«ã¯åãã§ãããListViewãSysHeader32ããæåã®ã¢ããªã±ãŒã·ã§ã³ã®2ã€ã®ã¹ã¯ããŒã«ãåãã§ã¯ãããŸããã
ããããæåã®ãªã¹ãã«ãããã衚瀺ãããªããšããäºå®ã¯äœã®æå³ããããŸããã ãããã®ãŠã£ã³ããŠã¯ãã€ã³ã¿ãŒã»ãã¿ãŒãåé€ããããšãã«äœæãããŸãããããã¯ã1ã€ã®çç±ã§ã®ã¿çºçããå¯èœæ§ããããŸããCreateWindowExWãžã®åŒã³åºãã¯ãããèªäœãžã®ååž°åŒã³åºãã«ã€ãªããå¯èœæ§ãããããã§ãã
ãã®ãããã€ã³ã¿ãŒã»ãã¿ãŒã®åé€ãšåŸ©å ãäžèŠãªæ¹æ³ã§ã€ã³ã¿ãŒã»ãã¿ãŒã³ãŒããå®è£ ããå¿ èŠããããŸãã
4.ååã³ãŒããåé€ããã«ãååããé¢æ°ãåŒã³åºããŸãã
æåŸã®èšäºã®ãã®åçãèŠãŠã¿ãŸãããã

ãããMessageBoxWé¢æ°ã®å§ãŸãã§ãã æåã®åœä»€ã¯ã5ã€ã®NOPåœä»€ãå è¡ããäœãããªãåœä»€MOV EDIãEDIã§ãã
ããã¯ãHotPatchã«ããã€ã³ã¿ãŒã»ããã®ããã«æºåãããé¢æ°ã®ã»ãšãã©ããç§ãã¡ãã€ã³ã¿ãŒã»ããããCreateWindowExWãå«ããŠã»ãšãã©åãããã«èŠããŸãã
é¢æ°ãã€ã³ã¿ãŒã»ããããããšãäœãããªãåœä»€ã«ãã£ãŠå æãããå²ãåœãŠããã7ãã€ãã®ä»£ããã«ã次ã®ã³ãŒããé 眮ãããŸãã

å®éãããã¯ã€ã³ã¹ããŒã«ããã€ã³ã¿ãŒã»ãã¿ãŒã§ãã
MOV EDIãEDIåœä»€ã®ä»£ããã«ãJMP -7ã³ãŒããé 眮ãããåã®åœä»€ã«å¶åŸ¡ã移ãããŸãã
5ã€ã®NOPåœä»€ã®ä»£ããã«ãã€ã³ã¿ãŒã»ãã¿ãŒé¢æ°ã®å é ã«ãžã£ã³ãããŸãã
CreateWindowExWé¢æ°ã®éå§ã¢ãã¬ã¹ããã§ã¯ãªãããã®æåã®æçšãªPUSH EBPåœä»€ã®ã¢ãã¬ã¹ããå®è¡ãéå§ããå Žåãã€ã³ã¹ããŒã«ããã€ã³ã¿ãŒã»ãã¿ãŒã«åœ±é¿ãäžããŸãããããã§ããã°ããããåé€ããŠãæå³ããããŸããã
ã³ãŒã圢åŒã§ã¯ã次ã®ããã«ãªããŸãã
type TCreateWindowExW = function(dwExStyle: DWORD; lpClassName: PWideChar; lpWindowName: PWideChar; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer; hWndParent: HWND; AMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND; stdcall; function InterceptedCreateWindowExW(dwExStyle: DWORD; lpClassName: PWideChar; lpWindowName: PWideChar; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND; stdcall; var S: string; Index: Integer; ACreateWindowExW: TCreateWindowExW; begin // Index := -1; if not IsBadReadPtr(lpClassName, 1) then begin S := 'ClassName: ' + string(lpClassName); S := IntToStr(WindowList.Count + 1) + ': ' + S; Index := WindowList.Add(S); end; // @ACreateWindowExW := PAnsiChar(HotPathSpliceRec.FuncAddr) + LockJmpOpcodeSize; Result := ACreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); // if Index >= 0 then begin S := S + ', handle: ' + IntToStr(Result); WindowList[Index] := S; end; end;
é¢æ°ã®å é ãã2ãã€ãã®ãªãã»ããã«çããæåã®æçšãªåœä»€ã®ã¢ãã¬ã¹ãèšç®ããåŸãäžæå€æ°ACreateWindowExWã«æ ŒçŽãããã®åŸãéåžžã®æ¹æ³ã§é¢æ°ãåŒã³åºããŸãã
ãã®å Žåã«äœãèµ·ãããèŠãŠã¿ãŸããããããã¯ç§ãã¡ãæåŸ ãããã®ã§ãïŒ

ãããŠãããã¯ç§ãã¡ã«äžãããããªã¹ãã§èŠã€ãããã®ã§ãã

ããŠããæ倱ããèŠã€ããŸããã14åã§ã¯ãªããTOpenDialogãåŒã³åºããããšãåã26åã®ãŠã£ã³ããŠããã¹ãŠäœæãããŸãã
ããã¯ãã¹ãŠæªåé«ãååž°åŒã³åºãã®åé¡ã§ãããInterceptedCreateWindowExWé¢æ°ã®å é ã«ãã¬ãŒã¯ãã€ã³ããèšå®ãããšãããã·ãŒãžã£ã³ãŒã«ã¹ã¿ãã¯ã«è¡šç€ºãããŸãã

5.ç°ãªãã¹ã¬ããããããã¯é¢æ°ãåŒã³åºããŠãããšãã«ãšã©ãŒãçºçããŸããã
ãã®ãšã©ãŒã§ã¯ãåãããšãç°¡åã§ãã é¢æ°ã€ã³ã¿ãŒã»ãã¿ãŒã絶ããåé€ããŠåŸ©å ãããšãããæç¹ã§ããlock xchg word ptr [ecx]ãaxããšããåœä»€ã®SpliceLockJmpé¢æ°ã§ãšã©ãŒãçºçããŸãã äºå®ããã®æç¹ã§å¥ã®ã¹ã¬ããããã€ã³ã¿ãŒã»ãã¿ãŒã®ã¢ãã¬ã¹ã«ããŒãžå±æ§ãè¿ãæäœãå®äºããããšãã§ããã¹ã¬ããã§ãã®ã¢ãã¬ã¹ãžã®æžã蟌ã¿ãèš±å¯ãããšããäºå®ã«ãããããããå®éã®ããŒãžå±æ§ã¯å®å šã«ç°ãªããŸãã
ããã¯ãŸãã«ããã®ãã©ã³ãã®äœæè ãééããåäœã§ãïŒ recvãã€ã³ã¿ãŒã»ããããŸãã
ãã®ãšã©ãŒã¯ãäžèšãšåãæ¹æ³ã§è§£æ±ºããå¿ èŠããããŸãã
確ãã«ãã€ã³ã¿ãŒã»ãããã³ãã©ãŒãå¿ããŠã¯ãªããŸãããã¹ã¬ããã»ãŒãã§ããããŸããããã³ãã©ãŒã®å®è£ ã¯ãŠãŒã¶ãŒæ¬¡ç¬¬ã§ãã
6.ã€ã³ã¿ãŒã»ãããããé¢æ°ã®æåã®2ãã€ããã¹ãããããããšã¯åžžã«å¯èœã§ããïŒ
èå³æ·±ã質åãšããã«å¯Ÿããçãã¯ãå¿ ããããããšã¯éããŸããã
HotPatchã¡ãœããã䜿çšããã€ã³ã¿ãŒã»ããã®æ©èœãæºåãããŠããå ŽåãMicrosoftã¯ããã®åã«åžžã«5ã€ã®NOPåœä»€ãããããã®ãããªåæ©èœã¯2ãã€ãåœä»€ã§å§ãŸãããšã®ã¿ãä¿èšŒããŸãã ãã以äžã®ä¿èšŒã¯ãããŸããã
MessageBoxWãŸãã¯CreateWindowExWã³ãŒããèŠããšãæåã®æçšãªPUSH EBPåœä»€ã1ãã€ããå ããããšãããããŸãã ãããã£ãŠãæ¡ä»¶ãæºãããªãããããã®é¢æ°ã®æ¬äœã®åã«ã¯ç©ºã®åŒã³åºãMOV EDIãEDIããããŸãã åãããšã¯ãé·ãã3ãã€ã以äžã®åœä»€ã§å§ãŸãé¢æ°ã«ãåœãŠã¯ãŸããŸãã ãã ããé¢æ°ã2ãã€ãã®åœä»€ã§å§ãŸãå ŽåãHotPatchã®ãã¹ãŠã®æ¡ä»¶ïŒ5ã€ã®NOPãš2ãã€ãïŒãæºããããããã空ã®ã¹ã¿ãã§æ¬äœãèšããŸããããšã¯æå³ããããŸããã
ãã®å Žåãäžèšã®æ¹æ³ãé©çšãããšããšã©ãŒä»¥å€ã¯è¡šç€ºãããŸããã
ãã®ãããªé¢æ°ã®äŸã¯ãRtlCreateUnicodeStringã§ãã
圹ç«ã€PUSH $ 0Cåœä»€ã§å§ãŸããŸãã

æãç°¡åãªè§£æ±ºçã¯ãå ã®é¢æ°ãåŒã³åºãåã«å ã®åœä»€ã埩å ããããšã§ãããæåããèšã£ãããã«ãããã«ã¯ãšã©ãŒããããããããŸãã
ãããã£ãŠãç§ãã¡ã¯ä»äºã«çŽé¢ããŸãã-劚害ãããåœä»€ãžã®åŒã³åºããæäŸããã€ã³ã¿ãŒã»ããã³ãŒãã»ããããã£ãŠãé¢æ°ã®æ©èœãä¿èšŒããïŒ

ååãšããŠãè©°ãŸã£ãåœä»€ã®ãã·ã³ã³ãŒãããããããã¯HotPathSpliceRec.LockJmpæ§é ã«æ ŒçŽãããŠããŸãããããã€ãã®çç±ã§çŽæ¥åŒã³åºãããšã¯ã§ããŸããã
ãŸããæåã«ããã®æ§é ã¯ããŒãäžã«ãããŸãïŒããæ£ç¢ºã«ã¯ãããŒãäžã§ã¯ãªããå²ãåœãŠãããã¡ã¢ãªå ã«ãããŸããããã¯ãDelphiãããŒãã¡ã«ããºã ãšçŽæ¥é£æºããªãããã§ãïŒã ã¢ãã¬ã¹HotPathSpliceRec.LockJmpã§CALLãäœããã®æ¹æ³ã§å®è¡ãããšããšã©ãŒãçºçããŸãã
ãã¡ãããæ£ããããŒãžå±æ§ãèšå®ã§ããŸãããããã¯é¢åã§ããããããå®è¡å¯èœã³ãŒããããŒã¿é åãšæ··åããªãã§ãã ããã
第äºã«ãå®è¡ããã®åœä»€ã«è»¢éããå Žåã§ããåŒã³åºãããåœä»€ã®ãªãã»ãããèæ ®ããŠãJMPåœä»€ããã®åŸã®æ£ããã¢ãã¬ã¹ã«åŒ·å¶ããå¿ èŠããããŸãïŒãã®å Žåã$ 77B062FBã«ãªããŸããåã®å³ãåç §ïŒã
第äžã«ãåŒã³åºãã«å ããŠãåŒã³åºãããé¢æ°ã«æž¡ããããã©ã¡ãŒã¿ãŒãæ£ããé åºã§ã¹ã¿ãã¯ã«é 眮ããå¿ èŠããããŸããããã«ãããå°ãªããšãasmæ¿å ¥ã䜿çšããå¿ èŠãçããŸãã
ãã¹ãŠãé çªã«è§£æ±ºããŠã¿ãŸãããã
ASMæ¿å ¥ããã®ãã©ã¡ãŒã¿ãŒã®åãæž¡ãã«é¢äžããªãããã«ããã®ã¿ã¹ã¯ãã³ã³ãã€ã©ãŒã«å²ãåœãŠãããšã«ãããäœããã®çš®é¡ã®ã¹ããªã³ã°ããŒãæ©èœãå®è£ ã§ããŸãã
ã€ãŸã ãããã次ã®ãããªã€ã³ã¿ãŒã»ãã¿ãŒãäœæããŸãã
function TrampolineRtlCreateUnicodeString(DestinationString: PUNICODE_STRING; SourceString: PWideChar): Integer; stdcall; begin asm db $90, $90, $90, $90, $90, $90, $90 end; end; function InterceptedRtlCreateUnicodeString(DestinationString: PUNICODE_STRING; SourceString: PWideChar): Integer; stdcall; begin Result := TrampolineRtlCreateUnicodeString(DestinationString, SourceString); ShowMessage(DestinationString^.Buffer); end;
ãã®å Žåãã€ã³ã¿ãŒã»ãã¿ãŒã¯ã¹ããªã³ã°ããŒãåŒã³åºããšãã®ã³ã°ãåŠçããŸãã
ã¹ããªã³ã°ããŒãé¢æ°å ã§ã¯ã7ãã€ããäºçŽãããŠããŸããããã¯ã2ãã€ãã®è©°ãŸã£ãåœä»€ãš5ãã€ãã®NEAR JMPãæžãã®ã«ååãªéã§ãã
é¢æ°èªäœã¯ã³ãŒãé åã«ããããã®åŒã³åºãã§åé¡ãåŒãèµ·ããããšã¯ãããŸããã
ãããŠä»ãéèŠãªãã¥ã¢ã³ã¹ã
äºçŽæžã¿ãããã¯ã®ä»£ããã«ãããã®7ãã€ããæžã蟌ããšãDelphiã®1ã€ã®äžå¿«ãªæ©èœã«ééããŸãã å®éãDelphiã³ã³ãã€ã©ã¯ã»ãšãã©ã®å Žåãé¢æ°ã®ããããŒã°ãšãšãããŒã°ãçæããŸãã
ããšãã°ããããã®åŸãé¢æ°ã®ã³ãŒãã次ã®ããã«ãªã£ããšããŸãã
function TrampolineRtlCreateUnicodeString(DestinationString: PUNICODE_STRING; SourceString: PWideChar): Integer; stdcall; begin asm push $0C // jmp $77B062FB // end; end;
å®éã次ã®ããã«ãªããŸãã

ã€ãŸã ã¹ã¿ãã¯ã«ã¯ã2ã€ã®ãã©ã¡ãŒã¿ãŒDestinationStringããã³SourceStringã®ä»£ããã«ãEBPããã³ECXã¬ãžã¹ã¿ãŒã®å€ãé 眮ãããŸããããã«ããããŸã£ããäºæž¬ã§ããªãçµæãçããŸãã
ããã¯çµ¶å¯Ÿã«å¿ èŠã§ã¯ãªãã®ã§ãç°¡åã«è¡ããŸããã€ãŸããã¹ããªã³ã°ããŒãã³ãŒãã¯ãã®é¢æ°ã®æåããçŽæ¥èšè¿°ãããé¢æ°ããããŒã°ã®æ瀺ãäžæžãããŸãã
ããããå®éã«ã¯ããããã®æ瀺ã¯çµ¶å¯Ÿã«å¿ èŠãããŸããã ã€ã³ã¿ãŒã»ãããããé¢æ°ã®æ¬äœãšãã®å®è¡ã«ãžã£ã³ãããåŸãã³ã³ãããŒã«ã¯ãã¢ã¯ã·ã§ã³ã«ãã£ãŠæªããããã¹ããªã³ã°ããŒãé¢æ°ã§ã¯ãªããåŒã³åºãããå Žæã«çŽæ¥æ»ããŸãã é¢æ°ã®ååã¯ãã³ãã©ãŒã§ãã
ãããã£ãŠãã€ã³ã¿ãŒã»ãã¿ãŒã®åæåã¯æ¬¡ã®æ¹æ³ã§å®è£ ããŸãã
// procedure InitHotPatchSpliceRecEx(const LibraryName, FunctionName: string; InterceptHandler, Trampoline: Pointer; out HotPathSpliceRec: THotPachSpliceData); var OldProtect: DWORD; TrampolineSplice: TNearJmpSpliceRec; begin // HotPathSpliceRec.FuncAddr := GetProcAddress(GetModuleHandle(PChar(LibraryName)), PChar(FunctionName)); // , Move(HotPathSpliceRec.FuncAddr^, HotPathSpliceRec.LockJmp, LockJmpOpcodeSize); // VirtualProtect(Trampoline, LockJmpOpcodeSize + NearJmpSpliceRecSize, PAGE_EXECUTE_READWRITE, OldProtect); try Move(HotPathSpliceRec.LockJmp, Trampoline^, LockJmpOpcodeSize); TrampolineSplice.JmpOpcode := JMP_OPKODE; TrampolineSplice.Offset := PAnsiChar(HotPathSpliceRec.FuncAddr) - PAnsiChar(Trampoline) - NearJmpSpliceRecSize; Trampoline := PAnsiChar(Trampoline) + LockJmpOpcodeSize; Move(TrampolineSplice, Trampoline^, SizeOf(TNearJmpSpliceRec)); finally VirtualProtect(Trampoline, LockJmpOpcodeSize + NearJmpSpliceRecSize, OldProtect, OldProtect); end; // JMP NEAR HotPathSpliceRec.SpliceRec.JmpOpcode := JMP_OPKODE; // ( NearJmpSpliceRecSize , // .. ) HotPathSpliceRec.SpliceRec.Offset := PAnsiChar(InterceptHandler) - PAnsiChar(HotPathSpliceRec.FuncAddr); end;
ã€ã³ã¿ãŒã»ãããããé¢æ°èªäœã®åæåãšåŒã³åºãã¯æ¬¡ã®ãšããã§ãã
type UNICODE_STRING = record Length: WORD; MaximumLength: WORD; Buffer: PWideChar; end; PUNICODE_STRING = ^UNICODE_STRING; function RtlCreateUnicodeString(DestinationString: PUNICODE_STRING; SourceString: PWideChar): BOOLEAN; stdcall; external 'ntdll.dll'; ... procedure TForm2.FormCreate(Sender: TObject); begin // InitHotPatchSpliceRecEx('ntdll.dll', 'RtlCreateUnicodeString', @InterceptedRtlCreateUnicodeString, @TrampolineRtlCreateUnicodeString, HotPathSpliceRec); // NOP- SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - NearJmpSpliceRecSize, HotPathSpliceRec.SpliceRec); end; procedure TForm2.Button1Click(Sender: TObject); var US: UNICODE_STRING; begin // RtlCreateUnicodeString SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); try RtlCreateUnicodeString(@US, 'Test UNICODE String'); finally // SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); end; end;
ããã§ããã¿ã³ãã¯ãªãã¯ããŠãååã®çµæãã¡ãã»ãŒãžã®åœ¢ã§èŠãããšãã§ããŸãã
çµè«ãšããŠ
ãã®çµæã第6ç« ã«ç€ºãããŠããã¹ãã©ã€ã·ã³ã°å®è£ ãªãã·ã§ã³ã¯ãHotPatchçšã«æºåãããé¢æ°ã®ã€ã³ã¿ãŒã»ããã®å Žåã«æãäžè¬çã§ãã ããã¯ãMOV EDIãEDIã¹ã¿ãã®å Žåãããã³ã€ã³ã¿ãŒã»ãããããé¢æ°ã®å é ã«ããæçšãªåœä»€ã®å Žåã«æ£ããæ©èœããŸãã èšäºã®åé ã§èª¬æãããšã©ãŒã®åœ±é¿ã¯åããŸãããããã®ã¢ã«ãŽãªãºã ã䜿çšããŠéåžžã®æ©èœãååããããšã¯ã§ããŸããã ãããã«ã€ããŠã¯ä»¥åã«æžããŸãã ã
æ å ±ãæçã«åå²ããŠäžåºŠã«ãã¹ãŠãæäŸããå¿ èŠããªãããšããaã³ããŸããã1幎åã«ã¢ããã€ã¹ãããããã«ãå 容ãæ¶åããæéãããããã«è³æãå°ããã€æäŸããããšããå§ãããŸã:)
äžæ¹ããã¹ãŠã®çŽ æãããŒãã«å ¥ãããšããŸãæéãããããŸãããããã¯ç§ã«ã¯ãããŸããã次ã«ã倧éã®ããã«å€èªã§ããŸããïŒåäŸããããŸããïŒã
ãããã£ãŠããã®æ¹ãè¯ãã§ãã
ãã®ãªã³ã¯ãããµã³ãã«ã®ãœãŒã¹ã³ãŒããååŸã§ããŸãã
©AlexanderïŒRouse_ïŒããŒã°ã«
2013幎5æ