If someone has enogh time and will, it would be great to convert this unit "fb_embedded2.pas" that embedds Firebird into .exe:
{*
* 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