EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

dll2ansi.htm
AnalyzeDLL
CollectNames
Header
PrintLine
PrintNames
SelectNames

DLL2ANSI is convertor which reads exported functions from dynamically-linked library (*.dll ) and writes names of those exported amphibious functions, which have both ANSI and WIDE variant (their names are suffixed with A and W).

Output text can be redirected to a source file winansi which is required by macro WinAPI.


Format
PE 32bit FLAT CON.
Platform
MS Windows 32-bit and 64-bit.
Input
Full path to a PECOFF dynamic library (DLL) specified as a command-line parameter. Core dynamic libraries of Windows API are located in %SystemRoot%\system32\ directory.
Output
Alphabetically sorted list of exported functions.
See also
winansi.htm.
Build
euroasm.exe dll2ansi.htm
Run
dll2ansi.exe %SystemRoot%\system32\kernel32.dll >> ..\maclib\winansi.asm or FOR %a in (*32.dll) DO dll2ansi %a >> winansi.asm
         EUROASM Unicode=off, AutoAlign=on, AutoSegment=on
dll2ansi PROGRAM Format=PE, Width=32, Subsystem=Con, Entry=Main:
         INCLUDEHEAD1 wins.htm, winscon.htm, winapi.htm, winf32.htm,  \
                      sort32.htm, string32.htm, cpuext32.htm,         \
                      ..\easource\pfcoff.htm, ..\easource\pfpe.htm, ..\easource\pfmz.htm

Main:PROC                ; Program entry.
     GetArg 1            ; Return the first argument in ESI,ECX.
     JC Help:            ; If syntax error on command line.
     JECXZ Help:         ; If no argument was provided.
     StripQuotes ESI,ECX ; Get rid of quotes, if they were used.
     FileAssign DllFile,ESI,Size=ECX
     FileLoad DllFile    ; Load the file contents into heap memory.
     JNC AnalyzeDLL:     ; Continue with DLL loaded at ESI,EAX.
     StdOutput ="Error reading file ", DllFile.Name, Eol=Yes
     TerminateProgram Errorlevel=8
Help:StdOutput HelpText
     TerminateProgram Errorlevel=12
     ENDP Main:

DllFile   DS FILE  ; This program uses WinFILE layer.
HelpText: D "Program: dll2ansi.exe",13,10
D "Function:Enumerate function names exported by the DLL with ANSI+WIDE variant.",13,10
D "Version: %^Date",13,10
D "Format:  Windows 32-bit console application.",13,10
D "Licence: Public domain by vitsoft.",13,10
D "Input:   DLL file name specified on the command line.",13,10
D "Output:  List of exported ANSI+WIDE function names.",13,10
D "Example: dll2ansi %%SystemRoot%%\system32\kernel32.dll >> winansi.asm",13,10,0
AnalyzeDLL

DLL file contents will be inspected. This procedure will recognize COFF section which accomodates export directory (usually it is [.edata] or [.text]).

Input
ESI=pointer to the DLL file loaded in memory (also stored in DllFile.BufPtr).
EAX=DLL file size.
NumberOfSections D DWORD  ; Copy of the field NumberOfSection in COFF file header.
AnalyzeDLL: PROC
     LEA EDX,[ESI+EAX] ; DLL contents is now pointed to with ESI..EDX.
     CMPW [ESI+PFMZ_DOS_HEADER.e_magic],'MZ'
     JNE Wrong:   ; If the file is not valid DLL.
     ADD ESI,[ESI+PFMZ_DOS_HEADER.e_lfanew] ; Skip DOS header.
     CMP ESI,EDX  ; Check for a premature end.
     JNB Wrong:   ; If DLL format is damaged.
     LODSD        ; Load PE signature and advance ESI to the COFF file header.
     CMP EAX,'PE'
     JNE Wrong:
     MOVZX EAX,[ESI+PFCOFF_FILE_HEADER.Machine]
     MOVZX EBX,[ESI+PFCOFF_FILE_HEADER.SizeOfOptionalHeader]
     MOVZX ECX,[ESI+PFCOFF_FILE_HEADER.NumberOfSections]
     ADD ESI,SIZE# PFCOFF_FILE_HEADER; ESI now points to the optional header.
     JECXZ NoExport:
     MOV [NumberOfSections],ECX
     ; Recognize the library width.
     CMP AX,pfcoffFILE_MACHINE_IA64
     JE .10:
     CMP AX,pfcoffFILE_MACHINE_AMD64
     JE .10:
     ; DLL is 32bit.
     MOV EDI,[ESI+PFPE_OPTIONAL_HEADER32.DataDirectory + 8*pfpeDIRECTORY_ENTRY_EXPORT + 0]
     MOV ECX,[ESI+PFPE_OPTIONAL_HEADER32.DataDirectory + 8*pfpeDIRECTORY_ENTRY_EXPORT + 4]
     JMP .20:
