├── .gitattributes ├── .gitignore ├── README.md ├── Smali2Java-VS2012.sln ├── Smali2Java-v4 ├── Parser │ ├── Line.cs │ ├── LineGroup.cs │ └── Parser.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── Samples │ ├── AndroidHandler.smali │ └── NetqinSmsFilter.smali ├── Smali │ └── SmaliClass.cs └── Smali2Java-v4.csproj └── smali2java ├── App.config ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── Samples ├── AndroidHandler.smali └── NetqinSmsFilter.smali ├── Smali ├── 2SmaliMethod.cs ├── SmaliCall.cs ├── SmaliClass.cs ├── SmaliEngine.cs ├── SmaliField.cs ├── SmaliLine.cs ├── SmaliMethod.cs ├── SmaliParameter.cs ├── SmaliUtils.cs └── SmaliVM.cs └── Smali2Java-v3.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Smali2Java 2 | This is an attempt to develop a direct smali to java converter. The goal is for it to be able to decompile a whole framework.jar or any kind of main Android APK without too much trouble into an Eclipse solution. 3 | 4 | The project's "homepage" (actually a XDA-Developers DevDB thread) is [here](http://forum.xda-developers.com/showthread.php?t=2592266). 5 | 6 | ## Important notes 7 | * THIS IS A WORK IN PROGRESS. It is not complete at all, in fact, it needs YOUR help!. If you're able to fork it and improve it so it can be able to reach its goal, by any means, please do it! 8 | * Please use sample files made with smali 2.0.2 or later, as this project is aimed to use their new syntax, like .param instead of .parameter, and such. 9 | 10 | ## Compatibility 11 | * You need Visual Studio 2012 and .NET Framework 3.5 installed on your machine. 12 | * It has been reported that it also works with SharpDevelop and Mono, so you can compile it under Linux too! 13 | -------------------------------------------------------------------------------- /Smali2Java-VS2012.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Smali2Java-v3", "smali2java\Smali2Java-v3.csproj", "{35577FBA-BEF5-43FB-8B2D-E6D10F0F62C0}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Smali2Java-v4", "Smali2Java-v4\Smali2Java-v4.csproj", "{DCA79475-B106-4055-85BB-30AA93D39D53}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {35577FBA-BEF5-43FB-8B2D-E6D10F0F62C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {35577FBA-BEF5-43FB-8B2D-E6D10F0F62C0}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {35577FBA-BEF5-43FB-8B2D-E6D10F0F62C0}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {35577FBA-BEF5-43FB-8B2D-E6D10F0F62C0}.Release|Any CPU.Build.0 = Release|Any CPU 18 | {DCA79475-B106-4055-85BB-30AA93D39D53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {DCA79475-B106-4055-85BB-30AA93D39D53}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {DCA79475-B106-4055-85BB-30AA93D39D53}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {DCA79475-B106-4055-85BB-30AA93D39D53}.Release|Any CPU.Build.0 = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /Smali2Java-v4/Parser/Line.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java_v4.Parser 7 | { 8 | public enum ELineType 9 | { 10 | Directive = 1, 11 | Instruction = 2, 12 | Label = 3, 13 | Comment = 4 14 | } 15 | 16 | public enum ELineDirective 17 | { 18 | Class = 1, 19 | Super, 20 | Source, 21 | Field, 22 | Method, 23 | EndMethod, 24 | Registers, 25 | Prologue, 26 | Line, 27 | Param, 28 | 29 | } 30 | 31 | public class Line 32 | { 33 | public ELineType Type; 34 | public ELineDirective Directive; 35 | public List Tokens = new List(); 36 | public bool NewGroup = false; 37 | public String Raw; 38 | 39 | public Line(string s) 40 | { 41 | s = s.Trim(); 42 | if(!String.IsNullOrEmpty(s)) 43 | if (s.Length > 0) 44 | { 45 | Raw = s; 46 | 47 | switch (s[0]) 48 | { 49 | case '.': 50 | Type = ELineType.Directive; 51 | break; 52 | case '#': 53 | Type = ELineType.Comment; 54 | break; 55 | case ':': 56 | Type = ELineType.Label; 57 | break; 58 | default: 59 | Type = ELineType.Instruction; 60 | break; 61 | } 62 | if (s.Contains(' ')) 63 | { 64 | Tokens.AddRange(s.Split(new String[] { " " }, StringSplitOptions.RemoveEmptyEntries)); 65 | if (Tokens.Count > 0) 66 | { 67 | switch (Tokens.First().ToLowerInvariant().Trim()) 68 | { 69 | case ".class": 70 | Directive = ELineDirective.Class; 71 | break; 72 | case ".super": 73 | Directive = ELineDirective.Super; 74 | break; 75 | case ".source": 76 | Directive = ELineDirective.Source; 77 | break; 78 | case ".field": 79 | Directive = ELineDirective.Field; 80 | NewGroup = true; 81 | break; 82 | case ".method": 83 | Directive = ELineDirective.Method; 84 | NewGroup = true; 85 | break; 86 | case ".end": 87 | if(Tokens[1] == "method") 88 | Directive = ELineDirective.EndMethod; 89 | break; 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Smali2Java-v4/Parser/LineGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java_v4.Parser 7 | { 8 | public class LineGroup 9 | { 10 | public List Lines = new List(); 11 | 12 | public void Add(Line l) 13 | { 14 | Lines.Add(l); 15 | } 16 | 17 | public String ToJava() 18 | { 19 | StringBuilder sb = new StringBuilder(); 20 | if (Lines.Count > 0) 21 | { 22 | bool bIsClass = false; 23 | foreach (Line l in Lines) 24 | { 25 | if (l.Type == ELineType.Directive) 26 | { 27 | switch (l.Directive) 28 | { 29 | case ELineDirective.Class: 30 | bIsClass = true; 31 | sb.Append(ParseAccesors(l.Tokens.Skip(1).Take(l.Tokens.Count - 2))); 32 | sb.Append(" class "); 33 | sb.Append(ParseObject(l.Tokens.Last())); 34 | break; 35 | case ELineDirective.Super: 36 | sb.Append(" extends "); 37 | sb.Append(ParseObject(l.Tokens.Last())); 38 | break; 39 | case ELineDirective.Field: 40 | sb.Append(ParseAccesors(l.Tokens.Skip(1).Take(l.Tokens.Count - 2))); 41 | sb.Append(" " + ParseObject(l.Tokens.Last()) + ";"); 42 | break; 43 | case ELineDirective.Method: 44 | sb.Append(ParseAccesors(l.Tokens.Skip(1).Take(l.Tokens.Count - 2))); 45 | sb.Append(" " + ParseMethod(l.Tokens.Last())); 46 | sb.AppendLine(" {"); 47 | break; 48 | case ELineDirective.EndMethod: 49 | sb.Append("}"); 50 | break; 51 | } 52 | } 53 | } 54 | 55 | if (bIsClass) 56 | sb.Append(" {"); 57 | } 58 | return sb.ToString(); 59 | } 60 | 61 | private String ParseMethod(String method) 62 | { 63 | StringBuilder sb = new StringBuilder(); 64 | String rType = method.Substring(method.LastIndexOf(')') + 1); 65 | rType = ParseObject(rType); 66 | 67 | String mName = method.Substring(0, method.IndexOf('(')); 68 | 69 | String mArgs = method.Substring(method.IndexOf('(') + 1); 70 | mArgs = mArgs.Substring(0, mArgs.LastIndexOf(')')); 71 | 72 | sb.Append(rType); 73 | sb.Append(" " + mName + "("); 74 | if (mArgs.Length > 0) 75 | { 76 | String[] args = mArgs.Split(new String[] { ";" }, StringSplitOptions.RemoveEmptyEntries); 77 | for(int i = 0; i < args.Length; i++) 78 | sb.Append(ParseObject(args[i]) + " p" + i.ToString()); 79 | } 80 | sb.Append(")"); 81 | 82 | return sb.ToString(); 83 | } 84 | 85 | private String ParseObject(string obj) 86 | { 87 | obj = obj.Trim(); 88 | if(!String.IsNullOrEmpty(obj)) { 89 | if (obj.Contains(":")) 90 | { 91 | String[] split = obj.Split(':'); 92 | split[1] = ParseObject(split[1]); 93 | return split[1] + " " + split[0]; 94 | } 95 | else 96 | { 97 | if (obj[0] == 'L') 98 | obj = obj.Substring(1); 99 | } 100 | obj = obj.Replace('/', '.'); 101 | obj = obj.Replace(";", ""); 102 | } 103 | return obj; 104 | } 105 | 106 | public String ParseAccesors(IEnumerable acc) 107 | { 108 | return String.Join(" ", acc.ToArray()); 109 | } 110 | 111 | public override string ToString() 112 | { 113 | return ToJava(); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Smali2Java-v4/Parser/Parser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Smali2Java_v4.Parser 8 | { 9 | public class ParserSmali 10 | { 11 | public List Lines = new List(); 12 | public List Output = new List(); 13 | 14 | public void Parse(string filename) 15 | { 16 | foreach (String s in File.ReadAllLines(filename)) 17 | if(!String.IsNullOrEmpty(s.Trim())) 18 | Lines.Add(new Line(s)); 19 | 20 | LineGroup lastGroup = new LineGroup(); 21 | foreach (Line l in Lines.Where(x => x.Type != ELineType.Comment)) 22 | { 23 | if (l.NewGroup) 24 | { 25 | Output.Add(lastGroup.ToString()); 26 | lastGroup = new LineGroup(); 27 | } 28 | lastGroup.Add(l); 29 | } 30 | Output.Add("}"); 31 | 32 | foreach (String s in Output) 33 | Console.WriteLine("[" + s + "]"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Smali2Java-v4/Program.cs: -------------------------------------------------------------------------------- 1 | using Smali2Java_v4.Parser; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Smali2Java_v4 8 | { 9 | class Program 10 | { 11 | public static void Main(string[] args) 12 | { 13 | ParserSmali p = new ParserSmali(); 14 | p.Parse("Samples\\NetqinSmsFilter.smali"); 15 | 16 | Console.ReadKey(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Smali2Java-v4/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Smali2Java-v4")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Smali2Java-v4")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("567b9f16-70c0-4e45-8ff1-a2bac2a53407")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Smali2Java-v4/Samples/AndroidHandler.smali: -------------------------------------------------------------------------------- 1 | .class public Lcom/android/internal/logging/AndroidHandler; 2 | .super Ljava/util/logging/Handler; 3 | .source "AndroidHandler.java" 4 | 5 | # interfaces 6 | .implements Ldalvik/system/DalvikLogHandler; 7 | 8 | 9 | # static fields 10 | .field private static final THE_FORMATTER:Ljava/util/logging/Formatter; 11 | 12 | 13 | # direct methods 14 | .method static constructor ()V 15 | .registers 1 16 | 17 | .prologue 18 | .line 88 19 | new-instance v0, Lcom/android/internal/logging/AndroidHandler$1; 20 | 21 | invoke-direct {v0}, Lcom/android/internal/logging/AndroidHandler$1;->()V 22 | 23 | sput-object v0, Lcom/android/internal/logging/AndroidHandler;->THE_FORMATTER:Ljava/util/logging/Formatter; 24 | 25 | return-void 26 | .end method 27 | 28 | .method public constructor ()V 29 | .registers 2 30 | 31 | .prologue 32 | .line 109 33 | invoke-direct {p0}, Ljava/util/logging/Handler;->()V 34 | 35 | .line 110 36 | sget-object v0, Lcom/android/internal/logging/AndroidHandler;->THE_FORMATTER:Ljava/util/logging/Formatter; 37 | 38 | invoke-virtual {p0, v0}, Lcom/android/internal/logging/AndroidHandler;->setFormatter(Ljava/util/logging/Formatter;)V 39 | 40 | .line 111 41 | return-void 42 | .end method 43 | 44 | .method static getAndroidLevel(Ljava/util/logging/Level;)I 45 | .registers 3 46 | .param p0, "level" # Ljava/util/logging/Level; 47 | 48 | .prologue 49 | .line 161 50 | invoke-virtual {p0}, Ljava/util/logging/Level;->intValue()I 51 | 52 | move-result v0 53 | 54 | .line 162 55 | .local v0, "value":I 56 | const/16 v1, 0x3e8 57 | 58 | if-lt v0, v1, :cond_a 59 | 60 | .line 163 61 | const/4 v1, 0x6 62 | 63 | .line 169 64 | :goto_9 65 | return v1 66 | 67 | .line 164 68 | :cond_a 69 | const/16 v1, 0x384 70 | 71 | if-lt v0, v1, :cond_10 72 | 73 | .line 165 74 | const/4 v1, 0x5 75 | 76 | goto :goto_9 77 | 78 | .line 166 79 | :cond_10 80 | const/16 v1, 0x320 81 | 82 | if-lt v0, v1, :cond_16 83 | 84 | .line 167 85 | const/4 v1, 0x4 86 | 87 | goto :goto_9 88 | 89 | .line 169 90 | :cond_16 91 | const/4 v1, 0x3 92 | 93 | goto :goto_9 94 | .end method 95 | 96 | 97 | # virtual methods 98 | .method public close()V 99 | .registers 1 100 | 101 | .prologue 102 | .line 116 103 | return-void 104 | .end method 105 | 106 | .method public flush()V 107 | .registers 1 108 | 109 | .prologue 110 | .line 121 111 | return-void 112 | .end method 113 | 114 | .method public publish(Ljava/util/logging/LogRecord;)V 115 | .registers 8 116 | .param p1, "record" # Ljava/util/logging/LogRecord; 117 | 118 | .prologue 119 | .line 125 120 | invoke-virtual {p1}, Ljava/util/logging/LogRecord;->getLevel()Ljava/util/logging/Level; 121 | 122 | move-result-object v4 123 | 124 | invoke-static {v4}, Lcom/android/internal/logging/AndroidHandler;->getAndroidLevel(Ljava/util/logging/Level;)I 125 | 126 | move-result v1 127 | 128 | .line 126 129 | .local v1, "level":I 130 | invoke-virtual {p1}, Ljava/util/logging/LogRecord;->getLoggerName()Ljava/lang/String; 131 | 132 | move-result-object v4 133 | 134 | invoke-static {v4}, Ldalvik/system/DalvikLogging;->loggerNameToTag(Ljava/lang/String;)Ljava/lang/String; 135 | 136 | move-result-object v3 137 | 138 | .line 127 139 | .local v3, "tag":Ljava/lang/String; 140 | invoke-static {v3, v1}, Landroid/util/Log;->isLoggable(Ljava/lang/String;I)Z 141 | 142 | move-result v4 143 | 144 | if-nez v4, :cond_17 145 | 146 | .line 137 147 | :goto_16 148 | return-void 149 | 150 | .line 132 151 | :cond_17 152 | :try_start_17 153 | invoke-virtual {p0}, Lcom/android/internal/logging/AndroidHandler;->getFormatter()Ljava/util/logging/Formatter; 154 | 155 | move-result-object v4 156 | 157 | invoke-virtual {v4, p1}, Ljava/util/logging/Formatter;->format(Ljava/util/logging/LogRecord;)Ljava/lang/String; 158 | 159 | move-result-object v2 160 | 161 | .line 133 162 | .local v2, "message":Ljava/lang/String; 163 | invoke-static {v1, v3, v2}, Landroid/util/Log;->println(ILjava/lang/String;Ljava/lang/String;)I 164 | :try_end_22 165 | .catch Ljava/lang/RuntimeException; {:try_start_17 .. :try_end_22} :catch_23 166 | 167 | goto :goto_16 168 | 169 | .line 134 170 | .end local v2 # "message":Ljava/lang/String; 171 | :catch_23 172 | move-exception v0 173 | 174 | .line 135 175 | .local v0, "e":Ljava/lang/RuntimeException; 176 | const-string v4, "AndroidHandler" 177 | 178 | const-string v5, "Error logging message." 179 | 180 | invoke-static {v4, v5, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I 181 | 182 | goto :goto_16 183 | .end method 184 | 185 | .method public publish(Ljava/util/logging/Logger;Ljava/lang/String;Ljava/util/logging/Level;Ljava/lang/String;)V 186 | .registers 9 187 | .param p1, "source" # Ljava/util/logging/Logger; 188 | .param p2, "tag" # Ljava/lang/String; 189 | .param p3, "level" # Ljava/util/logging/Level; 190 | .param p4, "message" # Ljava/lang/String; 191 | 192 | .prologue 193 | .line 141 194 | invoke-static {p3}, Lcom/android/internal/logging/AndroidHandler;->getAndroidLevel(Ljava/util/logging/Level;)I 195 | 196 | move-result v1 197 | 198 | .line 142 199 | .local v1, "priority":I 200 | invoke-static {p2, v1}, Landroid/util/Log;->isLoggable(Ljava/lang/String;I)Z 201 | 202 | move-result v2 203 | 204 | if-nez v2, :cond_b 205 | 206 | .line 151 207 | :goto_a 208 | return-void 209 | 210 | .line 147 211 | :cond_b 212 | :try_start_b 213 | invoke-static {v1, p2, p4}, Landroid/util/Log;->println(ILjava/lang/String;Ljava/lang/String;)I 214 | :try_end_e 215 | .catch Ljava/lang/RuntimeException; {:try_start_b .. :try_end_e} :catch_f 216 | 217 | goto :goto_a 218 | 219 | .line 148 220 | :catch_f 221 | move-exception v0 222 | 223 | .line 149 224 | .local v0, "e":Ljava/lang/RuntimeException; 225 | const-string v2, "AndroidHandler" 226 | 227 | const-string v3, "Error logging message." 228 | 229 | invoke-static {v2, v3, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I 230 | 231 | goto :goto_a 232 | .end method 233 | -------------------------------------------------------------------------------- /Smali2Java-v4/Samples/NetqinSmsFilter.smali: -------------------------------------------------------------------------------- 1 | .class public Lcom/netqin/NqSmsFilter; 2 | .super Ljava/lang/Object; 3 | .source "NqSmsFilter.java" 4 | 5 | 6 | # static fields 7 | .field private static final CONTENT_URI:Landroid/net/Uri; 8 | 9 | .field private static filter:Lcom/netqin/NqSmsFilter; 10 | 11 | 12 | # instance fields 13 | .field private ctx:Landroid/content/Context; 14 | 15 | 16 | # direct methods 17 | .method static constructor ()V 18 | .registers 1 19 | 20 | .prologue 21 | .line 23 22 | const/4 v0, 0x0 23 | 24 | sput-object v0, Lcom/netqin/NqSmsFilter;->filter:Lcom/netqin/NqSmsFilter; 25 | 26 | .line 28 27 | const-string v0, "content://com.netqin.provider.SmsFilterProvider" 28 | 29 | invoke-static {v0}, Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri; 30 | 31 | move-result-object v0 32 | 33 | sput-object v0, Lcom/netqin/NqSmsFilter;->CONTENT_URI:Landroid/net/Uri; 34 | 35 | .line 22 36 | return-void 37 | .end method 38 | 39 | .method private constructor (Landroid/content/Context;)V 40 | .registers 2 41 | .param p1, "ctx" # Landroid/content/Context; 42 | 43 | .prologue 44 | .line 25 45 | invoke-direct {p0}, Ljava/lang/Object;->()V 46 | 47 | .line 26 48 | iput-object p1, p0, Lcom/netqin/NqSmsFilter;->ctx:Landroid/content/Context; 49 | 50 | .line 27 51 | return-void 52 | .end method 53 | 54 | .method public static declared-synchronized getInstance(Landroid/content/Context;)Lcom/netqin/NqSmsFilter; 55 | .registers 3 56 | .param p0, "context" # Landroid/content/Context; 57 | 58 | .prologue 59 | .line 36 60 | const-class v1, Lcom/netqin/NqSmsFilter; 61 | 62 | monitor-enter v1 63 | 64 | :try_start_3 65 | sget-object v0, Lcom/netqin/NqSmsFilter;->filter:Lcom/netqin/NqSmsFilter; 66 | 67 | if-nez v0, :cond_e 68 | 69 | .line 37 70 | new-instance v0, Lcom/netqin/NqSmsFilter; 71 | 72 | invoke-direct {v0, p0}, Lcom/netqin/NqSmsFilter;->(Landroid/content/Context;)V 73 | 74 | sput-object v0, Lcom/netqin/NqSmsFilter;->filter:Lcom/netqin/NqSmsFilter; 75 | 76 | .line 40 77 | :cond_e 78 | sget-object v0, Lcom/netqin/NqSmsFilter;->filter:Lcom/netqin/NqSmsFilter; 79 | :try_end_10 80 | .catchall {:try_start_3 .. :try_end_10} :catchall_12 81 | 82 | monitor-exit v1 83 | 84 | return-object v0 85 | 86 | .line 36 87 | :catchall_12 88 | move-exception v0 89 | 90 | monitor-exit v1 91 | 92 | throw v0 93 | .end method 94 | 95 | 96 | # virtual methods 97 | .method public nqGetNetQinLogo()Landroid/graphics/Bitmap; 98 | .registers 5 99 | 100 | .prologue 101 | .line 94 102 | const/4 v0, 0x0 103 | 104 | .line 96 105 | .local v0, "b":Landroid/graphics/Bitmap; 106 | :try_start_1 107 | iget-object v2, p0, Lcom/netqin/NqSmsFilter;->ctx:Landroid/content/Context; 108 | 109 | invoke-virtual {v2}, Landroid/content/Context;->getResources()Landroid/content/res/Resources; 110 | 111 | move-result-object v2 112 | 113 | invoke-virtual {v2}, Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager; 114 | 115 | move-result-object v2 116 | 117 | const-string/jumbo v3, "netqin_icon.png" 118 | 119 | invoke-virtual {v2, v3}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream; 120 | 121 | move-result-object v2 122 | 123 | invoke-static {v2}, Landroid/graphics/BitmapFactory;->decodeStream(Ljava/io/InputStream;)Landroid/graphics/Bitmap; 124 | :try_end_15 125 | .catch Ljava/io/IOException; {:try_start_1 .. :try_end_15} :catch_17 126 | 127 | move-result-object v0 128 | 129 | .line 103 130 | :goto_16 131 | return-object v0 132 | 133 | .line 98 134 | :catch_17 135 | move-exception v1 136 | 137 | .line 100 138 | .local v1, "e":Ljava/io/IOException; 139 | invoke-virtual {v1}, Ljava/io/IOException;->printStackTrace()V 140 | 141 | goto :goto_16 142 | .end method 143 | 144 | .method public nqGetNetQinText()Ljava/lang/String; 145 | .registers 9 146 | 147 | .prologue 148 | const/4 v2, 0x0 149 | 150 | .line 77 151 | const-string v7, "Powered by NetQin" 152 | 153 | .line 78 154 | .local v7, "s":Ljava/lang/String; 155 | iget-object v1, p0, Lcom/netqin/NqSmsFilter;->ctx:Landroid/content/Context; 156 | 157 | invoke-virtual {v1}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver; 158 | 159 | move-result-object v0 160 | 161 | .line 79 162 | .local v0, "cr":Landroid/content/ContentResolver; 163 | sget-object v1, Lcom/netqin/NqSmsFilter;->CONTENT_URI:Landroid/net/Uri; 164 | 165 | const-string v3, "NetqinText" 166 | 167 | move-object v4, v2 168 | 169 | move-object v5, v2 170 | 171 | invoke-virtual/range {v0 .. v5}, Landroid/content/ContentResolver;->query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor; 172 | 173 | move-result-object v6 174 | 175 | .line 80 176 | .local v6, "c":Landroid/database/Cursor; 177 | if-eqz v6, :cond_23 178 | 179 | .line 81 180 | invoke-interface {v6}, Landroid/database/Cursor;->moveToFirst()Z 181 | 182 | move-result v1 183 | 184 | if-eqz v1, :cond_20 185 | 186 | .line 82 187 | const/4 v1, 0x0 188 | 189 | invoke-interface {v6, v1}, Landroid/database/Cursor;->getString(I)Ljava/lang/String; 190 | 191 | move-result-object v7 192 | 193 | .line 84 194 | :cond_20 195 | invoke-interface {v6}, Landroid/database/Cursor;->close()V 196 | 197 | .line 86 198 | :cond_23 199 | return-object v7 200 | .end method 201 | 202 | .method public nqSmsFilter(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z 203 | .registers 15 204 | .param p1, "smsNumber" # Ljava/lang/String; 205 | .param p2, "smsContent" # Ljava/lang/String; 206 | .param p3, "packageName" # Ljava/lang/String; 207 | .param p4, "appName" # Ljava/lang/String; 208 | 209 | .prologue 210 | const/4 v2, 0x0 211 | 212 | const/4 v8, 0x1 213 | 214 | const/4 v9, 0x0 215 | 216 | .line 52 217 | const/4 v6, 0x0 218 | 219 | .line 54 220 | .local v6, "b":I 221 | const/4 v1, 0x4 222 | 223 | new-array v4, v1, [Ljava/lang/String; 224 | 225 | aput-object p1, v4, v9 226 | 227 | aput-object p2, v4, v8 228 | 229 | const/4 v1, 0x2 230 | 231 | aput-object p3, v4, v1 232 | 233 | const/4 v1, 0x3 234 | 235 | aput-object p4, v4, v1 236 | 237 | .line 56 238 | .local v4, "args":[Ljava/lang/String; 239 | iget-object v1, p0, Lcom/netqin/NqSmsFilter;->ctx:Landroid/content/Context; 240 | 241 | invoke-virtual {v1}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver; 242 | 243 | move-result-object v0 244 | 245 | .line 57 246 | .local v0, "cr":Landroid/content/ContentResolver; 247 | sget-object v1, Lcom/netqin/NqSmsFilter;->CONTENT_URI:Landroid/net/Uri; 248 | 249 | move-object v3, v2 250 | 251 | move-object v5, v2 252 | 253 | invoke-virtual/range {v0 .. v5}, Landroid/content/ContentResolver;->query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor; 254 | 255 | move-result-object v7 256 | 257 | .line 58 258 | .local v7, "c":Landroid/database/Cursor; 259 | if-eqz v7, :cond_2e 260 | 261 | .line 59 262 | invoke-interface {v7}, Landroid/database/Cursor;->moveToFirst()Z 263 | 264 | move-result v1 265 | 266 | if-eqz v1, :cond_2b 267 | 268 | .line 60 269 | invoke-interface {v7, v9}, Landroid/database/Cursor;->getInt(I)I 270 | 271 | move-result v6 272 | 273 | .line 62 274 | :cond_2b 275 | invoke-interface {v7}, Landroid/database/Cursor;->close()V 276 | 277 | .line 65 278 | :cond_2e 279 | if-ne v6, v8, :cond_32 280 | 281 | move v1, v8 282 | 283 | .line 68 284 | :goto_31 285 | return v1 286 | 287 | :cond_32 288 | move v1, v9 289 | 290 | goto :goto_31 291 | .end method 292 | -------------------------------------------------------------------------------- /Smali2Java-v4/Smali/SmaliClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java_v4.Smali 7 | { 8 | public class SmaliClass 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Smali2Java-v4/Smali2Java-v4.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DCA79475-B106-4055-85BB-30AA93D39D53} 8 | Exe 9 | Properties 10 | Smali2Java_v4 11 | Smali2Java-v4 12 | v4.0 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Always 54 | 55 | 56 | 57 | 58 | Always 59 | 60 | 61 | 62 | 69 | -------------------------------------------------------------------------------- /smali2java/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /smali2java/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java 7 | { 8 | class Program 9 | { 10 | public static bool Debug = true; 11 | public static void Main(string[] args) 12 | { 13 | if (args.Length == 0) 14 | Console.WriteLine("ERROR: No Input File! using sample file\n"); 15 | 16 | String sFile = args.Length > 0 ? args[0] : "Samples\\AndroidHandler.smali"; 17 | string destFile = args.Length > 1 ? args[1] : null; 18 | 19 | SmaliEngine e = new SmaliEngine(); 20 | string contents = e.Indent(e.Decompile(sFile)); 21 | if (string.IsNullOrEmpty(destFile)) 22 | { 23 | Console.BufferHeight = 10000; 24 | Console.WindowWidth = Console.LargestWindowWidth; 25 | Console.BufferWidth = Console.LargestWindowWidth; 26 | 27 | Console.WriteLine("Decompiling file: " + sFile); 28 | Console.WriteLine("["); 29 | 30 | Console.Write(contents); 31 | Console.WriteLine("]"); 32 | Console.ReadKey(); 33 | } 34 | else 35 | { 36 | System.IO.File.WriteAllText(destFile, contents); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /smali2java/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Smali2Java-v3")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Smali2Java-v3")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2f9b0ddb-db6e-432d-a2a6-e13ccabc9ddb")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /smali2java/Samples/AndroidHandler.smali: -------------------------------------------------------------------------------- 1 | .class public Lcom/android/internal/logging/AndroidHandler; 2 | .super Ljava/util/logging/Handler; 3 | .source "AndroidHandler.java" 4 | 5 | # interfaces 6 | .implements Ldalvik/system/DalvikLogHandler; 7 | 8 | 9 | # static fields 10 | .field private static final THE_FORMATTER:Ljava/util/logging/Formatter; 11 | 12 | 13 | # direct methods 14 | .method static constructor ()V 15 | .registers 1 16 | 17 | .prologue 18 | .line 88 19 | new-instance v0, Lcom/android/internal/logging/AndroidHandler$1; 20 | 21 | invoke-direct {v0}, Lcom/android/internal/logging/AndroidHandler$1;->()V 22 | 23 | sput-object v0, Lcom/android/internal/logging/AndroidHandler;->THE_FORMATTER:Ljava/util/logging/Formatter; 24 | 25 | return-void 26 | .end method 27 | 28 | .method public constructor ()V 29 | .registers 2 30 | 31 | .prologue 32 | .line 109 33 | invoke-direct {p0}, Ljava/util/logging/Handler;->()V 34 | 35 | .line 110 36 | sget-object v0, Lcom/android/internal/logging/AndroidHandler;->THE_FORMATTER:Ljava/util/logging/Formatter; 37 | 38 | invoke-virtual {p0, v0}, Lcom/android/internal/logging/AndroidHandler;->setFormatter(Ljava/util/logging/Formatter;)V 39 | 40 | .line 111 41 | return-void 42 | .end method 43 | 44 | .method static getAndroidLevel(Ljava/util/logging/Level;)I 45 | .registers 3 46 | .param p0, "level" # Ljava/util/logging/Level; 47 | 48 | .prologue 49 | .line 161 50 | invoke-virtual {p0}, Ljava/util/logging/Level;->intValue()I 51 | 52 | move-result v0 53 | 54 | .line 162 55 | .local v0, "value":I 56 | const/16 v1, 0x3e8 57 | 58 | if-lt v0, v1, :cond_a 59 | 60 | .line 163 61 | const/4 v1, 0x6 62 | 63 | .line 169 64 | :goto_9 65 | return v1 66 | 67 | .line 164 68 | :cond_a 69 | const/16 v1, 0x384 70 | 71 | if-lt v0, v1, :cond_10 72 | 73 | .line 165 74 | const/4 v1, 0x5 75 | 76 | goto :goto_9 77 | 78 | .line 166 79 | :cond_10 80 | const/16 v1, 0x320 81 | 82 | if-lt v0, v1, :cond_16 83 | 84 | .line 167 85 | const/4 v1, 0x4 86 | 87 | goto :goto_9 88 | 89 | .line 169 90 | :cond_16 91 | const/4 v1, 0x3 92 | 93 | goto :goto_9 94 | .end method 95 | 96 | 97 | # virtual methods 98 | .method public close()V 99 | .registers 1 100 | 101 | .prologue 102 | .line 116 103 | return-void 104 | .end method 105 | 106 | .method public flush()V 107 | .registers 1 108 | 109 | .prologue 110 | .line 121 111 | return-void 112 | .end method 113 | 114 | .method public publish(Ljava/util/logging/LogRecord;)V 115 | .registers 8 116 | .param p1, "record" # Ljava/util/logging/LogRecord; 117 | 118 | .prologue 119 | .line 125 120 | invoke-virtual {p1}, Ljava/util/logging/LogRecord;->getLevel()Ljava/util/logging/Level; 121 | 122 | move-result-object v4 123 | 124 | invoke-static {v4}, Lcom/android/internal/logging/AndroidHandler;->getAndroidLevel(Ljava/util/logging/Level;)I 125 | 126 | move-result v1 127 | 128 | .line 126 129 | .local v1, "level":I 130 | invoke-virtual {p1}, Ljava/util/logging/LogRecord;->getLoggerName()Ljava/lang/String; 131 | 132 | move-result-object v4 133 | 134 | invoke-static {v4}, Ldalvik/system/DalvikLogging;->loggerNameToTag(Ljava/lang/String;)Ljava/lang/String; 135 | 136 | move-result-object v3 137 | 138 | .line 127 139 | .local v3, "tag":Ljava/lang/String; 140 | invoke-static {v3, v1}, Landroid/util/Log;->isLoggable(Ljava/lang/String;I)Z 141 | 142 | move-result v4 143 | 144 | if-nez v4, :cond_17 145 | 146 | .line 137 147 | :goto_16 148 | return-void 149 | 150 | .line 132 151 | :cond_17 152 | :try_start_17 153 | invoke-virtual {p0}, Lcom/android/internal/logging/AndroidHandler;->getFormatter()Ljava/util/logging/Formatter; 154 | 155 | move-result-object v4 156 | 157 | invoke-virtual {v4, p1}, Ljava/util/logging/Formatter;->format(Ljava/util/logging/LogRecord;)Ljava/lang/String; 158 | 159 | move-result-object v2 160 | 161 | .line 133 162 | .local v2, "message":Ljava/lang/String; 163 | invoke-static {v1, v3, v2}, Landroid/util/Log;->println(ILjava/lang/String;Ljava/lang/String;)I 164 | :try_end_22 165 | .catch Ljava/lang/RuntimeException; {:try_start_17 .. :try_end_22} :catch_23 166 | 167 | goto :goto_16 168 | 169 | .line 134 170 | .end local v2 # "message":Ljava/lang/String; 171 | :catch_23 172 | move-exception v0 173 | 174 | .line 135 175 | .local v0, "e":Ljava/lang/RuntimeException; 176 | const-string v4, "AndroidHandler" 177 | 178 | const-string v5, "Error logging message." 179 | 180 | invoke-static {v4, v5, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I 181 | 182 | goto :goto_16 183 | .end method 184 | 185 | .method public publish(Ljava/util/logging/Logger;Ljava/lang/String;Ljava/util/logging/Level;Ljava/lang/String;)V 186 | .registers 9 187 | .param p1, "source" # Ljava/util/logging/Logger; 188 | .param p2, "tag" # Ljava/lang/String; 189 | .param p3, "level" # Ljava/util/logging/Level; 190 | .param p4, "message" # Ljava/lang/String; 191 | 192 | .prologue 193 | .line 141 194 | invoke-static {p3}, Lcom/android/internal/logging/AndroidHandler;->getAndroidLevel(Ljava/util/logging/Level;)I 195 | 196 | move-result v1 197 | 198 | .line 142 199 | .local v1, "priority":I 200 | invoke-static {p2, v1}, Landroid/util/Log;->isLoggable(Ljava/lang/String;I)Z 201 | 202 | move-result v2 203 | 204 | if-nez v2, :cond_b 205 | 206 | .line 151 207 | :goto_a 208 | return-void 209 | 210 | .line 147 211 | :cond_b 212 | :try_start_b 213 | invoke-static {v1, p2, p4}, Landroid/util/Log;->println(ILjava/lang/String;Ljava/lang/String;)I 214 | :try_end_e 215 | .catch Ljava/lang/RuntimeException; {:try_start_b .. :try_end_e} :catch_f 216 | 217 | goto :goto_a 218 | 219 | .line 148 220 | :catch_f 221 | move-exception v0 222 | 223 | .line 149 224 | .local v0, "e":Ljava/lang/RuntimeException; 225 | const-string v2, "AndroidHandler" 226 | 227 | const-string v3, "Error logging message." 228 | 229 | invoke-static {v2, v3, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I 230 | 231 | goto :goto_a 232 | .end method 233 | -------------------------------------------------------------------------------- /smali2java/Samples/NetqinSmsFilter.smali: -------------------------------------------------------------------------------- 1 | .class public Lcom/netqin/NqSmsFilter; 2 | .super Ljava/lang/Object; 3 | .source "NqSmsFilter.java" 4 | 5 | 6 | # static fields 7 | .field private static final CONTENT_URI:Landroid/net/Uri; 8 | 9 | .field private static filter:Lcom/netqin/NqSmsFilter; 10 | 11 | 12 | # instance fields 13 | .field private ctx:Landroid/content/Context; 14 | 15 | 16 | # direct methods 17 | .method static constructor ()V 18 | .registers 1 19 | 20 | .prologue 21 | .line 23 22 | const/4 v0, 0x0 23 | 24 | sput-object v0, Lcom/netqin/NqSmsFilter;->filter:Lcom/netqin/NqSmsFilter; 25 | 26 | .line 28 27 | const-string v0, "content://com.netqin.provider.SmsFilterProvider" 28 | 29 | invoke-static {v0}, Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri; 30 | 31 | move-result-object v0 32 | 33 | sput-object v0, Lcom/netqin/NqSmsFilter;->CONTENT_URI:Landroid/net/Uri; 34 | 35 | .line 22 36 | return-void 37 | .end method 38 | 39 | .method private constructor (Landroid/content/Context;)V 40 | .registers 2 41 | .param p1, "ctx" # Landroid/content/Context; 42 | 43 | .prologue 44 | .line 25 45 | invoke-direct {p0}, Ljava/lang/Object;->()V 46 | 47 | .line 26 48 | iput-object p1, p0, Lcom/netqin/NqSmsFilter;->ctx:Landroid/content/Context; 49 | 50 | .line 27 51 | return-void 52 | .end method 53 | 54 | .method public static declared-synchronized getInstance(Landroid/content/Context;)Lcom/netqin/NqSmsFilter; 55 | .registers 3 56 | .param p0, "context" # Landroid/content/Context; 57 | 58 | .prologue 59 | .line 36 60 | const-class v1, Lcom/netqin/NqSmsFilter; 61 | 62 | monitor-enter v1 63 | 64 | :try_start_3 65 | sget-object v0, Lcom/netqin/NqSmsFilter;->filter:Lcom/netqin/NqSmsFilter; 66 | 67 | if-nez v0, :cond_e 68 | 69 | .line 37 70 | new-instance v0, Lcom/netqin/NqSmsFilter; 71 | 72 | invoke-direct {v0, p0}, Lcom/netqin/NqSmsFilter;->(Landroid/content/Context;)V 73 | 74 | sput-object v0, Lcom/netqin/NqSmsFilter;->filter:Lcom/netqin/NqSmsFilter; 75 | 76 | .line 40 77 | :cond_e 78 | sget-object v0, Lcom/netqin/NqSmsFilter;->filter:Lcom/netqin/NqSmsFilter; 79 | :try_end_10 80 | .catchall {:try_start_3 .. :try_end_10} :catchall_12 81 | 82 | monitor-exit v1 83 | 84 | return-object v0 85 | 86 | .line 36 87 | :catchall_12 88 | move-exception v0 89 | 90 | monitor-exit v1 91 | 92 | throw v0 93 | .end method 94 | 95 | 96 | # virtual methods 97 | .method public nqGetNetQinLogo()Landroid/graphics/Bitmap; 98 | .registers 5 99 | 100 | .prologue 101 | .line 94 102 | const/4 v0, 0x0 103 | 104 | .line 96 105 | .local v0, "b":Landroid/graphics/Bitmap; 106 | :try_start_1 107 | iget-object v2, p0, Lcom/netqin/NqSmsFilter;->ctx:Landroid/content/Context; 108 | 109 | invoke-virtual {v2}, Landroid/content/Context;->getResources()Landroid/content/res/Resources; 110 | 111 | move-result-object v2 112 | 113 | invoke-virtual {v2}, Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager; 114 | 115 | move-result-object v2 116 | 117 | const-string/jumbo v3, "netqin_icon.png" 118 | 119 | invoke-virtual {v2, v3}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream; 120 | 121 | move-result-object v2 122 | 123 | invoke-static {v2}, Landroid/graphics/BitmapFactory;->decodeStream(Ljava/io/InputStream;)Landroid/graphics/Bitmap; 124 | :try_end_15 125 | .catch Ljava/io/IOException; {:try_start_1 .. :try_end_15} :catch_17 126 | 127 | move-result-object v0 128 | 129 | .line 103 130 | :goto_16 131 | return-object v0 132 | 133 | .line 98 134 | :catch_17 135 | move-exception v1 136 | 137 | .line 100 138 | .local v1, "e":Ljava/io/IOException; 139 | invoke-virtual {v1}, Ljava/io/IOException;->printStackTrace()V 140 | 141 | goto :goto_16 142 | .end method 143 | 144 | .method public nqGetNetQinText()Ljava/lang/String; 145 | .registers 9 146 | 147 | .prologue 148 | const/4 v2, 0x0 149 | 150 | .line 77 151 | const-string v7, "Powered by NetQin" 152 | 153 | .line 78 154 | .local v7, "s":Ljava/lang/String; 155 | iget-object v1, p0, Lcom/netqin/NqSmsFilter;->ctx:Landroid/content/Context; 156 | 157 | invoke-virtual {v1}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver; 158 | 159 | move-result-object v0 160 | 161 | .line 79 162 | .local v0, "cr":Landroid/content/ContentResolver; 163 | sget-object v1, Lcom/netqin/NqSmsFilter;->CONTENT_URI:Landroid/net/Uri; 164 | 165 | const-string v3, "NetqinText" 166 | 167 | move-object v4, v2 168 | 169 | move-object v5, v2 170 | 171 | invoke-virtual/range {v0 .. v5}, Landroid/content/ContentResolver;->query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor; 172 | 173 | move-result-object v6 174 | 175 | .line 80 176 | .local v6, "c":Landroid/database/Cursor; 177 | if-eqz v6, :cond_23 178 | 179 | .line 81 180 | invoke-interface {v6}, Landroid/database/Cursor;->moveToFirst()Z 181 | 182 | move-result v1 183 | 184 | if-eqz v1, :cond_20 185 | 186 | .line 82 187 | const/4 v1, 0x0 188 | 189 | invoke-interface {v6, v1}, Landroid/database/Cursor;->getString(I)Ljava/lang/String; 190 | 191 | move-result-object v7 192 | 193 | .line 84 194 | :cond_20 195 | invoke-interface {v6}, Landroid/database/Cursor;->close()V 196 | 197 | .line 86 198 | :cond_23 199 | return-object v7 200 | .end method 201 | 202 | .method public nqSmsFilter(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z 203 | .registers 15 204 | .param p1, "smsNumber" # Ljava/lang/String; 205 | .param p2, "smsContent" # Ljava/lang/String; 206 | .param p3, "packageName" # Ljava/lang/String; 207 | .param p4, "appName" # Ljava/lang/String; 208 | 209 | .prologue 210 | const/4 v2, 0x0 211 | 212 | const/4 v8, 0x1 213 | 214 | const/4 v9, 0x0 215 | 216 | .line 52 217 | const/4 v6, 0x0 218 | 219 | .line 54 220 | .local v6, "b":I 221 | const/4 v1, 0x4 222 | 223 | new-array v4, v1, [Ljava/lang/String; 224 | 225 | aput-object p1, v4, v9 226 | 227 | aput-object p2, v4, v8 228 | 229 | const/4 v1, 0x2 230 | 231 | aput-object p3, v4, v1 232 | 233 | const/4 v1, 0x3 234 | 235 | aput-object p4, v4, v1 236 | 237 | .line 56 238 | .local v4, "args":[Ljava/lang/String; 239 | iget-object v1, p0, Lcom/netqin/NqSmsFilter;->ctx:Landroid/content/Context; 240 | 241 | invoke-virtual {v1}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver; 242 | 243 | move-result-object v0 244 | 245 | .line 57 246 | .local v0, "cr":Landroid/content/ContentResolver; 247 | sget-object v1, Lcom/netqin/NqSmsFilter;->CONTENT_URI:Landroid/net/Uri; 248 | 249 | move-object v3, v2 250 | 251 | move-object v5, v2 252 | 253 | invoke-virtual/range {v0 .. v5}, Landroid/content/ContentResolver;->query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor; 254 | 255 | move-result-object v7 256 | 257 | .line 58 258 | .local v7, "c":Landroid/database/Cursor; 259 | if-eqz v7, :cond_2e 260 | 261 | .line 59 262 | invoke-interface {v7}, Landroid/database/Cursor;->moveToFirst()Z 263 | 264 | move-result v1 265 | 266 | if-eqz v1, :cond_2b 267 | 268 | .line 60 269 | invoke-interface {v7, v9}, Landroid/database/Cursor;->getInt(I)I 270 | 271 | move-result v6 272 | 273 | .line 62 274 | :cond_2b 275 | invoke-interface {v7}, Landroid/database/Cursor;->close()V 276 | 277 | .line 65 278 | :cond_2e 279 | if-ne v6, v8, :cond_32 280 | 281 | move v1, v8 282 | 283 | .line 68 284 | :goto_31 285 | return v1 286 | 287 | :cond_32 288 | move v1, v9 289 | 290 | goto :goto_31 291 | .end method 292 | -------------------------------------------------------------------------------- /smali2java/Smali/2SmaliMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Smali2Java 8 | { 9 | public class SmaliMethod 10 | { 11 | public SmaliClass ParentClass; 12 | public SmaliVM vm = new SmaliVM(); 13 | public StringBuilder Buffer = new StringBuilder(); 14 | public StringBuilder JavaBuffer = new StringBuilder(); 15 | 16 | public List Java = new List(); 17 | public List Lines = new List(); 18 | public SmaliLine.EAccessMod AccessModifiers; 19 | public SmaliLine.ENonAccessMod NonAccessModifiers; 20 | public SmaliLine.LineReturnType ReturnType; 21 | public List Parameters = new List(); 22 | public String Name; 23 | public String SmaliReturnType; 24 | public bool IsClinit = false; 25 | public bool IsConstructor = false; 26 | public bool IsFirstParam = true; 27 | public bool Isp0self = false; 28 | 29 | // MAIN TRANSLATION METHOD, FAKE VIRTUAL MACHINE 30 | public void Process() 31 | { 32 | for (int i = 0; i < Lines.Count; i++) 33 | { 34 | SmaliLine l = Lines[i]; 35 | if (l.bIsDirective) 36 | { 37 | #region Directives 38 | switch (l.Instruction) 39 | { 40 | case SmaliLine.LineInstruction.Method: 41 | #region Method 42 | AccessModifiers = l.AccessModifiers; 43 | NonAccessModifiers = l.NonAccessModifiers; 44 | Name = l.aName; 45 | ReturnType = l.ReturnType; 46 | SmaliReturnType = l.aReturnType; 47 | IsConstructor = l.IsConstructor; 48 | #endregion 49 | break; 50 | case SmaliLine.LineInstruction.Parameter: 51 | #region Parameter 52 | if (l.aName != "p0" && IsFirstParam) 53 | { 54 | IsFirstParam = false; 55 | Isp0self = true; 56 | Parameters.Add(new SmaliParameter() 57 | { 58 | Name = "this", 59 | Register = "p0", 60 | Type = ParentClass.ClassName 61 | }); 62 | } 63 | 64 | l.aName = char.ToUpper(l.aName[0]) + l.aName.Substring(1); 65 | Parameters.Add(new SmaliParameter() 66 | { 67 | Name = "param" + l.aName, 68 | Register = l.lRegisters.Keys.First(), 69 | Type = l.aType 70 | }); 71 | #endregion 72 | break; 73 | case SmaliLine.LineInstruction.Prologue: 74 | #region Prologue (method declaration) 75 | StringBuilder sb = new StringBuilder(); 76 | 77 | if (Name == "") 78 | IsClinit = true; 79 | 80 | if (IsClinit) 81 | { 82 | Name = ""; 83 | ReturnType = SmaliLine.LineReturnType.Custom; 84 | SmaliReturnType = ""; 85 | } 86 | else if (Name == "") 87 | { 88 | Name = ParentClass.ClassName.Replace(";", ""); 89 | SmaliReturnType = ""; 90 | ReturnType = SmaliLine.LineReturnType.Custom; 91 | } 92 | 93 | sb.AppendFormat("{0} {1} {2} {3}", 94 | AccessModifiers == 0 ? "" : AccessModifiers.ToString().ToLowerInvariant().Replace(",", ""), 95 | NonAccessModifiers == 0 ? "" : NonAccessModifiers.ToString().ToLowerInvariant().Replace(",", ""), 96 | ReturnType == SmaliLine.LineReturnType.Custom ? SmaliUtils.General.Name2Java(SmaliReturnType) : ReturnType.ToString().ToLowerInvariant(), 97 | Name 98 | ); 99 | 100 | if (!IsClinit) 101 | sb.Append(" ("); 102 | 103 | if (Parameters.Count > 0) 104 | { 105 | for(int j = Isp0self ? 1 : 0; j < Parameters.Count; j++) 106 | sb.Append(Parameters[j].ToJava() + ", "); 107 | sb.Remove(sb.Length - 2, 2); 108 | 109 | if (Isp0self) 110 | vm.Put("p0", "this"); 111 | } 112 | 113 | if(!IsClinit) 114 | sb.Append(") "); 115 | 116 | sb.Append("{"); 117 | 118 | Buffer.Append(sb.ToString()); 119 | #endregion 120 | break; 121 | case SmaliLine.LineInstruction.EndMethod: 122 | Java.Add("}"); 123 | break; 124 | case SmaliLine.LineInstruction.Line: 125 | if (!String.IsNullOrEmpty(Buffer.ToString())) 126 | { 127 | JavaBuffer.Append(Buffer.ToString()); 128 | if (!String.IsNullOrEmpty(JavaBuffer.ToString())) 129 | { 130 | Java.Add(JavaBuffer.ToString()); 131 | Buffer = new StringBuilder(); 132 | JavaBuffer = new StringBuilder(); 133 | } 134 | } 135 | break; 136 | } 137 | #endregion 138 | } 139 | else 140 | { 141 | #region Smali instructions 142 | String sReg; 143 | String sSrcValue; 144 | String sDstValue; 145 | switch (l.Smali) 146 | { 147 | case SmaliLine.LineSmali.Const4: 148 | case SmaliLine.LineSmali.ConstString: 149 | vm.Put(l.lRegisters.Keys.First(), l.aValue); 150 | break; 151 | 152 | case SmaliLine.LineSmali.SputObject: 153 | sReg = l.lRegisters.Keys.First(); 154 | 155 | if (!vm.vmStack.ContainsKey(sReg)) 156 | { 157 | // SKIP! 158 | break; 159 | } 160 | 161 | sSrcValue = vm.Get(sReg); 162 | sDstValue = l.lRegisters[sReg]; 163 | 164 | Dictionary args = new Dictionary(); 165 | args[sReg] = sSrcValue; 166 | 167 | Buffer.Append(ParseSmali(sDstValue, args)); 168 | break; 169 | 170 | case SmaliLine.LineSmali.InvokeStatic: 171 | //case SmaliLine.LineSmali.InvokeDirect: 172 | 173 | args = new Dictionary(); 174 | foreach (KeyValuePair kv in l.lRegisters) 175 | { 176 | if (!vm.vmStack.ContainsKey(kv.Key)) 177 | { 178 | // SKIP! 179 | break; 180 | } 181 | args[kv.Key] = vm.Get(kv.Key); 182 | } 183 | 184 | Buffer.Append(SmaliUtils.General.Name2Java(l.aClassName)); 185 | Buffer.Append("." + l.aName + "("); 186 | 187 | if (args.Count > 0) 188 | { 189 | foreach (KeyValuePair kv in args) 190 | Buffer.Append(kv.Value + ", "); 191 | Buffer.Remove(Buffer.Length - 2, 2); 192 | } 193 | 194 | Buffer.Append(")"); 195 | 196 | break; 197 | 198 | case SmaliLine.LineSmali.MoveResultObject: 199 | 200 | if (Buffer.Length > 0) 201 | { 202 | sReg = l.lRegisters.Keys.First(); 203 | vm.Put(sReg, Buffer.ToString()); 204 | Buffer = new StringBuilder(); 205 | } 206 | 207 | break; 208 | case SmaliLine.LineSmali.ReturnVoid: 209 | Buffer.Append("return"); 210 | break; 211 | } 212 | #endregion 213 | } 214 | } 215 | } 216 | 217 | public string ParseSmali(string smaliLine, Dictionary args) 218 | { 219 | if (smaliLine.Contains('(')) 220 | { 221 | // It's a function 222 | } 223 | else 224 | { 225 | // It's an assignment 226 | String sClass = SmaliUtils.General.Eat(ref smaliLine, "->", true); 227 | String sName = SmaliUtils.General.Eat(ref smaliLine, ":", true); 228 | String sType = smaliLine; 229 | 230 | sClass = sClass.Replace(ParentClass.PackageName, ""); 231 | sClass = sClass.Substring(1); 232 | 233 | if (sClass == ParentClass.ClassName) 234 | sClass = ""; 235 | else 236 | sClass = SmaliUtils.General.Name2Java(sClass) + "."; 237 | 238 | return sClass + sName + " = " + args[args.Keys.First()] + ";"; 239 | } 240 | 241 | return ":D"; 242 | } 243 | 244 | public String ToJava() 245 | { 246 | StringBuilder sb = new StringBuilder(); 247 | foreach (String s in Java) 248 | sb.AppendLine(s); 249 | return sb.ToString(); 250 | } 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /smali2java/Smali/SmaliCall.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java 7 | { 8 | public class SmaliCall 9 | { 10 | [Flags] 11 | public enum ECallFlags 12 | { 13 | ClassInit = 1, 14 | Constructor = 2 15 | } 16 | 17 | public String ClassName; 18 | public String Method; 19 | public String Variable; 20 | public String Return; 21 | public List Parameters = new List(); 22 | public SmaliLine.LineReturnType SmaliReturnType; 23 | public ECallFlags CallFlags; 24 | 25 | public static SmaliCall Parse(String l) 26 | { 27 | SmaliCall rv = new SmaliCall(); 28 | rv.Method = l; 29 | 30 | if (l.Contains("(")) 31 | { 32 | // Function call 33 | rv.Method = rv.Method.Substring(0, rv.Method.IndexOf("(")); 34 | rv.Return = l.Substring(l.LastIndexOf(")") + 1); 35 | if (rv.Return.Length > 0) 36 | rv.SmaliReturnType = SmaliUtils.General.GetReturnType(rv.Return); 37 | 38 | if(rv.Method.Contains("->")) 39 | { 40 | rv.ClassName = rv.Method.Substring(0, rv.Method.IndexOf(";")); 41 | rv.Method = rv.Method.Substring(rv.Method.IndexOf("->") + 2); 42 | } 43 | } 44 | else 45 | { 46 | if (l.Contains("/")) 47 | { 48 | rv.ClassName = l; 49 | if (l.Contains("->")) 50 | rv.ClassName = l.Substring(0, l.IndexOf("->")); 51 | 52 | // Get class name out 53 | rv.ClassName = rv.ClassName.Substring(0, rv.ClassName.LastIndexOf('/')); 54 | rv.Method = l.Substring(rv.ClassName.Length + 1); 55 | if (l.Contains(":")) 56 | { 57 | rv.Variable = rv.Method.Substring(rv.Method.IndexOf("->") + 2); 58 | rv.Variable = rv.Variable.Substring(0, rv.Variable.IndexOf(":")); 59 | } 60 | rv.Method = rv.Method.Substring(0, rv.Method.IndexOf(";")); 61 | } 62 | } 63 | 64 | if (rv.Method.EndsWith(";")) 65 | rv.Method = rv.Method.Remove(rv.Method.Length - 1, 1); 66 | 67 | if(l.Contains("(")) 68 | { 69 | // Get parameters 70 | String sParameters = l.Substring(l.IndexOf("(") + 1); 71 | sParameters = sParameters.Substring(0, sParameters.IndexOf(")")); 72 | if (sParameters.Length > 0) 73 | { 74 | String[] aParm = sParameters.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); 75 | foreach (String p in aParm) 76 | if (p.StartsWith("L")) 77 | { 78 | rv.Parameters.Add(new SmaliParameter() 79 | { 80 | Type = p, 81 | }); 82 | } 83 | else 84 | { 85 | for (int i = 0 ; i < p.Length; i++) 86 | { 87 | if (!p[i].Equals('L')) 88 | { 89 | rv.Parameters.Add(new SmaliParameter() 90 | { 91 | Type = String.Empty + p[i], 92 | }); 93 | } 94 | else if (p[i].Equals('[')) // This is an Array. 95 | { 96 | if (p[i+1].Equals('L')) 97 | { 98 | rv.Parameters.Add(new SmaliParameter() 99 | { 100 | Type = p.Substring(i), 101 | }); 102 | break; 103 | } 104 | else 105 | { 106 | rv.Parameters.Add(new SmaliParameter() 107 | { 108 | Type = String.Empty + p[i] + p[i+1], 109 | }); 110 | i++; 111 | } 112 | } 113 | else 114 | { 115 | rv.Parameters.Add(new SmaliParameter() 116 | { 117 | Type = p.Substring(i), 118 | }); 119 | break; 120 | } 121 | } 122 | } 123 | } 124 | } 125 | 126 | // Set flags 127 | if (rv.Method == "") 128 | { 129 | rv.Method = String.Empty; 130 | rv.Return = String.Empty; 131 | rv.SmaliReturnType = SmaliLine.LineReturnType.Custom; 132 | rv.CallFlags |= ECallFlags.ClassInit; 133 | } 134 | if (rv.Method == "") 135 | { 136 | rv.Return = String.Empty; 137 | rv.SmaliReturnType = SmaliLine.LineReturnType.Custom; 138 | rv.CallFlags |= ECallFlags.Constructor; 139 | } 140 | 141 | return rv; 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /smali2java/Smali/SmaliClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java 7 | { 8 | public class SmaliClass 9 | { 10 | public List Lines; 11 | 12 | public String PackageName; 13 | public String ClassName; 14 | public String SourceFile; 15 | public String Extends; 16 | public String Implements; 17 | public SmaliLine.EAccessMod AccessModifiers; 18 | public SmaliLine.ENonAccessMod NonAccessModifiers; 19 | public List Fields = new List(); 20 | public List Methods = new List(); 21 | 22 | public void LoadAttributes() 23 | { 24 | SmaliLine line = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Class).Single(); 25 | ClassName = line.aClassName.Substring(line.aClassName.LastIndexOf('/') + 1).Replace(";", ""); 26 | AccessModifiers = line.AccessModifiers; 27 | NonAccessModifiers = line.NonAccessModifiers; 28 | if(line.aClassName.Contains("/")) 29 | PackageName = line.aClassName.Substring(0, line.aClassName.LastIndexOf('/')); 30 | 31 | line = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Super).SingleOrDefault(); 32 | if (line != null) 33 | Extends = line.aType; 34 | 35 | line = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Implements).SingleOrDefault(); 36 | if (line != null) 37 | Implements = line.aType; 38 | 39 | line = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Source).SingleOrDefault(); 40 | if(line != null) 41 | SourceFile = line.aExtra; 42 | } 43 | public void LoadFields() 44 | { 45 | foreach (SmaliLine l in Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Field)) 46 | Fields.Add(new SmaliField() 47 | { 48 | AccessModifiers = l.AccessModifiers, 49 | NonAccessModifiers = l.NonAccessModifiers, 50 | Type = l.aType, 51 | Name = l.aName 52 | }); 53 | } 54 | public void LoadMethods() 55 | { 56 | bool bAdd = false; 57 | SmaliMethod m = null; 58 | 59 | for (int i = 0; i < Lines.Count; i++) 60 | { 61 | SmaliLine l = Lines[i]; 62 | 63 | if (bAdd) 64 | { 65 | m.Lines.Add(l); 66 | if (l.Instruction == SmaliLine.LineInstruction.EndMethod) 67 | { 68 | bAdd = false; 69 | //if(Methods.Count < 3) 70 | Methods.Add(m); 71 | } 72 | else 73 | continue; 74 | } 75 | 76 | if (l.Instruction == SmaliLine.LineInstruction.Method) 77 | { 78 | bAdd = true; 79 | m = new SmaliMethod(); 80 | m.ParentClass = this; 81 | m.Lines.Add(l); 82 | } 83 | } 84 | 85 | foreach (SmaliMethod me in Methods) 86 | me.Process(); 87 | } 88 | 89 | public String ToJava() 90 | { 91 | String rv = String.Empty; 92 | StringBuilder sb = new StringBuilder(); 93 | 94 | if(!String.IsNullOrEmpty(PackageName)) 95 | sb.AppendFormat("package {0};\n\n", SmaliUtils.General.Name2Java(PackageName)); 96 | 97 | sb.AppendFormat("{0} {1} class {2} {3} {4} {5} {6} {{\n", 98 | AccessModifiers == 0 ? "" : AccessModifiers.ToString().ToLowerInvariant().Replace(",", ""), 99 | NonAccessModifiers == 0 ? "" : NonAccessModifiers.ToString().ToLowerInvariant().Replace(",", ""), 100 | SmaliUtils.General.Name2Java(ClassName), 101 | String.IsNullOrEmpty(Extends) ? "" : "extends", 102 | String.IsNullOrEmpty(Extends) ? "" : SmaliUtils.General.Name2Java(Extends), 103 | String.IsNullOrEmpty(Implements) ? "" : "implements", 104 | String.IsNullOrEmpty(Implements) ? "" : SmaliUtils.General.Name2Java(Implements) 105 | ); 106 | 107 | foreach (SmaliField f in Fields) 108 | sb.Append(f.ToJava()); 109 | 110 | foreach (SmaliMethod m in Methods) 111 | sb.Append(m.ToJava()); 112 | 113 | sb.AppendLine("}"); 114 | 115 | rv = sb.ToString(); 116 | return rv; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /smali2java/Smali/SmaliEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Smali2Java 8 | { 9 | public class SmaliEngine 10 | { 11 | public static SmaliVM VM = new SmaliVM(); 12 | private List Lines = new List(); 13 | 14 | public String Decompile(String sFilename) 15 | { 16 | String rv = String.Empty; 17 | 18 | foreach (String s in File.ReadAllLines(sFilename).Where(x => !String.IsNullOrEmpty(x))) 19 | { 20 | SmaliLine l = SmaliLine.Parse(s); 21 | if (l != null) 22 | Lines.Add(l); 23 | } 24 | 25 | SmaliClass c = new SmaliClass(); 26 | c.Lines = Lines; 27 | c.LoadAttributes(); 28 | c.LoadFields(); 29 | c.LoadMethods(); 30 | 31 | StringBuilder sb = new StringBuilder(); 32 | 33 | sb.Append(c.ToJava()); 34 | 35 | rv = sb.ToString(); 36 | return rv; 37 | } 38 | 39 | public String Indent(String java) 40 | { 41 | int indentation = 0; 42 | String indenter = " "; 43 | StringBuilder sb = new StringBuilder(); 44 | 45 | string[] lines = java.Split('\n'); 46 | for (int i = 0; i < lines.Length; i++) 47 | { 48 | if (lines[i].TrimStart().Contains("}")) 49 | { 50 | indentation--; 51 | } 52 | 53 | for (int n = 0; n < indentation; n++) 54 | { 55 | sb.Append(indenter); 56 | } 57 | sb.AppendFormat("{0}\n", lines[i]); 58 | 59 | if (lines[i].TrimStart().Contains("{")) 60 | { 61 | indentation++; 62 | } 63 | } 64 | 65 | return sb.ToString(); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /smali2java/Smali/SmaliField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java 7 | { 8 | public class SmaliField 9 | { 10 | public SmaliLine.EAccessMod AccessModifiers; 11 | public SmaliLine.ENonAccessMod NonAccessModifiers; 12 | public String Name; 13 | public String Type; 14 | 15 | public String ToJava() 16 | { 17 | return String.Format("{0} {1} {2} {3};\n", 18 | AccessModifiers == 0 ? "" : AccessModifiers.ToString().ToLowerInvariant().Replace(",", ""), 19 | NonAccessModifiers == 0 ? "" : NonAccessModifiers.ToString().ToLowerInvariant().Replace(",", ""), 20 | SmaliUtils.General.Name2Java(SmaliUtils.General.ReturnType2Java(SmaliUtils.General.GetReturnType(Type),Type)).Replace(";",""), 21 | Name 22 | ); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /smali2java/Smali/SmaliLine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java 7 | { 8 | public class SmaliLine 9 | { 10 | #region Definitions 11 | 12 | [Flags] 13 | public enum EAccessMod 14 | { 15 | Private = 1, 16 | Public = 2, 17 | Protected = 4 18 | } 19 | 20 | [Flags] 21 | public enum ENonAccessMod 22 | { 23 | Static = 1, 24 | Final = 2, 25 | Abstract = 4, 26 | Synchronized = 8, 27 | Volatile = 16, 28 | } 29 | 30 | public static String[] Keywords = new String[] 31 | { 32 | "public", 33 | "private", 34 | "protected", 35 | "static", 36 | "final", 37 | "abstract", 38 | "synchronized", 39 | "volatile", 40 | "constructor" 41 | }; 42 | 43 | public enum LineInstruction 44 | { 45 | Unknown = -1, 46 | Class = 1, 47 | Super, 48 | Implements, 49 | Source, 50 | Field, 51 | Method, 52 | Registers, 53 | Prologue, 54 | Line, 55 | EndMethod, 56 | Catch, 57 | Parameter 58 | } 59 | 60 | public enum LineBlock 61 | { 62 | None = 1, 63 | TryStart, 64 | TryCatch, 65 | TryEnd, 66 | IfStart, 67 | IfEnd 68 | } 69 | 70 | public enum LineSmali 71 | { 72 | Unknown = -1, 73 | Const4 = 1, 74 | Const, 75 | Const16, 76 | ConstHigh16, 77 | ConstString, 78 | SputObject, 79 | SgetObject, 80 | IputObject, 81 | IputBoolean, 82 | InvokeStatic, 83 | InvokeDirect, 84 | InvokeVirtual, 85 | MoveResultObject, 86 | MoveResult, 87 | NewInstance, 88 | ReturnVoid, 89 | Return, 90 | Unimplemented, 91 | Conditional, 92 | Label 93 | } 94 | 95 | public enum LineReturnType 96 | { 97 | Custom = 1, 98 | Void, 99 | Int, 100 | Boolean, 101 | Byte, 102 | Short, 103 | Char, 104 | Long, 105 | Double, 106 | CustomArray, 107 | VoidArray, 108 | IntArray, 109 | BooleanArray, 110 | ByteArray, 111 | ShortArray, 112 | CharArray, 113 | LongArray, 114 | DoubleArray 115 | } 116 | #endregion 117 | 118 | // Flags & identifiers 119 | public LineInstruction Instruction; 120 | public LineBlock Block; 121 | public LineSmali Smali; 122 | public EAccessMod AccessModifiers; 123 | public ENonAccessMod NonAccessModifiers; 124 | public LineReturnType ReturnType; 125 | 126 | // Simple flags 127 | public bool bIsDirective = false; 128 | public bool IsConstructor = false; 129 | public bool IsDestructor = false; 130 | 131 | // Attributes 132 | public String aType; 133 | public String aExtra; 134 | public String aName; 135 | public String aClassName; 136 | public String aReturnType; 137 | public String aValue; 138 | public Dictionary lRegisters = new Dictionary(); 139 | 140 | public static SmaliLine Parse(String l) 141 | { 142 | SmaliLine rv = new SmaliLine(); 143 | 144 | l = l.Trim(); 145 | if (l.Length == 0) 146 | return null; 147 | 148 | if (l[0] == '#') 149 | return null; 150 | 151 | String sIdentifiers = l; 152 | String sRawText = String.Empty; 153 | bool bHasString = l.Contains('"'); 154 | 155 | if (bHasString) 156 | sIdentifiers = SmaliUtils.General.Eat(ref l, '"', false); 157 | sRawText = l; 158 | 159 | String[] sWords = sIdentifiers.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 160 | 161 | if (sWords.Length == 0) 162 | return null; 163 | 164 | String sInst = sWords[0].ToLowerInvariant().Trim(); 165 | sWords[0] = String.Empty; 166 | 167 | if (sInst[0] == '.') 168 | if (!ParseAsDirective(rv, sInst, ref sWords, ref sRawText)) 169 | return null; 170 | else 171 | rv.bIsDirective = true; 172 | 173 | 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. 174 | { 175 | rv.Smali = LineSmali.Label; //TODO: add ParseAsLabel 176 | rv.aName = sRawText; 177 | } 178 | 179 | else if (sInst[0] != '.') 180 | if (!ParseAsInstruction(rv, sInst, ref sWords, ref sRawText)) 181 | return null; 182 | 183 | return rv; 184 | } 185 | 186 | #region Directive Parsing 187 | 188 | public static bool ParseAsDirective(SmaliLine rv, String sInst, ref String[] sWords, ref String sRawText) 189 | { 190 | switch (sInst) 191 | { 192 | case ".class": 193 | rv.Instruction = LineInstruction.Class; 194 | SetModifiers(rv, ref sWords, 1, sWords.Length - 1); 195 | rv.aClassName = sWords[sWords.Length - 1]; 196 | break; 197 | case ".super": 198 | rv.Instruction = LineInstruction.Super; 199 | rv.aType = sWords[1]; 200 | break; 201 | case ".implements": 202 | rv.Instruction = LineInstruction.Implements; 203 | rv.aType = sWords[1]; 204 | break; 205 | case ".source": 206 | rv.Instruction = LineInstruction.Source; 207 | rv.aExtra = sRawText; 208 | break; 209 | case ".field": 210 | rv.Instruction = LineInstruction.Field; 211 | SetModifiers(rv, ref sWords, 1, sWords.Length - 1); 212 | sRawText = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); 213 | rv.aName = sRawText.Split(':')[0]; 214 | rv.aType = sRawText.Split(':')[1]; 215 | break; 216 | case ".method": 217 | rv.Instruction = LineInstruction.Method; 218 | SetModifiers(rv, ref sWords, 1, sWords.Length - 1); 219 | sRawText = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); 220 | rv.aExtra = sRawText; 221 | break; 222 | case ".prologue": 223 | rv.Instruction = LineInstruction.Prologue; 224 | break; 225 | case ".registers": 226 | rv.Instruction = LineInstruction.Registers; 227 | break; 228 | case ".line": 229 | rv.Instruction = LineInstruction.Line; 230 | break; 231 | case ".end": 232 | switch (sRawText) 233 | { 234 | case ".end method": 235 | rv.Instruction = LineInstruction.EndMethod; 236 | break; 237 | } 238 | break; 239 | case ".param": 240 | rv.Instruction = LineInstruction.Parameter; 241 | sWords[1] = sWords[1].Replace(",", ""); 242 | rv.lRegisters[sWords[1].Trim()] = String.Empty; 243 | rv.aName = sRawText.Substring(sRawText.IndexOf('"') + 1); 244 | rv.aName = rv.aName.Substring(0, rv.aName.IndexOf('"')); 245 | rv.aType = sRawText.Substring(sRawText.IndexOf('#') + 1).Trim(); 246 | break; 247 | default: 248 | return false; 249 | } 250 | return true; 251 | } 252 | 253 | public static void SetModifiers(SmaliLine l, ref String[] ar, int start, int end) 254 | { 255 | for (int i = start; i < end; i++) 256 | if (Keywords.Contains(ar[i].ToLowerInvariant().Trim())) 257 | { 258 | if (!ParseNonAccess(l, ar[i].ToLowerInvariant().Trim())) 259 | if (!ParseAccess(l, ar[i].ToLowerInvariant().Trim())) 260 | ParseModifier(l, ar[i].ToLowerInvariant().Trim()); 261 | ar[i] = String.Empty; 262 | } 263 | } 264 | public static bool ParseNonAccess(SmaliLine l, String s) 265 | { 266 | switch (s) 267 | { 268 | case "static": 269 | l.NonAccessModifiers |= ENonAccessMod.Static; 270 | break; 271 | case "final": 272 | l.NonAccessModifiers |= ENonAccessMod.Final; 273 | break; 274 | case "abstract": 275 | l.NonAccessModifiers |= ENonAccessMod.Abstract; 276 | break; 277 | case "synchronized": 278 | l.NonAccessModifiers |= ENonAccessMod.Synchronized; 279 | break; 280 | case "volatile": 281 | l.NonAccessModifiers |= ENonAccessMod.Volatile; 282 | break; 283 | default: 284 | return false; 285 | } 286 | return true; 287 | } 288 | public static bool ParseAccess(SmaliLine l, String s) 289 | { 290 | switch (s) 291 | { 292 | case "public": 293 | l.AccessModifiers |= EAccessMod.Public; 294 | break; 295 | case "private": 296 | l.AccessModifiers |= EAccessMod.Private; 297 | break; 298 | case "protected": 299 | l.AccessModifiers |= EAccessMod.Protected; 300 | break; 301 | default: 302 | return false; 303 | } 304 | return true; 305 | } 306 | public static bool ParseModifier(SmaliLine l, String s) 307 | { 308 | switch (s) 309 | { 310 | case "constructor": 311 | l.IsConstructor = true; 312 | break; 313 | default: 314 | return false; 315 | } 316 | return true; 317 | } 318 | #endregion 319 | #region Instruction Parsing 320 | 321 | public static bool ParseAsInstruction(SmaliLine rv, String sInst, ref String[] sWords, ref String sRawText) 322 | { 323 | switch (sInst) 324 | { 325 | case "const": 326 | rv.Smali = LineSmali.Const; 327 | sWords[1] = sWords[1].Replace(",", ""); 328 | rv.lRegisters[sWords[1]] = String.Empty; 329 | rv.aValue = sWords[2]; 330 | break; 331 | case "const/16": 332 | rv.Smali = LineSmali.Const16; 333 | sWords[1] = sWords[1].Replace(",", ""); 334 | rv.lRegisters[sWords[1]] = String.Empty; 335 | rv.aValue = sWords[2]; 336 | break; 337 | case "const/high16": 338 | rv.Smali = LineSmali.ConstHigh16; 339 | sWords[1] = sWords[1].Replace(",", ""); 340 | rv.lRegisters[sWords[1]] = String.Empty; 341 | rv.aValue = sWords[2]; 342 | break; 343 | case "const/4": 344 | rv.Smali = LineSmali.Const4; 345 | sWords[1] = sWords[1].Replace(",", ""); 346 | rv.lRegisters[sWords[1]] = String.Empty; 347 | rv.aValue = sWords[2]; 348 | break; 349 | case "const-string": 350 | rv.Smali = LineSmali.ConstString; 351 | sWords[1] = sWords[1].Replace(",", ""); 352 | rv.lRegisters[sWords[1]] = String.Empty; 353 | rv.aValue = sRawText; 354 | break; 355 | case "invoke-static": 356 | rv.Smali = LineSmali.InvokeStatic; 357 | rv.aName = sWords[sWords.Length - 1]; 358 | sWords[sWords.Length - 1] = String.Empty; 359 | String sp = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); 360 | if (sp.EndsWith(",")) 361 | sp = sp.Substring(0, sp.Length - 1); 362 | ParseParameters(rv, sp); 363 | rv.lRegisters[rv.lRegisters.Keys.First()] = rv.aName; 364 | break; 365 | case "invoke-direct": 366 | rv.Smali = LineSmali.InvokeDirect; 367 | if (sWords[1].EndsWith(",")) 368 | sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); 369 | ParseParameters(rv, sWords[1]); 370 | rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; 371 | rv.aName = sWords[sWords.Length - 1]; 372 | break; 373 | case "move-result-object": 374 | rv.Smali = LineSmali.MoveResultObject; 375 | rv.lRegisters[sWords[1]] = String.Empty; 376 | break; 377 | case "move-result": 378 | rv.Smali = LineSmali.MoveResult; 379 | rv.lRegisters[sWords[1]] = String.Empty; 380 | break; 381 | case "return": 382 | case "return-object": 383 | rv.Smali = LineSmali.Return; 384 | if (sWords[1].EndsWith(",")) 385 | sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); 386 | ParseParameters(rv, sWords[1]); 387 | rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[1]; 388 | break; 389 | case "return-void": 390 | rv.Smali = LineSmali.ReturnVoid; 391 | break; 392 | case "sget-object": 393 | rv.Smali = LineSmali.SgetObject; 394 | if (sWords[1].EndsWith(",")) 395 | sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); 396 | ParseParameters(rv, sWords[1]); 397 | rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; 398 | break; 399 | case "sput-object": 400 | rv.Smali = LineSmali.SputObject; 401 | if (sWords[1].EndsWith(",")) 402 | sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); 403 | ParseParameters(rv, sWords[1]); 404 | rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; 405 | break; 406 | case "new-instance": 407 | rv.Smali = LineSmali.NewInstance; 408 | if (sWords[1].EndsWith(",")) 409 | sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); 410 | ParseParameters(rv, sWords[1]); 411 | rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; 412 | break; 413 | case "iput-object": 414 | rv.Smali = LineSmali.IputObject; 415 | rv.aValue = sWords[sWords.Length - 1]; 416 | sWords[sWords.Length - 1] = String.Empty; 417 | sp = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); 418 | if (sp.EndsWith(",")) 419 | sp = sp.Substring(0, sp.Length - 1); 420 | ParseParameters(rv, sp); 421 | break; 422 | case "iput-boolean": 423 | rv.Smali = LineSmali.IputBoolean; 424 | if (sWords[1].EndsWith(",")) 425 | sWords[1] = sWords[1].Substring(0, sWords[1].Length - 1); 426 | ParseParameters(rv, sWords[1]); 427 | rv.lRegisters[rv.lRegisters.Keys.First()] = sWords[2]; 428 | rv.aName = sWords[ sWords.Length - 1]; //Always the last entry. 429 | break; 430 | case "invoke-virtual": 431 | rv.Smali = LineSmali.InvokeVirtual; 432 | rv.aName = sWords[sWords.Length - 1]; 433 | sWords[sWords.Length - 1] = String.Empty; 434 | sp = String.Join(" ", sWords.Where(x => !String.IsNullOrEmpty(x)).ToArray()).Trim(); 435 | if (sp.EndsWith(",")) 436 | sp = sp.Substring(0, sp.Length - 1); 437 | ParseParameters(rv, sp); 438 | rv.lRegisters[rv.lRegisters.Keys.First()] = rv.aName; 439 | break; 440 | 441 | #region Unimplemented Functions 442 | 443 | case "add-double": 444 | case "add-double/2addr": 445 | case "add-float": 446 | case "add-float/2addr": 447 | case "add-int": 448 | case "add-int/2addr": 449 | case "add-int/lit16": 450 | case "add-int/lit8": 451 | case "add-long": 452 | case "add-long/2addr": 453 | case "aget": 454 | case "aget-boolean": 455 | case "aget-byte": 456 | case "aget-char": 457 | case "aget-object": 458 | case "aget-short": 459 | case "aget-wide": 460 | case "and-int": 461 | case "and-int/2addr": 462 | case "and-int/lit16": 463 | case "and-int/lit8": 464 | case "and-long": 465 | case "and-long/2addr": 466 | case "aput": 467 | case "aput-boolean": 468 | case "aput-byte": 469 | case "aput-char": 470 | case "aput-object": 471 | case "aput-short": 472 | case "aput-wide": 473 | case "array-length": 474 | case "check-cast": 475 | case "cmpg-double": 476 | case "cmpg-float": 477 | case "cmpl-double": 478 | case "cmpl-float": 479 | case "cmp-long": 480 | case "const-class": 481 | case "const-string/jumbo": 482 | case "const-wide": 483 | case "const-wide/16": 484 | case "const-wide/32": 485 | case "const-wide/high16": 486 | case "div-double": 487 | case "div-float": 488 | case "div-float/2addr": 489 | case "div-int": 490 | case "div-int/2addr": 491 | case "div-int/lit16": 492 | case "div-int/lit8": 493 | case "div-long": 494 | case "div-long/2addr": 495 | case "double-to-int": 496 | case "double-to-long": 497 | case "execute-inline": 498 | case "execute-inline/range": 499 | case "fill-array-data": 500 | case "filled-new-array": 501 | case "filled-new-array/range": 502 | case "float-to-double": 503 | case "float-to-int": 504 | case "float-to-long": 505 | case "iget": 506 | case "iget-boolean": 507 | case "iget-byte": 508 | case "iget-char": 509 | case "iget-object": 510 | case "iget-object-quick": 511 | case "iget-object-volatile": 512 | case "iget-quick": 513 | case "iget-short": 514 | case "iget-volatile": 515 | case "iget-wide": 516 | case "iget-wide-quick": 517 | case "iget-wide-volatile": 518 | case "instance-of": 519 | case "int-to-double": 520 | case "int-to-float": 521 | case "int-to-long": 522 | case "invoke-direct/range": 523 | case "invoke-direct-empty": 524 | case "invoke-interface": 525 | case "invoke-interface/range": 526 | case "invoke-object-init/range": 527 | case "invoke-static/range": 528 | case "invoke-super": 529 | case "invoke-super/range": 530 | case "invoke-super-quick": 531 | case "invoke-super-quick/range": 532 | case "invoke-virtual/range": 533 | case "invoke-virtual-quick": 534 | case "invoke-virtual-quick/range": 535 | case "iput": 536 | case "iput-byte": 537 | case "iput-char": 538 | case "iput-object-quick": 539 | case "iput-object-volatile": 540 | case "iput-quick": 541 | case "iput-short": 542 | case "iput-volatile": 543 | case "iput-wide": 544 | case "iput-wide-quick": 545 | case "iput-wide-volatile": 546 | case "long-to-double": 547 | case "long-to-float": 548 | case "long-to-int": 549 | case "move": 550 | case "move/16": 551 | case "move/from16": 552 | case "move-exception": 553 | case "move-object": 554 | case "move-object/16": 555 | case "move-object/from16": 556 | case "move-result-wide": 557 | case "move-wide": 558 | case "move-wide/16": 559 | case "move-wide/from16": 560 | case "mul-double": 561 | case "mul-float": 562 | case "mul-float/2addr": 563 | case "mul-int": 564 | case "mul-int/2addr": 565 | case "mul-int/lit16": 566 | case "mul-int/lit8": 567 | case "mul-long": 568 | case "mul-long/2addr": 569 | case "neg-double": 570 | case "neg-float": 571 | case "neg-int": 572 | case "neg-long": 573 | case "new-array": 574 | case "nop": 575 | case "not-int": 576 | case "not-long": 577 | case "or-int": 578 | case "or-int/2addr": 579 | case "or-int/lit16": 580 | case "or-long": 581 | case "or-long/2addr": 582 | case "packed-switch": 583 | case "rem-float": 584 | case "rem-float/2addr": 585 | case "rem-int": 586 | case "rem-int/2addr": 587 | case "rem-int/lit16": 588 | case "rem-int/lit8": 589 | case "rem-long": 590 | case "rem-long/2addr": 591 | case "return-void-barrier": 592 | case "return-wide": 593 | case "rsub-int": 594 | case "rsub-int/lit8": 595 | case "sget": 596 | case "sget-boolean": 597 | case "sget-byte": 598 | case "sget-char": 599 | case "sget-object-volatile": 600 | case "sget-short": 601 | case "sget-volatile": 602 | case "sget-wide": 603 | case "sget-wide-volatile": 604 | case "shl-int": 605 | case "shl-int/2addr": 606 | case "shl-long": 607 | case "shl-long/2addr": 608 | case "shr-int": 609 | case "shr-int/2addr": 610 | case "shr-long": 611 | case "shr-long/2addr": 612 | case "sparse-switch": 613 | case "sput": 614 | case "sput-boolean": 615 | case "sput-byte": 616 | case "sput-char": 617 | case "sput-object-volatile": 618 | case "sput-short": 619 | case "sput-volatile": 620 | case "sput-wide": 621 | case "sput-wide-volatile": 622 | case "sub-double": 623 | case "sub-float": 624 | case "sub-float/2addr": 625 | case "sub-int": 626 | case "sub-int/2addr": 627 | case "sub-long": 628 | case "sub-long/2addr": 629 | case "throw-verification-error": 630 | case "ushr-int": 631 | case "ushr-int/2addr": 632 | case "ushr-long": 633 | case "ushr-long/2addr": 634 | case "xor-int": 635 | case "xor-int/2addr": 636 | case "xor-long": 637 | case "xor-long/2addr": 638 | rv.Smali = LineSmali.Unimplemented; 639 | rv.aName = sRawText; 640 | break; 641 | case "goto": 642 | case "goto/16": 643 | case "goto/32": 644 | case "if-eq": 645 | case "if-eqz": 646 | case "if-ge": 647 | case "if-gez": 648 | case "if-gt": 649 | case "if-gtz": 650 | case "if-le": 651 | case "if-lez": 652 | case "if-lt": 653 | case "if-ltz": 654 | case "if-ne": 655 | case "if-nez": 656 | rv.Smali = LineSmali.Conditional; 657 | rv.aName = sRawText; 658 | break; 659 | default: 660 | rv.Smali = LineSmali.Unknown; 661 | rv.aName = sRawText; 662 | break; 663 | #endregion 664 | } 665 | return true; 666 | } 667 | 668 | public static void ParseParameters(SmaliLine rv, String s) 669 | { 670 | if (s.EndsWith(",")) 671 | s = s.Substring(0, s.Length - 1); 672 | 673 | if (s.Contains('{')) 674 | s = s.Substring(1, s.Length - 2); 675 | 676 | if(s.Contains(',')) 677 | { 678 | String[] sp = s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 679 | foreach (String p in sp) 680 | rv.lRegisters[p.Trim()] = String.Empty; 681 | } 682 | else 683 | rv.lRegisters[s] = String.Empty; 684 | } 685 | 686 | #endregion 687 | 688 | } 689 | } 690 | -------------------------------------------------------------------------------- /smali2java/Smali/SmaliMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java 7 | { 8 | public class SmaliMethod 9 | { 10 | [Flags] 11 | public enum EMethodFlags 12 | { 13 | p0IsSelf = 4 14 | } 15 | 16 | public List JavaOutput = new List(); 17 | public List Lines = new List(); 18 | 19 | //We can use this to generate variable names. 20 | public Dictionary varCount = new Dictionary(); 21 | 22 | public SmaliClass ParentClass; 23 | public SmaliLine.EAccessMod AccessModifiers; 24 | public SmaliLine.ENonAccessMod NonAccessModifiers; 25 | public EMethodFlags MethodFlags = 0; 26 | public SmaliCall MethodCall; 27 | 28 | public bool bIsFirstParam = true; 29 | public bool bHasParameters= true; 30 | public bool bHasPrologue = true; 31 | 32 | public int IncrementTypeCount(SmaliLine.LineReturnType type) 33 | { 34 | if (varCount.ContainsKey(type)) 35 | return varCount[type]++; 36 | else 37 | return varCount[type] = 1; 38 | } 39 | public int GetTypeCount(SmaliLine.LineReturnType type) 40 | { 41 | if (varCount.ContainsKey(type)) 42 | return varCount[type]; 43 | else 44 | return varCount[type] = 0; 45 | } 46 | public void Process() 47 | { 48 | bHasPrologue = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Prologue).Count() > 0; 49 | bHasParameters = Lines.Where(x => x.Instruction == SmaliLine.LineInstruction.Parameter).Count() > 0; 50 | for (int i = 0; i < Lines.Count; i++) 51 | { 52 | SmaliLine l = Lines[i]; 53 | if (l.bIsDirective) 54 | SmaliEngine.VM.ProcessDirective(this, l); 55 | else 56 | SmaliEngine.VM.ProcessInstruction(this, l); 57 | 58 | if (!String.IsNullOrEmpty(SmaliEngine.VM.Java)) 59 | { 60 | JavaOutput.Add(SmaliEngine.VM.Java); 61 | SmaliEngine.VM.Java = String.Empty; 62 | } 63 | } 64 | } 65 | 66 | public String ToJava() 67 | { 68 | return (String.Join("\n", JavaOutput.ToArray()) + "\n"); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /smali2java/Smali/SmaliParameter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java 7 | { 8 | public class SmaliParameter 9 | { 10 | public String Register; 11 | public String Name; 12 | public String Type; 13 | public String Value; 14 | 15 | public String ToJava() 16 | { 17 | return SmaliUtils.General.Name2Java(SmaliUtils.General.ReturnType2Java(SmaliUtils.General.GetReturnType(Type), Type)).Replace(";", "").TrimEnd() + " " + Name; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /smali2java/Smali/SmaliUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java 7 | { 8 | public static class SmaliUtils 9 | { 10 | public static class General 11 | { 12 | public static String Eat(ref String s, String until, bool addLength = false) 13 | { 14 | String rv = s.Substring(0, s.IndexOf(until)); 15 | s = s.Substring(rv.Length + (addLength ? until.Length : 0)); 16 | return rv; 17 | } 18 | 19 | public static String Eat(ref String s, char until, bool addLength = false) 20 | { 21 | String rv = s.Substring(0, s.IndexOf(until)); 22 | s = s.Substring(rv.Length + (addLength ? 1 : 0)); 23 | return rv; 24 | } 25 | 26 | public static String Name2Java(String smaliName) 27 | { 28 | if (smaliName.StartsWith("L")) 29 | smaliName = smaliName.Substring(1); 30 | if (smaliName.EndsWith(";")) 31 | smaliName = smaliName.Remove(smaliName.Length - 1, 1); 32 | smaliName = smaliName.Replace("/", "."); 33 | return smaliName; 34 | } 35 | 36 | public static String Modifiers2Java(SmaliLine.EAccessMod eAccessMod, SmaliLine.ENonAccessMod eNonAccessMod) 37 | { 38 | return String.Join(" ", new String[] { eAccessMod == 0 ? "" : eAccessMod.ToString().ToLowerInvariant().Replace(",", ""), eNonAccessMod == 0 ? "" : eNonAccessMod.ToString().ToLowerInvariant().Replace(",", "") }); 39 | } 40 | 41 | public static String ReturnType2Java(SmaliLine.LineReturnType rt, String customType) 42 | { 43 | if (rt.ToString().EndsWith("Array")) 44 | { 45 | if (rt == SmaliLine.LineReturnType.CustomArray) 46 | { 47 | if (customType != "") 48 | return customType.Substring(1) + "[] "; 49 | else 50 | return customType.Substring(1) + "[]"; 51 | } 52 | else 53 | return Name2Java(rt.ToString().Replace("Array","").ToLowerInvariant().Trim()) + "[] "; 54 | } 55 | else 56 | { 57 | if (rt == SmaliLine.LineReturnType.Custom) 58 | { 59 | if (customType != "") 60 | return customType + ' '; 61 | else 62 | return customType; 63 | } 64 | else 65 | return Name2Java(rt.ToString().ToLowerInvariant().Trim()) + ' '; 66 | } 67 | } 68 | 69 | public static SmaliLine.LineReturnType GetReturnType(String s) 70 | { 71 | String rt = s.ToLowerInvariant().Trim(); 72 | if (rt.StartsWith("[")) // This is an array 73 | { 74 | rt = rt.Substring(1); 75 | switch (rt) 76 | { 77 | case "v": 78 | return SmaliLine.LineReturnType.VoidArray; 79 | case "i": 80 | return SmaliLine.LineReturnType.IntArray; 81 | case "z": 82 | return SmaliLine.LineReturnType.BooleanArray; 83 | case "b": 84 | return SmaliLine.LineReturnType.ByteArray; 85 | case "s": 86 | return SmaliLine.LineReturnType.ShortArray; 87 | case "c": 88 | return SmaliLine.LineReturnType.CharArray; 89 | case "j": 90 | return SmaliLine.LineReturnType.LongArray; 91 | case "d": 92 | return SmaliLine.LineReturnType.DoubleArray; 93 | default: 94 | return SmaliLine.LineReturnType.CustomArray; 95 | } 96 | } 97 | switch(rt) 98 | { 99 | case "v": 100 | return SmaliLine.LineReturnType.Void; 101 | case "i": 102 | return SmaliLine.LineReturnType.Int; 103 | case "z": 104 | return SmaliLine.LineReturnType.Boolean; 105 | case "b": 106 | return SmaliLine.LineReturnType.Byte; 107 | case "s": 108 | return SmaliLine.LineReturnType.Short; 109 | case "c": 110 | return SmaliLine.LineReturnType.Char; 111 | case "j": 112 | return SmaliLine.LineReturnType.Long; 113 | case "d": 114 | return SmaliLine.LineReturnType.Double; 115 | default: 116 | return SmaliLine.LineReturnType.Custom; 117 | } 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /smali2java/Smali/SmaliVM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Smali2Java 7 | { 8 | public class SmaliVM 9 | { 10 | #region VM Stack (variable holder) 11 | public Dictionary vmStack = new Dictionary(); 12 | 13 | public void PutLastCall(SmaliCall value) 14 | { 15 | vmStack["lastCall"] = value; 16 | } 17 | 18 | public SmaliCall GetLastCall() 19 | { 20 | object result = null; 21 | vmStack.TryGetValue("lastCall", out result); 22 | return result as SmaliCall; 23 | } 24 | 25 | public void PutLastRegisters(Dictionary value) 26 | { 27 | vmStack["lastRegisters"] = value; 28 | } 29 | 30 | public Dictionary GetLastRegisters() 31 | { 32 | object result = null; 33 | vmStack.TryGetValue("lastRegisters", out result); 34 | return result as Dictionary; 35 | } 36 | 37 | public void Put(String register, String value) 38 | { 39 | vmStack[register] = value; 40 | } 41 | 42 | public String Get(String register) 43 | { 44 | return vmStack[register].ToString(); 45 | } 46 | #endregion 47 | 48 | public Directives smaliDirectives = new Directives(); 49 | public Instructions smaliInstructions = new Instructions(); 50 | public String Java; 51 | public StringBuilder Buf = new StringBuilder(); 52 | public void FlushBuffer() 53 | { 54 | Java = Buf.ToString(); 55 | Buf = new StringBuilder(""); 56 | } 57 | 58 | public int _idxParam = 0; 59 | 60 | public void ProcessDirective(SmaliMethod m, SmaliLine l) 61 | { 62 | smaliDirectives.m = m; 63 | smaliDirectives.l = l; 64 | switch (l.Instruction) 65 | { 66 | case SmaliLine.LineInstruction.Method: 67 | smaliDirectives.Method(); 68 | if (!m.bHasParameters) 69 | { 70 | smaliDirectives.Special_NoParameters(); 71 | if (!m.bHasPrologue) 72 | smaliDirectives.Prologue(); 73 | } 74 | break; 75 | case SmaliLine.LineInstruction.Parameter: 76 | smaliDirectives.Parameter(); 77 | break; 78 | case SmaliLine.LineInstruction.Prologue: 79 | smaliDirectives.Prologue(); 80 | break; 81 | case SmaliLine.LineInstruction.Line: 82 | smaliDirectives.Line(); 83 | break; 84 | case SmaliLine.LineInstruction.EndMethod: 85 | smaliDirectives.EndMethod(); 86 | break; 87 | } 88 | } 89 | 90 | public void ProcessInstruction(SmaliMethod m, SmaliLine l) 91 | { 92 | smaliInstructions.m = m; 93 | smaliInstructions.l = l; 94 | switch (l.Smali) 95 | { 96 | case SmaliLine.LineSmali.Const4: 97 | case SmaliLine.LineSmali.Const: 98 | case SmaliLine.LineSmali.Const16: 99 | case SmaliLine.LineSmali.ConstHigh16: //TODO: these may end up needing seperate instruction handlers. 100 | case SmaliLine.LineSmali.ConstString: 101 | smaliInstructions.Const(); 102 | break; 103 | case SmaliLine.LineSmali.SputObject: 104 | smaliInstructions.SputObject(); 105 | break; 106 | case SmaliLine.LineSmali.Return: 107 | case SmaliLine.LineSmali.ReturnVoid: 108 | smaliInstructions.Return(); 109 | break; 110 | case SmaliLine.LineSmali.SgetObject: 111 | smaliInstructions.SgetObject(); 112 | break; 113 | case SmaliLine.LineSmali.NewInstance: 114 | smaliInstructions.NewInstance(); 115 | break; 116 | case SmaliLine.LineSmali.InvokeVirtual: 117 | case SmaliLine.LineSmali.InvokeStatic: 118 | case SmaliLine.LineSmali.InvokeDirect: //TODO: These may need to be on their own functions, but for now the are all identical in implementation... 119 | smaliInstructions.Invoke(); 120 | break; 121 | case SmaliLine.LineSmali.IputBoolean: 122 | smaliInstructions.IputBoolean(); 123 | break; 124 | case SmaliLine.LineSmali.MoveResult: 125 | case SmaliLine.LineSmali.MoveResultObject: 126 | smaliInstructions.MoveResult(); 127 | break; 128 | case SmaliLine.LineSmali.Unimplemented: //These will cover most of the instructions right now... 129 | case SmaliLine.LineSmali.Unknown: 130 | case SmaliLine.LineSmali.Conditional: 131 | case SmaliLine.LineSmali.Label: 132 | smaliInstructions.Unimplemented(); 133 | break; 134 | } 135 | } 136 | 137 | public class Directives 138 | { 139 | public SmaliMethod m; 140 | public SmaliLine l; 141 | 142 | public void Method() 143 | { 144 | m.AccessModifiers = l.AccessModifiers; 145 | m.NonAccessModifiers = l.NonAccessModifiers; 146 | m.MethodCall = SmaliCall.Parse(l.aExtra); 147 | SmaliEngine.VM._idxParam = 0; 148 | } 149 | 150 | public void Special_NoParameters() 151 | { 152 | m.bIsFirstParam = false; 153 | m.MethodFlags |= SmaliMethod.EMethodFlags.p0IsSelf; 154 | m.MethodCall.Parameters.Insert(0, new SmaliParameter() 155 | { 156 | Name = "this", 157 | Register = "p0", 158 | Type = m.ParentClass.ClassName 159 | }); 160 | SmaliEngine.VM._idxParam = 1; 161 | for (; SmaliEngine.VM._idxParam < m.MethodCall.Parameters.Count; SmaliEngine.VM._idxParam++) 162 | { 163 | m.MethodCall.Parameters[SmaliEngine.VM._idxParam].Name = 164 | m.MethodCall.Parameters[SmaliEngine.VM._idxParam].Register = "p" + SmaliEngine.VM._idxParam; 165 | SmaliEngine.VM.Put(m.MethodCall.Parameters[SmaliEngine.VM._idxParam].Register, m.MethodCall.Parameters[SmaliEngine.VM._idxParam].Name); 166 | } 167 | } 168 | 169 | public void Parameter() 170 | { 171 | if (l.lRegisters.Keys.First() != "p0" && m.bIsFirstParam) 172 | { 173 | m.bIsFirstParam = false; 174 | m.MethodFlags |= SmaliMethod.EMethodFlags.p0IsSelf; 175 | m.MethodCall.Parameters.Insert(0, new SmaliParameter() 176 | { 177 | Name = "this", 178 | Register = "p0", 179 | Type = m.ParentClass.ClassName 180 | }); 181 | SmaliEngine.VM._idxParam = 1; 182 | } 183 | 184 | l.aName = char.ToUpper(l.aName[0]) + l.aName.Substring(1); 185 | 186 | // TODO: Check if this algorithm is right? 187 | m.MethodCall.Parameters[SmaliEngine.VM._idxParam].Name = "param" + l.aName; 188 | m.MethodCall.Parameters[SmaliEngine.VM._idxParam].Register = l.lRegisters.Keys.First(); 189 | SmaliEngine.VM.Put(m.MethodCall.Parameters[SmaliEngine.VM._idxParam].Register, m.MethodCall.Parameters[SmaliEngine.VM._idxParam].Name); 190 | SmaliEngine.VM._idxParam++; 191 | } 192 | 193 | public void Prologue() 194 | { 195 | // TODO: Create extension method HasFlag because .NET 3.5 doesn't have it? 196 | if((m.MethodCall.CallFlags & SmaliCall.ECallFlags.Constructor) == SmaliCall.ECallFlags.Constructor) 197 | m.MethodCall.Method = m.ParentClass.ClassName.Replace(";", ""); 198 | 199 | SmaliEngine.VM.Buf.AppendFormat("{0} {1}{2}", 200 | SmaliUtils.General.Modifiers2Java(m.AccessModifiers, m.NonAccessModifiers), 201 | SmaliUtils.General.ReturnType2Java(m.MethodCall.SmaliReturnType, m.MethodCall.Return), 202 | m.MethodCall.Method 203 | ); 204 | 205 | if (((m.MethodCall.CallFlags & SmaliCall.ECallFlags.ClassInit) == SmaliCall.ECallFlags.ClassInit) == false) 206 | SmaliEngine.VM.Buf.Append(" ("); 207 | 208 | if (m.MethodCall.Parameters.Count > 0) 209 | { 210 | // Let's save a couple of cycles and only calculate this once in this if block. 211 | bool p0isSelf = (m.MethodFlags & SmaliMethod.EMethodFlags.p0IsSelf) == SmaliMethod.EMethodFlags.p0IsSelf; 212 | 213 | for (int j = p0isSelf ? 1 : 0; j < m.MethodCall.Parameters.Count; j++) 214 | SmaliEngine.VM.Buf.Append(m.MethodCall.Parameters[j].ToJava() + ", "); 215 | 216 | // Only remove things from the buffer if we printed any args to remove. 217 | if (m.MethodCall.Parameters.Count > (p0isSelf ? 1 : 0) ) 218 | SmaliEngine.VM.Buf.Remove(SmaliEngine.VM.Buf.Length - 2, 2); 219 | 220 | if (p0isSelf) 221 | SmaliEngine.VM.Put("p0", "this"); 222 | } 223 | 224 | if (((m.MethodCall.CallFlags & SmaliCall.ECallFlags.ClassInit) == SmaliCall.ECallFlags.ClassInit) == false) 225 | SmaliEngine.VM.Buf.Append(") "); 226 | 227 | SmaliEngine.VM.Buf.Append("{"); 228 | SmaliEngine.VM.FlushBuffer(); 229 | } 230 | 231 | public void Line() 232 | { 233 | SmaliEngine.VM.FlushBuffer(); 234 | } 235 | 236 | public void EndMethod() 237 | { 238 | SmaliEngine.VM.Buf.Append("}"); 239 | SmaliEngine.VM.FlushBuffer(); 240 | } 241 | } 242 | public class Instructions 243 | { 244 | public SmaliMethod m; 245 | public SmaliLine l; 246 | 247 | public void Const() 248 | { 249 | if (Program.Debug) 250 | { 251 | SmaliEngine.VM.Buf.AppendFormat("\\\\{0} = {1};\n\n", 252 | l.lRegisters.Keys.First(), 253 | l.aValue 254 | ); 255 | } 256 | SmaliEngine.VM.Put(l.lRegisters.Keys.First(), l.aValue); 257 | //TODO: Figure out when these should be variable assignments, and when they should be constants... 258 | //Perhaps we can start from the return value, and work our way back from there, as well as looking at which methods are getting called by these. 259 | } 260 | 261 | public void SputObject() 262 | { 263 | String sReg = l.lRegisters.Keys.First(); 264 | 265 | // SKIP! TODO: Should not skip, actually. If it skips, something IS wrong 266 | if (!SmaliEngine.VM.vmStack.ContainsKey(sReg)) 267 | { 268 | Unimplemented(); 269 | return; 270 | } 271 | 272 | String sSrcValue = SmaliEngine.VM.Get(sReg); 273 | String sDstValue = l.lRegisters[sReg]; 274 | 275 | Dictionary args = new Dictionary(); 276 | args[sReg] = sSrcValue; 277 | 278 | SmaliCall c = SmaliCall.Parse(sDstValue); 279 | 280 | SmaliEngine.VM.Buf = new StringBuilder(); 281 | 282 | SmaliEngine.VM.Buf.AppendFormat("{0}{1}{2} = {3};\n", 283 | c.Variable, 284 | m.ParentClass.PackageName == c.ClassName ? "" : (c.ClassName + "."), 285 | m.ParentClass.ClassName == c.Method ? "" : (c.Method + "."), 286 | sSrcValue 287 | ); 288 | } 289 | 290 | public void SgetObject() 291 | { 292 | String sReg = l.lRegisters.Keys.First(); 293 | String sSrcValue = l.lRegisters[sReg]; 294 | String sDstValue = sReg; 295 | SmaliCall c = SmaliCall.Parse(sSrcValue); 296 | string prepend = String.Empty; 297 | if (m.ParentClass.PackageName == c.ClassName && m.ParentClass.ClassName == c.Method) 298 | prepend = "this."; 299 | else // I don't think sget-object should ever hit this? 300 | prepend = SmaliUtils.General.Name2Java(c.ClassName) + '.' + c.Method + '.'; 301 | SmaliEngine.VM.Put(sDstValue, prepend + c.Variable); 302 | } 303 | 304 | public void IputBoolean() 305 | { 306 | String sReg = l.lRegisters.Keys.First(); 307 | 308 | // SKIP! TODO: Should not skip, actually. If it skips, something IS wrong 309 | if (!SmaliEngine.VM.vmStack.ContainsKey(sReg)) 310 | { 311 | Unimplemented(); 312 | return; 313 | } 314 | 315 | String sSrcValue = SmaliEngine.VM.Get(sReg); 316 | String sDstValue = l.aName; 317 | 318 | Dictionary args = new Dictionary(); 319 | args[sReg] = sSrcValue; 320 | 321 | SmaliCall c = SmaliCall.Parse(sDstValue); 322 | 323 | SmaliEngine.VM.Buf = new StringBuilder(); 324 | 325 | SmaliEngine.VM.Buf.AppendFormat("{0}{1} = {2};\n", 326 | (m.ParentClass.PackageName == c.ClassName && m.ParentClass.ClassName == c.Method ? 327 | "this." : 328 | (SmaliUtils.General.Name2Java(c.ClassName) + "." + c.Method + ".")), 329 | c.Variable, 330 | (sSrcValue == "0x1" ? "true" : "false") 331 | ); 332 | 333 | //TODO: Well... todo. Lol. 334 | //Buffer.Append(ParseSmali(sDstValue, args)); 335 | } 336 | 337 | public void Return() 338 | { 339 | String sSrcValue = String.Empty; 340 | if (l.lRegisters.Count > 0) 341 | { 342 | String sReg = l.lRegisters.Keys.First(); 343 | 344 | // SKIP! TODO: Should not skip, actually. If it skips, something IS wrong 345 | if (!SmaliEngine.VM.vmStack.ContainsKey(sReg)) 346 | { 347 | Unimplemented(); 348 | return; 349 | } 350 | 351 | sSrcValue = ' ' + SmaliEngine.VM.Get(sReg); 352 | } 353 | // We don't wipe the buffer here... there may not have been a .line before return... 354 | SmaliEngine.VM.Buf.AppendFormat("return{0};\n", 355 | sSrcValue 356 | ); 357 | } 358 | 359 | public void NewInstance() 360 | { 361 | SmaliCall c = SmaliCall.Parse(l.lRegisters[l.lRegisters.Keys.First()]); 362 | StringBuilder sb = new StringBuilder(); 363 | sb.Append("new " + SmaliUtils.General.Name2Java(c.ClassName)); 364 | sb.Append("." + c.Method + "()"); 365 | SmaliEngine.VM.Put(l.lRegisters.Keys.First(), sb.ToString()); 366 | } 367 | 368 | public void Invoke() //TODO: Move this out into more generic functions? 369 | { 370 | String sReg = l.lRegisters.Keys.First(); 371 | // SKIP! TODO: Should not skip, actually. If it skips, something IS wrong 372 | if (!SmaliEngine.VM.vmStack.ContainsKey(sReg)) 373 | { 374 | Unimplemented(); 375 | return; 376 | } 377 | 378 | SmaliCall c = SmaliCall.Parse(l.lRegisters[l.lRegisters.Keys.First()]); 379 | 380 | // It's a constructor, skip method name 381 | if ((c.CallFlags & SmaliCall.ECallFlags.Constructor) == SmaliCall.ECallFlags.Constructor) 382 | SmaliEngine.VM.Buf.Append(SmaliEngine.VM.Get(sReg)); 383 | else 384 | { 385 | string regs = null; 386 | try 387 | { 388 | regs = ParseRegistersAsArgs(l.lRegisters); 389 | } 390 | catch 391 | { 392 | Unimplemented(); 393 | return; 394 | } 395 | SmaliEngine.VM.Buf.AppendFormat("{0}({1});\n", 396 | (m.ParentClass.PackageName == c.ClassName && m.ParentClass.ClassName == c.Method ? 397 | "this." : 398 | (SmaliUtils.General.Name2Java(c.ClassName) + "." + c.Method)), 399 | regs 400 | ); //We add this to the buffer one way or another, it just gets cleared if the next instruction is MoveResult. 401 | //TODO: Maybe we should simply prepend the buffer with the variable for move result? 402 | // We are actually returning something here, put this as the value of the last instruction to be acted on by move-result. 403 | if (c.SmaliReturnType != SmaliLine.LineReturnType.Void) 404 | { 405 | SmaliEngine.VM.PutLastCall(c); 406 | SmaliEngine.VM.PutLastRegisters(l.lRegisters); 407 | } 408 | } 409 | } 410 | 411 | 412 | /* 413 | * TODO: Figure out when these should be variable assignments, and when they should be constants... 414 | * Right now we spam variables like there is no tomorrow. Can we really rely on "end locals"? 415 | * Maybe we can count the usages, if it is never again assigned to, or it changes type we don't make a variable, and instead nest the calls... 416 | */ 417 | public void MoveResult() //We *MIGHT* need to make a second one for objects... 418 | { 419 | SmaliEngine.VM.Buf = new StringBuilder(); // Clear the buffer We'll plug the instruction we are getting the result into in the buffer in case this never gets called, so now we need to clear it. 420 | String sReg = l.lRegisters.Keys.First(); 421 | SmaliCall cOld = SmaliEngine.VM.GetLastCall(); 422 | Dictionary registers = SmaliEngine.VM.GetLastRegisters(); 423 | if (cOld != null && registers != null) //SKIP, again something is wrong if we skip here. 424 | { 425 | SmaliEngine.VM.Put(sReg, cOld.SmaliReturnType.ToString() + m.IncrementTypeCount(cOld.SmaliReturnType)); //TODO: generate variable names programatically here. 426 | SmaliEngine.VM.PutLastCall(null); // Wipe so we don't accidentally get something we missed again. 427 | SmaliEngine.VM.PutLastRegisters(null); 428 | string regs = null; 429 | try 430 | { 431 | regs = ParseRegistersAsArgs(registers); 432 | } 433 | catch 434 | { 435 | Unimplemented(); 436 | return; 437 | } 438 | SmaliEngine.VM.Buf.AppendFormat("{0} = {1}({2});\n", 439 | SmaliUtils.General.Name2Java(SmaliUtils.General.ReturnType2Java(cOld.SmaliReturnType, cOld.Return)).Replace(";", String.Empty) + SmaliEngine.VM.Get(sReg), 440 | (m.ParentClass.PackageName == cOld.ClassName && m.ParentClass.ClassName == cOld.Method ? 441 | "this." : 442 | (SmaliUtils.General.Name2Java(cOld.ClassName) + "." + cOld.Method)), 443 | regs 444 | ); 445 | SmaliEngine.VM.FlushBuffer(); 446 | } 447 | } 448 | 449 | public void Unimplemented() 450 | { 451 | if (Program.Debug) 452 | SmaliEngine.VM.Buf.AppendFormat("\\*\n* Warning, {0} instruction was not processed: \n* {1}\n*\\\n", 453 | l.Smali, 454 | l.aName 455 | ); 456 | else // Log Verbose comments only if the debug flag is enabled. 457 | SmaliEngine.VM.Buf.AppendFormat("\\\\{0}\n", 458 | l.aName 459 | ); 460 | SmaliEngine.VM.FlushBuffer(); 461 | } 462 | 463 | private String ParseRegistersAsArgs(Dictionary registers) //TODO: This should be elsewhere. 464 | { 465 | string regs = String.Empty; 466 | bool hadOne = false; 467 | foreach (string s in registers.Keys) 468 | { 469 | string reg = SmaliEngine.VM.Get(s); 470 | if (reg != "this" || hadOne) 471 | { 472 | regs += (reg != "this" ? SmaliEngine.VM.Get(s) + ", " : String.Empty); 473 | if (!hadOne) 474 | hadOne = true; 475 | } 476 | } 477 | if (hadOne) 478 | regs = regs.Substring(0, regs.Length - 2); 479 | return regs; 480 | } 481 | } 482 | } 483 | } 484 | -------------------------------------------------------------------------------- /smali2java/Smali2Java-v3.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {35577FBA-BEF5-43FB-8B2D-E6D10F0F62C0} 8 | Exe 9 | Properties 10 | Smali2Java 11 | Smali2Java 12 | v3.5 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Always 62 | 63 | 64 | 65 | 66 | Always 67 | 68 | 69 | 70 | 77 | --------------------------------------------------------------------------------