Sunday, January 30, 2011

taintdroid code reading 3.

I read a diff of services/java/com/android/server/LocationManagerService.java.
It is almost the same as the diff of telephony. When location update message is received, the location is stored in Taint object as following:


location.setLatitude(Taint.addTaintDouble(location.getLatitude(), tag));

But I cannot understand the reason why obtained value is set again, that is, why setLatitude is called.
And the other point I cannot understand is that how to distinguish the values. For example, the below is a code to store latitude and location.

    location.setLatitude(Taint.addTaintDouble(location.getLatitude(), tag));
    location.setLongitude(Taint.addTaintDouble(location.getLongitude(), tag));

where tag is given here as following:

    int tag = Taint.TAINT_LOCATION;
    if (LocationManager.GPS_PROVIDER.equals(provider)) {
        tag |= Taint.TAINT_LOCATION_GPS;
    }
    if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
        tag |= Taint.TAINT_LOCATION_NET;
    }

Latitude and Longitude are added by addTaingDouble, but I cannot see how to distinguish latitude and longitude.
I paste the whole diff below.


diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index bbb43d7..4a5846a 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -68,6 +68,10 @@ import com.android.internal.location.LocationProviderProxy;
 import com.android.internal.location.MockProvider;
 import com.android.internal.location.GpsNetInitiatedHandler;
 
+// begin WITH_TAINT_TRACKING
+import dalvik.system.Taint;
+// end WITH_TAINT_TRACKING
+
 /**
  * The service class that manages LocationProviders and issues location
  * updates and alerts.
@@ -1526,6 +1530,30 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                         Location location = (Location) msg.obj;
                         String provider = location.getProvider();
 
+   // begin WITH_TAINT_TRACKING
+   int tag = Taint.TAINT_LOCATION;
+   if (LocationManager.GPS_PROVIDER.equals(provider)) {
+       tag |= Taint.TAINT_LOCATION_GPS;
+   }
+   if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
+       tag |= Taint.TAINT_LOCATION_NET;
+   }
+   location.setLatitude(Taint.addTaintDouble(location.getLatitude(), tag));
+   location.setLongitude(Taint.addTaintDouble(location.getLongitude(), tag));
+   if (location.hasAltitude()) {
+       location.setAltitude(Taint.addTaintDouble(location.getAltitude(), tag));
+   }    
+   if (location.hasSpeed()) {
+       location.setSpeed(Taint.addTaintFloat(location.getSpeed(), tag));
+   }    
+   if (location.hasBearing()) {
+       location.setBearing(Taint.addTaintFloat(location.getBearing(), tag));
+   }    
+   if (location.hasAccuracy()) {
+       location.setAccuracy(Taint.addTaintFloat(location.getAccuracy(), tag));
+   }    
+   // end WITH_TAINT_TRACKING
+
                         // notify other providers of the new location
                         for (int i = mProviders.size() - 1; i >= 0; i--) {
                             LocationProviderProxy proxy = mProviders.get(i);

Also, the diff of location/java/com/android/internal/location/GpsLocationProvider.java is almost the same handling as LocationManagerService.java, that is, when location updated message is received, the values are set in Taint object.

Next, I'll read the diff for media.

taintdroid code reading 2.

These are diffs for framework/base/telephony.

diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index a5188ce..78904c5 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -78,6 +78,10 @@ import java.net.Socket;
 import java.util.ArrayList;
 import java.util.List;
 
+// begin WITH_TAINT_TRACKING
+import dalvik.system.Taint;
+// end WITH_TAINT_TRACKING
+
 /**
  * {@hide}
  */
@@ -1276,6 +1280,9 @@ public class GSMPhone extends PhoneBase {
                 }
 
                 mImei = (String)ar.result;
+  // begin WITH_TAINT_TRACKING
+  Taint.addTaintString(mImei, Taint.TAINT_IMEI);
+  // end WITH_TAINT_TRACKING
             break;
 
             case EVENT_GET_IMEISV_DONE:

