Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Перехват вызовов функций из динамических библиотек

Delphi , Файловая система , DLL и PlugIns

Перехват вызовов функций из динамических библиотек

Автор: Den is Com

В России запущенно производство принципиально новых программно-аппаратных средств для взлома систем под названием: "Plug & Fuck". Устройства и софт работают отлично.

// проверено и работает для WIN 9x и WinNT
// в юните на первый взгляд, есть структуры , описание которых уже есть в Дельфи , но к сожалению не
// всех и не во всех версиях Дельфи эти структуры присутствуют. Да уж, это не С

Проблема скорее для хакера, а не для программиста. Но существуют ситуации, когда это необходимо. Сложно предположить ситуацию, в которой это может понадобится, но например: можете перехватывать надоевшее окошко о необходимости купить компонент :) . Разумеется этот код предназначен для более широких целей и в более широком варианте позволяет контролировать работу внешней программы, производя "мягкий" взлом - изменения присходят только в памяти и не касаются исполняемого файла на диске. Разумеется можно использовать и для более светлых целей. При использовании данного исходника будьте осторожны: при компилировании пректа с динамическими пакетами перехватываемая функция может находится в пакете, а не в файле программы. Перед перехватом функции необходимо заменить её функцией-ловушкой. Например для MessageBox


type

TMyProc= function (hWnd: HWND; lpText, lpCaption: 
  PAnsiChar; uType: UINT): Integer; stdcall;
PTMyProc=^TMyProc;

function MyMessageBox(hWnd: HWND; lpText, lpCaption: 
  PAnsiChar; uType: UINT): Integer; stdcall;
begin
  ShowMessage('Message intercepted');
  result:=IDOK;
end;

и сам перехват происходит так


InterceptDllCall(hInstance,'user32.dll','MessageBoxA',
Pointer(@MyMessageBox),PPointer(@myProc),nil); 

теперь все вызовы MessageBox будут ссылаться на нашу функцию :) Надеюсь вы помните, что функции MessageBox в user32.dll нет - это только оболочка для MessageBoxА

и обратная операция - восстановление работоспособности старой функции


InterceptDllCall(hInstance,'user32.dll','MessageBoxA',
Pointer(myProc),nil,Pointer(@MyMessageBox)); 

Привожу полностью все файлы проекта:


// Intercep.pas

unit intercep;