.10: ; DLL is 64bit.
     MOV EDI,[ESI+PFPE_OPTIONAL_HEADER64.DataDirectory + 8*pfpeDIRECTORY_ENTRY_EXPORT + 0]
     MOV ECX,[ESI+PFPE_OPTIONAL_HEADER64.DataDirectory + 8*pfpeDIRECTORY_ENTRY_EXPORT + 4]
.20: ; EDI is RVA of the export data directory, ECX is its size.
     ; ESI points to optional header, EBX is its size.
     ADD ESI,EBX ; ESI is now the first section header.
.30: MOV EAX,[ESI+PFCOFF_SECTION_HEADER.VirtualAddress]
     CMP EDI,EAX
     JB .40:
     ADD EAX,[ESI+PFCOFF_SECTION_HEADER.SizeOfRawData]
     CMP EDI,EAX
     JB CollectNames: ; If export data directory is in the section specified by header ESI.
.40: ADD ESI,SIZE# PFCOFF_SECTION_HEADER ; Otherwise try the next COFF section.
     DEC [NumberOfSections]
     JZ NoExport: ; If no COFF section is left.
     JMP .30:
NoExport:StdOutput ="No ANSI+WIDE function is exported from ", DllFile.Name, Eol=Yes
     TerminateProgram Errorlevel=4
Wrong:StdOutput DllFile.Name, =" is not in valid DLL format.", Eol=Yes
     TerminateProgram Errorlevel=8
    ENDP AnalyzeDLL:
CollectNames

This procedure will find Name Pointer Table (NPT) which contains pointers to all symbols exported by the DLL. Then it sorts the table by size+name, so names which differ only in the last suffix ~A and ~W are kept together.
Sorting of pointers takes place in the DLL's image loaded in memory.

Input
ESI=pointer to the section header in memory, which hosts export directory table (EDT).
EDI=RVA of EDT.
RVA2PTR DD 0 ; Difference between RVA and pointer to memory where is the DLL loaded.
CollectNames: PROC
     MOV EBX,[DllFile.BufPtr] ; Start of file contents loaded in memory (FA=0).
     ADD EBX,[ESI+PFCOFF_SECTION_HEADER.PointerToRawData] ; Add FA of section data.
     SUB EBX,[ESI+PFCOFF_SECTION_HEADER.VirtualAddress]   ; Subtract RVA of section data.
     MOV [RVA2PTR],EBX                                    ; Remember the difference.
     ADD EDI,EBX  ; EDI is now pointer to Export Directory Table (EDT).
     MOV ECX,[EDI+PFPE_EXPORT_DIRECTORY.NumberOfNames]
     MOV ESI,[EDI+PFPE_EXPORT_DIRECTORY.AddressOfNames]
     ADD ESI,EBX  ; ESI is now pointer to Name Pointer Table (NPT) in memory.
     ; Sort NPT (array of ECX DWORD pointers to ASCIIZ names) pointed to by ESI.
     ShellSort ESI,ECX,4,BySize ; Macro from the library sort32.htm.
BySize: PROC1 ; Callback to compare ASCIIZ names pointed to by ESI and EDI.
       PUSH ECX
         MOV EAX,[EDI]
         ADD EAX,[RVA2PTR]
         GetLength$ EAX    ; Return the size of ASCIIZ string in ECX.
         MOV EDX,ECX
         MOV EAX,[ESI]
         ADD EAX,[RVA2PTR]
         GetLength$ EAX
         CMP ECX,EDX       ; Compare string sizes.
         JB .Ordered:
         JA .Swapped:
         PUSH ESI,EDI      ; Equal size of both string. Compare them.
           MOV ESI,[ESI]
           MOV EDI,[EDI]
           ADD ESI,[RVA2PTR]
           ADD EDI,[RVA2PTR]
           REPE:CMPSB
         POP EDI,ESI
         JB .Ordered:
.Swapped:LODSD ; Entered with CF=0, fn names are in wrong order.
         MOV EDX,[EDI]
         STOSD
         MOV [ESI-4],EDX  ; Swap pointers pointed to by ESI,EDI.
.Ordered:CMC   ; Entered with CF=1, the order of fn names complies.
       POP ECX
       RET
      ENDP1 BySize:
     ENDP CollectNames    ; Continue with SelectNames:.
SelectNames

Sorted names of all exports are examinated for the presence of ANSI and WIDE variant. Pointers to compliant names will be stored to a dynamically allocated table EXPtab.
Table EXPtab is then sorted again, alphabetically.

Input
EBX= RVA2PTR - difference between RVA and pointer to memory where is the DLL loaded.
ECX=number of DWORDs in NPT.
ESI=pointer to NPT, i. e. array of DWORDs to all exported ASCIIZ fn names.
Output
Table of DWORDs EXPtab..EXPptr is filled with pointers to amphibious fn names, sorted alphabetically.
NPTtop DD 0 ; Pointer beyond the last DWORD in NPT.
EXPtab DD 0 ; EXP table contains DWORD pointers to amphibious ASCIIZ fn names.
EXPptr DD 0 ; Pointer to the next free DWORD in EXPtab.
SelectNames:: PROC
      SAL ECX,2         ; Size of NPT in bytes.
      LEA EAX,[ESI+ECX] ; Pointer to the top of NPT.
      MOV [NPTtop],EAX
      WinAPI GlobalAlloc,GMEM_FIXED,ECX ; Allocate the room for pointers to selected names.
      MOV [EXPtab],EAX
      MOV [EXPptr],EAX
      TEST EAX
      JZ Wrong:    ; If unexpected allocation error.
      SUB ESI,4    ; Loop through the sorted NPT and search for termination with ~A and ~W.
.10:  ADD ESI,4    ; Search for the next amphibious fn name.
      MOV EAX,[NPTtop]
      SUB EAX,4
      CMP ESI,EAX
      JNB .70:     ; If no more names.
      MOV EAX,[ESI]
      MOV EDI,[ESI+4]
      ADD EAX,EBX
      ADD EDI,EBX  ; EAX and EDI now point to the two neibourghing names.
      GetLength$ EAX
      MOV EDX,ECX
      GetLength$ EDI
      CMP ECX,EDX
      JNE .10:     ; If they have different lengths, search further.
      DEC ECX      ; Let [EAX+ECX] and [EDI+ECX]  point to their last characters.
      CMPB [EAX+ECX],'A'
      JNE .10:
      CMPB [EDI+ECX],'W'
      JNE .10:
      MOV EDX,EAX  ; Save pointer to possible amphbious fn name.
      XCHG EAX,ESI ; ESI,EDI now point to same-length names terminated with A and W.
      REPE:CMPSB
      XCHG ESI,EAX
      JNE .10:     ; If they are different, search further.
      MOV EDI,[EXPptr]
      MOV EAX,EDX  ; EDX is now pointer to amphibious ASCIIZ function name.
      STOSD        ; Store name pointed to with EDX to EXPtab.
      MOV [EXPptr],EDI
      ADD ESI,4    ; Skip the stored pair.
      JMP .10:     ; Continue searching.
.70:  ; All amphibious names are selected now to EXPtab.
      MOV ESI,[EXPtab]
      MOV ECX,[EXPptr]
      SUB ECX,ESI
      SAR ECX,2     ; ECX is now the number of names.
      ShellSort ESI,ECX,4,ByName
