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 32bit and 64bit.
Input
Full path to a PECOFF dynamic library (DLL) specified as 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, winfile.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 DLL with ANSI+WIDE variant.",13,10
D "Version: %^Date",13,10
D "Format:  Windows 32bit console application.",13,10
D "Licence: Public domain by vitsoft.",13,10
D "Input:   DLL file name specified on 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 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 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_HEADER.DataDirectory + 8*pfpeDIRECTORY_ENTRY_EXPORT + 0]
     MOV ECX,[ESI+PFPE_OPTIONAL_HEADER.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 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 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 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 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 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 on 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 unused room in Line with spaces, complete the line line-continuation character \+CR+LF and write the Line on standard output.

Called from
PrintNames
PrintLine: PROC
      PUSHAD
       MOV ECX,Wrap ; Calculate 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▲