###### Module ###### A ``Module`` object represents the different programs that form our process, that means: * The program itself * Imported libraries (DLLs, Shared Objects, Shared Libraries, etc) * Other imported files ``Module`` objects are returned when we use ``Process.enumerateModulesSync`` or ``Process.enumerateModules``, this object have the following properties: * ``base``: Base address where the module is loaded in memory * ``name``: Name of the module, usually it's the name of the file but it may be missing if it was manually loaded in memory (f.e. loading an encrypted library) * ``path``: Absolut path of the loaded file, may be missing too * ``size``: Size in memory of the module _________________________________ Looking for a function in modules _________________________________ One of the most important features about the ``Module`` module (No pun intended) is that it allows us to look for exported functions/methods and get its address in memory which we can use later to call that function or change its behaviour .. code-block:: JavaScript :linenos: var function_ptr = Module.findExportByName('module_name', 'function_name'); // In case we don't know which module has the function we can use ``null`` // but note that it may impact the performance if there are a lot of modules var function_ptr = Module.findExportByName(null, 'function_name'); var function_ptr = Module.getExportByName('module_name', 'function_name'); var function_ptr = Module.getExportByName(null, 'function_name'); This returns a ``NativePointer`` object. The only difference between ``getExportByName`` and ``findExportByName`` is that the former will raise an exception if the function is not found while the later will just return an `undefined` object. _______________________________ Getting all exports in a module _______________________________ Sometimes we won't know exactly which export we're looking for, for this cases it may be useful to get a list of all the available exports in a certain module. .. code-block::JavaScript :linenos: var nc = Process.enumerateModulesSync()[0]; console.log(Module.enumerateExportsSync(nc.name)); >>> [ >>> { >>> "address": "0x5601ae4db360", >>> "name": "uflag", >>> "type": "variable" >>> }, >>> { >>> "address": "0x5601ae4db378", >>> "name": "Pflag", >>> "type": "variable" >>> }, >>> { >>> "address": "0x5601ae4db1f0", >>> "name": "minttl", >>> "type": "variable" >>> }, >>> { >>> "address": "0x5601ae4db250", >>> "name": "Cflag", >>> "type": "variable" >>> }, >>> ... /* We can use the asynchronous versions of ``Process.enumerateModules`` and ``Module.enumerateExports`` */ var variables = []; Process.enumerateModules({ onMatch: function(module){ if(module.name == 'nc.openbsd'){ Module.enumerateExports(module.name,{ onMatch: function(exp){ if(exp.type == 'variable'){ variables.push(exp); } }, onComplete: function(){ } }); } }, onComplete: function(){ console.log(variables.map(function(f){return JSON.stringify(f);}).join('\n')); } }); >>> {"type":"variable","name":"uflag","address":"0x5601ae4db360"} >>> {"type":"variable","name":"Pflag","address":"0x5601ae4db378"} >>> {"type":"variable","name":"minttl","address":"0x5601ae4db1f0"} >>> {"type":"variable","name":"Cflag","address":"0x5601ae4db250"} >>> {"type":"variable","name":"tflag","address":"0x5601ae4db3a4"} >>> {"type":"variable","name":"Oflag","address":"0x5601ae55b3d0"} >>> {"type":"variable","name":"recvcount","address":"0x5601ae4db390"} >>> {"type":"variable","name":"sflag","address":"0x5601ae4db370"} >>> {"type":"variable","name":"timeout","address":"0x5601ae4db1f8"} >>> {"type":"variable","name":"portlist","address":"0x5601ae4db3c0"} >>> {"type":"variable","name":"Nflag","address":"0x5601ae55b3dc"} >>> {"type":"variable","name":"Sflag_password","address":"0x5601ae55b400"} >>> {"type":"variable","name":"rflag","address":"0x5601ae55b3e8"} >>> {"type":"variable","name":"unix_dg_tmp_socket","address":"0x5601ae55 There are two kind of exports: `function` and `variable`. The names are self explanatory. _____________________________ Getting imports from a module _____________________________ In the same way that a module exports some of its functions and variables it may be importing functions and variables from other modules. For example, we may be interested in looking the function imported by the main module: .. code-block:: JavaScript :linenos: var nc = Process.enumerateModulesSync()[0]; Module.enumerateImportsSync(nc.name); >>> [ >>> { >>> "address": "0x7fa8a8f7c010", >>> "module": "/lib/x86_64-linux-gnu/libc-2.27.so", >>> "name": "__snprintf_chk", >>> "type": "function" >>> }, >>> { >>> "address": "0x7fa8a8fd4f80", >>> "module": "/lib/x86_64-linux-gnu/libc-2.27.so", >>> "name": "strcasecmp", >>> "type": "function" >>> }, >>> { >>> "address": "0x7fa8a8e6bf20", >>> "module": "/lib/x86_64-linux-gnu/libc-2.27.so", >>> "name": "__errno_location", >>> "type": "function" >>> }, >>> ... ___________________ Using the ModuleMap ___________________ Usually we won't be interested in looking into the entire process, often we'll just neet to look at a few modules that belong to the application we're analyzing but we don't care about some dependencies - f.e. `ld.so`. To avoid scanning all those modules innecesarily, we can create a ``ModuleMap`` that only has the modules we want: .. code-block:: JavaScript :linenos: var my_map = new ModuleMap(function(mod){ if(mod.name == 'nc.openbsd' || mod.name == 'libc-2.27.so') return true; // We return true for the modules we want to keep }); The map creates a snapshot of the currently imported modules and will use this cached version to respond our queries. Some useful functions: * ``my_map.update()``: Update the snapshot in use keeping same filters. * ``my_map.find(address)`` or ``my_map.get(address)``: Returns the module that address belongs to (The former returns null if none module matches while the later will raise an exception); * ``my_map.values()``: Returns an array with all the mapped modules The we can make bulk operations on all the mapped modules at once: .. code-block:: JavaScript :linenos: my_map.values().map(function(mod){ return Module.enumerateExportsSync(mod.name); }); >>> [ >>> [ >>> { >>> "address": "0x5601ae4db360", >>> "name": "uflag", >>> "type": "variable" >>> }, >>> { >>> "address": "0x5601ae4db378", >>> "name": "Pflag", >>> "type": "variable" >>> }, >>> { >>> "address": "0x5601ae4db1f0", >>> "name": "minttl", >>> "type": "variable" >>> }, >>> { >>> "address": "0x5601ae4db250", >>> "name": "Cflag", >>> "type": "variable" >>> }, >>> { >>> "address": "0x5601ae4db3a4", >>> "name": "tflag", >>> "type": "variable" >>> }, >>> ... >>> ], >>> [ >>> { >>> "address": "0x7fa8a8fb0520", >>> "name": "__libc_dlsym", >>> "type": "function" >>> }, >>> { >>> "address": "0x7fa8a8f62200", >>> "name": "__endmntent", >>> "type": "function" >>> }, >>> { >>> "address": "0x7fa8a8f08730", >>> "name": "wcstoq", >>> "type": "function" >>> }, >>> { >>> "address": "0x7fa8a8f586d0", >>> "name": "pwrite", >>> "type": "function" >>> }, >>> { >>> "address": "0x7fa8a8e896b0", >>> "name": "sigstack", >>> "type": "function" >>> }, >>> ... >>> ] >>> ] ___________________________ Other interesting functions ___________________________ * ``Module.getBaseAddress(name)`` and ``Module.findBaseAddress(name)``: Returns the base address of the module `name` * ``Module.ensureInitialized(name)``: It ensures that the module has been initialized before continuing execution. This is particularly useful when attempting early instrumentation but we still need a specific module available. * ``Module.enumerateRanges(protection_object)``: Same as ``Process.enumerateRanges(protection)`` but specific to a single module.