更多全球网络安全资讯尽在邑安全
一、Hello World 脚本public class HelloWorld extends GhidraScript { public void run() throws Exception { printf("Hello World\n"); //格式化输出 println("Hello World"); //打印字符串并换行 printerr("Hello World"); //错误消息打印控制台显示红色 } }
成功运行控制台打印出Hello World。
二、获取所有的符号public class HelloWorld extends GhidraScript { @Override public void run() throws Exception { //TODO Add User Code Here SymbolTable st = currentProgram.getSymbolTable(); SymbolIterator iter = st.getSymbolIterator(true); int count = 0; while (iter.hasNext() && !monitor.isCancelled()) { Symbol sym = iter.next(); if (sym != null) { printf("\t%s\n",sym.getName()); count++; } } println(count+" symbols"); }}
控制台输出如下:
脚本中使用currentProgram来获取符号表,这里currentProgram为抽象类GhidraScript提供的变量。软件中的参数和信息都是通过这些变量来获取的,常用的变量有如下几个:currentProgram 当前项目的程序
currentAddress Ghidra工具中闪烁光标位置的地址对象
currentLocation 工具中当前光标位置的程序位置;如果不存在程序位置,则为null
currentSelection 当前的选中对象;如果不存在选择,则为null
currentHighlight 工具中的当前突出显示;如果不存在突出显示,则为null
脚本开发中使用最多的是currentProgram了。
三、获取所有的Function对象public class HelloWorld extends GhidraScript { @Override public void run() throws Exception { FunctionIterator iterator2 =currentProgram.getListing().getFunctions(true); for (Function function : iterator2) { printf("\t%s\n",function.getName()); } }}
Function对象可以操作已经识别的函数,比如引用、函数内逻辑的分析、以及函数内的修改。
四、函数交叉引用public class HelloWorld extends GhidraScript { @Override public void run() throws Exception { FunctionIterator iterator2 =currentProgram.getListing().getFunctions(true); for (Function function : iterator2) { if (function.getName().equals("write")){ printf("\t%s @ %s\n",function.getName(),function.getEntryPoint()); Reference[] references = getReferencesTo(function.getEntryPoint()); for (Reference reference : references) { Function referencefunction=getFunctionContaining(reference.getFromAddress()); if (referencefunction!=null&& !referencefunction.isThunk()) printf("\t\t%s @ %s\n",referencefunction.getName(),referencefunction.getEntryPoint().toString()); } } } }}
控制台输出信息如下:
讲解下使用的api说明:function.getEntryPoint() 是返回函数地址Address对象,二进制里指的是函数所在起始地址用,但在Java中是Address对象对它进行描述。
function.getName() 是函数名,如果是有符号描述则为符号描述中但字符串,反之就是反汇编引擎随机分配的FUN_xxxx 类似名称。
getReferencesTo() 是返回Address参数的所有引用,并返回Reference对象的数组。
getFunctionContaining() 是根据传入的地址返回Function对象,如果是函数起始地址则返回Function对象,如果不是则返回null,所以使用这个API需要加上判断,以免脚本运行错误抛出异常。
五、函数转为P-CODE中间码public class HelloWorld extends GhidraScript { private DecompInterface decompInterface=null; @Override public void run() throws Exception { decompInterface = getDecompInterface(); FunctionIterator iterator2 =currentProgram.getListing().getFunctions(true); for (Function function : iterator2) { if (function.getName().equals("FUN_000aeabc")){ printf("\t%s @ %s\n",function.getName(),function.getEntryPoint()); DecompileResults results = decompInterface.decompileFunction(function,0,monitor); Iterator iterator = results.getHighFunction().getPcodeOps(); while (iterator.hasNext()){ PcodeOpAST op = iterator.next(); printf("%s\n",op.toString()); } } } } private DecompInterface getDecompInterface() throws DecompileException { DecompileOptions options = new DecompileOptions(); DecompInterface ifc = new DecompInterface(); ifc.setOptions(options); ifc.setSimplificationStyle("decompile"); if (!ifc.openProgram(this.getCurrentProgram())) { throw new DecompileException("Decompiler", "Unable to initialize: "+ifc.getLastMessage()); } return ifc; }}
控制台信息如下:
我们拿到Function对象需要借助DecompInterface对象来做更多事情,上面getDecompInterface()可以定式写成这样,因我们只需要拿到DecompInterface对象其他的不用考虑。decompInterface.decompileFunction(function,0,monitor); 参数解析:反编译function,设置等待时间,monitor为常量。通过这个api可以拿到DecompileResults对象,这个对象中存在HighFunction对象变量,HighFunction对象中getPcodeOps()函数可以返回值pcode迭代器,循环迭代就能获取函数里对应的pcode了。
六、函数转伪C代码public class HelloWorld extends GhidraScript { private DecompInterface decompInterface=null; @Override public void run() throws Exception { decompInterface = getDecompInterface(); FunctionIterator iterator2 =currentProgram.getListing().getFunctions(true); for (Function function : iterator2) { if (function.getName().equals("FUN_000aeabc")){ printf("\t%s @ %s\n",function.getName(),function.getEntryPoint()); DecompileResults results = decompInterface.decompileFunction(function,0,monitor); printf("%s\n",results.getDecompiledFunction().getC()); } } } private DecompInterface getDecompInterface() throws DecompileException { DecompileOptions options = new DecompileOptions(); DecompInterface ifc = new DecompInterface(); ifc.setOptions(options); ifc.setSimplificationStyle("decompile"); if (!ifc.openProgram(this.getCurrentProgram())) { throw new DecompileException("Decompiler", "Unable to initialize: "+ifc.getLastMessage()); } return ifc; }}
打印输出了伪C字符
DecompileResults 调用getDecompiledFunction()函数返回DecompiledFunction对象,这个对象中的getC()方法可以返回编译好伪C。当然这里输出伪C并不是唯一方法,另外还有两种方法也可以输出伪C。因为有些需求场景使用伪C字符串并不方便,所以需要另外更适合编程的方法,这个留在下一部分。
转自先知社区欢迎收藏并分享朋友圈,让五邑人网络更安全
推荐文章
1
新永恒之蓝?微软SMBv3高危漏洞(CVE-2020-0796)分析复现
2
重大漏洞预警:ubuntu最新版本存在本地提权漏洞(已有EXP)