这是在ApkIDE中Apk相关的处理命令工具,包括调用apktool反编译apk,调用apktool回编译apk,对生成的apk进行签名,调用Dex2jar对.dex反编译成.class文件,调用jad对.class文件进行反编译等。
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
namespace Com.Popotu.ApkIDE
{
/// <summary>
/// Apk相关处理命令(使用Apktool2.0测试)
/// ShellCmd类:http://www.jianshu.com/p/de99a6d99e31
/// </summary>
class ApkCmd
{
private static string GetApkToolCmdHead()
{
return "java -jar apktool.jar";
}
/// <summary>
/// 使用apktool反编译apk文件
/// </summary>
/// <param name="apkFilePathForDecompile">要反编译的apk文件路径</param>
/// <param name="smaliDirPathForOutput">反编译后smali源文件输出目录</param>
/// <param name="frameworkList"></param>
/// <param name="errinf"></param>
/// <returns></returns>
public static bool DecompileApk(string apkFilePathForDecompile, string smaliDirPathForOutput, List<string> frameworkList, out string errinf)
{
ShellCmd cmd = new ShellCmd();
List<string> cmdList = new List<string>();
cmdList.Add(string.Format("set path={0}", Path.Combine(Appres.JDK_HOME , "bin")));
foreach (string framework in frameworkList)
cmdList.Add(string.Format("{0} if \"{1}\"", GetApkToolCmdHead(), framework));
cmdList.Add(
string.Format("{0} d -f \"{1}\" -o \"{3}\"",
GetApkToolCmdHead(),
apkFilePathForDecompile,
smaliDirPathForOutput));
cmd.Run(cmdList.ToArray());
bool noerr = true;
if (!string.IsNullOrEmpty(cmd.Errinf))
{
errinf = cmd.Errinf;
noerr = !errinf.Contains("Exception in thread");
}
else errinf = string.Empty;
return noerr && Directory.Exists(smaliDirPathForOutput);
}
/// <summary>
/// 使用apktool将smali回编译为apk
/// </summary>
/// <param name="apkSourceDir">smali源文件夹</param>
/// <param name="apkOutputFile">编译输出的apk文件路径</param>
/// <param name="ingoreError">是否忽略错误(防卡死,但有副作用)</param>
/// <returns></returns>
public static bool CompileToApk(string smaliDirPathForCompile, string apkFilePathForOutput, List<string> frameworkList, bool ingoreError)
{
ShellCmd cmd = new ShellCmd();
if (ingoreError) cmd.IngoreError = true;
List<string> cmdList = new List<string>();
cmdList.Add(string.Format("set path={0}", Path.Combine(Appres.JDK_HOME, "bin")));
foreach (string framework in frameworkList)
cmdList.Add(string.Format("{0} if \"{1}\"", GetApkToolCmdHead(), framework));
cmdList.Add(
string.Format("{0} b \"{1}\" -o \"{3}\"",
GetApkToolCmdHead(),
smaliDirPathForCompile,
apkFilePathForOutput));
cmd.Run(cmdList.ToArray());
bool success = File.Exists(apkFilePathForOutput);
return success;
}
/// <summary>
/// 给apk签名
/// </summary>
/// <param name="apkFilePathForSigned">要签名的apk程序路径</param>
/// <param name="getSignedApkFilePath"></param>
/// <param name="useJarsigner">是否使用jarsigner来签名(需要设置keystore),否则使用signapk.jar签</param>
/// <returns>是否成功</returns>
public static bool SignApk(string apkFilePathForSigned, out string getSignedApkFilePath,
bool useJarsigner = false, string keystoreFile = null, string storepass = null, string keypass = null, string alias = null)
{
string apkname = IOCommand.GetFileNameWithoutExt(apkFilePathForSigned);
string signedApkOutputFilePath = Path.Combine(new FileInfo(apkFilePathForSigned).DirectoryName, apkname + "_Signed.apk");
if (File.Exists(signedApkOutputFilePath)) File.Delete(signedApkOutputFilePath);
ShellCmd cmd = new ShellCmd();
if (string.IsNullOrEmpty(keystoreFile) || string.IsNullOrEmpty(storepass) || string.IsNullOrEmpty(keypass) || string.IsNullOrEmpty(alias)) useJarsigner = false;
if (useJarsigner)//使用jarsigner.exe签名
{
string fmt = "jarsigner -keystore \"{0}\" -storepass {1} -keypass {2} \"{3}\" {4} {5}";
fmt = string.Format(fmt, new string[]{
keystoreFile,
storepass,
keypass,
apkFilePathForSigned,
alias,
"-digestalg SHA1 -sigalg MD5withRSA"
});
cmd.Run(new string[]{
string.Format("set path={0}", Path.Combine(Appres.JDK_HOME, "bin")),
fmt,
string.Format("zipalign -v 4 \"{0}\" \"{1}\"", apkFilePathForSigned, signedApkOutputFilePath)
});
}
else//使用signapk.jar签名
{
string fmt = "testkey.x509.pem testkey.pk8 \"{0}\" \"{1}\"";
fmt = string.Format(fmt, apkFilePathForSigned, signedApkOutputFilePath);
cmd.Run(new string[] {
string.Format("set path={0}", Path.Combine(Appres.JDK_HOME, "bin")),
"java -jar signapk.jar " + fmt
});
}
getSignedApkFilePath = signedApkOutputFilePath;
bool success = File.Exists(getSignedApkFilePath);
return success;
}
/// <summary>
/// 将所有.class文件用jad反编译成.java文件
/// </summary>
/// <param name="dirPathOfClassFiles"></param>
/// <param name="outputDirPathForJavaFiles"></param>
public static void Classes2Javas(string dirPathOfClassFiles, string outputDirPathForJavaFiles)
{
List<string> cmdList = new List<string>();
cmdList.Add(string.Format("jad -o -r -sjava -d\"{0}\" \"{1}\"/**/*.class", outputDirPathForJavaFiles, dirPathOfClassFiles));
ShellCmd cmd = new ShellCmd();
cmd.IngoreError = true;
cmd.Run(cmdList.ToArray());
}
/// <summary>
/// 从apk反编译出.class代码文件
/// </summary>
/// <param name="apkFilePath"></param>
/// <param name="outputDirPathForClassFiles"></param>
/// <param name="errinf">错误信息</param>
/// <exception cref="Exception">意外错误</exception>
/// <returns></returns>
public static bool Apk2Classes(string apkFilePath, string outputDirPathForClassFiles, out string errinf)
{
string dexFilePath = null;
try
{
dexFilePath = Path.Combine(Application.StartupPath, "classes.dex");
ApkZip.Unzip(apkFilePath, "classes.dex", dexFilePath);
bool success = Dex2jar(dexFilePath, outputDirPathForClassFiles);
errinf = string.Empty;
return success;
}
catch (ApplicationException e)
{
errinf = e.Message;
return false;
}
catch (Exception e)
{
throw e;
}
finally
{
try
{
if (!string.IsNullOrEmpty(dexFilePath) && File.Exists(dexFilePath)) File.Delete(dexFilePath);
}
catch { }
}
}
/// <summary>
/// dex2jar
/// </summary>
/// <param name="dexFile"></param>
/// <param name="outputDirPathForClassFiles"></param>
/// <exception cref="ApplicationException"></exception>
/// <returns></returns>
public static bool Dex2jar(string dexFile,string outputDirPathForClassFiles)
{
//生成classes_dex2jar.jar
List<string> cmdList = new List<string>();
cmdList.Add(
string.Format(
"set path={0};{1}",
Path.Combine(Appres.JDK_HOME, "bin"),
Path.Combine(Application.StartupPath, "dex2jar")));
cmdList.Add(
string.Format(
"d2j-dex2jar --force \"{0}\"",
dexFile));
ShellCmd cmd = new ShellCmd();
cmd.Run(cmdList.ToArray());
string cd2jFile = Path.Combine(new FileInfo(dexFile).Directory.FullName ,IOCommand.GetFileNameWithoutExt(dexFile) + "-dex2jar.jar");
try { if (Directory.Exists(outputDirPathForClassFiles)) Directory.Delete(outputDirPathForClassFiles, true); }
catch { }
ApkZip.Unzip(cd2jFile, outputDirPathForClassFiles);
try { if (File.Exists(cd2jFile)) File.Delete(cd2jFile); }catch { }
bool success = System.IO.Directory.Exists(outputDirPathForClassFiles);
if (!success && !string.IsNullOrEmpty(cmd.Errinf))
{
throw new ApplicationException(cmd.Errinf);
}
return success;
}
}
}