美文网首页
【C#与Apk二三事】Apk反编译回编译签名等相关的工具类

【C#与Apk二三事】Apk反编译回编译签名等相关的工具类

作者: 鳗驼螺 | 来源:发表于2017-06-22 09:51 被阅读1517次

    这是在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;
            }
    
        }
    }
    
    

    相关文章

      网友评论

          本文标题:【C#与Apk二三事】Apk反编译回编译签名等相关的工具类

          本文链接:https://www.haomeiwen.com/subject/uqbxcxtx.html