interface
uses windows, dialogs, SysUtils;
type

  PImageDosHeader = ^TImageDosHeader;
  {EXTERNALSYM _IMAGE_DOS_HEADER}
  _IMAGE_DOS_HEADER = packed record { DOS .EXE header                  }
    e_magic: Word; { Magic number                     }
    e_cblp: Word; { Bytes on last page of file       }
    e_cp: Word; { Pages in file                    }
    e_crlc: Word; { Relocations                      }
    e_cparhdr: Word; { Size of header in paragraphs     }
    e_minalloc: Word; { Minimum extra paragraphs needed  }
    e_maxalloc: Word; { Maximum extra paragraphs needed  }
    e_ss: Word; { Initial (relative) SS value      }
    e_sp: Word; { Initial SP value                 }
    e_csum: Word; { Checksum                         }
    e_ip: Word; { Initial IP value                 }
    e_cs: Word; { Initial (relative) CS value      }
    e_lfarlc: Word; { File address of relocation table }
    e_ovno: Word; { Overlay number                   }
    e_res: array[0..3] of Word; { Reserved words                   }
    e_oemid: Word; { OEM identifier (for e_oeminfo)   }
    e_oeminfo: Word; { OEM information; e_oemid specific}
    e_res2: array[0..9] of Word; { Reserved words                   }
    e_lfanew: LongInt; { File address of new exe header   }
  end;
  TImageDosHeader = _IMAGE_DOS_HEADER;
  //  {$EXTERNALSYM IMAGE_DOS_HEADER}

  IMAGE_DOS_HEADER = _IMAGE_DOS_HEADER;

  //***************************************
  PImageDataDirectory = ^TImageDataDirectory;
  _IMAGE_DATA_DIRECTORY = record
    VirtualAddress: DWORD;
    Size: DWORD;
  end;
  //  {$EXTERNALSYM _IMAGE_DATA_DIRECTORY}
  TImageDataDirectory = _IMAGE_DATA_DIRECTORY;
  IMAGE_DATA_DIRECTORY = _IMAGE_DATA_DIRECTORY;
  //  {$EXTERNALSYM IMAGE_DATA_DIRECTORY}

  //*************
  PImageOptionalHeader = ^TImageOptionalHeader;
  _IMAGE_OPTIONAL_HEADER = packed record
    { Standard fields. }
    Magic: Word;
    MajorLinkerVersion: Byte;
    MinorLinkerVersion: Byte;
    SizeOfCode: DWORD;
    SizeOfInitializedData: DWORD;
    SizeOfUninitializedData: DWORD;
    AddressOfEntryPoint: DWORD;
    BaseOfCode: DWORD;
    BaseOfData: DWORD;
    { NT additional fields. }
    ImageBase: DWORD;
    SectionAlignment: DWORD;
    FileAlignment: DWORD;
    MajorOperatingSystemVersion: Word;
    MinorOperatingSystemVersion: Word;
    MajorImageVersion: Word;
    MinorImageVersion: Word;
    MajorSubsystemVersion: Word;
    MinorSubsystemVersion: Word;
    Win32VersionValue: DWORD;
    SizeOfImage: DWORD;
    SizeOfHeaders: DWORD;
    CheckSum: DWORD;
    Subsystem: Word;
    DllCharacteristics: Word;
    SizeOfStackReserve: DWORD;
    SizeOfStackCommit: DWORD;
    SizeOfHeapReserve: DWORD;
    SizeOfHeapCommit: DWORD;
    LoaderFlags: DWORD;
    NumberOfRvaAndSizes: DWORD;
    DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of
      TImageDataDirectory;
  end;
  // {$EXTERNALSYM _IMAGE_OPTIONAL_HEADER}
  TImageOptionalHeader = _IMAGE_OPTIONAL_HEADER;
  IMAGE_OPTIONAL_HEADER = _IMAGE_OPTIONAL_HEADER;
  // {$EXTERNALSYM IMAGE_OPTIONAL_HEADER}

  PImageNtHeaders = ^TImageNtHeaders;
  _IMAGE_NT_HEADERS = packed record
    Signature: DWORD;
    FileHeader: TImageFileHeader;
    OptionalHeader: TImageOptionalHeader;
  end;
  // {$EXTERNALSYM _IMAGE_NT_HEADERS}
  TImageNtHeaders = _IMAGE_NT_HEADERS;
  IMAGE_NT_HEADERS = _IMAGE_NT_HEADERS;
  // {$EXTERNALSYM IMAGE_NT_HEADERS}

  PImage_import_by_name = ^TImage_import_by_mame;
  _IMAGE_IMPORT_BY_NAME = packed record

    Hint: Word;
    Name: Byte;
  end;
  TImage_import_by_mame = _IMAGE_IMPORT_BY_NAME;

  _u1 = packed record
    case Integer of

      0: (ForwarderString: PByte);
      1: (Functionn: PDWORD);
      2: (Ordinal: DWORD);
      3: (AddressOfData: PImage_import_by_name);
  end;
  PImageThunkData = ^TImageThunkData;
  _IMAGE_THUNK_DATA = packed record

    u1: _u1;
  end;
  TImageThunkData = _IMAGE_THUNK_DATA;
  IMAGE_THUNK_DATA = _IMAGE_THUNK_DATA;

  _temp_charcteristics = record
    case Integer of
      0: (Characteristics: DWORD); // 0 for terminating null import descriptor
      1: (OriginalFirstThunk: PImageThunkData); // RVA to original unbound IAT
  end;

  PImageImportDescriptor = ^TImageImportDescriptor;
  _IMAGE_IMPORT_DESCRIPTOR = packed record

    t: _temp_charcteristics;
    TimeDateStamp: DWord; // 0 if not bound,
    // -1 if bound, and real date\time stamp
    //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
    // O.W. date/time stamp of DLL bound to (Old BIND)

    ForwarderChain: DWORD; // -1 if no forwarders
    Name: DWORD;
    FirstThunk: PImageThunkData;
      // RVA to IAT (if bound this IAT has actual addresses)
  end;
  TImageImportDescriptor = _IMAGE_IMPORT_DESCRIPTOR;
  IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR;
  PPointer = ^Pointer;
