Android Crackme分析

1.Crackme01

APKtools反編譯成smali代碼 定位到關鍵部位如下:

invoke-static {v1}, Lcom/google/youngandroid/runtime;->sanitizeComponentData(Ljava/lang/Object;)Ljava/lang/Object;
    move-result-object v1
    sget-object v2, Lappinventor/ai_garikoitzmartinez/crackme01/Screen1;->Lit35:Lgnu/math/IntNum; #V2=0x2E812
    invoke-static {v1, v2}, Lgnu/lists/LList;->list2(Ljava/lang/Object;Ljava/lang/Object;)Lgnu/lists/Pair;
    move-result-object v1
sget-object v2, Lappinventor/ai_garikoitzmartinez/crackme01/Screen1;->Lit36:Lgnu/lists/PairWithPosition;
    const-string v3, ">"
    invoke-static {v0, v1, v2, v3}, Lcom/google/youngandroid/runtime;->callYailPrimitive(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    move-result-object v0
    sget-object v1, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean; #v1=false
    if-eq v0, v1, :cond_0   #v0=v1  Ôòʧ°Ü  Sv0ҪΪÕæ
    sget-object v0, Lappinventor/ai_garikoitzmartinez/crackme01/Screen1;->Lit0:Lgnu/mapping/SimpleSymbol;
    invoke-static {v0}, Lcom/google/youngandroid/runtime;->lookupInCurrentFormEnvironment(Lgnu/mapping/Symbol;)Ljava/lang/Object;
    move-result-object v0
    sget-object v1, Lappinventor/ai_garikoitzmartinez/crackme01/Screen1;->Lit13:Lgnu/mapping/SimpleSymbol;
 
    const-string v2, "Crackme01!  << by deurus >> - Good boy!"    


如果是爆破的話,把False改成true即可。而我想的是分析下這個cm的算法,於是開始向上走起了。因爲v1False,所以v0要爲True

V0-->callYailPrimitive(,,,)返回過來的,找到這函數:

.method public static callYailPrimitive(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    .locals 3
    .parameter "prim"      對應V0 爲函數返回值
    .parameter "arglist" 對應V1
    .parameter "typelist" 對應V2 Lit36
.parameter "codeblocks$Mnname" 對應V3 = “>”


因此另外幾個參數也要知曉纔好分析,於是繼續往上看 v3= ‘>’,然後又繼續往上看,V2的值是Lit36V1的值是list2函數返回的。繼續追list2函數:

 

public static Pair list2(Object arg1, Object arg2) {
        return new Pair(arg1, new Pair(arg2, LList.Empty));
}
只是創建了兩個Pair類 ,繼續向上分invoke-static {v0, v1, v5, v2}, Lgnu/lists/PairWithPosition;->make(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;I)Lgnu/lists/PairWithPosition;
    move-result-object v0
    sput-object v0, Lappinventor/ai_garikoitzmartinez/crackme01/Screen1;->Lit36:Lgnu/lists/PairWithPosition;
    const v0, 0x2e812
    invoke-static {v0}, Lgnu/math/IntNum;->make(I)Lgnu/math/IntNum;
    move-result-object v0
    sput-object v0, Lappinventor/ai_garikoitzmartinez/crackme01/Screen1;->Lit35:Lgnu/math/IntNum;析:

 

可以找到V11個裝有2個成員的List,一個爲用戶自己輸入的。一個就是Lit35=0x2E812

V2是多少,通過上述的代碼賦給Lit36的值 以及callYailPrimitive函數中參數的定義,我想應該就是2int類型了。

再把這部分分析結果拿出來看一下:

.locals 3
    .parameter "prim"      對應V0 爲函數返回值  也是關鍵點
    .parameter "arglist" 2個參數  一個用戶輸入的  一個爲0x2e812
    .parameter "typelist" int int
.parameter "codeblocks$Mnname" 對應V3 = “>”


 

不妨大膽猜想一下,應該就是這2個數比大小吧。於是進去callYailPrimitive函數中分析了下,確實如此:


2.Crackme02

如果是爆破的話還是隻要改一個地方:

sget-object v1, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean;

 

if-eq v0, v1, :cond_2

FALSE 改成 TRUE 即可。註冊成功背景爲綠色:


還是老套路,安好程序看一看先,看是個什麼情況。發現了輸入name和序列號是不正確的情況下,背景會顯示爲紅色。然後用神器反編譯好smali,我們去看代碼,看看有什麼我們的新發現!
分析了一會smali之後,發現還是看着蛋疼,看看源碼吧:

 public Object Button1_check$Click() {
        O後面還有2個給大家玩吧~累 休息
總的來說主要提高了對smali代碼的熟練度~收穫還不錯,糾正了一些理解上的偏差和鞏固了之前的smali。(*^__^*) 


BY Ericky 
2014.12.6bject v0;
        String v7 = "+";
        String v5 = "";
        runtime.addToCurrentFormEnvironment(Screen1.Lit12, Screen1.Lit28);
        runtime.addToCurrentFormEnvironment(Screen1.Lit14, Screen1.Lit11);
        if(runtime.isYailEqual(runtime.sanitizeComponentData(Invoke.invoke.apply2(runtime.lookupInCurrentFormEnvironment(
                Screen1.Lit37), Screen1.Lit22)), v5) != Boolean.FALSE) {
            runtime.callComponentMethod(Screen1.Lit53, Screen1.Lit54, LList.list3("Please Enter the Name", 
                    "Error", "Ok"), Screen1.Lit55);
            runtime.$PcSetAndCoerceProperty$Ex(runtime.lookupInCurrentFormEnvironment(Screen1.Lit37), 
                    Screen1.Lit22, v5, Screen1.Lit20);
            v0 = runtime.$PcSetAndCoerceProperty$Ex(runtime.lookupInCurrentFormEnvironment(Screen1.Lit47), 
                    Screen1.Lit22, v5, Screen1.Lit20);
        }
        else {
            while(runtime.callYailPrimitive(Scheme.numLEq, LList.list2(runtime.lookupInCurrentFormEnvironment(
                    Screen1.Lit12), runtime.callYailPrimitive(strings.string$Mnlength, LList.list1(runtime
                    .sanitizeComponentData(Invoke.invoke.apply2(runtime.lookupInCurrentFormEnvironment(
                    Screen1.Lit37), Screen1.Lit22))), Screen1.Lit56, "length")), Screen1.Lit57, "<=")
                     != Boolean.FALSE) {
                runtime.addToCurrentFormEnvironment(Screen1.Lit10, runtime.callComponentMethod(Screen1
                        .Lit58, Screen1.Lit59, LList.list1(runtime.callComponentMethod(Screen1.Lit58, 
                        Screen1.Lit60, LList.Empty, LList.Empty)), Screen1.Lit61));
                runtime.addToCurrentFormEnvironment(Screen1.Lit14, runtime.callYailPrimitive(AddOp.$Pl, 
                        LList.list2(runtime.lookupInCurrentFormEnvironment(Screen1.Lit14), runtime.callYailPrimitive(
                        MultiplyOp.$St, LList.list2(runtime.lookupInCurrentFormEnvironment(Screen1.Lit10), 
                        runtime.lookupInCurrentFormEnvironment(Screen1.Lit12)), Screen1.Lit62, "*")), 
                        Screen1.Lit63, v7));
                runtime.addToCurrentFormEnvironment(Screen1.Lit14, runtime.callYailPrimitive(AddOp.$Pl, 
                        LList.list2(runtime.lookupInCurrentFormEnvironment(Screen1.Lit14), runtime.callYailPrimitive(
                        numbers.modulo, LList.list2(runtime.lookupInCurrentFormEnvironment(Screen1.Lit14), 
                        Screen1.Lit64), Screen1.Lit65, "modulo")), Screen1.Lit66, v7));
                runtime.addToCurrentFormEnvironment(Screen1.Lit12, runtime.callYailPrimitive(AddOp.$Pl, 
                        LList.list2(runtime.lookupInCurrentFormEnvironment(Screen1.Lit12), Screen1.Lit28), 
                        Screen1.Lit67, v7));
            }

            v0 = runtime.isYailEqual(runtime.sanitizeComponentData(Invoke.invoke.apply2(runtime.lookupInCurrentFormEnvironment(
                    Screen1.Lit47), Screen1.Lit22)), runtime.lookupInCurrentFormEnvironment(Screen1.
                    Lit14)) != Boolean.FALSE ? runtime.$PcSetAndCoerceProperty$Ex(runtime.lookupInCurrentFormEnvironment(
                    Screen1.Lit0), Screen1.Lit16, Screen1.Lit68, Screen1.Lit18) : runtime.$PcSetAndCoerceProperty$Ex(
                    runtime.lookupInCurrentFormEnvironment(Screen1.Lit0), Screen1.Lit16, Screen1.Lit69, 
                    Screen1.Lit18);
        }

        return v0;
    }
分析代碼後發現,開頭有2句比較關鍵。拿出開頭的兩句:
runtime.addToCurrentFormEnvironment(Lit12, Lit28);
runtime.addToCurrentFormEnvironment(Lit14, Lit11);
通過分析可以發現這裏給變量賦值了,所以繼續追蹤:
發現Lit12就是”tam_nombre”
 Screen1.Lit34 = IntNum.make(-2);
        Screen1.Lit33 = SimpleSymbol.valueOf("Width");
        Screen1.Lit32 = IntNum.make(3);
        Screen1.Lit31 = SimpleSymbol.valueOf("FontTypeface");
        Screen1.Lit30 = IntNum.make(14);
        Screen1.Lit29 = SimpleSymbol.valueOf("FontSize");
        Screen1.Lit28 = IntNum.make(1);
        Screen1.Lit27 = SimpleSymbol.valueOf("Alignment");
        Screen1.Lit26 = SimpleSymbol.valueOf("Label1");
        Screen1.Lit25 = new FString("com.google.devtools.simple.runtime.components.android.Label");
        Screen1.Lit24 = SimpleSymbol.valueOf("Initialize");
        Screen1.Lit23 = SimpleSymbol.valueOf("Screen1$Initialize");
        Screen1.Lit22 = SimpleSymbol.valueOf("Text");
        Screen1.Lit21 = SimpleSymbol.valueOf("lbl_rules");
        Screen1.Lit19 = SimpleSymbol.valueOf("Title");
        int[] v0_1 = new int[2];
        v0_1[0] = -14336;
        Screen1.Lit17 = IntNum.make(v0_1);
        Screen1.Lit16 = SimpleSymbol.valueOf("BackgroundColor");
        Screen1.Lit15 = SimpleSymbol.valueOf("nombre");
        Screen1.Lit14 = SimpleSymbol.valueOf("temp");
        Screen1.Lit13 = SimpleSymbol.valueOf("serial");
        Screen1.Lit12 = SimpleSymbol.valueOf("tam_nombre");
        Screen1.Lit11 = IntNum.make(0);
        Screen1.Lit10 = SimpleSymbol.valueOf("ano");
        Screen1.Lit9 = SimpleSymbol.valueOf("*the-null-value*");
        Screen1.Lit8 = SimpleSymbol.valueOf("getErrorType");
        Screen1.Lit7 = SimpleSymbol.valueOf("get");
        Screen1.Lit6 = SimpleSymbol.valueOf("show");
        Screen1.Lit5 = IntNum.make(5);
        Screen1.Lit4 = SimpleSymbol.valueOf("getMessage");
        Screen1.Lit3 = SimpleSymbol.valueOf("makeText");
        Screen1.Lit2 = Toast.class;
        Screen1.Lit1 = SimpleSymbol.valueOf("repl");
        Screen1.Lit0 = SimpleSymbol.valueOf("Screen1");

所以有:

tam_nombre = 1

temp = 0

 

如果用戶不輸入一個name的話,他會顯示出錯,“請輸入用戶名”。看下一個條件中的判斷語句,出現了一個numLEq,從字面上理解爲“小於等於”。

分析代碼發現其實判斷條件爲:

while(tam_nombre <= len(nombre))  即爲while(1<= len(nombre))

從這裏可以知道,name的長度至少要1位既可以滿足條件。

同樣的方法,我們繼續分析下一個判斷可以知道,計算出來的序列號儲存在temp中。

 

給出一組序列號:

UsernameEricky

Password47652

KeygenCode:

public class Keygen {

	public static void main(String[] args) {
		int namelength =args[0].length();
		// TODO Auto-generated method stub
		int tam_nombre = 1;
		int temp = 0;
		int ano = 2014;
		while(tam_nombre<=namelength )
		{
		temp += ano * tam_nombre;
		temp += temp % 1638;
		tam_nombre += 1;
		
		}
		System.out.println("Serial : "+temp);
	}

}

後面還有2個給大家玩吧~累 休息

總的來說主要提高了對smali代碼的熟練度~收穫還不錯,糾正了一些理解上的偏差和鞏固了之前的smali(*^__^*) 

 

BY Ericky 

2014.12.6



發佈了31 篇原創文章 · 獲贊 2 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章