編輯:關於Android編程
在Android應用開發中,當我們開發完軟件之後,我們不希望別人能夠反編譯破解我們的應用程序,不能修改我們的代碼邏輯。實際上,在應用程序的安全機制考慮中,我們希望自己的應用程序安全性高,通過各種加密操作等來增大競爭對手的反編譯破解成本。設想,競爭對手開發一個同樣的應用程序需要10天,而破解我們的軟件程序需要100天,那麼勢必會打消黑客程序員破解我們應用程序的念頭。如何增加對手的破解成本,就需要考驗我們應用程序的安全性有多高,加密技術有多強。一個優秀的應用程序,不僅能為用戶帶來利益,同時也能保護自己的核心技術。
本文主要從以下幾個方面簡單介紹下Android應用程序的保護機制。
在上一篇文章中Android中的軟件安全和逆向分析[一]—apk反編譯破解以及java匯編代碼讀寫 裡面介紹了的大多數操作是Android裡的靜態反編譯破解apk文件。有些應用程序作了一些混淆,從SDK2.3開始我們可以看到在android-sdk-windows ools下面多了一個proguard文件夾,proguard是一個java代碼混淆的工具,具體介紹參考這篇博文,使的代碼邏輯比較復雜,此時我們如果還要靜態反編譯破解的話,就需要插入一些smali代碼動態的去調試觀察apk的邏輯。那麼如何保護自己的應用程序免受反編譯破解?我們需要阻止別的程序員反編譯,動態調試我的應用。換句話說,就是需要阻止黑客程序員安裝我的應用到模擬器上。
一種方式是不讓自己的應用程序運行在模擬器上,當應用程序發現自己安裝到模擬器上的時候就會自殺。
package com.example.cracktest;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
public class MainActivity1 extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (isEmulator()) {
// 立刻自殺,發現自己運行在模擬器上,趕緊自殺
android.os.Process.killProcess(android.os.Process.myPid());
}
setContentView(R.layout.activity_main);
}
/**
* 判斷應用程序是否運行在模擬器上
*
* @return
*/
public boolean isEmulator() {
// model:Android SDK built for x86
//只要是在模擬器中,不管是什麼版本的模擬器,在它的MODEL信息裡就會帶有關鍵字參數sdk
if (Build.MODEL.contains(sdk) || Build.MODEL.contains(SDK)) {
return true;
} else {
return false;
}
}
}
上述應用程序部署到真機上是可以運行的, 但是在模擬器上是打不開的,這樣就防止了黑客程序員動態調試我們的應用程序。
第二種保護應用程序的安全機制是檢測應用程序的完整性,我們可以用jni技術校驗應用程序的完整性,也可以利用數字簽名的方式來檢測應用程序的完整性。我們知道當一個apk文件被反編譯破解、修改完代碼邏輯之後,要使用jarsigner工具來重新給apk簽名,才能運行修改後的apk文件。一個應用程序的簽名,是識別一個開發者的唯一標識,如果一個應用程序被別人反編譯,那麼這個應用程序的簽名肯定會改變。當發現程序的簽名改變時,我們使之自殺就可以避免程序帶來損失。下面我們來介紹下數字簽名的方式檢測應用程序的完整性。
package com.example.cracktest;
import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
public class MainActivity2 extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println(getSignature());
}
/**
* 獲得應用程序的數字簽名
*
* @return
*/
public String getSignature() {
PackageManager pm = getPackageManager();
try {
// 得到當前應用程序的簽名
PackageInfo info = pm.getPackageInfo(getPackageName(),
PackageManager.GET_SIGNATURES);
return info.signatures[0].toCharsString();
} catch (NameNotFoundException e) {
e.printStackTrace();
return ;
}
}
}
上述簡單實例代碼獲取到的應用程序的數字簽名為,
任何一個對原apk的操作都會修改原apk的數字簽名,為了在程序中判斷方便,我們取數字簽名的MD5哈希值來判斷。
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">
package com.example.cracktest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5 {
/**
* 對字符串進行MD5加密
* @param content
* @return
*/
public static String getMD5(String content) {
try {
MessageDigest digest = MessageDigest.getInstance(MD5);
digest.update(content.getBytes());
return getHashString(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
private static String getHashString(MessageDigest digest) {
StringBuilder builder = new StringBuilder();
for (byte b : digest.digest()) {
builder.append(Integer.toHexString((b >> 4) & 0xf));
builder.append(Integer.toHexString(b & 0xf));
}
return builder.toString();
}
}
我們在應用程序運行時,判斷當前的數字簽名的MD5哈希值是否等於上述圖片中的哈希值,如果等於,合法運行,如果不等於,就能夠證明apk文件被反編譯破解過,這個時候我們1.5s後自殺程序。
package com.example.cracktest;
import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity2 extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println(getSignature());
// 正確的簽名信息為77e980cae813e5dacc11fdb4c67988fd
if (77e980cae813e5dacc11fdb4c67988fd.equals(getSignature())) {
Toast.makeText(this, 自校驗完畢,合法正常運行。, 0).show();
} else {
Toast.makeText(this, 你敢破解我的代碼!, 0).show();
new Thread() {
public void run() {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
android.os.Process.killProcess(android.os.Process.myPid());
};
}.start();
}
}
/**
* 獲得應用程序的數字簽名
*
* @return
*/
public String getSignature() {
PackageManager pm = getPackageManager();
try {
// 得到當前應用程序的簽名
PackageInfo info = pm.getPackageInfo(getPackageName(),
PackageManager.GET_SIGNATURES);
return MD5.getMD5(info.signatures[0].toCharsString());
} catch (NameNotFoundException e) {
e.printStackTrace();
return ;
}
}
}
具體的反編譯過程可以參見上一篇文章 Android中的軟件安全和逆向分析[一]—apk反編譯破解以及java匯編代碼讀寫 ,當反編譯apk,修改smali代碼,重新給apk簽名後,部署到模擬器上運行,發現1.5s後程序自殺。
檢測包名,版本名和版本號,然後做判斷,與檢測數字簽名方法大同小異。有興趣的可以自己研究研究。
應用程序的運行字節碼不在本地,而是在網絡端,就是說我們的應用程序的關鍵性核心代碼不要放在本地,應該放在網絡服務器端上。而在網絡端的字節碼如何獲取呢?我們通過URLClassLoader從服務器上把字節碼下載到本地,然後編譯運行。這種動態從網絡獲取字節碼的技術可以防止黑客程序員本地靜態的反編譯我們的應用程序。
開發程序員先做一個so的殼,當做應用程序的運行環境,殼裡面運行著我們的程序代碼,相當於在java虛擬機的上層加了一個代碼監視器。也可以說是在加密後的虛擬機裡運行我們的應用程序,增加了安全性。
一、首先,我們來看一下效果圖,這是新浪微博的Tab滑動效果。我們可以手勢滑動,也可以點擊上面的頭標進行切換。與此同方式, 白色橫條會移動到相應的頁卡頭標下。這是一個動
先給大家展示效果圖:package com.example.walkerlogin1; import android.app.Activity; import andro
一、什麼是相對布局相對布局是另外一種控件擺放的方式相對布局是通過指定當前控件與兄弟控件或者父控件之間的相對位置,從而達到相對的位置二、為什麼要使用相對布局相對於線性布局u
如何添加覆蓋物,實現周邊搜索,以及對覆蓋物的點擊出現介紹等效果。效果圖:我們的需求是,當用戶點擊衣食住行,或者對對附近搜索是,從服務器返回數據(經緯度,商家信息,介紹等)