function InterceptDllCall(

  hLocalModule: HModule;
  c_szDllName: Pchar;
  c_szApiName: PChar;
  pApiNew: Pointer;
  p_pApiOrg: PPointer;
  pApiToChange: Pointer): Boolean;
implementation

function MakePtr(base: Dword; Offset: DWORD): Pointer;
begin
  Result := Pointer(Base + Offset);
end;

function InterceptDllCall(

  hLocalModule: HModule;
  c_szDllName: Pchar;
  c_szApiName: PChar;
  pApiNew: Pointer;
  p_pApiOrg: PPointer;
  pApiToChange: Pointer): Boolean;

var
  pDosHeader: PImageDosHeader;

  pNtHeader: PImageNtHeaders;
  PImportDesc: PImageImportDescriptor;
  dwProtect: DWORD;
  dwNewProtect: DWORD;
  dwAddressToInterCept: DWORD;
  pThunk: PImageThunkData;
begin
  pDosHeader := PImageDosHeader(hLocalModule);
  Result := False;
  if (pApiToChange <> nil) then
    dwAddressToIntercept := DWORD(pApiToChange)
  else
    dwAddressToIntercept := Dword(GetProcAddress(GetModuleHandle(c_szDllName),
      c_szApiName));

  if IsBadReadPtr(Pointer(hLocalModule), sizeof(PImageNtHeaders)) then
    Exit;

  if pDosHeader.e_magic <> IMAGE_DOS_SIGNATURE then
    exit;
  pNtHeader := PImageNtHeaders(MakePtr(DWord(pDOSHeader),
    DWord(pDOSHeader.e_lfanew)));
  if pNTHeader.signature <> IMAGE_NT_SIGNATURE then
    exit;
  pImportDesc := PImageImportDescriptor(

    MakePtr(hLocalModule,
    pNtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));

  if (PImportDesc = PImageImportDescriptor(pNtHeader)) then
    exit;

  while (pImportDesc.Name > 0) do
  begin

    pThunk := PImageThunkData(MakePtr(DWord(hLocalModule),
      Dword(pImportDesc.FirstThunk)));
    while (pThunk.u1.Functionn <> nil) do
    begin
      if DWord(pThunk.u1.Functionn) = dwAddressToIntercept then
      begin
        if not IsBadWritePtr(Pointer(@pThunk.u1.Functionn), sizeof(DWORD)) then
        begin
          if (p_pApiOrg <> nil) then
            p_pApiOrg^ := Pointer(pThunk.u1.Functionn);
          pThunk.u1.Functionn := pApiNew;
          Result := True;
        end
        else
        begin
          if VirtualProtect(Pointer(@pThunk.u1.Functionn), sizeof(DWORD),
            PAGE_EXECUTE_READWRITE, @dwProtect) then
          begin
            if (p_pApiOrg <> nil) then
              p_pApiOrg^ := Pointer(pThunk.u1.Functionn);
            pThunk.u1.Functionn := PDWORD(pApiNew);
            Result := True;
            dwNewProtect := dwProtect;
            VirtualProtect(Pointer(@pThunk.u1.Functionn), sizeof(DWORD),
              dwNewProtect, @dwProtect);
          end;
        end;
      end;
      Inc(PThunk);
    end;
    Inc(pImportDEsc);
  end;
end;

end.

// Project1.dpr

program Project1;

uses
  Forms,
  Unit1 in '..\..\Work\Temp\4\Unit1.pas' {Form1};

{$R *.RES}

begin

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

// Unit1.dfm

object Form1: TForm1

  Left = 192
    Top = 107
    Width = 435
    Height = 300
    Caption = 'Form1'
    Color = clBtnFace
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'MS Sans Serif'
    Font.Style = []
    OldCreateOrder = False
    PixelsPerInch = 96
    TextHeight = 13
    object Button1: TButton
    Left = 72
      Top = 176
      Width = 273
      Height = 65
      Caption = 'Begin'
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -24
      Font.Name = 'MS Sans Serif'
      Font.Style = []
      ParentFont = False
      TabOrder = 0
      OnClick = Button1Click
  end
  object Button2: TButton
    Left = 304
      Top = 16
      Width = 105
      Height = 49
      Caption = 'MessageBox'
      TabOrder = 1
      OnClick = Button2Click
  end
end

// Unit1.pas

unit Unit1;

interface

uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, intercep;

type

  TMyProc = function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT):
    Integer; stdcall;
  PTMyProc = ^TMyProc;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var

  Form1: TForm1;
  myProc: PTMyProc;
implementation

function MyMessageBox(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT):
  Integer; stdcall;
begin
  ShowMessage('Message intercepted');

  result := IDOK;
end;
{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);

begin
  myProc := nil;
  MessageBox(0, 'Hello', 'Message 1', MB_OK);
  InterceptDllCall(hInstance, 'user32.dll', 'MessageBoxA',
    Pointer(@MyMessageBox), PPointer(@myProc), nil); //then ShowMessage('Ok');
  MessageBox(0, 'Hello', 'Message 2', MB_OK);
  InterceptDllCall(hInstance, 'user32.dll', 'MessageBoxA',
    Pointer(myProc), nil, Pointer(@MyMessageBox));
  MessageBox(0, 'Hello', 'Message 3 ', MB_OK);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  MessageBox(0, 'Hello', 'Message 4 ', MB_OK);
end;

end.

Перевод контента на русский язык:

Это проект Delphi, демонстрирующий, как интерceptar вызовы функции MessageBox из динамической библиотеки (DLL) с помощью техники называемой "hooking". Код определяет две функции: MyMessageBox, которая отображает сообщение в окне с пользовательским текстом, и InterceptDllCall, которая настраивает hook.

Разбивка кода:

  1. Единица Intercep определяет структуры для различных типов заголовков и каталогов, найденных в файлах PE (Portable Executable).
  2. Файл Project1.dpr является основным файлом проекта, содержащим точку входа для приложения.
  3. Единица Unit1 определяет форму (TForm1) с двумя кнопками: Button1 и Button2. Когда кликается Button1, она вызывает MyMessageBox и настраивает hook с помощью InterceptDllCall. Когда кликается Button2, она просто отображает сообщение без интерцепции вызова.
  4. Тип TMyProc определяет указатель функции, соответствующий сигнатуре MessageBoxA.
  5. В процедуре Button1Click код настраивает hook, вызывая InterceptDllCall с следующими аргументами:
    • hInstance: Обратный handle к DLL, содержащей функцию MessageBox.
    • 'user32.dll': Имя DLL, содержащей функцию MessageBox.
    • 'MessageBoxA': Имя функции для интерцепции.
    • Pointer(@MyMessageBox): Указатель на пользовательскую функцию сообщения (MyMessageBox).
    • PPointer(@myProc): Указатель на переменную, которая будет содержать оригинальный адрес функции MessageBox.
    • nil: Опциональный аргумент, не используемый в этом случае.

Настройка hook позволяет последующие вызовы функции MessageBoxA быть переданы в пользовательскую функцию сообщения (MyMessageBox). Код затем отображает три сообщения: одно с стандартным текстом и два с пользовательскими текстами.

Обратите внимание, что механизм hooking основан на том, что DLL загружается в память, и адреса функций известны. Это подход может быть использован для отладки или тестирования, но может не быть пригоден для производственного кода из-за потенциальных проблем с стабильностью и необходимости тщательного управления hook.

Также код использует функцию InterceptDllCall из единицы Intercep, которая не является стандартной библиотекой Delphi. Это может указывать на то, что это часть custom или third-party библиотеки.

В статье описывается способ перехвата вызовов функций из динамических библиотек (DLL) на языке Pascal. Автор предлагает использовать свой код для реализации этого и предоставляет пример проекта, который демонстрирует работу данной функции.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: DLL и PlugIns ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-19 13:29:56
2024-11-21 11:34:25/0.0071749687194824/1