\documentclass[11pt,a4paper]{article} % save as utf-8-emacs-unix % language support \usepackage[german]{babel} %\usepackage{german} \usepackage[utf8]{inputenc} % can use Umlauts now ü instead of "u \usepackage{url} % \url{} \path{} with correct "hyphenation" \parindent=0pt \begin{document} \title{Anzeigen von Strukturen} \author{Filippo Sala} \maketitle \begin{abstract}\itshape Dieser Artikel befasst sich mit dem Anlegen und Anzeigen von Strukturen. Wenn man mit Strukturen arbeitet, benötigt man ein Werkzeug zum Anzeigen der Strukturen. Das Wort \texttt{DUMP} ist hierfür unzureichend. Das Aufrufen der einzelnen Feldnamen enorm zeitaufwändig. Die Redefinition der Strukturworte \texttt{STRUCTUR}, \texttt{FIELD} und \texttt{ENDSTRUCTUR} löst das Problem optimal und 100\% Forth--gemäß! Als praktische Anwendung wird das Programm \texttt{DUMPPEH.4TH} vorgestellt. Es zeigt die Struktur des Programmkopfes und die importierten Funktionen einer EXE--Datei oder DLL an. Eine solche Datei wird PE--Datei (portable executable\footnote{\url{http://de.wikipedia.org/wiki/Portable_Executable}}) genannt. \end{abstract} \begin{multicols}{2} \section{Einiges über Strukturen} Strukturen sind bekanntlich eine Erweiterung des Datentyps Array. Die Struktur--Elemente sind über Namen erreichbar und können unterschiedlich lang sein. Die Struktur--Definition benutzt ausgiebig die Methode \texttt{CREATE .... DOES>}. Wenn eine Struktur--Datei geladen wird, wird ein Prototyp der Struktur angelegt. Der CREATE--Teil kreiert neue Worte, und zwar den Struktur--Bezeichner (\texttt{BNME}) und alle Feldname (\texttt{FNAME}). Zwei Tatsachen sind besonders hervorzuheben: \begin{itemize} \item Im Body (Wortkörper) von \texttt{BNAME} ist die Länge der Struktur gespeichert. \item Im Body von \texttt{FNAME} ist der Offset des Feldnames gespeichert. \end{itemize} Die Ausführung von \texttt{FNAME} (\texttt{DOES>}--Teil) bringt somit die Feldname--Adresse auf den Stack. \begin{quote} \begin{small} \begin{verbatim} FNAME ( adr dfa ) @ + ( adr+ofs ) \end{verbatim} \end{small} \end{quote} Der Parameter adr ist die Anfangsadresse der strukturierten Daten, die sich im Speicher befinden. Der Parameter dfa (data field address) ist die ANSForth--Bezeichnung für den Body. Befinden sich im Speicher keine Daten, so muss die Struktur erst mal mit Hilfe des Struktur--Bezeichners angelegt werden. Mit \begin{quote} \begin{small} \begin{verbatim} BNAME ( "sname" dfa) @ char allot \end{verbatim} \end{small} \end{quote} wird der Struktur--Name \texttt{SNAME} kreiert und Speicherplatz reserviert. Mit \begin{quote} \begin{small} \begin{verbatim} SNAME FNAME ( adr dfa ) @ + ( adr+ofs ) \end{verbatim} \end{small} \end{quote} wird schließlich die Feldname--Adresse auf den Stack gebracht. \section{Einiges über Windows} Ein Windows--Header besteht aus mehreren Strukturen. Sie sind z. B. in MASM (Microsoft--Assembler) in der Datei \texttt{WINDOWS.INC} zu finden. Es sind 4 Strukturen und sie heißen \texttt{DOS\_HEADER}, \texttt{NTFILE\_HEADER}, \texttt{OPTIONAL\_HEADER} und \texttt{SECTION\_HEADER}. Der \texttt{OPTIONAL\_HEADER} muss, trotz seines Namens, immer vorhanden sein. Der \texttt{SECTION\_HEADER} ist am wichtigsten. Er zeigt die Beschaffenheit der einzelnen Sektionen. Die 2 Sektionen TEXT (oder CODE) und DATA müssen immer vorhanden sein. Die kleinste Blockgröße im Speicher (Granularität) beträgt 4096 Bytes und somit, obwohl der Programmkopf maximal ca. 1000 Bytes belegt, beginnt die Text--Sektion bei Offset 4096. Jede Sektion belegt 4096 Bytes oder ein Vielfaches davon. Die Programme werden an die virtuelle Adresse 400000H (preferred base address) geladen. Mit der Linker--Option \texttt{/FIXED} kann man eine andere Basis--Adresse vorschreiben. Wegen der Granularität liegt das erste Code--Byte bei 401000H. Zu Beginn des Programmkopfes steht der (alte) \texttt{DOS--HEADER}. Er ist daher wegen zweier Tatsachen wichtig. Das erste Feld \texttt{e\_magic} mit dem magic byte `MZ' zeigt, dass es sich um einen Programmkopf handelt. Das letzte Feld \texttt{e\_lfanew} liefert den Offset zum \texttt{NTFILE--HEADER}. \section{Programm--Beschreibung} Zuerst werden die Strukturworte definiert. Die Datei mit den Strukturen \texttt{PE.INC} wird danach geladen und somit werden die Struktur--Prototypen angelegt. Alle Struktur--Elemente bekommen einen Namen. Anschließend wird der Windows--Programmkopf in den Speicher geladen und werden Worte definiert, die die Zeiger zu den einzelnen Strukturen liefern. Der Offset der einzelnen Strukturen ist entweder bekannt oder er lässt sich berechnen. Die Strukturworte \texttt{STRUCTUR}, \texttt{FIELD} und \texttt{ENDSTRUCTUR} werden jetzt redefiniert und die Datei \texttt{PE.INC} wird erneut geladen. Die zweite Definition bewirkt, dass die Strukturen, statt erneut angelegt, jetzt angezeigt werden. Das Programm ist ANSForth--kompatibel und wurde mit Win32for und Bigforth getestet. \section{Anwendungsbeispiel für Win32For} Verzeichnis \texttt{DEMOS\char`\\WINHEADER\char`\\} anlegen mit den Dateien: \begin{itemize} \item DUMPPEH.4TH --- das Programm \item PE.INC --- die Strukturen \item DUMPWORD.4TH --- das Anwendungswort \end{itemize} Datei DUMPWORD.4TH einlesen. Dabei werden folgende Worte definiert: \begin{quote} \begin{small} \begin{verbatim} : includepath_dump ( -- str len ) s" demos\winheader\dumppeh.4th" ; : includepath_pe ( -- str len ) s" demos\winheader\pe.inc" ; CREATE path\name 64 chars allot : DUMPPEH ( "name" -- ) nostack ( nur für win32for ) bl word count path\name place includepath_dump INCLUDED ; \end{verbatim} \end{small} \end{quote} Mit dem Aufruf \texttt{dumppeh "name"} wird die Programmkopf--Struktur von ``name'' angezeigt. Beispiele: \begin{quote} \begin{small} \begin{verbatim} dumppeh win32for.exe dumppeh wincon.dll dumppeh c:\windows\notepad.exe dumppeh .....\bigforth.exe. dumppeh .....\gforth.exe dumppeh .....\zf.exe \end{verbatim} \end{small} \end{quote} \end{multicols} \section{Listing: pe.inc} \begin{quote} \begin{small} \listinginput[1]{1}{2011-02/pe.fin} \end{small} \end{quote} \section{Listing: dumppeh.4th} \begin{quote} \begin{small} \listinginput[1]{1}{2011-02/dumppeh.4th} \end{small} \end{quote} \section{Listing: dumpword.4th} \begin{quote} \begin{small} \listinginput[1]{1}{2011-02/dumpword.4th} \end{small} \end{quote} \end{document}