/作者: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文件中application的name屬性指定的類會在所有類之前最先被執行
例如
<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_,"");">","<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();="" ```="" 方法差不多都寫上了="" 接下來貼加固過程="" ```java="" 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;
}
編譯完成,放圖
那么試試對msf載荷加固
上傳至在線木馬掃描網站
加固前:23個殺毒引擎報毒
加固后:3個引擎報毒,免殺效果還不錯嘛
開源放上:
https://pan.baidu.com/s/1klERbmiDRk3Ipo2tlapa7A
</fl.length;i++){></application","