Минимальная RTL. Проблемы с DLL

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Минимальная RTL. Проблемы с DLL

Сообщение TimK » 11.02.2010 17:15:57

Требуется длл минимального размера (глобальный хук). Код длл состоит только из API-вызовов. Для этого имеется урезанная RTL состоящая из оригинальных Windows, Messages и порезанного System:

Код: Выделить всё
unit System;

interface

{$I-,Q-,H-,R-,V-,S-}
{$mode objfpc}


{systemh.inc}

type
  DWord    = LongWord;
  Cardinal = LongWord;
  Integer  = SmallInt;
  UInt64   = QWord;

{$ifdef CPU64}
  SizeInt  = Int64;
  SizeUInt = QWord;
  PtrInt   = Int64;
  PtrUInt  = QWord;
  ValSInt  = Int64;
  ValUInt  = QWord;
{$endif CPU64}

{$ifdef CPU32}
  SizeInt  = Longint;
  SizeUInt = DWord;
  PtrInt   = Longint;
  PtrUInt  = DWord;
  ValSInt  = Longint;
  ValUInt  = Cardinal;
{$endif CPU32}

  PChar        = ^Char;
  PPChar       = ^PChar;

  TAnsiChar    = Char;
  AnsiChar     = Char;
  PAnsiChar    = PChar;
  PPAnsiChar   = PPChar;

  HRESULT      = type Longint;
{$ifndef FPUNONE}
  TDateTime    = type Double;
{$endif}
  TError       = type Longint;

{$ifndef FPUNONE}
  PSingle      = ^Single;
  PDouble      = ^Double;
  PExtended    = ^Extended;
{$endif}
  PCurrency    = ^Currency;
{$ifdef SUPPORT_COMP}
  PComp        = ^Comp;
{$endif SUPPORT_COMP}

  PSmallInt    = ^Smallint;
  PShortInt    = ^Shortint;
  PInteger     = ^Integer;
  PByte        = ^Byte;
  PWord        = ^Word;
  PDWord       = ^DWord;
  PLongWord    = ^LongWord;
  PLongint     = ^Longint;
  PCardinal    = ^Cardinal;
  PQWord       = ^QWord;
  PInt64       = ^Int64;
  PPtrInt      = ^PtrInt;
  PPtrUInt     = ^PtrUInt;
  PSizeInt     = ^SizeInt;

  PPointer     = ^Pointer;
  PPPointer    = ^PPointer;

  PBoolean     = ^Boolean;
  PWordBool    = ^WordBool;
  PLongBool    = ^LongBool;

  PShortString = ^ShortString;
  PAnsiString  = ^AnsiString;
  PWideString  = ^WideString;

  PVariant     = ^Variant;
  POleVariant  = ^OleVariant;

  WChar        = WideChar;
  UnicodeChar  = WideChar;
  PWideChar    = ^WideChar;
  PPWideChar   = ^PWideChar;
  PUnicodeChar = ^UnicodeChar;

  TProcedure = procedure;


{sysos.inc}

type
{$ifdef CPU64}
  THandle   = QWord;
  ULONG_PTR = QWord;
{$else CPU64}
  THandle   = DWord;
  ULONG_PTR = DWord;
{$endif CPU64}

  TThreadID = THandle;
  SIZE_T = ULONG_PTR;

  UINT = Cardinal;
  BOOL = LongBool;

{$ifdef UNICODE}
  LPTCH   = ^Word;
  LPTSTR  = ^Word;
  LPCTSTR = ^Word;
{$else UNICODE}
  LPTCH   = ^Char;
  LPTSTR  = ^Char;
  LPCTSTR = ^Char;
{$endif UNICODE}

  LPWSTR  = ^WChar;
  PVOID   = Pointer;
  LPVOID  = Pointer;
  LPCVOID = Pointer;
  LPDWORD = ^DWORD;
  HLocal  = THandle;
  PStr    = PChar;
  LPStr   = PChar;
  PLPSTR  = ^LPSTR;
  PLPWSTR = ^LPWSTR;

  PRTLCriticalSection = ^TRTLCriticalSection;
  TRTLCriticalSection = packed record
    DebugInfo: Pointer;
    LockCount: Longint;
    RecursionCount: Longint;
    OwningThread: THandle;
    LockSemaphore: THandle;
    SpinCount: ULONG_PTR;
  end;


{objpash.inc}

type
  PGuid = ^TGuid;
  TGuid = record
  end;

  PVarRec = ^TVarRec;
  TVarRec = record
  end;

  IUnknown = interface
  end;

  IInterface = IUnknown;


{$I setjumph.inc}


var
  ExitCode: Longint = 0;
  IsLibrary: Boolean;
  HInstance: THandle;
  DllReason: Longint;


type
  TDLL_Entry_Hook = procedure;

const
  Dll_Process_Detach_Hook: TDLL_Entry_Hook = nil;


  procedure Move(const Source; var Dest; Count: SizeInt);
  procedure FillChar(var Dest; Count: SizeInt; Value: AnsiChar);


implementation


function GetModuleHandle(lpModuleName: PChar): THandle; stdcall;
  external 'kernel32.dll' name 'GetModuleHandleA';
procedure ExitProcess(uExitCode: UINT); stdcall;
  external 'kernel32.dll' name 'ExitProcess';


procedure PascalMain; stdcall; external name 'PASCALMAIN';
procedure FPC_Do_Exit; stdcall; external name 'FPC_DO_EXIT';


procedure FPC_InitializeUnits; [public, alias: 'FPC_INITIALIZEUNITS'];
begin
end;

procedure FPC_LibInitializeUnits; [public, alias: 'FPC_LIBINITIALIZEUNITS'];
begin
end;


procedure Exe_Entry; [public, alias: '_FPC_EXE_Entry'];
begin
  IsLibrary := False;
  HInstance := GetModuleHandle(nil);
  PascalMain;
end;


{$I setjump.inc}

const
  DLL_PROCESS_ATTACH = 1;
  DLL_THREAD_ATTACH = 2;
  DLL_PROCESS_DETACH = 0;
  DLL_THREAD_DETACH = 3;
  DLLExitOK: Boolean = True;

var
  DllBuf: Jmp_buf;

procedure ExitDLL(ExitCode: Longint);
begin
  DLLExitOK := (ExitCode = 0);
  LongJmp(DllBuf, 1);
end;

function Dll_Entry: LongBool; [public, alias: '_FPC_DLL_Entry'];
begin
  IsLibrary := True;
  Dll_Entry := True;

  case DllReason of
    DLL_PROCESS_ATTACH:
    begin
      if (SetJmp(DllBuf) = 0) then
        PascalMain
      else
        Dll_Entry := DLLExitOK;
    end;

    DLL_PROCESS_DETACH :
    begin
      if (SetJmp(DllBuf) = 0) then
        FPC_Do_Exit;

      if Assigned(Dll_Process_Detach_Hook) then
        Dll_Process_Detach_Hook;
    end;
  end;
end;



procedure _FPC_WinMainCRTStartup; stdcall; public name '_WinMainCRTStartup';
begin
  Exe_Entry;
end;

procedure _FPC_DLLWinMainCRTStartup(_HInstance: THandle;
  _DllReason, _DllParam: Longint); stdcall; public name '_DLLWinMainCRTStartup';
begin
  HInstance := _HInstance;
  DllReason := _DllReason;
  DLL_Entry;
end;

procedure Do_Exit; [public, alias: 'FPC_DO_EXIT'];
begin
  if IsLibrary then
    ExitDLL(ExitCode)
  else
    ExitProcess(ExitCode);
end;



procedure MoveMemory(Dest: PVOID; Source: PVOID; Count: SIZE_T); stdcall;
  external 'ntdll.dll' name 'RtlMoveMemory';
procedure FillMemory(Dest: PVOID; Count: SIZE_T; Fill: Byte); stdcall;
  external 'ntdll.dll' name 'RtlFillMemory';

procedure Move(const Source; var Dest; Count: SizeInt);
begin
  MoveMemory(@Dest, @Source, Count);
end;

procedure FillChar(var Dest; Count: SizeInt; Value: AnsiChar);
begin
  FillMemory(@Dest, Count, Byte(Value));
end;


end.

Код DLL:

Код: Выделить всё
library dll;

uses
  Windows,
  Messages;

var
  FileMapping: THandle = 0;
  MappingData: PLongint = nil;

procedure DoProcessAttach;
begin
  FileMapping := CreateFileMapping(INVALID_HANDLE_VALUE,
    nil, PAGE_READWRITE, 0, SizeOf(Longint), 'sdasdasd');

  if (FileMapping = 0) then
    ShowLastErrorMessage('FileMapping');

  if (FileMapping <> 0) then
    MappingData := MapViewOfFile(FileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);

  if (MappingData = nil) then
    ShowLastErrorMessage('MapViewOfFile');
end;

procedure DoProcessDetach;
begin
  if (FileMapping <> 0) then
  begin
    if Assigned(MappingData) then
      UnmapViewOfFile(MappingData);

    CloseHandle(FileMapping);
  end;
end;

begin
  Dll_Process_Detach_Hook := @DoProcessDetach;
  DoProcessAttach;
end.

Этот код работает в Win32 и Win64. Но после добавления в DoProcessAttach пары локальных переменных:

Код: Выделить всё
procedure DoProcessAttach;
var
  VersionInfo: TOSVersionInfo;
  SecurityAttributes: TSecurityAttributes;
begin
  FileMapping := CreateFileMapping(INVALID_HANDLE_VALUE,
    nil, PAGE_READWRITE, 0, SizeOf(Longint), 'sdasdasd');

  if (FileMapping = 0) then
    ShowLastErrorMessage('FileMapping');

  if (FileMapping <> 0) then
    MappingData := MapViewOfFile(FileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);

  if (MappingData = nil) then
    ShowLastErrorMessage('MapViewOfFile');
end;

MapViewOfFile начинает возвращать nil с ошибкой "Access denied". Глюк возникает только в Win64. Даже гипотез никаких нет - как добавление неиспользуемых локальных переменных может повлиять на MapViewOfFile? С одной стороны явный баг FPC, который должен игнорировать несипользуемые переменные, с другой - их все-таки испольовать потом потребуется и баг не исчезнет :) Может кто сталкивался с подобным или имеет опыт более правильной кастрации RTL для DLL?
TimK
новенький
 
Сообщения: 16
Зарегистрирован: 13.01.2010 06:26:49

Re: Минимальная RTL. Проблемы с DLL

Сообщение coyot.rush » 11.02.2010 17:55:13

1)Возможно ошибки с типами данных. типо под win32 работает и integer и int64 , а под win64 только int64.
2)Нечто подобное встречалось в delphi глюк заключался в том что если имена переменых совпадают с именами в других модулях (входящих в комплект среды). то возникают "чудеса в решете"
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Минимальная RTL. Проблемы с DLL

Сообщение TimK » 11.02.2010 18:06:12

coyot.rush писал(а):1)Возможно ошибки с типами данных. типо под win32 работает и integer и int64 , а под win64 только int64.
2)Нечто подобное встречалось в delphi глюк заключался в том что если имена переменых совпадают с именами в других модулях (входящих в комплект среды). то возникают "чудеса в решете"


Типы определены верно и только один раз, в Windows. Если их испольование вынести в отдельную функцию и вызывать ее из DoProcessAttach - все работает. Если все делать в DoProcessAttach - нет.
TimK
новенький
 
Сообщения: 16
Зарегистрирован: 13.01.2010 06:26:49

Re: Минимальная RTL. Проблемы с DLL

Сообщение coyot.rush » 11.02.2010 18:18:46

попробуй поищи VersionInfo в исходниках fpc у меня 14 совпадений :!: версия 2.4.0
возможно 2) вариант
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Минимальная RTL. Проблемы с DLL

Сообщение TimK » 11.02.2010 18:25:13

coyot.rush писал(а):попробуй поищи VersionInfo в исходниках fpc у меня 14 совпадений :!: версия 2.4.0
возможно 2) вариант


Не, отпадает... Юзается правильная декларация. TOSVersionInfo только одна, в struct.inc. И потом так работает (TOSVersionInfo и TSecurityAttributes в отдельной функции):

Код: Выделить всё
function FakeFunc: Boolean;
var
  VersionInfo: TOSVersionInfo;
  SecurityAttributes: TSecurityAttributes;
begin
  FakeFunc := True;
end;

procedure DoProcessAttach;
begin
  if FakeFunc then
    FileMapping := CreateFileMapping(INVALID_HANDLE_VALUE,
      nil, PAGE_READWRITE, 0, SizeOf(Longint), 'sdasdasd');

  if (FileMapping = 0) then
    ShowLastErrorMessage('FileMapping');

  if (FileMapping <> 0) then
    MappingData := MapViewOfFile(FileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);

  if (MappingData = nil) then
    ShowLastErrorMessage('MapViewOfFile');
end;


А так нет:
Код: Выделить всё
procedure DoProcessAttach;
var
  VersionInfo: TOSVersionInfo;
  SecurityAttributes: TSecurityAttributes;
begin
  FileMapping := CreateFileMapping(INVALID_HANDLE_VALUE,
    nil, PAGE_READWRITE, 0, SizeOf(Longint), 'sdasdasd');

  if (FileMapping = 0) then
    ShowLastErrorMessage('FileMapping');

  if (FileMapping <> 0) then
    MappingData := MapViewOfFile(FileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);

  if (MappingData = nil) then
    ShowLastErrorMessage('MapViewOfFile');
end;


Добавлено спустя 5 минут 37 секунд:
И потом... Если закомментарить что-либо одно, или VersionInfo или SecurityAttributes, то начинает работать. Если оставить обе - нет :)
TimK
новенький
 
