欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Android编程实战】利用apktool编写apk的dex加壳工具

程序员文章站 2022-07-15 14:38:03
...

/作者:Kali_MG1937
CSDN博客:ALDYS4
QQ:3496925334
/

最近初学dex加固方面的内容
突发奇想想自己做一个自动化的脚本工具

DEX加壳原理

将源apk与脱壳用的dex合并为一个加密后的dex
修改加密后dex的头信息和长度信息等
让app在启动时先运行加密后dex的脱壳代码
释放源apk
利用动态class加载源app的代码
加壳过程详细看:
https://blog.csdn.net/jiangwei0910410003/article/details/48415225

构建思路

要如何让加固后的apk先运行脱壳代码?
我们知道AndroidManifest.xml文件中applicationname属性指定的类会在所有类之前最先被执行
例如

<application android:name=".Main">
</application>

那么app运行时就会最先执行Main中的代码
但Main必须继承Application

那么实现起来就简单了

先将apk和脱壳dex合并为加密后的dex,我先将它命名为classes_encode.dex
再反编译源apk
DEX脱壳类为ProxyApplication
那么就要修改源apk的AndroidManifest.xml中application的name属性为ProxyApplication
修改完成后回编译apk
解压回编译后的apk
删除源apk内的classes.dex并替换为加密后的dex
(重命名classes_encode.dex为classes.dex并放入源apk)
打包apk

实现项目

apk反编译我已经在我上次写的博客里实现了
https://blog.csdn.net/ALDYS4/article/details/85998037

/*
apktool即为AndroidApktool对象
详细看我上面发的博客
*/
	//反编译
	public void apkDecompile(final String file,final String outfile) throws InterruptedException{
		try
		{
			append("\n反编译:" + file);
			apktool = new AndroidApktool();//初始化apktool
			apktool.initAndroid(MainActivity.this);
			File out=new File("/sdcard/decode_dex/" + outfile);
			if (!out.isDirectory())
			{
				out.mkdirs();
			}
			Cmd cmds=new Cmd();
			cmds.apkDecompile(file, "/sdcard/decode_dex/" + outfile);
			String[] command=cmds.get();
			append("\n反编译执行:" + cmds.getString().replace("\n", " "));
			apktool.run(command);//执行命令
		}
		catch (InterruptedException e)
		{append("\n反编译Interrupted异常:"+e.toString());
		}
		catch (BrutException e)
		{append("\n反编译Burt异常:"+e.toString());
		}
		catch (IOException e)
		{append("\n反编译IO异常:"+e.toString());
		}
	}
	//回编译
	public void apkBackcompile(final String appfile) throws InterruptedException{
		try
		{
			append("\n开始回编译:" + appfile);
			String errorCode=readFile(BaseFile + appfile + "/AndroidManifest.xml");
			errorCode = errorCode.replace("android:resizeableActivity=\"true\"", "");
			writeFile(BaseFile + appfile + "/AndroidManifest.xml", errorCode);
			Cmd cmd=new Cmd();
			String aapt=Manage.copyfile(MainActivity.this, "aapt.mrp");
			//String aapt=apktool.extra("aapt.mrp",BaseFile).toString();
			cmd.apkCompile(BaseFile + appfile, aapt, BaseFile + appfile + ".apk");
			String[] command=cmd.get();
			append("\n回编译执行:" + cmd.getString().replace("\n", " "));
			apktool.run(command);
			append("\n回编译完成");
		}
		catch (InterruptedException e)
		{append("\n回编译Interrupted异常:"+e.toString());
		}
		catch (BrutException e)
		{append("\n回编译Burt异常:"+e.toString());
		}
		catch (IOException e)
		{append("\n回编译IO异常:"+e.toString());
		}
	}

先利用apkDecompile方法反编译apk
接下来就是application注入
即为修改application的name属性
我这里利用了dom4j来解析xml

	//注入application
	public void applicationInject() throws IOException, DocumentException{
		//AndroidManifest
		String AndroidManifest=readFile(BaseFile+"app_src/AndroidManifest.xml");
		Document doc=DocumentHelper.parseText(AndroidManifest);
		Element ele=doc.getRootElement().element("application");
		String name=ele.attributeValue("name");//获取application的name参数
		if(name==null){//当application不包含name参数时
			writeFile(BaseFile+"app_src/AndroidManifest.xml",
			AndroidManifest.replace("<application","<application android:name=\"com.dex.ProxyApplication\""));
		}
		else
		{
			String name_="android:name=\""+name+"\"";
			AndroidManifest=AndroidManifest.replace(name_,"");
			AndroidManifest=AndroidManifest.replace("<application","<application android:name=\"com.dex.ProxyApplication\"");
			AndroidManifest=AndroidManifest.replace("</application>","<meta-data android:name=\"APPLICATION_CLASS_NAME\" android:value=\""+name+"\"/>");
			writeFile(BaseFile+"app_src/AndroidManifest.xml",AndroidManifest);
		}
		append("\napplication已完成注入");
	}

注入完成后利用apkBackcompile方法打包为apk
接下来就是解压apk

	//文件解压
	public void zipEntry(boolean assets,String zipfile,String out,String refer) throws IOException{
		append("\n开始解压文件");
		boolean entry_=true;
		File file=null;
		if(assets==true){
			file=apktool.extra(zipfile,BaseFile);
			append("路径:"+file.getPath());
		}
		else{
			file=new File(zipfile);
		}
		ZipFile zip=new ZipFile(file);
		ZipInputStream zin=new ZipInputStream(new FileInputStream(file));
		ZipEntry entry ;
		while (((entry=zin.getNextEntry())!=null)){//如果entry不为空
		if(!refer.equals("")){//若要指定的文件名不为空
			if(entry.getName().equals(refer)){
				entry_=true;
			}else{entry_=false;}
		}else{entry_=true;}
		if(entry_){
			File tmp = new File(out+entry.getName());//解压出的文件路径
			if(entry.isDirectory()){
				tmp.mkdirs();
			}
			if (!tmp.exists()){//如果文件不存在
				tmp.getParentFile().mkdirs();//创建文件父类文件夹路径
				InputStream fis =  zip.getInputStream(entry);
				OutputStream fos = new FileOutputStream(tmp);
				byte []bys = new byte[1024];
				int len = 0;
				while((len = fis.read(bys)) != -1){
					fos.write(bys,0,len);
				}
				fos.close();
				fis.close();
			}
			zin.closeEntry();
			}//if entry_
		}
			zin.close();
			append("\n解压文件完成");
	}

解压完成
在替换dex前先对脱壳dex进行修改
我先释放含有脱壳dex的apk
对其进行反编译
再对ProxyApplication.smali代码中需要动态加载的class替换成源apk的主类

	//替换壳启动活动
	public void replaceAct(String com) throws IOException{
		String smali=readFile(BaseFile+"decode_app_src/smali/com/dex/ProxyApplication.smali");
		smali=smali.replace("com.test.MainActivity",com);
		writeFile(BaseFile+"decode_app_src/smali/com/dex/ProxyApplication.smali",smali);
		append("\n活动注入完成");
	}

回编译含有脱壳dex的apk
提取其dex
接下来就是加固dex了
因为我在文章开头贴上了加固dex方法的链接
这里就不贴代码了
加固完成后替换dex
再压缩为apk

	//压缩文件
	public void zip(String zipfile,File input) throws FileNotFoundException, IOException{
		append("\n开始打包");
		ZipOutputStream out=new ZipOutputStream(new FileOutputStream(zipfile));
		zip(out,input,"");
		out.close();
	}
	public void zip(ZipOutputStream out,File f,String base) throws IOException{
		if(f.isDirectory()){
			File[] fl=f.listFiles();
			if(base.length()!=0){
				out.putNextEntry(new ZipEntry((base+"/")));
				//System.out.println(base+"/");
			}
			for(int i=0;i<fl.length;i++){
				zip(out,fl[i],fl[i].getPath().replace(BaseFile+"app_dex/",""));
				System.out.println(base+"/");
			}
		}
		else{
			out.putNextEntry(new ZipEntry(base));
			FileInputStream in=new FileInputStream(f);
			int b;
			while((b=in.read())!=-1){
				out.write(b);
			}
			in.close();
		}
	}
	

方法差不多都写上了
接下来贴加固过程

	public class encoding extends AsyncTask<Void,Void,Void>
	{

		@Override
		protected Void doInBackground(Void[] p1)
		{
									try
									{
										append("\n框架准备");
										//installFrame();
										append("\nApktool反编译开始");
										apkDecompile(ed.getText().toString(),"app_src");
										//反编译输出位置/sdcard/decode_dex/app_src
										append("\n反编译完成,开始application注入");
										applicationInject();
										//zipEntry(true,"decode_app_src.zip",BaseFile,"");
										//解压解壳dex文件
										String dex_app=apktool.extra("decode_app.apk",BaseFile).toString();
										//释放壳文件
										apkDecompile(dex_app,"decode_app_src");
										//反编译壳文件
										showInject();
										lock();
										replaceAct(com);
										//替换壳启动活动
										apkBackcompile("decode_app_src");
										//回编译壳文件
										zipEntry(false,BaseFile+"decode_app_src.apk",BaseFile+"decode_dex/","classes.dex");
										//解压壳文件dex
										apkBackcompile("app_src");
										//回编译源app
										zipEntry(false,BaseFile+"app_src.apk",BaseFile+"app_dex/","");
										//解压源app
										dex.encode("decode_dex/classes.dex","app_src.apk");
										append("\nclasses.dex加固完成");
										//dex加固到/sdcard/decode_dex/classes.dex
										File f=new File(BaseFile+"app_dex/classes.dex");
										f.delete();
										append("\n"+f+"删除完成");
										//删除源app的dex文件
										copy(BaseFile+"classes.dex",BaseFile+"app_dex/classes.dex");
										//复制加壳后的dex至源app
										zip(BaseFile+"encode.apk",new File(BaseFile+"app_dex"));
										//打包app
										append("\n打包结束");
									}
									catch (InterruptedException e)
									{}
									catch (DocumentException e)
									{append("\nDocument异常:"+e.toString());
									}
									catch (IOException e)
									{append("\nIO异常:"+e.toString());
									}

						
			return null;
		}

编译完成,放图
【Android编程实战】利用apktool编写apk的dex加壳工具
【Android编程实战】利用apktool编写apk的dex加壳工具
那么试试对msf载荷加固
上传至在线木马扫描网站
加固前:23个杀毒引擎报毒
【Android编程实战】利用apktool编写apk的dex加壳工具
加固后:3个引擎报毒,免杀效果还不错嘛
【Android编程实战】利用apktool编写apk的dex加壳工具
开源放上:
https://pan.baidu.com/s/1klERbmiDRk3Ipo2tlapa7A