Calling functions in DLLs from JavaScript

During the past few weeks, I worked a lot with Google’s V8, the JavaScript engine used in Google Chrome. The engine can be easily embedded into applications, providing the ability to write some functionality of the application in JavaScript instead of C++. However, from within JavaScript code, there is no way out of the sandbox in which the engine executes the script code, except for a few functions explicitly added by the embedder (i.e., a browser) to communicate with the outside world. Due to security concerns, this makes much sense in a browser environment. Nevertheless, if the application only executes “trusted” scripts, it could be interesting to allow the script full access to the operating system, just like an ordinary application developed in C. That means that it should be possible to call functions in DLLs from pure JavaScript. This is similar to python-ctypes.

As a proof-of-concept, I created jswin, a small runtime environment for JavaScript based on V8 that allows script code to load a DLL and call its functions. Inside the environment it is possible to communicate directly with the native interface of the operating system. In this post I want to focus on the two most interesting points of the implementation: how to call a function in a DLL and how to handle callback functions. I recommend reading the API documentation of jswin before continuing.

Calling functions in DLLs

Basically, calling a function in a DLL on Windows is easy. Load the DLL with LoadLibrary, get the address of the function with GetProcAddress and call it using a function pointer in C. The compiler generates the code that passes arguments to the function based on the declaration of the function pointer. For example, if we want to call MessageBoxA from user32.dll, we write the following code:


typedef int
  (WINAPI* MessageBoxPtr)(HWND,LPCSTR,LPCSTR,UINT);

HMODULE hUser32 = LoadLibrary("user32.dll");
MessageBoxPtr MessageBox =
  (MessageBoxPtr)GetProcAddress(hUser32, "MessageBoxA");
MessageBox(NULL, "Text", "Title", 0);

In JavaScript, that could look similar:


var user32 = loadLibrary("user32.dll");
var MessageBox = user32.getProcAddress("MessageBoxA");
MessageBox(0, "Text", "Title", 0);

The JavaScript functions loadLibrary and getProc are easily implemented by just forwarding the call to the “real” functions. But how do we call MessageBox? We don’t have that function pointer, as at compile-time we don’t know the functions which the script wants to call. Therefore, the compiler can’t generate the code for passing arguments to MessageBoxA. We have to code it ourselves.

How arguments are passed to a function is determined by its calling convention. The MSDN has a nice overview of calling conventions used on x86 platforms. The Windows DLLs usually use the __stdcall calling convention, though the default calling convention for C programs is __cdecl. Currently, jswin only implements these two calling conventions.

In order to call a function, we have to know its calling convention and argument count. Ideally, we further know the argument types, so we can automatically convert the JavaScript type to the appropriate C type. Therefore, the code to call MessageBoxA now look as follows (differences are marked in bold):


var user32 = loadLibrary("user32.dll");
var MessageBox = user32.getProc("MessageBoxA", "icci", "stdcall");
MessageBox(0, "Text", "Title", 0);

According to the argument specification, we have to convert the value from JavaScript to C, push it on the stack following the calling convention, and move the instruction pointer to the appropriate address in memory. Note that some parts have to be performed in (inline) assembler. Pseudo-code:


// Push arguments on stack
foreach(arg in args) {
  convert JavaScript value to C type according to arg
  push converted value
}

// Call function and save result
call function by its address
mov [result], eax

// Clean up the stack (if necessary)
if(calling convention is __cdecl) {
  foreach(arg in args) {
    pop
  }
}

Callback functions

Another tricky part is the calling of JavaScript functions from C code, usually called callback function. The ‘address’ of a JavaScript function is handed over to the DLL and once a certain event occurs, the DLL calls the JavaScript function. An example from the README:


var onMouseDownHandler = new CallbackFunction("ii", "stdcall", function(x, y) {
  // ...
});

var SetOnMouseDownHandler = ....
SetOnMouseDownHandler(onMouseDownHandler.getAddress());

In the example, SetOnMouseDownHandler is a C function in a DLL that takes an address of another C function. Therefore, we have to create a C function whose address is passed to SetOnMouseDownHandler and that can call the JavaScript function. This work is done by CallbackFunction.

CallbackFunction allocates a memory region and fills in executable code. The code is a stub which only calls the JavaScript function. The stub has to read the arguments from the stack, convert them into an appropriate JavaScript type, call the JavaScript function and remove the arguments from the stack if necessary. For this purpose, argument types and calling convention have to be specified as before.

In jswin, the stub is split into two parts, a very small part in assembler and a larger part in C++. The assembler part basically forwards the ‘this’ pointer of the CallbackFunction object to the C++ part. As each CallbackFunction object has its own this pointer, there exists a stub for each instance. In pseudo-code:


// Stub (assembler)
push this-pointer on stack
mov eax, address of C++-part of stub
call eax
ret size of arguments on stack in bytes or 0

// Stub (C++)
unsigned int __stdcall
genericCallbackFunction(CallbackFunction* cb) {
  foreach(arg in args) {
    calculate address of arg on stack
    retrieve argument from stack by its address
    convert argument to JavaScript type
    store converted argument in local array
  }
  invoke JavaScript function and pass arguments
}

The assembler part of the stub has to be copied to a memory location from which it is allowed to execute code. On Windows, such memory can be allocated using VirtualAlloc with the PAGE_EXECUTE flag. The constructor of CallbackFunction allocates the memory this way and copies the opcodes into it.

Example

If you ask yourself “What is it good for?”, here is an example: creating windows using the native Win32 API from JavaScript.

jswin

Conclusion

With the technique shown in this article it is possible to call arbitrary functions in DLLs from JavaScript or another scripting language. It allows you to write wrappers for C libraries in pure JavaScript. As usual, the source code for jswin is found in my GitHub repository.

Download:
* Source code for jswin
* Binaries

Advertisements

Tags: , , , ,

7 Responses to “Calling functions in DLLs from JavaScript”

  1. windows 7 repair Says:

    Everything is very open with a precise description of the challenges.
    It was definitely informative. Your website is useful.

    Many thanks for sharing!

  2. ted Says:

    Hi,just I’m a beginner to this & can you explain how to setup this jswin step by step & use in windows environment…

    thank you.

    • 0xef Says:

      Hi! You have to download the zip file containing the binaries. Then, run “jswin.exe winmain” from the command prompt to start one of the examples. Or you can use jswin_wrapper.exe to build an executable: “jswin_wrapper.exe winmain winmain.exe” will create winmain.exe which you can start by double-clicking.

      • JavaScript fan Says:

        Hi 0xef Whats your Skype . Id like to send you an invitation /javascript dll programming

  3. satheesh Says:

    Hi i need one help . how i can write call dll function java script code in html page .

  4. Niyati Shah Says:

    I have tryied using above code, testdll.js
    WHile running code in javascript editor, giving error:

    loadLibrary function not found

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: