Recent

Author Topic: fb_embedded2.pas  (Read 5370 times)

tatamata

  • Hero Member
  • *****
  • Posts: 787
    • ZMSQL - SQL enhanced in-memory database
fb_embedded2.pas
« on: September 14, 2007, 03:18:44 pm »
If someone has enogh time and will, it would be great to convert this unit  "fb_embedded2.pas" that embedds Firebird into .exe:

Code: [Select]
{*
 * PROGRAM: Embed Firebird into EXE
 * MODULE: fb_embedded2.pas
 * DESCRIPTION: Embed Firebird into Application EXE
 *                and read lib from memory stream
 *
 *  The contents of this file are subject to the Initial
 *  Developer's Public License Version 1.0 (the "License");
 *  you may not use this file except in compliance with the
 *  License. You may obtain a copy of the License at
 *  http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
 *
 *  Software distributed under the License is distributed AS IS,
 *  WITHOUT WARRANTY OF ANY KIND, either express or implied.
 *  See the License for the specific language governing rights
 *  and limitations under the License.
 *
 *  The Original Code was created by Fikret Hasovic and Samir Ribic
 *
 *  Copyright (c) 2005 Fikret Hasovic <fikret.hasovic@gmail.com>
 *  and all contributors signed below.
 *
 *  All Rights Reserved.
 *  Contributor(s): Samir Ribic.
 *
 *
 *}

unit fb_embedded2;
{$R FB1.5_Embedded.RES}
interface
procedure redirect;
procedure unredirect;
implementation
uses windows, sysutils, classes, tlhelp32;
   {+++++++++++++++++++++++++++++++++++
    ***  Dll EntryPoint Definition  ***
    -----------------------------------}


   {++++++++++++++++++++++++++++++++++++++
    ***  MemoryModule Type Definition  ***
    --------------------------------------}
type
  PBTMemoryModule = ^TBTMemoryModule;
  _BT_MEMORY_MODULE = packed record
    headers: PImageNtHeaders;
    codeBase: Pointer;
    modules: Pointer;
    numModules: integer;
    initialized: boolean;
  end;
{$EXTERNALSYM _BT_MEMORY_MODULE}
  TBTMemoryModule = _BT_MEMORY_MODULE;
  BT_MEMORY_MODULE = _BT_MEMORY_MODULE;
{$EXTERNALSYM BT_MEMORY_MODULE}


   {++++++++++++++++++++++++++++++++++++++++++++++++++
    ***  Memory DLL loading functions Declaration  ***
    --------------------------------------------------}

  TDllEntryProc = function(hinstdll: THandle; fdwReason: DWORD; lpReserved: Pointer): BOOL; stdcall;


   {++++++++++++++++++++++++++++++++++++++++
    ***  Missing Windows API Definitions ***
    ----------------------------------------}

  PImageBaseRelocation = ^TImageBaseRelocation;
  _IMAGE_BASE_RELOCATION = packed record
    VirtualAddress: DWORD;
    SizeOfBlock: DWORD;
  end;
{$EXTERNALSYM _IMAGE_BASE_RELOCATION}
  TImageBaseRelocation = _IMAGE_BASE_RELOCATION;
  IMAGE_BASE_RELOCATION = _IMAGE_BASE_RELOCATION;
{$EXTERNALSYM IMAGE_BASE_RELOCATION}

  PImageImportDescriptor = ^TImageImportDescriptor;
  _IMAGE_IMPORT_DESCRIPTOR = packed record
    OriginalFirstThunk: DWORD;
    TimeDateStamp: DWORD;
    ForwarderChain: DWORD;
    Name: DWORD;
    FirstThunk: DWORD;
  end;
{$EXTERNALSYM _IMAGE_IMPORT_DESCRIPTOR}
  TImageImportDescriptor = _IMAGE_IMPORT_DESCRIPTOR;
  IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR;
{$EXTERNALSYM IMAGE_IMPORT_DESCRIPTOR}

  PImageImportByName = ^TImageImportByName;
  _IMAGE_IMPORT_BY_NAME = packed record
    Hint: Word;
    Name: array[0..255] of Byte; // original: "Name: array [0..0] of Byte;"
  end;
{$EXTERNALSYM _IMAGE_IMPORT_BY_NAME}
  TImageImportByName = _IMAGE_IMPORT_BY_NAME;
  IMAGE_IMPORT_BY_NAME = _IMAGE_IMPORT_BY_NAME;
{$EXTERNALSYM IMAGE_IMPORT_BY_NAME}

const
  IMAGE_SIZEOF_BASE_RELOCATION = 8;
{$EXTERNALSYM IMAGE_SIZEOF_BASE_RELOCATION}
  IMAGE_REL_BASED_HIGHLOW = 3;
{$EXTERNALSYM IMAGE_REL_BASED_HIGHLOW}
  IMAGE_ORDINAL_FLAG32 = DWORD($80000000);
{$EXTERNALSYM IMAGE_ORDINAL_FLAG32}

var
  lastErrStr: string;


   {+++++++++++++++++++++++++++++++++++++++++++++++++++++
    ***  Memory DLL loading functions Implementation  ***
    -----------------------------------------------------}

function BTMemoryGetLastError: string; stdcall;
begin
  Result := lastErrStr;
end;

function GetFieldOffset(const Struc; const Field): Cardinal; stdcall;
begin
  Result := Cardinal(@Field) - Cardinal(@Struc);
end;

function GetImageFirstSection(NtHeader: PImageNtHeaders): PImageSectionHeader; stdcall;
begin
  Result := PImageSectionHeader(Cardinal(NtHeader) +
    GetFieldOffset(NtHeader^, NtHeader^.OptionalHeader) +
    NtHeader^.FileHeader.SizeOfOptionalHeader);
end;

function GetHeaderDictionary(f_module: PBTMemoryModule; f_idx: integer): PImageDataDirectory; stdcall;
begin
  Result := PImageDataDirectory(@(f_module.headers.OptionalHeader.DataDirectory[f_idx]));
end;

function GetImageOrdinal(Ordinal: DWORD): Word; stdcall;
begin
  Result := Ordinal and $FFFF;
end;

function GetImageSnapByOrdinal(Ordinal: DWORD): Boolean; stdcall;
begin
  Result := ((Ordinal and IMAGE_ORDINAL_FLAG32) <> 0);
end;

procedure CopySections(const f_data: Pointer; const f_old_headers: TImageNtHeaders; f_module: PBTMemoryModule); stdcall;
var
  l_size, i: integer;
  l_codebase: Pointer;
  l_dest: Pointer;
  l_section: PImageSectionHeader;
begin
  l_codebase := f_module.codeBase;
  l_section := GetImageFirstSection(f_module.headers);
  for i := 0 to f_module.headers.FileHeader.NumberOfSections - 1 do begin
    // section doesn't contain data in the dll itself, but may define
    // uninitialized data
    if (l_section.SizeOfRawData = 0) then begin
      l_size := f_old_headers.OptionalHeader.SectionAlignment;
      if l_size > 0 then begin
        l_dest := VirtualAlloc(Pointer(Cardinal(l_codebase) + l_section.VirtualAddress), l_size, MEM_COMMIT, PAGE_READWRITE);
        l_section.Misc.PhysicalAddress := cardinal(l_dest);
        ZeroMemory(l_dest, l_size);
      end;
      inc(longword(l_section), sizeof(TImageSectionHeader));
      // Continue with the nex loop
      Continue;
    end;
    // commit memory block and copy data from dll
    l_dest := VirtualAlloc(Pointer(Cardinal(l_codebase) + l_section.VirtualAddress), l_section.SizeOfRawData, MEM_COMMIT, PAGE_READWRITE);
    CopyMemory(l_dest, Pointer(longword(f_data) + l_section.PointerToRawData), l_section.SizeOfRawData);
    l_section.Misc.PhysicalAddress := cardinal(l_dest);
    // IMAGE_SIZEOF_SECTION_HEADER
    inc(longword(l_section), sizeof(TImageSectionHeader));
  end;
end;

procedure PerformBaseRelocation(f_module: PBTMemoryModule; f_delta: Cardinal); stdcall;
var
  l_i: Cardinal;
  l_codebase: Pointer;
  l_directory: PImageDataDirectory;
  l_relocation: PImageBaseRelocation;
  l_dest: Pointer;
  l_relInfo: ^Word;
  l_patchAddrHL: ^DWord;
  l_type, l_offset: integer;
begin
  l_codebase := f_module.codeBase;
  l_directory := GetHeaderDictionary(f_module, IMAGE_DIRECTORY_ENTRY_BASERELOC);
  if l_directory.Size > 0 then begin
    l_relocation := PImageBaseRelocation(Cardinal(l_codebase) + l_directory.VirtualAddress);
    while l_relocation.VirtualAddress > 0 do begin
      l_dest := Pointer((Cardinal(l_codebase) + l_relocation.VirtualAddress));
      l_relInfo := Pointer(Cardinal(l_relocation) + IMAGE_SIZEOF_BASE_RELOCATION);
      for l_i := 0 to (trunc(((l_relocation.SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / 2)) - 1) do begin
        // the upper 4 bits define the type of relocation
        l_type := (l_relInfo^ shr 12);
        // the lower 12 bits define the offset
        l_offset := l_relInfo^ and $FFF;
        //showmessage(inttostr(l_relInfo^));
        if l_type = IMAGE_REL_BASED_HIGHLOW then begin
          // change complete 32 bit address
          l_patchAddrHL := Pointer(Cardinal(l_dest) + Cardinal(l_offset));
          l_patchAddrHL^ := l_patchAddrHL^ + f_delta;
        end;
        inc(l_relInfo);
      end;
      l_relocation := Pointer(cardinal(l_relocation) + l_relocation.SizeOfBlock);
    end;
  end;
end;

function BuildImportTable(f_module: PBTMemoryModule): boolean; stdcall;
var
  l_codeBase: Pointer;
  l_directory: PImageDataDirectory;
  l_importDesc: PImageImportDescriptor;
  l_thunkRef, l_funcRef: ^DWORD;
  l_handle: HMODULE;
  l_temp: integer;
  l_thunkData: TImageImportByName;
begin
  Result := true;
  l_codeBase := f_module.codeBase;
  l_directory := GetHeaderDictionary(f_module, IMAGE_DIRECTORY_ENTRY_IMPORT);
  if (l_directory.Size > 0) then begin
    l_importDesc := PImageImportDescriptor(Cardinal(l_codeBase) + l_directory.VirtualAddress);
    while (not IsBadReadPtr(l_importDesc, sizeof(TImageImportDescriptor))) and (l_importDesc.Name <> 0) do begin
      l_handle := LoadLibrary(PChar(Cardinal(l_codeBase) + l_importDesc.Name));
      if (l_handle = INVALID_HANDLE_VALUE) then begin
        lastErrStr := 'BuildImportTable: can''t load library: ' + PChar(Cardinal(l_codeBase) + l_importDesc.Name);
        Result := false;
        exit;
      end;
      // ReallocMemory crashes if "f_module.modules = nil"
      if f_module.modules = nil then
        f_module.modules := AllocMem(1);
      f_module.modules := ReallocMemory(f_module.modules, ((f_module.numModules + 1) * (sizeof(HMODULE))));
      if f_module.modules = nil then begin
        lastErrStr := 'BuildImportTable: ReallocMemory failed';
        result := false;
        exit;
      end;
      // module->modules[module->numModules++] = handle;
      l_temp := (sizeof(cardinal) * (f_module.numModules));
      inc(Cardinal(f_module.modules), l_temp);
      cardinal(f_module.modules^) := l_handle;
      dec(Cardinal(f_module.modules), l_temp);
      f_module.numModules := f_module.numModules + 1;
      if l_importDesc.OriginalFirstThunk <> 0 then begin
        l_thunkRef := Pointer(Cardinal(l_codeBase) + l_importDesc.OriginalFirstThunk);
        l_funcRef := Pointer(Cardinal(l_codeBase) + l_importDesc.FirstThunk);
      end else begin
        // no hint table
        l_thunkRef := Pointer(Cardinal(l_codeBase) + l_importDesc.FirstThunk);
        l_funcRef := Pointer(Cardinal(l_codeBase) + l_importDesc.FirstThunk);
      end;
      while l_thunkRef^ <> 0 do begin
        if GetImageSnapByOrdinal(l_thunkRef^) then
          l_funcRef^ := Cardinal(GetProcAddress(l_handle, PChar(GetImageOrdinal(l_thunkRef^))))
        else begin
          CopyMemory(@l_thunkData, Pointer(Cardinal(l_codeBase) + l_thunkRef^), sizeof(TImageImportByName));
          l_funcRef^ := Cardinal(GetProcAddress(l_handle, PChar(@(l_thunkData.Name))));
        end;
        if l_funcRef^ = 0 then begin
          lastErrStr := 'BuildImportTable: GetProcAddress failed';
          result := false;
          break;
        end;
        inc(l_funcRef);
        inc(l_thunkRef);
      end;
      inc(longword(l_importDesc), sizeof(TImageImportDescriptor));
    end;
  end;
end;

function GetSectionProtection(SC: cardinal): cardinal; stdcall;
//SC – ImageSectionHeader.Characteristics
begin
  result := 0;
  if (SC and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then
    result := result or PAGE_NOCACHE;
  // E - Execute, R – Read , W – Write
  if (SC and IMAGE_SCN_MEM_EXECUTE) <> 0 //E ?
    then if (SC and IMAGE_SCN_MEM_READ) <> 0 //ER ?
    then if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //ERW ?
      then result := result or PAGE_EXECUTE_READWRITE
      else result := result or PAGE_EXECUTE_READ
    else if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //EW?
      then result := result or PAGE_EXECUTE_WRITECOPY
    else result := result or PAGE_EXECUTE
  else if (SC and IMAGE_SCN_MEM_READ) <> 0 // R?
    then if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //RW?
    then result := result or PAGE_READWRITE
    else result := result or PAGE_READONLY
  else if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //W?
    then result := result or PAGE_WRITECOPY
  else result := result or PAGE_NOACCESS;
end;

procedure FinalizeSections(f_module: PBTMemoryModule); stdcall;
var
  l_i: integer;
  l_section: PImageSectionHeader;
  l_protect, l_oldProtect, l_size: Cardinal;
begin
  l_section := GetImageFirstSection(f_module.headers);
  for l_i := 0 to f_module.headers.FileHeader.NumberOfSections - 1 do begin

    if (l_section.Characteristics and IMAGE_SCN_MEM_DISCARDABLE) <> 0 then begin
      // section is not needed any more and can safely be freed
      VirtualFree(Pointer(l_section.Misc.PhysicalAddress), l_section.SizeOfRawData, MEM_DECOMMIT);
      inc(longword(l_section), sizeof(TImageSectionHeader));
      continue;
    end;

    l_protect := GetSectionProtection(l_section.Characteristics);
    if (l_section.Characteristics and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then
      l_protect := (l_protect or PAGE_NOCACHE);

    // determine size of region
    l_size := l_section.SizeOfRawData;
    if l_size = 0 then begin
      if (l_section.Characteristics and IMAGE_SCN_CNT_INITIALIZED_DATA) <> 0 then begin
        l_size := f_module.headers.OptionalHeader.SizeOfInitializedData;
      end else begin
        if (l_section.Characteristics and IMAGE_SCN_CNT_UNINITIALIZED_DATA) <> 0 then
          l_size := f_module.headers.OptionalHeader.SizeOfUninitializedData;
      end;
      if l_size > 0 then begin
        if not VirtualProtect(Pointer(l_section.Misc.PhysicalAddress), l_section.SizeOfRawData, l_protect, @l_oldProtect) then begin
          lastErrStr := 'FinalizeSections: VirtualProtect failed';
          exit;
        end;
      end;
    end;
    inc(longword(l_section), sizeof(TImageSectionHeader));
  end;
end;

procedure BTMemoryFreeLibrary(var f_module: PBTMemoryModule); stdcall;
var
  l_module: PBTMemoryModule;
  l_i: integer;
  l_temp: integer;
  l_DllEntry: TDllEntryProc;
begin
  l_module := f_module;
  if l_module <> nil then begin
    if l_module.initialized then begin
      @l_DllEntry := Pointer(Cardinal(l_module.codeBase) + l_module.headers.OptionalHeader.AddressOfEntryPoint);
      l_DllEntry(Cardinal(l_module.codeBase), DLL_PROCESS_DETACH, nil);
      l_module.initialized := false;
      // free previously opened libraries
      for l_i := 0 to l_module.numModules - 1 do begin
        l_temp := (sizeof(cardinal) * (l_i));
        inc(Cardinal(l_module.modules), l_temp);
        if Cardinal(f_module.modules^) <> INVALID_HANDLE_VALUE then
          FreeLibrary(Cardinal(f_module.modules^));
        dec(Cardinal(l_module.modules), l_temp);
      end;
      FreeMemory(l_module.modules);
      if l_module.codeBase <> nil then
        // release memory of library
        VirtualFree(l_module.codeBase, 0, MEM_RELEASE);
      HeapFree(GetProcessHeap(), 0, f_module);
      Pointer(f_module) := nil;
    end;
  end;
end;

function BTMemoryLoadLibary(var f_data: Pointer; const f_size: int64): PBTMemoryModule; stdcall;
var
  l_result: PBTMemoryModule;
  l_dos_header: TImageDosHeader;
  l_old_header: TImageNtHeaders;
  l_code, l_headers: Pointer;
  l_locationdelta: Cardinal;
  l_DllEntry: TDllEntryProc;
  l_successfull: boolean;
begin
  l_result := nil;
  Result := nil;
  try
    CopyMemory(@l_dos_header, f_data, sizeof(_IMAGE_DOS_HEADER));
    if (l_dos_header.e_magic <> IMAGE_DOS_SIGNATURE) then begin
      lastErrStr := 'BTMemoryLoadLibary: dll dos header is not valid';
      exit;
    end;
    CopyMemory(@l_old_header, pointer(longint(f_data) + l_dos_header._lfanew), sizeof(_IMAGE_NT_HEADERS));
    if l_old_header.Signature <> IMAGE_NT_SIGNATURE then begin
      lastErrStr := 'BTMemoryLoadLibary: IMAGE_NT_SIGNATURE is not valid';
      exit;
    end;
    // reserve memory for image of library
    l_code := VirtualAlloc(Pointer(l_old_header.OptionalHeader.ImageBase), l_old_header.OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
    if l_code = nil then
        // try to allocate memory at arbitrary position
      l_code := VirtualAlloc(nil, l_old_header.OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
    if l_code = nil then begin
      lastErrStr := 'BTMemoryLoadLibary: VirtualAlloc failed';
      exit;
    end;
    // alloc space for the result record
    l_result := PBTMemoryModule(HeapAlloc(GetProcessHeap(), 0, sizeof(TBTMemoryModule)));
    l_result.codeBase := l_code;
    l_result.numModules := 0;
    l_result.modules := nil;
    l_result.initialized := false;
    // xy: is it correct to commit the complete memory region at once?
    //     calling DllEntry raises an exception if we don't...
    VirtualAlloc(l_code, l_old_header.OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE);
    // commit memory for headers
    l_headers := VirtualAlloc(l_code, l_old_header.OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE);
    // copy PE header to code
    CopyMemory(l_headers, f_data, (Cardinal(l_dos_header._lfanew) + l_old_header.OptionalHeader.SizeOfHeaders));
    l_result.headers := PImageNtHeaders(longint(l_headers) + l_dos_header._lfanew);
    // update position
    l_result.headers.OptionalHeader.ImageBase := cardinal(l_code);
    // copy sections from DLL file block to new memory location
    CopySections(f_data, l_old_header, l_result);
    // adjust base address of imported data
    l_locationdelta := Cardinal(Cardinal(l_code) - l_old_header.OptionalHeader.ImageBase);
    if l_locationdelta <> 0 then
      PerformBaseRelocation(l_result, l_locationdelta);
    // load required dlls and adjust function table of imports
    if not BuildImportTable(l_result) then begin
      lastErrStr := lastErrStr + ' BTMemoryLoadLibary: BuildImportTable failed';
      Abort;
    end;
    // mark memory pages depending on section headers and release
    // sections that are marked as "discardable"
    FinalizeSections(l_result);
    // get entry point of loaded library
    if (l_result.headers.OptionalHeader.AddressOfEntryPoint) <> 0 then begin
      @l_DllEntry := Pointer(Cardinal(l_code) + l_result.headers.OptionalHeader.AddressOfEntryPoint);
      if @l_DllEntry = nil then begin
        lastErrStr := 'BTMemoryLoadLibary: Get DLLEntyPoint failed';
        Abort;
      end;
      l_successfull := l_DllEntry(Cardinal(l_code), DLL_PROCESS_ATTACH, nil);
      if not l_successfull then begin
        lastErrStr := 'BTMemoryLoadLibary: Can''t attach library';
        Abort;
      end;
      l_result.initialized := true;
    end;
  except
    BTMemoryFreeLibrary(l_result);
    exit;
  end;
  Result := l_result;
end;

function BTMemoryGetProcAddress(var f_module: PBTMemoryModule; const f_name: PChar): Pointer; stdcall;
var
  l_codeBase: Pointer;
  l_idx: integer;
  l_i: DWORD;
  l_nameRef: ^DWORD;
  l_ordinal: ^WORD;
  l_exports: PImageExportDirectory;
  l_directory: PImageDataDirectory;
  l_temp: ^DWORD;
begin
  Result := nil;
  l_codeBase := f_module.codeBase;
  l_idx := -1;
  l_directory := GetHeaderDictionary(f_module, IMAGE_DIRECTORY_ENTRY_EXPORT);
  if l_directory.Size = 0 then begin
    lastErrStr := 'BTMemoryGetProcAddress: no export table found';
    exit;
  end;
  l_exports := PImageExportDirectory(Cardinal(l_codeBase) + l_directory.VirtualAddress);
  if ((l_exports.NumberOfNames = 0) or (l_exports.NumberOfFunctions = 0)) then begin
    lastErrStr := 'BTMemoryGetProcAddress: DLL doesn''t export anything';
    exit;
  end;
  // search function name in list of exported names
  l_nameRef := Pointer(Cardinal(l_codeBase) + Cardinal(l_exports.AddressOfNames));
  l_ordinal := Pointer(Cardinal(l_codeBase) + Cardinal(l_exports.AddressOfNameOrdinals));
  for l_i := 0 to l_exports.NumberOfNames - 1 do begin
    if StrComp(f_name, PChar(Cardinal(l_codeBase) + l_nameRef^)) = 0 then begin
      l_idx := l_ordinal^;
      break;
    end;
    inc(l_nameRef);
    inc(l_ordinal);
  end;
  if (l_idx = -1) then begin
    lastErrStr := 'BTMemoryGetProcAddress: exported symbol not found';
    exit;
  end;
  if (Cardinal(l_idx) > l_exports.NumberOfFunctions - 1) then begin
    lastErrStr := 'BTMemoryGetProcAddress: name <-> ordinal number don''t match';
    exit;
  end;
  // AddressOfFunctions contains the RVAs to the "real" functions
  l_temp := Pointer(Cardinal(l_codeBase) + Cardinal(l_exports.AddressOfFunctions) + Cardinal((l_idx * 4)));
  Result := Pointer(Cardinal(l_codeBase) + l_temp^);
end;


const
  OP_eins = -1;
  OPnull = 0;
  OPeins = 1;
  OPzwei = 2;
  OPdrei = 3;
  OPvier = 4;
  OPfuenf = 5;
  OPsechs = 6;
  OPsieben = 7;
  OPacht = 8;
  OPneun = 9;
  OPzehn = 10;
  OPtable7 = 11; // table2 +1  (ok)
  OPtable2 = 12; //            (ok)
  OPtable5 = 15; //            (ok)
  OPtable6 = 16; // table2 +4  (ok)
  OPtableFF = 17; //            (ok)
  OPtableF7 = 18; //            (ok)
  OPtable8 = 19; //            (ok)
  OPtableFE = 20; //            (ok)
  OPtableDD = 21; //            (ok)
  OPtable0F = 22; //            (ok)
  OPtable = 23;
  OPtable3 = 24;

var firsttable: array[$00..$FF] of integer =

  (
  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f
    OPtable2, OPtable2, OPtable2, OPtable2, OPeins, OPvier, OPnull, OPnull, OPtable2, OPtable2, OPtable2, OPtable2, OPeins, OPvier, OPnull, OPtable0F,
    OPtable2, OPtable2, OPtable2, OPtable2, OPeins, OPvier, OPnull, OPnull, OPtable2, OPtable2, OPtable2, OPtable2, OPeins, OPvier, OPnull, OPnull,
    OPtable2, OPtable2, OPtable2, OPtable2, OPeins, OPvier, OPtable, OPnull, OPtable2, OPtable2, OPtable2, OPtable2, OPeins, OPvier, OPtable, OPnull,
    OPtable2, OPtable2, OPtable2, OPtable2, OPeins, OPvier, OPtable, OPnull, OPtable2, OPtable2, OPtable2, OPtable2, OPeins, OPvier, OPtable, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPtable2, OPtable2, OPtable, OPtable, OPtable, OPtable, OPvier, OPtable6, OPeins, OPtable7, OPnull, OPnull, OPnull, OPnull,
    OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins,
    OPtable7, OPtable6, OPtable7, OPtable7, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPsechs, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPvier, OPvier, OPvier, OPvier, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier,
    OPtable7, OPzwei, OPzwei, OPnull, OPtable2, OPtable2, OPtable7, OPtable6, OPvier, OPnull, OPzwei, OPnull, OPnull, OPeins, OPnull, OPnull,
    OPtable2, OPtable2, OPtable2, OPtable2, OPeins, OPeins, OPnull, OPnull, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtableDD, OPtable2, OPtable2,
    OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPvier, OPvier, OPsechs, OPeins, OPnull, OPnull, OPnull, OPnull,
    OPtable, OPnull, OPtable, OPtable, OPnull, OPnull, OPtable8, OPtableF7, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPtableFE, OPtableFF);


var thirdtable: array[$00..$FF] of integer =
  (
  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPvier, OPnull, OPnull);

var secondtable: array[$00..$FF] of integer =
  (
  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f
    OPnull, OPnull, OPnull, OPnull, OPtable3, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPtable3, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPtable3, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPtable3, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull);

var fftable: array[$00..$FF] of integer =
  (
  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins);

var f7table: array[$00..$FF] of integer =
  (
  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPacht, OPvier, OPvier, OPeins, OPeins, OPeins, OPeins, OPzwei, OPfuenf, OPeins, OPeins,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPvier, OPvier, OPvier, OPvier, OPsechs, OPfuenf, OPfuenf, OPfuenf, OPzwei, OPzwei, OPzwei, OPzwei, OPzwei, OPzwei, OPzwei, OPzwei,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPacht, OPacht, OPacht, OPacht, OPneun, OPacht, OPacht, OPacht, OPfuenf, OPfuenf, OPfuenf, OPfuenf, OPsechs, OPfuenf, OPfuenf, OPfuenf,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull);

var table8: array[$00..$FF] of integer =
  (
  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPfuenf, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPfuenf, OPeins, OPeins,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPzwei, OPzwei, OPzwei, OPzwei, OPdrei, OPzwei, OPzwei, OPzwei, OPzwei, OPzwei, OPzwei, OPzwei, OPdrei, OPzwei, OPzwei, OPzwei,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPfuenf, OPfuenf, OPfuenf, OPfuenf, OPsechs, OPfuenf, OPfuenf, OPfuenf, OPfuenf, OPfuenf, OPfuenf, OPfuenf, OPsechs, OPfuenf, OPfuenf, OPfuenf,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull);

var fetable: array[$00..$FF] of integer =
  (
  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins);

var ddtable: array[$00..$FF] of integer =
  (
  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPeins, OPvier, OPnull, OPnull,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPeins, OPzwei, OPeins, OPeins, OPeins,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPvier, OPvier, OPvier, OPvier, OPfuenf, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPfuenf, OPnull, OPvier, OPvier,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OP_eins, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OP_eins, OPnull, OPnull);

var table0F: array[$00..$FF] of integer =
  (
  // $0     $1      $2        $3      $4       $5      $6        $7       $8        $9      $a       $b       $c       $d       $e      $f
    OPtable2, OPtable2, OPtable2, OPtable2, OP_eins, OP_eins, OPnull, OP_eins, OPnull, OP_eins, OP_eins, OPnull, OP_eins, OPtable, OPnull, OPtable,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins, OP_eins,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier, OPvier,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull, OPnull,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2,
    OP_eins, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OPtable2, OP_eins);

function myInstructionLength(addr: pointer): integer; stdcall;
var anzahl: integer;
  fertig: boolean;
  b: ^byte;
  x: integer;
begin
  fertig := false;
  anzahl := 1;
  b := addr;
  x := firsttable[b^];
  repeat
    case x of
      -1..10:
        begin
          inc(anzahl, x);
          fertig := true;
        end;
      OPtable:
        begin
          inc(anzahl);
          b := pointer(integer(b) + 1);
          x := firsttable[b^];
        end;
      OPtable2:
        begin
          inc(anzahl);
          b := pointer(integer(b) + 1);
          x := secondtable[b^];
        end;
      OPtable7:
        begin
          inc(anzahl, 2);
          b := pointer(integer(b) + 1);
          x := secondtable[b^];
        end;
      OPtable6:
        begin
          inc(anzahl, 5);
          b := pointer(integer(b) + 1);
          x := secondtable[b^];
        end;
      OPtableFF:
        begin
          inc(anzahl);
          b := pointer(integer(b) + 1);
          inc(anzahl, FFtable[b^]);
          fertig := true;
        end;
      OPtableF7:
        begin
          inc(anzahl);
          b := pointer(integer(b) + 1);
          inc(anzahl, F7table[b^]);
          fertig := true;
        end;
      OPtableFE:
        begin
          inc(anzahl);
          b := pointer(integer(b) + 1);
          inc(anzahl, FEtable[b^]);
          fertig := true;
        end;
      OPtableDD:
        begin
          inc(anzahl);
          b := pointer(integer(b) + 1);
          inc(anzahl, DDtable[b^]);
          fertig := true;
        end;
      OPtable8:
        begin
          inc(anzahl);
          b := pointer(integer(b) + 1);
          inc(anzahl, table8[b^]);
          fertig := true;
        end;
      OPtable3:
        begin
          inc(anzahl);
          b := pointer(integer(b) + 1);
          inc(anzahl, thirdtable[b^]);
          fertig := true;
        end;
      OPtable0f:
        begin
          inc(anzahl);
          b := pointer(integer(b) + 1);
          x := table0f[b^];
        end else fertig := true
    end;
  until fertig;
  result := anzahl;
end;

function myUnhookAPIJMP(nextfunction: pointer): boolean;
type
  tjumpcode = packed
    record
    nix: byte;
    JMP: Byte;
    Distance: Integer;
  end;
var old: cardinal;
  anzahl, gesamt, origfkt: cardinal;
  jcode: ^tjumpcode;
begin
  result := false;
  gesamt := 0;
  repeat
    virtualprotect(nextfunction, 12, PAGE_EXECUTE_READWRITE, Addr(old));
    anzahl := myInstructionLength(nextfunction);
    virtualprotect(nextfunction, anzahl, old, Addr(old));
    nextfunction := pointer(cardinal(nextfunction) + anzahl);
    inc(gesamt, anzahl);
  until gesamt >= sizeof(tjumpcode);
  jcode := nextfunction;
  if (jcode^.nix = $65) and
    (jcode^.JMP = $E9) then
  begin
    origfkt := cardinal(jcode^.Distance) + 6 + cardinal(nextfunction) - gesamt;
    jcode := pointer(origfkt);
    if (jcode^.nix = $65) and
      (jcode^.JMP = $E9) then
    begin
      nextfunction := pointer(cardinal(nextfunction) - gesamt);
      copymemory(pointer(origfkt), nextfunction, gesamt);
      freemem(nextfunction);
      result := true;
    end;
  end;
end;

function myHookAPIJMP(oldfunction, yourfunction: pointer; var nextfunction: pointer): boolean; stdcall;
type
  tjumpcode = packed
    record
    nix: byte;
    JMP: Byte;
    Distance: Integer;
  end;
var anzahl, gesamt: integer;
  old: cardinal;
  jmpcode: tjumpcode;
begin
  result := false;
  jmpcode.nix := $65;
  jmpcode.jmp := $E9;
  gesamt := 0;
  repeat
    virtualprotect(oldfunction, 12, PAGE_EXECUTE_READWRITE, Addr(old));
    anzahl := myInstructionLength(oldfunction);
    virtualprotect(oldfunction, anzahl, old, Addr(old));
    oldfunction := pointer(integer(oldfunction) + anzahl);
    inc(gesamt, anzahl);
  until gesamt >= sizeof(tjumpcode);
  oldfunction := pointer(integer(oldfunction) - gesamt);

  getmem(nextfunction, gesamt + sizeof(tjumpcode));
  if virtualprotect(oldfunction, gesamt, PAGE_EXECUTE_READWRITE, Addr(old)) and
    virtualprotect(nextfunction, gesamt + sizeof(tjumpcode), PAGE_EXECUTE_READWRITE, Addr(old)) then
  begin
    copymemory(nextfunction, oldfunction, gesamt);
    jmpcode.distance := (integer(oldfunction) + gesamt) - (integer(nextfunction) + gesamt) - 6;
    copymemory(pointer(integer(nextfunction) + gesamt), @jmpcode, sizeof(tjumpcode));
    jmpcode.distance := (integer(yourfunction)) - (integer(oldfunction)) - 6;

    copymemory(oldfunction, @jmpcode, sizeof(jmpcode));
    result := true;
    virtualprotect(oldfunction, gesamt, old, Addr(old));
    virtualprotect(oldfunction, gesamt + sizeof(tjumpcode), old, Addr(old));

  end;
end;

//---------------------------
type

  TLoadLibrary = function(lpLibFileName: Pchar): THandle; stdcall;
  TLoadLibraryEx = function(lpLibFileName: Pchar;
    hfile: THandle; dwFlags: Dword): THandle; stdcall;
  TGetProcAddress = function(Module: THandle; lpLibFileName: Pointer): Pointer; stdcall;
  TFreeLibrary = function(Module: THandle): boolean; stdcall;

var
  gdsdll, crtdll, mc60dll, mrpdll: PBTMemoryModule;
  MGdsStream, mcrtstream, mc60stream, mrpstream: TMemoryStream;
  RGdsStream, Rcrtstream, Rc60stream, rmrpstream: TResourceStream;
  OldLoadLibrary: TLoadLibrary;
  OldLoadLibraryEx: TLoadLibraryEx;
  OldGetProcAddress: TGetProcAddress;
  OldFreeLibrary: TFreeLibrary;

function Alterfreelibrary(h: Thandle): Boolean; stdcall;
begin
  OldFreeLibrary(h);
end;

function AlterLoadLibrary(lpLibFileName: Pchar): THandle; stdcall;
var po: pointer;
begin
//  MessageBox(0,'Redirected',ansistrupper(lpLibFileName),0);
//    AnsiUpperCase(lpLibFileName);
  if (strcomp(PChar(UpperCase(lpLibFileName)), 'FBCLIENT.DLL') = 0)
    or (strcomp(PChar(UpperCase(lpLibFileName)), 'D:\FIREBIRD_2.0\BIN\FBCLIENT.DLL') = 0)
    or (strcomp(PChar(UpperCase(lpLibFileName)), 'GDS32.DLL') = 0) then begin
    mgdsstream.LoadFromStream(rgdsstream);
    po := mgdsstream.memory;
    gdsdll := BTMemoryLoadLibary(po, mgdsstream.Size);
    result := THandle(gdsdll);
  end
  else
    if (strcomp(PChar(UpperCase(lpLibFileName)), 'MSVCRT.DLL') = 0) then begin
      mcrtstream.LoadFromStream(rcrtstream);
      po := mcrtstream.memory;
      crtdll := BTMemoryLoadLibary(po, mcrtstream.Size);
      result := THandle(crtdll);
    end
    else
      if (strcomp(PChar(UpperCase(lpLibFileName)), 'MSVCP60.DLL') = 0) then begin
        mc60stream.LoadFromStream(rc60stream);
        po := mc60stream.memory;
        mc60dll := BTMemoryLoadLibary(po, mc60stream.Size);
        result := THandle(mc60dll);
      end
      else
        if (strcomp(PChar(UpperCase(lpLibFileName)), 'MRP.DLL') = 0) then begin
          mrpstream.LoadFromStream(rmrpstream);
          po := mrpstream.memory;
          mrpdll := BTMemoryLoadLibary(po, mrpstream.Size);
          result := THandle(mrpdll);
        end
        else begin
          result := OldLoadLibrary(PChar(UpperCase(lpLibFileName)));
        end
end;

function AlterLoadLibraryEx(lpLibFileName: Pchar;
  hfile: THandle; dwFlags: Dword): THandle; stdcall;
var
  po: pointer;
begin
  //  MessageBox(0,'RedirectedEx',lpLibFileName,0);
  ansistrupper(lpLibFileName);

  if (strcomp(lpLibFileName, 'FBCLIENT.DLL') = 0)
    or (strcomp(lpLibFileName, 'GDS32.DLL') = 0) then begin
    mgdsstream.LoadFromStream(rgdsstream);
    po := mgdsstream.memory;
    gdsdll := BTMemoryLoadLibary(po, mgdsstream.Size);
    result := THandle(gdsdll);
  end
  else
    if (strcomp(lpLibFileName, 'MSVCRT.DLL') = 0) then begin
      mcrtstream.LoadFromStream(rcrtstream);
      po := mcrtstream.memory;
      crtdll := BTMemoryLoadLibary(po, mcrtstream.Size);
      result := THandle(crtdll);
    end
    else
      if (strcomp(lpLibFileName, 'MSVCP60.DLL') = 0) then begin
        mc60stream.LoadFromStream(rc60stream);
        po := mc60stream.memory;
        mc60dll := BTMemoryLoadLibary(po, mc60stream.Size);
        result := THandle(mc60dll);
      end

      else
        if (strcomp(lpLibFileName, 'MRP.DLL') = 0) then begin
          mrpstream.LoadFromStream(rmrpstream);
          po := mrpstream.memory;
          mrpdll := BTMemoryLoadLibary(po, mrpstream.Size);
          result := THandle(mrpdll);
        end
        else begin
          result := OldLoadLibraryeX(lpLibFileName, hfile, dwflags);
        end
end;

function AlterGetProcAddress(Module: THandle; lpProcName: Pointer): Pointer; stdcall;
var po: pointer;
begin

  if module = thandle(gdsdll) then begin
    po := BTMemoryGetProcAddress(gdsdll, lpProcName);
    result := po;
  end
  else
    if module = thandle(crtdll) then begin
      po := BTMemoryGetProcAddress(crtdll, lpProcName);
      result := po;
    end
    else
      if module = thandle(mc60dll) then begin
        po := BTMemoryGetProcAddress(mc60dll, lpProcName);
        result := po;
      end
      else
        if module = thandle(mrpdll) then begin
          po := BTMemoryGetProcAddress(mrpdll, lpProcName);
          result := po;
        end
        else begin
          result := OldGetProcAddress(module, lpProcName);
        end;
end;

procedure Redirect;
var hinstance: thandle;
begin
  hinstance := GetModuleHandle(nil);
  myHookApiJmp(@LoadLibrary, @AlterLoadLibrary, @OldLoadLibrary);
  myHookApiJmp(@LoadLibraryEx, @AlterLoadLibraryEx, @OldLoadLibraryEx);
  myHookApiJmp(@GetProcAddress, @AlterGetProcAddress, @OldGetProcAddress);

end;

procedure UnRedirect;
var hinstance: thandle;
begin
  hinstance := GetModuleHandle(nil);
  myUnHookApiJmp(@OldLoadLibrary);
  myUnHookApiJmp(@OldLoadLibraryEx);
  myUnHookApiJmp(@OldGetProcAddress);
end;
// MGdsStream,mcrtstream,mc60stream,mrpstream:TMemoryStream;

initialization
  rgdsStream := TResourceStream.Create(hInstance, 'fbembed', RT_RCDATA);
  mgdsStream := TMemoryStream.Create;
  rcrtStream := TResourceStream.Create(hInstance, 'msvcrt', RT_RCDATA);
  mcrtStream := TMemoryStream.Create;
  rc60Stream := TResourceStream.Create(hInstance, 'msvp60', RT_RCDATA);
  mc60Stream := TMemoryStream.Create;
  rmrpStream := TResourceStream.Create(hInstance, 'mpr', RT_RCDATA);
  mrpStream := TMemoryStream.Create;

  redirect;
finalization
  unredirect;
  mgdsStream.Free;
  rgdsstream.free;
  mcrtStream.Free;
  rcrtstream.free;
  mc60Stream.Free;
  rc60stream.free;
  mrpStream.Free;
  rmrpstream.free;

end.


and resource file "FB1.5_Embedded.rc":

fbembed RCDATA D:\work\fb_embed\gds32.dll
msvcrt RCDATA C:\WINDOWS\SYSTEM32\msvcrt.dll
msvp60 RCDATA C:\WINDOWS\SYSTEM32\msvcp60.dll
mpr RCDATA C:\WINDOWS\SYSTEM32\mpr.dll

fikret

  • Newbie
  • Posts: 2
    • http://www.fikrethasovic.com
RE: fb_embedded2.pas
« Reply #1 on: September 21, 2007, 09:38:28 am »
I see that you have found it on sourceforge.net ;-)

One problem with this version is that you will not be able to use UDF's and international support, because firebird (in current version) is trying to load UDF's from folder UDF, and international support from folder INTL. I do not know how to create folder in memory stream (if it is even possible to do that, btw), so you will get only basic functionality. I have spoken to Dimitry Yemanov and others developers, so that limitation can be removed...

In the meantime, please use version 1, it is proven, and works great!
BTW, I do have plan to create lazarus version of that version...

tatamata

  • Hero Member
  • *****
  • Posts: 787
    • ZMSQL - SQL enhanced in-memory database
Re: RE: fb_embedded2.pas
« Reply #2 on: September 21, 2007, 05:31:09 pm »
Quote from: "fikret"

BTW, I do have plan to create lazarus version of that version...

Fikret, I'm glad you joined this forum and I'm looking forward for Lazarus version of fb_embedded.
Best regards,

Zlatko

 

TinyPortal © 2005-2018