This diff is to store IMEI number to Taint object. Taint.addTaintString(mImei, Taint.TAINT_IMEI); is called in public void setMsisdnNumber(String alphaTag, String number, Message onComplete).


diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index d711a80..6beee1b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -38,6 +38,9 @@ import com.android.internal.telephony.MccTable;
 
 import java.util.ArrayList;
 
+// begin WITH_TAINT_TRACKING
+import dalvik.system.Taint;
+// end WITH_TAINT_TRACKING
 
 /**
  * {@hide}
@@ -236,6 +239,9 @@ public final class SIMRecords extends IccRecords {
             Message onComplete) {
 
         msisdn = number;
+ // begin WITH_TAINT_TRACKING
+ Taint.addTaintString(msisdn, Taint.TAINT_PHONE_NUMBER);
+ // end WITH_TAINT_TRACKING
         msisdnTag = alphaTag;
 
         if(DBG) log("Set MSISDN: " + msisdnTag +" " + msisdn);
@@ -488,6 +494,11 @@ public final class SIMRecords extends IccRecords {
                 }
 
                 imsi = (String) ar.result;
+  // begin WITH_TAINT_TRACKING
+  //if (imsi != null) {
+      //Taint.addTaintString(imsi, Taint.TAINT_IMSI);
+  //}
+  // end WITH_TAINT_TRACKING
 
                 // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
                 // than 15 (and usually 15).
@@ -617,6 +628,9 @@ public final class SIMRecords extends IccRecords {
                 adn = (AdnRecord)ar.result;
 
                 msisdn = adn.getNumber();
+  // begin WITH_TAINT_TRACKING
+  Taint.addTaintString(msisdn, Taint.TAINT_PHONE_NUMBER);
+  // end WITH_TAINT_TRACKING
                 msisdnTag = adn.getAlphaTag();

Summary

These changes stores IMEI, Phone number (ISDN) and ICCID in Taint object

Quesion

When are these values stored in Taint object?

Next, I'll read services/java/com/android/server/LocationManagerService.java.

taintdroid code reading 1.

I am curious how taintdroid track apps which use senseitive information.
Firstly, I check the diff between taintdroid and android.
According to TaintDroid Build Instructions, it modifies the source under dalvik/ and frameworks/base.

We can obtain the list of modified files by:

  git diff --name-only 0e9d568ec6b946e77bc0ec1903acac1ef916e6d1
for dalvik/, and
  git diff --name-only 562ac30bddb37b8bebeedfb035111dda41187332.
for framework/base.

The list for dalvik is too huge, is 456 files, so firstly we check one for framework/base.


README_TAINTDROID.txt
api/current.xml
cmds/servicemanager/Android.mk
cmds/servicemanager/binder.c
core/java/android/hardware/Camera.java
core/java/android/hardware/SensorManager.java
core/java/android/os/Parcel.java
core/jni/Android.mk
core/jni/android_util_Binder.cpp
include/binder/Parcel.h
libs/binder/Android.mk
libs/binder/Parcel.cpp
location/java/com/android/internal/location/GpsLocationProvider.java
media/java/android/media/AudioRecord.java
media/java/android/media/MediaRecorder.java
media/jni/Android.mk
media/jni/android_media_MediaRecorder.cpp
services/java/com/android/server/LocationManagerService.java
telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
telephony/java/com/android/internal/telephony/gsm/SIMRecords.java

Next, I'll check what changes were made in services and telephont.

repackage? android app

先日のblog articleで署名を突破できないという指摘を受けました。当然の指摘です。署名を検証するアプリケーション配布サイトですと問題はないのでしょう。
結局は自分が浅はかであることを実感してソースコードがないandroid アプリをいじることができるかどうか,試してみました。ただ,既に知られている情報をただ単に追っただけなので,新規情報量はないです。

参考

まずは,"Push Me"というボタンを押すと,Toastで"Hello World"というmessageを表示するアプリケーションを用意しました。


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button b = (Button)findViewById(R.id.Button01);
    }

    private class ButtonOnClickListener implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            if (v.getId() == R.id.Button01) {
                Toast.makeText(getApplicationContext(), "Hello World!", Toast.LENGTH_LONG).show();
            }
            
        }
    }

一方,"Push Me"というボタンを押すと,Toastで"Hello World"というmessageを表示すると同時に,call_log を読むアプリケーションを用意しました。同様に,キーとなるコード部分を下に記しておきます。

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button b = (Button)findViewById(R.id.Button01);
        b.setOnClickListener(new ButtonOnClickListener());
    }

    private class ButtonOnClickListener implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            if (v.getId() == R.id.Button01) {
                Toast.makeText(getApplicationContext(), "Hello World!", Toast.LENGTH_LONG).show();
                queryContentProvidersInfo();
            }
            
        }

        private void queryContentProvidersInfo() {
            String[] projections = new String[] {
                    CallLog.Calls._ID,
                    CallLog.Calls.NUMBER,
                    CallLog.Calls.TYPE,
                    CallLog.Calls.DURATION,
                    CallLog.Calls.DATE,
                    CallLog.Calls.CACHED_NAME,
            };
            
            Uri calls = CallLog.Calls.CONTENT_URI;
            ContentResolver cr = getContentResolver();
            Cursor c = cr.query(calls, projections, null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
            if (c != null) {
                getColumnData(c);
                c.close();
            }
        }

        private void getColumnData(Cursor c) {
            if (c.moveToFirst()) {
                String number;
                int numberColumn = c.getColumnIndex(CallLog.Calls.NUMBER);
                String cashed_name;
                int cashed_nameColumn = c.getColumnIndex(CallLog.Calls.NUMBER);
                do {
                    number = c.getString(numberColumn);
                    cashed_name = c.getString(cashed_nameColumn);
                    Log.d(TAG, "number: " + number);
                    if (cashed_name != null) {
                        Log.d(TAG, "cashed_name: " + cashed_name);
                    }
                } while (c.moveToNext());
            }
        }
    }

apkからbaksmaliを用いて,この部分の処理をdiassembleしたsmali型式コードを以下に貼り付けます。 単にmessageを表示する箇所。

# virtual methods
.method public final onClick(Landroid/view/View;)V
    .registers 5

    invoke-virtual {p1}, Landroid/view/View;->getId()I

    move-result v0

    const/high16 v1, 0x7f05

    if-ne v0, v1, :cond_9b

    iget-object v0, p0, Lcom/damburisoft/app/android/helloworld/a;->a:Lcom/damburisoft/app/android/helloworld/HelloWorldActivity;

    invoke-virtual {v0}, Lcom/damburisoft/app/android/helloworld/HelloWorldActivity;->getApplicationContext()Landroid/content/Context;

    move-result-object v0

    const-string v1, "Hello World!"

    const/4 v2, 0x1

    invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

    :cond_9b
    return-void
.end method

call_logを読む箇所。

# virtual methods
.method public final onClick(Landroid/view/View;)V
    .registers 10

    const/4 v3, 0x0

    const/4 v4, 0x1

    const-string v7, "ReadInfo"

    const-string v6, "number"

    invoke-virtual {p1}, Landroid/view/View;->getId()I

    move-result v0

    const/high16 v1, 0x7f05

    if-ne v0, v1, :cond_9b

    iget-object v0, p0, Lcom/damburisoft/android/app/readinfo/a;->a:Lcom/damburisoft/android/app/readinfo/ReadInfo;

    invoke-virtual {v0}, Lcom/damburisoft/android/app/readinfo/ReadInfo;->getApplicationContext()Landroid/content/Context;

    move-result-object v0

    const-string v1, "Hello World!"

    invoke-static {v0, v1, v4}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

    const/4 v0, 0x6

    new-array v2, v0, [Ljava/lang/String;

    const/4 v0, 0x0

    const-string v1, "_id"

    aput-object v1, v2, v0

    const-string v0, "number"

    aput-object v6, v2, v4

    const/4 v0, 0x2

    const-string v1, "type"

    aput-object v1, v2, v0

    const/4 v0, 0x3

    const-string v1, "duration"

    aput-object v1, v2, v0

    const/4 v0, 0x4

    const-string v1, "date"

    aput-object v1, v2, v0

    const/4 v0, 0x5

    const-string v1, "name"

    aput-object v1, v2, v0

    sget-object v1, Landroid/provider/CallLog$Calls;->CONTENT_URI:Landroid/net/Uri;

    iget-object v0, p0, Lcom/damburisoft/android/app/readinfo/a;->a:Lcom/damburisoft/android/app/readinfo/ReadInfo;

    invoke-virtual {v0}, Lcom/damburisoft/android/app/readinfo/ReadInfo;->getContentResolver()Landroid/content/ContentResolver;

    move-result-object v0

    const-string v5, "date DESC"

    move-object v4, v3

    invoke-virtual/range {v0 .. v5}, Landroid/content/ContentResolver;->query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;

    move-result-object v0

    if-eqz v0, :cond_9b

    invoke-interface {v0}, Landroid/database/Cursor;->moveToFirst()Z

    move-result v1

    if-eqz v1, :cond_98

    const-string v1, "number"

    invoke-interface {v0, v6}, Landroid/database/Cursor;->getColumnIndex(Ljava/lang/String;)I

    move-result v1

    const-string v2, "number"

    invoke-interface {v0, v6}, Landroid/database/Cursor;->getColumnIndex(Ljava/lang/String;)I

    move-result v2

    :cond_60
    invoke-interface {v0, v1}, Landroid/database/Cursor;->getString(I)Ljava/lang/String;

    move-result-object v3

    invoke-interface {v0, v2}, Landroid/database/Cursor;->getString(I)Ljava/lang/String;

    move-result-object v4

    const-string v5, "ReadInfo"

    new-instance v5, Ljava/lang/StringBuilder;

    const-string v6, "number: "

    invoke-direct {v5, v6}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V

    invoke-virtual {v5, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v3

    invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v3

    invoke-static {v7, v3}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

    if-eqz v4, :cond_92

    const-string v3, "ReadInfo"

    new-instance v3, Ljava/lang/StringBuilder;

    const-string v5, "cashed_name: "

    invoke-direct {v3, v5}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V

    invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v3

    invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v3

    invoke-static {v7, v3}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

    :cond_92
    invoke-interface {v0}, Landroid/database/Cursor;->moveToNext()Z

    move-result v3

    if-nez v3, :cond_60

    :cond_98
    invoke-interface {v0}, Landroid/database/Cursor;->close()V

    :cond_9b
    return-void
.end method

上記のsmali型式のコードを比較して,call_logの内容を読む処理を前者の単にToastでmessageを表示するアプリケーションに追加してみます。追加した結果のsmali型式ファイルは以下の通りです。

# virtual methods
.method public final onClick(Landroid/view/View;)V
    .registers 10

    const/4 v3, 0x0

    const/4 v4, 0x1

    const-string v7, "ReadInfo"

    const-string v6, "number"

    invoke-virtual {p1}, Landroid/view/View;->getId()I

    move-result v0

    const/high16 v1, 0x7f05

    if-ne v0, v1, :cond_1b

    iget-object v0, p0, Lcom/damburisoft/app/android/helloworld/a;->a:Lcom/damburisoft/app/android/helloworld/HelloWorldActivity;

    invoke-virtual {v0}, Lcom/damburisoft/app/android/helloworld/HelloWorldActivity;->getApplicationContext()Landroid/content/Context;

    move-result-object v0

    const-string v1, "Hello World!"

    const/4 v2, 0x1

    invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

    const/4 v0, 0x6

    new-array v2, v0, [Ljava/lang/String;

    const/4 v0, 0x0

    const-string v1, "_id"

    aput-object v1, v2, v0

    const-string v0, "number"

    aput-object v6, v2, v4

    const/4 v0, 0x2

    const-string v1, "type"

    aput-object v1, v2, v0

    const/4 v0, 0x3

    const-string v1, "duration"

    aput-object v1, v2, v0

    const/4 v0, 0x4

    const-string v1, "date"

    aput-object v1, v2, v0

    const/4 v0, 0x5

    const-string v1, "name"

    aput-object v1, v2, v0

    sget-object v1, Landroid/provider/CallLog$Calls;->CONTENT_URI:Landroid/net/Uri;

    iget-object v0, p0, Lcom/damburisoft/app/android/helloworld/a;->a:Lcom/damburisoft/app/android/helloworld/HelloWorldActivity;

    invoke-virtual {v0}, Lcom/damburisoft/app/android/helloworld/HelloWorldActivity;->getContentResolver()Landroid/content/ContentResolver;

    move-result-object v0

    const-string v5, "date DESC"

    move-object v4, v3

    invoke-virtual/range {v0 .. v5}, Landroid/content/ContentResolver;->query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;

    move-result-object v0

    if-eqz v0, :cond_1b

    invoke-interface {v0}, Landroid/database/Cursor;->moveToFirst()Z

    move-result v1

    if-eqz v1, :cond_18

    const-string v1, "number"

    invoke-interface {v0, v6}, Landroid/database/Cursor;->getColumnIndex(Ljava/lang/String;)I

    move-result v1

    const-string v2, "number"

    invoke-interface {v0, v6}, Landroid/database/Cursor;->getColumnIndex(Ljava/lang/String;)I

    move-result v2

    :cond_60
    invoke-interface {v0, v1}, Landroid/database/Cursor;->getString(I)Ljava/lang/String;

    move-result-object v3

    invoke-interface {v0, v2}, Landroid/database/Cursor;->getString(I)Ljava/lang/String;

    move-result-object v4

    const-string v5, "ReadInfo"

    new-instance v5, Ljava/lang/StringBuilder;

    const-string v6, "number: "

    invoke-direct {v5, v6}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V

    invoke-virtual {v5, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v3

    invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v3

    invoke-static {v7, v3}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

    if-eqz v4, :cond_92

    const-string v3, "ReadInfo"

    new-instance v3, Ljava/lang/StringBuilder;

    const-string v5, "cashed_name: "

    invoke-direct {v3, v5}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V

    invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v3

    invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v3

    invoke-static {v7, v3}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

    :cond_92
    invoke-interface {v0}, Landroid/database/Cursor;->moveToNext()Z

    move-result v3

    if-nez v3, :cond_60

    :cond_18
    invoke-interface {v0}, Landroid/database/Cursor;->close()V

    :cond_1b
    return-void
.end method

さて,この編集した.smaliファイルでclasses.dexをアセンブルして,HelloWorld.apkのclasses.dexに入れ替えます。
% java -Xmx1G -jar ~/lib/smali-1.2.6.jar -o classes.dex out
% zip ~/HelloWorldApp.apk classes.dex
classed.dexを入れ替えたHelloWorld.apkをもう一度署名しなおして,emulatorにインストールしてみました。実行した結果,SecurityExceptionが発生しました。

E/AndroidRuntime(  251): java.lang.SecurityException: Permission Denial: reading com.android.providers.contacts.CallLogProvider uri content://call_log/calls from pid=251, uid=10041 requires android.permission.READ_CONTACTS
E/AndroidRuntime(  251):  at android.os.Parcel.readException(Parcel.java:1247)
E/AndroidRuntime(  251):  at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:160)
E/AndroidRuntime(  251):  at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:114)
E/AndroidRuntime(  251):  at android.content.ContentProviderProxy.bulkQueryInternal(ContentProviderNative.java:330)
E/AndroidRuntime(  251):  at android.content.ContentProviderProxy.query(ContentProviderNative.java:366)
E/AndroidRuntime(  251):  at android.content.ContentResolver.query(ContentResolver.java:245)
E/AndroidRuntime(  251):  at com.damburisoft.app.android.helloworld.a.onClick(Unknown Source)
E/AndroidRuntime(  251):  at android.view.View.performClick(View.java:2408)
E/AndroidRuntime(  251):  at android.view.View$PerformClick.run(View.java:8816)
E/AndroidRuntime(  251):  at android.os.Handler.handleCallback(Handler.java:587)
E/AndroidRuntime(  251):  at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime(  251):  at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime(  251):  at android.app.ActivityThread.main(ActivityThread.java:4627)
E/AndroidRuntime(  251):  at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(  251):  at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime(  251):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
E/AndroidRuntime(  251):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
E/AndroidRuntime(  251):  at dalvik.system.NativeStart.main(Native Method)

AndroidManifest.xmlを編集していませんので,当然の結果です。ただ,Content Provider CallLogs.Callにアクセスする機能を追加できたのではないかと思われます。

今回は,パッケージに入っているクラスをsmali型式のファイルを通して編集することによって,動作を変更いたしましたが,編集ではなく新規にクラスを追加して実行させることも可能ではないのでしょうか。 いろいろと検索してみますと,disassembleしてアプリをハックする方法がいろいろとありますので,そんな難しいことではないのかもしれません。

Thursday, January 27, 2011

どのように,偽のandroid appをつくるのか?

GeiminiというAndroid OSを標的とした,Trojanの報告がある。
Lookout社のGeimini発見のレポート(Blog)

このTrojanは,として,第三者が運営するアプリ配布サイトで配布されている正規アプリの海賊版と一緒になって配布されている。
ここでは正規アプリの海賊版を簡単に作成できるかどうか考察してみたい。

Androidアプリケーションのリバースエンジニアリングより引用すると,

Androidアプリケーションのリバースエンジニアリングをする場合には、目的として「解析だけしたい」場合と、「解析した上で、さらに動作を自分好みに変更する」、つまりアプリケーションの改造までを行いたい場合があるだろう。前者の場合、JDによるJavaソースコード形式への(ときに不完全な)変換で十分な場合もあるだろう。この場合、読みにくいsmali形式のファイルと格闘する必要がないかもしれない。しかし後者、つまり改造までを行いたい場合、アプリケーション内の目的の箇所を自分の意図を達成するように書き換え、ふたたびAndroidアプリケーションとして動作するよう、正しくアセンブルしなおす必要がある。smaliはこれを可能にしてくれる。非常に精度が高いディスアセンブル・アセンブルが可能なので、classes.dex -> smali -> classes.dexという変換が可能なのだ。
つまり,既に apk ファイルから,classを解析して(dex2jar),ディスアセンブル(smali)して,再びclasses.dexを作成するツールが存在することを示している。
そこで,今回次のようなデモシナリオを提案する。
  • ボタンを押したら Toast Messageを表示するAndroid Appを作成する。
  • ボタンをクリックしたとき,その裏で,Identifyを読み取るコードを埋め込む。
  • 再びアセンブルしてパッケージを作成する。
  • この作業がどれだけ簡単かどうかは,後日考察してみたい。

    Monday, January 17, 2011

    Update PutYourMind to 1.2

    Update PutYourMind to version 1.2

    new feature
    add webpage title with url to your readitlater list.

    PutYourMindを1.2に更新いたしました。

    新規機能
    WebPageのURLをReadItLaterリストに追加する際に,そのページのtitleも一緒に登録するようにしました。

    Sunday, January 16, 2011

    PackageManager (ApplicationInfo)

    Android SDKには, PacageManagerという,デバイス上にインストールされたアプリケーションパッケージに関する情報を扱うクラスが提供されております。
    これで,どんな情報が取得できるか,試してみました。

    最初は, public abstract List getInstalledApplications (int flags)で得られるApplicationInfoにどんな情報が含まれているかについて調べてみました。

    
        @Override
        protected void onResume() {
            // TODO Auto-generated method stub
            super.onResume();
            mPackageManager = getPackageManager();
            getApplicationInfoList();
        }
    
        private void getApplicationInfoList() {
            List installedAppList = mPackageManager
                    .getInstalledApplications(PackageManager.GET_META_DATA | 
                            PackageManager.GET_SHARED_LIBRARY_FILES | 
                            PackageManager.GET_UNINSTALLED_PACKAGES);
            showApplicationInfos(installedAppList);
        }
    
        private void showApplicationInfos(List infos) {
            if (infos != null) {
                for (ApplicationInfo info : infos) {
                    showApplicationInfo(info);
                }
            }
        }
    
        private void showApplicationInfo(ApplicationInfo info) {
            if (info != null) {
                Log.d(TAG, "showApplicationInfo");
                Log.d(TAG, "className: " + info.className);
                Log.d(TAG, "packagename: " + info.packageName);
                Log.d(TAG, "name: " + info.name);
            }
        }
    
    
    

    結果は,こんな感じです。

    D/PkgInfoSampleAppActivity(20363): showApplicationInfo
    D/PkgInfoSampleAppActivity(20363): className: null
    D/PkgInfoSampleAppActivity(20363): packagename: com.sonyericsson.android.contentmanager.contentprovider.webmedia
    D/PkgInfoSampleAppActivity(20363): name: null
    D/PkgInfoSampleAppActivity(20363): showApplicationInfo
    D/PkgInfoSampleAppActivity(20363): className: null
    D/PkgInfoSampleAppActivity(20363): packagename: com.noshufou.android.su
    D/PkgInfoSampleAppActivity(20363): name: null
    D/PkgInfoSampleAppActivity(20363): showApplicationInfo
    D/PkgInfoSampleAppActivity(20363): className: null
    D/PkgInfoSampleAppActivity(20363): packagename: com.damburisoft.android.app.showmyicon
    D/PkgInfoSampleAppActivity(20363): name: null
    
    packagename は得られましたが,nameやclassNameはなぜかnullです。もっと詳細な情報を得るにはどうしたらいいか,引き続き課題です。

    Tuesday, January 11, 2011

    Update PutYourMind to 1.1

    Update PutYourMind to version 1.1

    new feature
    add webpage title with url to your readitlater list.

    PutYourMindを1.1に更新いたしました。

    新規機能
    WebPageのURLをReadItLaterリストに追加する際に,そのページのtitleも一緒に登録するようにしました。

    Sunday, January 09, 2011

    PutYourMind (android app)

    The 2nd. Android application made breaking out.

    This application catches an implicit intent, which data has a uri data. And put its uri data to your readitlater list.
    This application requires your readitlater account.

    Please search it on Android Market by PutYourMind, or use the following QR code.

    突発的に作成したアンドロイドアプリ第2弾。

    URIデータを含む暗黙的なインテントをキャッチして,そのデータをReadItLaterに追加します。

    Android Marketに公開しましたので, PutYourMindで検索するか,QRコードからダウンロードしてみてください。


    アイコンとアプリ名,なんかいいのがないかどうか募集です。

    Saturday, January 08, 2011

    ShowMyIcon (Android Application)

    When I went to a twitter off-line party, who present are a fan of Vegalta Sendai, it was a time to introduce oneself. Someone used a mobile phone to show her/his twitter's icon image to attendees. Though I used an Android phone, I didn't prepare my icon image to show them. So I create a simple application, ShowMyIcon, to show my twitter icon on Android phone.

    Just put your twitter's name.
    Then this application downloads your icon image file and stores it inside. Once you download, you can show it in without internet connections.

    This application does not require user authorization. So it is possible for spoofing.

    This application, ShowMyIcon is available from an android market.
    Please search by "ShowMyIcon" or access the following QR code: