| Index | Manual | Download | Source | Macros | Embedded word Case ins.
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`

Header

  The header defines program format, reads the command-line parameter and loads the processed DLL to memory with macro FileLoad . Inspection of DLL format will use definition of PECOFF headers, whose structures are borrowed from EuroAssembler source files pf*.htm included to this program.

  All used WinAPI invocations are in the default library kernel32.dll, no import library is linked.

  This sample program also demonstrates the feature `EUROASM AUTOSEGMENT=ON` . No explicit section switching is used here.

             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▲