71 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			71 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
const { utils: { book_new, json_to_sheet }, writeFileXLSX } = require("xlsx");
 | 
						|
 | 
						|
/* start decompiler */
 | 
						|
const DecompInterface = JavaHelper.getClass('ghidra.app.decompiler.DecompInterface');
 | 
						|
const decompiler = new DecompInterface();
 | 
						|
decompiler.openProgram(currentProgram);
 | 
						|
 | 
						|
/* get decompiled C source */
 | 
						|
const src = (() => {
 | 
						|
  const fname = '_TSTCellToCellStorage';
 | 
						|
 | 
						|
  /* find address to function */
 | 
						|
  const fsymbs = currentProgram.getSymbolTable().getGlobalSymbols(fname);
 | 
						|
  if(!fsymbs) throw new Error(`Global Symbol ${fname} cannot be found`);
 | 
						|
 | 
						|
  /* find function */
 | 
						|
  const fn = currentProgram.getFunctionManager().getFunctionAt(fsymbs[0].getAddress());
 | 
						|
  if(!fn) throw new Error(`Function ${fname} cannot be found`);
 | 
						|
 | 
						|
  /* decompile function */
 | 
						|
  const decomp = decompiler.decompileFunction(fn, 10000, null);
 | 
						|
  if (decomp.isTimedOut() || !decomp.decompileCompleted()) throw new Error(`Function ${fname} at ${fn} could not be decompiled`);
 | 
						|
 | 
						|
  /* get and return generated C code */
 | 
						|
  const src = decomp.getDecompiledFunction().getC();
 | 
						|
  if(!src) throw new Error(`Function ${fname} at ${fn} decompilation`);
 | 
						|
  return src;
 | 
						|
})();
 | 
						|
 | 
						|
/* offset[n] will be the name of the field at bit `n` (mask `1 << n`) */
 | 
						|
let offset = [];
 | 
						|
 | 
						|
/* combine split lines and lazily extract data from C source */
 | 
						|
let n = -1;
 | 
						|
src.split(/[\r\n]+/).reduce((acc,row,i) => {
 | 
						|
  if(i <= 9) acc.rows.push(row);
 | 
						|
  else if(row.match(/[{};]$/)) {
 | 
						|
    if(acc.buf) { row = acc.buf + row.trim(); acc.buf = ""; }
 | 
						|
    acc.rows.push(row);
 | 
						|
  } else acc.buf += acc.buf ? row.trim() : row.replace(/[\r\n]+$/,"");
 | 
						|
  return acc;
 | 
						|
}, {rows:[], buf:""}).rows.forEach(line => {
 | 
						|
  if(line.match(/^  if.*(char|short| >> | & )/)) {
 | 
						|
    n = -1;
 | 
						|
    if(!line.match(/Var/)) return;
 | 
						|
    if(line.match(/char/)) n = 7;
 | 
						|
    else if(line.match(/short/)) n = 15;
 | 
						|
    else if(line.match(/>>/)) n = parseInt(line.match(/>> ([1-9]\d*|0x[0-9a-f]+)/)[1]);
 | 
						|
    else if(line.match(/&/)) n = Math.round(Math.log2(parseInt(line.match(/& ([1-9]\d*|0x[0-9a-f]+)/)[1])));
 | 
						|
  } else if(line.match(/PTR__objc_msgSend/) && n >= 0) {
 | 
						|
    if(line.match(/AssertionHandler|NSString|stringWithUTF8String|Failure/)) return;
 | 
						|
    if(!line.match(/,/)) return; // suppress noop
 | 
						|
    const ptr = line.match(/PTR_s_\w+/)[0];
 | 
						|
    offset[+n] = ptr;
 | 
						|
    n = -1;
 | 
						|
  }
 | 
						|
});
 | 
						|
 | 
						|
/* construct objects with "Mask" (hex string) and "Internal Name" */
 | 
						|
const aoo = offset.map((name, idx) => ({
 | 
						|
  Mask: "0x" + (1 << idx).toString(16),
 | 
						|
  "Internal Name": name.replace(/^PTR_s_|_[0-9a-f]*$/g,"").replace(/[A-Z]/g, " $&").toLowerCase().replace(/ i d/, " ID")
 | 
						|
})).filter(x => x);
 | 
						|
 | 
						|
/* create worksheet */
 | 
						|
const ws = json_to_sheet(aoo);
 | 
						|
/* write workbook */
 | 
						|
const wb = book_new(ws, "Offsets");
 | 
						|
/* write to XLSX */ 
 | 
						|
writeFileXLSX(wb, "SheetJSGhidraTSTCell.xlsx");
 |