Disassemble firmware completely (rebuild functions in IDA)

The first steps after acquiring the firmware of an embedded system are mainly to:

  1. determine the processor of the device,
  2. disassemble the firmware image,
  3. reconstruct the firmware: rebuild functions, determine the base address, collect information from strings, rebuild symbols etc.

Regarding the processor identification, there is Skochinsky’s presentation which is actually amazing. For disassembling the binary image there is IDA. In order to proper reconstruct the firmware however, several techniques must be applied on the file. For example, one must determine the base address of the firmware i.e. the starting location of the firmware in order to have accurate interpretations of segments referenced by immediate addresses. The “load technique” is usually used for this step, given that there exist immediate address references in the disassembly. We will talk in future tutorials about this technique.

Today, we will present a simple trick how to rebuild functions and thus fix the disassemble code in IDA. The script below (kudos to Santamarta) simply instructs IDA to explore the remaining unexplored functions in the firmware. The example firmware in our case is based on ARM ISA. In addition, the prologue signature of the already IDA automatically identified functions is a STMFD instruction that pushes the current register values to the stack. The registers pushed to the stack are different between each STMFD instruction but the two most significant bytes of the instruction remain the same (“E9 2D”). This is verified also from the ARM instruction encoding standard. Hence, by editing Santamarta’s script to target this signature (+corrected for endianness), the script is applied to the loaded in IDA firmware. Consequently, a significant part of the firmware binary image is explored since more functions are identified.

/* Ruben Santamarta www.reversemode.com */
/* Fix functions - Schneider NOE 110 firmware */
 
/* Edited by Harrys Kon Feb. 2015*/
 
/* FixARMfunctions.idc*/
 
#include <idc.idc>
 
static main() {
 auto ae;
 auto funct;
 auto minea;
 auto prolog;
 auto j;
 auto fun_array;
 
 minea = MinEA();
 SetStatus(IDA_STATUS_WORK);
 fun_array = CreateArray("ProGos");
 
 if (fun_array == -1) 
   fun_array = GetArrayId("ProGos");
 
 SetArrayString(fun_array,0,"2D E9"); 
 
 for (j=0;j<1;j++){
   ae = minea;
   prolog = GetArrayElement(AR_STR,fun_array,j);
   while (1) {
     funct = FindBinary ( ae, SEARCH_DOWN, prolog); 
     if (funct == BADADDR )
       break; 
     funct = funct - 2;
     MakeCode (funct);
     MakeFunction (funct, BADADDR); 
     ae = funct + 4;
   }
 }
 SetStatus(IDA_STATUS_READY); 
}
Advertisements