欢迎来真孝善网,为您提供真孝善正能量书籍故事!

Android应用程序加固方法研究(篇三)

时间:11-23 神话故事 提交错误

今天给各位分享Android应用程序加固方法研究(篇三)的知识,其中也会对进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

Android APK加固技术研究(三)

为了保证Android应用程序的源代码安全,我们一般会对线上应用程序的代码进行混淆。然而,代码混淆还不够。我们还需要加强我们的应用程序,防止他人通过反编译获取我们的源代码。目前apk加固技术已经比较成熟和完善,市场上比较流行的就是“360加固”。本文对apk加固技术进行技术探索。希望读者读完后能够理解加固原理,并自行实现加固方案。

源码地址:https://gitee.com/openjk/apk-jiagu

在Android apk加固技术探索(二)中,我们通过创建Steady模块生成了shell.arr文件,用于对加密的dex文件进行解密和类加载。本文主要讲解如何对原apk的dex进行加密,并在原apk中输入shell.arr,最终生成一个新的apk

一、反编译 APK 文件

Android APK加固技术研究(一)讲解如何反编译apk文件。这里我们使用apktool工具来反编译apk。通过执行命令java -jar outlibs/apktool_2.5.0.jar d "解压后的apk的路径" -o "解压后要存放的路径"

/**

* 反编译APK文件

*/

有趣的apkDecode(){

println("开始反编译")

val 进程=Runtime.getRuntime()

.exec("java -jar outlibs/apktool_2.5.0.jar d "+ orginApk.absolutePath+" -o "+apkDecode.absolutePath)

进程.waitFor()

if(process.exitValue() !=0) {

FileUtils.printStream(process.errorStream)

}别的{

FileUtils.printStream(process.inputStream)

}

进程.destroy()

}

二、修改 AndroidManifest.xml 文件

获取步骤1解压后的文件目录,并在该目录中找到AndroidManifest文件。这里修改AndroidManifest.xml文件有两种方法。一是通过“AXMLEditor.jar”和“AXMLPrinter2.jar”工具修改AndroidManifest.xml文件。另一种是通过SAX解析xml文件,然后在对应的节点位置插入需要的数据,最后发现虽然方法一修改了xml文件,但最终打包的新APK中的AndroidManifest.xml文件没有生效。后来方法二就生效了。下面发布了这两种方法的代码。如果有人发现方法一有问题,请不吝赐教。

方法一:关于如何使用“AXMLEditor.jar”和“AXMLPrinter2.jar”这两个工具,大家可以自行百度搜索。我们不会在这里展开它们。

/**

* 修改AndroidManifest

*/

有趣的更改AndroidManifest(apkUnzipDir:File){

val aManifest=apkUnzipDir.listFiles { _, name -name?equals("AndroidManifest.xml")==true

}

val file=if (aManifest !=null aManifest.isNotEmpty()) {

清单[0]

}否则{空}

文件?let {

//将模板插入到AndroidManifest中

val process2=Runtime.getRuntime()

.exec("java -jar outlibs/AXMLEditor.jar -tag -i 工具/src/main/assets/ApplicationName.xml " +

文件.absolutePath+""+文件.absolutePath)

process2.waitFor()

if(process2.exitValue() !=0) {

打印("2")

FileUtils.printStream(process2.errorStream)

}

process2.destroy()

//解析出原来的Application类名

var process0=Runtime.getRuntime()

.exec("java -jar 工具/libs/AXMLPrinter2.jar "+file.absolutePath)

process0.waitFor()

val applicationPath=XmlParseUtils.sax2xml(process0.inputStream)

if(process0.exitValue() !=0){

println("0")

FileUtils.printStream(process0.errorStream)

}

process0.destroy()

//参考https://github.com/fourbrother/AXMLEditor

//修改Application下插入标签的值

val process1=Runtime.getRuntime()

.exec("java -jar tool/libs/AXMLEditor.jar -attr -i 元数据包值"+applicationPath

+ " " + 文件.absolutePath+" "+文件.absolutePath)

process1.waitFor()

if(process1.exitValue() !=0){

打印("1")

FileUtils.printStream(process1.errorStream)

}

process1.destroy()

//参考https://github.com/fourbrother/AXMLEditor

//修改Application下的name标签

val process3=Runtime.getRuntime()

.exec("java -jar tool/libs/AXMLEditor.jar -attr -m 应用程序包名称com.sakuqi.shell.NewApplication"

+ " " + 文件.absolutePath+" "+文件.absolutePath)

process3.waitFor()

if(process3.exitValue() !=0){

println("3")

FileUtils.printStream(process3.errorStream)

}

process3.destroy()

//解析出原来的Application类名

var process4=Runtime.getRuntime()

.exec("java -jar 工具/libs/AXMLPrinter2.jar "+file.absolutePath)

process4.waitFor()

FileUtils.printStream(process4.inputStream)

process4.destroy()

}

}方法二:查看相关API文档了解如何使用SAXReader。

/**

* 修改xml文件

*/

有趣的变化AndroidManifest(){

println("开始修改AndroidManifest")

var manifestFile=File("输出/apktool/decode/AndroidManifest.xml")

changeXmlBySax(manifestFile,"com.sakuqi.steady.SteadyApplication")

//com.sakuqi.steady.SteadyApplication名称是Shell.arr中的Application类

}

/**

* 修改xml文件

*/

有趣的changeXmlBySax(fileXml:File,newApplicationName:String){

var sax=SAXReader()

var 文档=sax.read(fileXml)

var root=document.rootElement

var application=root.element("应用程序")

//原应用名称

var applicationName=application.attributeValue("name")

var applicationAttr=application.attribute("名称")

//用shell中的应用替换原来的应用

applicationAttr.text=newApplicationName

var element=application.addElement("元数据")

element.addAttribute("android:name","app_name")

element.addAttribute("android:value",applicationName)

保存文档(文档,fileXml)

}

有趣的saveDocument(document:Document,file:File){

var osWrite=OutputStreamWriter(FileOutputStream(文件))

var format=OutputFormat.createPrettyPrint()//获取指定的输出格式

格式.编码="UTF-8"

var writer=XMLWriter(osWrite,格式)

writer.write(文档)

writer.flush()

writer.close()

}

三、编译修改 AndroidManifest.xml 后的反编译目录

/**

* 编译APK文件

*/

有趣的apkBuild(){

println("开始重新编译")

val 进程=Runtime.getRuntime()

.exec("java -jar outlibs/apktool_2.5.0.jar b "+ "反编译目录"+" -o "+ "编译目录")

进程.waitFor()

if(process.exitValue() !=0) {

FileUtils.printStream(process.errorStream)

}别的{

FileUtils.printStream(process.inputStream)

}

进程.destroy()

}

四、解压 APK 文件并加密所以 Dex 文件

java.util.zip.ZipFile类用于解压。这里封装了工具类,最终会放到源码中,所以这里就不展开了。解压后需要删除原apk中的签名文件,以便以后重新签名。过滤掉解压目录下所有dex后缀的文件,然后进行加密。需要注意的是,加密方法需要与shell.arr中的解密方法保持一致。这里使用的是AES加密方法。稍后将讨论源代码。在开源项目中显示。加密后需要删除原dex文件。大致代码如下:

/**

* 解压APK文件并加密所有dex文件

*/

有趣的unZipApkAndEncrypt(){

println("解压APK")

val apkUnzipDir=文件("输出/解压/apk")

if(!apkUnzipDir.exists()){

apkUnzipDir.mkdirs()

}

FileUtils.delete(apkUnzipDir)

ZipUtils.unZip(apkBuild,apkUnzipDir)

//删除META-INF/CERT.RSA,META-INF/CERT.SF,META-INF/MANIFEST.MF

val certRSA=文件(apkUnzipDir,"META-INF/CERT.RSA")

certRSA.delete()

val certSF=文件(apkUnzipDir,"META-INF/CERT.SF")

certSF.delete()

val manifestMF=文件(apkUnzipDir,"META-INF/MANIFEST.MF")

清单MF.delete()

//更改AndroidManifest(apkUnzipDir)

//获取dex文件

val apkFiles=apkUnzipDir.listFiles(对象:FilenameFilter{

覆盖乐趣接受(dir:文件?name:字符串?):布尔值{

返回名称?endsWith(".dex")==true

}

})

for (apkFiles 中的dexFile){

val 名称=dexFile.name

println("dex:$名称")

val 字节=DexUtils.getBytes(dexFile)

val encrypt: 字节数组?=EncryptUtils.加密(字节, EncryptUtils.ivBytes)

val fos: FileOutputStream=FileOutputStream(

文件(

dexFile.parent,

"秘密-" + dexFile.getName()

fos.write(加密)

fos.flush()

fos.close()

dexFile.delete()

}

}

五、解压壳 aar 得到 class.jar ,然后把 class.jar 在转换成 class.dex,再将class.dex 移到原 apk 的解压目录,最后压缩成新的 apk 文件

这里仍然使用unzip的工具类进行解压,使用Android SDK自带的命令dx来转换class.dex。

/**

* 解压shell aar并将jar转换为dex

*/

有趣的makeDecodeDex(){

println("解压AAR")

var shellUnzipDir=文件("输出/解压/shell")

if(!shellUnzipDir.exists()){

shellUnzipDir.mkdirs()

}

FileUtils.delete(shellUnzipDir)

//解压AAR

ZipUtils.unZip(shellAAR,shellUnzipDir)

//将jar转为dex

println("将jar 转换为dex")

var shellJar=文件(shellUnzipDir,"classes.jar")

var shellDex=File("输出/解压/apk","classes.dex")

DexUtils.dxCommand(shellJar,shellDex)

moveLibSoToApk()

//盒

println("打包APK")

var unsignedApk=File("输出/unsigned_$orginApkName")

ZipUtils.zip(文件("输出/解压/apk"),unsignedApk)

}

/**

* 将shell中的lib文件移动到apk中

*/

有趣的moveLibSoToApk(){

var shellUnzipLibDir=文件("输出/解压/shell/jni")

var apkUnzipLibDir=文件("输出/解压/apk/lib")

if(!apkUnzipLibDir.exists()){

apkUnzipLibDir.mkdirs()

}

FileUtils.copy(shellUnzipLibDir,apkUnzipLibDir)

}对象DexUtils {

@Throws(IOException:类,InterruptedException:类)

有趣的dxCommand(jar:File,dex:File){

var 运行时=Runtime.getRuntime()

var process=runtime.exec("dx --dex --output "+dex.absolutePath+" "+jar.absolutePath)

尝试{

进程.waitFor()

}捕获(e:InterruptedException){

e.printStackTrace()

扔e

}

if(process.exitValue() !=0){

val 输入流=process.errorStream

var 缓冲区=ByteArray(1024)

val bos=ByteArrayOutputStream()

var len=inputStream.read(缓冲区)

而(长度!=-1){

bos.write(缓冲区,0,len)

len=inputStream.read(缓冲区)

}

System.out.println(String(bos.toByteArray(), Charset.forName("GBK")))

抛出RuntimeException("dx 运行失败")

}别的{

System.out.println("执行成功:"+process.exitValue())

}

进程.destroy()

}

/**

* 读取文件

* @参数文件

* @返回

* @抛出异常

*/

@Throws(Exception:类)

fun getBytes(file: 文件?): ByteArray {

val r=RandomAccessFile(文件, "r")

val buffer=ByteArray(r.length().toInt())

r.readFully(缓冲区)

r.close()

返回缓冲区

}

}

五、将压缩后的新的 apk 文件进行 zip 对齐操作

/**

* 结盟

*/

有趣的zipalign(){

println("对齐打包的apk")

var unsignedApk=File("输出/unsigned_$orginApkName")

valalignedApk=File("输出/无符号对齐_$orginApkName")

val 进程=Runtime.getRuntime().exec(

"zipalign -p -f -v 4"+unsignedApk.absolutePath+""+alignedApk.absolutePath)

process.waitFor(5,TimeUnit.SECONDS)

尝试{

if (process.exitValue() !=0) {

println("压缩对齐错误")

FileUtils.printStream(process.errorStream)

} 别的{

FileUtils.printStream(process.inputStream)

}

println("完整的apk对齐")

进程.destroy()

}捕获(e:异常){

println("对齐超时.")

}

}

六、将对齐后的 apk 文件进行签名

/**

* 签署APK

*/

有趣的jksToApk(){

println("签名的APK")

varsignedApk=File("输出/signed_$orginApkName")

valalignedApk=File("输出/无符号对齐_$orginApkName")

SignUtils.signature(alignedApk,signedApk,signFile.absolutePath)

}对象SignUtils {

@Throws(InterruptedException:类,IOException:类)

有趣的签名(unsignedApk:文件,signedApk:文件,keyStore:字符串){

val cmd=arrayOf(

"jarsigner",

"-sigalg",

"SHA1withRSA",

"-消化",

"SHA1",

"-密钥库",

密钥库,

"-商店通行证",

"密码",

"-keypass",

"密码",

"-signedjar",

签名的Apk.absolutePath,

未签名的Apk.absolutePath,

"阿利纳斯"

val 进程=Runtime.getRuntime().exec(cmd)

println("开始标志")

尝试{

val waitResult=process.waitFor()

println("waitResult: $waitResult")

} catch (e: InterruptedException) {

e.printStackTrace()

扔e

}

println("process.exitValue()" + process.exitValue())

if (process.exitValue() !=0) {

val 输入流=process.errorStream

var len: 整数

val 缓冲区=ByteArray(2048)

val bos=ByteArrayOutputStream()

len=inputStream.read(缓冲区)

while (len!=-1) {

bos.write(缓冲区, 0, 长度)

len=inputStream.read(缓冲区)

}

println(String(bos.toByteArray(), Charset.forName("gbk")))

throw RuntimeException("签名执行失败")

}

println("完成签名")

进程.destroy()

}

用户评论

自繩自縛

终于等到新的文章了,一直在关注这个系列。

    有13位网友表示赞同!

杰克

想了解一下最新的加固技巧,看看能不能提升自己APP的安全防范措施。

    有7位网友表示赞同!

南宫沐风

这篇文章肯定能让我受益匪浅,期待深入学习。

    有18位网友表示赞同!

请在乎我1秒

以前对Android APK加固技术只知道皮毛,希望能通过这篇文章了解更多专业知识。

    有18位网友表示赞同!

呆萌

最近在搞app安全开发,正好学习一下加固技术。

    有16位网友表示赞同!

枫无痕

希望解释详细一些,方便小白理解。

    有18位网友表示赞同!

米兰

想知道有哪些最新的常用加固工具和方法?

    有11位网友表示赞同!

该用户已上天

关注这个题材好久了,每次更新都期待值满满!

    有12位网友表示赞同!

凉城°

作者的分析很透彻,希望能看到更多实用的案例分享。

    有16位网友表示赞同!

陌颜

学习一下Android APK加固技术,让自己成为更优秀的开发者。

    有5位网友表示赞同!

麝香味

想了解加固技术对app性能影响有多大?

    有10位网友表示赞同!

执笔画眉

想知道如何评估加固的效果,以及有哪些测试方法吗?

    有18位网友表示赞同!

暮染轻纱

最近在考虑使用哪种加固方式,这篇文章应该能帮我做出决定。

    有19位网友表示赞同!

醉红颜

期待看到文章讨论一些常见的加固技术漏洞和应对策略。

    有13位网友表示赞同!

珠穆郎马疯@

学习了这个系列后,可以做出一款更加安全的APP吗?

    有9位网友表示赞同!

青衫负雪

希望看到更多关于逆向工程和安全测试的内容。

    有17位网友表示赞同!

无望的后半生

作者的技术水平真的很棒!期待更精彩的分享。

    有9位网友表示赞同!

巷陌繁花丶

这篇文章值得收藏,以后有机会再仔细研究一下。

    有20位网友表示赞同!

冷青裳

对于开发新APP来说,加固技术是必不可少的环节吧?

    有13位网友表示赞同!

若他只爱我。

感觉学习这些高深的知识会让我对Android编程有更深入的理解。

    有7位网友表示赞同!

【Android应用程序加固方法研究(篇三)】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活