Отладчик под 98
От: alex134  
Дата: 20.04.03 16:17
Оценка:
Пишу простой отладчик, задача которого ставить breakpoint на выполнение команды опр. с адресом. Написал я этот код "по мотивам" статьи "Использование Debug API пример перехвата вызовов функций" (автор Ketmar):

const
  EFLAGS_TRACE = $100;

type
  TThreadList= array[0..99] of
    record
      Id, Handle, Flag: DWORD;
    end;

var
  ThreadList: TThreadList;

procedure AddThreadToList(List: TThreadList; ThreadId, ThreadH: DWord);
var
  i : integer;
begin
  i:=-1;
  repeat
    inc(i);
  until List[i].Flag=0;
  List[i].Handle:=ThreadH;
  List[i].Id:=ThreadId;
end;

procedure DeleteThreadFromList(List: TThreadList; ThreadId: DWord);
var
  i : integer;
begin
  for i:=0 to 99 do
    if List[i].Id=ThreadId then
    begin
      List[i].Id:=0;
      List[i].Handle:=0;
      List[i].Flag:=0;
    end;
end;

function GetThreadHandleFromList(List: TThreadList; ThreadId: DWord): DWord;
var
  i : integer;
begin
  Result:=0;
  for i:=0 to 99 do
    if List[i].Id=ThreadId then
    begin
      Result:=List[i].Handle;
      Break;
    end;
end;

function WriteInt3(PrcH: THandle; n: DWord):byte;
var
  BreakByte, A : Byte;
  Count : DWord;
begin
  A:=$CC;
  Result:=0;
  if ReadProcessMemory(PrcH, Ptr(n), @BreakByte, 1, Count) then
  begin
    if WriteProcessMemory(PrcH, Ptr(n), @A, 1, Count) then Result:=BreakByte;
  end;
end;

function WriteByte(PrcH: THandle; n: DWord; B: Byte):byte;
var
  Count : DWord;
begin
  Result:=0;
  if WriteProcessMemory(PrcH, Ptr(n), @B, 1, Count) then Result:=1;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ProcID : DWord;
  lpDebugEvent : TDebugEvent;
  WindowH, ProcHandle, CurThread : THandle;
  Bp1 : DWORD;
  B1 : Byte;
  Context : TContext;
  RestoreBreak: Boolean;
begin
  FillChar(ThreadList, SizeOf(ThreadList), 0);
  Bp1:=StrToInt(Edit2.Text);
  RestoreBreak := False;

  WindowH:=FindWindow(nil, 'testdebug');
  if WindowH=0 then
  begin
    ShowMessage('Окно не найдено! Невозможно пролучить ID процесса.');
    Exit;
  end;
  GetWindowThreadProcessID(WindowH, @ProcID);
  ProcHandle := OpenProcess(PROCESS_ALL_ACCESS, False, ProcID);

  B1:=WriteInt3(ProcHandle, Bp1);
  if B1=0 then
  begin
    ShowMessage('Невозможно установить breakpoint');
    Exit;
  end;


  DebugActiveProcess(ProcID);
  while true do
  begin
     if not WaitForDebugEvent(lpDebugEvent, INFINITE) then Break;
     CurThread := GetThreadHandleFromList(ThreadList, lpDebugEvent.dwThreadId);
     case lpDebugEvent.dwDebugEventCode of
     CREATE_PROCESS_DEBUG_EVENT: AddThreadToList(ThreadList, lpDebugEvent.dwThreadId, lpDebugEvent.CreateProcessInfo.hThread);
     CREATE_THREAD_DEBUG_EVENT: AddThreadToList(ThreadList, lpDebugEvent.dwThreadId, lpDebugEvent.CreateThread.hThread);
     EXIT_THREAD_DEBUG_EVENT: DeleteThreadFromList(ThreadList, lpDebugEvent.dwThreadId);
     EXCEPTION_DEBUG_EVENT:
       begin
         if (lpDebugEvent.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_BREAKPOINT) then begin
           Context.ContextFlags := CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
           GetThreadContext(CurThread, Context);
           if (Bp1 <> 0) and (Context.EIP = Bp1 + 1) then
           begin
             Memo1.Lines.Add('Breakpoint EIP=0x'+IntToStr(Context.EIP)+' EXC=0x'+IntToStr(Context.Ecx));
             Context.EIP := Bp1;
             WriteByte(ProcHandle, Bp1, B1);
             Context.EFlags := Context.EFlags or EFLAGS_TRACE;
             Context.ContextFlags := CONTEXT_CONTROL;
             SetThreadContext(CurThread, Context);
             RestoreBreak := True;
           end else Memo1.Lines.Add('INT EIP='+IntToStr(Context.EIP)+' EXC='+IntToStr(Context.Ecx));
           ContinueDebugEvent(lpDebugEvent.dwProcessId, lpDebugEvent.dwThreadId, DBG_Continue);
         end else ContinueDebugEvent(lpDebugEvent.dwProcessId, lpDebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
       end;
     EXCEPTION_SINGLE_STEP:
     if RestoreBreak and (Context.EIP >= Bp1) and (Context.EIP <= Bp1 + 32) then
     begin
       Context.ContextFlags := CONTEXT_CONTROL;
       GetThreadContext(CurThread, Context);
       B1:=WriteInt3(ProcHandle, Bp1);
       Context.EFlags := Context.EFlags and not EFLAGS_TRACE;
       Context.ContextFlags := CONTEXT_CONTROL;
       SetThreadContext(CurThread, Context);
       RestoreBreak := False;
     end;
     EXIT_PROCESS_DEBUG_EVENT: Break;
     end;
     if lpDebugEvent.dwDebugEventCode<>EXCEPTION_DEBUG_EVENT then ContinueDebugEvent(lpDebugEvent.dwProcessId, lpDebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
  end;
  CloseHandle(ProcHandle);
end;


B1 — адрес точкки останова (я его ввожу из Edit'a). Когда отлаживаемая программа доходит до места куда мы ставим int 3 она начинает глючить — попробуйте сами! Не могу найти ошибку
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.