Skip to content

Latest commit

 

History

History
94 lines (79 loc) · 3.94 KB

DEVELOPERS.md

File metadata and controls

94 lines (79 loc) · 3.94 KB

Developing on jsdec

jsdec is written in javascript uses QuickJS.

Extending jsdec arch

First of all when you need to add a new architecture, you need to create a new .js file inside js/libdec/arch/.

For example js/libdec/arch/arch9999.js and it needs to follow the minimal base javascript template:

import Base from '../core/base.js';
import Variable from '../core/variable.js';
import Extra from '../core/extra.js';
return {
    instructions: {
        add: function(instr, context, instructions) {
            return Base.add(instr.parsed.opd[0], instr.parsed.opd[1], instr.parsed.opd[2]);
        },
        nop: function() {
            return Base.nop();
        },
        invalid: function(instr, context, instructions) {
            return Base.nop();
        }
    },
    parse: function(assembly) {
        var tokens = assembly.trim().split(' ');
        return { mnem: tokens.shift(), opd: tokens };
    },
    context: function() {
        return { cond: { a: '?', b: '?' } };
    },
    preanalisys: function(instructions, context) {},
    postanalisys: function(instructions, context) {},
    localvars: function(context) {
        return [];
    },
    globalvars: function(context) {
        return [];
    },
    arguments: function(context) {
        return [];
    },
    returns: function(context) {
        return 'void';
    }
};

After saving the new arch (arch9999.js in the example), you need to add this arch to the file libdec/Archs.js.

The new architecture needs to have the same name as the cmd e asm.arch, because the architecture is choosen from that input, regardless the bits, etc.. of the arch.

For example:

import arm from './arch/arm.js';
import x86 from './arch/x86.js';
import arch9999 from './arch/arch9999.js';

export default {
    arm: arm,
    arch9999: arch9999,
    x86: x86
};

Codebase:

So the codebase will use the Base object.

  • All the common instructions are under Base.*; they will follow the following input: fcn(destination, reg0, reg1, ...).
    • Base.composed allows to build a set of readable instructions that can be used to express a complex opcode/instruction (see for example rlwimi under ppc.js).
  • Variable.* will include the creators for known arguments, like
    • Variable.functionPointer(value, type_or_bits, is_signed) defines a function pointer (uint16_t (*mypointer)(...)) as argument for Base.*.
    • Variable.pointer(value, type_or_bits, is_signed) defines a pointer (uint16_t* mypointer) as argument for Base.*.
    • Variable.local(value, type_or_bits, is_signed) defines a local (int32_t mylocal) as argument for Base.*.
    • Variable.string(content) is ment to be used for strings as argument of Base.* functions; eg: return Base.assign('r0', Base.string('"wooooow"'));.
  • var Long = require('libdec/long'); can be used to support 64 bits values on javascript.

All the instructions added under arch.instructions.* will have the following data as input (instr, context, instructions), where:

  • instr is the current instruction analized.
  • context is the an object that can be used to store values tha will be used by instructions that will be analyzed later.
  • instructions is the array with all the libdec/instruction.js derived objects that can be used to recover some required infos that might be needed. One last thing:
  • context used by instructions to store/retrieve data is generated by arch.context().
  • arch.parse is used to parse the instruction to a json object:
    • an example: "add r0, r1, r2" to { "mnem": "add", "opd": ["r0", "r1", "r2"] }.
    • assembly is a string containing the r2 enriched assembly (for example: call sym.imp.__libc_start_main).
    • simplified is a string containing the standard assembly (for example: call 0x4a234).
    • the returned object is available under instr.parsed, meanwhile the original string can still be found under instr.assembly or instr.simplified.

Deroad.