From: malkia
Subject: Simple lisp program that reads a DLL and prints all exported symbols
Date: 
Message-ID: <1190189490.840758.233940@v23g2000prn.googlegroups.com>
Just a simple stuff I wrote in an matter of an hour (trying to
understand how to decode a PE executable file).

This program here, would read any Windows DLL and printout the export
symbols (much like the venerable DEPENDS.EXE)

(defun load-binary-file (filename)
  (with-open-file (file filename
                        :direction :input
                        :element-type '(unsigned-byte 8))
    (let* ((buffer-size (file-length file))
           (buffer (make-array buffer-size :element-type '(unsigned-
byte 8)))
           (readed (read-sequence buffer file)))
      (assert (= readed buffer-size))
      buffer)))

(defun aref-le32 (a o)
  (+ (ash (aref a (+ o 0)) 0)
     (ash (aref a (+ o 1)) 8)
     (ash (aref a (+ o 2)) 16)
     (ash (aref a (+ o 3)) 24)))

(defconstant +pe-rva+
  '((:export-table            . 96)
    (:import-table            . 104)
    (:resource-table          . 112)
    (:exception-table         . 120)
    (:certificate-table       . 128)
    (:base-relocation-table   . 136)
    (:debug                   . 144)
    (:architecture            . 152)
    (:global-pointer          . 160)
    (:tls-table               . 168)
    (:load-config-table       . 176)
    (:bound-import            . 184)
    (:import-address-table    . 192)
    (:delay-import-descriptor . 200)
    (:com+-runtime-header     . 208)
    (:reserved                . 216)))

(defun string-from-cstring (buffer offset)
  (loop for n from 0 below (length buffer)
        do (when (= (aref buffer (+ offset n)) 0)
             (let ((string (make-string n)))
               (loop for m from 0 below n
                     do (setf (aref string m)
                              (code-char (aref buffer (+ offset m)))))
               (return-from string-from-cstring string)))))

(defun list-dll-symbols (pe-buffer offset)
  (let* ((symbol-text   (aref-le32 pe-buffer (+ offset 12)))
         (symbol-count  (aref-le32 pe-buffer (+ offset 20)))
         (symbol-count2 (aref-le32 pe-buffer (+ offset 24)))
         (symbol-table  (aref-le32 pe-buffer (+ offset 32))))
    (format t "offset        ~X~&" offset)
    (format t "symbol-text   ~X~&" symbol-text)
    (format t "symbol-count  ~X~&" symbol-count)
    (format t "symbol-count2 ~X~&" symbol-count2)
    (format t "symbol-table  ~X~&" symbol-table)
    (dotimes (n symbol-count)
      (format t "~A ~A~&" n
              (string-from-cstring pe-buffer
                                   (aref-le32 pe-buffer (+ symbol-
table (* n 4))))))))

