Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Laden einer alten 16 Bit dll unter WinXP? (https://www.delphipraxis.net/177781-laden-einer-alten-16-bit-dll-unter-winxp.html)

Nintendo 27. Nov 2013 08:43

Laden einer alten 16 Bit dll unter WinXP?
 
Hallo,

ich habe eine alte dll aus win3.1 Zeiten. Ich besitze den Quelltext, weiß aber auch, das unter windows NT das Laden und Verwenden von 16 Bit dlls nicht mehr so einfach möglich ist.

Um nun nicht alles neu schreiben zu müssen und auch aus Interesse am Problem an sich, will ich diese DLL nun mit eigenen Routinen in den Speicher laden.
Meine konkrete Dll verwendet außerdem Bibliotheken, die ich momentan nur im 16 Bit Format verfügbar habe. Neben dem Ouellcode der Dll besitze ich noch den Binärcode der Dll.

Meine Überlegung ist folgende:

Die CPU (32Bit) kann 16 Bit Code noch immer ausführen. Win 3.1 Programme laufen auf Windows XP.

Deshalb sollte es doch möglich sein, unter Beachtung des anderen Formats der Startadresse der Funktionen in der DLL

(32 Bit -> Flat Modell -> 32 Bit Offset)
(16 Bit -> Segment Modell -> 32 Bit Pointer -> Segment:Offset)

Lineare Adresse := Sement * 16 + Offset
Offset := Lineare Adresse - Segment * 16
Segment := (Lieare Adresse - Offset) div 16

So sollte es doch möglich sein, die in der DLL codierten Funktionen dennoch aufzurufen, ja wenn ich das exakte Format der guten alten 16 Bit DLL genau kennen würde. Dann nämlich könnte ich mir die Laderoutinen schreiben und eine Tabelle mit den von der DLL exportierten Funktionen bereit setellen. Von dieser Tabelle aus sollte der Aufruf doch dann klappen, oder?

Ich bin nicht ausschließlich an der Nutzung der DLL Funktionen, sondern auch an der Lösung des hier geschilderten Problems interessiert. Die DLL enthält zudem auch sehr viele Funktionen. Eine Neukodierung würde also auch recht vielZeit in Anspruch nehmen, nicht nur wegen veränderter Direktiven (stdcall statt export, ...)

Wo also finde ich das genaue Format der alten 16 Bit dll.

Ich habe das hier: file:///C:/Daten/SystemAdmin/Eigene%...og_public.html

gefunden. Das bezieht sich aber auf heutige 32 Bit DLLs und die Beschreibung des Formates ist mir dort nicht dateiliiet genug. Die Seite verlinkt außerdem auf eine c++ Bibliothek zum Laden einer DLL in den Ram, nutzt aber auch Standard Windows Funktionen zum Laden.

Wegen der Problematik, das eine 16 Bit DLL unter Windows NT nur mit Einschränkungen nutzbar ist, will ich die Laderoutinen komplett selber schreiben und die Exporttabelle auf der 32 Bit Seite als Array bereit stellen.

Wenn das klappt, könnte man damit auch Dlls die von anderen Compilern übersetzt wurden und bisher in Delphi Probleme machen auf die gleiche Weise verfügbar machen, solange entweder der Quellcode der DLL verfügbar ist oder eine .def Datei mit den exportierten Funktionen.

Wo finde ich exakte Informationen zum Dll Format?

Sowohl für 16 Bit als auch für 32 Bit.

64 Bit dlls will ich vorerst ausklammern. Zuerst will ich das oben genannte Problem lösen.

Neutral General 27. Nov 2013 10:38

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Hallo,

Ich kann mich irren, aber ich glaube es gibt da ein weiteres Problem und zwar, dass sich die Opcodes eines Befehls in 16- und 32-Bit Assembler z.T. unterscheiden.

Ich bin mir nicht 100%ig sicher, aber ich habe da was im Kopf. Und von daher würde es nicht reichen die Adressen der Funktionen rauszufinden und dir eine Tabelle zu machen.

Informationen wie DLLs aufgebaut sind:

http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx

(DLLs sind zu 99% normale .exe Dateien)

Andere Frage:
Kannst du die DLL nicht einfach als 32-Bit DLL neu compilieren wenn du den Code hast?
Müsste doch relativ einfach machbar sein oder?
Zumindest kann ich mir nicht vorstellen, dass es aufwendiger ist als das was du vorhast.

Nintendo 27. Nov 2013 18:56

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Danke für den Link. Werde ich mir anschauen.

Zitat:

Zitat von Neutral General
Ich kann mich irren, aber ich glaube es gibt da ein weiteres Problem und zwar, dass sich die Opcodes eines Befehls in 16- und 32-Bit Assembler z.T. unterscheiden.

Das sich die Opcodes regelrecht unterscheiden, kann ich mir nicht vorstellen. Höchstens, das halt die 16 Bit Äquivalente verwendet werden. Die Prozessorfamilie bleibt ja gleich (x86). Oder brauche ich mehr, um 16 Bit Code auf einer 32 Bit Maschine ausführen zu können. Dank Dosbox klappt das ja mit DOS Programmen.

Und hier in diesem Fall?

Zitat:

Zitat von Neutral General
Ich bin mir nicht 100%ig sicher, aber ich habe da was im Kopf. Und von daher würde es nicht reichen die Adressen der Funktionen rauszufinden und dir eine Tabelle zu machen.

Warum reicht das nicht? Wenn ich da die Adressen korrekt von 32Bit Flat in Seg:Ofs umrechne und dann die Funktion aufrufe? Oder braucht da zwingend den 16 Bit Layer, wie für DOS Programme die DOSBox?

Ich habe zwar den Quellcode der Dll aber nicht von allen in dieser dll verwendeten Bibliotheken.

Namenloser 27. Nov 2013 19:19

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Was Neutral General da sagt über unterschiedlich interpretierte OPCodes bei 16-Bit und 32-Bit, kommt mir auch dunkel bekannt vor. Ich hatte vor einiger Zeit mal versucht, einen Disassembler zu schreiben, und hatte da glaube ich auch so ein Problem...

Aber du schreibst was von Windows XP. Da kann man 16-Bit-Programme ja noch direkt laufen lassen. Wäre es nicht einfacher, eine 16-bittige Wrapper-Applikation für die DLL zu schreiben und diese vom Hauptprogramm aus mit Pipes o.ä. anzusteuern?

Spätestens wenn mal auf ein neues Windows geupdatet werden soll, wird es dann aber wieder haarig. Da müsste man dann wohl die DLL bzw. den Wrapper emulieren, vielleicht mit DOSBox als Vermittlungsstelle (ich weiß nicht ob das so schon geht, oder ob man diese Funktionalität erst noch in DOSBox einbauen müsste...). So baut man Schicht um Schicht um eine antike Bibliothek... ob man das wirklich will?

Also alles in allem wird das nicht gerade einfach, denke ich. Wäre vermutlich effizienter, die Bibliotheken der DLL einfach zu ersetzen/neu zu schreiben.

glotzer 27. Nov 2013 19:59

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Wie wärs damit die DLL mit Wrapper-Programm in QEMU laufen zu lassen?
Dann würde das ganze auch auf aktuellen Betriebsystemen laufen.

himitsu 27. Nov 2013 20:31

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Aber ganz im Ernst, wenn du den Quelltext besitzt, warum dann mühevoll versuchen das Alte irgendwie brutal in die eigene Anwendung reinzuhäcken oder es über wilde Umwege und mithilfe von Zusatzprogrammen zum Laufen bekommen,

Wenn es wesentlich leichter wäre den Quellcode an 32 Bit anzupassen und vielleicht auch gleich auch mit für 64 Bit
und die DLL dann ganz normal ins Programm einzubinden?

OK, eine 16-Bit-Host-Anwendung als Out-Of-Process-Server zu verwenden, wäre der andere "einfache"/gängige Weg,
aber bei aktuellen 64-Bit-Windowsen wurde nun endlich das 16-Bit-Subsystem komplett rausgeworfen, womit da 16-Bit-Anwendung garnicht mehr laufen. (Emulatoren und VMs mit Emulierung ausgeschlossen)

jaenicke 27. Nov 2013 21:55

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Zitat:

Zitat von Nintendo (Beitrag 1237680)
Warum reicht das nicht? Wenn ich da die Adressen korrekt von 32Bit Flat in Seg:Ofs umrechne und dann die Funktion aufrufe? Oder braucht da zwingend den 16 Bit Layer, wie für DOS Programme die DOSBox?

Es hat einen Grund warum 64-Bit Versionen von Windows keine 16-Bit Programme mehr ausführen können. Eben weil die nicht so direkt ausgeführt werden können. Heutige CPUs kennen einen 32-Bit und einen 64-Bit Mode, aber keinen 16-Bit Mode. Deshalb müsstest du nicht nur die Einsprungadressen suchen, sondern auch jeden einzelnen Befehl nach 32-Bit übersetzen, ausführen und das Ergebnis zurück übersetzen. Im Grunde ist das dann ein Interpreter, der die Befehle der Reihe nach ausführt. Das ist ein hoher Aufwand.

Deshalb wäre ein 16-Bit Wrapper am sinnvollsten, aber 64-Bit Betriebssysteme wären dann tabu.

JamesTKirk 28. Nov 2013 05:35

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Zitat:

Zitat von Nintendo (Beitrag 1237680)
Zitat:

Zitat von Neutral General
Ich kann mich irren, aber ich glaube es gibt da ein weiteres Problem und zwar, dass sich die Opcodes eines Befehls in 16- und 32-Bit Assembler z.T. unterscheiden.

Das sich die Opcodes regelrecht unterscheiden, kann ich mir nicht vorstellen. Höchstens, das halt die 16 Bit Äquivalente verwendet werden. Die Prozessorfamilie bleibt ja gleich (x86). Oder brauche ich mehr, um 16 Bit Code auf einer 32 Bit Maschine ausführen zu können.

Der wichtigste Punkt ist, dass Windows XP es dir enorm übel nehmen könnte, wenn du das System in einem inkonsistentem Zustand hinterlässt, wenn die Zeitscheibe deines Prozesses aufgebraucht ist (was du ja nicht beinflussen kannst). Deswegen "leben" 16-Bit Programme ja auch in der NTVDM, welche die ganzen "gefährlichen" Befehle nur emuliert. Da in ReactOS aktuell an der Implementierung der NTVDM gearbeitet wird könnstet du dir deren 486-Emulater-Bibliothek anschauen und vielleicht verwenden, so dass du quasi eine "16-Bit Skript Engine" implementieren könntest, die dir deine 16-Bit DLL auf Anforderung aufruft und emuliert.

Zitat:

Zitat von Nintendo (Beitrag 1237680)
Dank Dosbox klappt das ja mit DOS Programmen.

DOSBox emuliert eine komplette CPU, deswegen funktioniert das da auch ohne Probleme.

Gruß,
Sven

Blup 28. Nov 2013 08:06

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Zu den gennanten Problemen kommt hinzu, so eine DLL läuft ja nicht im leeren Raum.
Da werden 16-Bit API-Funktionen aufgerufen, mit 16-Bit Parametern und Rückgabewerten, aus weitere 16-Bit DLLs des Betriebssystems z.B..
Neben der CPU müsste man die 16-Bit Betriebssystem-Umgebung emulieren.

Nintendo 29. Nov 2013 09:16

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Danke Euch allen. Werde mich jetzt erst mal mit der Problematik beschäftigen. Ich tendiere zur Nutzung des 486 Emulators, wie ihn JamesTKirk vorgeschlagen hat. Oder VirtualBox, QEmu,...

Allerdings interessirt mich auch der Aufbau des 486 Emulators. Und da kann ich ja den Quellcode studieren. Dann sehe ich weiter.

8-)

