Skip to content

Writing an AssemblerPlugin

Antonio Davide edited this page Feb 20, 2019 · 12 revisions

The AssemblerPlugin provides an instruction decoder for a specific cpu/architecture, usually it's not tied to a specific FormatPlugin (currently, only DalvikAssembler is tied to DEXFormat).

The most important function of an AssemblerPlugin is decodeInstruction(): this function decodes a single Instruction, also, this class provides methods needed for custom printing, emulation and operand analysis.
onDecoded is called only when the instruction is valid.

Creation

Like FormatPlugin, the first thing to do is to create a folder called customasm in redasm/assemblers and declare a class called CustomAssembler that inherits from AssemblerPlugin.
After the creation, we need to declare our plugin by calling DECLARE_ASSEMBLER_PLUGIN macro and associate a unique id to it.

// customasm.h

#include "../../plugins/plugins.h" // Import AssemblerPlugin
#include "../../support/dispatcher.h"

class CustomAssembler: public AssemblerPlugin
{
    public:
      CustomAssembler();
      virtual const char* name() const;                                      // Assembler's display name

    protected
      virtual bool decodeInstruction(const BufferView& view const InstructionPtr& instruction); // Our decoding function
      virtual void onDecoded(const InstructionPtr& instruction) const; // ...when instruction is decoded...

    private:
      Dispatcher<u16, void(Buffer&, const InstructionPtr&)> m_decodemap; // Our decoding map
};

DECLARE_ASSEMBLER_PLUGIN(CustomAssembler, customasm) // Declare the plugin with id: CustomAssembler=customasm
// customasm.cpp

#include "customasm.h"

CustomAssembler::CustomAssembler(): AssemblerPlugin()
{
    /* 
     * Fill m_decodemap with
     * m_decodemap[opcode] = decode_callback;
     */
}

const char* CustomAssembler::name() const { return "Custom Assembler"; }

bool CustomAssembler::decodeInstruction(const BufferView& view, const InstructionPtr& instruction)
{
    u16 opcode = *buffer;    // Read 16-bits from buffer with the right endianness
   
    if(!m_decodemap.contains(opcode))
      return false; // Unknown opcode: REDasm will generate an invalid Instruction

    m_decodemap(buffer, instruction);
    return true;
}

void CustomAssembler::onDecoded(const InstructionPtr& instruction) const
{
    // Post decoding code: operand definition, instruction type, etc...
}

Registration

In order to make our format visible to REDasm, it needs to be registered in plugins.cpp by using REGISTER_ASSEMBLER_PLUGIN macro.

// plugins.cpp

#include ASSEMBLER_PLUGIN(customasm) // Import CustomAssembler

void init(const std::string& searchpath)
{
  ...
  REGISTER_ASSEMBLER_PLUGIN(customasm); // Register CustomAssembler by using its ID
  ...
}

Backend support

This article describes the most basic type of AssemblerPlugin, but, for example, it's possible to use the Capstone customized one called CapstoneAssemblerPlugin which provides its CapstonePrinter in order to decode registers automatically, also, decodeInstruction() function is customized and it decodes instruction automatically by calling Capstone APIs and it allows to use cs_insn* type for analysis.

You can’t perform that action at this time.