(defun load-dll (filename)
  (let* ((pe-buffer (load-binary-file filename))
         (pe-header (aref-le32 pe-buffer #x3c))
         (pe32+ (if (= #x20b (aref-le16 pe-buffer (+ pe-header 8))) 16
0)))
    (format t "pe-header               ~X~&" pe-header)
    (format t "pe32+                   ~X~&" pe32+)
    (dotimes (n (length +pe-rva+))
      (let ((addr (aref-le32 pe-buffer (+ pe-header pe32+ (cdr (nth n
+pe-rva+)) 0)))
            (size (aref-le32 pe-buffer (+ pe-header pe32+ (cdr (nth n
+pe-rva+)) 4))))
        (format t "ADDR=~X SIZE=~X ~A~&" addr size (car (nth n +pe-rva
+)))))
    (list-dll-symbols pe-buffer
                      (aref-le32 pe-buffer (+ pe-header pe32+
                                              (cdr (assoc :exception-
table +pe-rva+)))))))

#+nil
(load-dll "C:/Program Files/Safari/CoreFoundation.dll")

#+nil
(load-dll "C:/Program Files/Safari/CFNetwork.dll")

#+nil
(load-dll "C:/Program Files/Safari/CoreGraphics.dll")

#+nil
(load-dll "C:/Program Files/Safari/PubSubDLL.dll")

From: Rainer Joswig
Subject: Re: Simple lisp program that reads a DLL and prints all exported symbols
Date: 
Message-ID: <joswig-44766F.11052819092007@news-europe.giganews.com>
In article <························@v23g2000prn.googlegroups.com>,
 malkia <······@gmail.com> wrote:

> Just a simple stuff I wrote in an matter of an hour (trying to
> understand how to decode a PE executable file).
> 
> This program here, would read any Windows DLL and printout the export
> symbols (much like the venerable DEPENDS.EXE)
> 
> (defun load-binary-file (filename)
>   (with-open-file (file filename
>                         :direction :input
>                         :element-type '(unsigned-byte 8))
>     (let* ((buffer-size (file-length file))
>            (buffer (make-array buffer-size :element-type '(unsigned-
> byte 8)))
>            (readed (read-sequence buffer file)))
>       (assert (= readed buffer-size))
>       buffer)))
> 
> (defun aref-le32 (a o)
>   (+ (ash (aref a (+ o 0)) 0)
>      (ash (aref a (+ o 1)) 8)
>      (ash (aref a (+ o 2)) 16)
>      (ash (aref a (+ o 3)) 24)))
> 
> (defconstant +pe-rva+
>   '((:export-table            . 96)
>     (:import-table            . 104)
>     (:resource-table          . 112)
>     (:exception-table         . 120)
>     (:certificate-table       . 128)
>     (:base-relocation-table   . 136)
>     (:debug                   . 144)
>     (:architecture            . 152)
>     (:global-pointer          . 160)
>     (:tls-table               . 168)
>     (:load-config-table       . 176)
>     (:bound-import            . 184)
>     (:import-address-table    . 192)
>     (:delay-import-descriptor . 200)
>     (:com+-runtime-header     . 208)
>     (:reserved                . 216)))
> 
> (defun string-from-cstring (buffer offset)
>   (loop for n from 0 below (length buffer)
>         do (when (= (aref buffer (+ offset n)) 0)
>              (let ((string (make-string n)))
>                (loop for m from 0 below n
>                      do (setf (aref string m)
>                               (code-char (aref buffer (+ offset m)))))
>                (return-from string-from-cstring string)))))
> 
> (defun list-dll-symbols (pe-buffer offset)
>   (let* ((symbol-text   (aref-le32 pe-buffer (+ offset 12)))
>          (symbol-count  (aref-le32 pe-buffer (+ offset 20)))
>          (symbol-count2 (aref-le32 pe-buffer (+ offset 24)))
>          (symbol-table  (aref-le32 pe-buffer (+ offset 32))))
>     (format t "offset        ~X~&" offset)
>     (format t "symbol-text   ~X~&" symbol-text)
>     (format t "symbol-count  ~X~&" symbol-count)
>     (format t "symbol-count2 ~X~&" symbol-count2)
>     (format t "symbol-table  ~X~&" symbol-table)
>     (dotimes (n symbol-count)
>       (format t "~A ~A~&" n
>               (string-from-cstring pe-buffer
>                                    (aref-le32 pe-buffer (+ symbol-
> table (* n 4))))))))
> 
> (defun load-dll (filename)
>   (let* ((pe-buffer (load-binary-file filename))
>          (pe-header (aref-le32 pe-buffer #x3c))
>          (pe32+ (if (= #x20b (aref-le16 pe-buffer (+ pe-header 8))) 16
> 0)))
>     (format t "pe-header               ~X~&" pe-header)
>     (format t "pe32+                   ~X~&" pe32+)
>     (dotimes (n (length +pe-rva+))
>       (let ((addr (aref-le32 pe-buffer (+ pe-header pe32+ (cdr (nth n
> +pe-rva+)) 0)))
>             (size (aref-le32 pe-buffer (+ pe-header pe32+ (cdr (nth n
> +pe-rva+)) 4))))
>         (format t "ADDR=~X SIZE=~X ~A~&" addr size (car (nth n +pe-rva
> +)))))
>     (list-dll-symbols pe-buffer
>                       (aref-le32 pe-buffer (+ pe-header pe32+
>                                               (cdr (assoc :exception-
> table +pe-rva+)))))))
> 
> #+nil
> (load-dll "C:/Program Files/Safari/CoreFoundation.dll")
> 
> #+nil
> (load-dll "C:/Program Files/Safari/CFNetwork.dll")
> 
> #+nil
> (load-dll "C:/Program Files/Safari/CoreGraphics.dll")
> 
> #+nil
> (load-dll "C:/Program Files/Safari/PubSubDLL.dll")

And? What does it print? Why not show an example. Not everybody
has Windows. ;-)

A few minor remarks:

* you may want to use a Usenet reader that does not add newlines
  when posting code with 'long' lines

* you might want to compare it to a version
  that does not read the whole file, but uses
  FILE-POSITION and READ-SEQUENCE. You can set a
  file position and READ-SEQUENCE takes a start and
  end argument.
  I may not be worth the trouble for this example,
  but if you want to analyze larger files (like movies)
  it might help.

* You might want to add documentation strings.

* I would rename LOAD-BINARY-FILE to READ-BINARY-FILE.
  All you do is reading.

-- 
http://lispm.dyndns.org
From: Dimiter "malkia" Stanev
Subject: Re: Simple lisp program that reads a DLL and prints all exported symbols
Date: 
Message-ID: <5le6riF7r6rdU1@mid.individual.net>
> And? What does it print? Why not show an example. Not everybody
> has Windows. ;-)

Heh, it just prints the exported symbols from any DLL.

> A few minor remarks:
> 
> * you may want to use a Usenet reader that does not add newlines
>   when posting code with 'long' lines

Yes, unfortunately I'm not sure how to setup The Mozilla to do that, and 
the previous email was sent directly from groups.google.com

> * you might want to compare it to a version
>   that does not read the whole file, but uses
>   FILE-POSITION and READ-SEQUENCE. You can set a
>   file position and READ-SEQUENCE takes a start and
>   end argument.

That is reasonable, but for the stuff that right now I'm interrested, it 
would only complicate the bits (might add it later).

>   I may not be worth the trouble for this example,
>   but if you want to analyze larger files (like movies)
>   it might help.

Or some large executables produced by LispWorks (no pun intended, it's 
okay for LispWorks to create such executables, after all, it's a 
complete Common Lisp + Compiler).

> * You might want to add documentation strings.
 >
> * I would rename LOAD-BINARY-FILE to READ-BINARY-FILE.
>   All you do is reading.

Too much C in me I guess, I used to call in my tools everything starting 
with save- and load- when comes to full load save, and read to partial, 
but I would definitely need to make the change, as load means other 
stuff in CL (loading forms, loading code, etc.).

Thanks for the remarks, Rainer!
From: Slobodan Blazeski
Subject: Re: Simple lisp program that reads a DLL and prints all exported symbols
Date: 
Message-ID: <1190548645.252696.180330@o80g2000hse.googlegroups.com>
It lokks like nifty tool . I will try it thanks.

bobi
From: Dimiter "malkia" Stanev
Subject: Re: Simple lisp program that reads a DLL and prints all exported symbols
Date: 
Message-ID: <5le6ikF7q8qiU1@mid.individual.net>
; Much shorter version, and more to the point (the previous was just the 
product of exploration how the stuff works).

(defun aref-le32 (a o)
   (+ (ash (aref a (+ o 0)) 0)
      (ash (aref a (+ o 1)) 8)
      (ash (aref a (+ o 2)) 16)
      (ash (aref a (+ o 3)) 24)))

(defun aref-le16 (a o)
   (+ (ash (aref a (+ o 0)) 0)
      (ash (aref a (+ o 1)) 8)))

(defun string-from-cstring (buffer offset)
   (loop for n from 0 below (length buffer)
         do (when (= (aref buffer (+ offset n)) 0)
              (let ((string (make-string n)))
                (loop for m from 0 below n
                      do (setf (aref string m)
                               (code-char (aref buffer (+ offset m)))))
                (return-from string-from-cstring string)))))

(defun get-dll-symbols (filename)
   (with-open-file (file filename :element-type'(unsigned-byte 8))
     (let* ((buffer-size (file-length file))
            (buffer (make-array buffer-size
                                :element-type '(unsigned-byte 8)))
            (readed (read-sequence buffer file)))
       (assert (= readed buffer-size))
       (let* ((pe-offset (aref-le32 buffer #x3C))
              (pe-extra-offset
               (if (= #x20B (aref-le16 buffer (+ pe-offset 8))) 16 0))
              (symbol-offset
               (aref-le32 buffer (+ pe-offset pe-extra-offset 120)))
              (symbol-count (aref-le32 buffer (+ symbol-offset 20)))
              (symbol-table (aref-le32 buffer (+ symbol-offset 32)))
              (symbols))
         (dotimes (n symbol-count)
           (push (string-from-cstring
                  buffer
                  (aref-le32 buffer (+ symbol-table (* n 4))))
           symbols))
         (nreverse symbols)))))

#+nil
(get-dll-symbols "C:/Program Files/Safari/CoreFoundation.dll")

#+nil
(get-dll-symbols "C:/Program Files/Safari/CFNetwork.dll")

#+nil
(get-dll-symbols "C:/Program Files/Safari/CoreGraphics.dll")

#+nil
(get-dll-symbols "C:/Program Files/Safari/PubSubDLL.dll")
From: Dimiter "malkia" Stanev
Subject: Re: Simple lisp program that reads a DLL and prints all exported   symbols
Date: 
Message-ID: <5lecq3F7isspU1@mid.individual.net>
I've added this in LispWorks that would allow you to have minimal 
selection box interface with the function name, and clicking on it would 
open google.com to search for the name of the exported function

#+lispworks
(capi:contain
  (make-instance
   'capi:list-panel
   :items (get-dll-symbols
           "C:/Program Files/Safari/CoreGraphics.dll")
   :selection-callback
   (lambda (data interface)
     (system:open-url
      (concatenate 'string
                   "http://www.google.com/search?q="
                   data)))))
From: GP lisper
Subject: Re: Simple lisp program that reads a DLL and prints all exported symbols
Date: 
Message-ID: <slrnff53gv.via.spambait@phoenix.clouddancer.com>
On Wed, 19 Sep 2007 20:09:06 -0700, <······@gmail.com> wrote:
> ; Much shorter version, and more to the point (the previous was just the 
> product of exploration how the stuff works).


Trying this on something common such as MSVCRT.DLL,

   [Condition of type SIMPLE-ERROR]

Restarts:
  0: [ABORT] Return to Top-Level.

Debug  (type H for help)

(LISP::%ARRAY-ROW-MAJOR-INDEX #(77 90 144 0 3 ...) (1699881070) T)
Source: 
; File: target:code/array.lisp
(ERROR "Invalid index ~D in ~S" INDEX ARRAY)
0] :0

in cmucl

-- 
One of the strokes of genius from McCarthy was making lists the center of the language - kt

-- 
Posted via a free Usenet account from http://www.teranews.com
From: verec
Subject: Re: Simple lisp program that reads a DLL and prints all exported symbols
Date: 
Message-ID: <46f4d2e1$0$766$5a6aecb4@news.aaisp.net.uk>
On 2007-09-20 04:09:06 +0100, "Dimiter \"malkia\" Stanev" 
<······@gmail.com> said:

> (defun get-dll-symbols (filename)
[...]

> #+nil
> (get-dll-symbols "C:/Program Files/Safari/PubSubDLL.dll")

I'm on a similar exploration path with Mach-O files, and I'm
using Peter Seibel binary files parser classes (ch, 24 & 25
of Practical Common Lisp) with mush success.

I do not know how far you intend to push your exploration
of the COFF format, but a set of tools like the ones those
classes provide are a great help to be quickly done with
the lowest level stuff and start looking a bit more into
the interesting bits :-)
--
JFB