工具:
apktool:https://code.google.com/p/android-apktool/
dex2jar: https://code.google.com/p/dex2jar/
jd-gui: http://jd.benow.ca/
反编译命令提取资源(smail汇编代码):apktool d file.apk path
dex2jar反编译:dex2jar file.apk (or classes.dex)
用jd-gui就可以打开jar看了
用jd-gui在windows下没问题,在linux64下要装ia32的库。
一般代码都被混淆过。
都是abcdefg。。。
下面讲讲本人的一些小技巧。
本人最近反编译一个aide,菜鸟抄抄别人的实现。
一般都是从布局入手,找出相应关键的view类:如<com.aide.ui.AIDEEditorPager 。。。
可以在代码文件里找到AIDEEditorPager这个类,下面贴点代码:
package com.aide.ui; import android.content.Context; import android.graphics.Rect; import android.os.Build.VERSION; import android.support.v4.view.ViewPager; import android.support.v4.view.aa; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import com.aide.common.c; import com.aide.engine.SyntaxError; import com.aide.ui.util.k; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import rg; import rh; import ri; public class AIDEEditorPager extends ViewPager implements ri { private boolean DW; private f FH; private boolean Hw; private List j6 = new ArrayList(); private l v5; public AIDEEditorPager(Context paramContext) { super(paramContext); sG(); } public AIDEEditorPager(Context paramContext, AttributeSet paramAttributeSet) { super(paramContext, paramAttributeSet); sG(); } private void DW(boolean paramBoolean) { int i = 4; View localView1 = getRootView(); int j; View localView3; if (localView1 != null) { View localView2 = localView1.findViewById(2131427448); if (localView2 != null) { if (!paramBoolean) { break label62; } j = 0; localView2.setVisibility(j); } localView3 = localView1.findViewById(2131427446); if (localView3 != null) { if (!paramBoolean) { break label68; } } } for (;;) { localView3.setVisibility(i); return; label62: j = i; break; label68: i = 0; } } private int Hw(String paramString) { for (int i = 0;; i++) { if (i >= this.j6.size()) { i = -1; } while (v5(i).d_().equals(paramString)) { return i; } } } private void Sf() { postDelayed(new Runnable() { public void run() { AIDEEditorPager.DW(AIDEEditorPager.this).v5(); } }, 50L); }
这么乱的代码,想找到自己想要的代码真是不容易。但是有一点不可能变的是,函数之间的调用关系是不变的。
比如AIDEEditorPager和MainActivty之间有几个混淆的类,有时一个功能会有几十个方法调用,但是只要猜解关键方法的功能,其他的根据效果进行分析,基本上8,9不离十。
方法唯一的标志就是参数。可能一个类会有几个j6(。。。)这样的方法,但是他们的参数类型都不是不同的。
如想提取actionbar tab的相关代码: 首先搜索MainActivity文件addTab 结果: public void j6(final String paramString) { if ((Build.VERSION.SDK_INT > 10) && (m.nw())) { ActionBar localActionBar = getActionBar(); final ActionBar.Tab localTab = localActionBar.newTab().setText(com.aide.ui.util.l.v5(paramString)); localActionBar.addTab(localTab, false); } } 其实看以看得出这个是一个addTab。 要找到谁是调用j6这个函数,首先找类中有没调用,找不到,就全文件搜索 一般先搜索哪里引用了MainActivity,找到AIDEEditorPager(当然可能有好几个引用了,这个看运气咯),如 private MainActivity ef() { return (MainActivity)getContext(); } 同样的找到调用ef()的, public rh DW(String paramString) { View localView = LayoutInflater.from(getContext()).inflate(2130903059, null); AIDEEditor localAIDEEditor = (AIDEEditor)localView.findViewById(2131427405); rh localrh = localAIDEEditor.j6(paramString); DW(true); ef().j6(paramString); Sf(); this.j6.add(localView); DW().FH(); return localrh; } 这个方法,首先,两个id可以找出相应的资源文件,从public.xml找到对应的id名,然后搜索相应的id名,个人用notepad++,在多文件中进行查找,第一个id,应该是一个布局文件(R.layout.xxx),第二个自然是一个view,不用说前面的暂时没什么影响,DW(true)暂时不解,ef().j6(paramString);就是了。 DW().FH()经查找是原来的getAdpter().notifyDataChanged(). Sf(),DW()暂时不解。 同理找出removetab(); 接着tab点击支持弹出菜单功能 在资源文件里面有个filetab_menu.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@id/editorMenuClose" android:title="Close" /> <item android:id="@id/filetabMenuCloseOthers" android:title="Close Others" /> <item android:id="@id/filetabMenuCloseAll" android:title="Close All" /> </menu> 从app里可以看到这三个菜单。找到filetab_menu的id,如
<public type="menu" name="filetab_menu" id="0x7f0a0004" />
十进制是2131361796,搜索全文件结果只找到一次,在MainActivity里。
this.j3 = new l(this, 2131361796);
找来找去找不到this.j3,或MainActivity.j3...
下面讲讲反编译代码相关的东西:
从程序使用效果就是弹出菜单onTabReselected,
public void j6(final String paramString) { if ((Build.VERSION.SDK_INT > 10) && (m.nw())) { ActionBar localActionBar = getActionBar(); final ActionBar.Tab localTab = localActionBar.newTab().setText(com.aide.ui.util.l.v5(paramString)); localTab.setTabListener(new ActionBar.TabListener() { public void onTabReselected(ActionBar.Tab paramAnonymousTab, FragmentTransaction paramAnonymousFragmentTransaction) { if (localTab == paramAnonymousTab) { MainActivity.j6(MainActivity.this).j6(MainActivity.j6(MainActivity.this, paramAnonymousTab), true); } }t public void onTabSelected(ActionBar.Tab paramAnonymousTab, FragmentTransaction paramAnonymousFragmentTransaction) { if ((localTab == paramAnonymousTab) && (!paramString.equals(j.tp().Hw()))) { j.tp().v5(paramString); } } public void onTabUnselected(ActionBar.Tab paramAnonymousTab, FragmentTransaction paramAnonymousFragmentTransaction) {} }); localActionBar.addTab(localTab, false); } }
MainActivity.j6(MainActivity.this).j6(
MainActivity.j6(MainActivity.this, paramAnonymousTab), true);
这一句MainActivity.j6(MainActivity.this)其实是调用MainActivity.j6();
MainActivity.j6(MainActivity.this, paramAnonymousTab)其实是使用了j6(ActionBar.Tab tab)这个原型
但第二个找到,第一个找不到MainActivity.j6();
private View j6(ActionBar.Tab paramTab) { return findViewById(2131427444); }
查找id,发现main.xml
<LinearLayout android:orientation="horizontal" android:id="@id/mainActionBarPopupAnchor" ...
从popup就可以看出这个弹出的区域。一下子全解了,之前一直不知道tab怎么可以popupmenu,因为popupmenu需要view,而这个popupAnchor正好是那个view
上文提到this.j3 = new l(this, 2131361796);
找来找去找不到this.j3,或MainActivity.j3...
突然想起匿名类[new ActionBar.TabListener(){...}] 取得主类[MainActivity]私有成员变量也是用方法(反汇编出来是调用主类的一个方法。
记得见过this$0,this$400()...与这些的道理是一样的。
那么是取得哪一个呢。j3是也。可能性很高。
从new l(this, 213...)找到l的源码。
public void j6(View paramView, boolean paramBoolean) { if (Build.VERSION.SDK_INT < 11) { j6(paramBoolean); return; } DW(); this.Hw = paramBoolean; PopupMenu localPopupMenu = new PopupMenu(this.DW, paramView); localPopupMenu.getMenuInflater().inflate(this.j6, localPopupMenu.getMenu()); j6(localPopupMenu.getMenu()); localPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem paramAnonymousMenuItem) { l.j6(l.this, paramAnonymousMenuItem); return true; } }); localPopupMenu.show(); }
MainActivity.j6(MainActivity.this).j6(
MainActivity.j6(MainActivity.this, paramAnonymousTab), true);
其实就是
View v = MainActivity.j6(tab);//int getFileTabMenu()
MainActivity.j3.j6(v, true); //l大概应该是FileTabMenu,这里的j6应该是showTabMenu(View anchor, boolean show);