Importing procedures from DLL

The Flat Assembler provides us with yet another option for using external functionality. While with other assemblers we need a linker in order to link against DLLs, Flat Assembler makes it possible to produce an executable with all the imports defined in source code, which allows us to simply compile the source code and run the executable.

The process of runtime linking dynamic link libraries to our code is fairly simple and may be illustrated with the following diagram:

Once the loader has loaded an executable, it parses its import table (if present) and identifies the requested libraries (refer to PECOFF.docx for the import table format specifications). For each library reference found in the import section, the loader attempts to load the library, then parses the executable's import section for the names of procedures exported by the library in question, and scans the library's export section for a match. Once a matching entry is found, the loader calculates the virtual address of the entry and writes it back to the import section of the executable. This sequence is repeated for every imported entry of every requested library.

For our example, we will use the same code as with linking objects (just rename it to dll_win.asm) with just a few tiny modifications, and crypto_w32.dll instead of crypto_w32.obj. First of all, remove all the extrn and public declarations and then tell the assembler that this time we are expecting a console executable, rather than an object file, by changing format MS COFF to format PE CONSOLE.

As we will create our own import table, we need to include the win32a.inc file that contains all the macros we may need for our purpose. Add this line after the format declaration:

include 'win32a.inc'

We are almost there; append the following code to the source file:

section '.idata' import data readable writeable

; Tell the assembler which libraries we are interested in
library kernel,'kernel32.dll',
crypto,'crypto_w32.dll'

; Specify procedures we need from kernel32.dll
import kernel,
GetStdHandle, 'GetStdHandle',
WriteConsole, 'WriteConsoleA',
ExitProcess, 'ExitProcess'

; And, finally, tell the assembler we are also
; interested in our crypto engine
import crypto,
GetPointers, 'GetPointers'

The last modification that we have to make is change call GetPointers to call [GetPointers], as this time, the GetPointers; procedure will not be statically linked to our executable, but it will be imported from a dynamic link library, meaning that the GetPointers label will refer to an address in memory where the address of the GerPointers procedure will be stored.

Try to compile the file and run it in the console. You should get the same output as the one with the executable we linked from multiple objects.

If you get an error message saying that the executable failed to launch instead of the expected output, try adding the section '.reloc' fixups data readable discardable line to the TARGET_W32_DLL section of the finalize macro in the platform.inc file, and recompile crypto_w32.dll. This is correct for building a DLL in general, although it may work without this in certain circumstances.

It is, of course, possible to load DLLs manually with the LoadLibrary() Windows API, and resolve addresses of needed procedures with GetProcAddress(), but that does not differ from linking against a DLL or importing APIs, as we still do need to import these two APIs. There is, however, a method that allows us to import API addresses in the so-called stealthy way.

The exact same rules apply when it comes to building 64-bit executables. The only difference is the location of kernel32.lib, which will be c:Program FilesMicrosoft SDKsWindowsvX.XLibx64, and the size of pointers. Also, it is very important to remember that the calling convention used on x86_64 Windows is neither cdecl nor stdcall!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset