Android逆向實例筆記—同步家教王及其升級版的破解

一朋友讓我來破解下一軟件,我拿來一看是這玩意。我以爲很難,結果發現沒殼。興趣就來了,弄了一天,就弄出來了。這裏把過程和思路分享一下。其實很簡單,大神一看就知道。因爲這個沒加殼,只是加了混淆的。

這算是我第一次破解玩玩整整的apk了

然後我們就開始吧。


一、工具

這次我用的是AndroidKiller,感覺很不錯的樣子

然後就是我每次都要用的藍疊


二、同步家教王

1.看情況

老規矩,還是先拖藍疊看看情況





隨便輸了123,出現了激活碼錯誤。我們記下來


2.反編譯

這個就不多說了,前面說的夠多了。直接拖進去,反編譯就OK。




3.修改

我們先去string.xml中沒有信息,然後轉碼搜索激活碼錯誤



我們跳過去,看看源碼。右鍵,查看-查看源碼


<span style="font-size:14px;">package com.school.app.activity.login;

import android.os.Handler;
import android.os.Message;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.school.app.utils.SharedPreHandler;

class LoginActivity$3
  extends Handler
{
  LoginActivity$3(LoginActivity paramLoginActivity, String paramString) {}
  
  public void handleMessage(Message paramMessage)
  {
    try
    {
      if (paramMessage.obj != null)
      {
        paramMessage = ((String)paramMessage.obj).split("&");
        if (paramMessage[0].equals("yes"))
        {
          SharedPreHandler.getShared().setSharedPreKey("activation_code", this.val$text);
          SharedPreHandler.getShared().setSharedPreKey("activation_deviceId", LoginActivity.access$1(this.this$0));
          SharedPreHandler.getShared().setSharedPreKey("activation_model", LoginActivity.access$2(this.this$0));
          if (paramMessage[1].equals("-1")) {}
          for (paramMessage = "激活成功";; paramMessage = String.format(LoginActivity.access$3(this.this$0), new Object[] { paramMessage[1], paramMessage[2] }))
          {
            SharedPreHandler.getShared().setSharedPreKey("activation_msg", paramMessage);
            LoginActivity.access$4(this.this$0);
            this.this$0.finish();
            return;
          }
        }
      }
      return;
    }
    catch (Exception paramMessage)
    {
      paramMessage.printStackTrace();
      this.this$0.title.setText("激活碼錯誤");
      this.this$0.back.setVisibility(0);
      this.this$0.exit.setVisibility(0);
      this.this$0.yes.setVisibility(8);
      this.this$0.clear.setVisibility(8);
      this.this$0.edit.setVisibility(8);
    }
  }
}
</span>

我們可以很容易的看到激活碼出錯的字樣。再來分析一下java代碼。

我們發現激活碼錯誤並沒有跳轉到這裏,但是之前的代碼卻有個 :cond_1跳轉這裏來。所以我們明顯知道是加了混淆的。

那我們只有從激活成功去看看下手了。

再次搜索




發現有兩處

剛剛這出看過了,我們去看看另一處的源碼


package com.school.app.service;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.widget.Toast;
import com.school.app.activity.login.LoginActivity;
import com.school.app.utils.CommTool;
import com.school.app.utils.SharedPreHandler;