Сообщения: 16
Зарегистрирован: 13.01.2010 06:26:49

Re: Минимальная RTL. Проблемы с DLL

Сообщение coyot.rush » 11.02.2010 18:37:33

В том и беда что по теории юзаеться одна деклорация а на практике подключаеться каойнибудь JwaWinVer.pas :shock:
1)Имхо попроюуй Ollydbg посмотри за Access denied. судя по всему непрвильный дескриптор для отображения файла или
2) траблы с правами FILE_MAP_ALL_ACCESS полный доступ :!: может антивирь мозг выносит. ось случаем не семерка :?:

Добавлено спустя 4 минуты 15 секунд:
И потом... Если закомментарить что-либо одно, или VersionInfo или SecurityAttributes, то начинает работать. Если оставить обе - нет

а если переименовать VersionInfo>_Version0001Info_ :idea:
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Минимальная RTL. Проблемы с DLL

Сообщение TimK » 11.02.2010 19:05:41

В том и беда что по теории юзаеться одна деклорация а на практике подключаеться каойнибудь JwaWinVer.pas :shock:

Да нет же :) Только Windows и Messages в uses.

Имхо попроюуй Ollydbg посмотри за Access denied. судя по всему непрвильный дескриптор для отображения файла

CreateFileMapping отрабатывает нормально, дескриптор не нулевой.

траблы с правами FILE_MAP_ALL_ACCESS полный доступ :!: может антивирь мозг выносит. ось случаем не семерка

Файл с такими правами и создается. И открывается, пока в локальные переменные не добавляется вышеуказанное :shock:. Ось ХП, антивирусов нет.

а если переименовать VersionInfo>_Version0001Info_

Не помогло :)
TimK
новенький
 
Сообщения: 16
Зарегистрирован: 13.01.2010 06:26:49

Re: Минимальная RTL. Проблемы с DLL

Сообщение coyot.rush » 11.02.2010 19:20:45

Остаеться только сравнение дизасеммблерных листингов до и после включения переменных. :?

Может объявить структуры заново
Код: Выделить всё
type
  _OSVERSIONINFOW = record
    dwOSVersionInfoSize: ULONG;
    dwMajorVersion: ULONG;
    dwMinorVersion: ULONG;
    dwBuildNumber: ULONG;
    dwPlatformId: ULONG;
    szCSDVersion: array[0..127] of WCHAR; // Maintenance string for PSS usage
  end;
  OSVERSIONINFOW = _OSVERSIONINFOW;
  POSVERSIONINFOW = ^OSVERSIONINFOW;
  LPOSVERSIONINFOW = ^OSVERSIONINFOW;
  RTL_OSVERSIONINFOW = OSVERSIONINFOW;


взято из JwaNative

Добавлено спустя 4 минуты 29 секунд:
Вроде нета структура :?
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Минимальная RTL. Проблемы с DLL

Сообщение TimK » 11.02.2010 19:41:28

Отличия есть, да... Выделил жирным:

С переменными:
.386p
DGROUP GROUP _BSS,_DATA
ASSUME CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP
_CODE SEGMENT PARA PUBLIC USE32 'CODE'
ALIGN 16
PUBLIC P$DLL_DOPROCESSATTACH
P$DLL_DOPROCESSATTACH:
push rbp
mov rbp,rsp
sub rsp,272
mov qword ptr [rbp-184],rbx
mov ebx,4
mov rax,offset _$DLL$_Ld3
mov r9d,0
mov r8d,4
mov rdx,0
mov rcx,-1
mov dword ptr [rsp+32],ebx
mov qword ptr [rsp+40],rax
call CreateFileMappingA
mov qword ptr [TC_P$DLL_FILEMAPPING+rip],rax
mov rax,qword ptr [TC_P$DLL_FILEMAPPING+rip]
test rax,rax
jne @@j32
mov rcx,offset _$DLL$_Ld4
call MSGBOX_SHOWLASTERRORMESSAGE$PCHAR
@@j32:
mov rax,qword ptr [TC_P$DLL_FILEMAPPING+rip]
test rax,rax
je @@j36
mov eax,0
mov rcx,qword ptr [TC_P$DLL_FILEMAPPING+rip]
mov r9d,0
mov r8d,0
mov edx,983071
mov dword ptr [rsp+32],eax
call MapViewOfFile
mov qword ptr [TC_P$DLL_MAPPINGDATA+rip],rax
@@j36:
mov rax,qword ptr [TC_P$DLL_MAPPINGDATA+rip]
test rax,rax
jne @@j50
mov rcx,offset _$DLL$_Ld5
call MSGBOX_SHOWLASTERRORMESSAGE$PCHAR
@@j50:
mov rbx,qword ptr [rbp-184]
leave
ret
_CODE ENDS

