News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Importing DLLs properly

Started by scolby33, July 30, 2009, 06:11:39 PM

Previous topic - Next topic

scolby33

I am working on this to learn how to call DLLs that are not Windows-standard. I am using Steve Gibson's Perfect Paper Passwords (PPP) library from http://www.grc.com/ppp/pppdll.htm. On that page are the functions and the arguments they take. I made my own protos from this documentation because there is no include file that comes with the dll, only the dll and a library. The problem is, when I try to put this through the linker, I get 2 unresolved external LNK2001 errors (For GenerateRandomSequenceKey and RetrievePasscodes), even though I have the library (in the correct directory) and the protos included. What am I doing wrong?
Also, is it possible to send the output of input directly to a variable instead of with mov, lea, mov? (It will probably assemble to that anyway, but it would make the code clearer.)

include \masm32\include\masm32rt.inc

includelib ppp.lib  ;Steve Gibson's PPP Lib

;There is no .inc file with the lib, so I made my own protos. (Based on http://www.grc.com/ppp/pppdll.htm)
GenerateRandomSequenceKey   proto c :DWORD
RetrievePasscodes           proto c :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD

.data?
    passcodechars   db  ?
    firstpasscodeno db  ?
    passcodecount   db  ?
    sequencekey     db  ?
    passcodelength  db  ?

.const
    characterset    db  "!#%+23456789:=?@ABCDEFGHJKLMNPRSTUVWXYZabcdefghijkmnopqrstuvwxyz",0
    AppName         db  "PPP DLL Test",0

.code

start:

invoke AllocConsole
SetConsoleCaption addr AppName

print "Prepare to enter parameters...",13,10
mov edi, input("Enter First Passcode Number: ")
lea eax, firstpasscodeno
mov [eax],edi
mov edi, input("Enter Passcode Count: ")
lea eax, passcodecount
mov [eax], edi
mov edi, input("Enter Passcode Length: ")
lea eax, passcodelength
mov [eax], edi

invoke GenerateRandomSequenceKey,addr sequencekey

invoke RetrievePasscodes,addr passcodechars,addr firstpasscodeno,addr passcodecount,addr sequencekey,addr characterset,addr passcodelength

print addr passcodechars

inkey "Operation Finished. Press a key to exit..."

invoke FreeConsole

invoke ExitProcess,0

end start

bruce1948

I notice from the site that:

QuoteIt follows 'C' naming conventions and PASCAL calling conventions.

I'm not to clear on how to declare and call with PASCAL calling conventions but it's definitely something you should take into account.

Vortex

MASM Programmer's Guide : Mixed-Language Programming

http://webster.cs.ucr.edu/Page_TechDocs/MASMDoc/ProgrammersGuide/Chap_12.htm

QuoteMASM supports several different conventions. The assembler uses C convention when you specify a language type (langtype) of C, and Pascal convention for language types PASCAL, BASIC, or FORTRAN. To the assembler, the keywords BASIC, PASCAL, and FORTRAN are synonymous. MASM also supports the SYSCALL and STDCALL conventions, which mix elements of the C and Pascal conventions.

scolby33

"C" naming convention is like this: MyFunction, with every first letter capitalized. PASCAL calling convention seems to be parameters are pushed by the caller but the stack is cleaned up by the callee. It is unclear, however, weather the parameters are pushed left-to-right or right-to-left. In the declaration RetrievePasscodes proto c :DWORD,.... the"c" should take care of that, but I'm not sure.

Edit: On the site, he says parameters are passed right-to-left, which is what I am doing in the code. Since he specifies PASCAL calling, should I change my proto directive?

MichaelW

PPP.DLL appears to be a standard DLL that uses STDCALL, and PPP.LIB is an import library. I'm not sure why he chose to confuse the user with the mixed description. Including the import library with the includelib directive causes the linker to include information in the EXE that the system will use to perform Load-Time Dynamic Linking.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
    includelib ppp.lib

    GenerateRandomSequenceKey proto :DWORD
    ConvertAsciiTo128BitDecimal proto :DWORD,:DWORD

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      sequenceKeyBuffer db 32 dup(0)
      binaryBuffer      db 16 dup(0)
      asciiString       db "012345678901234567890123456789",0
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    REPEAT 2
      invoke GenerateRandomSequenceKey, ADDR sequenceKeyBuffer
      print uhex$(DWORD PTR sequenceKeyBuffer),13,10
      print uhex$(DWORD PTR sequenceKeyBuffer+4),13,10
      print uhex$(DWORD PTR sequenceKeyBuffer+8),13,10
      print uhex$(DWORD PTR sequenceKeyBuffer+12),13,10
      print uhex$(DWORD PTR sequenceKeyBuffer+16),13,10
      print uhex$(DWORD PTR sequenceKeyBuffer+20),13,10
      print uhex$(DWORD PTR sequenceKeyBuffer+24),13,10
      print uhex$(DWORD PTR sequenceKeyBuffer+28),13,10,13,10
    ENDM

    invoke ConvertAsciiTo128BitDecimal, ADDR binaryBuffer, ADDR asciiString
    print str$(eax),13,10
    print uhex$(DWORD PTR binaryBuffer),13,10
    print uhex$(DWORD PTR binaryBuffer+4),13,10
    print uhex$(DWORD PTR binaryBuffer+8),13,10
    print uhex$(DWORD PTR binaryBuffer+12),13,10,13,10

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


Note that the import library must be present at build time, and the DLL at run time.


eschew obfuscation

Astro

Interesting.

EDIT: No, he doesn't supply source code.

Best regards,
Astro.

scolby33

#6
Thanks MichaelW. Now GetSequenceKey works.
But RetrievePasscodes doesn't. Every time execution proceeds there, it crashes. I thought it might have been because I was passing strings, not integers, so I used code I found at http://www.masm32.com/board/index.php?topic=11024.0. Based on the information on the Implementation page I linked to earlier and MichaelW's code, I defined all the parameters that are passed to RetrievePasscodes to be 16 bytes and the sequenceKey to be 32 bytes. Still it crashes. Any suggestions?

Edit:When I pass values directly (invoke RetrievePasscodes,addr passCodeChars,0,10,addr sequenceKey,addr characterSet,2), it works. So how do I take an input string and make it an integer? Clearly my method is not working.

include \masm32\include\masm32rt.inc

includelib ppp.lib  ;Steve's PPP Lib

GenerateRandomSequenceKey   proto :DWORD
RetrievePasscodes           proto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD

.data?
    sequenceKey     db  32 dup(?)
    firstPassCodeNo db  16 dup(?)
    passCodeCount   db  16 dup(?)
    passCodeLength  db  16 dup(?)
    passCodeChars   db  ?

.const
    characterSet    db  "!#%+23456789:=?@ABCDEFGHJKLMNPRSTUVWXYZabcdefghijkmnopqrstuvwxyz",0    ;this is PPP's default character set
    AppName        db  " PPP!",0
    message1        db  "Enter First Passcode Number: ",0
    message2        db  "Enter Passcode Count: ",0
    message3        db  "Enter Passcode Length: ",0

.code

start:

invoke AllocConsole
SetConsoleCaption addr AppName

print "Welcome to PPP!",13,10,"Prepare to enter parameters...",13,10
    invoke StdOut,addr message1
    invoke StdIn,addr firstPassCodeNo,128
    mov BYTE PTR [firstPassCodeNo+eax-2],0                    ;This is supposed to change the string
    invoke atodw,addr firstPassCodeNo                              ;to an integer. I don't know if it works.
   
    invoke StdOut,addr message2
    invoke StdIn,addr passCodeCount,128
    mov BYTE PTR [passCodeCount+eax-2],0
    invoke atodw,addr passCodeCount

    invoke StdOut,addr message3
    invoke StdIn,addr passCodeLength,128
    mov BYTE PTR [passCodeLength+eax-2],0
    invoke atodw,addr passCodeLength

invoke GenerateRandomSequenceKey,addr sequenceKey

; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
; Begin Debug Section
; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤

;print sequenceKey in DWORD-length blocks
print "sequenceKey",13,10
    print uhex$(DWORD PTR sequenceKey),13,10
    print uhex$(DWORD PTR sequenceKey+4),13,10
    print uhex$(DWORD PTR sequenceKey+8),13,10
    print uhex$(DWORD PTR sequenceKey+12),13,10
    print uhex$(DWORD PTR sequenceKey+16),13,10
    print uhex$(DWORD PTR sequenceKey+20),13,10
    print uhex$(DWORD PTR sequenceKey+24),13,10
    print uhex$(DWORD PTR sequenceKey+28),13,10,13,10

;print other parameters
print "Parameters",13,10
print "firstPassCodeNo",13,10
    print uhex$(DWORD PTR firstPassCodeNo)
    print uhex$(DWORD PTR firstPassCodeNo+4)
    print uhex$(DWORD PTR firstPassCodeNo+8)
    print uhex$(DWORD PTR firstPassCodeNo+12),13,10
print "passCodeCount",13,10
    print uhex$(DWORD PTR passCodeCount)
    print uhex$(DWORD PTR passCodeCount+4)
    print uhex$(DWORD PTR passCodeCount+8)
    print uhex$(DWORD PTR passCodeCount+12),13,10
print "passCodeLength",13,10
    print uhex$(DWORD PTR passCodeLength)
    print uhex$(DWORD PTR passCodeLength+4)
    print uhex$(DWORD PTR passCodeLength+8)
    print uhex$(DWORD PTR passCodeLength+12),13,10

inkey

; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
; End Debug Section
; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤

invoke RetrievePasscodes,addr passCodeChars,addr firstPassCodeNo,addr passCodeCount,addr sequenceKey,addr characterSet,addr passCodeLength

print addr passCodeChars

inkey

invoke FreeConsole
invoke ExitProcess,0

end start

MichaelW

The atodw procedure appears to be broken. For MASM32 v10 here is a demo of three workable alternatives, all of which can correctly convert input values from -2147483648 to 4294967295.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      buff db 30 dup(0)
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    invoke StdIn, ADDR buff, 30
    print ADDR buff,13,10

    invoke atol, ADDR buff
    push eax
    print str$(eax),9,"atol as signed",13,10
    pop eax
    print ustr$(eax),9,"atol as unsigned",13,10

    invoke crt_atol, ADDR buff
    push eax
    print str$(eax),9,"crt_atol as signed",13,10
    pop eax
    print ustr$(eax),9,"crt_atol as unsigned",13,10

    invoke crt_atoi, ADDR buff
    push eax
    print str$(eax),9,"crt_atoi as signed",13,10
    pop eax
    print ustr$(eax),9,"crt_atoi as unsigned",13,10

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

eschew obfuscation

ecube


here's a atodw that works with negatives aswell as positive, is from the thread http://www.masm32.com/board/index.php?topic=11275.0

a2dwLIB proc uses ecx edi edx esi String:DWORD

      ;----------------------------------------
      ; Convert decimal string into dword value
      ; return value in eax
      ;----------------------------------------

      xor ecx, ecx
      mov edi, String
      invoke lstrlen, String

      .while eax != 0
        xor edx, edx
        mov dl, byte ptr [edi]
        sub dl, "0" ; subtrack each digit with "0" to convert it to hex value
        mov esi, eax
        dec esi
        push eax
        mov eax, edx
        push ebx
        mov ebx, 10
          .while esi > 0
            mul ebx
            dec esi
          .endw
        pop ebx
        add ecx, eax
        pop eax
        inc edi
        dec eax
      .endw

        mov eax, ecx
        ret

a2dwLIB endp

MichaelW

a2dwLIB appears the code from the MASM32 library a2dw procedure, which is also broken.
eschew obfuscation