/// <summary> /// Try to load a bitmap from file. /// Returns null when that was not possible. /// </summary> private static Image LoadBitmap(ApkFile apk, string fileName) { var data = apk.Load(fileName); if (data == null) return null; return Image.FromStream(new MemoryStream(data)); }
/// <summary> /// Load a resources table from the given apk. /// </summary> private static Table CreateResourcesArsc(ApkFile apkFile) { var data = (apkFile != null) ? apkFile.Load("resources.arsc") : null; if (data == null) return null; return new Table(new MemoryStream(data)); }
/// <summary> /// Default ctor /// </summary> public ApkRunner(IIde ide, string apkPath, string packageName, string activity, bool debuggable, int launchFlags) { this.ide = ide; this.apkPath = apkPath; this.packageName = packageName; this.activity = activity; this.debuggable = debuggable; this.launchFlags = launchFlags; cancellationTokenSource = new CancellationTokenSource(); outputPane = ide.CreateDot42OutputPane(); DeployApk = true; // Load package try { var apk = new ApkFile(apkPath); if (!apk.Manifest.TryGetMinSdkVersion(out minSdkVersion)) minSdkVersion = -1; } catch (Exception ex) { minSdkVersion = -1; ErrorLog.DumpError(ex); } }
/// <summary> /// Create an layout.xml parser for the data in the given framework folder. /// </summary> private static LayoutXmlParser CreateLayoutXmlParser(ApkFile apkFile) { var data = (apkFile != null) ? apkFile.Load("layout.xml") : null; if (data == null) return new LayoutXmlParser(null); return new LayoutXmlParser(new MemoryStream(data)); }
/// <summary> /// Create an attrs.xml parser for the data in the given framework folder. /// </summary> private static AttrsXmlParser CreateAttrXmlParser(ApkFile apkFile) { var data = (apkFile != null) ? apkFile.Load("attrs.xml") : null; if (data == null) return new AttrsXmlParser(null); return new AttrsXmlParser(new MemoryStream(data)); }
private SourceFile(ApkFile apk, JarFile jar, ISpySettings settings, MapFile mapFile, string singleFilePath = null) { this.apk = apk; this.jar = jar; this.settings = settings; this.mapFile = mapFile; this.singleFilePath = singleFilePath; #if DEBUG classLoader = new AssemblyClassLoader(module.OnClassLoaded); var modParams = new ModuleParameters { AssemblyResolver = new AssemblyResolver(new[] { Frameworks.Instance.FirstOrDefault().Folder }, classLoader, module.OnAssemblyLoaded), Kind = ModuleKind.Dll }; assembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition("spy", Version.Parse("1.0.0.0")), "main", modParams); classLoader.LoadAssembly(assembly); var dot42Assembly = modParams.AssemblyResolver.Resolve("dot42"); // Force loading of classes if (jar != null) { foreach (var fileName in jar.ClassFileNames) { OpenClass(fileName); } } #endif }
internal static byte[] GetIcon(string resourceId, ApkFile apk) { // Look for the files var iconFileNames = apk.FileNames.Where(x => MatchesWith(x, resourceId)).ToList(); // Load all variations var icons = iconFileNames.Select(x => LoadBitmap(apk, x)).Where(x => x != null).OrderByDescending(x => Math.Max(x.Width, x.Height)).ToList(); var icon = icons.FirstOrDefault(x => (x.Height <= MaxWidthHeight) && (x.Width <= MaxWidthHeight)); if (icon == null) return null; // Try scaling // Return icon var stream = new MemoryStream(); icon.Save(stream, ImageFormat.Png); return stream.ToArray(); }
private static void UninstallAPK(string path) { var pathSet = new HashSet<string>(); if (File.Exists(path)) { pathSet.Add(path); } else if (Directory.Exists(path)) { foreach (var file in Directory.EnumerateFiles(path, "*.apk", SearchOption.AllDirectories)) { pathSet.Add(file); } } try { var names = new HashSet<string>(); foreach (var iterator in pathSet) { var apk = new ApkFile(iterator); var name = apk.Manifest.PackageName; names.Add(name); } foreach (var name in names) { UninstallAPKByPackageName(name); } } catch (Exception ex) { Console.WriteLine("Failed to uninstall {0} because {1}", path, ex.Message); } }
/// <summary> /// Default ctor /// </summary> public MetaInfManifestBuilder(ApkFile apk, string author, string debugTokenPath, Dictionary<string, string> apkPath2barPath) { // Prepare var developmentMode = !string.IsNullOrEmpty(debugTokenPath); var debugToken = developmentMode ? new BarFile(debugTokenPath) : null; if (debugToken != null) { // Verify debug token if (!string.Equals(debugToken.Manifest.PackageType, "debug-token", StringComparison.OrdinalIgnoreCase)) throw new ArgumentException(string.Format("Debug token {0} has invalid package type", debugTokenPath)); if (string.IsNullOrEmpty(debugToken.Manifest.PackageAuthor)) throw new ArgumentException(string.Format("Debug token {0} has no package author", debugTokenPath)); if (string.IsNullOrEmpty(debugToken.Manifest.PackageAuthorId)) throw new ArgumentException(string.Format("Debug token {0} has no package author id", debugTokenPath)); } // Create manifest AppendLine("Archive-Manifest-Version: 1.1"); AppendLine("Created-By: dot42"); AppendLine(); var androidManifest = apk.Manifest; if (developmentMode) { AppendLine("Package-Author: " + debugToken.Manifest.PackageAuthor); AppendLine("Package-Author-Id: " + debugToken.Manifest.PackageAuthorId); } else { AppendLine("Package-Author: " + author); AppendLine("Package-Author-Id: " + FormatID(author)); } AppendLine("Package-Name: " + androidManifest.PackageName); AppendLine("Package-Id: " + FormatID(androidManifest.PackageName)); AppendLine("Package-Version: " + androidManifest.VersionName); AppendLine("Package-Version-Id: " + FormatID(androidManifest.VersionName)); AppendLine("Package-Type: application"); AppendLine(); AppendLine("Application-Name: " + androidManifest.ApplicationLabel); AppendLine("Application-Id: " + FormatID(androidManifest.ApplicationLabel)); AppendLine("Application-Version: " + androidManifest.VersionName); AppendLine("Application-Version-Id: " + FormatID(androidManifest.VersionName)); if (developmentMode) { AppendLine("Application-Development-Mode: true"); } AppendLine(); // Collect permissions var permissions = new HashSet<string> { "access_shared", "play_audio" }; foreach (var permission in androidManifest.UsesPermissions) { string bbPerm; var key = (permission.Name ?? string.Empty).ToUpperInvariant(); if (permissionMap.TryGetValue(key, out bbPerm)) permissions.Add(bbPerm); } var userActions = string.Join(",", permissions); var entryPoint = GetEntryPoint(androidManifest); if (entryPoint != null) { AppendLine("Entry-Point-Name: " + androidManifest.ApplicationLabel); AppendLine("Entry-Point-Type: Qnx/Android"); AppendLine("Entry-Point: " + string.Format("android://{0}?activity-name={1}", androidManifest.PackageName, entryPoint.Name)); if (!string.IsNullOrEmpty(userActions)) { AppendLine("Entry-Point-User-Actions: " + userActions); } var icon = entryPoint.Icon; if (string.IsNullOrEmpty(icon)) icon = androidManifest.ApplicationIcon; if (!string.IsNullOrEmpty(icon)) { string iconBarPath; if (apkPath2barPath.TryGetValue(icon, out iconBarPath)) { AppendLine("Entry-Point-Icon: " + iconBarPath); } } AppendLine(); } }
/// <summary> /// Compile the given XML file to a binary XML file in the given output folder. /// </summary> public void Build() { #if DEBUG //Debugger.Launch(); #endif // Prepare folder var outputFolder = Path.GetDirectoryName(path); if (!Directory.Exists(outputFolder)) Directory.CreateDirectory(outputFolder); // Sign bar? const bool sign = true; // Load APK var apk = new ApkFile(ApkPath); // Collect entries var entries = new List<BarEntry>(); var apkName = Path.GetFileNameWithoutExtension(path) + ".apk"; entries.Add(new BarEntry(string.Format(@"android\{0}", apkName), ApkPath)); // Collect icon's var apkPath2barPath = new Dictionary<string, string>(); CollectIcons(apk, entries, apkPath2barPath); // Build ZIP var manifest = new MetaInfManifestBuilder(apk, Author, DebugTokenPath, apkPath2barPath); // Build signatures if (sign) { foreach (var entry in entries) { manifest.AddArchiveAsset(entry.Name, entry.Data); //signature.AddSha1Digest(entry.Name, entry.Data); } } // Create zip ////string md5FingerPrint = null; ////string sha1FingerPrint = null; using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write)) { using (var zipStream = new ZipOutputStream(fileStream) {UseZip64 = UseZip64.Off}) { zipStream.SetLevel(9); zipStream.PutNextEntry(new ZipEntry("META-INF/MANIFEST.MF") { CompressionMethod = CompressionMethod.Deflated }); manifest.WriteTo(zipStream); zipStream.CloseEntry(); ////if (sign) ////{ //// zipStream.PutNextEntry(new ZipEntry("META-INF/LE-C0FC2.SF") //// {CompressionMethod = CompressionMethod.Deflated}); //// signature.WriteTo(zipStream); //// zipStream.CloseEntry(); //// zipStream.PutNextEntry(new ZipEntry("META-INF/LE-C0FC2.RSA") //// {CompressionMethod = CompressionMethod.Deflated}); //// rsa.WriteTo(zipStream, out md5FingerPrint, out sha1FingerPrint); //// zipStream.CloseEntry(); ////} foreach (var entry in entries) { var entryName = entry.Name.Replace('\\', '/'); zipStream.PutNextEntry(new ZipEntry(entryName) { CompressionMethod = GetCompressionMethod(entryName) }); entry.WriteTo(zipStream); zipStream.CloseEntry(); } } } #if NO_FINGERPRINT_YET // Save MD5 fingerprint var md5FingerPrintPath = Path.ChangeExtension(path, ".md5"); File.WriteAllText(md5FingerPrintPath, md5FingerPrint ?? string.Empty); // Save SHA1 fingerprint var sha1FingerPrintPath = Path.ChangeExtension(path, ".sha1"); File.WriteAllText(sha1FingerPrintPath, sha1FingerPrint ?? string.Empty); #endif #if DEBUG && NO_RSA_YET // Create RSA using (var fileStream = new FileStream(Path.Combine(outputFolder, "CERT.RSA"), FileMode.Create, FileAccess.Write)) { rsa.WriteTo(fileStream, out md5FingerPrint, out sha1FingerPrint); } #endif }
/// <summary> /// Collect all icons /// </summary> private static void CollectIcons(ApkFile apk, List<BarEntry> entries, Dictionary<string, string> apkPath2barPath) { #if DEBUG Debugger.Launch(); #endif var iconNames = apk.Manifest.Activities.Select(x => x.Icon).Where(x => !string.IsNullOrEmpty(x)).ToList(); var appIcon = apk.Manifest.ApplicationIcon; if (!string.IsNullOrEmpty(appIcon)) iconNames.Add(appIcon); foreach (var name in iconNames) { if (apkPath2barPath.ContainsKey(name)) continue; int nameAsInt; if (!int.TryParse(name, out nameAsInt)) continue; var resId = apk.Resources.GetResourceIdentifier(nameAsInt); var iconData = IconBuilder.GetIcon(resId, apk); if (iconData != null) { var barPath = "android/res/drawable/" + resId + ".png"; var entry = new BarEntry(barPath, new MemoryStream(iconData)); entries.Add(entry); apkPath2barPath[name] = barPath; } } }
private DexLookup LoadDex() { var apk = new ApkFile(_apkPath); var dex = apk.Load("classes.dex"); return new DexLookup(Dex.Read(new MemoryStream(dex))); }
/// <summary> /// Starts the debugger. /// </summary> internal void DebugLaunch(uint grfLaunch) { // Open the package PackageFile packageFile; var packagePath = PackagePath; try { packageFile = new PackageFile(packagePath); } catch (Exception ex) { MessageBox.Show(string.Format("Failed to open package because: {0}", ex.Message)); return; } // Show device selection var debuggable = (grfLaunch != (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_NoDebug); var ide = Package.Ide; #if ANDROID int minSdkVersion; if (!packageFile.Manifest.TryGetMinSdkVersion(out minSdkVersion)) { minSdkVersion = -1; } var targetFramework = (minSdkVersion > 0) ? Frameworks.Instance.GetBySdkVersion(minSdkVersion) : null; var targetVersion = (targetFramework != null) ? targetFramework.Name : null; var runner = new ApkRunner(ide, packagePath, packageFile.Manifest.PackageName, packageFile.Manifest.Activities.Select(x => x.Name).FirstOrDefault(), debuggable, (int)grfLaunch); #elif BB var targetFramework = Frameworks.Instance.FirstOrDefault(); var targetVersion = (targetFramework != null) ? targetFramework.Name : null; var runner = new BarRunner(ide, packagePath, packageFile.Manifest.PackageName, "--default--", debuggable, (int)grfLaunch); #endif using (var dialog = new DeviceSelectionDialog(ide, runner.DeviceIsCompatible, targetVersion)) { var rc = dialog.ShowDialog(); switch (rc) { case DialogResult.OK: var device = dialog.SelectedDevice; Package.Ide.LastUsedUniqueId = device.UniqueId; using (var xDialog = new LauncherDialog(packagePath, debuggable)) { var stateDialog = xDialog; stateDialog.Cancel += (s, x) => runner.Cancel(); stateDialog.Load += (s, x) => runner.Run(device, stateDialog.SetState); stateDialog.ShowDialog(); } break; case DialogResult.Retry: // Change project target version try { ChangeAndroidTargetVersion(dialog.NewProjectTargetVersion); MessageBox.Show(string.Format("Changed target framework version to {0}, to match the Android version of your device.", dialog.NewProjectTargetVersion)); } catch (Exception ex) { MessageBox.Show(string.Format("Failed to change target framework version because: {0}", ex.Message)); } break; } } }
/// <summary> /// Compile the given resources into a suitable output folder. /// </summary> internal bool Compile(List<Tuple<string, ResourceType>> resources, List<string> appWidgetProviderCodeFiles, List<string> references, List<string> referenceFolders, string baseApkPath) { // Remove temp folder if (Directory.Exists(tempFolder)) { Directory.Delete(tempFolder, true); } // Ensure temp\res folder exists var resFolder = Path.Combine(tempFolder, "res"); Directory.CreateDirectory(resFolder); var tempApkPath = Path.Combine(tempFolder, "temp.apk"); // Compile each resource foreach (var resource in resources.Where(x => x.Item2 != ResourceType.Manifest)) { CopyResourceToFolder(tempFolder, resource.Item1, resource.Item2); } // Extract resources out of library project references var resolver = new AssemblyResolver(referenceFolders, null, null); foreach (var path in references) { ExtractLibraryProjectResources(resFolder, path, resolver); } // Select manifest path var manifestPath = resources.Where(x => x.Item2 == ResourceType.Manifest).Select(x => x.Item1).FirstOrDefault(); // Ensure files exists for the appwidgetproviders CreateAppWidgetProviderFiles(tempFolder, manifestPath, appWidgetProviderCodeFiles); // Create system ID's resource CreateSystemIdsResource(tempFolder); // Run aapt var args = new[] { "p", "-f", "-S", resFolder, "-M", GetManifestPath(tempFolder, manifestPath, packageName), "-I", baseApkPath, "-F", tempApkPath }; var runner = new ProcessRunner(Locations.Aapt, args); var exitCode = runner.Run(); if (exitCode != 0) { ProcessAaptErrors(runner.Output, tempFolder, resources); return false; } // Unpack compiled resources to base folder. Table resourceTable = null; using (var apk = new ApkFile(tempApkPath)) { foreach (var name in apk.FileNames) { // Extract var data = apk.Load(name); // Save var path = Path.Combine(baseFolder, name); Directory.CreateDirectory(Path.GetDirectoryName(path)); File.WriteAllBytes(path, data); // Is resource table? yes -> load it if (name == "resources.arsc") { resourceTable = new Table(new MemoryStream(data)); } } } // Create R.cs if (!string.IsNullOrEmpty(generatedCodeFolder)) { var codeBuilder = new CreateResourceIdsCode(resourceTable, resources, valuesResourceProcessor.StyleableDeclarations); codeBuilder.Generate(generatedCodeFolder, packageName, generatedCodeNamespace, generatedCodeLanguage, lastModified); } // Create resource type usage info file if (!string.IsNullOrEmpty(resourceTypeUsageInformationPath)) { // Ensure folder exists var folder = Path.GetDirectoryName(resourceTypeUsageInformationPath); if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); // Create file File.WriteAllLines(resourceTypeUsageInformationPath, layoutProcessor.CustomClassNames); } return true; }
public override void Start(bool withDebugging) { // Open the package ApkFile apkFile; var apkPath = ApkPath; try { apkFile = new ApkFile(apkPath); } catch (Exception ex) { MessageBox.Show(string.Format("Failed to open package because: {0}", ex.Message)); return; } // Show device selection var ide = Dot42Addin.Ide; int minSdkVersion; if (!apkFile.Manifest.TryGetMinSdkVersion(out minSdkVersion)) minSdkVersion = -1; var targetFramework = (minSdkVersion > 0) ? Frameworks.Instance.GetBySdkVersion(minSdkVersion) : null; var targetVersion = (targetFramework != null) ? targetFramework.Name : null; var runner = new ApkRunner(ide, ApkPath, apkFile.Manifest.PackageName, apkFile.Manifest.Activities.Select(x => x.Name).FirstOrDefault(), withDebugging, 0); using (var dialog = new DeviceSelectionDialog(ide, IsCompatible, targetVersion)) { if (dialog.ShowDialog() == DialogResult.OK) { // Run on the device now var device = dialog.SelectedDevice; ide.LastUsedUniqueId = device.UniqueId; using (var xDialog = new LauncherDialog(apkPath, withDebugging)) { var stateDialog = xDialog; stateDialog.Cancel += (s, x) => runner.Cancel(); stateDialog.Load += (s, x) => runner.Run(device, stateDialog.SetState); stateDialog.ShowDialog(); } } } }
/// <summary> /// Starts the debugger. /// </summary> internal void DebugLaunch(uint grfLaunch) { // Open the package PackageFile packageFile; var packagePath = PackagePath; try { packageFile = new PackageFile(packagePath); } catch (Exception ex) { MessageBox.Show(string.Format("Failed to open package because: {0}", ex.Message)); return; } // Show device selection var debuggable = (grfLaunch != (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_NoDebug); var ide = Package.Ide; #if ANDROID int minSdkVersion; if (!packageFile.Manifest.TryGetMinSdkVersion(out minSdkVersion)) minSdkVersion = -1; var targetFramework = (minSdkVersion > 0) ? Frameworks.Instance.GetBySdkVersion(minSdkVersion) : null; var targetVersion = (targetFramework != null) ? targetFramework.Name : null; var runner = new ApkRunner(ide, packagePath, packageFile.Manifest.PackageName, packageFile.Manifest.Activities.Select(x => x.Name).FirstOrDefault(), debuggable, (int) grfLaunch); #elif BB var targetFramework = Frameworks.Instance.FirstOrDefault(); var targetVersion = (targetFramework != null) ? targetFramework.Name : null; var runner = new BarRunner(ide, packagePath, packageFile.Manifest.PackageName, "--default--", debuggable, (int)grfLaunch); #endif using (var dialog = new DeviceSelectionDialog(ide, runner.DeviceIsCompatible, targetVersion)) { var rc= dialog.ShowDialog(); switch (rc) { case DialogResult.OK: var device = dialog.SelectedDevice; Package.Ide.LastUsedUniqueId = device.UniqueId; using (var xDialog = new LauncherDialog(packagePath, debuggable)) { var stateDialog = xDialog; stateDialog.Cancel += (s, x) => runner.Cancel(); stateDialog.Load += (s, x) => runner.Run(device, stateDialog.SetState); stateDialog.ShowDialog(); } break; case DialogResult.Retry: // Change project target version try { ChangeAndroidTargetVersion(dialog.NewProjectTargetVersion); MessageBox.Show(string.Format("Changed target framework version to {0}, to match the Android version of your device.", dialog.NewProjectTargetVersion)); } catch (Exception ex) { MessageBox.Show(string.Format("Failed to change target framework version because: {0}", ex.Message)); } break; } } }
/// <summary> /// Gets the name of the APK package. /// </summary> private string GetApkName() { var apk = new ApkFile(Package.ItemSpec); return apk.Manifest.PackageName; }