Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 27.08.2023, 12:24   #1
Комиссар Катани
Пользователь
 
Регистрация: 29.12.2012
Сообщений: 21
По умолчанию WinIO для чтения/записи портов I/O и физпамяти

Добрый день!

Есть подписанный ЭЦП драйвер WinIo 3.0 для доступа к портам и мапинга физической памяти для 32/64-разрадяных Windows. Драйвер с открытым исходным кодом и является весьма популярным.

На Delphi 7 я воспроизвёл код установки драйвера в системе и обращение к нему через DeviceIoControl. Драйвер успешно зарегистрировался в Service Control Manager, запустился через StartService, успешно возвратил хэндл через CreateFile и даже смог считать и писать порты ввода-вывода, как под Windows 11 x64, так и Windows 7 32-bit.

Однако если попытаться замапить память через MapPhysToLin, то драйвер возвращает совсем не то, что нужно. Код мапинга очень простой и ошибки здесь нет:

Код:
type
  TtagPhysStruct = packed record
    dwPhysMemSizeInBytes : Int64; //Number of bytes to map
    pvPhysAddress : Int64;        //Physical address to be mapped
    PhysicalMemoryHandle : Int64; //Handle to a section returned by ZwOpenSection
    pvPhysMemLin : Int64;         //Pointer to a variable that receives the base address of the view
    pvPhysSection : Int64;
  end;

function MapPhysToLin(var PhysStruct: TtagPhysStruct) : Int64;
var
  dwBytesReturned : DWORD;
begin
  if not DeviceIoControl(hDriver,
                         IOCTL_WINIO_MAPPHYSTOLIN, //IOCTL 0x810
                         @PhysStruct,
                         SizeOf(TtagPhysStruct),
                         @PhysStruct,
                         SizeOf(TtagPhysStruct),
		         dwBytesReturned,nil)
    then Result:=0
      else Result:=PhysStruct.pvPhysMemLin;
Поэтому я решился попробовать замапить память через прилагаемую к драйверу библиотеку WinIo32.dll, которая экспортирует функцию GetPhysLong. Данная функция возвращает значение типа DWORD, записанное по определённому адресу в физической памяти.

Код:
var
  dllGetPhysLong: function (pbPhysAddr: PByte; out pdwPhysVal: PDWORD): Boolean; stdcall;
  dllInitializeWinIo: function : Boolean; stdcall;

procedure TForm1.Button2Click(Sender: TObject);
var
  hLibrary: THandle;
  hBuffer : PDWORD;
begin
  hBuffer:=0;
  hLibrary:=LoadLibrary('WinIo32.dll');
  if hLibrary > HINSTANCE_ERROR then
  begin
    @dllInitializeWinIo:=GetProcAddress(hLibrary, 'InitializeWinIo');
    @dllGetPhysLong:=GetProcAddress(hLibrary, 'GetPhysLong');
    if @dllInitializeWinIo <> nil then
      if dllInitializeWinIo then
        if @dllGetPhysLong <> nil then
        begin
          if dllGetPhysLong(Ptr($C0000),hBuffer) then
            ShowMessage(IntToHex(DWORD(hBuffer),8))
            else ShowMessage('Error '+IntToHex(GetLastError,8));;
        end;
    FreeLibrary(hLibrary);
  end;
end;
В коде выше я считываю 4 байта под адресу 0xC0000 (видеопамять). По этому адресу записано 0хE972AA55, которое успешно и возвращается при нажатии на кнопку. Но юзать DLL-ку мне не хочется. Хотелось бы воспроизвести все функции в своём коде самостоятельно.

Есть подозрение, что в С++ своя особенная упаковка структуры TtagPhysStruct:

Код:
#pragma pack(push)
#pragma pack(1)

struct tagPhysStruct
{
	DWORD64 dwPhysMemSizeInBytes;
	DWORD64 pvPhysAddress;
	DWORD64 PhysicalMemoryHandle;
	DWORD64 pvPhysMemLin;
	DWORD64 pvPhysSection;
};

#pragma pack(pop)

#endif
В общем, если кому-то уже ранее удалось портировать WinIo на Delphi, то я был бы рад любой помощи!

Последний раз редактировалось Комиссар Катани; 27.08.2023 в 12:27.
Комиссар Катани вне форума Ответить с цитированием
Старый 27.08.2023, 12:39   #2
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,709
По умолчанию

Цитата:
Сообщение от Комиссар Катани Посмотреть сообщение
Есть подозрение, что в С++ своя особенная упаковка структуры TtagPhysStruct:
Код:
#pragma pack(1)
Как раз байт к байту без паддинга