public class TimeCountService
  extends Service
{
  private static final long sMinute = 1L;
  private Handler mHandler = new Handler()
  {
    public void handleMessage(Message paramAnonymousMessage)
    {
      try
      {
        if ((paramAnonymousMessage.obj != null) && (((String)paramAnonymousMessage.obj).contains("stop")))
        {
          SharedPreHandler.getShared().setSharedPreKey("activation_code", "");
          SharedPreHandler.getShared().setSharedPreKey("activation_msg", "");
          paramAnonymousMessage = new Intent();
          paramAnonymousMessage.setFlags(268435456);
          paramAnonymousMessage.setClass(TimeCountService.this, LoginActivity.class);
          TimeCountService.this.startActivity(paramAnonymousMessage);
        }
        return;
      }
      catch (Exception paramAnonymousMessage)
      {
        paramAnonymousMessage.printStackTrace();
      }
    }
  };
  private MyReceiver myReceiver;
  private long time;
  
  private void requestLoginInfo()
  {
    if (CommTool.isNetworkAvailable(this))
    {
      String str = SharedPreHandler.getShared().getSharedStrPreKey("activation_code", "");
      CommTool.getActivationCode(SharedPreHandler.getShared().getSharedStrPreKey("activation_deviceId", ""), SharedPreHandler.getShared().getSharedStrPreKey("activation_model", ""), str, this.mHandler);
    }
  }
  
  private void stopTimeCountService()
  {
    Intent localIntent = new Intent();
    localIntent.setClass(this, TimeCountService.class);
    stopService(localIntent);
  }
  
  public IBinder onBind(Intent paramIntent)
  {
    return null;
  }
  
  public void onCreate()
  {
    super.onCreate();
  }
  
  public void onDestroy()
  {
    super.onDestroy();
    if (this.myReceiver != null) {
      unregisterReceiver(this.myReceiver);
    }
  }
  
  public int onStartCommand(Intent paramIntent, int paramInt1, int paramInt2)
  {
    String str = SharedPreHandler.getShared().getSharedStrPreKey("activation_msg", "");
    if ((!str.equals("")) && (!str.equals("激活成功"))) {
      Toast.makeText(this, str, 1).show();
    }
    requestLoginInfo();
    return super.onStartCommand(paramIntent, paramInt1, paramInt2);
  }
  
  class MyReceiver
    extends BroadcastReceiver
  {
    MyReceiver() {}
    
    public void onReceive(Context paramContext, Intent paramIntent) {}
  }
}


這裏的話,我們還可以清晰看到激活的只是一個判斷,然後Toast出來的,那我們去修改前面那一處的跳轉試試。

在研究一下之前的源碼,發現很混亂。但是明確知道,有個地方會跳轉來驗證。

的確很混亂,我研究了半天,纔在這個地方破解出來。這個不寫出出來這個方法,因爲我自己也不是太清楚。我是自己不清楚,就絕不誤人子弟的,這裏大家可以自行嘗試。

這裏給大家就說另一個簡單點的。我想起來wnagzihxain大神寫的移動惡意APP分析的心得分享

於是想到了這個思路。

從入口去看看



其實這個工具挺好的,直接把入口寫這了,都不用我們去AndroidManifest.xml裏面找了
好吧,直接點過。看看源碼

package com.school.app.activity;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import com.school.app.activity.login.LoginActivity;
import com.school.app.service.TimeCountService;
import com.school.app.utils.SharedPreHandler;

public class MainActivity
  extends FragmentActivity
{
  private void startCountTimeService()
  {
    Intent localIntent = new Intent();
    localIntent.setClass(this, TimeCountService.class);
    startService(localIntent);
  }
  
  public boolean isActivationCode()
  {
    if (SharedPreHandler.getShared().getSharedStrPreKey("activation_code", "").equals(""))
    {
      Intent localIntent = new Intent();
      localIntent.setClass(this, LoginActivity.class);
      startActivityForResult(localIntent, 10085);
      return false;
    }
    startCountTimeService();
    return true;
  }
  
  protected void onActivityResult(int paramInt1, int paramInt2, Intent paramIntent)
  {
    if ((paramInt1 == 10085) && (paramInt2 == 10086)) {
      finish();
    }
    super.onActivityResult(paramInt1, paramInt2, paramIntent);
  }
  
  protected void onCreate(Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    setContentView(2130903040);
    isActivationCode();
  }
  
  protected void onRestart()
  {
    super.onRestart();
  }
}

仔細一看,這不太簡單了麼。大概意思就是跳過去驗證。這個時候,我們想到了,如果我們不去驗證,不就完了麼。
有了思路,就直接上手,找到地方。



就是這裏了,別問我是怎麼找到的,多看兩遍源碼。不廢話,改爲nez試試再說。

4.驗證
這裏就不多說了,修改完了保存。打開就直接沒有驗證了。

三、學習平臺(綜合版)
這個怎麼說呢,算我是投機取巧吧。因爲就上上面那個的升級版。更復雜。我估計要是沒有前面那個,後面這個我也許還不能弄出來呢。害羞
同樣找到跳轉驗證的地方,給修改掉。





還是改爲nez就OK了


此處,沒有太多的技術含量。寫這個的主要目的一是記記自己第一次破解完整的apk,然後就是寫點換個思路的方式。

最後給出兩個apk的下載地址:

https://yunpan.cn/cMeIDvXGmzBjP  訪問密碼 1603

https://yunpan.cn/cMeIpjDyebQPw  訪問密碼 2eae

最後需要這兩個破解的app的話,就去吾愛搜索吧,我把破解好的在吾愛發過帖子。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章