Nintendo 1. Dez 2013 11:32

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Hallo,

es hat sich eine neue Frage ergeben, die ich auch hier: http://www.delphipraxis.net/148977-d...nzubinden.html

gepostet habe, da das auch bei Dlls der gleichen Prozessorfamilie bei gleicher Wortbreite interessant ist, zum Beispiel halt für die Kommunikation mit Freepascal Programmen.

Die Exporttabelle mit den anzusprechenden Funktionen wird, wie ich bisher verstanden habe durch eine Struktur mit Namen

IMAGE_EXPORT_DIRECTORY

repräsentiert. Ich kann aber die Adrees dieser Tabelle in den im Netz verfügbaren Dokus nirgends finden.

*** Code im verlinkten Beitrag ***


Ist vieleicht hier schon in einem Datenfeld die Adresse der Exporttabelle verborgen?

Die Struktur der .EXE Datei ist nur bis hierher dokumnentiert. Danach kommen die Section Header. Wo aber ist die Exporttabelle -> IMAGE_EXPORT_DIRECTORY?

Bernhard Geyer 1. Dez 2013 16:31

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Wenn Du wissen willst di ein Exe/DLL aufgebaut ist so schau am besten in der MSDN nach

Nintendo 2. Dez 2013 09:40

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1238115)
Wenn Du wissen willst di ein Exe/DLL aufgebaut ist so schau am besten in der MSDN nach

Hab ich schon gemacht. Was ich aber jetzt wissen muss, ist, in der wievielten Section die Exporttabelle steht.

Nach PE-Optional-Header folgen mehrere Section-Headers. Meine Frage ist nun:

Der wievielte Section Header enthält denn nun die Exporttabelle.

Entweder bin ich im englischen nicht fit genug oder ich habe irgenwas noch nicht verstanden.

Was ich bisher verstanden habe, ist der grundsätzliche Aufbau des PE Headers. Die Section Headers sind die vorletzten Header, danach folgen die Ressourcen Header (IMAGE_RESOURCE_DIRECTORY). Meine Dll enthält aber keine Ressourcen.

Was ich noch nicht rausgekriegt habe, ist, der wievielte Section Header denn nun auf die Exporttabelle zeigt, mit der Struktur IMAGE_EXPORT_DIRECTORY. Wo gibt es dazu detailliertere Auskunft.

Die angegebene Doku ist da leider vieeel zu knapp. Warum kann sowas nicht generell detaillierter dokumentiert werden?

Wird doch auch von anderen gebraucht, nicht nur hier von mir.

Wenn natürlich hier: http://msdn.microsoft.com/en-us/magazine/bb985996.aspx

die Sections in derjenigen Reihenfolge beschrieben sind, in der sie in der library abgespeichert sind, dann natürlich habe ich bereits gefunden, wonach ich suche. Werde das gleich mal ausprobieren.

Delphi-Quellcode:
Figure 1 Section Names

Name
   Description
.text
   The default code section.
.data
   The default read/write data section. Global variables typically go here.
.rdata
   The default read-only data section. String literals and C++/COM vtables are examples of items put into .rdata.
.idata
   The imports table. It has become common practice (either explicitly, or via linker default behavior) to merge the .idata section into another section, typically .rdata. By default, the linker only merges the .idata section into another section when creating a release mode executable.
.edata
   The exports table. When creating an executable that exports APIs or data, the linker creates an .EXP file. The .EXP file contains an .edata section that's added into the final executable. Like the .idata section, the .edata section is often found merged into the .text or .rdata sections.
.rsrc
   The resources. This section is read-only. However, it should not be named anything other than .rsrc, and should not be merged into other sections.
.bss
   Uninitialized data. Rarely found in executables created with recent linkers. Instead, the VirtualSize of the executable's .data section is expanded to make enough room for uninitialized data.
.crt
   Data added for supporting the C++ runtime (CRT). A good example is the function pointers that are used to call the constructors and destructors of static C++ objects. See the January 2001 Under The Hood column for details on this.
.tls
   Data for supporting thread local storage variables declared with __declspec(thread). This includes the initial value of the data, as well as additional variables needed by the runtime.
.reloc
   The base relocations in an executable. Base relocations are generally only needed for DLLs and not EXEs. In release mode, the linker doesn't emit base relocations for EXE files. Relocations can be removed when linking with the /FIXED switch.
.sdata
   "Short" read/write data that can be addressed relative to the global pointer. Used for the IA-64 and other architectures that use a global pointer register. Regular-sized global variables on the IA-64 will go in this section.
.srdata
   "Short" read-only data that can be addressed relative to the global pointer. Used on the IA-64 and other architectures that use a global pointer register.
.pdata
   The exception table. Contains an array of IMAGE_RUNTIME_FUNCTION_ENTRY structures, which are CPU-specific. Pointed to by the IMAGE_DIRECTORY_ENTRY_EXCEPTION slot in the DataDirectory. Used for architectures with table-based exception handling, such as the IA-64. The only architecture that doesn't use table-based exception handling is the x86.
.debug$S
   Codeview format symbols in the OBJ file. This is a stream of variable-length CodeView format symbol records.
.debug$T
   Codeview format type records in the OBJ file. This is a stream of variable-length CodeView format type records.
.debug$P
   Found in the OBJ file when using precompiled headers.
.drectve
   Contains linker directives and is only found in OBJs. Directives are ASCII strings that could be passed on the linker command line. For instance:

  -defaultlib:LIBC

Directives are separated by a space character.
.didat
   Delayload import data. Found in executables built in nonrelease mode. In release mode, the delayload data is merged into another section.

JamesTKirk 4. Dez 2013 21:44

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Zitat:

Zitat von Nintendo (Beitrag 1238082)
es hat sich eine neue Frage ergeben, die ich auch hier: http://www.delphipraxis.net/148977-d...nzubinden.html

gepostet habe, da das auch bei Dlls der gleichen Prozessorfamilie bei gleicher Wortbreite interessant ist, zum Beispiel halt für die Kommunikation mit Freepascal Programmen.

Warum sollte man das brauchen? Free Pascal erzeugt normale Win32/64/CE DLLs, die von jedem anderem Windows Program auch nutzbar sind (zumindest solange man sich daran hält keine FPC spezifischen Typen zu verwenden, aber das gilt analog für Delphi und C++ auch...)

Delphi-Quellcode:
  PIMAGE_OPTIONAL_HEADER32 = ^IMAGE_OPTIONAL_HEADER32;
   IMAGE_OPTIONAL_HEADER32 = record
    //
    // Standard fields.
    //

    Magic                      : WORD;
    MajorLinkerVersion         : BYTE;
    MinorLinkerVersion         : BYTE;
    SizeOfCode                 : DWORD;
    SizeOfInitializedData      : DWORD;
    SizeOfUninitializedData    : DWORD;
    AddressOfEntryPoint        : DWORD;
    BaseOfCode                 : DWORD;
    BaseOfData                 : DWORD;

    //
    // NT additional fields.
    //

    ImageBase                  : DWORD;
    SectionAlignment           : DWORD;
    FileAlignment              : DWORD;
    MajorOperatingSystemVersion : WORD;
    MinorOperatingSystemVersion : WORD;
    MajorImageVersion          : WORD;
    MinorImageVersion          : WORD;
    MajorSubsystemVersion      : WORD;
    MinorSubsystemVersion      : WORD;
    Win32VersionValue          : DWORD;
    SizeOfImage                : DWORD;
    SizeOfHeaders              : DWORD;
    CheckSum                   : DWORD;
    Subsystem                  : WORD;
    DllCharacteristics         : WORD;
    SizeOfStackReserve         : DWORD;
    SizeOfStackCommit          : DWORD;
    SizeOfHeapReserve          : DWORD;
    SizeOfHeapCommit           : DWORD;
    LoaderFlags                : DWORD;
    NumberOfRvaAndSizes        : DWORD;
    //...X.....X...
    //....X...X....
    //.....X.X.....
    //......X......
    //.....X.X.....
    //....X...X....
    //...X.....X...
    DataDirectory              : array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of IMAGE_DATA_DIRECTORY;
  end;
Zitat:

Zitat von Nintendo (Beitrag 1238082)
Ist vieleicht hier schon in einem Datenfeld die Adresse der Exporttabelle verborgen?

Das X markiert den Schatz... oder so... :P

Zitat:

Zitat von Nintendo (Beitrag 1238147)
Entweder bin ich im englischen nicht fit genug oder ich habe irgenwas noch nicht verstanden.

Was ich bisher verstanden habe, ist der grundsätzliche Aufbau des PE Headers. Die Section Headers sind die vorletzten Header, danach folgen die Ressourcen Header (IMAGE_RESOURCE_DIRECTORY). Meine Dll enthält aber keine Ressourcen.

Was ich noch nicht rausgekriegt habe, ist, der wievielte Section Header denn nun auf die Exporttabelle zeigt, mit der Struktur IMAGE_EXPORT_DIRECTORY. Wo gibt es dazu detailliertere Auskunft.

Wenn man ein bisschen weiß, wonach man suchen muss (ich weiß, sagt sich so leicht...), dann findet man zum Beispiel diese Funktion, bei der die Beschreibung zum
Delphi-Quellcode:
DirectoryEntry
das enthält, was du suchst (Hinweis: Keine Ahnung, ob du diese Funktion für eine 16-Bit DLL verwenden könntest).

Bei der Suche nach dem dort angegebenen Wert in Google kommen dann durchaus noch ein paar Tutorials zum Thema zu Tage...

Gruß,
Sven

Nintendo 6. Dez 2013 10:28

AW: Laden einer alten 16 Bit dll unter WinXP?
 
Zitat:

Zitat von JamesTKirk
Warum sollte man das brauchen? Free Pascal erzeugt normale Win32/64/CE DLLs, die von jedem anderem Windows Program auch nutzbar sind (zumindest solange man sich daran hält keine FPC spezifischen Typen zu verwenden, aber das gilt analog für Delphi und C++ auch...)

Ich besitze Graphic Vision von Jason Burgon. Das grafische Gegenstück zu Free Vision. Das ist nicht so einfach nach 32 Bit zu portieren, weil der Code viele Assembleranweisungen enthält. Wollte dieses Paket für Freepascal verfügbar machen, da es ja nun mal den Go32 Port, die Dos Seite noch gibt. Mag ja sein, das DOS hoffnungslos veraltet ist. Dennoch gibt es im Widerspruch zu dieser Aussage das FreeDOS Projekt und verschiedene DOS Emulatoren. Klar, auf so einem Emulator läuft dann auch die 16 Bit Version klaglos, aber ich wollte nun dieses Graphic Vision für Freepascal verfügbar machen. Dazu brauche ich die Dll, die ich aber, weil Go32 keine Dlls unterstützt, von Hand (per eigenem Code) in den Speicher laden muss, von wo aus ich dann Routinen aufrufen will, wiederum mit eigenem Code, die Graphic Vision steuern. Ereignisse sollten sich mit Callback Funktionen beherrschen lassen. Die Dll dazu muss ich noch schreiben, mit Funktionen, die auf die GVision Objekte zugreifen und Daten entgegen nehmen.

Lizenzrechtlich ist zu sagen, das jeder Herrn Jason Burgon eine Emailschicken kann, mit der Bitte, ihm die GVision zu schicken. Ich hab das per Anfrage wegen des von ihm nicht mehr verfügbaren Vertriebes gemacht, wollte das Paket auch kaufen. Er hat mir dann das Paket kostenlos geschickt.
War dazu auf seiner Webseite und habe "Order" angeklickt.

Er plant eine Portierung nach Freepascal, aber nur für die Windows Plattform. Um für Go32 die Portierung zu sparen, das Umschreiben des Codes, will ich das Problem per Dll lösen, denn Borland Pascal, das ich besitze, erlaubt das compilieren von Dlls für Dos unter 16Bit DPMI.

Die damit verbundene Notwendigkeit, mich mit dem Aufbau einer ausführbaren Datei zu beschäftigen, hilft mir vielleicht später bei anderen Programmprojekten. Das bloße Umschreiben von DOS Code hilft mir dagegen weniger, außer natürlich betreffs Assembler, denn wegen der anderen Wortbreite müssen die Assemblerteile angepasst werden. Ich fühle mich aber nicht fit genug dafür, da sich die Assembler Syntax doch von der in BPascal unterscheidet. Wäre höchstens ein Versuch Wert mit Freepascal bis 1.9.2. Dieser Compiler konnte noch den 16 Bit Assemblercode einfach lesen und in passende 32 Bit Befehle übersetzen. Leider machen das spätere FPC Compiler nicht mehr so einfach. Aber ich habe noch so einen alten FPC Compiler im Netz gefunden.

Wegen Opensource mache ich mir da momentan wenig Sorgen, da Herr Burgon bei höflicher Anfrage kulant ist und die Graphic Vision dem Interessenten zusendet, womit dieser Interessent dann auch den Quellcode hat. Allerdings nur wenn er den korrekt installiert. Dazu ist dann allerdings eine legale Borland Pascal Distri erforderlich, weil nur da die Quellcodes der Laufzeitbibliotheken dabei sind, die zur Installation der Quellcodes Voraussetzung sind. Zur Not könnte man sich aber vielleicht mit der Kenntnis der Baumstruktur der Directories behelfen. Es gibt Borland Pascal zum Download im Internet. Wie legal das da ist, weiß ich nicht. Ich habe aber mehrmals Borland, wie auch Emba auf diese Downloads hingewiesen aber nie eine Antwort erhalten. Die Downloadlinks funktionieren noch immer. Wenn also der Eigentümer die Situation duldet....?

Habe zudem in einem Internetforum gelesen, das man wohl bei Emba oder Borland höflich anfragen kann und dann auf Wunsch das Paket zugesendet bekommt. Möglicherweise völlig kostenlos. Das wäre dann der völlig legale Weg.

Aus diesen Gründen bevorzuge ich das Schreiben einer Unit, die meine spätere Dll in den Speicher liest, Das Wissen zum Aufbau der Exe dürfte auch in anderer Hinsicht in der Windows Programmierung nützlich sein. Diese Unit soll auch den Code zum Aufruf meiner Dll Funktionen enthalten.


Aktuell allerdings habe ich mir zum Testen erst mal eine 32 Bit Dll mit einer einzigen Exportfunktion geschrieben.

Delphi-Quellcode:
library Test32dll;

//Uses Klausel wie vom Delphi Dll Experten eingerichtet

function helloWorld; stdcall;
begin
  Writeln('Hello World from a DLL!');
  Writeln('Zurück mit <<ENTER>>... ');
  Readln;
end;

exports
 helloWorld;
Delphi-Quellcode:
unit ULoadDll;

interface

uses
  Windows; { wegen VirtualAlloc() }

(* MemoryModule.h *)

const
  {
  ERROR_RESOURCE_DATA_NOT_FOUND   =
  ERROR_RESOURCE_LANG_NOT_FOUND   =
  ERROR_RESOURCE_NAME_NOT_FOUND   =
  ERROR_RESOURCE_TYPE_NOT_FOUND   =
  }
  IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;

  IMAGE_SIZEOF_SHORT_NAME         = 8;

  { Indizes in Sections Array }
  IMAGE_DEFAULT_CODE              = 0;
  IMAGE_DEFAULT_DATA_READWRITE    = 1;
  IMAGE_DEFAULT_DATA_READONLY     = 2;
  IMAGE_IMPORT_TABLE              = 3;
  IMAGE_EXPORT_TABLE              = 4; //meine Funktionen
  IMAGE_RESOURCE_TABLE            = 5;
  IMAGE_UNINITIALIZED_DATA        = 6;
  IMAGE_CPP_RUNTIME_SUPPORT       = 7;
  IMAGE_DATA_THREAD_LOCAL_STORAGE = 8;
  IMAGE_BASE_RELOCATIONS          = 9;
  IMAGE_SDATA_FORIA64_ONLY        = 10;
  IMAGE_SRDATA_FORIA64_ONLY       = 11;
  IMAGE_PDATA_FORIA64_ONLY        = 12;
  IMAGE_DEBUG_CODEVIEW_SYMBOLS    = 13;
  IMAGE_DEBUG_CODEVIEW_TYPERECORDS = 14;
  IMAGE_DEBUG_PRECOMPILED_HEADERS = 15;
  IMAGE_CONTAINS_LINKER_DIREKTIVES = 16;
  IMAGE_DELAY_LOAD_IMPORT_DATA    = 17;

type
  HMEMORYMODULE = Pointer;

  HMEMORYRSRC  = Pointer;

  HCUSTOMMODULE = Pointer;

  LPVOID       = Pointer;

  LPCTSTR      = PChar;
  LPTSTR       = PChar;

  PUINT        = ^UINT;
  UINT         = Longint;

  PULONG       = ^ULONG;
  ULONG        = LongWord; { in delphi 3 -> Longint }

  PDWORD       = ^DWORD;
  DWORD        = LongWord; { in delphi 3 -> Longint }

  PIMAGE_DOS_HEADER = ^IMAGE_DOS_HEADER;
  IMAGE_DOS_HEADER = record            // DOS .EXE header
    e_magic   : WORD;                  // Magic number { MZ for exe }
    e_cblp    : WORD;                  // Bytes on last page of file
    e_cp      : WORD;                  // Pages in file
    e_crlc    : WORD;                  // Relocations
    e_cparhdr : WORD;                  // Size of header in paragraphs
    e_minalloc : WORD;                  // Minimum extra paragraphs needed
    e_maxalloc : WORD;                  // Maximum extra paragraphs needed
    e_ss      : WORD;                  // Initial (relative) SS value
    e_sp      : WORD;                  // Initial SP value
    e_csum    : WORD;                  // Checksum
    e_ip      : WORD;                  // Initial IP value
    e_cs      : WORD;                  // Initial (relative) CS value
    e_lfarlc  : WORD;                  // File address of relocation table
    e_ovno    : WORD;                  // Overlay number
    e_res     : array[0..3] of WORD;   // Reserved words
    e_oemid   : WORD;                  // OEM identifier (for e_oeminfo)
    e_oeminfo : WORD;                  // OEM information; e_oemid specific
    e_res2     : array[0..9] of WORD;   // Reserved words
    e_lfanew  : Longint;               // File address of new exe header
  end;
 
  PIMAGE_FILE_HEADER = ^IMAGE_FILE_HEADER;
   IMAGE_FILE_HEADER = record
    Machine             : WORD;
    NumberOfSections    : WORD;
    TimeDateStamp       : DWORD;
    PointerToSymbolTable : DWORD;
    NumberOfSymbols     : DWORD;
    SizeOfOptionalHeader : WORD;
    Characteristics     : WORD;
  end;

  TLocation = record
   case DWORD of
    0: (PhysicalAddress: DWORD);
    1: (VirtualSize: DWORD);
  end;

  IMAGE_SECTION_HEADER = record
    Name               : array[0..IMAGE_SIZEOF_SHORT_NAME-1] of BYTE;
    Misc               : TLocation;
    VirtualAddress     : DWORD;
    SizeOfRawData      : DWORD;
    PointerToRawData   : DWORD;
    PointerToRelocations: DWORD;
    PointerToLinenumbers: DWORD;
    NumberOfRelocations : WORD;
    NumberOfLinenumbers : WORD;
    Characteristics    : DWORD;
  end;

  PIMAGE_DATA_DIRECTORY = ^IMAGE_DATA_DIRECTORY;
   IMAGE_DATA_DIRECTORY = record
    VirtualAddress: DWORD;
    Size: DWORD;
  end;

  PIMAGE_BASE_RELOCATION = ^IMAGE_BASE_RELOCATION;
   IMAGE_BASE_RELOCATION = record
    VirtualAddress: DWORD;
    SizeOfBlock: DWORD;
  end;

  PIMAGE_OPTIONAL_HEADER32 = ^IMAGE_OPTIONAL_HEADER32;
   IMAGE_OPTIONAL_HEADER32 = record
    //
    // Standard fields.
    //

    Magic                      : WORD;
    MajorLinkerVersion         : BYTE;
    MinorLinkerVersion         : BYTE;
    SizeOfCode                 : DWORD;
    SizeOfInitializedData      : DWORD;
    SizeOfUninitializedData    : DWORD;
    AddressOfEntryPoint        : DWORD;
    BaseOfCode                 : DWORD;
    BaseOfData                 : DWORD;

    //
    // NT additional fields.
    //

    ImageBase                  : DWORD;
    SectionAlignment           : DWORD;
    FileAlignment              : DWORD;
    MajorOperatingSystemVersion : WORD;
    MinorOperatingSystemVersion : WORD;
    MajorImageVersion          : WORD;
    MinorImageVersion          : WORD;
    MajorSubsystemVersion      : WORD;
    MinorSubsystemVersion      : WORD;
    Win32VersionValue          : DWORD;
    SizeOfImage                : DWORD;
    SizeOfHeaders              : DWORD;
    CheckSum                   : DWORD;
    Subsystem                  : WORD;
    DllCharacteristics         : WORD;
    SizeOfStackReserve         : DWORD;
    SizeOfStackCommit          : DWORD;
    SizeOfHeapReserve          : DWORD;
    SizeOfHeapCommit           : DWORD;
    LoaderFlags                : DWORD;
    NumberOfRvaAndSizes        : DWORD;
    DataDirectory              : array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of IMAGE_DATA_DIRECTORY;
  end;

  PIMAGE_NT_HEADERS32 = ^IMAGE_NT_HEADERS32;
   IMAGE_NT_HEADERS32 = record
    Signature     : DWORD;
    FileHeader    : IMAGE_FILE_HEADER;
    OptionalHeader : IMAGE_OPTIONAL_HEADER32;
  end;
 
  TThunkCharacterisics = record
  case DWORD of
   0: (Characteristics  : DWORD);        { 0 for terminating null import descriptor       }
   1: (OriginalFirstThunk: DWORD);        { RVA to original unbound IAT (PIMAGE_THUNK_DATA) }
  end;

  PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;
   IMAGE_IMPORT_DESCRIPTOR = record
    Thunk         : TThunkCharacterisics;
    TimeDateStamp : DWORD;                { 0 if not bound,                               }
                                            { -1 if bound, and real date\time stamp         }
                                            {     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) }
                                            { O.W. date/time stamp of DLL bound to (Old BIND)     }

    ForwarderChain : DWORD;                { -1 if no forwarders                          }
    Name          : DWORD;
    FirstThunk    : DWORD;                    { RVA to IAT (if bound this IAT has actual addresses) }
  end;
 
  TCode = record
  case LongWord of
   0 : (Offset,Segment: Word);
   1 : (LinearAddr: LongWord);
  end;
 
  PIMAGE_EXPORT_DIRECTORY = ^IMAGE_EXPORT_DIRECTORY;
   IMAGE_EXPORT_DIRECTORY = record
    Characteristics      : DWORD;
    TimeDateStamp        : DWORD;
    MajorVersion         : WORD;
    MinorVersion         : WORD;
    Name                 : DWORD;
    Base                 : DWORD;
    NumberOfFunctions    : DWORD;
    NumberOfNames        : PDWORD;
    AddressOfFunctions   : PDWORD; { RVA from base of image }
    AddressOfNames       : PDWORD; { RVA from base of image }
    AddressOfNameOrdinals : PDWORD; { RVA from base of image }
  end;

  TSections = Array[0..17] of IMAGE_SECTION_HEADER;

  PDllFileStruct = ^TDllFileStruct;
  TDllFileStruct = record
    dosheader   : IMAGE_DOS_HEADER;
    dosStub     : array [0..27] of Byte;
    peHeader    : IMAGE_NT_HEADERS32;
    SectionHeader: IMAGE_SECTION_HEADER;
    Code        : array of Byte;
  end;

  PIMAGE_RESOURCE_DIRECTORY_ENTRY = ^IMAGE_RESOURCE_DIRECTORY_ENTRY;
   IMAGE_RESOURCE_DIRECTORY_ENTRY = record
    Name: DWORD;
    OffsetToData: DWORD;
  end;

  PIMAGE_RESOURCE_DATA_ENTRY = ^IMAGE_RESOURCE_DATA_ENTRY;
   IMAGE_RESOURCE_DATA_ENTRY = record
    OffsetToData: ULONG;
    Size       : ULONG;
    CodePage   : ULONG;
    Reserved   : ULONG;
  end;

  PIMAGE_RESOURCE_DIR_STRING_U = ^IMAGE_RESOURCE_DIR_STRING_U;
   IMAGE_RESOURCE_DIR_STRING_U = record
    Length: WORD;
    NameString: array[0..1] of WORD; { WCHAR -> 16 Bit UNICODE-CHAR }
  end;

  PIMAGE_RESOURCE_DIRECTORY = ^IMAGE_RESOURCE_DIRECTORY;
   IMAGE_RESOURCE_DIRECTORY = record
    Characteristics: DWORD;
    TimeDateStamp: DWORD;
    MajorVersion: WORD;
    MinorVersion: WORD;
    NumberOfNamedEntries: WORD;
    NumberOfIdEntries: WORD;
    { dynamic array }
    DirectoryEntries: array of IMAGE_RESOURCE_DIRECTORY_ENTRY; { EntryCount is NumberOfIdEntries}
  end;

