public int GetTypeCount(SmaliLine.LineReturnType type) { if (varCount.ContainsKey(type)) return varCount[type]; else return varCount[type] = 0; }
public static bool ParseNonAccess(SmaliLine l, String s) { switch (s) { case "static": l.NonAccessModifiers |= ENonAccessMod.Static; break; case "final": l.NonAccessModifiers |= ENonAccessMod.Final; break; case "abstract": l.NonAccessModifiers |= ENonAccessMod.Abstract; break; case "synchronized": l.NonAccessModifiers |= ENonAccessMod.Synchronized; break; case "volatile": l.NonAccessModifiers |= ENonAccessMod.Volatile; break; default: return(false); } return(true); }
public String Decompile(String sFilename) { String rv = String.Empty; foreach (String s in File.ReadAllLines(sFilename).Where(x => !String.IsNullOrEmpty(x))) { SmaliLine l = SmaliLine.Parse(s); if (l != null) { Lines.Add(l); } } SmaliClass c = new SmaliClass(); c.Lines = Lines; c.LoadAttributes(); c.LoadFields(); c.LoadMethods(); StringBuilder sb = new StringBuilder(); sb.Append(c.ToJava()); rv = sb.ToString(); return(rv); }
public int IncrementTypeCount(SmaliLine.LineReturnType type) { if (varCount.ContainsKey(type)) return varCount[type]++; else return varCount[type] = 1; }
public static String ReturnType2Java(SmaliLine.LineReturnType rt, String customType) { if (rt.ToString().EndsWith("Array")) { if (rt == SmaliLine.LineReturnType.CustomArray) { if (customType != "") return customType.Substring(1) + "[] "; else return customType.Substring(1) + "[]"; } else return Name2Java(rt.ToString().Replace("Array","").ToLowerInvariant().Trim()) + "[] "; } else { if (rt == SmaliLine.LineReturnType.Custom) { if (customType != "") return customType + ' '; else return customType; } else return Name2Java(rt.ToString().ToLowerInvariant().Trim()) + ' '; } }
public void ProcessDirective(SmaliMethod m, SmaliLine l) { smaliDirectives.m = m; smaliDirectives.l = l; switch (l.Instruction) { case SmaliLine.LineInstruction.Method: smaliDirectives.Method(); if (!m.bHasParameters) { smaliDirectives.Special_NoParameters(); if (!m.bHasPrologue) smaliDirectives.Prologue(); } break; case SmaliLine.LineInstruction.Parameter: smaliDirectives.Parameter(); break; case SmaliLine.LineInstruction.Prologue: smaliDirectives.Prologue(); break; case SmaliLine.LineInstruction.Line: smaliDirectives.Line(); break; case SmaliLine.LineInstruction.EndMethod: smaliDirectives.EndMethod(); break; } }
public void ProcessDirective(SmaliMethod m, SmaliLine l) { smaliDirectives.m = m; smaliDirectives.l = l; switch (l.Instruction) { case SmaliLine.LineInstruction.Method: smaliDirectives.Method(); if (!m.bHasParameters) { smaliDirectives.Special_NoParameters(); if (!m.bHasPrologue) { smaliDirectives.Prologue(); } } break; case SmaliLine.LineInstruction.Parameter: smaliDirectives.Parameter(); break; case SmaliLine.LineInstruction.Prologue: smaliDirectives.Prologue(); break; case SmaliLine.LineInstruction.Line: smaliDirectives.Line(); break; case SmaliLine.LineInstruction.EndMethod: smaliDirectives.EndMethod(); break; } }
public void LoadAttributes() { SmaliLine line = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Class).Single(); ClassName = line.aClassName.Substring(line.aClassName.LastIndexOf('/') + 1).Replace(";", ""); AccessModifiers = line.AccessModifiers; NonAccessModifiers = line.NonAccessModifiers; if (line.aClassName.Contains("/")) { PackageName = line.aClassName.Substring(0, line.aClassName.LastIndexOf('/')); } line = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Super).SingleOrDefault(); if (line != null) { Extends = line.aType; } line = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Implements).SingleOrDefault(); if (line != null) { Implements = line.aType; } line = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Source).SingleOrDefault(); if (line != null) { SourceFile = line.aExtra; } }
public static void ParseParameters(SmaliLine rv, String s) { if (s.EndsWith(",")) { s = s.Substring(0, s.Length - 1); } if (s.Contains('{')) { s = s.Substring(1, s.Length - 2); } if (s.Contains(',')) { String[] sp = s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (String p in sp) { rv.lRegisters[p.Trim()] = String.Empty; } } else { rv.lRegisters[s] = String.Empty; } }
public void ProcessInstruction(SmaliMethod m, SmaliLine l) { smaliInstructions.m = m; smaliInstructions.l = l; switch (l.Smali) { case SmaliLine.LineSmali.Const4: case SmaliLine.LineSmali.Const: case SmaliLine.LineSmali.Const16: case SmaliLine.LineSmali.ConstHigh16: //TODO: these may end up needing seperate instruction handlers. case SmaliLine.LineSmali.ConstString: smaliInstructions.Const(); break; case SmaliLine.LineSmali.SputObject: smaliInstructions.SputObject(); break; case SmaliLine.LineSmali.Return: case SmaliLine.LineSmali.ReturnVoid: smaliInstructions.Return(); break; case SmaliLine.LineSmali.SgetObject: smaliInstructions.SgetObject(); break; case SmaliLine.LineSmali.NewInstance: smaliInstructions.NewInstance(); break; case SmaliLine.LineSmali.InvokeVirtual: case SmaliLine.LineSmali.InvokeStatic: case SmaliLine.LineSmali.InvokeDirect: //TODO: These may need to be on their own functions, but for now the are all identical in implementation... smaliInstructions.Invoke(); break; case SmaliLine.LineSmali.IputBoolean: smaliInstructions.IputBoolean(); break; case SmaliLine.LineSmali.MoveResult: case SmaliLine.LineSmali.MoveResultObject: smaliInstructions.MoveResult(); break; case SmaliLine.LineSmali.Unimplemented: //These will cover most of the instructions right now... case SmaliLine.LineSmali.Unknown: case SmaliLine.LineSmali.Conditional: case SmaliLine.LineSmali.Label: smaliInstructions.Unimplemented(); break; } }
public static bool ParseModifier(SmaliLine l, String s) { switch (s) { case "constructor": l.IsConstructor = true; break; default: return(false); } return(true); }
public static void SetModifiers(SmaliLine l, ref String[] ar, int start, int end) { for (int i = start; i < end; i++) { if (Keywords.Contains(ar[i].ToLowerInvariant().Trim())) { if (!ParseNonAccess(l, ar[i].ToLowerInvariant().Trim())) { if (!ParseAccess(l, ar[i].ToLowerInvariant().Trim())) { ParseModifier(l, ar[i].ToLowerInvariant().Trim()); } } ar[i] = String.Empty; } } }
public static bool ParseAccess(SmaliLine l, String s) { switch (s) { case "public": l.AccessModifiers |= EAccessMod.Public; break; case "private": l.AccessModifiers |= EAccessMod.Private; break; case "protected": l.AccessModifiers |= EAccessMod.Protected; break; default: return(false); } return(true); }
public void LoadMethods() { bool bAdd = false; SmaliMethod m = null; for (int i = 0; i < Lines.Count; i++) { SmaliLine l = Lines[i]; if (bAdd) { m.Lines.Add(l); if (l.Instruction == SmaliLine.LineInstruction.EndMethod) { bAdd = false; //if(Methods.Count < 3) Methods.Add(m); } else { continue; } } if (l.Instruction == SmaliLine.LineInstruction.Method) { bAdd = true; m = new SmaliMethod(); m.ParentClass = this; m.Lines.Add(l); } } foreach (SmaliMethod me in Methods) { me.Process(); } }
public void Process() { bHasPrologue = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Prologue).Count() > 0; bHasParameters = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Parameter).Count() > 0; for (int i = 0; i < Lines.Count; i++) { SmaliLine l = Lines[i]; if (l.bIsDirective) { SmaliEngine.VM.ProcessDirective(this, l); } else { SmaliEngine.VM.ProcessInstruction(this, l); } if (!String.IsNullOrEmpty(SmaliEngine.VM.Java)) { JavaOutput.Add(SmaliEngine.VM.Java); SmaliEngine.VM.Java = String.Empty; } } }
public static bool ParseAccess(SmaliLine l, String s) { switch (s) { case "public": l.AccessModifiers |= EAccessMod.Public; break; case "private": l.AccessModifiers |= EAccessMod.Private; break; case "protected": l.AccessModifiers |= EAccessMod.Protected; break; default: return false; } return true; }
// MAIN TRANSLATION METHOD, FAKE VIRTUAL MACHINE public void Process() { for (int i = 0; i < Lines.Count; i++) { SmaliLine l = Lines[i]; if (l.bIsDirective) { #region Directives switch (l.Instruction) { case SmaliLine.LineInstruction.Method: #region Method AccessModifiers = l.AccessModifiers; NonAccessModifiers = l.NonAccessModifiers; Name = l.aName; ReturnType = l.ReturnType; SmaliReturnType = l.aReturnType; IsConstructor = l.IsConstructor; #endregion break; case SmaliLine.LineInstruction.Parameter: #region Parameter if (l.aName != "p0" && IsFirstParam) { IsFirstParam = false; Isp0self = true; Parameters.Add(new SmaliParameter() { Name = "this", Register = "p0", Type = ParentClass.ClassName }); } l.aName = char.ToUpper(l.aName[0]) + l.aName.Substring(1); Parameters.Add(new SmaliParameter() { Name = "param" + l.aName, Register = l.lRegisters.Keys.First(), Type = l.aType }); #endregion break; case SmaliLine.LineInstruction.Prologue: #region Prologue (method declaration) StringBuilder sb = new StringBuilder(); if (Name == "<clinit>") { IsClinit = true; } if (IsClinit) { Name = ""; ReturnType = SmaliLine.LineReturnType.Custom; SmaliReturnType = ""; } else if (Name == "<init>") { Name = ParentClass.ClassName.Replace(";", ""); SmaliReturnType = ""; ReturnType = SmaliLine.LineReturnType.Custom; } sb.AppendFormat("{0} {1} {2} {3}", AccessModifiers == 0 ? "" : AccessModifiers.ToString().ToLowerInvariant().Replace(",", ""), NonAccessModifiers == 0 ? "" : NonAccessModifiers.ToString().ToLowerInvariant().Replace(",", ""), ReturnType == SmaliLine.LineReturnType.Custom ? SmaliUtils.General.Name2Java(SmaliReturnType) : ReturnType.ToString().ToLowerInvariant(), Name ); if (!IsClinit) { sb.Append(" ("); } if (Parameters.Count > 0) { for (int j = Isp0self ? 1 : 0; j < Parameters.Count; j++) { sb.Append(Parameters[j].ToJava() + ", "); } sb.Remove(sb.Length - 2, 2); if (Isp0self) { vm.Put("p0", "this"); } } if (!IsClinit) { sb.Append(") "); } sb.Append("{"); Buffer.Append(sb.ToString()); #endregion break; case SmaliLine.LineInstruction.EndMethod: Java.Add("}"); break; case SmaliLine.LineInstruction.Line: if (!String.IsNullOrEmpty(Buffer.ToString())) { JavaBuffer.Append(Buffer.ToString()); if (!String.IsNullOrEmpty(JavaBuffer.ToString())) { Java.Add(JavaBuffer.ToString()); Buffer = new StringBuilder(); JavaBuffer = new StringBuilder(); } } break; } #endregion } else { #region Smali instructions String sReg; String sSrcValue; String sDstValue; switch (l.Smali) { case SmaliLine.LineSmali.Const4: case SmaliLine.LineSmali.ConstString: vm.Put(l.lRegisters.Keys.First(), l.aValue); break; case SmaliLine.LineSmali.SputObject: sReg = l.lRegisters.Keys.First(); if (!vm.vmStack.ContainsKey(sReg)) { // SKIP! break; } sSrcValue = vm.Get(sReg); sDstValue = l.lRegisters[sReg]; Dictionary <String, String> args = new Dictionary <String, String>(); args[sReg] = sSrcValue; Buffer.Append(ParseSmali(sDstValue, args)); break; case SmaliLine.LineSmali.InvokeStatic: //case SmaliLine.LineSmali.InvokeDirect: args = new Dictionary <string, string>(); foreach (KeyValuePair <String, String> kv in l.lRegisters) { if (!vm.vmStack.ContainsKey(kv.Key)) { // SKIP! break; } args[kv.Key] = vm.Get(kv.Key); } Buffer.Append(SmaliUtils.General.Name2Java(l.aClassName)); Buffer.Append("." + l.aName + "("); if (args.Count > 0) { foreach (KeyValuePair <String, String> kv in args) { Buffer.Append(kv.Value + ", "); } Buffer.Remove(Buffer.Length - 2, 2); } Buffer.Append(")"); break; case SmaliLine.LineSmali.MoveResultObject: if (Buffer.Length > 0) { sReg = l.lRegisters.Keys.First(); vm.Put(sReg, Buffer.ToString()); Buffer = new StringBuilder(); } break; case SmaliLine.LineSmali.ReturnVoid: Buffer.Append("return"); break; } #endregion } } }
public static bool ParseAsInstruction(SmaliLine rv, String sInst, ref String[] sWords, ref String sRawText) { switch (sInst) { case "const": rv.Smali = LineSmali.Const; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sWords[2]; break; case "const/16": rv.Smali = LineSmali.Const16; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sWords[2]; break; case "const/high16": rv.Smali = LineSmali.ConstHigh16; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sWords[2]; break; case "const/4": rv.Smali = LineSmali.Const4; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sWords[2]; break; case "const-string": rv.Smali = LineSmali.ConstString; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sRawText; break; case "invoke-static": rv.Smali = LineSmali.InvokeStatic; rv.aName = sWords[sWords.Length - 1]; sWords[sWords.Length - 1] = String.Empty; String sp = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); if (sp.EndsWith(",")) { sp = sp.Substring(0, sp.Length - 1); } ParseParameters(rv, sp); rv.lRegisters[rv.lRegisters.Keys.First()] = rv.aName; break; case "invoke-direct": rv.Smali = LineSmali.InvokeDirect; if (sWords[1].EndsWith(",")) { sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); } ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; rv.aName = sWords[sWords.Length - 1]; break; case "move-result-object": rv.Smali = LineSmali.MoveResultObject; rv.lRegisters[sWords[1]] = String.Empty; break; case "move-result": rv.Smali = LineSmali.MoveResult; rv.lRegisters[sWords[1]] = String.Empty; break; case "return": case "return-object": rv.Smali = LineSmali.Return; if (sWords[1].EndsWith(",")) { sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); } ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[1]; break; case "return-void": rv.Smali = LineSmali.ReturnVoid; break; case "sget-object": rv.Smali = LineSmali.SgetObject; if (sWords[1].EndsWith(",")) { sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); } ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; break; case "sput-object": rv.Smali = LineSmali.SputObject; if (sWords[1].EndsWith(",")) { sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); } ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; break; case "new-instance": rv.Smali = LineSmali.NewInstance; if (sWords[1].EndsWith(",")) { sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); } ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; break; case "iput-object": rv.Smali = LineSmali.IputObject; rv.aValue = sWords[sWords.Length - 1]; sWords[sWords.Length - 1] = String.Empty; sp = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); if (sp.EndsWith(",")) { sp = sp.Substring(0, sp.Length - 1); } ParseParameters(rv, sp); break; case "iput-boolean": rv.Smali = LineSmali.IputBoolean; if (sWords[1].EndsWith(",")) { sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); } ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; rv.aName = sWords[sWords.Length - 1]; //Always the last entry. break; case "invoke-virtual": rv.Smali = LineSmali.InvokeVirtual; rv.aName = sWords[sWords.Length - 1]; sWords[sWords.Length - 1] = String.Empty; sp = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); if (sp.EndsWith(",")) { sp = sp.Substring(0, sp.Length - 1); } ParseParameters(rv, sp); rv.lRegisters[rv.lRegisters.Keys.First()] = rv.aName; break; #region Unimplemented Functions case "add-double": case "add-double/2addr": case "add-float": case "add-float/2addr": case "add-int": case "add-int/2addr": case "add-int/lit16": case "add-int/lit8": case "add-long": case "add-long/2addr": case "aget": case "aget-boolean": case "aget-byte": case "aget-char": case "aget-object": case "aget-short": case "aget-wide": case "and-int": case "and-int/2addr": case "and-int/lit16": case "and-int/lit8": case "and-long": case "and-long/2addr": case "aput": case "aput-boolean": case "aput-byte": case "aput-char": case "aput-object": case "aput-short": case "aput-wide": case "array-length": case "check-cast": case "cmpg-double": case "cmpg-float": case "cmpl-double": case "cmpl-float": case "cmp-long": case "const-class": case "const-string/jumbo": case "const-wide": case "const-wide/16": case "const-wide/32": case "const-wide/high16": case "div-double": case "div-float": case "div-float/2addr": case "div-int": case "div-int/2addr": case "div-int/lit16": case "div-int/lit8": case "div-long": case "div-long/2addr": case "double-to-int": case "double-to-long": case "execute-inline": case "execute-inline/range": case "fill-array-data": case "filled-new-array": case "filled-new-array/range": case "float-to-double": case "float-to-int": case "float-to-long": case "iget": case "iget-boolean": case "iget-byte": case "iget-char": case "iget-object": case "iget-object-quick": case "iget-object-volatile": case "iget-quick": case "iget-short": case "iget-volatile": case "iget-wide": case "iget-wide-quick": case "iget-wide-volatile": case "instance-of": case "int-to-double": case "int-to-float": case "int-to-long": case "invoke-direct/range": case "invoke-direct-empty": case "invoke-interface": case "invoke-interface/range": case "invoke-object-init/range": case "invoke-static/range": case "invoke-super": case "invoke-super/range": case "invoke-super-quick": case "invoke-super-quick/range": case "invoke-virtual/range": case "invoke-virtual-quick": case "invoke-virtual-quick/range": case "iput": case "iput-byte": case "iput-char": case "iput-object-quick": case "iput-object-volatile": case "iput-quick": case "iput-short": case "iput-volatile": case "iput-wide": case "iput-wide-quick": case "iput-wide-volatile": case "long-to-double": case "long-to-float": case "long-to-int": case "move": case "move/16": case "move/from16": case "move-exception": case "move-object": case "move-object/16": case "move-object/from16": case "move-result-wide": case "move-wide": case "move-wide/16": case "move-wide/from16": case "mul-double": case "mul-float": case "mul-float/2addr": case "mul-int": case "mul-int/2addr": case "mul-int/lit16": case "mul-int/lit8": case "mul-long": case "mul-long/2addr": case "neg-double": case "neg-float": case "neg-int": case "neg-long": case "new-array": case "nop": case "not-int": case "not-long": case "or-int": case "or-int/2addr": case "or-int/lit16": case "or-long": case "or-long/2addr": case "packed-switch": case "rem-float": case "rem-float/2addr": case "rem-int": case "rem-int/2addr": case "rem-int/lit16": case "rem-int/lit8": case "rem-long": case "rem-long/2addr": case "return-void-barrier": case "return-wide": case "rsub-int": case "rsub-int/lit8": case "sget": case "sget-boolean": case "sget-byte": case "sget-char": case "sget-object-volatile": case "sget-short": case "sget-volatile": case "sget-wide": case "sget-wide-volatile": case "shl-int": case "shl-int/2addr": case "shl-long": case "shl-long/2addr": case "shr-int": case "shr-int/2addr": case "shr-long": case "shr-long/2addr": case "sparse-switch": case "sput": case "sput-boolean": case "sput-byte": case "sput-char": case "sput-object-volatile": case "sput-short": case "sput-volatile": case "sput-wide": case "sput-wide-volatile": case "sub-double": case "sub-float": case "sub-float/2addr": case "sub-int": case "sub-int/2addr": case "sub-long": case "sub-long/2addr": case "throw-verification-error": case "ushr-int": case "ushr-int/2addr": case "ushr-long": case "ushr-long/2addr": case "xor-int": case "xor-int/2addr": case "xor-long": case "xor-long/2addr": rv.Smali = LineSmali.Unimplemented; rv.aName = sRawText; break; case "goto": case "goto/16": case "goto/32": case "if-eq": case "if-eqz": case "if-ge": case "if-gez": case "if-gt": case "if-gtz": case "if-le": case "if-lez": case "if-lt": case "if-ltz": case "if-ne": case "if-nez": rv.Smali = LineSmali.Conditional; rv.aName = sRawText; break; default: rv.Smali = LineSmali.Unknown; rv.aName = sRawText; break; #endregion } return(true); }
public static SmaliLine Parse(String l) { SmaliLine rv = new SmaliLine(); l = l.Trim(); if (l.Length == 0) // don't process empty lines return null; if (l[0] == '#') // don't process comments return null; String sIdentifiers = l; String sRawText = String.Empty; bool bHasString = l.Contains('"'); if (bHasString) sIdentifiers = SmaliUtils.General.Eat(ref l, '"', false); // get all up to the string sRawText = l; // holds a line or string from a line [OK?] String[] sWords = sIdentifiers.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // space delimited split if (sWords.Length == 0) // nothing to work with return null; String sInst = sWords[0].ToLowerInvariant().Trim(); // get the first item sWords[0] = String.Empty; if (sInst[0] == '.') if (!ParseAsDirective(rv, sInst, ref sWords, ref sRawText)) // only successful and continues if directive is recognized return null; else rv.bIsDirective = true; else if (sRawText[0] == ':') //We'll go with the idea that a label is still an instruction, but there is no need to waste cycles in the instruction parsing loop. { rv.Smali = LineSmali.Label; //TODO: add ParseAsLabel rv.aName = sRawText; } else if (sInst[0] != '.') if (!ParseAsInstruction(rv, sInst, ref sWords, ref sRawText)) return null; return rv; }
public static String Modifiers2Java(SmaliLine.EAccessMod eAccessMod, SmaliLine.ENonAccessMod eNonAccessMod) { return String.Join(" ", new String[] { eAccessMod == 0 ? "" : eAccessMod.ToString().ToLowerInvariant().Replace(",", ""), eNonAccessMod == 0 ? "" : eNonAccessMod.ToString().ToLowerInvariant().Replace(",", "") }); }
public static bool ParseAsDirective(SmaliLine rv, String sInst, ref String[] sWords, ref String sRawText) { switch (sInst) { case ".class": rv.Instruction = LineInstruction.Class; SetModifiers(rv, ref sWords, 1, sWords.Length - 1); rv.aClassName = sWords[sWords.Length - 1]; break; case ".super": rv.Instruction = LineInstruction.Super; rv.aType = sWords[1]; break; case ".implements": rv.Instruction = LineInstruction.Implements; rv.aType = sWords[1]; break; case ".source": rv.Instruction = LineInstruction.Source; rv.aExtra = sRawText; break; case ".field": rv.Instruction = LineInstruction.Field; SetModifiers(rv, ref sWords, 1, sWords.Length - 1); sRawText = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); rv.aName = sRawText.Split(':')[0]; rv.aType = sRawText.Split(':')[1]; break; case ".method": rv.Instruction = LineInstruction.Method; SetModifiers(rv, ref sWords, 1, sWords.Length - 1); sRawText = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); rv.aExtra = sRawText; break; case ".prologue": rv.Instruction = LineInstruction.Prologue; break; case ".registers": rv.Instruction = LineInstruction.Registers; break; case ".line": rv.Instruction = LineInstruction.Line; break; case ".end": switch (sRawText) { case ".end method": rv.Instruction = LineInstruction.EndMethod; break; } break; case ".param": rv.Instruction = LineInstruction.Parameter; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1].Trim()] = String.Empty; rv.aName = sRawText.Substring(sRawText.IndexOf('"') + 1); rv.aName = rv.aName.Substring(0, rv.aName.IndexOf('"')); rv.aType = sRawText.Substring(sRawText.IndexOf('#') + 1).Trim(); break; default: return(false); } return(true); }
public static SmaliLine Parse(String l) { SmaliLine rv = new SmaliLine(); l = l.Trim(); if (l.Length == 0) return null; if (l[0] == '#') return null; String sIdentifiers = l; String sRawText = String.Empty; bool bHasString = l.Contains('"'); if (bHasString) sIdentifiers = SmaliUtils.General.Eat(ref l, '"', false); sRawText = l; String[] sWords = sIdentifiers.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (sWords.Length == 0) return null; String sInst = sWords[0].ToLowerInvariant().Trim(); sWords[0] = String.Empty; if (sInst[0] == '.') if (!ParseAsDirective(rv, sInst, ref sWords, ref sRawText)) return null; else rv.bIsDirective = true; else if (sRawText[0] == ':') //We'll go with the idea that a label is still an instruction, but there is no need to waste cycles in the instruction parsing loop. { rv.Smali = LineSmali.Label; //TODO: add ParseAsLabel rv.aName = sRawText; } else if (sInst[0] != '.') if (!ParseAsInstruction(rv, sInst, ref sWords, ref sRawText)) return null; return rv; }
public static void SetModifiers(SmaliLine l, ref String[] ar, int start, int end) { for (int i = start; i < end; i++) // loop through line instruction args if (Keywords.Contains(ar[i].ToLowerInvariant().Trim())) { if (!ParseNonAccess(l, ar[i].ToLowerInvariant().Trim())) if (!ParseAccess(l, ar[i].ToLowerInvariant().Trim())) ParseModifier(l, ar[i].ToLowerInvariant().Trim()); ar[i] = String.Empty; } }
public static SmaliLine Parse(String l) { SmaliLine rv = new SmaliLine(); l = l.Trim(); if (l.Length == 0) { return(null); } if (l[0] == '#') { return(null); } String sIdentifiers = l; String sRawText = String.Empty; bool bHasString = l.Contains('"'); if (bHasString) { sIdentifiers = SmaliUtils.General.Eat(ref l, '"', false); } sRawText = l; String[] sWords = sIdentifiers.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (sWords.Length == 0) { return(null); } String sInst = sWords[0].ToLowerInvariant().Trim(); sWords[0] = String.Empty; if (sInst[0] == '.') { if (!ParseAsDirective(rv, sInst, ref sWords, ref sRawText)) { return(null); } else { rv.bIsDirective = true; } } else if (sRawText[0] == ':') //We'll go with the idea that a label is still an instruction, but there is no need to waste cycles in the instruction parsing loop. { rv.Smali = LineSmali.Label; //TODO: add ParseAsLabel rv.aName = sRawText; } else if (sInst[0] != '.') { if (!ParseAsInstruction(rv, sInst, ref sWords, ref sRawText)) { return(null); } } return(rv); }
public static void ParseParameters(SmaliLine rv, String s) { if (s.EndsWith(",")) s = s.Substring(0, s.Length - 1); if (s.Contains('{')) s = s.Substring(1, s.Length - 2); if(s.Contains(',')) { String[] sp = s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (String p in sp) rv.lRegisters[p.Trim()] = String.Empty; } else rv.lRegisters[s] = String.Empty; }
public static bool ParseNonAccess(SmaliLine l, String s) { switch (s) { case "static": l.NonAccessModifiers |= ENonAccessMod.Static; break; case "final": l.NonAccessModifiers |= ENonAccessMod.Final; break; case "abstract": l.NonAccessModifiers |= ENonAccessMod.Abstract; break; case "synchronized": l.NonAccessModifiers |= ENonAccessMod.Synchronized; break; case "volatile": l.NonAccessModifiers |= ENonAccessMod.Volatile; break; default: return false; } return true; }
public static bool ParseModifier(SmaliLine l, String s) { switch (s) { case "constructor": l.IsConstructor = true; break; default: return false; } return true; }
public static bool ParseAsInstruction(SmaliLine rv, String sInst, ref String[] sWords, ref String sRawText) { switch (sInst) { case "const": rv.Smali = LineSmali.Const; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sWords[2]; break; case "const/16": rv.Smali = LineSmali.Const16; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sWords[2]; break; case "const/high16": rv.Smali = LineSmali.ConstHigh16; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sWords[2]; break; case "const/4": rv.Smali = LineSmali.Const4; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sWords[2]; break; case "const-string": rv.Smali = LineSmali.ConstString; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1]] = String.Empty; rv.aValue = sRawText; break; case "invoke-static": rv.Smali = LineSmali.InvokeStatic; rv.aName = sWords[sWords.Length - 1]; sWords[sWords.Length - 1] = String.Empty; String sp = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); if (sp.EndsWith(",")) sp = sp.Substring(0, sp.Length - 1); ParseParameters(rv, sp); rv.lRegisters[rv.lRegisters.Keys.First()] = rv.aName; break; case "invoke-direct": rv.Smali = LineSmali.InvokeDirect; if (sWords[1].EndsWith(",")) sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; rv.aName = sWords[sWords.Length - 1]; break; case "move-result-object": rv.Smali = LineSmali.MoveResultObject; rv.lRegisters[sWords[1]] = String.Empty; break; case "move-result": rv.Smali = LineSmali.MoveResult; rv.lRegisters[sWords[1]] = String.Empty; break; case "return": case "return-object": rv.Smali = LineSmali.Return; if (sWords[1].EndsWith(",")) sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[1]; break; case "return-void": rv.Smali = LineSmali.ReturnVoid; break; case "sget-object": rv.Smali = LineSmali.SgetObject; if (sWords[1].EndsWith(",")) sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; break; case "sput-object": rv.Smali = LineSmali.SputObject; if (sWords[1].EndsWith(",")) sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; break; case "new-instance": rv.Smali = LineSmali.NewInstance; if (sWords[1].EndsWith(",")) sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; break; case "iput-object": rv.Smali = LineSmali.IputObject; rv.aValue = sWords[sWords.Length - 1]; sWords[sWords.Length - 1] = String.Empty; sp = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); if (sp.EndsWith(",")) sp = sp.Substring(0, sp.Length - 1); ParseParameters(rv, sp); break; case "iput-boolean": rv.Smali = LineSmali.IputBoolean; if (sWords[1].EndsWith(",")) sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); ParseParameters(rv, sWords[1]); rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; rv.aName = sWords[ sWords.Length - 1]; //Always the last entry. break; case "invoke-virtual": rv.Smali = LineSmali.InvokeVirtual; rv.aName = sWords[sWords.Length - 1]; sWords[sWords.Length - 1] = String.Empty; sp = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); if (sp.EndsWith(",")) sp = sp.Substring(0, sp.Length - 1); ParseParameters(rv, sp); rv.lRegisters[rv.lRegisters.Keys.First()] = rv.aName; break; #region Unimplemented Functions case "add-double": case "add-double/2addr": case "add-float": case "add-float/2addr": case "add-int": case "add-int/2addr": case "add-int/lit16": case "add-int/lit8": case "add-long": case "add-long/2addr": case "aget": case "aget-boolean": case "aget-byte": case "aget-char": case "aget-object": case "aget-short": case "aget-wide": case "and-int": case "and-int/2addr": case "and-int/lit16": case "and-int/lit8": case "and-long": case "and-long/2addr": case "aput": case "aput-boolean": case "aput-byte": case "aput-char": case "aput-object": case "aput-short": case "aput-wide": case "array-length": case "check-cast": case "cmpg-double": case "cmpg-float": case "cmpl-double": case "cmpl-float": case "cmp-long": case "const-class": case "const-string/jumbo": case "const-wide": case "const-wide/16": case "const-wide/32": case "const-wide/high16": case "div-double": case "div-float": case "div-float/2addr": case "div-int": case "div-int/2addr": case "div-int/lit16": case "div-int/lit8": case "div-long": case "div-long/2addr": case "double-to-int": case "double-to-long": case "execute-inline": case "execute-inline/range": case "fill-array-data": case "filled-new-array": case "filled-new-array/range": case "float-to-double": case "float-to-int": case "float-to-long": case "iget": case "iget-boolean": case "iget-byte": case "iget-char": case "iget-object": case "iget-object-quick": case "iget-object-volatile": case "iget-quick": case "iget-short": case "iget-volatile": case "iget-wide": case "iget-wide-quick": case "iget-wide-volatile": case "instance-of": case "int-to-double": case "int-to-float": case "int-to-long": case "invoke-direct/range": case "invoke-direct-empty": case "invoke-interface": case "invoke-interface/range": case "invoke-object-init/range": case "invoke-static/range": case "invoke-super": case "invoke-super/range": case "invoke-super-quick": case "invoke-super-quick/range": case "invoke-virtual/range": case "invoke-virtual-quick": case "invoke-virtual-quick/range": case "iput": case "iput-byte": case "iput-char": case "iput-object-quick": case "iput-object-volatile": case "iput-quick": case "iput-short": case "iput-volatile": case "iput-wide": case "iput-wide-quick": case "iput-wide-volatile": case "long-to-double": case "long-to-float": case "long-to-int": case "move": case "move/16": case "move/from16": case "move-exception": case "move-object": case "move-object/16": case "move-object/from16": case "move-result-wide": case "move-wide": case "move-wide/16": case "move-wide/from16": case "mul-double": case "mul-float": case "mul-float/2addr": case "mul-int": case "mul-int/2addr": case "mul-int/lit16": case "mul-int/lit8": case "mul-long": case "mul-long/2addr": case "neg-double": case "neg-float": case "neg-int": case "neg-long": case "new-array": case "nop": case "not-int": case "not-long": case "or-int": case "or-int/2addr": case "or-int/lit16": case "or-long": case "or-long/2addr": case "packed-switch": case "rem-float": case "rem-float/2addr": case "rem-int": case "rem-int/2addr": case "rem-int/lit16": case "rem-int/lit8": case "rem-long": case "rem-long/2addr": case "return-void-barrier": case "return-wide": case "rsub-int": case "rsub-int/lit8": case "sget": case "sget-boolean": case "sget-byte": case "sget-char": case "sget-object-volatile": case "sget-short": case "sget-volatile": case "sget-wide": case "sget-wide-volatile": case "shl-int": case "shl-int/2addr": case "shl-long": case "shl-long/2addr": case "shr-int": case "shr-int/2addr": case "shr-long": case "shr-long/2addr": case "sparse-switch": case "sput": case "sput-boolean": case "sput-byte": case "sput-char": case "sput-object-volatile": case "sput-short": case "sput-volatile": case "sput-wide": case "sput-wide-volatile": case "sub-double": case "sub-float": case "sub-float/2addr": case "sub-int": case "sub-int/2addr": case "sub-long": case "sub-long/2addr": case "throw-verification-error": case "ushr-int": case "ushr-int/2addr": case "ushr-long": case "ushr-long/2addr": case "xor-int": case "xor-int/2addr": case "xor-long": case "xor-long/2addr": rv.Smali = LineSmali.Unimplemented; rv.aName = sRawText; break; case "goto": case "goto/16": case "goto/32": case "if-eq": case "if-eqz": case "if-ge": case "if-gez": case "if-gt": case "if-gtz": case "if-le": case "if-lez": case "if-lt": case "if-ltz": case "if-ne": case "if-nez": rv.Smali = LineSmali.Conditional; rv.aName = sRawText; break; default: rv.Smali = LineSmali.Unknown; rv.aName = sRawText; break; #endregion } return true; }
public static bool ParseAsDirective(SmaliLine rv, String sInst, ref String[] sWords, ref String sRawText) { switch (sInst) { case ".class": rv.Instruction = LineInstruction.Class; SetModifiers(rv, ref sWords, 1, sWords.Length - 1); rv.aClassName = sWords[sWords.Length - 1]; break; case ".super": rv.Instruction = LineInstruction.Super; rv.aType = sWords[1]; break; case ".implements": rv.Instruction = LineInstruction.Implements; rv.aType = sWords[1]; break; case ".source": rv.Instruction = LineInstruction.Source; rv.aExtra = sRawText; break; case ".field": rv.Instruction = LineInstruction.Field; SetModifiers(rv, ref sWords, 1, sWords.Length - 1); sRawText = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); rv.aName = sRawText.Split(':')[0]; rv.aType = sRawText.Split(':')[1]; break; case ".method": rv.Instruction = LineInstruction.Method; SetModifiers(rv, ref sWords, 1, sWords.Length - 1); sRawText = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); rv.aExtra = sRawText; break; case ".prologue": rv.Instruction = LineInstruction.Prologue; break; case ".registers": rv.Instruction = LineInstruction.Registers; break; case ".line": rv.Instruction = LineInstruction.Line; break; case ".end": switch (sRawText) { case ".end method": rv.Instruction = LineInstruction.EndMethod; break; } break; case ".param": rv.Instruction = LineInstruction.Parameter; sWords[1] = sWords[1].Replace(",", ""); rv.lRegisters[sWords[1].Trim()] = String.Empty; rv.aName = sRawText.Substring(sRawText.IndexOf('"') + 1); rv.aName = rv.aName.Substring(0, rv.aName.IndexOf('"')); rv.aType = sRawText.Substring(sRawText.IndexOf('#') + 1).Trim(); break; default: return false; } return true; }