DWORD64 это UInt64
p51x вне форума Ответить с цитированием
Старый 27.08.2023, 12:52   #3
Комиссар Катани
Пользователь
 
Регистрация: 29.12.2012
Сообщений: 21
По умолчанию

Цитата:
Сообщение от p51x Посмотреть сообщение
DWORD64 это UInt64
Согласен с Вами, но в Delphi 7 нет типа UInt64. Он введён, начиная c Delphi2007, если не ошибаюсь.
Комиссар Катани вне форума Ответить с цитированием
Старый 28.08.2023, 01:37   #4
northener
ПШП
Участник клуба
 
Регистрация: 15.07.2013
Сообщений: 1,872
По умолчанию

Цитата:
Сообщение от Комиссар Катани Посмотреть сообщение
о в Delphi 7 нет типа UInt64
How-to-define-an-unsigned-64-bit-integer-in-delphi7
northener вне форума Ответить с цитированием
Старый 28.08.2023, 13:51   #5
Комиссар Катани
Пользователь
 
Регистрация: 29.12.2012
Сообщений: 21
По умолчанию

В общем, друзья, сегодня установил Delphi 11.3 Community Edition, заменил тип Int64 переменных структуры TtagPhysStruct на DWORD64, как в сишном исходнике, и скомпилировал:

Код:
type
  TtagPhysStruct = packed record
    dwPhysMemSizeInBytes : DWORD64; //Number of bytes to map
    pvPhysAddress : DWORD64;        //Physical address to be mapped
    PhysicalMemoryHandle : DWORD64; //Handle to a section returned by ZwOpenSection
    pvPhysMemLin : DWORD64;         //Pointer to a variable that receives the base address of the view
    pvPhysSection : DWORD64;
  end;

function MapPhysToLin(var PhysStruct: TtagPhysStruct) : Int64;
var
  dwBytesReturned : DWORD;
begin
  if not DeviceIoControl(hDriver,
                         IOCTL_WINIO_MAPPHYSTOLIN, //IOCTL 0x810
                         @PhysStruct,
                         SizeOf(TtagPhysStruct),
                         @PhysStruct,
                         SizeOf(TtagPhysStruct),
		         dwBytesReturned,nil)
    then Result:=0
      else Result:=PhysStruct.pvPhysMemLin;
Результат, увы, тот же, как и с использованием Int64. Вместо PhysStruct в качестве выходного буфера я попробовал подставить статический массив типа Byte размерностью 40 байтов -- возвращается такая же белиберда. В общем, не знаю, куда капать дальше.
Комиссар Катани вне форума Ответить с цитированием
Старый 28.08.2023, 14:00   #6
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,709
По умолчанию

Покажите как вызываете
p51x вне форума Ответить с цитированием
Старый 28.08.2023, 15:15   #7
Комиссар Катани
Пользователь
 
Регистрация: 29.12.2012
Сообщений: 21
По умолчанию

Цитата:
Сообщение от p51x Посмотреть сообщение
Покажите как вызываете
Вызываю просто:
Код:
procedure TForm1.Button3Click(Sender: TObject);
var
  PhysStruct : TtagPhysStruct;
  ResultQw : Int64;
begin
  ZeroMemory(@PhysStruct,SizeOf(PhysStruct));
  PhysStruct.dwPhysMemSizeInBytes:=4; //мапинг 4-х байтов физической памяти
  PhysStruct.pvPhysAddress:=$C0000; //по адресу 0xC0000 - адрес начала региона Video BIOS 
  ResultQw:=MapPhysToLin(PhysStruct);
end;
Функция MapPhysToLin отрабатывает нормально, т.е. функция DeviceIoControl даёт успех (True), но выходной буфер PhysStruct типа TtagPhysStruct заполняется неверно. Вот, например, так:

Код:
dwPhysMemSizeInBytes = 4
pvPhysAddress = 786432 (0xC0000)
PhysicalMemoryHandle = 508 (0x1FC)
pvPhysMemLin = 26411008 (0x1930000)
pvPhysSection = 3405802376 (0xCB006B88)
Функция GetPhysLong, экспортируемая из родной библиотеки WinIo32.dll (скомпилирована на MS VS2008 SP1), делает то же самое, что я написал в качестве кода для обработчика события кнопки Button3. В случае вызова GetPhysLong из библиотеки буфер PhysStruct заполняется корректно.

Скорее всего, что я не совсем точно перевёл код функции с С++ на Паскаль. Вот, что она собой представляет в библиотеке WinIo32.dll:
Код:
PBYTE _stdcall MapPhysToLin(tagPhysStruct &PhysStruct)
{
	DWORD dwBytesReturned;

	if (!DeviceIoControl(hDriver, IOCTL_WINIO_MAPPHYSTOLIN, &PhysStruct,
		sizeof(tagPhysStruct), &PhysStruct, sizeof(tagPhysStruct),
		&dwBytesReturned, NULL))
	{
		return NULL;
	}

	return (PBYTE)PhysStruct.pvPhysMemLin; //на этой строчке в своём коде я не преобразовываю к типу PBYTE
}

Последний раз редактировалось Комиссар Катани; 28.08.2023 в 18:20. Причина: Добавлен сишный код функции MapPhysToLin
Комиссар Катани вне форума Ответить с цитированием
Старый 29.08.2023, 10:07   #8
Комиссар Катани
Пользователь
 
Регистрация: 29.12.2012
Сообщений: 21
По умолчанию

Друзья, установил я ApiMonitor и отследил, как заполняется буфер PhysStruct типа TtagPhysStruct драйвером при обращении к нему через DeviceIoControl. Результат прилагается.

В первом случае, как видно на скрине, прога напрямую вызывает функцию MapPhysToLin, отправляя через DeviceIoControl соответствующий IOCTL код драйверу. Драйвер заполняет буфер PhysStruct и передаёт его программе обратно.

Во втором случае вызов функции MapPhysToLin происходит из библиотеки WinIo32.dll. Как видно, заполненный буфер PhysStruct не сильно отличается от первого случая.

В обоих случаях перед вызовом DeviceIoControl в буфер записываются dwPhysMemSizeInBytes = 4 и pvPhysAddress = $C0000.

Тогда вопрос, как тогда MapPhysToLin из WinIo32.dll возвращает корректное значение $E975AA55, если на скрине видно, что pvPhysMemLin = $012F0000?
Изображения
Тип файла: png DeviceIoControl_dump.png (33.2 Кб, 4 просмотров)
Комиссар Катани вне форума Ответить с цитированием
Старый 29.08.2023, 13:31   #9
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 161
По умолчанию

Цитата:
Сообщение от Комиссар Катани Посмотреть сообщение
else Result:=PhysStruct.pvPhysMemLin;
Код:
else Result:=addr(PhysStruct.pvPhysMemLin);
не?
DIONISKA вне форума Ответить с цитированием
Старый 29.08.2023, 14:13   #10
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,777
По умолчанию

Цитата:
Сообщение от Комиссар Катани Посмотреть сообщение
Тогда вопрос, как тогда MapPhysToLin из WinIo32.dll возвращает корректное значение $E975AA55, если на скрине видно, что pvPhysMemLin = $012F0000?
Использует другую функцию?
Код:
function MapPhysToLin(var PhysStruct: TtagPhysStruct): Int64;
begin
  // написана правильно, остается
end;

var
  hMap: Int64;

function GetPhysLong(Addr: PByte; out Val: LongWord): Boolean;
begin
  if Addr <> 0 then
  begin
    Val := PLongWord(PAnsiChar(Addr) - Integer(hMap))^;
    Result := True;
  end
  else
    Result := False;
end;

var
  PhysStruct: TtagPhysStruct;
  Buffer: LongWord;
begin
  ZeroMemory(@PhysStruct, SizeOf(PhysStruct));
  PhysStruct.dwPhysMemSizeInBytes := 4;
  PhysStruct.pvPhysAddress := $C0000;
  hMap := MapPhysToLin(PhysStruct);
  if GetPhysLong(Ptr($C0000), Buffer) then
    ShowMessage(IntToHex(Buffer ,8))
  else
    ShowMessage('Error ' + IntToHex(GetLastError, 8));
end;
Код примерный, для 32 бит.
Vapaamies вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Обращение по индексу(свойство чтения и записи) plktre Помощь студентам 0 22.02.2020 20:25
Попытка чтения или записи в защищенную память. zzz6 Общие вопросы C/C++ 2 23.03.2012 20:26
Как открыть для чтения и записи файл без расширения DeDoK Общие вопросы Delphi 4 11.11.2009 22:41
С++. Кеширование чтения\записи файла Vinny Помощь студентам 1 03.06.2009 00:43
Защита HDD от чтения/записи при любых условиях. Air Свободное общение 43 17.05.2009 18:33