Node-ffi is here: https://github.com/node-ffi/node-ffi. Let's create a dll for it:
In Visual studio new c++ project, dll type. Then:
#include "stdafx.h"
#include <iostream>
extern "C"
__declspec(dllexport) void stdoutput()
{
std::cout << "test output";
}
extern "C"
__declspec(dllexport) void crash()
{
__asm
{
int 3;
}
}
End result:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\dumpbin.exe c:\users\ledin_000\documents\visual studio 2013\Projects\sample_dll\Debug\sample_dll.dll
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\dumpbin.exe" /exports "c:\users\ledin_000\documents\visual studio 2013\Projects\sample_dll\Debug\sample_dll.dll"
...
ordinal hint RVA name
1 0 0001101E crash = @ILT+25(_crash)
2 1 000110DC stdoutput = @ILT+215(_stdoutput)
Now to node. https://www.npmjs.org/package/node-ffi
npm install node-ffi suggested to install module ffi.
At some point npm errorred out because I did not have C:\Users\<username>\AppData\Roaming\npm directory.
After that, compiles stuff using my visual studio. Interesting security consequences. So I have trust npm. It does do ssl connection to the servers where it downloads things from. Fiddler says.
Here is a more serious tutorial: https://github.com/node-ffi/node-ffi/wiki/Node-FFI-Tutorial
Turns out my node installation is 64 bit. Kind of expected. So now: ::DebugBreak(); instead of the __asm sequence.
var ffi = require('ffi');
var funcs = ffi.Library('sample_dll.dll', {
'stdoutput': [ 'void', [ ] ],
'crash': [ 'void', [ ] ],
});
funcs.stdoutput();
funcs.crash()
Didn't crash. Why not?
I guess I need to execute it under debugger.
I will sleep for 20 seconds, to enable attach with visual studio.
JS does not have a sync sleep function, so npm install sleep.
Node populates C:\Program Files\nodejs\node_modules\sleep, so it is easy to look how a module looks like.
Somehow I cannot see a nice callstack when attaching and waiting for Debugbreak(). Debugbreak happens, but not with expected callstack.
So I do:
windbg node exp2.js
sxe ld sample_dll -- wait till loading of sample_dll happens.
x sample_dll!*crash* -- to see I have symbols, which I have in path.
then
bu sample_dll!crash
g
and...
0:000> k
Child-SP RetAddr Call Site
00000000`0035f4c8 00007ffe`15ff9dc3 sample_dll!crash [c:\users\<user>\documents\visual studio 2013\projects\sample_dll\sample_dll\sample_dll.cpp @ 15]
00000000`0035f4d0 00007ffe`15ff39b6 ffi_bindings!ffi_call_win64+0x77
00000000`0035f510 00007ffe`15ff26df ffi_bindings!ffi_call+0xa6 [c:\node_modules\ffi\deps\libffi\src\x86\ffi.c @ 421]
*** ERROR: Symbol file could not be found. Defaulted to export symbols for node.exe -
00000000`0035f570 00007ff7`5288bff4 ffi_bindings!FFI::FFICall+0x14f [c:\node_modules\ffi\src\ffi.cc @ 289]
00000000`0035f5f0 00007ff7`52889d56 node!uv_cancel+0x44674
...
In other words I crashed where I expected. No symbols for node though. I wonder where I could find them.
In either case, lesson here is that:
1) debugging native with node.js is easy.
2) writing native code as node module should be easy as well. Sample code is close and available.