/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Outputs all calls to EtwWrite* reachable from each function along with provider and event metadata. // // functions.txt - functions to analyze. Defaults to exports otherwise. // ignore.txt - functions to ignore - especially error handling paths. // // Kernel-mode ETW functions are prefixed with Etw, the Win32 equivalents with Event and the native API ones with EtwEvent. // All APIs take the same parameters so this script should partially work on every binary. // //@category Functions.ETW //@author jdu2600 import java.io.*; import java.lang.Math.*; import java.nio.file.*; import java.util.*; import java.util.stream.*; import generic.stl.Pair; import docking.options.OptionsService; import ghidra.app.cmd.function.*; import ghidra.app.decompiler.*; import ghidra.app.script.*; import ghidra.app.services.*; import ghidra.framework.options.*; import ghidra.framework.plugintool.util.*; import ghidra.program.model.address.*; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; import ghidra.program.model.pcode.*; import ghidra.program.model.symbol.*; import ghidra.program.model.util.*; import ghidra.util.exception.*; public class DumpEtwWrites extends GhidraScript { // ********************** // Configurable Settings // quickscan: stop processing after maxEvents have been found, or extraCallDepth/maxExportCallDepth has been reached private Boolean quickScan = true; // maxEvents: maximum events to report per API private int maxEvents = 100; // maxCallDepth: maximum call depth to search for events private int maxCallDepth = 5; // extraCallDepth: maximum additional call depth to search for events private int extraCallDepth = 1; // maxExportCallDepth: maximum depth of exported functions to search private int maxExportCallDepth = 0; // debugPrint: verbose logging private Boolean debugPrint = false; // decompileTimeoutSeconds: per-function timeout for Ghidra decompilation private int decompileTimeoutSeconds = 60; // ********************** private String functionsFile = "functions.txt"; // analyse these functions private String ignoreFile = "ignore.txt"; // ignore these functions private DataType eventDescriptorType = null; private DataType ucharType = null; private DataType ushortType = null; private DataType ulonglongType = null; private DataType guidType = null; private DataType stringType = null; private DecompInterface decomplib = null; private Set exports = null; private Set functions = null; private Set ignored = null; private PrintWriter csv = null; private Dictionary> providerGuidMap = new Hashtable>(); // Address, (Guid, GuidSymbol) private List notYetImplemented = new LinkedList(); @Override public void run() throws Exception { printf("\n\n--==[ DumpEtwWrites ]==--\n"); printf(" * %s\n", currentProgram.getName()); if(quickScan) printf(" * quick scan mode - maxCallDepth=%d extraCallDepth=%d maxExportCallDepth=%d\n", maxCallDepth, extraCallDepth, maxExportCallDepth); else printf(" * full scan mode - finding all reachable ETW writes\n"); // we want the names of all exports - as we use these as a measure of relevance // for a given ETW write exports = new HashSet(); for(Symbol symbol : currentProgram.getSymbolTable().getAllSymbols(false)) if (symbol.isExternalEntryPoint()) exports.add(symbol.getName()); printf(" * found %d exports\n", exports.size()); // provide a list of the functions that you want to analyse, finding the ETW writes // if not provided, all exports will be parsed // e.g. this could be the list of Native API syscalls // or a list of RPC methods e.g. using xpn's RpcEnum try { functions = new HashSet(Files.readAllLines(Paths.get(functionsFile))); printf(" * analysing %d functions from %s\n", functions.size(), FileSystems.getDefault().getPath(functionsFile)); } catch(Exception e) { if(exports.contains("NtQuerySystemInformation")) { functions = new HashSet(); for(String func : exports) { if(func.startsWith("Nt")) functions.add(func); if(func.startsWith("Zw")) functions.add(func.replaceFirst("Zw", "Nt")); } for(String func : functions) if(func.startsWith("Nt")) exports.add(func); printf(" * %s not provided - analysing all %d syscalls instead\n", functionsFile, functions.size()); } else { functions = exports; printf(" * %s not provided - analysing all %d exports instead\n", functionsFile, functions.size()); } Files.write(FileSystems.getDefault().getPath("exports.txt"), exports); } // optionally provide a list of functions you want to ignore // e.g. common error handling functions like KeBugCheckEx try { ignored = new HashSet(Files.readAllLines(Paths.get(ignoreFile))); printf(" * ignoring %d functions\n", ignored.size()); } catch(Exception e) { ignored = new HashSet(); } // prepare the output file File csvFile = new File(currentProgram.getName() + ".csv"); csvFile.delete(); printf(" * output will be written to %s\n", csvFile.getAbsolutePath()); csv = new PrintWriter(csvFile); csv.println("Function,ProviderGuid,ProviderSymbol,ReghandleSymbol,WriteFunction,EventDescriptorSymbol,Id,Version,Channel,Level,Opcode,Task,Keyword,ContainingFunction,CallDepth,ExportedCallDepth,CallPath"); setUpDataTypes(); setUpDecompiler(currentProgram); if (!decomplib.openProgram(currentProgram)) { println("Decompiler Setup Error: " + decomplib.getLastMessage()); return; } try { /* first we cache the REGHANDLE address and the GUID of all register ETW Providers so that we can later * match ETW events to the Provider GUIDs * * providers are registered via [Etw|Event]Register(LPCGUID ProviderId, .., .., PREGHANDLE RegHandle) * * https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-etwregister * https://docs.microsoft.com/en-us/windows/win32/api/evntprov/nf-evntprov-eventregister */ for(String etwRegisterFuncName : etwRegisterFuncs) { List etwRegisterFuncList = getGlobalFunctions(etwRegisterFuncName); if(etwRegisterFuncList.size() > 1) { println("Script aborted: Found " + etwRegisterFuncList.size() + " instances of " + etwRegisterFuncName); return; } if(etwRegisterFuncList.size() == 0) continue; Function etwRegisterFunc = etwRegisterFuncList.get(0); Reference[] refs = this.getSymbolAt(etwRegisterFunc.getEntryPoint()).getReferences(null); printf(" * found %d %s calls\n", refs.length, etwRegisterFuncName); for (Reference ref : refs) { if (monitor.isCancelled()) break; analyseEtwRegisterCall(ref); } } /* now for each function, output the parameters of all ETW writes ( GUID, Event Id etc) */ for(String functionName : functions) { List functionList = getGlobalFunctions(functionName); if(functionList.size() == 0) { printf(" * %s - function not found\n", functionName); continue; } if(functionList.size() > 1) throw new Exception("Script aborted: Found " + functionList.size() + " instances of " + functionName); // decompile function & output ETW writes analyseFunction(functionList.get(0)); } } finally { decomplib.dispose(); csv.close(); } // if this isn't empty, then I haven't implemented all possible code paths yet :-( if (notYetImplemented.size() > 0) printf(" ---------- TODO ----------\n"); for(String todo : notYetImplemented) { printf("%s\n", todo); } } /* * EtwRegister - cache all global REGHANDLE addresses and registration details */ List etwRegisterFuncs = Arrays.asList("EtwRegister", "EventRegister", "EtwEventRegister", "EtwNotificationRegister", "EventNotificationRegister", "EtwEventNotificationRegister"); public void analyseEtwRegisterCall(Reference ref) throws Exception { Address refAddr = ref.getFromAddress(); if (refAddr == null) throw new NotFoundException("Reference.getFromAddress() == null"); if(refAddr.getOffset() == 0) return; // skip 'data' references - e.g. import / export offsets Data refData = getDataAt(refAddr); if (refData == null) refData = getDataContaining(refAddr); if (refData != null && (refData.getDataType().toString().startsWith("_IMAGE_RUNTIME_FUNCTION_ENTRY") || refData.getDataType().toString().startsWith("GuardCfgTableEntry") || refData.getDataType().isEquivalent(new IBO32DataType()) || refData.getDataType().isEquivalent(new DWordDataType()))) return; Function refFunc = currentProgram.getFunctionManager().getFunctionContaining(refAddr); if (refFunc == null) { int transactionID = currentProgram.startTransaction("attempting findFunctionEntry()"); CreateFunctionCmd createCmd = new CreateFunctionCmd(refAddr, true); createCmd.applyTo(currentProgram); currentProgram.endTransaction(transactionID, true); refFunc = currentProgram.getFunctionManager().getFunctionContaining(refAddr); } if (refFunc == null) // programmatic resolution failed - user should try manually finding and defining the function throw new NotFoundException("getFunctionContaining == null; refAddr=" + refAddr); ClangTokenGroup cCode = decomplib.decompileFunction(refFunc, decompileTimeoutSeconds, monitor).getCCodeMarkup(); if (cCode == null) throw new Exception("[CALL EtwRegister] Decompile Error: " + decomplib.getLastMessage()); try { boolean found = cacheProviderReghandle(refFunc, cCode, refAddr); if(!found) { // Could not resolve provider GUID(s) yet. // :TODO: Search a level deeper. Reference[] refRefs = this.getSymbolAt(refFunc.getEntryPoint()).getReferences(null); logTODO("Search the " + refRefs.length + " calls to " + refFunc.getName() + " for EtwRegister calls"); } } catch(NotYetImplementedException e) { logTODO(e.getMessage()); } } private boolean cacheProviderReghandle(Function f, ClangNode astNode, Address refAddr) throws Exception { if(astNode == null || astNode.getMinAddress() == null) return false; // leaf node if (astNode.getMaxAddress() == null) throw new InvalidInputException("ClangNode.getMaxAddress() is null"); boolean found = false; Stack callPath = new Stack(); // helps with back tracing constants, and determining relevance callPath.push(f); // have we found the call(s) yet? if (refAddr.getPhysicalAddress().equals(astNode.getMaxAddress()) && astNode instanceof ClangStatement) { ClangStatement stmt = (ClangStatement) astNode; PcodeOp pcodeOp = stmt.getPcodeOp(); if (pcodeOp.getOpcode() == PcodeOp.CALL) { long callAddress = astNode.getMaxAddress().getOffset(); String etwRegisterCall = getFunctionAt(pcodeOp.getInput(0).getAddress()).getName(); List pGuids = null; List reghandles = new LinkedList(); // we need to pass the calling function in order to back trace through any parameters Stack callingFunc = new Stack(); callingFunc.push(f); debugPrintf("%s :: %s\n", refAddr.toString(), stmt); if(etwRegisterCall.endsWith("NotificationRegister")) { // NTSTATUS EtwNotificationRegister (LPCGUID Guid, ULONG Type, PETW_NOTIFICATION_CALLBACK Callback, PVOID Context, PREGHANDLE RegHandle); throw new NotYetImplementedException(etwRegisterCall); } if(f.getName().startsWith("TraceLogging")) { if(pcodeOp.getNumInputs() == 0) { printf("[WARNING] Incomplete Decompilation @ 0x%x - %s\n", callAddress, stmt.toString()); return false; } // TraceLoggingRegisterEx_EtwRegister_EtwSetInformation(PTLGREG param_1, ...) List tlgregs = null; try { // Only the first parameter is needed // It points to an undocumented TraceLogging provider registration struct. tlgregs = resolveToConstant(1, callingFunc); } catch (NotFoundException e) { printf(" --> skipping %s due to local variable storage @ 0x%x\n", f.getName(), callAddress); return true; } printf(" * found %d TraceLoggingRegister calls\n", tlgregs.size()); for(int i=0; i < tlgregs.size(); i++) { Long tlgreg = tlgregs.get(i); // At offset 8 of the TLG registration is a pointer to the TLG provider metadata Long tlgprov = getLong(toAddr(tlgreg + 8)); // The provider guid is at offset -0x10 Address guidAddr = toAddr(tlgprov - 0x10); clearListing(guidAddr, guidAddr.add(guidType.getLength()-1)); createData(guidAddr, guidType); String guid = getDataAt(guidAddr).toString().substring(5); // The provider name is at offet +2 Address nameAddr = toAddr(tlgprov + 2); clearListing(nameAddr); createData(nameAddr, stringType); String providerName = getDataAt(nameAddr).toString().substring(3); // strip type // The REGHANDLE will be saved at offset 0x20 Long reghandle = tlgreg + 0x20; printf(" --> cached TraceLoggingRegister(%s, %s)\n", guid, providerName); providerGuidMap.put(reghandle, new Pair(guid, providerName)); } return true; } if(etwRegisterCall.startsWith("Etw") || etwRegisterCall.startsWith("Event")) { if(pcodeOp.getNumInputs() < 5) { printf("[WARNING] Incomplete Decompilation @ 0x%x - %s\n", callAddress, stmt.toString()); return false; } try { pGuids = resolveFunctionParameterToConstant(pcodeOp, 1, callingFunc); } catch (NotFoundException e) { printf(" --> skipping %s as guid not found @ 0x%x\n", etwRegisterCall, callAddress); return false; } try { reghandles = resolveFunctionParameterToConstant(pcodeOp, 4, callingFunc); } catch (NotFoundException e) { // a global REGHANDLE address was not found // assume local only use - and cache the containing function as the address debugPrintf("local REGHANDLE @ 0x%x\n", callAddress); reghandles.add(f.getEntryPoint().getOffset()); } } // :TODO: better guarantee the (guid, reghandle) correlation? if(pGuids.size() != reghandles.size()) throw new NotFoundException("ETW register parameter list size mismatch"); for(int i = 0; i < pGuids.size(); i++) { long pGuid = pGuids.get(i); String guid = ""; String guidSymbol = ""; if(pGuid != 0) { Address guidAddr = toAddr(pGuid); clearListing(guidAddr, guidAddr.add(guidType.getLength()-1)); createData(guidAddr, guidType); guid = getDataAt(guidAddr).toString().substring(5); // strip GUID_ prefix guidSymbol = SymbolAt(pGuid); } long reghandle = reghandles.get(i); if(reghandle != 0 && pGuid != 0) { printf(" --> cached %s(%s, %s)\n", etwRegisterCall, guid, guidSymbol); providerGuidMap.put(reghandle, new Pair(guid, guidSymbol)); found = true; } } return found; // CALL found - stop looking } } // otherwise traverse children to find call(s) for (int j = 0; j < astNode.numChildren(); j++) { found |= cacheProviderReghandle(f, astNode.Child(j), refAddr); } return found; } /* * functions of interest */ List etwWriteFuncs = Arrays.asList("EtwWrite", "EventWrite", "EtwEventWrite", "EtwWriteEx", "EventWriteEx", "EtwEventWriteEx", "EtwWriteTransfer", "EventWriteTransfer", "EtwEventWriteTransfer", "EtwEventWriteFull", "EtwWriteStartScenario", "EventWriteStartScenario", "EtwEventWriteStartScenario", "EtwWriteEndScenario", "EventWriteEndScenario", "EtwEventWriteEndScenario", "EtwWriteString", "EventWriteString", "EtwEventWriteString", "EtwWriteNoRegistration", "EventWriteNoRegistration", "EtwEventWriteNoRegistration"); List classicMessageFuncs = Arrays.asList("TraceMesssage", "EtwTraceMessage", "TraceMessageVa", "EtwTraceMessageVa"); List classicEventFuncs = Arrays.asList("TraceEvent", "EtwTraceEvent", "TraceEventInstance", "EtwTraceEventInstance"); public void analyseFunction(Function func) throws Exception { Queue queue = new LinkedList(); List processed = new LinkedList(); Stack callPath = new Stack(); // helps with back tracing constants, and determining relevance callPath.push(func); int eventCount = 0; int depth = 0; int exportDepth = 0; int maxLocalCallDepth = maxCallDepth; String lastParameters = null; // find all reachable ETW writes for(Function calledFunction : func.getCalledFunctions(monitor)) queue.add(new QueuedFunction(calledFunction, func, 1, 0, callPath)); while (queue.size() != 0) { if (monitor.isCancelled()) break; QueuedFunction next = queue.remove(); Function thisFunction = next.queuedFunction; Function callingFunction = next.callingFunction; depth = next.callDepth; exportDepth = next.exportedCallDepth; callPath = next.callPath; String funcName = thisFunction.getName(); String containingFunction = callingFunction.getName(); if( containingFunction.startsWith("FUN_")) { // Search for the first symbol in the call stack Stack stack = (Stack) callPath.clone(); while(containingFunction.startsWith("FUN_")) containingFunction = stack.pop().getName(); } if (processed.contains(funcName) || ignored.contains(funcName)) continue; if(quickScan && (depth > maxLocalCallDepth || exportDepth > maxExportCallDepth || eventCount == maxEvents)) continue; if(funcName.startsWith("_tlgWrite")) { ClangTokenGroup cCode = decomplib.decompileFunction(callingFunction, decompileTimeoutSeconds, monitor).getCCodeMarkup(); if (cCode == null) throw new Exception("[CALL _tlgWrite] Decompile Error: " + decomplib.getLastMessage()); List tlgWriteParametersList = new LinkedList(); try { getTlgWriteParameters(funcName, cCode, tlgWriteParametersList, callPath, 0); for(StringBuffer tlgWriteParameters : tlgWriteParametersList) { if(tlgWriteParameters.toString().equals(lastParameters)) continue; // remove duplicates lastParameters = tlgWriteParameters.toString(); csv.printf("%s,%s,%s,%d,%d,%s\n", func.getName(), tlgWriteParameters, containingFunction.replace(',','-'), depth, exportDepth, callPath.toString().replace(',','-').replace(' ','>') ); eventCount++; maxLocalCallDepth = Math.min(maxLocalCallDepth, depth + extraCallDepth); } } catch(NotFoundException e) { logTODO(e.getMessage()); } catch(NotYetImplementedException e) { logTODO(e.getMessage()); } } else if(classicEventFuncs.contains(funcName)) { logTODO("Implement classic provider support for " + containingFunction); } else if(classicMessageFuncs.contains(funcName)) { List wppWriteParametersList = getWppWriteParameters(funcName, callingFunction, callPath); for(String wppWriteParameters : wppWriteParametersList) { csv.printf("%s,%s,%s,%d,%d,%s\n", func.getName(), wppWriteParameters, containingFunction.replace(',','-'), depth, exportDepth, callPath.toString().replace(',','-').replace(' ','>') ); eventCount++; maxLocalCallDepth = Math.min(maxLocalCallDepth, depth + extraCallDepth); } } else if(etwWriteFuncs.contains(funcName)) { ClangTokenGroup cCode = decomplib.decompileFunction(callingFunction, decompileTimeoutSeconds, monitor).getCCodeMarkup(); if (cCode == null) throw new Exception("[CALL EtwWrite] Decompile Error: " + decomplib.getLastMessage()); List etwWriteParametersList = new LinkedList(); try { getEtwWriteParameters(funcName, cCode, etwWriteParametersList, callPath, 0); for(StringBuffer etwWriteParameters : etwWriteParametersList) { if(etwWriteParameters.toString().equals(lastParameters)) continue; // remove duplicates lastParameters = etwWriteParameters.toString(); csv.printf("%s,%s,%s,%d,%d,%s\n", func.getName(), etwWriteParameters, containingFunction.replace(',','-'), depth, exportDepth, callPath.toString().replace(',','-').replace(' ','>') ); eventCount++; maxLocalCallDepth = Math.min(maxLocalCallDepth, depth + extraCallDepth); } } catch(NotFoundException e) { logTODO(e.getMessage()); } catch(NotYetImplementedException e) { logTODO(e.getMessage()); } } // Handling classic kernel events via this wrapper function adds more context else if(funcName.equals("EtwTraceKernelEvent")) { List kernelEventParametersList = getTraceKernelEventParameters(funcName, callingFunction, callPath); for(String kernelEventParameters : kernelEventParametersList) { if(kernelEventParameters.toString().equals(lastParameters)) continue; // remove duplicates lastParameters = kernelEventParameters.toString(); csv.printf("%s,%s,%s,%d,%d,%s\n", func.getName(), kernelEventParameters, containingFunction.replace(',','-'), depth, exportDepth, callPath.toString().replace(',','-').replace(' ','>') ); eventCount++; maxLocalCallDepth = Math.min(maxLocalCallDepth, depth + extraCallDepth); } } else { String functionCrumb = func.getName(); if(functionCrumb.length() > 5) functionCrumb = functionCrumb.substring(2, functionCrumb.length() - 5); if(exports.contains(funcName) && !funcName.contains(functionCrumb)) exportDepth++; processed.add(funcName); for(Function calledFunction : thisFunction.getCalledFunctions(monitor)) { if(calledFunction == null) throw new Exception("Argh!"); if(calledFunction.getName() == null) createFunction(calledFunction.getEntryPoint(), null); if(calledFunction.getName() == null) throw new Exception("FUN_" + calledFunction.getEntryPoint().toString() + " is not defined"); callPath = (Stack) next.callPath.clone(); if(funcName.startsWith("FUN_")) queue.add(new QueuedFunction(calledFunction, thisFunction, depth, exportDepth, callPath)); else { callPath.add(thisFunction); queue.add(new QueuedFunction(calledFunction, thisFunction, depth+1, exportDepth, callPath)); } } } } printf(" * %s - found %d events in %d functions. callDepth=%d exportDepth=%d\n", func.getName(), eventCount, processed.size(), maxLocalCallDepth, exportDepth); csv.flush(); } private boolean getEtwWriteParameters(String etwWriteCall, ClangNode node, List etwWriteParametersList, Stack callPath, int depth) throws Exception { if(node == null || node.getMinAddress() == null) return false; // leaf node if (node.getMaxAddress() == null) throw new InvalidInputException("ClangNode.getMaxAddress() is null"); boolean found = false; // have we found the right CALL yet? if(node instanceof ClangStatement) { ClangStatement stmt = (ClangStatement) node; PcodeOp pcodeOp = stmt.getPcodeOp(); if (pcodeOp != null && pcodeOp.getOpcode() == PcodeOp.CALL && getSymbolAt(pcodeOp.getInput(0).getAddress()) != null && getSymbolAt(pcodeOp.getInput(0).getAddress()).getName().endsWith(etwWriteCall)) { if(pcodeOp.getNumInputs() < 3) { printf("[WARNING] Incomplete Decompilation @ 0x%x - %s\n", node.getMaxAddress().getOffset(), stmt.toString()); } debugPrintf("%s :: %s\n", callPath.peek().toString(), stmt); if(etwWriteCall.endsWith("WriteNoRegistration")) { // NTSTATUS EtwEventWriteNoRegistration (PCGUID ProviderId, PCEVENT_DESCRIPTOR EventDescriptor, ULONG UserDataCount, PEVENT_DATA_DESCRIPTOR UserData); throw new NotYetImplementedException("EtwEventWriteNoRegistration"); } long reghandle = 0; if(pcodeOp.getNumInputs() > 1) { List reghandles = null; try { reghandles = resolveFunctionParameterToConstant(pcodeOp, 1, callPath); if(reghandles.size() == 0) throw new NotFoundException("ETW write with no REGHANDLE"); if(reghandles.size() > 1) throw new NotYetImplementedException("ETW write with multiple REGHANDLE"); reghandle = reghandles.get(0); } catch (NotFoundException e) { debugPrintf("ETW write REGHANDLE resolves to local variable in " + callPath.peek()); // Attempt lookup via function address instead reghandle = callPath.peek().getEntryPoint().getOffset(); } catch (NotYetImplementedException e) { // non fatal logTODO("Handle REGHANDLE in " + e.getMessage()); } } String providerGuid = "???"; String providerSymbol = ""; String reghandleSymbol = SymbolAt(reghandle); Pair providerRegistration = providerGuidMap.get(reghandle); if ( providerRegistration != null) { providerGuid = providerRegistration.first; providerSymbol = providerRegistration.second; } StringBuffer etwWriteParameters = new StringBuffer(); if(etwWriteCall.endsWith("WriteString")) { // NTSTATUS EtwWriteString(REGHANDLE RegHandle, UCHAR Level, ULONGLONG Keyword, LPCGUID ActivityId, PCWSTR String) etwWriteParameters.append(providerGuid + ","); etwWriteParameters.append(providerSymbol + ","); etwWriteParameters.append(reghandleSymbol + ","); etwWriteParameters.append(etwWriteCall + ","); List levels = resolveFunctionParameterToConstant(pcodeOp, 2, callPath); List keywords = resolveFunctionParameterToConstant(pcodeOp, 3, callPath); List strings = resolveFunctionParameterToConstant(pcodeOp, 5, callPath); if(levels.size() + keywords.size() + strings.size() != 3) throw new NotYetImplementedException("EtwWriteString with multiple paths"); etwWriteParameters.append(",,,,"+ levels.get(0) + ",,," + keywords.get(0)); // :TODO: output (PCWSTR String) parameter logTODO(etwWriteCall); return true; } // NTSTATUS EtwWrite*(REGHANDLE RegHandle, PCEVENT_DESCRIPTOR EventDescriptor, LPCGUID ActivityId, ULONG UserDataCount, PEVENT_DATA_DESCRIPTOR UserData); Address event = null; if(pcodeOp.getNumInputs() > 2) { List pEvents = new LinkedList(); try { debugPrintf("resolveFunctionParameterToConstant(2)\n"); pEvents = resolveFunctionParameterToConstant(pcodeOp, 2, callPath); if(pEvents.size() == 0) logTODO("EtwWrite EVENT_DESCRIPTOR not found in " + callPath.peek()); } catch (NotFoundException e) { logTODO("EtwWrite EVENT_DESCRIPTOR not found in " + callPath.peek()); etwWriteParameters = new StringBuffer(); etwWriteParameters.append(providerGuid + ","); etwWriteParameters.append(providerSymbol + ","); etwWriteParameters.append(reghandleSymbol + ","); etwWriteParameters.append(etwWriteCall + ","); etwWriteParameters.append(",,,,,,,"); // not found etwWriteParametersList.add(etwWriteParameters); } catch (NotYetImplementedException e) { throw new NotYetImplementedException("EVENT_DESCRIPTOR " + e.getMessage()); } for(long pEvent : pEvents) { if(pEvent == 0) continue; // a quirk of ghidra's decompilation? Or because of initialise to zero and error paths? etwWriteParameters = new StringBuffer(); etwWriteParameters.append(providerGuid + ","); etwWriteParameters.append(providerSymbol + ","); etwWriteParameters.append(reghandleSymbol + ","); etwWriteParameters.append(etwWriteCall + ","); String eventDescriptorSymbol = SymbolAt(pEvent); etwWriteParameters.append(eventDescriptorSymbol + ","); event = toAddr(pEvent); clearListing(event, event.add(eventDescriptorType.getLength()-1)); try { createData(event, eventDescriptorType); appendStructure(event, etwWriteParameters, true); } catch(CodeUnitInsertionException e) { debugPrintf("EVENT_DESCRIPTOR parsing failed @ 0x%x", pEvent); etwWriteParameters.append(",,,,,,"); } etwWriteParametersList.add(etwWriteParameters); } } found = true; } } // search children until call(s) found for (int j = 0; j < node.numChildren(); j++) found |= getEtwWriteParameters(etwWriteCall, node.Child(j), etwWriteParametersList, callPath, depth + 1); if(!found && depth == 0) throw new Exception("didn't find " + etwWriteCall); return found; } private boolean getTlgWriteParameters(String tlgWriteCall, ClangNode node, List tlgWriteParametersList, Stack callPath, int depth) throws Exception { if(node == null || node.getMinAddress() == null) return false; // leaf node if (node.getMaxAddress() == null) throw new InvalidInputException("ClangNode.getMaxAddress() is null"); boolean found = false; // have we found the right CALL yet? if(node instanceof ClangStatement) { ClangStatement stmt = (ClangStatement) node; PcodeOp pcodeOp = stmt.getPcodeOp(); if (pcodeOp != null && pcodeOp.getOpcode() == PcodeOp.CALL && getSymbolAt(pcodeOp.getInput(0).getAddress()) != null && getSymbolAt(pcodeOp.getInput(0).getAddress()).getName().endsWith(tlgWriteCall)) { if(pcodeOp.getNumInputs() < 2) { printf("[WARNING] Incomplete Decompilation @ 0x%x - %s\n", node.getMaxAddress().getOffset(), stmt.toString()); } found = true; if(tlgWriteCall.startsWith("_tlgWriteEx")) tlgWriteCall = "_tlgWriteEx"; else if(tlgWriteCall.startsWith("_tlgWriteTransfer")) tlgWriteCall = "_tlgWriteTransfer"; debugPrintf("%s :: %s\n", tlgWriteCall, stmt); // _tlgWrite(PTLG_REGISTRATION, PTLG_EVENT, ...) long reghandle = 0; if(pcodeOp.getNumInputs() > 1) { List reghandles = null; try { reghandles = resolveFunctionParameterToConstant(pcodeOp, 1, callPath); if(reghandles.size() == 0) throw new NotFoundException("TLG write with no REGHANDLE"); if(reghandles.size() > 1) throw new NotYetImplementedException("TLG write with multiple REGHANDLE"); // REGHANDLE is at offset 0x20 in TLG_REGISTRATION reghandle = reghandles.get(0) + 0x20; } catch (NotFoundException e) { // non fatal logTODO("_tlgWrite REGHANDLE not found in " + callPath.peek()); } catch (NotYetImplementedException e) { // non fatal logTODO("REGHANDLE " + e.getMessage()); } } String providerGuid = "???"; String providerName = ""; Pair providerRegistration = providerGuidMap.get(reghandle); if ( providerRegistration != null) { providerGuid = providerRegistration.first; providerName = providerRegistration.second; } String reghandleSymbol = SymbolAt(reghandle); if(reghandleSymbol.startsWith("DAT_")) reghandleSymbol = ""; if(pcodeOp.getNumInputs() > 2) { List pTlgEvents = null; // TLG_EVENT pointers try { pTlgEvents = resolveFunctionParameterToConstant(pcodeOp, 2, callPath); } catch (NotFoundException e) { throw new NotYetImplementedException("TLG write EVENT_DESCRIPTOR resolves to local variable in " + callPath.peek()); // :TODO: } catch (NotYetImplementedException e) { throw new NotYetImplementedException("EVENT_DESCRIPTOR " + e.getMessage()); } if(pTlgEvents.size() == 0) throw new NotFoundException("TLG write with no EVENT_DESCRIPTOR"); for(long pEvent : pTlgEvents) { if(pEvent == 0) continue; // a quirk of ghidra's decompilation? Or because of initialise to zero and error paths? StringBuffer tlgWriteParameters = new StringBuffer(); tlgWriteParameters.append(providerGuid + ","); tlgWriteParameters.append(providerName + ","); tlgWriteParameters.append(reghandleSymbol + ","); // usually empty for TLG tlgWriteParameters.append(tlgWriteCall + ","); // https://posts.specterops.io/data-source-analysis-and-dynamic-windows-re-using-wpp-and-tracelogging-e465f8b653f7 // UCHAR Channel // UCHAR Level // UCHAR OpCode // UINT64 Keyword // UINT16 Size // UCHAR Zero // CSTR EventName Byte channel = getByte(toAddr(pEvent)); Byte level = getByte(toAddr(pEvent + 1)); Byte opcode = getByte(toAddr(pEvent + 2)); Long keyword = getLong(toAddr(pEvent + 3)); Address nameAddr = toAddr(pEvent + 15); clearListing(nameAddr); createData(nameAddr, stringType); String eventName = getDataAt(nameAddr).toString().substring(3); // strip type // TraceLogging doesn't have equivalent fields for id, task and version. tlgWriteParameters.append(eventName + ","); tlgWriteParameters.append("-,-,"); // Id, Version tlgWriteParameters.append(channel + ","); tlgWriteParameters.append(level + ","); tlgWriteParameters.append(opcode + ","); tlgWriteParameters.append("-,"); // Task tlgWriteParameters.append(String.format("0x%x", keyword)); tlgWriteParametersList.add(tlgWriteParameters); } } else { StringBuffer tlgWriteParameters = new StringBuffer(); tlgWriteParameters.append(providerGuid + ","); tlgWriteParameters.append(providerName + ","); tlgWriteParameters.append(reghandleSymbol + ","); tlgWriteParameters.append(tlgWriteCall + ","); tlgWriteParameters.append(",,,,,,,"); tlgWriteParametersList.add(tlgWriteParameters); } } } // search children until call(s) found for (int j = 0; j < node.numChildren(); j++) found |= getTlgWriteParameters(tlgWriteCall, node.Child(j), tlgWriteParametersList, callPath, depth + 1); if(!found && depth == 0) throw new Exception("didn't find " + tlgWriteCall); return found; } private List getWppWriteParameters(String wppWriteCall, Function callingFunction, Stack callPath) throws Exception { HighFunction hf = decomplib.decompileFunction(callingFunction, decompileTimeoutSeconds, monitor).getHighFunction(); if (hf == null) throw new Exception("[CALL WppWrite] Decompile Error: " + decomplib.getLastMessage()); List wppWriteParametersList = new LinkedList(); boolean found = false; Iterator ops = hf.getPcodeOps(); while (ops.hasNext() && !monitor.isCancelled()) { PcodeOpAST pcodeOp = ops.next(); if (pcodeOp.getOpcode() == PcodeOp.CALL && getSymbolAt(pcodeOp.getInput(0).getAddress()) != null && getSymbolAt(pcodeOp.getInput(0).getAddress()).getName().endsWith(wppWriteCall)) { if(pcodeOp.getNumInputs() < 4) { printf("[WARNING] Incomplete Decompilation of " + callingFunction.getName()); } // ULONG TraceMessage(TRACEHANDLE LoggerHandle, ULONG MessageFlags, LPCGUID MessageGuid, USHORT MessageNumber, ...); StringBuffer wppWriteParameters = new StringBuffer(); found = true; try { long tracehandle = resolveParameterToConstant(pcodeOp, wppWriteCall, "TRACEHANDLE", 1, callPath); long messageFlags = resolveParameterToConstant(pcodeOp, wppWriteCall, "MessageFlags", 2, callPath); long _messageGuid = resolveParameterToConstant(pcodeOp, wppWriteCall, "MessageGuid", 3, callPath); long messageId = pcodeOp.getNumInputs() == 4 ? 0 : resolveParameterToConstant(pcodeOp, wppWriteCall, "MessageId", 4, callPath); String providerGuid = "???"; String providerSymbol = ""; String reghandleSymbol = SymbolAt(tracehandle); Pair providerRegistration = providerGuidMap.get(tracehandle); if ( providerRegistration != null) { providerGuid = providerRegistration.first; providerSymbol = providerRegistration.second; } String messageGuid = "???"; Pair guidRegistration = providerGuidMap.get(_messageGuid); if ( guidRegistration != null) messageGuid = guidRegistration.first; wppWriteParameters.append("WPP_"+providerGuid + ","); wppWriteParameters.append(providerSymbol + ","); wppWriteParameters.append(reghandleSymbol + ","); wppWriteParameters.append(wppWriteCall + ","); wppWriteParameters.append(messageGuid + ","); // EventDescriptorSymbol wppWriteParameters.append(messageId + ","); // Id wppWriteParameters.append(",,,,,"); // Version,Channel,Level,Opcode,Task, wppWriteParameters.append("Flags=" + messageFlags); // Keyword } catch(NotFoundException e) { wppWriteParameters.append(",,,,,,,,,,,"); } wppWriteParametersList.add(wppWriteParameters.toString()); } } if(!found) throw new NotFoundException("didn't find any " + wppWriteCall + " calls in " + callPath.peek()); return wppWriteParametersList; } private List getTraceKernelEventParameters(String funcName, Function callingFunction, Stack callPath) throws Exception { HighFunction hf = decomplib.decompileFunction(callingFunction, decompileTimeoutSeconds, monitor).getHighFunction(); if (hf == null) throw new Exception("[CALL " + funcName + "] Decompile Error: " + decomplib.getLastMessage()); List parametersList = new LinkedList(); boolean found = false; Iterator ops = hf.getPcodeOps(); while (ops.hasNext() && !monitor.isCancelled()) { PcodeOpAST pcodeOp = ops.next(); if (pcodeOp.getOpcode() == PcodeOp.CALL && getSymbolAt(pcodeOp.getInput(0).getAddress()) != null && getSymbolAt(pcodeOp.getInput(0).getAddress()).getName().endsWith(funcName)) { if(pcodeOp.getNumInputs() < 3) { printf("[WARNING] Incomplete Decompilation of " + callingFunction.getName()); } StringBuffer parameters = new StringBuffer(); found = true; parameters.append("Windows Kernel Trace,"); try { // EtwTraceKernelEvent(PEVENT_DESCRIPTOR, UINT32, PERFINFO_GROUPMASK, LOG_TYPE, UINT32) long perfinfo = resolveParameterToConstant(pcodeOp, funcName, "PERFINFO_GROUPMASK", 3, callPath); long logtype = resolveParameterToConstant(pcodeOp, funcName, "LOG_TYPE", 4, callPath); // If someone wants to reverse the format then more event metadata could likely be // extracted from the 1st, 2nd and 5th parameters. parameters.append(LookupPerfInfoMask(perfinfo) + ","); parameters.append(LookupTraceGroup(logtype) + ","); parameters.append(funcName + ","); parameters.append(LookupLogType(logtype) + ","); parameters.append(",,,,,,"); // Id,Version,Channel,Level,Opcode,Task,Keyword } catch(NotFoundException e) { parameters.append(",,,,,,,,,,"); } parametersList.add(parameters.toString()); } } if(!found) throw new NotFoundException("didn't find any " + funcName + " calls in " + callPath.peek()); return parametersList; } // resolve an intermediate pcode call parameter to a list of possible constant values public List resolveFunctionParameterToConstant(PcodeOp call, int paramIndex, Stack callPath) throws Exception { if (call.getOpcode() != PcodeOp.CALL) throw new InvalidInputException("Expected a CALL function"); Varnode calledFunc = call.getInput(0); if (calledFunc == null || !calledFunc.isAddress()) throw new InvalidInputException("Invalid CALL PcodeOp"); if (paramIndex >= call.getNumInputs()) throw new InvalidInputException("Decompiler discovered insufficient parameters"); Varnode param = call.getInput(paramIndex); if (param == null) throw new NotFoundException("Missing Parameter"); // else process return resolveVarnodeToConstant(param, callPath, 0); } // resolve a variable to a list of possible constant values private List resolveVarnodeToConstant(Varnode node, Stack callPath, int astDepth) throws Exception { if (node.isConstant()) return new LinkedList(Arrays.asList(node.getOffset())); if (node.isAddress()) return new LinkedList(Arrays.asList(node.getAddress().getOffset())); HighVariable hvar = node.getHigh(); if (hvar instanceof HighParam) return resolveToConstant(((HighParam)hvar).getSlot() + 1, callPath); if (hvar instanceof HighGlobal) debugPrintf(":TODO: found a global... already handled?"); if (hvar instanceof HighLocal) { // printf("### HighLocal " + callPath.peek().getName() + " node: " + node.getDef() + "\n"); return resolvePcodeOpToConstant(node.getDef(), callPath, astDepth); } if (hvar instanceof HighOther) { ///printf("### HighOther " + callPath.peek().getName() + " hvar: " + hvar + "\n"); ///printf("### getRepresentative: " + hvar.getRepresentative().getDef() + "\n"); ///printf("### getDef: " + node.getDef() + "\n"); if(hvar.getRepresentative().getDef() != null) return resolvePcodeOpToConstant(hvar.getRepresentative().getDef(), callPath, astDepth); if(node.getDef() != null) return resolvePcodeOpToConstant(node.getDef(), callPath, astDepth); } throw new NotFoundException(); } // resolve a function call parameter to a list of possible constant values private List resolveToConstant(int parameterIndex, Stack callPath) throws Exception { List constants = new LinkedList(); Stack parentCallPath = (Stack)callPath.clone(); Function func = parentCallPath.pop(); if (callPath.size() > 1) { // forward trace - with full call path ClangNode astNode = decomplib.decompileFunction(parentCallPath.peek(), decompileTimeoutSeconds, monitor).getCCodeMarkup(); if (astNode == null) throw new Exception("[resolveToConstant] Decompile Error: " + decomplib.getLastMessage()); constants.addAll(resolveToConstant(astNode, func, parameterIndex, parentCallPath, 0)); } else { // backwards trace - incomplete call path, follow all paths for(Function callingFunction : func.getCallingFunctions(monitor)) { ClangNode astNode = decomplib.decompileFunction(callingFunction, decompileTimeoutSeconds, monitor).getCCodeMarkup(); if (astNode == null) throw new Exception("[resolveToConstant] Decompile Error: " + decomplib.getLastMessage()); parentCallPath.push(callingFunction); constants.addAll(resolveToConstant(astNode, func, parameterIndex, parentCallPath, 0)); parentCallPath.pop(); } } if (constants.size() == 0) throw new NotFoundException("resolveToConstant(parameter)"); return constants.stream().distinct().collect(Collectors.toList()); } // resolve a high level C statement to a list of possible constant values private List resolveToConstant(ClangNode astNode, Function func, int parameterIndex, Stack callPath, int nodeDepth) throws Exception { List constants = new LinkedList(); // find the call(s) to func - and back trace all possible parameter values if(astNode instanceof ClangStatement) { ClangStatement stmt = (ClangStatement) astNode; PcodeOp pcodeOp = stmt.getPcodeOp(); if (pcodeOp != null && pcodeOp.getOpcode() == PcodeOp.CALL && getFunctionAt(pcodeOp.getInput(0).getAddress()) != null && getFunctionAt(pcodeOp.getInput(0).getAddress()).getName().equals(func.getName())) { if(parameterIndex >= pcodeOp.getNumInputs()) { // After porting to Ghidra 11 this condition is triggering when it shouldn't. // Recovering programmatically appears to require invalidate the existing // decompilation result so isn't trivial. // Print (likely) manual recovery instructions for now. printf("Navigate to " + pcodeOp.getInput(0).getAddress() + " " + stmt + "\n"); printf("P 'Commit Params/Return' for this function and retry\n"); printf("Or try Auto Analyze again if it keeps happening\n"); throw new ArrayIndexOutOfBoundsException(astNode.getMinAddress() + " CALL " + stmt + " parameterIndex=" + parameterIndex + " of " + (pcodeOp.getNumInputs() - 1)); } constants.addAll(resolveVarnodeToConstant(pcodeOp.getInput(parameterIndex), callPath, 0)); } } // also traverse all children to find call(s) for (int i = 0; i < astNode.numChildren(); i++) constants.addAll(resolveToConstant(astNode.Child(i), func, parameterIndex, callPath, nodeDepth + 1)); if(nodeDepth == 0 && constants.isEmpty()) throw new NotFoundException("resolveToConstant(parameter)"); return constants.stream().distinct().collect(Collectors.toList()); } // resolve an intermediate pcode operation to a list of possible constant values private List resolvePcodeOpToConstant(PcodeOp node, Stack callPath, int astDepth) throws Exception { if(node == null) throw new NotFoundException("node == null"); if(astDepth > 128) throw new NotFoundException("Pcode AST depth > 128 in " + callPath.peek()); debugPrintf("%s (depth=%d)\n", node.toString(), astDepth); List input0; List input1; List output = new LinkedList(); int opcode = node.getOpcode(); switch (opcode) { case PcodeOp.CAST: case PcodeOp.COPY: case PcodeOp.INT_ZEXT: // zero-extend output = resolveVarnodeToConstant(node.getInput(0), callPath, astDepth+1); break; case PcodeOp.INT_2COMP: // twos complement input0 = resolveVarnodeToConstant(node.getInput(0), callPath, astDepth+1); output = input0.stream().map(a->-a).collect(Collectors.toList()); break; case PcodeOp.INT_NEGATE: input0 = resolveVarnodeToConstant(node.getInput(0), callPath, astDepth+1); output = input0.stream().map(a->~a).collect(Collectors.toList()); break; case PcodeOp.LOAD: output = resolveVarnodeToConstant(node.getInput(1), callPath, astDepth+1); break; case PcodeOp.INT_ADD: case PcodeOp.PTRSUB: // pointer to structure and offset to subcomponent input0 = resolveVarnodeToConstant(node.getInput(0), callPath, astDepth+1); input1 = resolveVarnodeToConstant(node.getInput(1), callPath, astDepth+1); for(int i = 0; i < input0.size(); i++) for(int j = 0; j < input1.size(); j++) output.add(input0.get(i) + input1.get(j)); break; case PcodeOp.INT_MULT: input0 = resolveVarnodeToConstant(node.getInput(0), callPath, astDepth+1); input1 = resolveVarnodeToConstant(node.getInput(1), callPath, astDepth+1); for(int i = 0; i < input0.size(); i++) for(int j = 0; j < input1.size(); j++) output.add(input0.get(i) * input1.get(j)); break; case PcodeOp.INT_NOTEQUAL: input0 = resolveVarnodeToConstant(node.getInput(0), callPath, astDepth+1); input1 = resolveVarnodeToConstant(node.getInput(1), callPath, astDepth+1); for(int i = 0; i < input0.size(); i++) for(int j = 0; j < input1.size(); j++) output.add((input0.get(i) != input1.get(j)) ? 1L : 0L); break; case PcodeOp.PTRADD: input0 = resolveVarnodeToConstant(node.getInput(0), callPath, astDepth+1); input1 = resolveVarnodeToConstant(node.getInput(1), callPath, astDepth+1); List elementSize = resolveVarnodeToConstant(node.getInput(2), callPath, astDepth+1); for(int i = 0; i < input0.size(); i++) for(int j = 0; j < input1.size(); j++) for(int k = 0; k < elementSize.size(); k++) output.add(input0.get(i) + (input1.get(j) * elementSize.get(k))); break; case PcodeOp.INT_AND: input0 = resolveVarnodeToConstant(node.getInput(0), callPath, astDepth+1); input1 = resolveVarnodeToConstant(node.getInput(1), callPath, astDepth+1); for(int i = 0; i < input0.size(); i++) for(int j = 0; j < input1.size(); j++) output.add(input0.get(i) & input1.get(j)); break; case PcodeOp.MULTIEQUAL: for(Varnode n : node.getInputs()) output.addAll(resolveVarnodeToConstant(n, callPath, astDepth+1)); break; case PcodeOp.INDIRECT: debugPrintf("ignoring possible indirect effects in %s\n", callPath.peek()); output = resolveVarnodeToConstant(node.getInput(0), callPath, astDepth+1); break; case PcodeOp.CALL: debugPrintf("guessing TRUE for CALL in %s\n", callPath.peek()); output.add(1L); // TRUE break; default: throw new NotYetImplementedException("PcodeOp " + node.toString() + " in " + callPath.peek()); } // remove duplicates return output.stream().distinct().collect(Collectors.toList()); } private void appendStructure(Address addr, StringBuffer buff, Boolean valuesOnly) throws Exception { Data struct = getDataAt(addr); for(int i = 0; i < struct.getNumComponents(); i++) { if(i != 0) buff.append(","); Data component = struct.getComponent(i); if(!valuesOnly) buff.append(component.getComponentPathName() + "="); DataType dt = component.getDataType(); if (dt.isEquivalent(ucharType)) { buff.append(component.getUnsignedByte(0)); } else if (dt.isEquivalent(ushortType)) { buff.append(component.getUnsignedShort(0)); } else if (dt.isEquivalent(ulonglongType)) { buff.append(String.format("0x%x", component.getBigInteger(0, 8, false))); } else throw new Exception("Unsupported Type:" + dt.toString() + " (DataTypeManager=" + dt.getDataTypeManager().getName() + "CategoryPath=" + dt.getCategoryPath() + ")"); } } private long resolveParameterToConstant(PcodeOp pcodeOp, String function, String parameterType, int parameterIndex, Stack callPath) throws Exception { if(pcodeOp.getNumInputs() <= parameterIndex) throw new Exception("Decompilation failure in " + function); List constants = null; try { constants = resolveFunctionParameterToConstant(pcodeOp, parameterIndex, callPath); if(constants.size() == 0) throw new NotFoundException(parameterType + " not found in " + callPath.peek() + "->" + function); if(constants.size() > 1) throw new NotYetImplementedException(parameterType + " with multiple values in " + callPath.peek() + "->" + function); return constants.get(0); } catch (NotFoundException e) { logTODO(parameterType + " resolves to local variable in " + callPath.peek() + "->" + function); } catch (NotYetImplementedException e) { logTODO(parameterType + " failed to resolve to constant in " + callPath.peek() + "->" + function + " due to " + e.getMessage()); } throw new NotFoundException(parameterType + " not found in " + callPath.peek() + "->" + function); } private String SymbolAt(long address) { String strSymbol = ""; Symbol symbol = this.getSymbolAt(toAddr(address)); if (symbol != null) strSymbol = symbol.toString(); if (strSymbol.startsWith("DAT_")) strSymbol = ""; return strSymbol; } private void setUpDecompiler(Program program) { decomplib = new DecompInterface(); DecompileOptions options; options = new DecompileOptions(); OptionsService service = state.getTool().getService(OptionsService.class); if (service != null) { ToolOptions opt = service.getOptions("Decompiler"); options.grabFromToolAndProgram(null,opt,program); } decomplib.setOptions(options); decomplib.toggleCCode(true); decomplib.toggleSyntaxTree(true); decomplib.setSimplificationStyle("decompile"); } private void setUpDataTypes() throws NotFoundException { eventDescriptorType = getDataType("EVENT_DESCRIPTOR"); ulonglongType = getDataType("ULONGLONG"); ushortType = getDataType("USHORT"); ucharType = getDataType("UCHAR"); guidType = getDataType("GUID"); stringType = getDataType("TerminatedCString"); } private DataType getDataType(String name) throws NotFoundException { DataTypeManagerService service = state.getTool().getService(DataTypeManagerService.class); // Loop through all managers in the data type manager service for (DataTypeManager manager : service.getDataTypeManagers()) { List dataTypes = new ArrayList(); manager.findDataTypes(name, dataTypes); if(dataTypes.size() != 0) return dataTypes.get(0); } throw new NotFoundException(name); } private void debugPrintf(String template, Object... args) { if(debugPrint) printf("[DEBUG] " + template, args); } private void logTODO(String message) { if(!notYetImplemented.contains(message)) notYetImplemented.add(message); } public class QueuedFunction { public Function queuedFunction; public Function callingFunction; public int callDepth; public int exportedCallDepth; public Stack callPath; public QueuedFunction(Function queuedFunction, Function callingFunction, int callDepth, int exportedCallDepth, Stack callPath ) { this.queuedFunction = queuedFunction; this.callingFunction = callingFunction; this.callDepth = callDepth; this.exportedCallDepth = exportedCallDepth; this.callPath = callPath; } } // // Some helpful constants from Windows headers // public String LookupPerfInfoMask(long perfinfo) { switch((int)perfinfo) { case 0x00000001: return "PROCESS"; case 0x00000002: return "THREAD"; case 0x00000004: return "LOADER"; case 0x00000200: return "FILENAME"; case 0x00001000: return "ALL_FAULTS"; case 0x00002000: return "HARD_FAULTS"; case 0x00010000: return "NETWORK"; case 0x00020000: return "REGISTRY"; case 0x00040000: return "DBGPRINT"; case 0x00000008: return "COUNTER"; case 0x00000400: return "DISK_IO_INIT"; case 0x00100000: return "ALPC"; case 0x00200000: return "SPLIT_IO"; case 0x02000000: return "FILE_IO"; case 0x04000000: return "FILE_IO_INIT"; case 0x00008000: return "VAMAP"; case 0x20000001: return "MEMORY"; case 0x20000002: return "PROFILE"; case 0x20000004: return "CONTEXT_SWITCH"; case 0x20000008: return "FOOTPRINT"; case 0x20000010: return "DRIVERS"; case 0x20000020: return "REFSET"; case 0x20000040: return "POOL"; case 0x20000041: return "POOLTRACE"; case 0x20000080: return "DPC"; case 0x20000100: return "COMPACT_CSWITCH"; case 0x20000200: return "DISPATCHER"; case 0x20000400: return "PMC_PROFILE"; case 0x20000402: return "PROFILING"; case 0x20000800: return "PROCESS_INSWAP"; case 0x20001000: return "AFFINITY"; case 0x20002000: return "PRIORITY"; case 0x20004000: return "INTERRUPT"; case 0x20008000: return "VIRTUAL_ALLOC"; case 0x20010000: return "SPINLOCK"; case 0x20020000: return "SYNC_OBJECTS"; case 0x20040000: return "DPC_QUEUE"; case 0x20080000: return "MEMINFO"; case 0x20100000: return "CONTMEM_GEN"; case 0x20200000: return "SPINLOCK_CNTRS"; case 0x20210000: return "SPININSTR"; case 0x20400000: return "SESSION"; case 0x20800000: return "MEMINFO_WS"; case 0x21000000: return "KERNEL_QUEUE"; case 0x22000000: return "INTERRUPT_STEER"; case 0x24000000: return "SHOULD_YIELD"; case 0x28000000: return "WS"; case 0x40000001: return "ANTI_STARVATION"; case 0x40000002: return "PROCESS_FREEZE"; case 0x40000004: return "PFN_LIST"; case 0x40000008: return "WS_DETAIL"; case 0x40000010: return "WS_ENTRY"; case 0x40000020: return "HEAP"; case 0x40000040: return "SYSCALL"; case 0x40000080: return "UMS"; case 0x40000100: return "BACKTRACE"; case 0x40000200: return "VULCAN"; case 0x40000400: return "OBJECTS"; case 0x40000800: return "EVENTS"; case 0x40001000: return "FULLTRACE"; case 0x40002000: return "DFSS"; case 0x40004000: return "PREFETCH"; case 0x40008000: return "PROCESSOR_IDLE"; case 0x40010000: return "CPU_CONFIG"; case 0x40020000: return "TIMER"; case 0x40040000: return "CLOCK_INTERRUPT"; case 0x40080000: return "LOAD_BALANCER"; case 0x40100000: return "CLOCK_TIMER"; case 0x40200000: return "IDLE_SELECTION"; case 0x40400000: return "IPI"; case 0x40800000: return "IO_TIMER"; case 0x41000000: return "REG_HIVE"; case 0x42000000: return "REG_NOTIF"; case 0x44000000: return "PPM_EXIT_LATENCY"; case 0x48000000: return "WORKER_THREAD"; case 0x80000001: return "OPTICAL_IO"; case 0x80000002: return "OPTICAL_IO_INIT"; case 0x80000008: return "DLL_INFO"; case 0x80000010: return "DLL_FLUSH_WS"; case 0x80000040: return "OB_HANDLE"; case 0x80000080: return "OB_OBJECT"; case 0x80000200: return "WAKE_DROP"; case 0x80000400: return "WAKE_EVENT"; case 0x80000800: return "DEBUGGER"; case 0x80001000: return "PROC_ATTACH"; case 0x80002000: return "WAKE_COUNTER"; case 0x80008000: return "POWER"; case 0x80010000: return "SOFT_TRIM"; case 0x80020000: return "CC"; case 0x80080000: return "FLT_IO_INIT"; case 0x80100000: return "FLT_IO"; case 0x80200000: return "FLT_FASTIO"; case 0x80400000: return "FLT_IO_FAILURE"; case 0x80800000: return "HV_PROFILE"; case 0x81000000: return "WDF_DPC"; case 0x82000000: return "WDF_INTERRUPT"; case 0x84000000: return "CACHE_FLUSH"; case 0xA0000001: return "HIBER_RUNDOWN"; case 0x00000000: return "SYSCFG_SYSTEM"; case 0xC0000001: return "SYSCFG_GRAPHICS"; case 0xC0000004: return "SYSCFG_STORAGE"; case 0xC0000008: return "SYSCFG_NETWORK"; case 0xC0000010: return "SYSCFG_SERVICES"; case 0xC0000020: return "SYSCFG_PNP"; case 0xC0000040: return "SYSCFG_OPTICAL"; } return "PERF_" + String.format("0x%x", perfinfo); } public String LookupTraceGroup(long logtype) { switch((int)logtype & 0xFF00 ) { case 0x0000: return "HEADER"; case 0x0100: return "IO"; case 0x0200: return "MEMORY"; case 0x0300: return "PROCESS"; case 0x0400: return "FILE"; case 0x0500: return "THREAD"; case 0x0600: return "TCPIP"; case 0x0700: return "JOB"; case 0x0800: return "UDPIP"; case 0x0900: return "REGISTRY"; case 0x0A00: return "DBGPRINT"; case 0x0B00: return "CONFIG"; case 0x0D00: return "WNF"; case 0x0E00: return "POOL"; case 0x0F00: return "PERFINFO"; case 0x1000: return "HEAP"; case 0x1100: return "OBJECT"; case 0x1200: return "POWER"; case 0x1300: return "MODBOUND"; case 0x1400: return "IMAGE"; case 0x1500: return "DPC"; case 0x1600: return "CC"; case 0x1700: return "CRITSEC"; case 0x1800: return "STACKWALK"; case 0x1900: return "UMS"; case 0x1A00: return "ALPC"; case 0x1B00: return "SPLITIO"; case 0x1C00: return "THREAD_POOL"; case 0x1D00: return "HYPERVISOR"; case 0x1E00: return "HYPERVISORX"; } return "EVENT_TRACE_GROUP_" + String.format("0x%x", logtype); } public String LookupLogType(long logtype) { switch((int)logtype) { case 0x0000: return "HEADER"; case 0x0005: return "HEADER_EXTENSION"; case 0x0008: return "RUNDOWN_COMPLETE"; case 0x0020: return "GROUP_MASKS_END"; case 0x0030: return "RUNDOWN_BEGIN"; case 0x0031: return "RUNDOWN_END"; case 0x0040: return "DBGID_RSDS"; case 0x0041: return "DBGID_NB10"; case 0x0042: return "BUILD_LAB"; case 0x0043: return "BINARY_PATH"; case 0x010A: return "IO_READ"; case 0x010B: return "IO_WRITE"; case 0x010C: return "IO_READ_INIT"; case 0x010D: return "IO_WRITE_INIT"; case 0x010E: return "IO_FLUSH"; case 0x010F: return "IO_FLUSH_INIT"; case 0x0110: return "IO_REDIRECTED_INIT"; case 0x0120: return "DRIVER_INIT"; case 0x0121: return "DRIVER_INIT_COMPLETE"; case 0x0122: return "DRIVER_MAJORFUNCTION_CALL"; case 0x0123: return "DRIVER_MAJORFUNCTION_RETURN"; case 0x0124: return "DRIVER_COMPLETIONROUTINE_CALL"; case 0x0125: return "DRIVER_COMPLETIONROUTINE_RETURN"; case 0x0126: return "DRIVER_ADD_DEVICE_CALL"; case 0x0127: return "DRIVER_ADD_DEVICE_RETURN"; case 0x0128: return "DRIVER_STARTIO_CALL"; case 0x0129: return "DRIVER_STARTIO_RETURN"; case 0x0130: return "PREFETCH_ACTION"; case 0x0131: return "PREFETCH_REQUEST"; case 0x0132: return "PREFETCH_READLIST"; case 0x0133: return "PREFETCH_READ"; case 0x0134: return "DRIVER_COMPLETE_REQUEST"; case 0x0135: return "DRIVER_COMPLETE_REQUEST_RETURN"; case 0x0136: return "BOOT_PREFETCH_INFORMATION"; case 0x0137: return "OPTICAL_IO_READ"; case 0x0138: return "OPTICAL_IO_WRITE"; case 0x0139: return "OPTICAL_IO_FLUSH"; case 0x013A: return "OPTICAL_IO_READ_INIT"; case 0x013B: return "OPTICAL_IO_WRITE_INIT"; case 0x013C: return "OPTICAL_IO_FLUSH_INIT"; case 0x020A: return "PAGE_FAULT_TRANSITION"; case 0x020B: return "PAGE_FAULT_DEMAND_ZERO"; case 0x020C: return "PAGE_FAULT_COPY_ON_WRITE"; case 0x020D: return "PAGE_FAULT_GUARD_PAGE"; case 0x020E: return "PAGE_FAULT_HARD_PAGE_FAULT"; case 0x020F: return "PAGE_FAULT_ACCESS_VIOLATION"; case 0x0220: return "HARDFAULT"; case 0x0221: return "REMOVEPAGEBYCOLOR"; case 0x0222: return "REMOVEPAGEFROMLIST"; case 0x0223: return "PAGEINMEMORY"; case 0x0224: return "INSERTINFREELIST"; case 0x0225: return "INSERTINMODIFIEDLIST"; case 0x0226: return "INSERTINLIST"; case 0x0228: return "INSERTATFRONT"; case 0x0229: return "UNLINKFROMSTANDBY"; case 0x022A: return "UNLINKFFREEORZERO"; case 0x022B: return "WORKINGSETMANAGER"; case 0x022C: return "TRIMPROCESS"; case 0x022E: return "ZEROSHARECOUNT"; case 0x023C: return "WSINFOPROCESS"; case 0x0245: return "FAULTADDR_WITH_IP"; case 0x0246: return "TRIMSESSION"; case 0x0247: return "MEMORYSNAPLITE"; case 0x0248: return "PFMAPPED_SECTION_RUNDOWN"; case 0x0249: return "PFMAPPED_SECTION_CREATE"; case 0x024A: return "WSINFOSESSION"; case 0x024B: return "CREATE_SESSION"; case 0x024C: return "SESSION_RUNDOWN_DC_END"; case 0x024D: return "SESSION_RUNDOWN_DC_START"; case 0x024E: return "SESSION_DELETE"; case 0x024F: return "PFMAPPED_SECTION_DELETE"; case 0x0262: return "VIRTUAL_ALLOC"; case 0x0263: return "VIRTUAL_FREE"; case 0x0264: return "HEAP_RANGE_RUNDOWN"; case 0x0265: return "HEAP_RANGE_CREATE"; case 0x0266: return "HEAP_RANGE_RESERVE"; case 0x0267: return "HEAP_RANGE_RELEASE"; case 0x0268: return "HEAP_RANGE_DESTROY"; case 0x0269: return "PAGEFILE_BACK"; case 0x0270: return "MEMINFO"; case 0x0271: return "CONTMEM_GENERATE"; case 0x0272: return "FILE_STORE_FAULT"; case 0x0273: return "INMEMORY_STORE_FAULT"; case 0x0274: return "COMPRESSED_PAGE"; case 0x0275: return "PAGEINMEMORY_ACTIVE"; case 0x0276: return "PAGE_ACCESS"; case 0x0277: return "PAGE_RELEASE"; case 0x0278: return "PAGE_RANGE_ACCESS"; case 0x0279: return "PAGE_RANGE_RELEASE"; case 0x027A: return "PAGE_COMBINE"; case 0x027B: return "KERNEL_MEMUSAGE"; case 0x027C: return "MM_STATS"; case 0x027D: return "MEMINFOEX_WS"; case 0x027E: return "MEMINFOEX_SESSIONWS"; case 0x027F: return "VIRTUAL_ROTATE"; case 0x0280: return "VIRTUAL_ALLOC_DC_START"; case 0x0281: return "VIRTUAL_ALLOC_DC_END"; case 0x0282: return "PAGE_ACCESS_EX"; case 0x0283: return "REMOVEFROMWS"; case 0x0284: return "WSSHAREABLE_RUNDOWN"; case 0x0285: return "INMEMORYACTIVE_RUNDOWN"; case 0x0286: return "MEM_RESET_INFO"; case 0x0287: return "PFMAPPED_SECTION_OBJECT_CREATE"; case 0x0288: return "PFMAPPED_SECTION_OBJECT_DELETE"; case 0x0301: return "PROCESS_CREATE"; case 0x0302: return "PROCESS_DELETE"; case 0x0303: return "PROCESS_DC_START"; case 0x0304: return "PROCESS_DC_END"; case 0x030A: return "PROCESS_LOAD_IMAGE"; case 0x030B: return "PROCESS_TERMINATE"; case 0x0320: return "PROCESS_PERFCTR_END"; case 0x0321: return "PROCESS_PERFCTR_RD"; case 0x0323: return "INSWAPPROCESS"; case 0x0324: return "PROCESS_FREEZE"; case 0x0325: return "PROCESS_THAW"; case 0x0326: return "BOOT_PHASE_START"; case 0x0327: return "ZOMBIE_PROCESS"; case 0x0328: return "PROCESS_SET_AFFINITY"; case 0x0330: return "CHARGE_WAKE_COUNTER_USER"; case 0x0331: return "CHARGE_WAKE_COUNTER_EXECUTION"; case 0x0332: return "CHARGE_WAKE_COUNTER_KERNEL"; case 0x0333: return "CHARGE_WAKE_COUNTER_INSTRUMENTATION"; case 0x0334: return "CHARGE_WAKE_COUNTER_PRESERVE_PROCESS"; case 0x0340: return "RELEASE_WAKE_COUNTER_USER"; case 0x0341: return "RELEASE_WAKE_COUNTER_EXECUTION"; case 0x0342: return "RELEASE_WAKE_COUNTER_KERNEL"; case 0x0343: return "RELEASE_WAKE_COUNTER_INSTRUMENTATION"; case 0x0344: return "RELEASE_WAKE_COUNTER_PRESERVE_PROCESS"; case 0x0350: return "WAKE_DROP_USER"; case 0x0351: return "WAKE_DROP_EXECUTION"; case 0x0352: return "WAKE_DROP_KERNEL"; case 0x0353: return "WAKE_DROP_INSTRUMENTATION"; case 0x0354: return "WAKE_DROP_PRESERVE_PROCESS"; case 0x0360: return "WAKE_EVENT_USER"; case 0x0361: return "WAKE_EVENT_EXECUTION"; case 0x0362: return "WAKE_EVENT_KERNEL"; case 0x0363: return "WAKE_EVENT_INSTRUMENTATION"; case 0x0364: return "WAKE_EVENT_PRESERVE_PROCESS"; case 0x0370: return "DEBUG_EVENT"; case 0x0400: return "FILENAME"; case 0x0420: return "FILENAME_CREATE"; case 0x0421: return "FILENAME_SAME"; case 0x0422: return "FILENAME_NULL"; case 0x0423: return "FILENAME_DELETE"; case 0x0424: return "FILENAME_RUNDOWN"; case 0x0425: return "MAPFILE"; case 0x0426: return "UNMAPFILE"; case 0x0427: return "MAPFILE_DC_START"; case 0x0428: return "MAPFILE_DC_END"; case 0x0440: return "FILE_IO_CREATE"; case 0x0441: return "FILE_IO_CLEANUP"; case 0x0442: return "FILE_IO_CLOSE"; case 0x0443: return "FILE_IO_READ"; case 0x0444: return "FILE_IO_WRITE"; case 0x0445: return "FILE_IO_SET_INFORMATION"; case 0x0446: return "FILE_IO_DELETE"; case 0x0447: return "FILE_IO_RENAME"; case 0x0448: return "FILE_IO_DIRENUM"; case 0x0449: return "FILE_IO_FLUSH"; case 0x044A: return "FILE_IO_QUERY_INFORMATION"; case 0x044B: return "FILE_IO_FS_CONTROL"; case 0x044C: return "FILE_IO_OPERATION_END"; case 0x044D: return "FILE_IO_DIRNOTIFY"; case 0x044E: return "FILE_IO_CREATE_NEW"; case 0x044F: return "FILE_IO_DELETE_PATH"; case 0x0450: return "FILE_IO_RENAME_PATH"; case 0x0451: return "FILE_IO_SETLINK_PATH"; case 0x0452: return "FILE_IO_SETLINK"; case 0x0460: return "FLT_PREOP_INIT"; case 0x0461: return "FLT_POSTOP_INIT"; case 0x0462: return "FLT_PREOP_COMPLETION"; case 0x0463: return "FLT_POSTOP_COMPLETION"; case 0x0464: return "FLT_PREOP_FAILURE"; case 0x0465: return "FLT_POSTOP_FAILURE"; case 0x0501: return "THREAD_CREATE"; case 0x0502: return "THREAD_DELETE"; case 0x0503: return "THREAD_DC_START"; case 0x0504: return "THREAD_DC_END"; case 0x0524: return "CONTEXTSWAP"; case 0x0525: return "CONTEXTSWAP_BATCH"; case 0x0529: return "SPINLOCK"; case 0x052A: return "QUEUE"; case 0x052B: return "RESOURCE"; case 0x052C: return "PUSHLOCK"; case 0x052D: return "WAIT_SINGLE"; case 0x052E: return "WAIT_MULTIPLE"; case 0x052F: return "DELAY_EXECUTION"; case 0x0530: return "THREAD_SET_PRIORITY"; case 0x0531: return "THREAD_SET_BASE_PRIORITY"; case 0x0532: return "READY_THREAD"; case 0x0533: return "THREAD_SET_PAGE_PRIORITY"; case 0x0534: return "THREAD_SET_IO_PRIORITY"; case 0x0535: return "THREAD_SET_AFFINITY"; case 0x0539: return "WORKER_THREAD_ITEM"; case 0x053A: return "DFSS_START_NEW_INTERVAL"; case 0x053B: return "DFSS_PROCESS_IDLE_ONLY_QUEUE"; case 0x053C: return "ANTI_STARVATION_BOOST"; case 0x053D: return "THREAD_MIGRATION"; case 0x053E: return "KQUEUE_ENQUEUE"; case 0x053F: return "KQUEUE_DEQUEUE"; case 0x0540: return "WORKER_THREAD_ITEM_START"; case 0x0541: return "WORKER_THREAD_ITEM_END"; case 0x0542: return "AUTO_BOOST_SET_FLOOR"; case 0x0543: return "AUTO_BOOST_CLEAR_FLOOR"; case 0x0544: return "AUTO_BOOST_NO_ENTRIES"; case 0x0545: return "THREAD_SUBPROCESSTAG_CHANGED"; case 0x060A: return "TCPIP_SEND"; case 0x060B: return "TCPIP_RECEIVE"; case 0x060C: return "TCPIP_CONNECT"; case 0x060D: return "TCPIP_DISCONNECT"; case 0x060E: return "TCPIP_RETRANSMIT"; case 0x060F: return "TCPIP_ACCEPT"; case 0x0610: return "TCPIP_RECONNECT"; case 0x0611: return "TCPIP_FAIL"; case 0x0612: return "TCPIP_TCPCOPY"; case 0x0613: return "TCPIP_ARPCOPY"; case 0x0614: return "TCPIP_FULLACK"; case 0x0615: return "TCPIP_PARTACK"; case 0x0616: return "TCPIP_DUPACK"; case 0x061A: return "TCPIP_SEND_IPV6"; case 0x061B: return "TCPIP_RECEIVE_IPV6"; case 0x061C: return "TCPIP_CONNECT_IPV6"; case 0x061D: return "TCPIP_DISCONNECT_IPV6"; case 0x061E: return "TCPIP_RETRANSMIT_IPV6"; case 0x061F: return "TCPIP_ACCEPT_IPV6"; case 0x0620: return "TCPIP_RECONNECT_IPV6"; case 0x0621: return "TCPIP_FAIL_IPV6"; case 0x0622: return "TCPIP_TCPCOPY_IPV6"; case 0x0623: return "TCPIP_ARPCOPY_IPV6"; case 0x0624: return "TCPIP_FULLACK_IPV6"; case 0x0625: return "TCPIP_PARTACK_IPV6"; case 0x0626: return "TCPIP_DUPACK_IPV6"; case 0x0720: return "JOB_CREATE"; case 0x0721: return "JOB_TERMINATE"; case 0x0722: return "JOB_OPEN"; case 0x0723: return "JOB_ASSIGN_PROCESS"; case 0x0724: return "JOB_REMOVE_PROCESS"; case 0x0725: return "JOB_SET"; case 0x0726: return "JOB_QUERY"; case 0x0727: return "JOB_SET_FAILED"; case 0x0728: return "JOB_QUERY_FAILED"; case 0x0729: return "JOB_SET_NOTIFICATION"; case 0x072A: return "JOB_SEND_NOTIFICATION"; case 0x072B: return "JOB_QUERY_VIOLATION"; case 0x072C: return "JOB_SET_CPU_RATE"; case 0x072D: return "JOB_SET_NET_RATE"; case 0x080A: return "UDP_SEND"; case 0x080B: return "UDP_RECEIVE"; case 0x0811: return "UDP_FAIL"; case 0x081A: return "UDP_SEND_IPV6"; case 0x081B: return "UDP_RECEIVE_IPV6"; case 0x0918: return "REG_RUNDOWNBEGIN"; case 0x0919: return "REG_RUNDOWNEND"; case 0x0920: return "CMCELLREFERRED"; case 0x0921: return "REG_SET_VALUE"; case 0x0922: return "REG_COUNTERS"; case 0x0923: return "REG_CONFIG"; case 0x0924: return "REG_HIVE_INITIALIZE"; case 0x0925: return "REG_HIVE_DESTROY"; case 0x0926: return "REG_HIVE_LINK"; case 0x0927: return "REG_HIVE_RUNDOWN_DC_END"; case 0x0928: return "REG_HIVE_DIRTY"; case 0x0930: return "REG_NOTIF_REGISTER"; case 0x0931: return "REG_NOTIF_DELIVER"; case 0x0A20: return "DEBUG_PRINT"; case 0x0B0A: return "CONFIG_CPU"; case 0x0B0B: return "CONFIG_PHYSICALDISK"; case 0x0B0C: return "CONFIG_LOGICALDISK"; case 0x0B0D: return "CONFIG_NIC"; case 0x0B0E: return "CONFIG_VIDEO"; case 0x0B0F: return "CONFIG_SERVICES"; case 0x0B10: return "CONFIG_POWER"; case 0x0B12: return "CONFIG_OPTICALMEDIA"; case 0x0B15: return "CONFIG_IRQ"; case 0x0B16: return "CONFIG_PNP"; case 0x0B17: return "CONFIG_IDECHANNEL"; case 0x0B18: return "CONFIG_NUMANODE"; case 0x0B19: return "CONFIG_PLATFORM"; case 0x0B1A: return "CONFIG_PROCESSORGROUP"; case 0x0B1B: return "CONFIG_PROCESSORNUMBER"; case 0x0B1C: return "CONFIG_DPI"; case 0x0B1D: return "CONFIG_CODEINTEGRITY"; case 0x0B1E: return "CONFIG_MACHINEID"; case 0x0D20: return "WNF_SUBSCRIBE"; case 0x0D21: return "WNF_UNSUBSCRIBE"; case 0x0D22: return "WNF_CALLBACK"; case 0x0D23: return "WNF_PUBLISH"; case 0x0D24: return "WNF_NAME_SUB_RUNDOWN"; case 0x0E20: return "ALLOCATEPOOL"; case 0x0E21: return "ALLOCATEPOOL_SESSION"; case 0x0E22: return "FREEPOOL"; case 0x0E23: return "FREEPOOL_SESSION"; case 0x0E24: return "ADDPOOLPAGE"; case 0x0E25: return "ADDPOOLPAGE_SESSION"; case 0x0E26: return "BIGPOOLPAGE"; case 0x0E27: return "BIGPOOLPAGE_SESSION"; case 0x0E28: return "POOLSNAP_DC_START"; case 0x0E29: return "POOLSNAP_DC_END"; case 0x0E2A: return "BIGPOOLSNAP_DC_START"; case 0x0E2B: return "BIGPOOLSNAP_DC_END"; case 0x0E2C: return "POOLSNAP_SESSION_DC_START"; case 0x0E2D: return "POOLSNAP_SESSION_DC_END"; case 0x0E2E: return "SESSIONBIGPOOLSNAP_DC_START"; case 0x0E2F: return "SESSIONBIGPOOLSNAP_DC_END"; case 0x0F20: return "RUNDOWN_CHECKPOINT"; case 0x0F22: return "MARK"; case 0x0F24: return "ASYNCMARK"; case 0x0F26: return "IMAGENAME"; case 0x0F27: return "DELAYS_CC_CAN_I_WRITE"; case 0x0F2E: return "SAMPLED_PROFILE"; case 0x0F2F: return "PMC_INTERRUPT"; case 0x0F30: return "PMC_CONFIG"; case 0x0F32: return "MSI_INTERRUPT"; case 0x0F33: return "SYSCALL_ENTER"; case 0x0F34: return "SYSCALL_EXIT"; case 0x0F35: return "BACKTRACE"; case 0x0F36: return "BACKTRACE_USERSTACK"; case 0x0F37: return "SAMPLED_PROFILE_CACHE"; case 0x0F38: return "EXCEPTION_STACK"; case 0x0F39: return "BRANCH_TRACE"; case 0x0F3A: return "DEBUGGER_ENABLED"; case 0x0F3B: return "DEBUGGER_EXIT"; case 0x0F40: return "BRANCH_TRACE_DEBUG"; case 0x0F41: return "BRANCH_ADDRESS_DEBUG"; case 0x0F42: return "THREADED_DPC"; case 0x0F43: return "INTERRUPT"; case 0x0F44: return "DPC"; case 0x0F45: return "TIMERDPC"; case 0x0F46: return "IOTIMER_EXPIRATION"; case 0x0F47: return "SAMPLED_PROFILE_NMI"; case 0x0F48: return "SAMPLED_PROFILE_SET_INTERVAL"; case 0x0F49: return "SAMPLED_PROFILE_DC_START"; case 0x0F4A: return "SAMPLED_PROFILE_DC_END"; case 0x0F4B: return "SPINLOCK_DC_START"; case 0x0F4C: return "SPINLOCK_DC_END"; case 0x0F4D: return "ERESOURCE_DC_START"; case 0x0F4E: return "ERESOURCE_DC_END"; case 0x0F4F: return "CLOCK_INTERRUPT"; case 0x0F50: return "TIMER_EXPIRATION_START"; case 0x0F51: return "TIMER_EXPIRATION"; case 0x0F52: return "TIMER_SET_PERIODIC"; case 0x0F53: return "TIMER_SET_ONE_SHOT"; case 0x0F54: return "TIMER_SET_THREAD"; case 0x0F55: return "TIMER_CANCEL"; case 0x0F56: return "TIME_ADJUSTMENT"; case 0x0F57: return "CLOCK_MODE_SWITCH"; case 0x0F58: return "CLOCK_TIME_UPDATE"; case 0x0F59: return "CLOCK_DYNAMIC_TICK_VETO"; case 0x0F5A: return "CLOCK_CONFIGURATION"; case 0x0F5B: return "IPI"; case 0x0F5C: return "UNEXPECTED_INTERRUPT"; case 0x0F5D: return "IOTIMER_START"; case 0x0F5E: return "IOTIMER_STOP"; case 0x0F5F: return "PASSIVE_INTERRUPT"; case 0x0F60: return "WDF_INTERRUPT"; case 0x0F61: return "WDF_PASSIVE_INTERRUPT"; case 0x0F62: return "WDF_DPC"; case 0x0F63: return "CPU_CACHE_FLUSH"; case 0x0F64: return "DPC_ENQUEUE"; case 0x0F65: return "DPC_EXECUTION"; case 0x0F66: return "INTERRUPT_STEERING"; case 0x0F67: return "WDF_WORK_ITEM"; case 0x0F68: return "KTIMER2_SET"; case 0x0F69: return "KTIMER2_EXPIRATION"; case 0x0F6A: return "KTIMER2_CANCEL"; case 0x0F6B: return "KTIMER2_DISABLE"; case 0x0F6C: return "KTIMER2_FINALIZATION"; case 0x0F6D: return "SHOULD_YIELD_PROCESSOR"; case 0x0F80: return "FUNCTION_CALL"; case 0x0F81: return "FUNCTION_RETURN"; case 0x0F82: return "FUNCTION_ENTER"; case 0x0F83: return "FUNCTION_EXIT"; case 0x0F84: return "TAILCALL"; case 0x0F85: return "TRAP"; case 0x0F86: return "SPINLOCK_ACQUIRE"; case 0x0F87: return "SPINLOCK_RELEASE"; case 0x0F88: return "CAP_COMMENT"; case 0x0F89: return "CAP_RUNDOWN"; case 0x1020: return "HEAP_CREATE"; case 0x1021: return "HEAP_ALLOC"; case 0x1022: return "HEAP_REALLOC"; case 0x1023: return "HEAP_DESTROY"; case 0x1024: return "HEAP_FREE"; case 0x1025: return "HEAP_EXTEND"; case 0x1026: return "HEAP_SNAPSHOT"; case 0x1027: return "HEAP_CREATE_SNAPSHOT"; case 0x1028: return "HEAP_DESTROY_SNAPSHOT"; case 0x1029: return "HEAP_EXTEND_SNAPSHOT"; case 0x102A: return "HEAP_CONTRACT"; case 0x102B: return "HEAP_LOCK"; case 0x102C: return "HEAP_UNLOCK"; case 0x102D: return "HEAP_VALIDATE"; case 0x102E: return "HEAP_WALK"; case 0x102F: return "HEAP_SUBSEGMENT_ALLOC"; case 0x1030: return "HEAP_SUBSEGMENT_FREE"; case 0x1031: return "HEAP_SUBSEGMENT_ALLOC_CACHE"; case 0x1032: return "HEAP_SUBSEGMENT_FREE_CACHE"; case 0x1033: return "HEAP_COMMIT"; case 0x1034: return "HEAP_DECOMMIT"; case 0x1035: return "HEAP_SUBSEGMENT_INIT"; case 0x1036: return "HEAP_AFFINITY_ENABLE"; case 0x1038: return "HEAP_SUBSEGMENT_ACTIVATED"; case 0x1039: return "HEAP_AFFINITY_ASSIGN"; case 0x103A: return "HEAP_REUSE_THRESHOLD_ACTIVATED"; case 0x1120: return "CREATE_HANDLE"; case 0x1121: return "CLOSE_HANDLE"; case 0x1122: return "DUPLICATE_HANDLE"; case 0x1124: return "OBJECT_TYPE_DC_START"; case 0x1125: return "OBJECT_TYPE_DC_END"; case 0x1126: return "OBJECT_HANDLE_DC_START"; case 0x1127: return "OBJECT_HANDLE_DC_END"; case 0x1130: return "CREATE_OBJECT"; case 0x1131: return "DELETE_OBJECT"; case 0x1132: return "REFERENCE_OBJECT"; case 0x1133: return "DEREFERENCE_OBJECT"; case 0x1220: return "BATTERY_LIFE_INFO"; case 0x1221: return "IDLE_STATE_CHANGE"; case 0x1222: return "SET_POWER_ACTION"; case 0x1223: return "SET_POWER_ACTION_RET"; case 0x1224: return "SET_DEVICES_STATE"; case 0x1225: return "SET_DEVICES_STATE_RET"; case 0x1226: return "PO_NOTIFY_DEVICE"; case 0x1227: return "PO_NOTIFY_DEVICE_COMPLETE"; case 0x1228: return "PO_SESSION_CALLOUT"; case 0x1229: return "PO_SESSION_CALLOUT_RET"; case 0x1230: return "PO_PRESLEEP"; case 0x1231: return "PO_POSTSLEEP"; case 0x1232: return "PO_CALIBRATED_PERFCOUNTER"; case 0x1233: return "PPM_PERF_STATE_CHANGE"; case 0x1234: return "PPM_THROTTLE_STATE_CHANGE"; case 0x1235: return "PPM_IDLE_STATE_CHANGE"; case 0x1236: return "PPM_THERMAL_CONSTRAINT"; case 0x1237: return "PO_SIGNAL_RESUME_UI"; case 0x1238: return "PO_SIGNAL_VIDEO_ON"; case 0x1239: return "PPM_IDLE_STATE_ENTER"; case 0x123A: return "PPM_IDLE_STATE_EXIT"; case 0x123B: return "PPM_PLATFORM_IDLE_STATE_ENTER"; case 0x123C: return "PPM_IDLE_EXIT_LATENCY"; case 0x123D: return "PPM_IDLE_PROCESSOR_SELECTION"; case 0x123E: return "PPM_IDLE_PLATFORM_SELECTION"; case 0x123F: return "PPM_COORDINATED_IDLE_ENTER"; case 0x1240: return "PPM_COORDINATED_IDLE_EXIT"; case 0x1318: return "COWHEADER"; case 0x1319: return "COWBLOB"; case 0x131A: return "COWBLOB_CLOSED"; case 0x1320: return "MODULEBOUND_ENT"; case 0x1321: return "MODULEBOUND_JUMP"; case 0x1322: return "MODULEBOUND_RET"; case 0x1323: return "MODULEBOUND_CALL"; case 0x1324: return "MODULEBOUND_CALLRET"; case 0x1325: return "MODULEBOUND_INT2E"; case 0x1326: return "MODULEBOUND_INT2B"; case 0x1327: return "MODULEBOUND_FULLTRACE"; case 0x1401: return "IMAGE_LOAD"; case 0x1402: return "IMAGE_UNLOAD"; case 0x1403: return "IMAGE_DC_START"; case 0x1404: return "IMAGE_DC_END"; case 0x1420: return "IMAGE_RELOCATION"; case 0x1421: return "IMAGE_KERNEL_BASE"; case 0x1422: return "IMAGE_HYPERCALL_PAGE"; case 0x1480: return "LDR_LOCK_ACQUIRE_ATTEMPT"; case 0x1481: return "LDR_LOCK_ACQUIRE_SUCCESS"; case 0x1482: return "LDR_LOCK_ACQUIRE_FAIL"; case 0x1483: return "LDR_LOCK_ACQUIRE_WAIT"; case 0x1484: return "LDR_PROC_INIT_DONE"; case 0x1485: return "LDR_CREATE_SECTION"; case 0x1486: return "LDR_SECTION_CREATED"; case 0x1487: return "LDR_MAP_VIEW"; case 0x1490: return "LDR_RELOCATE_IMAGE"; case 0x1491: return "LDR_IMAGE_RELOCATED"; case 0x1492: return "LDR_HANDLE_OLD_DESCRIPTORS"; case 0x1493: return "LDR_OLD_DESCRIPTORS_HANDLED"; case 0x1494: return "LDR_HANDLE_NEW_DESCRIPTORS"; case 0x1495: return "LDR_NEW_DESCRIPTORS_HANDLED"; case 0x1496: return "LDR_DLLMAIN_EXIT"; case 0x14A0: return "LDR_FIND_DLL"; case 0x14A1: return "LDR_VIEW_MAPPED"; case 0x14A2: return "LDR_LOCK_RELEASE"; case 0x14A3: return "LDR_DLLMAIN_ENTER"; case 0x14A4: return "LDR_ERROR"; case 0x14A5: return "LDR_VIEW_MAPPING"; case 0x14A6: return "LDR_SNAPPING"; case 0x14A7: return "LDR_SNAPPED"; case 0x14A8: return "LDR_LOADING"; case 0x14A9: return "LDR_LOADED"; case 0x14AA: return "LDR_FOUND_KNOWN_DLL"; case 0x14AB: return "LDR_ABNORMAL"; case 0x14AC: return "LDR_PLACEHOLDER"; case 0x14AD: return "LDR_RDY_TO_INIT"; case 0x14AE: return "LDR_RDY_TO_RUN"; case 0x14B0: return "LDR_NEW_DLL_LOAD"; case 0x14B1: return "LDR_NEW_DLL_AS_DATA"; case 0x14C0: return "LDR_EXTERNAL_PATH"; case 0x14C1: return "LDR_GENERATED_PATH"; case 0x14D0: return "LDR_APISET_RESOLVING"; case 0x14D1: return "LDR_APISET_HOSTED"; case 0x14D2: return "LDR_APISET_UNHOSTED"; case 0x14D3: return "LDR_APISET_UNRESOLVED"; case 0x14D4: return "LDR_SEARCH_SECURITY"; case 0x14D5: return "LDR_SEARCH_PATH_SECURITY"; case 0x1600: return "CC_WORKITEM_ENQUEUE"; case 0x1601: return "CC_WORKITEM_DEQUEUE"; case 0x1602: return "CC_WORKITEM_COMPLETE"; case 0x1603: return "CC_READ_AHEAD"; case 0x1604: return "CC_WRITE_BEHIND"; case 0x1605: return "CC_LAZY_WRITE_SCAN"; case 0x1606: return "CC_CAN_I_WRITE_FAIL"; case 0x1609: return "CC_FLUSH_CACHE"; case 0x160A: return "CC_FLUSH_SECTION"; case 0x160B: return "CC_READ_AHEAD_PREFETCH"; case 0x160C: return "CC_SCHEDULE_READ_AHEAD"; case 0x160D: return "CC_LOGGED_STREAM_INFO"; case 0x160E: return "CC_EXTRA_WRITEBEHIND_THREAD"; case 0x1720: return "CRITSEC_ENTER"; case 0x1721: return "CRITSEC_LEAVE"; case 0x1722: return "CRITSEC_COLLISION"; case 0x1723: return "CRITSEC_INITIALIZE"; case 0x1820: return "STACKWALK"; case 0x1822: return "STACKTRACE_CREATE"; case 0x1823: return "STACKTRACE_DELETE"; case 0x1824: return "STACKTRACE_RUNDOWN"; case 0x1825: return "STACKTRACE_KEY_KERNEL"; case 0x1826: return "STACKTRACE_KEY_USER"; case 0x1920: return "UMS_DIRECTED_SWITCH_START"; case 0x1921: return "UMS_DIRECTED_SWITCH_END"; case 0x1922: return "UMS_PARK"; case 0x1923: return "UMS_DISASSOCIATE"; case 0x1924: return "UMS_CONTEXT_SWITCH"; case 0x1A21: return "ALPC_SEND_MESSAGE"; case 0x1A22: return "ALPC_RECEIVE_MESSAGE"; case 0x1A23: return "ALPC_WAIT_FOR_REPLY"; case 0x1A24: return "ALPC_WAIT_FOR_NEW_MESSAGE"; case 0x1A25: return "ALPC_UNWAIT"; case 0x1A26: return "ALPC_CONNECT_REQUEST"; case 0x1A27: return "ALPC_CONNECT_SUCCESS"; case 0x1A28: return "ALPC_CONNECT_FAIL"; case 0x1A29: return "ALPC_CLOSE_PORT"; case 0x1B20: return "SPLITIO_VOLMGR"; case 0x1C20: return "TP_CALLBACK_ENQUEUE"; case 0x1C21: return "TP_CALLBACK_DEQUEUE"; case 0x1C22: return "TP_CALLBACK_START"; case 0x1C23: return "TP_CALLBACK_STOP"; case 0x1C24: return "TP_CALLBACK_CANCEL"; case 0x1C25: return "TP_POOL_CREATE"; case 0x1C26: return "TP_POOL_CLOSE"; case 0x1C27: return "TP_POOL_TH_MIN_SET"; case 0x1C28: return "TP_POOL_TH_MAX_SET"; case 0x1C29: return "TP_WORKER_NUMANODE_SWITCH"; case 0x1C2A: return "TP_TIMER_SET"; case 0x1C2B: return "TP_TIMER_CANCELLED"; case 0x1C2C: return "TP_TIMER_SET_NTTIMER"; case 0x1C2D: return "TP_TIMER_CANCEL_NTTIMER"; case 0x1C2E: return "TP_TIMER_EXPIRATION_BEGIN"; case 0x1C2F: return "TP_TIMER_EXPIRATION_END"; case 0x1C30: return "TP_TIMER_EXPIRATION"; } return "PERFINFO_LOG_TYPE_" + String.format("0x%x", logtype); } }