forked from sheetjs/docs.sheetjs.com
		
	
		
			
	
	
		
			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") | ||
|  | })); | ||
|  | 
 | ||
|  | /* create worksheet */ | ||
|  | const ws = json_to_sheet(aoo); | ||
|  | /* write workbook */ | ||
|  | const wb = book_new(ws, "Offsets"); | ||
|  | /* write to XLSX */  | ||
|  | writeFileXLSX(wb, "SheetJSGhidraTSTCell.xlsx"); |