function LoadLibraryFromFile(Filename: String): TDllFileStruct;

function MemoryLoadLibraryEx(var ALibrary: TDllFileStruct): HMEMORYMODULE;

procedure MemoryFreeLibrary(var ALibrary: HMEMORYMODULE);

(**


 * Find the location of a resource with the specified type and name.


 *)


function MemoryFindResource(module: HMEMORYMODULE; lpName,lpType: LPCTSTR): HMEMORYRSRC;


(**


 * Find the location of a resource with the specified type, name and language.


 *)


function MemoryFindResourceEx(module: HMEMORYMODULE; lpName,lpType: LPCTSTR; language: WORD): HMEMORYRSRC;




(**


 * Get the size of the resource in bytes.

 *)

function MemorySizeofResource(module: HMEMORYMODULE; resource: HMEMORYRSRC): DWORD;


(**


 * Get a pointer to the contents of the resource.


 *)


function MemoryLoadResource(module: HMEMORYMODULE; resource: HMEMORYRSRC): LPVOID;


(**


 * Load a string resource.


 *)


function MemoryLoadString(module: HMEMORYMODULE; id: UINT; buffer: LPTSTR; maxsize: Longint): Longint;


(**


 * Load a string resource with a given language.


 *)


function MemoryLoadStringEx(module: HMEMORYMODULE; id: UINT; buffer: LPTSTR; maxsize: Longint; language: WORD): Longint;








implementation

uses
  {$ifdef DOS}
  Dos,
    {$ifdef FPC}
    Go32,
    {$else}

    {$endif}
  {$endif}
  SysUtils, Classes;



function LoadLibraryFromFile(Filename: String): TDllFileStruct;
var
  S: TFileStream;
  H: TDllFileStruct;
  CodeSize: Longint;
begin
  S := TFileStream.Create(Filename, fmOpenRead);
  S.Read(H, Sizeof(H)-4);
  CodeSize := S.Size - S.Position;
  SetLength(H.Code, CodeSize);
  S.Read(H.Code, CodeSize);
  S.Free;
  Result := H;
end;

const
  _MEM_COMMIT = $00001000; { Wert zu Windows äquivalent }
  _MEM_RESERVE = $00002000; { Wert zu Windows äquivalent }

  _PAGE_NO_ACCESS = $01;   { Wert zu Windows äquivalent }
  _PAGE_READONLY = $02;   { Wert zu Windows äquivalent }
  _PAGE_READWRITE = $04;   { Wert zu Windows äquivalent }
  _PAGE_WRITECOPY = $08;   { Wert zu Windows äquivalent }

  _PAGE_EXECUTE          = $10; { Wert zu Windows äquivalent }
  _PAGE_EXECUTE_READ     = $20; { Wert zu Windows äquivalent }
  _PAGE_EXECUTE_READWRITE = $40; { Wert zu Windows äquivalent }
  _PAGE_EXECUTE_WRITECOPY = $80; { Wert zu Windows äquivalent }

function _VirtualAlloc(DestAddr: Pointer; DestSize: Longint; AllocType, ProtectFlags: DWORD): HMemoryModule;
begin
  //in Freepascal  mit GO32 - Memmngr
  //in Delphi-WDOSX mit DPMI - MemMngr
  //implementieren
end;

function MemoryLoadLibraryEx(var ALibrary: TDllFileStruct): HMEMORYMODULE;
var
  Delta : Longint;
  LibSize: Longint;
  LibAddr: Longint;
  AddrPtr: HMemoryModule;
  EffAddr: Longint;
  MemSize: Longint;
  SectionsCount: Integer;
begin
  LibSize := ALibrary.peHeader.OptionalHeader.SizeOfImage;
  LibAddr := ALibrary.peHeader.OptionalHeader.ImageBase;
  AddrPtr := VirtualAlloc(
    Pointer(ALibrary.peHeader.OptionalHeader.ImageBase),
    ALibrary.peHeader.OptionalHeader.SizeOfImage,
    MEM_RESERVE,
    PAGE_READWRITE
  );
  EffAddr := Longint(AddrPtr);

  Delta := EffAddr - ALibrary.peHeader.OptionalHeader.ImageBase;

  { Dieses Delta muss zu den in den Offsets im File addiert werden }

  SectionsCount := ALibrary.peHeader.FileHeader.NumberOfSections;
  Writeln('Anzahl Sectionen: ', SectionsCount);
  EffAddr := LibAddr +  ALibrary.SectionHeader.VirtualAddress;
  MemSize := ALibrary.SectionHeader.SizeOfRawData;
  {
  in Windows:
  NewAddressPointer := VirtualAlloc(EffAddr, ALibrary.SectionHeader.SizeOfRawData, MEM_COMMIT, RAGE_READWRITE);
  Aber für DOS32 Schnittstelle muss anderer Weg beschritten werden:
  }
  Result := HMEMORYMODULE(EffAddr);
  //Jetzt muss relocation folgen
  {
  Offset := SizeOf(dosheader) + SizeOf(dosStub) + SizeOf(peHeader);
  Funcns := SizeOf(SectionHeader) * 4 + Offset;
  }
end;

procedure MemoryFreeLibrary(var ALibrary: HMEMORYMODULE);
begin

  {HeapFree(GetProcessHeap(), 0, ALibrary);}
  Dispose(ALibrary);

end;

const
 DEFAULT_LANGUAGE = 0;

function MemoryFindResource(module: HMEMORYMODULE; lpName,lpType: LPCTSTR): HMEMORYRSRC;
begin
  Result := MemoryFindResourceEx(module, lpName, lpType, DEFAULT_LANGUAGE);
end;

function _MemorySearchResourceEntry(

    var root: Pointer;

    resources: PIMAGE_RESOURCE_DIRECTORY;

    key: LPCTSTR): PIMAGE_RESOURCE_DIRECTORY_ENTRY;

begin
end;

function MemoryFindResourceEx(module: HMEMORYMODULE; lpName,lpType: LPCTSTR; language: WORD): HMEMORYRSRC;
begin
end;

function MemorySizeofResource(module: HMEMORYMODULE; resource: HMEMORYRSRC): DWORD;
begin
end;

function MemoryLoadResource(module: HMEMORYMODULE; resource: HMEMORYRSRC): LPVOID;
begin
end;

function MemoryLoadString(module: HMEMORYMODULE; id: UINT; buffer: LPTSTR; maxsize: Longint): Longint;
begin
end;

function MemoryLoadStringEx(module: HMEMORYMODULE; id: UINT; buffer: LPTSTR; maxsize: Longint; language: WORD): Longint;
begin
end;  

end.
Und hier noch mein Testprogramm:

Delphi-Quellcode:
program LoadDll16;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ULoadDll,
  Convert,
  LibExec in 'LibExec.pas';

var
  MyLib: TDllFileStruct;
  MemModul: HMEMORYMODULE;
begin
  { TODO -oUser -cConsole Main : Insert code here }
  MyLib := LoadLibraryFromFile('Test32dll.dll');
  Writeln('Kennzeichen ',WordToHex(MyLib.dosheader.e_magic));
  Writeln('Anzahl Sections: ', MyLib.peHeader.FileHeader.NumberOfSections);
  Writeln('Zurück mit << E N T E R >> ... ');
  ReadLn;
  MemModul := MemoryLoadLibraryEx(MyLib);
end.
Was mich jetzt wundert, ist, das bei Anzahl Section für diese kleine Dll, die ich zunächst mit Delphi (Turbo Delphi) geschrieben habe, 25954 Sections angezeigt bekomme. Was stimmt da nicht?

Das Programm sollte auch ohne die Unit LibExec übersetzbar sein, falls einer so nett ist, das mal auszuprobieren. LibExec enthält noch mal mit anderen Feldbezeichnern die Headerstrukturen und eine Klassendefinition für das Lesen der Dll. Diese Dinge werden von dem Testprogramm nicht benutzt.

Mich wundert die hohe Anzahl Sections. Und das ist wie gesagt, die 32 Bit Dll.

Die 16 Bit dll, testweise auch nur mit der Hello World Funktion, zeigt mir Null Sections an.

Hat die vielleicht doch einen etwas anderen Aufbau?


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:31 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz