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")
 | |
| })).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");
 |