ãããã¬ãŒã®äœæ¥ã«æ¢ã«ç²ŸéããŠããå Žå-倧äžå€«ã§ããèšäºã§èšåãããŠããäœæ¥ã®ããã€ãã®åŽé¢ãèå³ãåŒãå¯èœæ§ããããŸãã
ãããã¬ãŒã®ç¬ç«ããå®è£ ã«äžåºŠãééããããšããªãããããã«èå³ãããå Žåã¯ãå°ãªããšã次ã®ãªã³ã¯ããå§ããå¿ èŠããããŸãã ãããã°ãšãšã©ãŒåŠç
ããã䜿çšãããšãäŸå€ã®æ§é åŠçããããã°æ å ±ã®æäœããããã³ããªã©ããããã°ã®äž»ãªåŽé¢ã«ã€ããŠåŠç¿ã§ããŸãã å®è¡å¯èœãã¡ã€ã«ã®ã€ã¡ãŒãžãããããŒãã»ã¯ã·ã§ã³ãããã»ã¹ã¡ã¢ãªã«ãŒããRVAãšVAãªã©ã®æäœãªã©ã
ããããããã¯ããã®ãã¹ãŠã®ãããã³ãç解ãããå Žåã®ã¿ã§ãã
ãã®äžéšã®ã¿ãããã·ã³ãã«ãªèšèªã§èª¬æããããã«ããŸããããããã°ãçªç¶èå³ãæã€ããã«ãªãããã¡ããã¢ããªã±ãŒã·ã§ã³ä¿è·ãå®è£ ããå Žåã¯ãå°ãªããšããããã¬ãŒã®è€éããç解ããå¿ èŠããããŸãã ïŒãã以å€ã®å Žåã¯ã©ãã§ããïŒïŒã
èšäºã®ããã¹ãã«ã¯å€ãã®ã³ãŒããå«ãŸããŸãããã€ãã³ãã®ãããã°æã«åæ§é ã®ãã¹ãŠã®ãã©ã¡ãŒã¿ãŒãèæ ®ããããã§ã¯ãããŸãããããã«ã¯MSDNããããŸãã äœæ¥ã«å¿ èŠãªãããã¬ãŒã«ã€ããŠã®ã¿èª¬æãããããã°ãšã³ãžã³ãç¬ç«ããŠå®è£ ããŠãããšãã«çºçããå¯èœæ§ãæãé«ã埮åŠãªéããããã€ãæããã«ããŸãã
ããªããããå°ãªããšãã¢ã»ã³ãã©ã®æå°éã®ç¥èãæã€ããšãæãŸããã æ²ããããªããã®èšäºã¯ãããªãã§ã¯ã§ããŸããã
ãããã¬ãŒãããã»ã¹ã«ã¢ã¿ããããããšããå§ããŸãããã
ããã»ã¹ã«æ¥ç¶ããåã®æåã®ã¹ãããã¯ããããã°ç¹æš©ãååŸããããšã§ãã ããã¯ã次ã®ãããªåçŽãªã³ãŒãã§å®è¡ãããŸãã
function SetDebugPriv: Boolean; var Token: THandle; tkp: TTokenPrivileges; begin Result := false; if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token) then begin if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'), tkp.Privileges[0].Luid) then begin tkp.PrivilegeCount := 1; tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; Result := AdjustTokenPrivileges(Token, False, tkp, 0, PTokenPrivileges(nil)^, PDWord(nil)^); end; end; end;
次ã®ã¹ãããã¯ããã§ã«å®è¡äžã®ããã»ã¹ã«åå ãããããŒãããæ°ããããã»ã¹ãéå§ãããã§ãã
ããã»ã¹ãæ¢ã«å®è¡ãããŠããŠãåå ãããå Žåã¯ãããã»ã¹ã®PIDãèŠã€ããŠæ¬¡ã®ã³ãŒããå®è¡ããã ãã§ãã
function TFWDebugerCore.AttachToProcess(ProcessID: DWORD; SentEntryPointBreakPoint: Boolean): Boolean; begin Result := False; if FProcessInfo.ProcessID <> 0 then Exit; FSetEntryPointBreakPoint := SentEntryPointBreakPoint; FProcessInfo.ProcessID := ProcessID; Result := DebugActiveProcess(ProcessID); end;
確ãã«ããã®ã³ãŒãã¯å°ãªããšã2ã€ã®çç±ã§åžžã«æ£åžžã«å®è¡ããããšã¯éããŸããã
å®éãWindowsã§ã¯ã2ã€ã®ãããã¬ãŒã§åæã«ããã»ã¹ã«æ¥ç¶ããããšã¯äžå¯èœã§ããããããã¬ãŒãå¿ èŠãªããã»ã¹ã«æ¢ã«æ¥ç¶ãããŠããå ŽåãDebugActiveProcessé¢æ°ã®åŒã³åºãã¯æåãããGetLastErrorã¯ãšã©ãŒã³ãŒãERROR_INVALID_PARAMETERãè¿ããŸãã
2çªç®ã®çç±ã¯ãå¿ èŠãªããã»ã¹ããããã¬ãŒãããé«ãç¹æš©ã§éå§ãããŠããããšã§ãã ãã®å ŽåãDebugActiveProcessé¢æ°ã®åŒã³åºãã倱æããGetLastErrorã¯ãšã©ãŒã³ãŒãERROR_ACCESS_DENIEDãè¿ããŸãã
2çªç®ã®å Žåãå¿ èŠãªç¹æš©ã§ãããã¬ãŒãå®è¡ããããšã«ããããã®ãšã©ãŒãåé¿ã§ããŸãã
2çªç®ã®ãªãã·ã§ã³ã¯ã次ã®ã³ãŒãã§ããã»ã¹ãéå§ããããšã«ããããããã¬ãŒãããã»ã¹ã«ã¢ã¿ããããããšã§ãã
function TFWDebugerCore.DebugNewProcess(const FilePath: string; SentEntryPointBreakPoint: Boolean): Boolean; var PI: TProcessInformation; SI: TStartupInfo; begin Result := False; if FProcessInfo.ProcessID <> 0 then Exit; FSetEntryPointBreakPoint := SentEntryPointBreakPoint; ZeroMemory(@SI, SizeOf(TStartupInfo)); SI.cb := SizeOf(TStartupInfo); Result := CreateProcess(PChar(FilePath), nil, nil, nil, False, DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS, nil, nil, SI, PI); if Result then begin FProcessInfo.ProcessID := PI.dwProcessId; FProcessInfo.CreatedProcessHandle := PI.hProcess; FProcessInfo.CreatedThreadHandle := PI.hThread; end; end;
ããã§ã¯ãã¹ãŠãç°¡åã§ããäžèšã®ã³ãŒãã§ã¯ãããã»ã¹ãDEBUG_PROCESSãã©ã°ã§éå§ããããã«DEBUG_ONLY_THIS_PROCESSãã©ã°ãæå®ããŠããããã°ãããããã»ã¹ã«ãã£ãŠäœæãããããã»ã¹ããããã°ããªãããšã瀺ããŠããŸãã
ããã»ã¹ãéå§ããåŸããã®ãã©ã¡ãŒã¿ãŒãèŠããŠãããŠãã ããïŒæçšïŒã
ãããã¬ãŒãšããŠããã»ã¹ã«åå ãããšããã«ããã®ããã»ã¹ã¯åç¬ã§åäœãåæ¢ããååäœã®ããŒã ãåŸ æ©ããŸã-次ã«äœããã¹ããã ãããè¡ãããã«ã圌ã¯ãããã°ã€ãã³ããçæãããããã«åå¿ãããŸã§åŸ æ©ããŸãã
WaitForDebugEventé¢æ°ãåŒã³åºããŠãããã°ããã»ã¹ãããããã°ã€ãã³ããååŸã§ããŸãããã®åŸãContinueDebugEventé¢æ°ãåŒã³åºããŠå¿ èŠãªã¢ã¯ã·ã§ã³ãå®è¡ããå¶åŸ¡ãè¿ãããšãã§ããŸãããã®åŸã次ã®ã€ãã³ããåŸ ã€å¿ èŠããããŸãã
ã€ãŸã 倧äœããããã°ã€ãã³ãã«ãŒããå®è£ ããå¿ èŠããããŸãã
MSNDã§ã¯ã次ã®ãããã°ã€ãã³ãã«ãŒãã®å®è£ ãæšå¥šããŠããŸãã
ãããã¬ãŒã®ã¡ã€ã³ã«ãŒãã®èšè¿°
ãããã¬ã§ãã»ãŒåãããã«å®è£ ããŸãã
procedure TFWDebugerCore.RunMainLoop; var DebugEvent: TDebugEvent; CallNextLoopIteration: Boolean; ThreadIndex: Integer; begin CallNextLoopIteration := False; repeat ContinueStatus := DBG_CONTINUE; if not WaitForDebugEvent(DebugEvent, MainLoopWaitPeriod) then begin if GetLastError = ERROR_SEM_TIMEOUT then begin DoIdle; if FProcessInfo.ProcessID = 0 then Exit; CallNextLoopIteration := True; Continue; end else begin DoMainLoopFailed; Break; end; end; case DebugEvent.dwDebugEventCode of CREATE_THREAD_DEBUG_EVENT: DoCreateThread(DebugEvent); CREATE_PROCESS_DEBUG_EVENT: DoCreateProcess(DebugEvent); EXIT_THREAD_DEBUG_EVENT: DoExitThread(DebugEvent); EXIT_PROCESS_DEBUG_EVENT: begin DoExitProcess(DebugEvent); Break; end; LOAD_DLL_DEBUG_EVENT: DoLoadDll(DebugEvent); UNLOAD_DLL_DEBUG_EVENT: DoUnLoadDll(DebugEvent); OUTPUT_DEBUG_STRING_EVENT: DoDebugString(DebugEvent); RIP_EVENT: DoRip(DebugEvent); EXCEPTION_DEBUG_EVENT: begin ThreadIndex := GetThreadIndex(DebugEvent.dwThreadId); case DebugEvent.Exception.ExceptionRecord.ExceptionCode of EXCEPTION_BREAKPOINT: ProcessExceptionBreakPoint(ThreadIndex, DebugEvent); EXCEPTION_SINGLE_STEP: ProcessExceptionSingleStep(ThreadIndex, DebugEvent); EXCEPTION_GUARD_PAGE: ProcessExceptionGuardPage(ThreadIndex, DebugEvent); else CallUnhandledExceptionEvents(ThreadIndex, CodeDataToExceptionCode( DebugEvent.Exception.ExceptionRecord.ExceptionCode), DebugEvent); end; end; end; CallNextLoopIteration := ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, ContinueStatus); until not CallNextLoopIteration; end;
ãããã°ã®ããã»ã¹ã§ã¯ã絶ãããã®ãµã€ã¯ã«å ã«ããŠãæ¢ç¥ã®ã€ãã³ããåŠçããŸãã ãããã°ã«ãŒãã®åå埩ã§ã®WaitForDebugEventé¢æ°ã¯ãDEBUG_EVENTæ§é äœãè¿ããŸãã ãã®æ§é äœã®dwDebugEventCodeãã©ã¡ãŒã¿ãŒã«åºã¥ããŠãåä¿¡ããã€ãã³ãã®ã¿ã€ããã€ãã³ããçºçããããã»ã¹IDãšã¹ã¬ãããããã³ãã®æ§é äœã®æåŸã®ãã£ãŒã«ãã«ãã£ãŠçµåã®åœ¢ã§è¡šç€ºãããåã€ãã³ãã®ãã©ã¡ãŒã¿ãŒãèå¥ã§ããŸãã
PDebugEvent = ^TDebugEvent; _DEBUG_EVENT = record dwDebugEventCode: DWORD; dwProcessId: DWORD; dwThreadId: DWORD; case Integer of 0: (Exception: TExceptionDebugInfo); 1: (CreateThread: TCreateThreadDebugInfo); 2: (CreateProcessInfo: TCreateProcessDebugInfo); 3: (ExitThread: TExitThreadDebugInfo); 4: (ExitProcess: TExitProcessDebugInfo); 5: (LoadDll: TLoadDLLDebugInfo); 6: (UnloadDll: TUnloadDLLDebugInfo); 7: (DebugString: TOutputDebugStringInfo); 8: (RipInfo: TRIPInfo); end; {$EXTERNALSYM _DEBUG_EVENT} TDebugEvent = _DEBUG_EVENT; DEBUG_EVENT = _DEBUG_EVENT; {$EXTERNALSYM DEBUG_EVENT}
åã€ãã³ãã«ã¯ç¬èªã®ãã©ã¡ãŒã¿ãŒã»ããããããŸããããããã«ã€ããŠã¯åŸã»ã©è©³ãã説æããŸãã
ããããã®ã€ãã³ããã³ãŒãã§åŠçãããªãå ŽåãContinueStatusãã©ã¡ãŒã¿ãŒãDBG_CONTINUEã«èšå®ããŠContinueDebugEventé¢æ°ãåŒã³åºãããããã°ãããããã»ã¹ãå®è¡ãç¶ããã ãã§ãã
ãã¥ã¢ã³ã¹ïŒWaitForDebugEventããšã©ãŒãè¿ããå ŽåïŒã¿ã€ã ã¢ãŠããªã©ïŒãContinueDebugEventãåŒã³åºããªãã§ãã ããããšã©ãŒãè¿ããŸãã ãã®æç¹ã§ã圌ãã¯ãã°ãã°ã€ãŸãããŸããããªãèªèº«ã®ãããã¬ã®å®è£ ã§ãããèæ ®ããããšãå¿ããªãã§ãã ããã
ãããŸã§ã®ãšããããã¹ãŠãéåžžã«åçŽã§ãã次ã«ãã©ã®ã€ãã³ããç§ãã¡ã«äžããããèŠãŠã¿ãŸãããã
CREATE_PROCESS_DEBUG_EVENTïŒ
ãããã°ã®éå§æã«ãããã¬ãŒãåãåãæåã®ã€ãã³ãã ããã»ã¹ãèªåã§éå§ããããDebugActiveProcessãåŒã³åºããŠããã»ã¹ã«åå ãããã¯é¢ä¿ãããŸãããäœæ¥ãéå§ããŸãã ãã®ã€ãã³ãã®ãã©ã¡ãŒã¿ãŒã¯ã DebugEvent.CreateProcessInfoæ§é ïŒCREATE_PROCESS_DEBUG_INFOæ§é ïŒã«ä¿åãããŸãã
äžè¬ã«ããã®ã€ãã³ãã®ãã³ãã©ãŒã¯æ¬¡ã®ããã«ãªããŸãã
procedure TFWDebugerCore.DoCreateProcess(DebugEvent: TDebugEvent); begin // FProcessInfo.AttachedFileHandle := DebugEvent.CreateProcessInfo.hFile; FProcessInfo.AttachedProcessHandle := DebugEvent.CreateProcessInfo.hProcess; FProcessInfo.AttachedThreadHandle := DebugEvent.CreateProcessInfo.hThread; FProcessInfo.EntryPoint := DWORD(DebugEvent.CreateProcessInfo.lpStartAddress); AddThread(DebugEvent.dwThreadId, FProcessInfo.AttachedThreadHandle); // BreakPoint if FSetEntryPointBreakPoint then SetBreakpoint(FProcessInfo.EntryPoint, 'Process Entry Point Breakpoint'); if Assigned(FCreateProcess) then begin FCreateProcess(Self, GetThreadIndex(DebugEvent.dwThreadId), DebugEvent.CreateProcessInfo); DoResumeAction(GetThreadIndex(DebugEvent.dwThreadId)); end; end;
ãã®äžã§ãããã»ã¹ã®ãã©ã¡ãŒã¿ãŒãèŠããŠããã ãã§ãªããããã»ã¹ã®ã¡ã€ã³ã¹ã¬ããã®IDãšãã³ãã«ãå éšãªã¹ãã«è¿œå ããŸãã ãããã®ããŒã¿ã¯åŸã§åœ¹ç«ã¡ãŸãã
ããã§ãããã»ã¹ãšã³ããªãã€ã³ãïŒãšã³ããªãã€ã³ãïŒã決å®ãããã®å€ãDebugEvent.CreateProcessInfo.lpStartAddresãã©ã¡ãŒã¿ãŒã«èšé²ããå¿ èŠã«å¿ããŠããã®ã¢ãã¬ã¹ã«ãã¬ãŒã¯ãã€ã³ãïŒä»¥éBPãšåŒã³ãŸãïŒãèšå®ããå®è¡ããããã»ã¹ãéå§ããŸãã å°ãç²ãå Žåã¯ããã®ã¢ã¯ã·ã§ã³ãå®è¡ããããšã«ãããF7ãã¿ã³ãæŒãããšãã®Delphiãããã¬ãŒã®åäœãã·ãã¥ã¬ãŒãããŸãã
ãšã³ããªãã€ã³ããšã¯ïŒããŒããŒãããã»ã¹ãäœæãããšããããã»ã¹ãéå§ããç¬éãŸã§ãå€ãã®æºåã¢ã¯ã·ã§ã³ãå®è¡ãããŸãã ã¢ããªã±ãŒã·ã§ã³ã®ã¡ã€ã³ã¹ã¬ããã®äœæãã¹ã¿ãã¯ã®èšå®ãç°å¢/ã¹ã¬ãããããã¯ã®åŠçãã©ã€ãã©ãªã®ããŒããTLSã³ãŒã«ããã¯ã®å®è¡ãªã©ã ããããã¹ãŠãå®äºããåŸã«ã®ã¿ãããŒããŒã¯ãããã°ã©ããŒã«ãã£ãŠå®è£ ãããã³ãŒããæ¢ã«éå§ãããŠãããšã³ããªãã€ã³ãã«å¶åŸ¡ãçŽæ¥è»¢éããŸãã ãã®ãã€ã³ãã®ã¢ãã¬ã¹ã¯ãPEãã¡ã€ã«ã®ããããŒã«çŽæ¥æ ŒçŽãããŸããPEãã¡ã€ã«ã®æ§é ã衚瀺ããã¢ããªã±ãŒã·ã§ã³ïŒPEiDãPeExplorerãªã©ïŒããååŸã§ããŸãããŸãã¯ããã¡ã€ã«ã®å é ã«ããTImageDosHeaderæ§é ãèªã¿åãããšã§ãã®å€ãèªã¿åãããšãã§ãããã®_lfanewãã£ãŒã«ãã¯ãªãã»ãããããŸãTImageNtHeadersãèµ·åããŸãããã®åŸãTImageNtHeadersæ§é èªäœãèªã¿åããTImageNtHeaders.OptionalHeader.AddressOfEntryPointãã£ãŒã«ãã®å€ã確èªããŸãã
空ã®ãããžã§ã¯ããã³ã³ãã€ã«ããŠãF7ãæŒããŠãã[CPU-View]ã¿ãã«ç§»åãããšã次ã®ããã«ãªããŸãã
ãšã³ããªãã€ã³ãã¢ãã¬ã¹ãå€æããŸããïŒ0x0043E2D4ã ããã§ãPEiDãçµæã®ã¢ããªã±ãŒã·ã§ã³ã«ã€ããŠäœãäŒããŠããããèŠãŠã¿ãŸãããã
圌ã¯ããšã³ããªãã€ã³ãã®å€ã¯0x0003E2D4ã ãšèšããŸãã
AddressOfEntryPointãã©ã¡ãŒã¿ãŒã«æ ŒçŽãããå€ã¯RVAïŒçžå¯Ÿä»®æ³ã¢ãã¬ã¹ïŒãšããŠè¡šãããããããããã¬ãŒã§èŠãæ°ãšäžèŽããŸããããããã§ãããã§ã¯ãã¹ãŠãæ£ããã§ãã ãã®ã¢ãã¬ãã·ã³ã°ã®ç¹åŸŽã¯ãã¢ãžã¥ãŒã«ïŒhInstanceïŒã®ããŒãã¢ãã¬ã¹ãèæ ®ããªãããšã§ãã RVAã¢ãã¬ã¹ããVAïŒä»®æ³ã¢ãã¬ã¹ïŒãååŸããã«ã¯ãããã«hInstanceã¢ãžã¥ãŒã«ãè¿œå ããå¿ èŠããããŸãã
埮åŠãªéãããããŸããããã¯ã¢ããªã±ãŒã·ã§ã³ã«ã®ã¿åœãŠã¯ãŸããŸãããã©ã€ãã©ãªãŒã§ã¯å°ãç°ãªããŸãã 圌ãã«ãšã£ãŠã¯ãã»ã¯ã·ã§ã³ã®ã¢ãã¬ã¹ã«éäžããå¿ èŠããããŸãã 詳现ã«ã€ããŠã¯ããã®ãã¢ããã¡ã€ã«ããããã£ããã¯ããŒã¯ã®å®è£ ããåç §ããŠãã ããã
DebugHlp.pasã¢ãžã¥ãŒã«ã§ã¯ãImageRvaToVaïŒïŒé¢æ°ã®å®è£ ãæäŸãããŸããããã«ãããã¢ãã¬ã¹ããã£ã¹ãããããã®ã«ãŒã«ãæ確ã«èª¿ã¹ãããšãã§ããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®å ŽåãããŒã¹ããŠã³ããŒãã¢ãã¬ã¹ã¯åžžã«ãImage Baseãã©ã¡ãŒã¿ãŒã®ãªã³ã«ãŒèšå®ã§æå®ãããå€ã«çãããããã©ã«ãã§ã¯0x00400000ã§ãã ãããã®2ã€ã®æ°å€ãè¿œå ãããšãå¿ èŠãª0x0043E2D4ãååŸãããŸãã
LOAD_DLL_DEBUG_EVENTïŒ
CREATE_PROCESS_DEBUG_EVENTã®çŽåŸã«ã DebugEvent.LoadDllæ§é äœïŒLOAD_DLL_DEBUG_INFOæ§é äœïŒã®ãã©ã¡ãŒã¿ãŒã䜿çšããŠãã©ã€ãã©ãªèªã¿èŸŒã¿ã€ãã³ãã®åä¿¡ãéå§ããŸãã
äžè¬çãªã±ãŒã¹ã§ã¯ãDelphiãããã¬ãŒã§ã©ã€ãã©ãªã®ããŒãã芳å¯ã§ããŸããããã«ãããã€ãã³ããã°ã«ããŒãã®éç¥ã衚瀺ãããŸãã
ãã®ã€ãã³ããåãåããšãã¢ãžã¥ãŒã«ãããŒãããããã«BPãã€ã³ã¹ããŒã«ãããŠããå ŽåãDelphiãããã¬ãŒã¯ããŒãçŽåŸã«äžæãããŸãã
ãã®ã³ãŒãã䜿çšããŠãã¢ãžã¥ãŒã«ã®ããŒãã«ã€ããŠãŠãŒã¶ãŒã«éç¥ããããšãã§ããŸãã
procedure TFWDebugerCore.DoLoadDll(DebugEvent: TDebugEvent); begin if Assigned(FLoadDll) then begin FLoadDll(Self, GetThreadIndex(DebugEvent.dwThreadId), DebugEvent.LoadDll); DoResumeAction; end; CloseHandle(DebugEvent.LoadDll.hFile); end;
ãã®å Žåãã€ãã³ããçºçãããããšã«å ããŠãããŒããããã©ã€ãã©ãªã®ãã³ãã«ãããã«éããŸãããããã¯ããå¿ èŠãããŸããïŒãã®ããŒãžã§ã³ã®ãããã¬ãŒå®è£ ã§ã¯ïŒã
ãã¥ã¢ã³ã¹ã¯æ¬¡ã®ãšããã§ããDebugEvent.LoadDll.lpImageNameãã©ã¡ãŒã¿ãŒã«æ ŒçŽãããŠãããããŒããããã©ã€ãã©ãªãžã®ãã¹ãæã€ã¢ãã¬ã¹ã¯ã¢ãã¬ã¹ç©ºéã«ãªããããReadProcessMemoryãä»ããŠèªã¿åãå¿ èŠããããŸãã
2çªç®ã®ãã¥ã¢ã³ã¹ïŒãã®å€ã¯ããã¹ã«é¢ããããŒã¿ãé 眮ãããŠãããããã¡ãŒãžã®ãã€ã³ã¿ãŒã§ããããŸãã å°ãªããšã2åèªãå¿ èŠããããŸãã
3çªç®ã®æ³šæäºé ïŒãã¹ã¯ãAnsiiãšUnicodeãšã³ã³ãŒãã£ã³ã°ã®äž¡æ¹ã§ããå¯èœæ§ããããŸãã
ããŠãããã€ã«ã€ããŠã¯ã4çªç®ã®æ³šæäºé ïŒããŒã¿ãèªã¿åããªãå ŽåããããŸã:)
ããŒãå¯èœãªã©ã€ãã©ãªãžã®æå¹ãªãã¹ãååŸããããã«ãTFWDebugerCoreã¯ã©ã¹ã¯ãããããã¹ãŠã®ãã€ã³ããèæ ®ããGetDllNameã¡ãœãããæäŸããŸãã
å®è£ ãæ€èšããŠãã ããã
TFWDebugerCoreã¯ã©ã¹ã¯ãå€éšã®OnLoadDllã€ãã³ããåŒã³åºããŠã©ã€ãã©ãªã®ããŒããéç¥ããŸããããã§ã次ã®ã³ãŒããèšè¿°ããŸãã
procedure TdlgDebuger.OnLoadDll(Sender: TObject; ThreadIndex: Integer; Data: TLoadDLLDebugInfo); const FormatStrKnownDLL = 'Load Dll at instance %p handle %d "%s"'; FormatStrUnknownDLL = 'Load unknown Dll at instance %p handle %d'; var DllName: AnsiString; IsUnicodeData: Boolean; begin FCore.ContinueStatus := DBG_EXCEPTION_NOT_HANDLED; IsUnicodeData := Data.fUnicode = 1; DllName := FCore.GetDllName(Data.lpImageName, Data.lpBaseOfDll, IsUnicodeData); if DllName <> '' then begin if IsUnicodeData then Writeln(Format(FormatStrKnownDLL, [Data.lpBaseOfDll, Data.hFile, PWideChar(@DllName[1])])) else Writeln(Format(FormatStrKnownDLL, [Data.lpBaseOfDll, Data.hFile, PAnsiChar(@DllName[1])])); end else Writeln(Format(FormatStrUnknownDLL, [Data.lpBaseOfDll, Data.hFile])); end;
ããã§ã¯ãTFWDebugerCore.GetDllNameïŒïŒã¡ãœãããåŒã³åºããïŒfUnicodeãã©ã¡ãŒã¿ãŒã«çŠç¹ãåœãŠãŠïŒããŒã¿ãã³ã³ãœãŒã«ã«åºåããŸãã
GetDllNameã¡ãœããã®å®è£ ã¯æ¬¡ã®ãšããã§ãã
function TFWDebugerCore.ReadData(AddrPrt, ResultPtr: Pointer; DataSize: Integer): Boolean; var Dummy: DWORD; begin Result := ReadProcessMemory(FProcessInfo.AttachedProcessHandle, AddrPrt, ResultPtr, DataSize, Dummy) and (Integer(Dummy) = DataSize); end; function TFWDebugerCore.ReadStringA(AddrPrt: Pointer; DataSize: Integer): AnsiString; begin SetLength(Result, DataSize); if not ReadData(AddrPrt, @Result[1], DataSize) then Result := ''; end; function GetMappedFileNameA(hProcess: THandle; lpv: Pointer; lpFilename: LPSTR; nSize: DWORD): DWORD; stdcall; external 'psapi.dll'; function TFWDebugerCore.GetDllName(lpImageName, lpBaseOfDll: Pointer; var Unicode: Boolean): AnsiString; var DllNameAddr: Pointer; MappedName: array [0..MAX_PATH - 1] of AnsiChar; begin if ReadData(lpImageName, @DllNameAddr, 4) then Result := ReadStringA(DllNameAddr, MAX_PATH); if Result = '' then begin if GetMappedFileNameA(FProcessInfo.AttachedProcessHandle, lpBaseOfDll, @MappedName[0], MAX_PATH) > 0 then begin Result := PAnsiChar(@MappedName[0]); Unicode := False; end; end; end;
ã€ãŸããæåã«ããããã°ãããããã»ã¹ã®ã¢ãã¬ã¹ç©ºéïŒReadData + ReadStringAïŒããããŒã¿ãèªã¿åã£ãŠã©ã€ãã©ãªãã¹ãååŸããããšããŸããããŸããããªãå Žåã¯ãGetMappedFileNameAé¢æ°ãåŒã³åºããŠãã®ããŒã¿ãååŸããŸãã ã·ã³ããªãã¯ãªã³ã¯ã䜿çšããŠããŒã¿ãè¿ããããè¯å¥œãªçµæãéåžžã®ãã¹ã«æ»ãå¿ èŠããããŸããããã®å Žåã¯ã³ãŒããé床ã«è€éã«ããªãããã«ãããè¡ããŸããã§ããã
CREATE_THREAD_DEBUG_EVENT
ãããã°ãããã¢ããªã±ãŒã·ã§ã³ã§æ°ããã¹ã¬ãããäœæããããšãã«ããã®ã€ãã³ããåãåããŸãã ãã®ã€ãã³ãã®ãã©ã¡ãŒã¿ãŒã¯ã DebugEvent.CreateThreadæ§é äœïŒCREATE_THREAD_DEBUG_INFOæ§é äœïŒã«ä¿åãããŸãã
ãã¹ãŠã®ãã©ã¡ãŒã¿ãŒã®ãã¡ãæãé¢å¿ãããã®ã¯DebugEvent.CreateThread.hThreadã§ããããã¯å éšãªã¹ãã«ä¿åããããšãæãŸããã§ãã
ãã¥ã¢ã³ã¹ã¯ãã»ãšãã©ã®ã€ãã³ãã«ã¯ã¹ã¬ããã®IDã®ã¿ã«é¢ããããŒã¿ãå«ãŸããŠãããããããã䜿çšããå ŽåïŒããšãã°ãããŒããŠã§ã¢ãã¬ãŒã¯ãã€ã³ãã®ã€ã³ã¹ããŒã«ïŒãéä¿¡ãããIDã«å¯ŸããŠOpenThreadåŒã³åºããè¡ãå¿ èŠããããŸãã ãããã®ã¢ã¯ã·ã§ã³ã«ç ©ããããªãããã«ãThreadID = ThreadHandleã®ãã¢ãç¬èªã®ãã£ãã·ã¥ã«ä¿æããŸãã
ãã®ã€ãã³ãã®ãã³ãã©ãŒã³ãŒãã¯æ¬¡ã®ãšããã§ãã
procedure TFWDebugerCore.DoCreateThread(DebugEvent: TDebugEvent); begin AddThread(DebugEvent.dwThreadId, DebugEvent.CreateThread.hThread); if Assigned(FCreateThread) then begin FCreateThread(Self, GetThreadIndex(DebugEvent.dwThreadId), DebugEvent.CreateThread); DoResumeAction; end; end;
ã¹ã¬ããã®ãã©ã¡ãŒã¿ãŒãä¿åããå€éšãã³ãã©ãŒãåŒã³åºãããšã«å ããŠããã®äžã«ã¯äœããããŸããã
OUTPUT_DEBUG_STRING_EVENTïŒ
ã€ãã³ãã¯ããããã°ãããã¢ããªã±ãŒã·ã§ã³ãOutputDebugStringé¢æ°ã®åŒã³åºãã«äœããéä¿¡ããããšããŠãããšãã«çæãããŸãã ãã®ã€ãã³ãã®ãã©ã¡ãŒã¿ãŒã¯ã DebugEvent.DebugStringæ§é ïŒOUTPUT_DEBUG_STRING_INFOæ§é ïŒã«ä¿åãããŸãã
ã€ãã³ããã³ãã©ã¯ç°¡åã§ãã
procedure TFWDebugerCore.DoDebugString(DebugEvent: TDebugEvent); begin if Assigned(FDebugString) then begin FDebugString(Self, GetThreadIndex(DebugEvent.dwThreadId), DebugEvent.DebugString); DoResumeAction; end; end;
ã€ãŸã ããŒãå¯èœãªã©ã€ãã©ãªãžã®ãã¹ãèªã¿åãã®ãšåãååã«åŸã£ãŠãéä¿¡ãããæååãèªã¿åãå¿ èŠãããå€éšãã³ãã©ãåŒã³åºãã ãã§ãã
ããšãã°ã次ã®ããã«ïŒ
procedure TdlgDebuger.OnDebugString(Sender: TObject; ThreadIndex: Integer; Data: TOutputDebugStringInfo); begin if Data.fUnicode = 1 then Writeln('DebugString: ' + PWideChar(FCore.ReadStringW(Data.lpDebugStringData, Data.nDebugStringLength))) else Writeln('DebugString: ' + PAnsiChar(FCore.ReadStringA(Data.lpDebugStringData, Data.nDebugStringLength))); end;
ãã³ãã©ãŒã§ã¯ãData.fUnicodeãã©ã¡ãŒã¿ãŒã«çŠç¹ãåãããŠããããã¡ãŒã«æž¡ããããšã³ã³ãŒãã調ã¹ããããã¬ãŒã³ã¢ã®ReadStringXïŒïŒã®å¯Ÿå¿ããé¢æ°ãåŒã³åºããŸãã
UNLOAD_DLL_DEBUG_EVENTãEXIT_THREAD_DEBUG_EVENTãEXIT_PROCESS_DEBUG_EVENTãRIP_EVENTïŒ
ã©ã€ãã©ãªã®ã¢ã³ããŒããã¹ã¬ããã®ã¯ããŒãºãããã»ã¹ã®çµäºããããã¬ãŒã³ã¢ã§ã®ãšã©ãŒã
ãããã®4ã€ã®ã€ãã³ãã¯ã¹ãããããŸãã ãããã«ã€ããŠç¹å¥ãªãã®ã¯äœããããŸããã ãããã®ãããããåãåããšãå€éšãã³ãã©ãŒãåŒã³åºããããããã¬ãŒã«ãã£ãŠä¿åãããå éšãªã¹ããæ¶å»ãããŸãã
ãããã䜿çšããå Žåããã¥ã¢ã³ã¹ã¯ãããŸããã
EXCEPTION_DEBUG_EVENTïŒ
äžèšã®8ã€ã®ã€ãã³ãã¯ãã¹ãŠãååãšããŠäºæ¬¡çãªãã®ã§ãã ã¡ã€ã³ã®äœæ¥ã¯ãEXCEPTION_DEBUG_EVENTã€ãã³ãã®å°çåŸã«ã®ã¿éå§ãããŸãã
ãã®ãã©ã¡ãŒã¿ãŒã¯DebugEvent.Exceptionæ§é ïŒEXCEPTION_DEBUG_INFOæ§é ïŒã«éãããŸãã
ãã®ã€ãã³ãã®çæã¯ããããã°ãããã¢ããªã±ãŒã·ã§ã³ã§ç¹å®ã®äŸå€ãçºçããããšãæå³ãããã®ã¿ã€ãã¯DebugEvent.Exception.ExceptionRecord.ExceptionCodeãã©ã¡ãŒã¿ãŒã§èŠã€ããããšãã§ããŸãã èšäºã®æåã®éšåã§ããããã°ã¯æ§é åãšã©ãŒåŠçïŒSEHïŒã¡ã«ããºã ãä»ããŠè¡ãããããšãèŠããŠããŸããïŒ æ¬¡ã«ãããã«ã€ããŠããã«è©³ããæ€èšããŸãã
ãããã°ããã»ã¹ã®ã»ãšãã©ã®äŸå€ãææãããŠããŸãã ã€ãŸããäŸå€ãååŸããŠããããã°ã©ã èªäœã§ãšã©ãŒãçºçããããã§ã¯ãããŸããã ãããããBPã®ã€ã³ã¹ããŒã«ãªã©ãã¢ããªã±ãŒã·ã§ã³ã§ã®ãããã¬ãŒã®ä»å ¥ãåå ã§äŸå€ãçºçããŸããã
ãã¥ã¢ã³ã¹ïŒã¢ããªã±ãŒã·ã§ã³èªäœã§ãšã©ãŒãçºçããå Žåããããã°äŸå€ã®åœ¢åŒã§ããšã©ãŒãåãåããŸãããŸãããŠãŒã¶ãŒãšã©ãŒãšèªå°ããããšã©ãŒãåºå¥ã§ããããã«ããããã¬ã³ãŒããå®è£ ããå¿ èŠããããŸãã
éåžžããããã¬ãŒã¯BPãæäœããããã®3ã€ã®ã¡ã«ããºã ãæäŸããŸãïŒå®éããã®æ©èœã¯åŸæ¥ã®BPã§ã¯ãªããããBPãèæ ®ããŠã¢ãžã¥ãŒã«ãããŒãããªãå ŽåïŒã
- ã³ãŒãè¡ããšã®æšæºBPã
- ã¡ã¢ãªã¢ãã¬ã¹ãžã®BPïŒã¡ã¢ãªãã¬ãŒã¯ãã€ã³ããŸãã¯Delphiã®åãæšãŠãããããŒã¿ããªã¢ãã¯ãã€ã³ãïŒã
- ããŒããŠã§ã¢BPïŒDelphiã§ã¯äœ¿çšäžå¯ïŒã
ãããã䜿çšããã«ã¯ã3çš®é¡ã®äŸå€ãåŠçããã ãã§ååã§ãã
EXCEPTION_DEBUG_EVENT: begin ThreadIndex := GetThreadIndex(DebugEvent.dwThreadId); case DebugEvent.Exception.ExceptionRecord.ExceptionCode of EXCEPTION_BREAKPOINT: ProcessExceptionBreakPoint(ThreadIndex, DebugEvent); EXCEPTION_SINGLE_STEP: ProcessExceptionSingleStep(ThreadIndex, DebugEvent); EXCEPTION_GUARD_PAGE: ProcessExceptionGuardPage(ThreadIndex, DebugEvent); else CallUnhandledExceptionEvents(ThreadIndex, CodeDataToExceptionCode( DebugEvent.Exception.ExceptionRecord.ExceptionCode), DebugEvent); end; end;
ããã3ã€ã®äŸå€ã ãã§ååãªçç±ãããæ確ã«ããããã«ãEXCEPTION_DEBUG_EVENTã€ãã³ããåŠçããããã®ããžãã¯ã®åæã«é²ãåã«ãåã¿ã€ãã®BPãèšå®ããã¡ã«ããºã ãæåã«æ€èšããå¿ èŠããããŸãã
ã³ãŒãè¡ã«ãã¬ãŒã¯ãã€ã³ããå®è£ ããïŒ
ã³ãŒãè¡ãžã®BPã®ã€ã³ã¹ããŒã«ã¯ããããã°ãããã¢ããªã±ãŒã·ã§ã³ã®ã³ãŒããå€æŽããããšã«ããè¡ãããŸãã å€å žçã«ã¯ãããã¯BPã«ãã£ãŠèšå®ãããã¢ãã¬ã¹ã«åœä»€ãINT3ããæå³ãã0xCCãªãã³ãŒããæžã蟌ãããšã«ãã£ãŠè¡ãããŸãã
ä»ã®ãªãã·ã§ã³ãããšãã°0xCD03ãªãã³ãŒãããããŸããããã¯ãINT3ãåœä»€ã§ããããŸãã 2çªç®ã®ãªãã·ã§ã³ã¯ãã¢ã³ããããã°ã®ããã«ããå€ã䜿çšãããã»ãšãã©ã®å Žåãã¢ããªã±ãŒã·ã§ã³èªäœã«ãã£ãŠã€ã³ã¹ããŒã«ãããŸããæ ž_KiTrap03ïŒïŒã¯ã·ã³ã°ã«ãã€ããªãã³ãŒãã§ã®ã¿åäœããããã«ãã€ããªãã³ãŒãããããã«èª€ã£ãŠåŠçãããšããäºå®ã§ãããã¬ãŒã®ååšããã£ããããããšããŸãã
ããããããã¯ãã¹ãŠæè©ã§ããæåã®ãªãã³ãŒãã«èå³ããããŸãã
ã€ã³ã¹ããŒã«ãããBPã®ãªã¹ããä¿åããããã«ãTFWDebugerCoreã¯ã©ã¹ã¯æ¬¡ã®æ§é ã䜿çšããŸãã
// ( ) TBreakpointType = ( btBreakpoint, // WriteProcessMemoryEx + 0xCC btMemoryBreakpoint // VirtualProtectEx + PAGE_GUARD ); // TInt3Breakpoint = record Address: Pointer; ByteCode: Byte; end; TMemotyBreakPoint = record Address: Pointer; Size: DWORD; BreakOnWrite: Boolean; RegionStart: Pointer; RegionSize: DWORD; PreviosRegionProtect: DWORD; end; TBreakpoint = packed record bpType: TBreakpointType; Description: ShortString; Active: Boolean; case Integer of 0: (Int3: TInt3Breakpoint;); 1: (Memory: TMemotyBreakPoint); end; TBreakpointList = array of TBreakpoint;
æ°ããBPãè¿œå ããåã«ã圌ã¯TBreakpointã¬ã³ãŒããåæåããŠå¿ èŠãªãã©ã¡ãŒã¿ãŒãå ¥åããããããã¬ãŒã¯ãã€ã³ãã®äžè¬ãªã¹ãã«è¿œå ããŸãã
ã³ãŒãè¡ã®BPã®å Žåã0xCCãªãã³ãŒãã§æ¶å»ããåã«ãBPã®ã¢ãã¬ã¹ãšãã®ã¢ãã¬ã¹ã«ä¿åãããŠãããã€ãã®å€ã®2ã€ã®å€ã®ã¿ãä¿åããå¿ èŠããããŸãã
ãããã°ãããã¢ããªã±ãŒã·ã§ã³ã«BPãã€ã³ã¹ããŒã«ãããšã次ã®ããã«ãªããŸãã
function TFWDebugerCore.SetBreakpoint(Address: DWORD; const Description: string): Boolean; var Breakpoint: TBreakpoint; OldProtect: DWORD; Dummy: DWORD; begin ZeroMemory(@Breakpoint, SizeOf(TBreakpoint)); Breakpoint.bpType := btBreakpoint; Breakpoint.Int3.Address := Pointer(Address); Breakpoint.Description := Description; Check(VirtualProtectEx(FProcessInfo.AttachedProcessHandle, Pointer(Address), 1, PAGE_READWRITE, OldProtect)); try Check(ReadProcessMemory(FProcessInfo.AttachedProcessHandle, Pointer(Address), @Breakpoint.Int3.ByteCode, 1, Dummy)); Check(WriteProcessMemory(FProcessInfo.AttachedProcessHandle, Pointer(Address), @BPOpcode, 1, Dummy)); finally Check(VirtualProtectEx(FProcessInfo.AttachedProcessHandle, Pointer(Address), 1, OldProtect, OldProtect)); end; Result := AddNewBreakPoint(Breakpoint); end;
æåã«ãæ§é ãåæåãããBPã®ã¿ã€ãã確ç«ããããã®èª¬æãšãã©ã¡ãŒã¿ãŒãèšå®ãããŸããéåžžã¯æžã蟌ã¿æš©éãæããªãã³ãŒãé åã«æžã蟌ãããã察å¿ããæš©å©ãèšå®ãããã¢ãã¬ã¹BPã«ããå ã®å€ãèªã¿åãããBPOpcodeå®æ°ã§è¡šããã0xCCåœä»€ãæžã蟌ãŸããå ã®ããŒãžå±æ§ãVirtualProtectExïŒïŒã®ç¹°ãè¿ãåŒã³åºãã«ãã£ãŠè¿ãããŸãããã¹ãŠã®æåŸã§ããšã©ãŒãçºçããŠããªãå Žåãã€ã³ã¹ããŒã«ãããBPã®ã¬ã³ãŒããã¯ã©ã¹ã®äžè¬ãªã¹ãã«é 眮ãããŸãã
ããŠãä»ãã楜ãã¿ãå§ãŸããŸãïŒ
BPã®ã€ã³ã¹ããŒã«åŸããããã°ãããã¢ããªã±ãŒã·ã§ã³ã¯ãåœç€Ÿãèšé²ããINT3åœä»€ãžã®ç§»è¡ãçºçãããŸã§éåžžã®åäœãç¶ããŸãããã®æç¹ã§ãEXCEPTION_DEBUG_EVENTã€ãã³ããäŸå€ã³ãŒãEXCEPTION_BREAKPOINTã§çºçããŸãã
äŸå€ãã©ã¡ãŒã¿ãŒã¯ãDebugEvent.Exception.ExceptionRecordïŒEXCEPTION_DEBUG_INFOæ§é äœïŒæ§é äœã® 圢åŒã§æž¡ãããŸãã
åã«èª¬æããããã«ãBPã¯ãããã°ãããã¢ããªã±ãŒã·ã§ã³èªäœã«ãã£ãŠã€ã³ã¹ããŒã«ã§ããŸãããããã£ãŠããããã®ãã©ã¡ãŒã¿ãŒã«æ³šç®ããŠãã©ã®ãããªBPãæ©èœããããææ¡ããå¿ èŠããããŸããïŒ
ãããè¡ãã«ã¯ã以åã«ä¿åããããã¬ãŒã¯ãã€ã³ãã®ãªã¹ããå¿ èŠã§ãããããå®è¡ããDebugEvent.Exception.ExceptionRecord.ExceptionAddressãã©ã¡ãŒã¿ãŒã«æ ŒçŽãããã¢ãã¬ã¹ãbtBreakpointã¿ã€ãã®åã¬ã³ãŒãã®Addressãã£ãŒã«ããšæ¯èŒãããšãBPããã®ã¢ãã¬ã¹ã«ã€ã³ã¹ããŒã«ãããããããšãç§ãã¡ã®ãã®ã§ã¯ãªãããå€æã§ããŸãã
BPãæ¬åœã«ç§ãã¡ã®ãã®ã§ãããšå€æããå Žåã¯ãå€éšã€ãã³ããçºçããïŒããã«ããã ãã§ãªããåäœããŠããããšããŠãŒã¶ãŒã«ç€ºãããïŒããããåŠçããåŸããããã°ãããã¢ããªã±ãŒã·ã§ã³ã埩å ããŸãã
BPãã€ã³ã¹ããŒã«ããå Žåã®çµæïŒBPãã€ã³ã¹ããŒã«ãã
ãšãå®è¡å¯èœã³ãŒãã®äžéšã倱ãããŸãã
ããšãã°ãåæã³ãŒãã¯æ¬¡ã®ãšããã§ããã
æäœåŸã次ã®ããã«ãªããŸããã
æåã®ã¹ãããã¯ãå ã®åœä»€ã®æå³ã埩å ããããšã§ãã
ããããã䟿å©ã«ããããã«ãTBreakpointæ§é ã«ã¯ããã¬ãŒã¯ãã€ã³ãã®ç¶æ ã瀺ãActiveãã©ã¡ãŒã¿ãŒããããŸãããã®ãã©ã¡ãŒã¿ãŒã«æ³šç®ããŠãTFWDebugerCoreã¯ã©ã¹ã¯ã¢ã¯ãã£ããã£ãèªèããç¶æ ãåãæ¿ããããã«ToggleInt3Breakpointã¡ãœãããå®è£ ããŸãããã®ã¡ãœããã§ã¯ããã©ã°ã«å¿ããŠBPã®ãªã³ãšãªããåãæ¿ããæ¶å»ããããã€ãããã®å Žæã«æ»ããŸãã
procedure TFWDebugerCore.ToggleInt3Breakpoint(Index: Integer; Active: Boolean); var OldProtect: DWORD; Dummy: DWORD; begin CheckBreakpointIndex(Index); if FBreakpointList[Index].bpType <> btBreakpoint then Exit; if FBreakpointList[Index].Active = Active then Exit; Check(VirtualProtectEx(FProcessInfo.AttachedProcessHandle, FBreakpointList[Index].Int3.Address, 1, PAGE_READWRITE, OldProtect)); try if Active then Check(WriteProcessMemory(FProcessInfo.AttachedProcessHandle, FBreakpointList[Index].Int3.Address, @BPOpcode, 1, Dummy)) else Check(WriteProcessMemory(FProcessInfo.AttachedProcessHandle, FBreakpointList[Index].Int3.Address, @FBreakpointList[Index].Int3.ByteCode, 1, Dummy)); finally Check(VirtualProtectEx(FProcessInfo.AttachedProcessHandle, FBreakpointList[Index].Int3.Address, 1, OldProtect, OldProtect)); end; FBreakpointList[Index].Active := Active; end;
å®è£ ã¯ãBPãåã€ã³ã¹ããŒã«ãããšãã«ããã€ãå€ãå床èªã¿åãå¿ èŠããªããšããç¹ãé€ããŠãBPãèšå®ããã³ãŒããšã»ãŒåãã§ãïŒæ¢ã«ããã£ãŠããããïŒã
ããã§æ³šæç¹ïŒãããã°ããã¢ããªã±ãŒã·ã§ã³ãä»å®è¡ãããšããšã©ãŒãçºçããŸãããããŠããã¹ãŠãINT3ãåœä»€ããã§ã«å®è¡ãããŠããã0x452220ã®å Žæã«ççšãããã€ããæ»ãããšããŠãããããã°ãããããã°ã©ã ã¯ããmov ebpãespãåœä»€ããããã©ãããã§ã¯ãªãã¢ãã¬ã¹0x452221ããå®è¡ãç¶ç¶ããŸããããã°äŸå€ãã¹ããŒãããŸããã
2çªç®ã®ãã¥ã¢ã³ã¹ïŒç¢ºãã«ãã®æ¹åã«å€¢ãèŠãããšãã§ããŸãïŒãããŠãèããŠã¿ãŠãã ãã-ãebpãããã·ã¥ãã¯å€±æããŸãããã¹ã¿ãã¯ã¯æµ®ãäžãããŸããããç§ãã¡ã¯ãããã¬ãŒã§ãããäœããæ¥ãŠãã¹ãŠãä¿®æ£ã§ããå Žå©ããã€ãŸãã1ã€ã®ç¹ãé€ããŠãåºæ¬çã«æ£ããã§ãã
ã¯ãããã®å Žåããããã¬ãŒãšããŠã¹ã¿ãã¯ããããŒãæ£ãã移åããæºããããŠããªãåœä»€ã«æ³šæãæãããšã¯ã§ããŸããããã¢ã³ããããã°ïŒããæ£ç¢ºã«ã¯éã¢ã»ã³ãã©ãŒãé£èªåããããšãç®çãšãããããã¬ãŒã¯ããã«æ°ä»ããªãïŒãšããŠé »ç¹ã«äœ¿çšãããããªãã¯ããããŸãæ瀺ã®éäžã
ãããäœã§ãããïŒ
ãã®ãã¯ããã¯ã¯ãéã¢ã»ã³ãã©ããã·ã³ã³ãŒããåžžã«æ£ãã解éã§ããããã§ã¯ãªããšããäºå®ã«åºã¥ããŠããŸãã
äŸãšããŠãããªãã®æ°ã®éçºè ããé·ãNOPããªã©ã®æŠå¿µãç¥ã£ãŠããŸããããã«ã1幎ååã«ã¯Intelã®ããã¥ã¢ã«ã«ã¯ãããŸããã§ããããNOPïŒã³ãŒãã®æŽåã«äœ¿çšããã空ã®åœä»€ïŒã¯0x90ãªãã³ãŒãã®åœ¢åŒã§ã®ã¿è¡šç€ºããããšèšãããŠããŸããããããã£ãŠãã»ãšãã©ã®éã¢ã»ã³ãã©ãŒã¯ãã®ãªãã³ãŒãã§ã®ã¿æ©èœããŸããã¯ãããããããªã倧å€æ°-ç§ã¯ãŸã é·ã足ãæ£ããèªèããéã¢ã»ã³ãã©ãŒã«äŒã£ãŠããŸããã
éã¢ã»ã³ãã©ã¯æ£åžžã«èªèã§ããªãããã次ã®ããªãã¯ãå®è¡ã§ããŸãã
ããšãã°ã3ãã€ãã®NOPïŒãªãã³ãŒã$ 0Fã$ 1Fã$ 00ïŒãååŸããŠããã®ã³ãŒããèšè¿°ããŸãã
asm db $0F, $1F, $00 xor eax, eax inc eax neg eax end;
ãããŠãããã«éã¢ã»ã³ãã©ãŒã瀺ããã®ããããŸãïŒ
ãã¹ãŠã®åœä»€ã®ãªãã³ãŒãã¯æ£ãããæ£ããå®è¡ãããŸãããéã¢ã»ã³ãã©ãŒã¯æåã«æžãããã®ã絶察ã«ç€ºããŸããã
ãŸãããŸãã¯2çªç®ã®äŸã§ã¯ãæ¢ã«çŽæ¥ãžã£ã³ãã䜿çšããŠããŸããããã§ã®èãæ¹ã¯ã次ã®åœä»€ã®éå§åã«ã絶察巊ãã€ããæžã蟌ãŸãããã®åã«åœä»€ã³ãŒããjmp +1ããæžã蟌ãŸããããã°ã©ã ããã®ã¬ããŒãžãã€ããã¹ãããããŠç®çã®ã³ãŒãã«çŽæ¥ç§»åãããšããäºå®ã«ãããŸããããã¯å¹³å¡ãªããšã®ããã«æããŸãããéã¢ã»ã³ãã©ãŒã¯éåžžã«æ··ä¹±ããŠããŸãã
äŸãšããŠã次ã®ã³ãŒããèšè¿°ããŸãã
asm db $EB, $01 // jmp +1 ( xor " ") db $B8 // "" xor eax, eax // inc eax neg eax not eax sub edx, eax imul eax, edx nop nop end;
ããŠãéã¢ã»ã³ãã©ãŒãç§ãã¡ã«äœã瀺ããŠããã®ãèŠãŠã¿ãŸãããïŒ
æåŸ éãã®å®å šãªãŽãã
BPã«æ»ããããã·ã¥$ 00452245åœä»€ã®éå§æã«0x452220ã§ã¯ãªããããã«9ãã€ãã§ã€ã³ã¹ããŒã«ããããšæ³åããŠã¿ãŸãããã
ãã®åœä»€ã¯ãã·ã³ã°ã«ãã€ãã®ãããã·ã¥epbããšã¯ç°ãªãã5ãã€ãã®åœ¢åŒã§è¡šç€ºãããŸããæ¶å»ããããã€ãã®å€ã®å埩ãçºçããåŸã§ããã³ãŒããå®è¡ãç¶ãããšãåœä»€ã®å é ããã§ã¯ãªãããã®éäžããéå§ããŸããããã§ã¯ãéã¢ã»ã³ãã©ã§ã¯ãªãããããã¬èªäœãééã£ãŠããŸããæ¹æ³ïŒ
ã€ãŸãå ã®ãpush $ 00452245ãã®ä»£ããã«ããinc epbãããã³ãand alã[ebp + $ 00]ããšããåœä»€ãå®è¡ãããŸãããããã¯ããã§ã¯ãããŸããã§ããããããŠãããã€ãã®æ瀺ã®åŸãäºæ³ããããã®ãã€ãŸããšã©ãŒãååŸããŸãã
ãããã£ãŠãæ¶å»ããããã€ãããã®å Žæã«æ»ãã ãã§ã¯ååã§ã¯ãªãããããã°ãããã¢ããªã±ãŒã·ã§ã³ã«æ£ããã¢ãã¬ã¹ããããã°ã©ã ãç¶è¡ãããå¿ èŠããããŸãã次ã®å埩ã§å®è¡ãããåœä»€ã®ã¢ãã¬ã¹ã«ã¯ãEIPïŒæ¡åŒµåœä»€ãã€ã³ã¿ãŒïŒã¬ãžã¹ã¿ãæ ŒçŽãããŸãããã®ã¬ãžã¹ã¿ãžã®ã¢ã¯ã»ã¹ã¯ãå²ã蟌ã¿ãçºçãããããã°æžã¿ããã»ã¹ã®ã¹ã¬ããã³ã³ããã¹ããä»ããŠå®è¡ãããŸãã EIPã¬ãžã¹ã¿ã®å€ãå€æŽããã«ã¯ãGetThreadContexté¢æ°ãåŒã³åºããŠã³ã³ããã¹ããååŸããContext.Eipãã©ã¡ãŒã¿ãŒã®çŸåšã®å€ãæžãããŠãããSetThreadContexté¢æ°ãåŒã³åºããŠæ°ããå€ãæžã蟌ãå¿ èŠããããŸãã
埮åŠãªéãããããŸãïŒEXCEPTION_DEBUG_EVENTã€ãã³ããçºçãããšãDebugEvent.dwThreadIdãã©ã¡ãŒã¿ãŒã§ã¹ã¬ããIDã®ã¿ãååŸããGetThreadContextïŒïŒããã³SetThreadContextïŒïŒé¢æ°ã¯äœæ¥ã«ã¹ã¬ãããã³ãã«ãå¿ èŠãšããŸãããã¡ãããOpenThreadé¢æ°ãåŒã³åºãããšã§å¿ èŠãªå€ãååŸã§ããŸããããã®å ŽåãThreadID = ThreadHandleã®åœ¢åŒã§ä¿åãããã¹ã¬ãããã³ãã«ã®ä¿åãªã¹ããããããããããè¡ãå¿ èŠã¯ãããŸããã
ããã§ãã¹ãŠãæ£ããè¡ãããæ¶å»ããããã€ãã埩å ãããåœä»€ã®æ£ããã¢ãã¬ã¹ãèšå®ãããããã«èŠããŸããå®è¡ã®ããã«ããã°ã©ã ãå®è¡ããããšãã§ããŸããããã1ã€ãããŸãããããŠã0xCCãªãã³ãŒããåé€ããåŸãBPã¬ã³ãŒãã¯ãããã¬ãŒãªã¹ãã«ã®ã¿æ®ã£ãŠããŸãããããããã°ãããã¢ããªã±ãŒã·ã§ã³ã«ã¯å®éã«ã¯ãªãããã以åã«ã€ã³ã¹ããŒã«ãããBPãã©ãããŸããïŒä»ããã°ã©ã ãå®è¡ãããšãçŸåšã®åœä»€ãå®è¡ãããåæ¢ããããšãªã次ã®åœä»€ã«ç§»åããä»ã®BPãŸãã¯ãšã©ãŒãçºçãããŸã§ããã°ã©ã ã³ãŒãã®å®è¡ãç¶ããŸãã
ãã®ãããã¿ã¹ã¯ã衚瀺ãããã®ã§ãBPãåé€ããã°ããã®åœä»€ãå®è¡ããçŽåŸã«ãäœããã®æ¹æ³ã§ã¢ããªã±ãŒã·ã§ã³ãå¶åŸ¡ããããã¬ãŒã«è»¢éããå¿ èŠããããŸããæåããã°ãBPãæ£åœãªå Žæã«æ»ãããšãã§ããŸãã
ããšãã°ãçŸåšã®åœä»€ã®ãµã€ãºãèšç®ãã次ã®åœä»€ã®å é ã«æ°ããäžæçãªBPãé 眮ã§ããŸãããé·ãã®éã¢ã»ã³ãã©ãŒãèšè¿°ãã次ã®åœä»€ã®å é ã«BPãã€ã³ã¹ããŒã«ã§ããç¬éãèæ ®ããå¿ èŠããããŸããå®éãããã¯æ£ãã決å®ã§ã¯ãããŸããã
ãã®å Žåã®æ£ãã解決çã¯ãããã»ããµããã¬ãŒã¹ã¢ãŒãã«ããããšã§ãã
ããã»ããµãââã©ã°ã¯ããã®ã¢ãŒããæå¹ã«ããŸãããã®ãã©ã°ãæå¹ãªå Žåãååœä»€ã¯ãINT1ãå²ã蟌ã¿ãããªã¬ãŒãããããã°ãããããã»ã¹ã§äŸå€ãã¹ããŒãããããã¬ãŒã¯äŸå€ã³ãŒãEXCEPTION_SINGLE_STEPã§EXCEPTION_DEBUG_EVENTã€ãã³ããå¶åŸ¡ããŸãã
ãã®ãã©ã°ã¯ãEIPã¬ãžã¹ã¿ã®å€ãå€æŽããã¹ã¬ããã³ã³ããã¹ããä»ããŠæå¹ã«ã§ããŸãããã©ã°ã®ç¶æ ã¯ãContext.EFlagsãã©ã¡ãŒã¿ãŒã«ãã£ãŠå¶åŸ¡ãããŸããTFãã©ã°ã¯ããã®ãã©ã¡ãŒã¿ãŒã®8çªç®ã®ãããã«æ ŒçŽãããŸããã€ãŸã æå¹åããããã«åçŽåããã«ã¯ã次ã®ããã«ããŸãã
const EFLAGS_TF = $100; // 8- ... Context.EFlags := Context.EFlags or EFLAGS_TF;
ãã¬ãŒã¹ãã¥ã¢ã³ã¹ïŒãINT1ãå²ã蟌ã¿ã®ç¹æ§ã¯ãTFãã©ã°ããªã»ããããããšã§ãã ã€ãŸãBPã埩å ããããã«1ã€ã®åœä»€ã®ã¿ãå®è¡ããå¿ èŠãããå ŽåãTFãã©ã°ãå ã®ç¶æ ã«åŸ©å ããããšãå¿é ããå¿ èŠããªãããããã®åäœã¯å®å šã«é©ããŠããŸãããã ããååœä»€ã®ã·ãŒã±ã³ã·ã£ã«ãã¬ãŒã¹ã«é¢å¿ãããå Žåã¯ãåEXCEPTION_SINGLE_STEPãã³ãã©ãŒã§TFãã©ã°ãåå¥ã«åçºçããå¿ èŠããããŸãããã®ã¢ãŒãã¯åŸã§æ€èšããŸãã
èŠçŽãããšãã³ãŒãã¢ãã¬ã¹ã§BPãã€ã³ã¹ããŒã«ããã³åŠçããããã®ã¢ã«ãŽãªãºã ã¯æ¬¡ã®ãšããã§ãã
- BPãèšè¿°ããæ§é ãåæåãããã®ã¢ãã¬ã¹ã®ã¢ãã¬ã¹ãšãã€ãå€ãä¿åããŸãã
- 0xCCãªãã³ãŒããBPã¢ãã¬ã¹ã«æžã蟌ã¿ãããã°ã©ã ãå®è¡ããŸãã
- EXCEPTION_BREAKPOINTäŸå€ãåŸ ã¡ãŸããäŸå€ãåä¿¡ãããšãå ã®ãã€ãã埩å ããŸã
- EIPã¬ãžã¹ã¿ã®å€ãå€æŽããTFãã©ã°ãæå¹ã«ããŠããã»ããµããã¬ãŒã¹ã¢ãŒãã«ããŸãã
- EXCEPTION_SINGLE_STEPäŸå€ãåŸ ã€
- 0xCCãªãã³ãŒããåã€ã³ã¹ããŒã«ããŸãã
ããã§ãDelphiãããã¬ãŒã§F7ãã¿ã³ãæŒãããšãã«å®éã«å®è¡ãããã¢ã¯ã·ã§ã³ã®æ°ãæå°éã«ãªããŸãã:)
ããŠãããã¯TFWDebugerCoreã¯ã©ã¹ã§ã®å®è£ æ¹æ³ã§ãã
EXCEPTION_BREAKPOINTäŸå€ãã³ãã©ãŒïŒ
procedure TFWDebugerCore.ProcessExceptionBreakPoint(ThreadIndex: Integer; DebugEvent: TDebugEvent); var ReleaseBP: Boolean; BreakPointIndex: Integer; begin ReleaseBP := False; BreakPointIndex := GetBPIndex( DWORD(DebugEvent.Exception.ExceptionRecord.ExceptionAddress)); if BreakPointIndex >= 0 then begin if Assigned(FBreakPoint) then FBreakPoint(Self, ThreadIndex, DebugEvent.Exception.ExceptionRecord, BreakPointIndex, ReleaseBP) else CallUnhandledExceptionEvents(ThreadIndex, ecBreakpoint, DebugEvent); ToggleInt3Breakpoint(BreakPointIndex, False); SetSingleStepMode(ThreadIndex, True); if ReleaseBP then RemoveBreakpoint(BreakPointIndex) else FRestoreBPIndex := BreakPointIndex; end else CallUnhandledExceptionEvents(ThreadIndex, ecBreakpoint, DebugEvent); end;
ãã®äžã§ããŸãExceptionAddressãã©ã¡ãŒã¿ãŒã«ãã£ãŠå éšãªã¹ãã§BPã€ã³ããã¯ã¹ãæ¢ããŸãã
å€éšã€ãã³ããçºçãããŸãã
ToggleInt3Breakpointã¡ãœãããåŒã³åºããŠãBPããªãã«ããŸãã
EIPãç·šéããSetSingleStepModeã¡ãœãããåŒã³åºããŠãã¬ãŒã¹ãæå¹ã«ããŸãã
å€éšã€ãã³ããã³ãã©ãŒã®ãŠãŒã¶ãŒããã®BPãåé€ããããšèšã£ãå ŽåãRemoveBreakpointãåŒã³åºããŠåé€ããŸãã
å®è¡ãç¶ç¶ããå¿ èŠãããå Žåã¯ãEXCEPTION_SINGLE_STEPãã³ãã©ãŒã®çŸåšã®BPã®ã€ã³ããã¯ã¹ãèšæ¶ããŸãããã®å€æ°ã«çŠç¹ãåœãŠããšããããã°ãããããã»ã¹ã§BPã埩å ãããŸãã
SetSingleStepModeã¡ãœããã®ã³ãŒãã¯æ¬¡ã®ãšããã§ãã
procedure TFWDebugerCore.SetSingleStepMode(ThreadIndex: Integer; RestoreEIPAfterBP: Boolean); var Context: TContext; begin ZeroMemory(@Context, SizeOf(TContext)); Context.ContextFlags := CONTEXT_FULL; Check(GetThreadContext(FThreadList[ThreadIndex].ThreadHandle, Context)); if RestoreEIPAfterBP then Dec(Context.Eip); Context.EFlags := Context.EFlags or EFLAGS_TF; Check(SetThreadContext(FThreadList[ThreadIndex].ThreadHandle, Context)); end;
ããã§ã¯ãã¹ãŠãéåžžã«ç°¡åã§ããCONTEXT_FULLãã©ã°ãèšå®ããããšã§å®å šãªã¹ã¬ããã³ã³ããã¹ããååŸããŸãã
å¿ èŠã«å¿ããŠãEIPã¬ãžã¹ã¿ãç·šé
ããTFãã©ã°ããªã³ã«ããŸãã
ãããŠãæ°ããã³ã³ããã¹ããå²ãåœãŠãŸãã
RemoveBreakpointã¡ãœããã¯ããã«ç°¡åã§ãã
procedure TFWDebugerCore.RemoveBreakpoint(Index: Integer); var Len: Integer; begin ToggleBreakpoint(Index, False); Len := BreakpointCount; if Len = 1 then SetLength(FBreakpointList, 0) else begin FBreakpointList[Index] := FBreakpointList[Len - 1]; SetLength(FBreakpointList, Len - 1); end; end;
ããã§ã¯ãBPããªãã«ãªãã ãã§ãBPããŒã¿ããããã¬ãŒãªã¹ãããåé€ãããŸãã
ãããŸã§ã®ãšãããäŸå€ãã³ãã©EXCEPTION_SINGLE_STEPã®ã³ãŒãã¯æäŸããŠããŸãããBPã®åŸ©å ã ãã«äœ¿çšãããããã§ã¯ãããŸãããèšäºã®æåŸã«ããã¹ãŠã®ãã¥ã¢ã³ã¹ãèæ ®ããããšãã«è¡šç€ºããŸãã
ã¡ã¢ãªã¢ãã¬ã¹ã«BPãå®è£ ããïŒ
次ã®ã¿ã€ãã®BPã¯ããããã°ãããã¢ããªã±ãŒã·ã§ã³ã®ã¡ã¢ãªå ã®ããŒã¿å€æŽãå¶åŸ¡ããããã«äœ¿çšãããŸããã¡ã¢ãªãã¬ãŒã¯ãã€ã³ãïŒä»¥éMBPïŒãšããŠç¥ãããŠããŸãã
次ã®ããã«å®è£ ãããŸããã¢ããªã±ãŒã·ã§ã³ã¡ã¢ãªå šäœã¯ãäžèŠ§è¡šç€ºããŠå±æ§ãååŸã§ããããŒãžã®ã»ãããšããŠè¡šç€ºãããŸãã ïŒãã¢ã¢ããªã±ãŒã·ã§ã³ãåç §ããŠãã ããïŒããã»ã¹ã¡ã¢ãªã«ãŒãïŒãããã¢ãã¬ã¹ã«MBPãé 眮ããå Žåããã®ã¢ãã¬ã¹ãå±ããããŒãžã®å¢çãèšç®ããVirtualProtectExé¢æ°ãåŒã³åºããŠPAGE_GUARDãã©ã°ãèšå®ããå¿ èŠããããŸãã
ãã¥ã¢ã³ã¹ïŒç¢ºãã«ããŒãžã¢ãã¬ã¹ãèšç®ããããšã¯ã§ããŸããããåã«å¿ èŠãªã¢ãã¬ã¹ã§VirtualProtectExãåŒã³åºããŸãããããŒãžã¢ãã¬ã¹æå®ã®ç¹æ§ã¯ãä»ã®ãã¹ãŠã®ã¢ãã¬ã¹ãå€æŽããã«ããŒãžã®å°ããªã»ã¯ã·ã§ã³ã®ä¿è·ãå€æŽã§ããªãããšã§ããã»ãã¥ãªãã£å±æ§ã¯åžžã«ããŒãžå šäœã«å²ãåœãŠãããŸãããããã£ãŠã1ãã€ãã ãã§å€æŽã远跡ããããšãããšãããã«é£æ¥ãããã€ãã«ã¢ã¯ã»ã¹ãããšãã«ããããã¬ãŒãéç¥ãåãåããŸãã
2çªç®ã®èŠåïŒã»ãšãã©ã®ãããã¬ãŒã§ã¯ãåãããŒãžå ã«åæã«2ã€ä»¥äžã®MBPãã€ã³ã¹ããŒã«ããããšã¯ã§ããŸããããã®åäœã¯ã次ã®ç¹ãåå ã§ããå¯èœæ§ãæãé«ããªããŸããMBPãã€ã³ã¹ããŒã«ããå ŽåãMBPãåé€ãããšãã«ããŒãžã®ä¿è·ãã£ãŒã«ãã®çŸåšã®ç¶æ ãæ»ãå¿ èŠããããŸããããŒãžã§MBPãæ¢ã«èšå®ãããŠããå Žåããã®ä¿è·å±æ§ãå€æŽãããŸãããã®ç¹ãåé¿ããããã«ãTFWDebugerCoreã¯ã©ã¹ã§ã¯æ¬¡ã®ã¢ãããŒãã䜿çšãããŸããæ°ããMBPãã€ã³ã¹ããŒã«ãããšãããã®ããŒãžãå¶åŸ¡ããå¥ã®MBPããããã©ãããæåã«ãã§ãã¯ãããŸããèŠã€ãã£ãå ŽåãPreviosRegionProtectãã©ã¡ãŒã¿ãŒã®å€ãåããŸããMDRããªãå Žåããã®å€ã¯VirtualProtectExãåŒã³åºãããšã«ãã£ãŠååŸãããŸãã
MVRã€ã³ã¹ããŒã«ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
function TFWDebugerCore.SetMemoryBreakpoint(Address: Pointer; Size: DWORD; BreakOnWrite: Boolean; const Description: string): Boolean; var Breakpoint: TBreakpoint; MBI: TMemoryBasicInformation; Index: Integer; begin Index := GetMBPIndex(DWORD(Address)); if (Index >= 0) and (FBreakpointList[Index].bpType = btMemoryBreakpoint) then begin MBI.BaseAddress := FBreakpointList[Index].Memory.RegionStart; MBI.RegionSize := FBreakpointList[Index].Memory.RegionSize; MBI.Protect := FBreakpointList[Index].Memory.PreviosRegionProtect; end else Check(VirtualQueryEx(DebugProcessData.AttachedProcessHandle, Address, MBI, SizeOf(TMemoryBasicInformation)) > 0); ZeroMemory(@Breakpoint, SizeOf(TBreakpoint)); Breakpoint.bpType := btMemoryBreakpoint; Breakpoint.Description := ShortString(Description); Breakpoint.Memory.Address := Address; Breakpoint.Memory.Size := Size; Breakpoint.Memory.BreakOnWrite := BreakOnWrite; Breakpoint.Memory.RegionStart := MBI.BaseAddress; Breakpoint.Memory.RegionSize := MBI.RegionSize; Check(VirtualProtectEx(FProcessInfo.AttachedProcessHandle, Address, Size, MBI.Protect or PAGE_GUARD, Breakpoint.Memory.PreviosRegionProtect)); if Index >= 0 then Breakpoint.Memory.PreviosRegionProtect := MBI.Protect; Result := AddNewBreakPoint(Breakpoint); end;
MBPã®å ŽåãBPãšã¯ç°ãªããããå€ãã®ãã©ã¡ãŒã¿ãŒãä¿åããå¿ èŠããããŸããå¶åŸ¡é åã®ã¢ãã¬ã¹ãšãã®ãµã€ãºã«å ããŠãMBPèªäœãæ§æãããã©ã¡ãŒã¿ãŒ-BreakOnWriteãæ ŒçŽãããŸããããã¯ãå€éšã€ãã³ããããªã¬ãŒããæ¡ä»¶ã管çããŸãïŒå¶åŸ¡é åããããŒã¿ãèªã¿åããšãããŸãã¯æžã蟌ããšãïŒãããŒãžã®å é ã®ã¢ãã¬ã¹ãšãã®ãµã€ãºãä¿åãããŸãã
MVRã®ã€ã³ã¹ããŒã«åŸãããã°ã©ã ãå®è¡ããããšãã§ããŸããç£èŠå¯Ÿè±¡ããŒãžãžã®ã¢ã¯ã»ã¹ãçºçãããšããã«ãEXCEPTION_DEBUG_EVENTã€ãã³ããEXCEPTION_GUARD_PAGEäŸå€ã³ãŒããšãšãã«çæãããŸãã
ããã«ããã¥ã¢ã³ã¹ããããŸããããŒãžã«PAGE_GUARDãã©ã°ãèšå®ãããšãæåã«ã¢ã¯ã»ã¹ãããšãã«äŸå€ãçºçãããã®ãã©ã°ã¯åé€ãããŸããã€ãŸããBPãšã¯ç°ãªããMVRã®åæãåå¥ã«è¡ãå¿ èŠã¯ãããŸãããããããå°ããªåé¡ããããŸããåè¿°ããããã«ãMDRãèšå®ãããŠããã¢ãã¬ã¹ã ãã§ãªããããŒãžãã¢ã¯ã»ã¹ããããã³ã«EXCEPTION_GUARD_PAGEäŸå€ãçºçããããããããã¬ãŒã¯PAGE_GUARDãã©ã°ã埩å ããŠã確ç«ãããMVRãæ£åžžã«æ©èœãç¶ããå¿ èŠããããŸãã
ãã³ãã©ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
procedure TFWDebugerCore.ProcessExceptionGuardPage(ThreadIndex: Integer; DebugEvent: TDebugEvent); var CurrentMBPIndex: Integer; function CheckWriteMode: Boolean; begin Result := not FBreakpointList[CurrentMBPIndex].Memory.BreakOnWrite; if not Result then Result := DebugEvent.Exception.ExceptionRecord.ExceptionInformation[0] = 1; end; var MBPIndex: Integer; ReleaseMBP: Boolean; dwGuardedAddr: DWORD; begin ReleaseMBP := False; dwGuardedAddr := DebugEvent.Exception.ExceptionRecord.ExceptionInformation[1]; MBPIndex := GetMBPIndex(dwGuardedAddr); if MBPIndex >= 0 then begin CurrentMBPIndex := MBPIndex; while not CheckIsAddrInRealMemoryBPRegion(CurrentMBPIndex, dwGuardedAddr) do begin CurrentMBPIndex := GetMBPIndex(dwGuardedAddr, CurrentMBPIndex + 1); if CurrentMBPIndex < 0 then Break; end; if CurrentMBPIndex >= 0 then begin MBPIndex := CurrentMBPIndex; if Assigned(FBreakPoint) and CheckWriteMode then FBreakPoint(Self, ThreadIndex, DebugEvent.Exception.ExceptionRecord, MBPIndex, ReleaseMBP) else CallUnhandledExceptionEvents(ThreadIndex, ecGuard, DebugEvent); end else CallUnhandledExceptionEvents(ThreadIndex, ecGuard, DebugEvent); FBreakpointList[MBPIndex].Active := False; SetSingleStepMode(ThreadIndex, False); if ReleaseMBP then RemoveBreakpoint(MBPIndex) else FRestoreMBPIndex := MBPIndex; end else CallUnhandledExceptionEvents(ThreadIndex, ecGuard, DebugEvent); end;
æåã«ããããã¬ãŒã¯ãäŸå€ãçºçããããã«åŒã³åºããçºçããã¢ãã¬ã¹ãåãåããŸãããã®ã¢ãã¬ã¹ã¯2çªç®ã®ãã©ã¡ãŒã¿ãŒãšããŠExceptionRecord.ExceptionInformationé åã«æ ŒçŽãããæäœãã©ã°ã¯ãã®é åã®æåã®ãã©ã¡ãŒã¿ãŒã§ãããŒãã¯ã¢ãã¬ã¹ã§ã®èªã¿åãè©Šè¡ãæå³ãã1ã¯ã¢ãã¬ã¹ã§ã®èªã¿åãè©Šè¡ãæå³ããŸãã
次ã«ãCheckIsAddrInRealMemoryBPRegionãåŒã³åºããŠé©åãªMDRãæ€çŽ¢ããã¢ãã¬ã¹ãMDRã«ãã£ãŠå¶åŸ¡ããããŸãŒã³ã«ãããã©ããã確èªããŸãã
é©åãªãã®ãèŠã€ãã£ãå ŽåãBreakOnWriteãã©ã¡ãŒã¿ãŒããã§ãã¯ãããŸãã
ãã®ãã©ã¡ãŒã¿ãŒã®å€ã¯ãæåã®ãã©ã¡ãŒã¿ãŒExceptionInformationã®å€ãšæ¯èŒãããŸãã BreakOnWriteãæå¹ãªå ŽåããŠããããExceptionInformationã«ããå Žåã«ã®ã¿å€éšã€ãã³ããåŒã³åºããããã以å€ã®å ŽåãBreakOnWriteãç¡å¹ãªå Žåãã€ãã³ãã¯åžžã«åŒã³åºãããŸãã
ãã¹ãŠã®ãã§ãã¯ã®åŸãã³ãŒãã¯BPåŠçãšåæ§ã«å®è£ ãããŸããBPåŠçãšã®å¯äžã®éãã¯ããã®å ŽåãEIPã¬ãžã¹ã¿ã®å€ãç·šéããå¿ èŠããªãããšã§ãããããè¡ãã«ã¯ã2çªç®ã®ãã©ã¡ãŒã¿ãŒãšããŠSetSingleStepModeã¡ãœããã«Falseãæž¡ãããŸãã
åæ§ã«ããã£ããã£ãããMVPã®å埩ã¯ãFRestoreMBPIndexã€ã³ããã¯ã¹ã«åºã¥ããŠEXCEPTION_SINGLE_STEPãã³ãã©ãŒã§çºçããŸãã
次ã®ã³ãŒãã¯ãMBPã®ã¢ã¯ãã£ããã£ãåãæ¿ãã圹å²ãæãããŸãã
procedure TFWDebugerCore.ToggleMemoryBreakpoint(Index: Integer; Active: Boolean); var Dummy: DWORD; begin CheckBreakpointIndex(Index); if FBreakpointList[Index].bpType <> btMemoryBreakpoint then Exit; if FBreakpointList[Index].Active = Active then Exit; if Active then Check(VirtualProtectEx(FProcessInfo.AttachedProcessHandle, FBreakpointList[Index].Memory.Address, FBreakpointList[Index].Memory.Size, FBreakpointList[Index].Memory.PreviosRegionProtect or PAGE_GUARD, Dummy)) else Check(VirtualProtectEx(FProcessInfo.AttachedProcessHandle, FBreakpointList[Index].Memory.Address, FBreakpointList[Index].Memory.Size, FBreakpointList[Index].Memory.PreviosRegionProtect, Dummy)); FBreakpointList[Index].Active := Active; end;
MVRã®åé€ã¯ãBPãšåãæ¹æ³ã§è¡ãããŸãã
ååãšããŠãBPãšMVRã«ã¯ããã€ãã®ãã¥ã¢ã³ã¹ãé€ããŠãäž»èŠãªéãã¯ãããŸããããããã¯ããããã®ã¿ã¹ã¯ã«é©çšããã ãã§ãã
ããšãã°ãæã MBPããã¬ãŒãµãŒãšããŠäœ¿çšãããŸãããã®æ©èœãå®è£ ããã«ã¯ãICBMãã³ãŒãé åã«èšå®ããã ãã§ããããã¬ãŒã®èµ·ååŸããªã¢ãŒãã¢ããªã±ãŒã·ã§ã³ã®çŸåšã®EIPã®å€æŽã«é¢ããéç¥ã®åä¿¡ãéå§ããŸããããªã䟿å©ãªããšã§ãããåæ ã¯Delphiãããã¬ãŒã§ã¯å®çŸã§ããŸããã
ãã®ãããªäœ¿çšã®äŸãèšäºã®æåŸã«ç€ºããŸãã次ã«ãæåŸã®3çªç®ã®ã¿ã€ãã®ãã¬ãŒã¯ãã€ã³ãã«é²ã¿ãŸãããã
ããŒããŠã§ã¢ãã¬ãŒã¯ãã€ã³ãã®å®è£ ïŒ
ããããããŒããŠã§ã¢ãã¬ãŒã¯ãã€ã³ãïŒä»¥éHBPïŒãååã«åŒ·åãªãããã°ããŒã«ã BPããã³MVRãšã¯ç°ãªãããããã®ãã¬ãŒã¯ãã€ã³ãã¯ãããã°ãããã¢ããªã±ãŒã·ã§ã³ã®ã¡ã¢ãªãå€æŽããŸãããå¯äžã®æªãç¹ã¯ããããã®æ°ãéåžžã«å°ãªããåã¹ã¬ããã«4ã€ã®ããŒã¹ãããªãããšã§ãã
ããããä»ã®HBPãšã¯ç°ãªãããããã°ãããã¢ããªã±ãŒã·ã§ã³ãå¶åŸ¡ããããã®ããªãæè»ãªæ¡ä»¶ãæäŸããŸãã
æ¯èŒïŒ
BP-å®è¡å¯èœã³ãŒããžã®ã¢ã¯ã»ã¹ã®ã¿ã远跡ïŒå®è¡ã¢ãŒããªã©ïŒ;
MVR-èªã¿åããŸãã¯èªã¿åã/æžã蟌ã¿ã¢ãŒãã§ã¢ã¯ã»ã¹ã远跡ã§ããŸãã
-æ¡ä»¶ãããæ£ç¢ºã«èšå®ã§ããŸããæžã蟌ã¿ãèªã¿åã/æžã蟌ã¿ãIOã¢ãŒãïŒå ¥å/åºåããŒããžã®ã¢ã¯ã»ã¹ïŒãšå®è¡ã¢ãŒãã®ã¢ãŒããåºå¥ããŸãã
ã€ãŸãHBPã¯ãBPïŒå®è¡ã¢ãŒãïŒããã³MBPïŒã¬ã³ãŒã-èªã¿åã/æžã蟌ã¿ã¢ãŒãïŒã®äž¡æ¹ã®åäœããšãã¥ã¬ãŒãã§ããŸãã確ãã«ãMVRãšã¯ç°ãªããã¡ã¢ãªé åã®åºãç¯å²ãå¶åŸ¡ããããšã¯ã§ããŸãããåºå®ãµã€ãº1ã2ããŸãã¯4ãã€ãã®ãããã¯ã§ã®ã¿æ©èœããŸãã
HBPèšå®ã¯åã¹ã¬ããã®ã³ã³ããã¹ãã«ä¿åãããŸãããã®DRã¬ãžã¹ã¿ã䜿çšããããããCONTEXT_DEBUG_REGISTERSãã©ã°ãæå®ããããšãã«ã¢ã¯ã»ã¹ãããŸãã
ãããã®6ã€ããããŸãã Dr0..Dr3ãDr6ãDr7ã ïŒDr4ããã³Dr5ã¯äºçŽæžã¿ã§ãïŒã
æåã®4ã€ã®ã¬ãžã¹ã¿ã«ã¯ãåHBPã®ã¢ãã¬ã¹ãæ ŒçŽãããŸããã¬ãžã¹ã¿ãŒDr7ã¯ãåHBPã®ãã©ã¡ãŒã¿ãŒã埮調æŽããããã«äœ¿çšãããŸããã¬ãžã¹ã¿ãŒDr6ã¯ã4ã€ã®HBPã®ããããã®æäœåŸã«çµæãèªã¿åãã®ã«åœ¹ç«ã¡ãŸãã
TFWDebugerCoreã¯ã©ã¹ã¯ãHBPã«é¢ããæ å ±ã次ã®æ§é ã®åœ¢åŒã§ä¿åããŸãã
THWBPIndex = 0..3; THWBPSize = (hsByte, hdWord, hsDWord); THWBPMode = (hmExecute, hmWrite, hmIO, hmReadWrite); THardwareBreakpoint = packed record Address: array [THWBPIndex] of Pointer; Size: array [THWBPIndex] of THWBPSize; Mode: array [THWBPIndex] of THWBPMode; Description: array [THWBPIndex] of ShortString; Active: array [THWBPIndex] of Boolean; end;
ç¹å®ã®åã¹ã¬ããã®4ã€ã®HBPã«ã¯ãã¹ãŠç¬èªã®ãã®ããããããBPã¯ã©ã¹ã®äžè¬ãªã¹ãã«ã¯ä¿åãããŸããã
æåã«ããã¢ID = hThreadHandleã®åœ¢åŒã§åå¥ã®ãªã¹ãã«ã¹ã¬ããã«é¢ããããŒã¿ãæ ŒçŽããããšãèšã£ãããšãæãåºããŠãã ãããå®éããã®ãªã¹ãã¯æ¬¡ã®ãšããã§ãã
TThreadData = record ThreadID: DWORD; ThreadHandle: THandle; Breakpoint: THardwareBreakpoint; end; TThreadList = array of TThreadData;
ã€ãŸããããã®2ã€ã®ãã©ã¡ãŒã¿ãŒã«å ããŠãåã¹ã¬ããã«ã¯ãããã«å±ããHBPã®èšå®ãèšè¿°ããç¬èªã®æ§é ããããŸãã
ã€ã³ã¹ããŒã«ãç¶æ ã®å€æŽãHBPã®åé€ã¯éåžžã«ç°¡åã§ãã
ã€ã³ã¹ããŒã«ã¯æ¬¡ã®ããã«ãªããŸãã
procedure TFWDebugerCore.SetHardwareBreakpoint(ThreadIndex: Integer; Address: Pointer; Size: THWBPSize; Mode: THWBPMode; HWIndex: THWBPIndex; const Description: string); begin if ThreadIndex < 0 then Exit; FThreadList[ThreadIndex].Breakpoint.Address[HWIndex] := Address; FThreadList[ThreadIndex].Breakpoint.Size[HWIndex] := Size; FThreadList[ThreadIndex].Breakpoint.Mode[HWIndex] := Mode; FThreadList[ThreadIndex].Breakpoint.Description[HWIndex] := ShortString(Description); FThreadList[ThreadIndex].Breakpoint.Active[HWIndex] := True; UpdateHardwareBreakpoints(ThreadIndex); end;
æ§é ãåæåããUpdateHardwareBreakpointsã¡ãœãããåŒã³åºãã ãã§ãã
ç¶æ ã®å€æŽã¯ã次ã®ã³ãŒãã«ãã£ãŠå®è£ ãããŸãã
procedure TFWDebugerCore.ToggleHardwareBreakpoint(ThreadIndex: Integer; Index: THWBPIndex; Active: Boolean); begin if ThreadIndex < 0 then Exit; if FThreadList[ThreadIndex].Breakpoint.Active[Index] = Active then Exit; FThreadList[ThreadIndex].Breakpoint.Active[Index] := Active; UpdateHardwareBreakpoints(ThreadIndex); end;
Activeãã©ã°ãå€æŽããŠãUpdateHardwareBreakpointsãå床åŒã³åºããŸãã
ããŠãåé€ïŒ
procedure TFWDebugerCore.DropHardwareBreakpoint(ThreadIndex: Integer; Index: THWBPIndex); begin if ThreadIndex < 0 then Exit; if FThreadList[ThreadIndex].Breakpoint.Address[Index] = nil then Exit; FThreadList[ThreadIndex].Breakpoint.Address[Index] := nil; UpdateHardwareBreakpoints(ThreadIndex); end;
HBPã¢ãã¬ã¹ããªã»ããããUpdateHardwareBreakpointsãå床åŒã³åºããŸãã
埮åŠãªéãã¯ãUpdateHardwareBreakpointsã¡ãœããã«ãããŸãã
ãã®äž»ãªã¿ã¹ã¯ã¯ãDr0-Dr3ã¬ãžã¹ã¿ã«ã¢ã¯ãã£ããªHBPã®ã¢ãã¬ã¹ãå ¥åããDr7ã¬ãžã¹ã¿ãæ£ããåæåããããšã§ãã
ããã§ããããããå¿ èŠããããŸãã
ãã®ã¬ãžã¹ã¿ã¯ãåHBPã®èšå®ãå®çŸ©ããããããã©ã°ã®ã»ããã§ãããæ£åŒã«ã¯ãã¹ãŠã次ã®ããã«ãªããŸã
ãæãå€ã4ãããïŒ31-28ïŒã¯ãDr3ã¬ãžã¹ã¿ã®èšå®ãä¿åããŸãã
次ã®ãã
ã«ãªããŸãã4ã€ã®äžäœ2ãããïŒLENiïŒã¯ãç£èŠå¯Ÿè±¡ã®HBPã¡ã¢ãªã®ãµã€ãºãæ åœããŸãã
00-1ãã€ã
01-2ãã€ã
10-ãã®ãããã®çµã¿åããã¯äœ¿çšãããŸããã
11-4ãã€ã
4ã®äžäœ2ãããïŒRWiïŒã¯ãHBPã®åäœã¢ãŒããèšå®ãã圹å²ãæãããŸã
00-å®è¡
01-æžã蟌ã¿
10-IOèªã¿åã/æžã蟌ã¿
11-èªã¿åã/æžã蟌ã¿
ãããã£ãŠãDr3ã¬ãžã¹ã¿ããã®HBPã4ãã€ãããå§ãŸãæžã蟌ã¿ã«å¿çããããã«ããå ŽåDr3ã§æå®ãããå€ãããDr7ã¬ãžã¹ã¿ã®äžäœ4ãããã¯1101
ã®ããã«ãªããŸãã次ã®4ãããïŒ27-24ïŒã¯ãDr2ã¬ãžã¹ã¿ã®HBPã®èšå®ã«äœ¿çšãããŸãã
ããã23-20ã¯Dr1ããæåŸã«ããã19-16ã¯ã¬ãžã¹ã¿Dr0ãåç §ããŸãã
Dr7ã¬ãžã¹ã¿ã®ããã13ïŒGD-ã°ããŒãã«ãããã°ã¬ãžã¹ã¿ã¢ã¯ã»ã¹æ€åºïŒ-ãããã°ã¬ãžã¹ã¿å ã®ããŒã¿ã®æŽåæ§ã管çããŸããããšãã°ããããã°äžã®ããã°ã©ã ããããã®ã¬ãžã¹ã¿ã«å€ãä¿åããããšãçªç¶æ±ºå®ããå Žåããããã¬ãŒã¯ããã«ã€ããŠéç¥ãããŸãã
Dr7ã¬ãžã¹ã¿ã®ããã9ïŒGE-ã°ããŒãã«å®å šäžèŽããŒã¿ãã¬ãŒã¯ãã€ã³ãäžèŽïŒ-ã°ããŒãã«HBPã§ã®äœæ¥ãå«ã¿ãŸãã
Dr7ã¬ãžã¹ã¿ã®ããã8ïŒLE-Local ExactããŒã¿ãã¬ãŒã¯ãã€ã³ãã®äžèŽïŒ-ããŒã«ã«HBPã§ã®äœæ¥ãæå¹ã«ããŸãã
ã¿ã¹ã¯ãåãæ¿ãããšLEãããããªã»ããããã詳现ã¯Intelã®ããã¥ã¢ã«ã«èšèŒãããŠããŸãã
ã°ããŒãã«ã¢ãŒããŸãã¯ããŒã«ã«ã¢ãŒãã®HBPãå«ãåã¬ãžã¹ã¿ã®Giãã©ã°ãšLiãã©ã°ã®ãã¢ãšããŠè¡šãããæ®ãã®8ãããïŒ7-0ïŒããããŸãã
ããã7ïŒGi-ã°ããŒãã«ãã¬ãŒã¯ãã€ã³ãã€ããŒãã«ïŒ-Dr3ã¬ãžã¹ã¿ã®ã°ããŒãã«ã¢ãŒããæå¹ã«ããŸã;
ããã6ïŒLi-ããŒã«ã«ãã¬ãŒã¯ãã€ã³ãã€ããŒãã«ïŒ-Dr3ã¬ãžã¹ã¿5-4ã®ããŒã«ã«ã¢ãŒããæå¹ã«ããŸã;
Dr1ã®Dr2
3-2ãšDr0ã®1-0ã¯åã
ã§ããïŒ
ããŠãããã«åçããããŸãïŒ
ãœãŒã¹ã³ãŒãã®åœ¢åŒã§ã¯ããã¹ãŠãéåžžã«åçŽã«èŠããŸãã
procedure TFWDebugerCore.UpdateHardwareBreakpoints(ThreadIndex: Integer); const DR7_SET_LOC_DR0 = $01; DR7_SET_GLB_DR0 = $02; DR7_SET_LOC_DR1 = $04; DR7_SET_GLB_DR1 = $08; DR7_SET_LOC_DR2 = $10; DR7_SET_GLB_DR2 = $20; DR7_SET_LOC_DR3 = $40; DR7_SET_GLB_DR3 = $80; DR7_SET_LOC_ON = $100; DR7_SET_GLB_ON = $200; DR7_PROTECT = $2000; DR_SIZE_BYTE = 0; DR_SIZE_WORD = 1; DR_SIZE_DWORD = 3; DR_MODE_E = 0; DR_MODE_W = 1; DR_MODE_I = 2; DR_MODE_R = 3; DR7_MODE_DR0_E = DR_MODE_E shl 16; DR7_MODE_DR0_W = DR_MODE_W shl 16; DR7_MODE_DR0_I = DR_MODE_I shl 16; DR7_MODE_DR0_R = DR_MODE_R shl 16; DR7_SIZE_DR0_B = DR_SIZE_BYTE shl 18; DR7_SIZE_DR0_W = DR_SIZE_WORD shl 18; DR7_SIZE_DR0_D = DR_SIZE_DWORD shl 18; DR7_MODE_DR1_E = DR_MODE_E shl 20; DR7_MODE_DR1_W = DR_MODE_W shl 20; DR7_MODE_DR1_I = DR_MODE_I shl 20; DR7_MODE_DR1_R = DR_MODE_R shl 20; DR7_SIZE_DR1_B = DR_SIZE_BYTE shl 22; DR7_SIZE_DR1_W = DR_SIZE_WORD shl 22; DR7_SIZE_DR1_D = DR_SIZE_DWORD shl 22; DR7_MODE_DR2_E = DR_MODE_E shl 24; DR7_MODE_DR2_W = DR_MODE_W shl 24; DR7_MODE_DR2_I = DR_MODE_I shl 24; DR7_MODE_DR2_R = DR_MODE_R shl 24; DR7_SIZE_DR2_B = DR_SIZE_BYTE shl 26; DR7_SIZE_DR2_W = DR_SIZE_WORD shl 26; DR7_SIZE_DR2_D = DR_SIZE_DWORD shl 26; DR7_MODE_DR3_E = DR_MODE_E shl 28; DR7_MODE_DR3_W = DR_MODE_W shl 28; DR7_MODE_DR3_I = DR_MODE_I shl 28; DR7_MODE_DR3_R = DR_MODE_R shl 28; DR7_SIZE_DR3_B = DR_SIZE_BYTE shl 30; DR7_SIZE_DR3_W = DR_SIZE_WORD shl 30; DR7_SIZE_DR3_D = $C0000000; //DR_SIZE_DWORD shl 30; DR_On: array [THWBPIndex] of DWORD = ( DR7_SET_LOC_DR0, DR7_SET_LOC_DR1, DR7_SET_LOC_DR2, DR7_SET_LOC_DR3 ); DR_Mode: array [THWBPIndex] of array [THWBPMode] of DWORD = ( (DR7_MODE_DR0_E, DR7_MODE_DR0_W, DR7_MODE_DR0_I, DR7_MODE_DR0_R), (DR7_MODE_DR1_E, DR7_MODE_DR1_W, DR7_MODE_DR1_I, DR7_MODE_DR1_R), (DR7_MODE_DR2_E, DR7_MODE_DR2_W, DR7_MODE_DR2_I, DR7_MODE_DR2_R), (DR7_MODE_DR3_E, DR7_MODE_DR3_W, DR7_MODE_DR3_I, DR7_MODE_DR3_R) ); DR_Size: array [THWBPIndex] of array [THWBPSize] of DWORD = ( (DR7_SIZE_DR0_B, DR7_SIZE_DR0_W, DR7_SIZE_DR0_D), (DR7_SIZE_DR1_B, DR7_SIZE_DR1_W, DR7_SIZE_DR1_D), (DR7_SIZE_DR2_B, DR7_SIZE_DR2_W, DR7_SIZE_DR2_D), (DR7_SIZE_DR3_B, DR7_SIZE_DR3_W, DR7_SIZE_DR3_D) ); var Context: TContext; I: THWBPIndex; begin if ThreadIndex < 0 then Exit; ZeroMemory(@Context, SizeOf(TContext)); Context.ContextFlags := CONTEXT_DEBUG_REGISTERS; for I := 0 to 3 do begin if not FThreadList[ThreadIndex].Breakpoint.Active[I] then Continue; if FThreadList[ThreadIndex].Breakpoint.Address[I] <> nil then begin Context.Dr7 := Context.Dr7 or DR7_SET_LOC_ON; case I of 0: Context.Dr0 := DWORD(FThreadList[ThreadIndex].Breakpoint.Address[I]); 1: Context.Dr1 := DWORD(FThreadList[ThreadIndex].Breakpoint.Address[I]); 2: Context.Dr2 := DWORD(FThreadList[ThreadIndex].Breakpoint.Address[I]); 3: Context.Dr3 := DWORD(FThreadList[ThreadIndex].Breakpoint.Address[I]); end; Context.Dr7 := Context.Dr7 or DR_On[I]; Context.Dr7 := Context.Dr7 or DR_Mode[I, FThreadList[ThreadIndex].Breakpoint.Mode[I]]; Context.Dr7 := Context.Dr7 or DR_Size[I, FThreadList[ThreadIndex].Breakpoint.Size[I]]; end; end; Check(SetThreadContext(FThreadList[ThreadIndex].ThreadHandle, Context)); end;
ã³ãŒãã®åã«ããå®æ°ã®ãããã¯ã«æ³šæãæããªãå ŽåãDr7ã¬ãžã¹ã¿ã®åæåã¯3è¡ã®ã¿ã§å®è£ ãããŸãã
Context.Dr7 := Context.Dr7 or DR_On[I]; Context.Dr7 := Context.Dr7 or DR_Mode[I, FThreadList[ThreadIndex].Breakpoint.Mode[I]]; Context.Dr7 := Context.Dr7 or DR_Size[I, FThreadList[ThreadIndex].Breakpoint.Size[I]];
ãŸããDR7_SET_LOC_ONå®æ°ã§è¡šãããLEããããå«ããããšã¯å¥ã§ãã
次ã«ãHBPã®åŠçã«ã€ããŠèª¬æããŸãã
BPãããªã¬ãŒããããšãã³ãŒãEXCEPTION_BREAKPOINTãåãåããŸããã
MVRãããªã¬ãŒããããšããã³ãŒãã¯EXCEPTION_GUARD_PAGEã§ããã
ãããŠãHBPã®äžææã«ãã³ãŒãEXCEPTION_SINGLE_STEPã䜿çšããŠEXCEPTION_DEBUG_EVENTã€ãã³ããçæããŸããããã¯ããšãããBPããã³MBPã®ç¶æ ã埩å ããããã«äœ¿çšãããŸãïŒãããã£ãŠãèšäºã®åé ã§å®è£ ãåŒçšããŸããã§ããïŒã
EXCEPTION_SINGLE_STEPãåä¿¡ãããšãæåã®ãã®ãšããŠå®è£ ãããHBPãã³ãã©ãŒã¯æ¬¡ã®ããã«åŒã³åºãããŸãã
function TFWDebugerCore.ProcessHardwareBreakpoint(ThreadIndex: Integer; DebugEvent: TDebugEvent): Boolean; var Index: Integer; Context: TContext; ReleaseBP: Boolean; begin ZeroMemory(@Context, SizeOf(TContext)); Context.ContextFlags := CONTEXT_DEBUG_REGISTERS; Check(GetThreadContext(FThreadList[ThreadIndex].ThreadHandle, Context)); Result := Context.Dr6 and $F <> 0; if not Result then Exit; Index := -1; if Context.Dr6 and 1 <> 0 then Index := 0; if Context.Dr6 and 2 <> 0 then Index := 1; if Context.Dr6 and 4 <> 0 then Index := 2; if Context.Dr6 and 8 <> 0 then Index := 3; if Index < 0 then begin Result := False; Exit; end; ReleaseBP := False; if Assigned(FHardwareBreakpoint) then FHardwareBreakpoint(Self, ThreadIndex, DebugEvent.Exception.ExceptionRecord, Index, ReleaseBP); ToggleHardwareBreakpoint(ThreadIndex, Index, False); SetSingleStepMode(ThreadIndex, False); if ReleaseBP then DropHardwareBreakpoint(ThreadIndex, Index) else begin // HWBP , // .. // ProcessExceptionSingleStep, HWBP // HWBP if (FRestoredThread >= 0) and (FRestoredHWBPIndex >= 0) then ToggleHardwareBreakpoint(FRestoredThread, FRestoredHWBPIndex, True); FRestoredHWBPIndex := Index; FRestoredThread := ThreadIndex; end; end;
ãã®ã¿ã¹ã¯ã¯ãã©ã®ç¹å®ã®HBPãäžæãåŒãèµ·ãããããå€æããå€éšã€ãã³ããããªã¬ãŒããBPããã³MVRãã³ãã©ãŒã§ãã§ã«ç€ºãããŠããã¢ã«ãŽãªãºã ãšã»ãŒåæ§ã®ãã¡ã€ãã©ã€ãºã¢ã«ãŽãªãºã ãå®è¡ããããšã§ãã
HBPçªå·ã決å®ããã«ã¯ãã¹ã¬ããã³ã³ããã¹ãããDr6ã¬ãžã¹ã¿ã®å€ãèªã¿åãå¿ èŠããããŸãã
ãã®ã¬ãžã¹ã¿ã®äžäœ4ãããã¯ã察å¿ããDrXã¬ãžã¹ã¿ãæ©èœããŠããå Žåã«å€1ããšããã©ã°ã§ãã
ãã¹ãŠãéåžžã«ç°¡åã§ããå¿ èŠãªNVRã決å®ããåŸãå€éšã€ãã³ããåŒã³åºããNVRããªãã«ããŠãããã»ããµããã¬ãŒã¹ã¢ãŒãã«ãïŒEIPãç·šéããã«ïŒãNVRãåé€ãããããã®ã€ã³ããã¯ã¹ã2ã€ã®å€æ°ã«ä¿åããŸããEXCEPTION_SINGLE_STEPãã³ãã©ãŒã¯NVRã®ç¶æ ã埩å ããŸã
ããŠãè«ççãªçµè«ã«éããããã§ãã
EXCEPTION_SINGLE_STEPãã³ãã©ãŒèªäœã®å®è£ ã瀺ãããã ãã«æ®ããŸãã
次ã®ããã«ãªããŸãã
procedure TFWDebugerCore.ProcessExceptionSingleStep(ThreadIndex: Integer; DebugEvent: TDebugEvent); var Handled: Boolean; begin // HWBP Handled := ProcessHardwareBreakpoint(ThreadIndex, DebugEvent); // - HWPB HWBP if not Handled and (FRestoredThread >= 0) and (FRestoredHWBPIndex >= 0) then begin ToggleHardwareBreakpoint(FRestoredThread, FRestoredHWBPIndex, True); FRestoredThread := -1; FRestoredHWBPIndex := -1; end; // if FRestoreBPIndex >= 0 then begin CheckBreakpointIndex(FRestoreBPIndex); if FBreakpointList[FRestoreBPIndex].bpType = btBreakpoint then ToggleInt3Breakpoint(FRestoreBPIndex, True); FRestoreBPIndex := -1; end; // M if FRestoreMBPIndex >= 0 then begin CheckBreakpointIndex(FRestoreMBPIndex); if FBreakpointList[FRestoreMBPIndex].bpType = btMemoryBreakpoint then ToggleMemoryBreakpoint(FRestoreMBPIndex, True); FRestoreMBPIndex := -1; end; // // if ResumeAction <> raRun then begin CallUnhandledExceptionEvents(ThreadIndex, ecSingleStep, DebugEvent); // DoResumeAction(ThreadIndex); end; end;
圌ã®ä»äºã¯ãHBPã®åæ¢ã«ããäŸå€ãçæããããã©ãããæåã«å€æããããšã§ãããããåœãŠã¯ãŸãå ŽåãToggleHardwareBreakpointãåŒã³åºãããšã«ãããHBPã¯ãã®å Žæã«æ»ããŸãã
BPãŸãã¯MVPåŠçåŸã«ãã¬ãŒã¹ãã©ã°ããªã³ã«ãªã£ãããã«äŸå€ãçºçããå Žåãå€æ°FRestoreBPIndexããã³FRestoreMBPIndexã¯ããã®å Žæã«æ»ãå¿ èŠããããã¬ãŒã¯ãã€ã³ãã®ã€ã³ããã¯ã¹ã瀺ããŸãã
ãã®ã¿ã€ãã«å¿ããŠãToggleInt3BreakpointãŸãã¯ToggleMemoryBreakpointã¡ãœãããåŒã³åºãããŸãã
ç·Žç¿ïŒ
ãããã¬ãŒå®è£ ã®èª¬æã§ãããçµäºããŸãããæéãããããŸã-å®éã«èŠãããç¹ãããã€ããããŸãã
é£è¡æ©ã«ã€ããŠã®ãžã§ãŒã¯ã®ããã«ïŒãä»ããã®ã«ããŒå šäœã空äžã«æã¡äžããããšããŸãã:)
ãã®ããã«ã¯ã2ã€ã®ã¢ããªã±ãŒã·ã§ã³ãå®è£ ããå¿ èŠããããŸãã
æåã«ããããã°ãè©Šã¿ãŸããæ°ããVCLãããžã§ã¯ããäœæãããtest_appããšããååã§ä¿åããŠããããããžã§ã¯ããã³ã³ãã€ã«ããŸãã
次ã«ããããã¬ã¢ããªã±ãŒã·ã§ã³ãäœæããŸãããã®ããã«ã2ã€ã®ãã¿ã³ïŒãããã°ããã»ã¹ãéå§ããã³åæ¢ããïŒãšããã¹ãŠã®æ å ±ã衚瀺ãããTMemoãŸãã¯TRichEditã®ååãªãã©ãŒã ããããŸãã
ç§ãã¡ã¯æžããŸãïŒ
type TdlgDebuger = class(TForm) Panel1: TPanel; btnStart: TButton; btnStop: TButton; edLog: TRichEdit; procedure btnStartClick(Sender: TObject); procedure btnStopClick(Sender: TObject); private FCore: TFWDebugerCore; FNeedStop: Boolean; procedure Writeln(const Value: string = ''); end; ... procedure TdlgDebuger.btnStartClick(Sender: TObject); var Path: string; begin FNeedStop := False; // Path := ExtractFilePath(ParamStr(0)) + '..\test_app\test_app.exe'; FCore := TFWDebugerCore.Create(50); try btnStart.Enabled := False; btnStop.Enabled := True; if not FCore.DebugNewProcess(Path, True) then RaiseLastOSError; FCore.RunMainLoop; finally FCore.Free; btnStart.Enabled := True; btnStop.Enabled := False; end; Writeln; Writeln('Debug stop'); end; procedure TdlgDebuger.Writeln(const Value: string); begin edLog.Lines.Add(Value); end; procedure TdlgDebuger.btnStopClick(Sender: TObject); begin FNeedStop := True; end;
次ã®ãããªãã®ã衚瀺ãããã¯ãã§ãã
ãéå§ããã¿ã³ãã¯ãªãã¯ããŸãããã¹ãŠãæ£ããå®äºãããããã¹ãã¢ããªã±ãŒã·ã§ã³ãèµ·åããŸãã
ãã®å Žåãã¡ã€ã³ã¢ããªã±ãŒã·ã§ã³ã¯ãããŠã¹ãšããŒããŒãã®ã³ãã³ãã«å®è³ªçã«å¿çããªããªããŸãã
å®éã«ã¯ãèµ·ååŸã«TFWDebugerCore.RunMainLoopãããã°ãµã€ã¯ã«å ã«é 眮ããããããã¡ãã»ãŒãžãã¥ãŒãã§ãããµã€ã¯ã«ã®å®è¡ã劚ããããŸãã
ãã¹ãã¢ããªã±ãŒã·ã§ã³ãéããŸããããã«ããããããã¬ãŒã¯ãããã°ãµã€ã¯ã«ãçµäºãããŠã£ã³ããŠãæäœã§ããããã«ãªããŸãã
è¯ãæ¹æ³ã§ã¯ããããã¬ãŒãå¥ã®ã¹ã¬ããã§å®è¡ããå¿ èŠããããŸãïŒããããè¯ãæ¹æ³ã§ã¯ãããŸããããããã¯æ£ããã¢ãããŒãã§ãïŒããèµ·åããªããŠããTFWDebugerCoreã¯ã©ã¹ã®OnIdleã€ãã³ããéããããšã§éåžžã®æ¹æ³ã§äœæ¥ã§ããŸãã
procedure TdlgDebuger.OnIdle(Sender: TObject); begin if FNeedStop then FCore.StopDebug else Application.ProcessMessages; end;
Application.ProcessMessagesãåŒã³åºããŠããã¢ããªã±ãŒã·ã§ã³ã®ããã»ã¹ãé ããªãããšã¯ãããŸããã
次ã«ãDelphiãããã¬ãŒã衚瀺ãã圢åŒã§ãããã»ã¹ã«é¢ãããããã°æ å ±ãååŸããŠã¿ãŸãããããããè¡ãã«ã¯ãOnCreateProcessãã³ãã©ãŒãšOnLoadDllãã³ãã©ãŒãæ¥ç¶ããŸãã
æåã«ã以äžãèšè¿°ããŸãã
procedure TdlgDebuger.OnCreateProcess(Sender: TObject; ThreadIndex: Integer; Data: TCreateProcessDebugInfo); var T: TThreadData; begin T := FCore.GetThreadData(ThreadIndex); Writeln(Format('CreateThread ID: %d', [T.ThreadID])); Writeln(Format('ProcessStart ID: %d', [FCore.DebugProcessData.ProcessID])); end;
第äºã«ããã®ã³ãŒãïŒ
procedure TdlgDebuger.OnLoadDll(Sender: TObject; ThreadIndex: Integer; Data: TLoadDLLDebugInfo); const FormatStrKnownDLL = 'Load Dll at instance %p handle %d "%s"'; FormatStrUnknownDLL = 'Load unknown Dll at instance %p handle %d'; var DllName: AnsiString; IsUnicodeData: Boolean; begin FCore.ContinueStatus := DBG_EXCEPTION_NOT_HANDLED; IsUnicodeData := Data.fUnicode = 1; DllName := FCore.GetDllName(Data.lpImageName, Data.lpBaseOfDll, IsUnicodeData); if DllName <> '' then begin if IsUnicodeData then Writeln(Format(FormatStrKnownDLL, [Data.lpBaseOfDll, Data.hFile, PWideChar(@DllName[1])])) else Writeln(Format(FormatStrKnownDLL, [Data.lpBaseOfDll, Data.hFile, PAnsiChar(@DllName[1])])); end else Writeln(Format(FormatStrUnknownDLL, [Data.lpBaseOfDll, Data.hFile])); end;
ãã®åŸããããã°ã¢ããªã±ãŒã·ã§ã³ãå床起åãã[éå§]ãã¿ã³ãæŒããŸãã
次ã®
ããã«ãªããŸãã
ãã¬ãŒã¹å®è£ ïŒ
ããã§ã¯ããããã¬ã§äœæ¥ããŠã¿ãŸãããããŸãããã¬ãŒã¹ã®2ã€ã®ãªãã·ã§ã³ãæ€èšããŸãã1ã€ç®ã¯TFãã©ã°ã2ã€ç®ã¯MBPã§ããããã°ã©ã ã®ãšã³ããªãã€ã³ãããæåã®40ãã€ãããã¬ãŒã¹ããŸããããã«ããããã©ã®ããã«èŠãããèŠãŠã¿ãŸãããïŒ
è¯ããã¬ãŒã¹ãéå§ããã«ã¯ãããã»ã¹ãåæåãããã®ãåŸ ã€å¿ èŠããããŸãããã®åŸãBP / MVRãªã©ãå®å šã«èšå®ã§ããŸãããããè¡ãã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ãšã³ããªãã€ã³ãã«BPãã€ã³ã¹ããŒã«ãããããããã¬ãŒã«æ瀺ããå¿ èŠããããŸããDebugNewProcessé¢æ°ã®2çªç®ã®ãã©ã¡ãŒã¿ãŒããããæ åœããŸããæ¢ã«Trueã«èšå®ãããŠããããã®BPãåŠçããããã ãã«æ®ã£ãŠããŸãããããè¡ãã«ã¯ããã¬ãŒã¹ã¢ãŒããèšå®ããOnBreakPointãã³ãã©ãŒãæ¥ç¶ããŸãã
procedure TdlgDebuger.OnBreakPoint(Sender: TObject; ThreadIndex: Integer; ExceptionRecord: Windows.TExceptionRecord; BreakPointIndex: Integer; var ReleaseBreakpoint: Boolean); begin // Writeln(Format('!!! --> Breakpoint "%s"', [FCore.BreakpointItem(BreakPointIndex).Description])); // ( ) ReleaseBreakpoint := True; // FCore.ResumeAction := raTraceInto; // FStepCount := 0; end;
ãã¬ãŒã¹ã¯OnSingleStepã€ãã³ãã®çæãéããŠçºçããããããããå®è£ ããŸãã
procedure TdlgDebuger.OnSingleStep(Sender: TObject; ThreadIndex: Integer; ExceptionRecord: Windows.TExceptionRecord); begin // Inc(FStepCount); Writeln(Format('!!! --> trace step â%d at addr 0x%p', [FStepCount, ExceptionRecord.ExceptionAddress])); // if FStepCount > 10 then FCore.ResumeAction := raRun else FCore.ResumeAction := raTraceInto; end;
çµæã¯æ¬¡ã®ããã«ãªããŸã
ãStepInãã¬ãŒã¹ãå®è¡ããŸããã0x00409FF4ã§çºçãããã¬ãŒã¹ã®5çªç®ã®ã¹ãããã¯ãããæ確ã«ç€ºããŠããŸããããã¯0x00409C53ã§åŒã³åºããã_InitExeïŒïŒé¢æ°ã®å§ãŸãã§ãããã¬ãŒã¹ã¯ããªãé ãããã»ã¹ã§ããã_InitExeïŒïŒé¢æ°ããå¶åŸ¡ãæ»ãã®ãåŸ ã¡ãŸããã§ããããã¢ã³ã¹ãã¬ãŒã·ã§ã³ã®ããã«ãç§ã¯æ°åã¹ãããã«å¶éããŸããã
2çªç®ã®ãã¬ãŒã¹ã¢ãŒãã¯ãMVRã®ã€ã³ã¹ããŒã«ã§ãã
ãããå®èšŒããã«ã¯ãOnPageGuardã€ãã³ãããããã¯ããå¿ èŠãããããšã³ããªãã€ã³ãã«å°éããããå¶åŸ¡ãããã¡ã¢ãªç¯å²ã0ã«ããŠSetMemoryBreakpointã¡ãœãããåŒã³åºããŸãããã®å Žåããããã¬ãŒã¯MBPã«ãã£ãŠç£èŠãããŠããããŒãžãèªèããŸããããã®MBPã®OnBreakPointãã³ãã©ãŒã¯åŒã³åºãããŸããããã®ãã¬ãŒã¹ãªãã·ã§ã³ã®å®è£ ã¯ããªãã®è£éã«ä»»ãããŠããŸãããã³ãããäŒãããŸãããããã°ã€ãã³ããã³ãã©ãŒããRemoveBreakpointã¡ãœãããåŒã³åºããªãããšã匷ããå§ãããŸãïŒã€ã³ããã¯ã¹ã¯æ¶ããŸãïŒã ããŸãã¯ããããã®ãã³ãã©ãŒã§äœ¿çšå¯èœãªRemoveCurrentBreakpointããã·ãŒãžã£ããããããTFWDebugerCoreã¯ã©ã¹ã®æ¬¡ã®å®è£ ã§ã¯ããã®åäœãä¿®æ£ãããŸããããããåœåã®éããã®ãããªãªãã·ã§ã³ã¯è¡ãã§ãããã
ãã¡ããããã¬ãŒã¹ã¯è¯ãã®ã§ãããèšäºã®å®éã®éšåã§ã¯èª¬æããããªãã£ãã®ã§ããã¢ã«ãã¬ãŒã¹ã®äŸã¯ãããŸããã
ãããã°æååã®åä¿¡ïŒ
éå§ããã«ã¯ãã¢ããªã±ãŒã·ã§ã³ãOutputDebugStringé¢æ°ã䜿çšããŠãããã¬ãŒã«éä¿¡ããæååã®åä¿¡ã衚瀺ããå¿ èŠããããŸããããããè¡ãã«ã¯ããã¹ãã¢ããªã±ãŒã·ã§ã³ã«ãã¿ã³ãé 眮ããããšãã°ããã³ãã©ãŒã§æ¬¡ã®ã³ãŒããèšè¿°ããŸãã
// // // ============================================================================= procedure TForm1.btnDebugStringClick(Sender: TObject); begin OutputDebugString('Test debug string'); end;
次ã«ããããã¬ãŒã§ã次ã®ã³ãŒããå®è£ ããŠOnDebugStringã€ãã³ããéããŸãã
procedure TdlgDebuger.OnDebugString(Sender: TObject; ThreadIndex: Integer; Data: TOutputDebugStringInfo); begin if Data.fUnicode = 1 then Writeln('DebugString: ' + PWideChar(FCore.ReadStringW(Data.lpDebugStringData, Data.nDebugStringLength))) else Writeln('DebugString: ' + PAnsiChar(FCore.ReadStringA(Data.lpDebugStringData, Data.nDebugStringLength))); end;
ãããã°ãããã¢ããªã±ãŒã·ã§ã³ã§ãããã¬ãŒãå®è¡ãããã¿ã³ãã¯ãªãã¯ããŸãã ããã¹ããããã°æååããšããã¡ãã»ãŒãžããã°ã«è¡šç€ºãããŸããïŒã¯ãã®å Žåããã¹ãŠãæ£ããè¡ãããŸãã:)
äŸå€åŠçïŒ
BPãã¢ã³ããããã°ã¢ããªã±ãŒã·ã§ã³ãšããŠäœ¿çšããããšãæãåºããŸãããïŒæ¬¡ã«ãåããªãã·ã§ã³ã«ã€ããŠæ€èšããŠã¿ãŸãããããã¹ãã¢ããªã±ãŒã·ã§ã³ã§ãå¥ã®ãã¿ã³ãè¿œå ãã次ã®ã³ãŒããèšè¿°ããŸãã
// // // ============================================================================= procedure TForm1.btnExceptClick(Sender: TObject); begin try asm int 3 end; ShowMessage('Debugger detected.'); except ShowMessage('Debugger not found.'); end; end;
ååãšããŠãããã¯åãããã°ã§ã¯ãããŸããããå¥åŠãªããšã«ããã®ãããªåå§çãªã¹ããŒã ã§ãããäžéšã®ãªããŒãµãçŒãä»ãããšããããŸãã
ãã®ã¡ãœããã®æ¬è³ªã¯æ¬¡ã®ãšããã§ããèšäºã®åé ã§ããããã°ãµã€ã¯ã«ã®äŸã瀺ããŸããããã®äžã§ãåå埩ã§ãContinueDebugEventé¢æ°ãåŒã³åºãããContinueStatusãã©ã¡ãŒã¿ãŒãDBG_CONTINUEå®æ°ã§åæåãããŸãããããã¯ã©ãããæå³ã§ããïŒããã¯ãçºçããäŸå€ããããã¬ãæ£åžžã«åŠçããããšã瀺ãã·ã°ãã«ã§ããããããããã«ããã䟡å€ã¯ãããŸããã
ããŠããããäžèšã®ã³ãŒãã®äŸã§äœãæå³ããã®ãïŒãINT3ãåœä»€ãåŒã³åºãããšã«ãããäŸå€ãçºçãããŸããã¢ããªã±ãŒã·ã§ã³ã®éåžžã®æäœäžããã®äŸå€ãåŠçãã人ã¯ããªããããäŸå€ãçºçãããšãexception..endãã³ãã©ãŒãžã®é·ç§»ãçºçããŸãããããã¬ãŒã®äžã«ããå Žåã圌ã¯ãã®äŸå€ããã£ããããã¢ããªã±ãŒã·ã§ã³ãã³ãã©ãŒã¯åŒã³åºãããŸããã
確èªããŠãã¢ããªã±ãŒã·ã§ã³ãèµ·åãããã®ã³ãŒãã®ãã¿ã³ãã¯ãªãã¯ãããšãæ£çŽã«è¡šç€ºãããŸã-ãããã¬ãŒã®äžã«ãããŸãã
ãã®ã³ãŒããå æããã®ãåããããç°¡åã§ããOnUnknownBreakPointã€ãã³ãããããã¯ããã ãã§ååã§ãïŒint3ã¯ãã¬ãŒã¯ãã€ã³ãã§ãããç§ãã¡ã«ãã£ãŠèšå®ãããŠããªãããããã®ã€ãã³ãã§ãã£ãããããŸãïŒãã€ãã³ããã³ãã©ãŒã§ã次ã®ã³ãŒããèšè¿°ããŸãã
procedure TdlgDebuger.OnUnknownBreakPoint(Sender: TObject; ThreadIndex: Integer; ExceptionRecord: Windows.TExceptionRecord); var ApplicationBP: Boolean; begin ApplicationBP := (DWORD(ExceptionRecord.ExceptionAddress) > FCore.DebugProcessData.EntryPoint) and (DWORD(ExceptionRecord.ExceptionAddress) < $500000); Writeln; if ApplicationBP then begin Writeln(Format('!!! --> Unknown application breakpoint at addr 0X%p', [ExceptionRecord.ExceptionAddress])); Writeln('!!! --> Exception not handled.'); FCore.ContinueStatus := DBG_EXCEPTION_NOT_HANDLED; end else begin Writeln(Format('!!! --> Unknown breakpoint at addr 0X%p', [ExceptionRecord.ExceptionAddress])); Writeln('!!! --> Exception handled.'); FCore.ContinueStatus := DBG_CONTINUE; end; Writeln; end;
BPãã€ã³ã¹ããŒã«ãããŠããã¢ãã¬ã¹ã«åºã¥ããŠããã¹ãŠãã·ã³ãã«ã§ããã¢ããªã±ãŒã·ã§ã³æ¬äœã§ã®äœçœ®ã決å®ããŸãïŒã¢ããªã±ãŒã·ã§ã³ã®ããŠã³ããŒãã¢ãã¬ã¹ãã500,000ãã«ãŸã§ã®ç¯å²ã倧ãŸãã«ããŸãïŒã BPãã¢ããªã±ãŒã·ã§ã³ã®æ¬äœã«ã€ã³ã¹ããŒã«ãããŠããå Žåãããã¯ããçš®ã®ã¢ã³ããããã°ã§ãããããã¬ãŒã«DBG_EXCEPTION_NOT_HANDLEDãã©ã°ãèšå®ããããšã§äœããã¹ããããããªãããšãäŒããŸããããã§ãªãå Žåã¯ãä»ã®èª°ãããã¬ãŒã¯ãã€ã³ãã§éãã§ããæ å ±ãèšé²ããã ãã§ãã
ãã®ãããªãžã§ã¹ãã£ãŒã®çµæãã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠäººçºçã«çºçããäŸå€ã¯åŠçãããããããã¬ãŒãæ€åºãããªãã£ãããšãåãã§éç¥ããŸã:) ã¹ã¿ãã¯ããªãŒããŒãããŒãããšã©ããªããŸã
ãïŒ
ããŠãæåŸã«èŠãããã®ã¯ããããã¬ãŒåŽããèŠãã¹ã¿ãã¯ãªãŒããŒãããŒã®æ§åã§ãã次ã®ããã«ã以åã®èšäºã®1ã€ããã®ãªãŒããŒãããŒã®äŸãåãäžããŸãã
// // // ============================================================================= procedure TForm1.btnKillStackClick(Sender: TObject); procedure T; var HugeBuff: array [0..10000] of DWORD; begin if HugeBuff[0] <> HugeBuff[10000] then Inc(HugeBuff[0]); T; end; begin try T; except T; end; end;
ãã®ã³ãŒãããã¹ãã¢ããªã±ãŒã·ã§ã³ã«è¿œå ãããã¿ã³ãã¯ãªãã¯ããŸãããããã¬ã®å¿çã¯ç°ãªãå ŽåããããŸãããçµæã¯åžžã«åãã§ã-ãããã¬ã¯éåžžã«æªããªããŸãããã®å Žåã¯ã©ããªããŸããïŒã¹ã¿ãã¯ãªãŒããŒãããŒãæ€åºããã¡ã«ããºã ã¯éåžžã«åçŽã§ã亀差ã§ããªãå¢çç·ã¯ãPAGE_GUARDãã©ã°ã§ããŒã¯ãããå¥ã®ããŒãžã§è¡šãããŸãããããã¯ããããã¯MVRãã»ããã¢ããããã®ãšåãã¡ã«ããºã ã§ããããã®å Žåã¯ä»ã®ç®çã«äœ¿çšãããŸãããªãŒããŒãããŒãããšãEXCEPTION_STACK_OVERFLOWã¯ãããã¬ãŒãžã®åæéç¥ãåãåããŸããååãšããŠãããã§ããªãŒã«ã也ç¥ãããŠãããã¬ãŒãã·ã£ããããŠã³ã§ããŸãããç§ãã¡ã¯æ°žç¶çã§ããããã¹ãã¢ããªã±ãŒã·ã§ã³ãããã«èµ·åããŸãã PAGE_GUARDãã©ã°ã®ãã¥ã¢ã³ã¹ã¯ãæåã®åŒã³åºãåŸã«åé€ãããããšãèŠããŠããå Žåãåãã±ãŒã¹ã§ãããã®ããŒãžã«å床ã¢ã¯ã»ã¹ãããšãEXCEPTION_ACCESS_VIOLATION以å€ã¯äœããã£ããããããããã§ã¯æ¬åœã«ããã¹ãŠãã§ããããããµãã€ãã®ã¯æå³ããããŸãããDBG_CONTROL_Cãèšå®ããŠãããã°ãåæ¢ããã ãã§ãïŒãã¡ãããæ°žä¹ çãªãµã€ã¯ã«ã芳å¯ãããå Žåãé€ããŸãïŒ AVã®çºè¡ãšïŒã
OnUnknownExceptionã€ãã³ãã«ãªãŒããŒãããŒãã³ãã©ãå®è£ ããŸããTFWDebugerCoreã¯ãããã2ã€ã®äŸå€ãåå¥ã®ã€ãã³ããšããŠã¹ããŒããŸããããã®äžã«ä»¥äžãæžããŸãã
procedure TdlgDebuger.OnUnknownException(Sender: TObject; ThreadIndex: Integer; ExceptionRecord: Windows.TExceptionRecord); var Cause: string; begin Writeln; case ExceptionRecord.ExceptionCode of EXCEPTION_STACK_OVERFLOW: begin Writeln('!!! --> Stack overflow detected. Probe to continue.'); FCore.ContinueStatus := DBG_CONTINUE; end; EXCEPTION_ACCESS_VIOLATION: begin { The first element of the array contains a read-write flag that indicates the type of operation that caused the access violation. If this value is zero, the thread attempted to read the inaccessible data. If this value is 1, the thread attempted to write to an inaccessible address. If this value is 8, the thread causes a user-mode data execution prevention (DEP) violation. The second array element specifies the virtual address of the inaccessible data. } case ExceptionRecord.ExceptionInformation[0] of 0: Cause := 'read'; 1: Cause := 'write'; 8: Cause := 'DEP violation'; else Cause := 'unknown cause'; end; Writeln(Format('!!! --> Access violation at addr 0x%p %s of address 0x%p', [ ExceptionRecord.ExceptionAddress, Cause, Pointer(PDWORD(@ExceptionRecord.ExceptionInformation[1])^) ])); Writeln('!!! --> Process Stopped.'); FCore.ContinueStatus := DBG_CONTROL_C; end; else Writeln(Format('!!! --> Unknown exception code %p at addr 0x%p', [ Pointer(ExceptionRecord.ExceptionCode), ExceptionRecord.ExceptionAddress ])); end; Writeln; end;
次ã®ããã«ãªããŸãã
èŠçŽãããšïŒ
åºæ¬çã«ãããããããã¬ã®å®è£ ã«ã€ããŠäŒãããã£ãããšã®ãã¹ãŠã§ããæããã«ãããŠããªããããã¯ãããã€ããããŸããããããã¯ç¬¬3éšã«ãããŸãã
èšäºãéåžžã«èšå€§ãªãã®ã«ãªã£ãããšãåŸæããŠããŸãããæ®å¿µãªããããããå°ããªéšåã«åå²ããããšã¯ã§ããŸããã§ãããå°ãªããšãç§ã¯ä¹Ÿç¥ããäºå®ã§ã¯ãªããæè¡èšäºã§ã¯éåžžçç¥ãããŠãããã¥ã¢ã³ã¹ã«æ倧éã®æ³šæãæãããã«ããŸããã
ç§ã¯ææãæçšã§ãã誰ã«äººã ãããããšãé¡ã£ãŠããŸã:)
èšäºãžã®ãœãŒã¹ã³ãŒãã¯ããã®ãªã³ã¯ããããŠã³ããŒãããããšãã§ããŸãïŒhttp://rouse.drkb.ru/blog/dbg_part2.zip
ããŠããã®èšäºã®ç¬¬äžéšã§ã¯ãæã ã¯å¯Ÿç«ã®ãããã¬ã¢ããªã±ãŒã·ã§ã³ããšãèŠãŠãããŸãæ¬åœã«ãããã°ããããªã:)
ãããŠãããã«ã¯æ¬åœã«ãã¹ãŠããããŸãã
©AlexanderïŒRouse_ïŒããŒã°ã«
ã¢ã¹ã¯ã¯ã2012幎11æ