Tecnologer
Tecnologer

Reputation: 488

How can I find procedure from a DLL using its ordinal value?

I'm trying to call procedure (without name) from a DLL using the ordinal value.

I can use this DLL in C#, setting the ordinal value to the property EntryPoint of DllImport.

... or you can identify the entry point by its ordinal. Ordinals are prefixed with the # sign, for example, #1. [...]

Example in C#:

[DllImport("dllname.dll", EntryPoint = "#3", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern int DeviceList(ref IntPtr hDeviceList);

When try find the procedure with "#" sign in Go, it shows the the following error:

Failed to find #3 procedure in dllname.dll: The specified procedure could not be found.

I used dumpbin to show the information of the DLL, no function has a name:

dumpbin results

Is there a way to find a procedure with its ordinal value (like C#)?

Upvotes: 1

Views: 1234

Answers (1)

gonutz
gonutz

Reputation: 5582

There is a github issue here for this, but it seems not to have been merged as of Go 1.10.3 (the version I am using right now).

Anyway, the github issue links to a changeset with the respective function from which I extracted the code to do what you want here:

var (
    kernel32           = syscall.NewLazyDLL("kernel32.dll")
    procGetProcAddress = kernel32.NewProc("GetProcAddress")
)

// GetProcAddressByOrdinal retrieves the address of the exported
// function from module by ordinal.
func GetProcAddressByOrdinal(module syscall.Handle, ordinal uintptr) (uintptr, error) {
    r0, _, _ := syscall.Syscall(procGetProcAddress.Addr(), 2, uintptr(module), ordinal, 0)
    proc := uintptr(r0)
    if proc == 0 {
        return 0, syscall.EINVAL
    }
    return proc, nil
}

For completeness, here is the full example with which I tested this, using the Dependecy Walker I found that the first function in kernel32.dll is AcquireSRWLockExclusive and using the new function it shows that the proc addresses really match.

package main

import (
    "fmt"
    "syscall"
)

func main() {
    dll, err := syscall.LoadDLL("kernel32.dll")
    check(err)

    want, err := syscall.GetProcAddress(dll.Handle, "AcquireSRWLockExclusive")
    check(err)
    fmt.Println(want)

    first, err := GetProcAddressByOrdinal(dll.Handle, 1)
    check(err)
    fmt.Println(first)
}

func check(err error) {
    if err != nil {
        panic(err)
    }
}

var (
    kernel32           = syscall.NewLazyDLL("kernel32.dll")
    procGetProcAddress = kernel32.NewProc("GetProcAddress")
)

// GetProcAddressByOrdinal retrieves the address of the exported
// function from module by ordinal.
func GetProcAddressByOrdinal(module syscall.Handle, ordinal uintptr) (uintptr, error) {
    r0, _, _ := syscall.Syscall(procGetProcAddress.Addr(), 2, uintptr(module), ordinal, 0)
    proc := uintptr(r0)
    if proc == 0 {
        return 0, syscall.EINVAL
    }
    return proc, nil
}

Upvotes: 1

Related Questions