ByName:PROC1 ; Callback to compare ASCIIZ names pointed to by ESI and EDI.
       PUSH ECX
         MOV EAX,[EDI]
         GetLength$ EAX
         MOV EDX,ECX
         MOV EAX,[ESI]
         GetLength$ EAX
         CMP ECX,EDX
         JLE .Short:
         MOV ECX,EDX
  .Short:DEC ECX  ; Compare only in the size of the shorter name.
         JS .Ordered:
         PUSH ESI,EDI
           MOV ESI,[ESI]
           MOV EDI,[EDI]
           REPE:CMPSB
         POP EDI,ESI
         JB .Ordered:
         LODSD ; Entered with CF=0.
         MOV EDX,[EDI]
         STOSD ; Swap name pointers.
         MOV [ESI-4],EDX
.Ordered:CMC   ; Entered with CF=1.
       POP ECX
       RET
      ENDP1 ByName:
     ENDP SelectNames:  ; Continue with PrintNames:.
PrintNames

This procedure writes the list of exported names from EPTtab to the standard output formated to lines. Then it terminates the program.

Input
ECX=number of DWORDs in EPTtab.
Line    D 128*BYTE ; Room where the printed line is compiled.
LinePtr D D        ; Pointer to the next free position in Line.
Number  D 12*BYTE  ; Room for the ASCIIZ number of amphibious functions exported by this DLL.
Wrap    EQU 78     ; Line size where it wraps.
PrintNames:: PROC
      MOV EAX,Line
      MOV [LinePtr],EAX ; Start with empty line.
      ; The first output line is a comment.
      MOV EAX,ECX  ; Number of amphibious functions.
      MOV EDI,Number
      StoD EDI
      SUB EAX,EAX
      STOSB
      LEA EDX,[DllFile.Name]     ; EDX now points to ASCIIZ DLL path.
      ADD EDX,[DllFile.NameOffs] ; EDX now points to ASCIIZ DLL name without path.
      StdOutput =B"   \ ",Number,=B" ANSI+WIDE functions exported by ",EDX,=B":",Eol=Yes
      ; Print export names in a loop, wrap when line size approaches Wrap.
      MOV ESI,[EXPtab]
.10:  CMP ESI,[EXPptr]
      JAE .90:        ; If the last fn has been written.
      LODSD           ; Load pointer to ASCIIZ fn name and advance ESI to the next name.
      GetLength$ EAX
      DEC ECX         ; Get rid of the last character A or W.
      MOV EDI,[LinePtr]
      LEA EDX,[EDI+ECX]
      SUB EDX,Line
      CMP EDX,Wrap
      JB .20:         ; Skip to .20: if Wrap would not be overrun yet.
      CALL PrintLine: ; Terminate Line contents with line-continuation \ and CR+LF.
      MOV EDI,[LinePtr]
.20:  XCHG EAX,ESI
      REP:MOVSB
      XCHG ESI,EAX
      MOV AL,','      ; Terminate each name with comma ,.
      STOSB
      MOV [LinePtr],EDI
      JMP .10:
.90: CALL PrintLine:  ; Finish the last line.
     ; The final cleaning.
     WinAPI GlobalFree,[EXPtab]
     FileClose [DllFile]
     TerminateProgram  Errorlevel=0
    ENDP PrintNames:
PrintLine

This procedure will pad the unused room in Line with spaces, complete the line with a line-continuation character \+CR+LF and write the Line on the standard output.

Called from
PrintNames
PrintLine: PROC
      PUSHAD
       MOV ECX,Wrap ; Calculate the number of spaces to pad the line.
       MOV EDX,Line
       MOV EDI,[LinePtr]
       ADD ECX,EDX
       SUB ECX,EDI
       JNA .50:
       MOV AL,' '
       REP:STOSB    ; Pad with spaces.
.50:   MOV AL,'\'   ; Continuation character is right-justified.
       STOSB
       SUB EDI,EDX  ; Printed line size.
       StdOutput EDX,Size=EDI,Eol=Yes
       MOV [LinePtr],EDX ; Reinitializate the Line.
      POPAD
      RET
     ENDP PrintLine:
   ENDPROGRAM dll2ansi

▲Back to the top▲