Как сохранить адрес исходной функции и вызвать ее позже? - PullRequest
0 голосов
/ 24 января 2019

Я пытаюсь вызвать оригинальную функцию в API-хуке, который предотвращает dll-инъекции функцией LdrLoadDll(), но каждый раз, когда я пытаюсь загрузить dll, отличную от того, что отфильтровано, приложение вылетает и неВозможен вызов оригинальной функции.Кажется, что я делаю что-то не так, когда сохраню «original_function» перед хуком.

Я тестирую на Windows 7 x64, внедряю 32-битную DLL в 32-битное приложение (код ниже).

Как это исправить?

program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Windows,
  SysUtils;

type
  NTSTATUS = Cardinal;
  PUNICODE_STRING = ^UNICODE_STRING;

  UNICODE_STRING = packed record
    Length: Word;
    MaximumLength: Word;
    Buffer: PWideChar;
  end;

const
  STATUS_ACCESS_DENIED = NTSTATUS($C0000022);

var
  Old_LdrLoadDll: function(szcwPath: PWideChar; dwFlags: DWORD;
    pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
    : NTSTATUS; stdcall;

function LdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
  pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
  : NTSTATUS; stdcall;
begin
  Result := Old_LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance);
end;

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
  OldProtect: DWORD;
begin
  if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
  begin
    Move(NewCode, Address^, Size);
    FlushInstructionCache(GetCurrentProcess, Address, Size);
    VirtualProtect(Address, Size, OldProtect, @OldProtect);
  end;
end;

type
  PInstruction = ^TInstruction;

  TInstruction = packed record
    Opcode: Byte;
    Offset: Integer;
  end;

procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
  NewCode: TInstruction;
begin
  NewCode.Opcode := $E9;
  NewCode.Offset := NativeInt(NewAddress) - NativeInt(OldAddress) -
    SizeOf(NewCode);
  PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;

function NewLdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
  pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
  : NTSTATUS; stdcall;
begin
  if (pos('111', pUniModuleName.Buffer) > 0) or
    (pos('222', pUniModuleName.Buffer) > 0) then

    Result := STATUS_ACCESS_DENIED
  else
    Result := LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance);
end;

begin
  @Old_LdrLoadDll := GetProcAddress(GetModuleHandle('ntdll.dll'), 'LdrLoadDll');
  try
    RedirectProcedure(GetProcAddress(GetModuleHandle('ntdll.dll'),
      'LdrLoadDll'), @NewLdrLoadDll);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;

end.

Ответы [ 2 ]

0 голосов
/ 25 января 2019

Вот один рабочий код, созданный после следующих предложений @GolezTrol:

program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Windows,
  SysUtils;

type
  NTSTATUS = Cardinal;
  PUNICODE_STRING = ^UNICODE_STRING;

  UNICODE_STRING = packed record
    Length: Word;
    MaximumLength: Word;
    Buffer: PWideChar;
  end;

const
  STATUS_ACCESS_DENIED = NTSTATUS($C0000022);

var
  Old_LdrLoadDll: function(szcwPath: PWideChar; dwFlags: DWORD;
    pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
    : NTSTATUS; stdcall;

function LdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
  pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
  : NTSTATUS; stdcall;
begin
  Result := Old_LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance);
end;

type
  PInstruction = ^TInstruction;

  TInstruction = packed record
    Opcode: Byte;
    Offset: Integer;
  end;

//======= Structure to store original function ======== 

type
  TSaveOriginal = packed record
    Addr: Pointer;
    Bytes: array [0 .. SizeOf(TInstruction)] of Byte;
  end;

  PSaveOriginal = ^TSaveOriginal;

var
  SaveOriginal: TSaveOriginal;

//====================================================

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer;
  SaveOriginal: PSaveOriginal);
var
  OldProtect: DWORD;
begin
  if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
  begin
    //======== Saving original function =========
    if Assigned(SaveOriginal) then
    begin
      SaveOriginal^.Addr := Address;
      Move(Address^, SaveOriginal^.Bytes, Size);
    end;
    //===========================================
    Move(NewCode, Address^, Size);
    FlushInstructionCache(GetCurrentProcess, Address, Size);
    VirtualProtect(Address, Size, OldProtect, @OldProtect);
  end;
end;

procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
  NewCode: TInstruction;
begin
  NewCode.Opcode := $E9;
  NewCode.Offset := NativeInt(NewAddress) - NativeInt(OldAddress) -
    SizeOf(NewCode);
  PatchCode(OldAddress, NewCode, SizeOf(NewCode), @SaveOriginal);
end;

procedure UndoRedirectProcedure(const SaveOriginal: TSaveOriginal);
var
  OldProtect: Cardinal;
begin
  if not VirtualProtect(SaveOriginal.Addr, SizeOf(TInstruction),
    PAGE_EXECUTE_READWRITE, OldProtect) then
    RaiseLastOSError;
  Move(SaveOriginal.Bytes, SaveOriginal.Addr^, SizeOf(TInstruction));
  if not VirtualProtect(SaveOriginal.Addr, SizeOf(TInstruction), OldProtect,
    OldProtect) then
    RaiseLastOSError;
end;

function NewLdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
  pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
  : NTSTATUS; stdcall;
begin
  if (pos('111', pUniModuleName.Buffer) > 0) or
     (pos('222', pUniModuleName.Buffer) > 0) then

    Result := STATUS_ACCESS_DENIED
  else
  begin

    UndoRedirectProcedure(SaveOriginal); // Restore original function

    @Old_LdrLoadDll := SaveOriginal.Addr;

    Result := LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance); // Call original function

    RedirectProcedure(GetProcAddress(GetModuleHandle('ntdll.dll'),
      'LdrLoadDll'), @NewLdrLoadDll); // Hook again
  end;
end;

begin
  try
    RedirectProcedure(GetProcAddress(GetModuleHandle('ntdll.dll'),
      'LdrLoadDll'), @NewLdrLoadDll); 
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;

end.
0 голосов
/ 24 января 2019

Я полагаю, что вы не используете самодельный перехват и получаете для этого существующую библиотеку.

Microsoft Detours теперь бесплатно и с открытым исходным кодом. И поскольку он собирается в DLL, вы можете использовать его с Delphi.

Вам потребуется компилятор C ++ для его сборки из исходного кода, но опять же сообщество Visual Studio бесплатно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...