END


Без них :shock::
.386p
DGROUP GROUP _BSS,_DATA
ASSUME CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP
_CODE SEGMENT PARA PUBLIC USE32 'CODE'
ALIGN 16
PUBLIC P$DLL_DOPROCESSATTACH
P$DLL_DOPROCESSATTACH:
push rbp
mov rbp,rsp
sub rsp,96
mov qword ptr [rbp-8],rbx
mov ebx,4
mov rax,offset _$DLL$_Ld3
mov r9d,0
mov r8d,4
mov rdx,0
mov rcx,-1
mov dword ptr [rsp+32],ebx
mov qword ptr [rsp+40],rax
call CreateFileMappingA
mov qword ptr [TC_P$DLL_FILEMAPPING+rip],rax
mov rax,qword ptr [TC_P$DLL_FILEMAPPING+rip]
test rax,rax
jne @@j32
mov rcx,offset _$DLL$_Ld4
call MSGBOX_SHOWLASTERRORMESSAGE$PCHAR
@@j32:
mov rax,qword ptr [TC_P$DLL_FILEMAPPING+rip]
test rax,rax
je @@j36
mov eax,0
mov rcx,qword ptr [TC_P$DLL_FILEMAPPING+rip]
mov r9d,0
mov r8d,0
mov edx,983071
mov dword ptr [rsp+32],eax
call MapViewOfFile
mov qword ptr [TC_P$DLL_MAPPINGDATA+rip],rax
@@j36:
mov rax,qword ptr [TC_P$DLL_MAPPINGDATA+rip]
test rax,rax
jne @@j50
mov rcx,offset _$DLL$_Ld5
call MSGBOX_SHOWLASTERRORMESSAGE$PCHAR
@@j50:
mov rbx,qword ptr [rbp-8]
leave
ret
_CODE ENDS

END


Только непонятно, какого они есть и что с ними делать? :)
TimK
новенький
 
Сообщения: 16
Зарегистрирован: 13.01.2010 06:26:49

Re: Минимальная RTL. Проблемы с DLL

Сообщение coyot.rush » 11.02.2010 20:24:07

выделяеться разное количество памяти под перменные.
Код: Выделить всё
sub rsp,272

видимо fpc не включает смартлинк :o и в функцию CreateFileMappingA попадают не те данные.
видимо это баг компилятора :(
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Минимальная RTL. Проблемы с DLL

Сообщение TimK » 11.02.2010 20:40:10

Ну насчет смартлинка не знаю, но неиспользуемые переменные точно на генерируемый код влиять не должны. Проверил с оригинальной RTL - те же различия. В Win32 тоже. С другой стороны такой баг уже бы вылез везде-вокруг :)
TimK
новенький
 
Сообщения: 16
Зарегистрирован: 13.01.2010 06:26:49

Re: Минимальная RTL. Проблемы с DLL

Сообщение coyot.rush » 11.02.2010 20:49:06

Как я понял стоит задача по написанию маленькой dll, используй kol. лично сам юзал kol+ mck на lazarus пустое окошко 45 kb :!: :!: :!: должно сработать и с dll :D
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Минимальная RTL. Проблемы с DLL

Сообщение Sergei I. Gorelkin » 11.02.2010 20:59:38

Я, честно говоря, не совсем понимаю, что там творится: ну вычли из стека чуть побольше - это неоптимально, но вроде как работать должно по-прежнему. Или же причина в том, что Win64 предъявляет определенные требования к выравниванию стека, а Win32 - нет?

Это явление удается воспроизвести с оригинальным модулем System?
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Минимальная RTL. Проблемы с DLL

Сообщение TimK » 11.02.2010 21:00:48

coyot.rush писал(а):Как я понял стоит задача по написанию маленькой dll, используй kol. лично сам юзал kol+ mck на lazarus пустое окошко 45 kb :!: :!: :!: должно сработать и с dll :D


Ну она и так маленькая, 4К. KOL не нужен - код состоит из 10 вызовов WinAPI. Вот бы еще с глюками разобраться :)
TimK
новенький
 
Сообщения: 16
Зарегистрирован: 13.01.2010 06:26:49

Re: Минимальная RTL. Проблемы с DLL

Сообщение coyot.rush » 11.02.2010 21:04:15

Если пишешь для себя посмотри здесь Кодим Dll во сне и на яву или таинство встраивания кода http://www.cracklab.ru/art/?action=view&id=367
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru