private void WriteOutCatchStatements(TextWriter output, Indentation indent, TryCatchBlock currentTryBlock, JumpTable jumpTable) { indent--; foreach (var catchBlock in currentTryBlock.Handlers) { output.WriteLine(string.Format("{0}catch({1}) :{2}", indent.ToString(), catchBlock.TypeIndex == 0 ? "ALL" : _dex.GetTypeName(catchBlock.TypeIndex), jumpTable.GetHandlerLabel(catchBlock))); } }
private void WriteOutCatchStatements(TextWriter output, Indentation indent, TryCatchBlock currentTryBlock) { output.WriteLine(string.Format("{0}{1} {2}", indent.ToString(), "".PadLeft(12, ' '), ".CATCH")); indent++; foreach (var catchBlock in currentTryBlock.Handlers) { output.WriteLine(string.Format("{0}{1} {2} address:{3}", indent.ToString(), "".PadLeft(12, ' '), catchBlock.TypeIndex == 0 ? "ALL" : _dex.GetTypeName(catchBlock.TypeIndex), catchBlock.HandlerOffset)); } indent--; }
public string WriteOutMethod(Class dexClass, Method method, Indentation indent, bool renderOpcodes = true) { string output = ""; var jumpTable = BuildJumpTable(method); /*foreach (var annotation in method.Annotations) * { * AnnotationToString(output, annotation.Values, dexClass, indent); * } * * foreach (var annotation in method.ParameterAnnotations) * { * AnnotationToString(output, annotation.Values, dexClass, indent); * }*/ // Initialize a pointer to the first jump target var targets = jumpTable.Targets.Keys.GetEnumerator(); targets.MoveNext(); output += (indent.ToString()); output += (MethodToString(method)); output += (" {") + "\n"; if (renderOpcodes) { indent++; var lastTryBlockId = 0; var activeTryBlocks = new List <TryCatchBlock>(); TryCatchBlock currentTryBlock = null; foreach (var opcode in method.GetInstructions()) { long offset = opcode.OpCodeOffset; // Print out jump target labels while (offset == targets.Current) { output += "\n"; //output += "{0}:{1}", indent.ToString(), string.Join(", ", jumpTable.GetTargetLabels(targets.Current)) \n ; output += indent.ToString() + ":" + string.Join(", ", jumpTable.GetTargetLabels(targets.Current)) + "\n"; if (!targets.MoveNext()) { break; } } // Test for the end of the current try block if (currentTryBlock != null && !currentTryBlock.IsInBlock(offset)) { //WriteOutCatchStatements(output, indent, currentTryBlock, jumpTable); activeTryBlocks.Remove(currentTryBlock); if (activeTryBlocks.Count > 0) { currentTryBlock = activeTryBlocks[activeTryBlocks.Count - 1]; } else { currentTryBlock = null; } } // Should open a new try block? if (method.TryCatchBlocks != null && method.TryCatchBlocks.Length > lastTryBlockId) { var tryBlock = method.TryCatchBlocks[lastTryBlockId]; if (tryBlock.IsInBlock(offset)) { output += indent.ToString(); output += "try" + "\n"; activeTryBlocks.Add(tryBlock); currentTryBlock = tryBlock; lastTryBlockId++; indent++; } } if (opcode.Instruction != Instructions.Nop) { output += indent.ToString(); output += OpCodeToString(opcode, dexClass, method, jumpTable) + "\n"; } } if (currentTryBlock != null) { //WriteOutCatchStatements(output, indent, currentTryBlock, jumpTable); } indent--; } output += indent.ToString(); output += "}" + "\n"; return(output); }
public void WriteOutMethod(Class dexClass, Method method, TextWriter output, Indentation indent, bool renderOpcodes = false) { var stringIndent = indent.ToString(); var proto = _dex.GetPrototype(method.PrototypeIndex); output.WriteLine(string.Format("{0}.METHOD {1} : {2}", stringIndent, method.Name, _dex.GetTypeName(proto.ReturnTypeIndex))); indent++; var paramCount = 0; foreach (var param in proto.Parameters) { output.WriteLine(string.Format("{0}.PARAM {1}", indent.ToString(), _dex.GetTypeName(param))); if (method.ParameterAnnotations.Count > paramCount) { indent++; WriteOutAnnotation(output, method.ParameterAnnotations[paramCount].Values, dexClass, indent); indent--; } paramCount++; } indent--; output.WriteLine(string.Format("{0}.MODIFIERS {1}", stringIndent, _helper.AccessFlagsToString(((AccessFlag)method.AccessFlags)))); output.WriteLine(string.Format("{0}.REGISTERS {1}", stringIndent, method.GetRegisterCount())); foreach (var annotation in method.Annotations) { WriteOutAnnotation(output, annotation.Values, dexClass, indent); } if (renderOpcodes) { output.WriteLine(string.Format("{0}.CODE", stringIndent)); indent++; stringIndent = indent.ToString(); long offset = 0; var lastTryBlockId = 0; var activeTryBlocks = new List <TryCatchBlock> (); TryCatchBlock currentTryBlock = null; foreach (var opcode in method.GetInstructions()) { offset = opcode.OpCodeOffset; // Test for the end of the current try block if (currentTryBlock != null && !currentTryBlock.IsInBlock(offset)) { WriteOutCatchStatements(output, indent, currentTryBlock); activeTryBlocks.Remove(currentTryBlock); if (activeTryBlocks.Count > 0) { currentTryBlock = activeTryBlocks [activeTryBlocks.Count - 1]; } else { currentTryBlock = null; } } // Should open a new try block? if (method.TryCatchBlocks != null && method.TryCatchBlocks.Length > lastTryBlockId) { var tryBlock = method.TryCatchBlocks [lastTryBlockId]; if (tryBlock.IsInBlock(offset)) { output.WriteLine(string.Format("{0}{1} {2} #{3}", stringIndent, "".PadLeft(12, ' '), ".TRY", lastTryBlockId)); activeTryBlocks.Add(tryBlock); currentTryBlock = tryBlock; lastTryBlockId++; } } if (opcode.Instruction != Instructions.Nop) { output.WriteLine(string.Format("{0}{1} {2}", stringIndent, offset.ToString().PadLeft(12, ' '), opcode.ToString())); } } if (currentTryBlock != null) { WriteOutCatchStatements(output, indent, currentTryBlock); } indent--; } }
internal Method(uint id, Dex dex, BinaryReader reader, uint codeOffset) { Id = id; Dex = dex; ClassIndex = reader.ReadUInt16(); PrototypeIndex = reader.ReadUInt16(); NameIndex = reader.ReadUInt32(); Annotations = new Annotation[0]; ParameterAnnotations = new List <Annotation>(); // This method has no opcodes, must be abstract or native. // Or the method is being loaded directly from the methods list if (codeOffset != 0) { reader.BaseStream.Position = codeOffset; RegistersSize = reader.ReadUInt16(); ArgumentsSize = reader.ReadUInt16(); ReturnValuesSize = reader.ReadUInt16(); var numberOfTryItems = reader.ReadUInt16(); // Not parsing debug info /*var debugInfoOffset =*/ reader.ReadUInt32(); CodeLength = reader.ReadUInt32(); CodeOffset = reader.BaseStream.Position; // Skip the opcode block reader.BaseStream.Position += CodeLength * 2; // Skip the optional padding if ((numberOfTryItems != 0) && (CodeLength % 2 != 0)) { reader.BaseStream.Position += 2; } // Load the try blocks if (numberOfTryItems != 0) { TryCatchBlocks = new TryCatchBlock[numberOfTryItems]; var handlerOffsets = new long[numberOfTryItems]; // read Try for (int i = 0; i < numberOfTryItems; i++) { var tryCatch = new TryCatchBlock(CodeOffset); tryCatch.StartAddress = reader.ReadUInt32(); tryCatch.InstructionCount = reader.ReadUInt16(); TryCatchBlocks [i] = tryCatch; handlerOffsets[i] = reader.ReadUInt16(); } var encodedCatchHandlerListOffset = reader.BaseStream.Position; // Size of the list, could be used to confirm the DEX is properly // built. For this purpose will assume DEX files are always good Leb128.ReadUleb(reader); // read Catch blocks for (int i = 0; i < numberOfTryItems; i++) { //encoded_catch_handler if (handlerOffsets [i] > 0) { reader.BaseStream.Position = encodedCatchHandlerListOffset + handlerOffsets [i]; var handlersCount = Leb128.ReadLeb(reader); var handlers = new CatchHandler[handlersCount <= 0 ? Math.Abs(handlersCount) + 1 : handlersCount]; for (int j = 0; j < Math.Abs(handlersCount); j++) { var catchHandler = new CatchHandler(CodeOffset); catchHandler.TypeIndex = Leb128.ReadUleb(reader); catchHandler.Address = Leb128.ReadUleb(reader); handlers [j] = catchHandler; } // parse the catch all block if (handlersCount <= 0) { var catchHandler = new CatchHandler(CodeOffset); catchHandler.TypeIndex = 0; catchHandler.Address = Leb128.ReadUleb(reader); handlers [handlers.Length - 1] = catchHandler; } TryCatchBlocks [i].Handlers = handlers; } } } } }