Google MAP avec un fragment dynamique

android
Pour avoir Google Map dans son application, 4 étapes sont nécessaires :

  • Obtenir une clé pour utiliser l’API
  • Récupérer le Google Map service
  • Ajouter les informations nécessaires dans Google MAP
  • Implémenter le fragment dans l’application

Obtenir une clé pour utiliser l’API

Tout d’abord, il faut se connecter sur le site de Google API Console . Puis dans le menu gauche, il faut cliquer sur API Access et cliquer sur « Create New Android Key… ».

Nous avons besoin de récupérer l’empreinte de notre clé grâce au SHA1, pour cela il faut se placer dans le répertoire cd ~/.android/. C’est ici que se trouve votre clé debug.keystore.

keytool -list -v -alias androiddebugkey -keystore debug.keystore -storepass android -keypass android

Grâce a cette commande, on peut récupérer une empreinte du certificat. En l’occurrence, la ligne qui nous intéresse est celle avec clé SHA1.

Copier cette ligne sur le site de google API et ajouter à la fin un ; + le nom du package.

Cela va générer une API clé qu’il faudra utiliser dans votre manifest.

Note: : Pour définir le nom du package, il faut regarder dans votre manifest le package définit. En ce qui me concerne, j’ai choisi : fr.oversimple.applicationdemo

Récupérer le Google Map service

Afin d’utiliser Google Map, il faut télécharger la librairie : Google Play services via le Android SDK Manager
Google Play Services

Une fois le téléchargement effectué il faut l’ajouter comme librairie dans l’environnement de développement. Le répertoire se trouve dans extra/google/google_play_services . Pour Eclipse, il faut le déclarer comme une librairie (Clic droit sur le projet -> Properties -> Android -> Is Library) Puis pour le projet, au lieu de le déclarer comme librairie, il faut l’ajouter comme librairie.

En ce qui concerne Android studio (ou Intellij), il faut l’importer comme module.

Ajouter les informations nécessaires dans Google MAP

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="fr.oversimple.applicationdemo"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="19" />
 
    <permission
            android:name="fr.oversimple.applicationdemo.permission.MAPS_RECEIVE"
            android:protectionLevel="signature" />
 
    <uses-feature
            android:glEsVersion="0x00020000"
            android:required="true"/>
 
    <!-- Google map -->
    <uses-permission android:name="fr.oversimple.applicationdemo.permission.MAPS_RECEIVE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 
    <uses-permission android:name="android.permission.INTERNET" />
 
 
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.OrangeNoActionBar" >
        <activity android:name=".activities.MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <!-- https://code.google.com/apis/console/ -->
        <meta-data
                android:name="com.google.android.gms.version"
                android:value="@integer/google_play_services_version" />
        <meta-data
                android:name="com.google.android.maps.v2.API_KEY"
                android:value="Votre API KEY" />
    </application>
 
</manifest>

Implémenter le fragment dans l’application

Le XML correspondant map_main_activity.xml :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <com.google.android.gms.maps.MapView
            android:id="@+id/mapView"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"/>
</RelativeLayout>

Le code correspondant pour la map :

public class MapsFragment extends Fragment {
 
    private MapView map;
 
    public MapsFragment() {
    }
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.map_main_activity, container, false);
 
        if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity().getApplicationContext()) == ConnectionResult.SUCCESS) {
 
            //Initialze mapview
            MapsInitializer.initialize(getActivity());
 
            map = (MapView) view.findViewById(R.id.mapView);
            map.onCreate(savedInstanceState);
 
            GoogleMap gMap = map.getMap();
            gMap.addMarker(new MarkerOptions().title("title").snippet("description").position(new LatLng(49.5594950, -1.8414880))).showInfoWindow();
 
        } else {
            Toast.makeText(getActivity(), "Please install google play services", Toast.LENGTH_LONG).show();
        }
        return view;
    }
 
    @Override
    public void onResume() {
        super.onResume();
        map.onResume();
    }
 
    @Override
    public void onPause() {
        super.onPause();
        map.onPause();
    }
 
    @Override
    public void onDestroy() {
        super.onDestroy();
        map.onDestroy();
    }
 
    @Override
    public void onLowMemory() {
        super.onLowMemory();
        map.onLowMemory();
    }
}

Pour appeler le fragment, l’id content frame correspond à mon cœur d’application. En l’occurrence, je l’ai utilisé avec le navigation drawer d’Android afin d’avoir un menu sur la gauche.

mapFragment = new MapsFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, mapFragment).commit();

Ce fragment de Google Map peut être remplacé facilement par un autre fragment.

It’s oversimple, isn’t it?

Un peu de Volley sous Android!

android
Pour ceux qui ne connaisse pas Volley, c’est LE Framekwork de communication réseau.

Pour commencer, voici une trés bonne vidéo de présentation réalisée par Ficus Kirkpatrick .

L’article ci-dessous permet de faire une introduction à l’utilisation Volley.

Si vous n’avez pas regardé la vidéo, vous allez me dire, il existe déjà plusieurs framework réseau sous Android, pourquoi utiliser un autre framework?

A ma connaissance, il existe 2 possibilités de framework sous Android, afin de faire du HTTP. Le premier est Apache HTTP Client, c’est celui-ci que j’utilisais avant de découvrir Volley. Mais comme vous le savez sans doute, Apache HTTP Client possède des bugs et celui-ci n’est pas forcement maintenu par l’équipe Android.
La seconde API est HttpURLConnection que je n’ai jamais utilisé mais celle-ci possède des bugs.

Pour chacun de ces 2 frameworks, il faut rédefinir des Thread afin de ne pas rester dans le main thread. Cela impliquait l’utilisation des Asynctask.

Volley permet de s’abstenir de toute cette couche. C’est facile, puissant et rapide! De plus, celui-ci possède un cache mémoire ou disque.

C’est bien beau, mais comment ça fonctionne?

Son fonctionnement est aussi simple, il possède une queue que l’on doit initialiser UNE fois  (cette initialisation est assez coûteuse en performance). Ensuite, on ajoute dans cette queue les REQUETES que l’on doit effectuer. Le reste est géré par Volley.

Et comment on l’utilise?

Tout d’abord, il faut penser à mettre le user permission Internet dans le manifest d’Android :

<uses-permission android:name="android.permission.INTERNET" />

Puis, il faut récupérer le JAR ou le projet:

git clone https://android.googlesource.com/platform/frameworks/volley
cd volley
android list targets #Choisir l'ID pour la compilitation du JAR
android update project -p . --target ID_DE_TARGETS
ant jar

Une fois le JAR généré, il faut le placer dans le répertoire libs de votre projet. (Penser à l’ajouter au classpath en faisant clic droit add as library)

pour la création de la QUEUE,  je considère que l’on en a besoin partout dans notre Application donc on l’initialise qu’une fois. Cette initialisation est faite dans le contexte de l’application (extends Application) :

public class IntroApplication extends Application {
    private RequestQueue volleyRequestQueue;
 
    @Override
    public void onCreate() {
        super.onCreate();
        volleyRequestQueue = Volley.newRequestQueue(this);
        volleyRequestQueue.start();
    }
 
    @Override
    public void onTerminate() {
        volleyRequestQueue.stop();
        super.onTerminate();
    }
 
    public RequestQueue getVolleyRequestQueue() {
        return volleyRequestQueue;
    }
}

Vu que l’on extends Application, il faut penser à l’ajouter dans le manifest dans l’ application android:name= ».IntroApplication ».

Une fois cette initialisation faite, c’est bon, on peut travailler avec Volley. Il existe plusieurs type de Request dans Volley, String, JSONObject, JSONArray etc… (on peut bien sûr extends Request)

Un exemple avec String:

        StringRequest stringRequest = new StringRequest("url",new Response.Listener<String>() {
            @Override
            public void onResponse(String s) {
                Log.d("MainActivity","On doit traiter ici la reponse : " + s);
            }
        },new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Log.d("MainActivity","On doit gérer ici l'erreur");
            }
        });

En ce qui concerne les deux listener(la réponse et l’erreur), il faut implémenter les interfaces : Response.Listener et Response.ErrorListener.
Une fois que notre stringRequest est géré, il faut l’ajouter dans la Queue.

IntroApplication introApplication = (IntroApplication) getApplication();
mVolleyRequestQueue = introApplication.getVolleyRequestQueue();
mVolleyRequestQueue.add(stringRequest);

Cette exemple est valable pour String mais il fonctionne tout aussi bien avec les JsonObjectRequest, JsonArrayRequest. Il faut aussi remplacer les types des listener par JSONObject ou bien JSONArray.

En ce qui concerne les images au lieu d’utiliser les ImageView, nous allons utiliser les Images pour Volley, c’est à dire NetworkImageView (com.android.volley.toolbox.NetworkImageView). Cette modification doit être effectuée au niveau du XML et ainsi au niveau des CAST pour utiliser un objet de type NetworkImageView au lieu d’un ImageView.
Il faut également ajouter dans le contexte de l’application, le chargement des images.
mVolleyImageLoader = new ImageLoader(mVolleyRequestQueue, new BitmapLruCache());
Avant le start de volley request start de préférence.

Le XML:

    <com.android.volley.toolbox.NetworkImageView
            android:id="@+id/monImage"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_launcher"/>

BitmapLruCache :

public class BitmapLruCache extends LruCache&lt;String, Bitmap&gt; implements ImageLoader.ImageCache {
 
    /**
     * @param maxSize for caches that do not override {@link #sizeOf}, this is
     *                the maximum number of entries in the cache. For all other caches,
     *                this is the maximum sum of the sizes of the entries in this cache.
     */
    public BitmapLruCache(int maxSize) {
        super(maxSize);
    }
 
    public BitmapLruCache() {
        this(getDefaultLruCacheSize());
    }
 
    public static int getDefaultLruCacheSize() {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;
        return cacheSize;
    }
 
    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }
 
    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }
 
    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
}

Un exemple d’utilisation, super simple:

NetworkImageView networkImageView = (NetworkImageView) findViewById(R.id.monImage);
networkImageView.setImageUrl("lienDeLimage",mVolleyImageLoader);

Et si on désire passer des paramètres? Sans problème, il faut juste extends Request et redéfinir la méthode getParams (Hasmap de String/String).
Un exemple est présent dans l’archive ci-jointe : JSONParams

HashMap<String,String> map = new HashMap<String,String>();
map.put("UnParametre","laValeurDuParametre");
JSONParams jsonParams = new JSONParams("url",map,this,this);
mVolleyRequestQueue.add(jsonParams);

Et si on souhaite annuler une requête dans la QUEUE?
Super simple, il faut sur chaque Request mettre un setTag afin de pouvoir les identifier. Une fois identifiée, il faudra juste annuler celle que l’on désire:
Par exemple, si je reprends l’exemple de stringRequest avant de l’ajouter dans la queue, j’effectue un setTag

stringRequest.setTag("identifiantDeMaStringRequest");
mVolleyRequestQueue.add(stringRequest);
mVolleyRequestQueue.cancelAll("identifiantDeMaStringRequest");

Vous pouvez télécharger l’archive ici.

It’s Oversimple, isn’t it?

Apple store sans carte bancaire!

Dans le cadre de mon travail, je dois utiliser un mac. Pour cela, mon chef a du me créer un compte pour pouvoir accéder à l’Apple Store. Une fois le compte créé, je me connecte afin de télécharger xcode. Cependant, Apple me demande de valider mon compte, ce que je fais jusqu’au moment où je suis resté bloqué sur l’écran de saisie de ma carte bancaire… J’ai donc voulu contourner cet écran mais impossible de le faire directement, il demande forcement une carte bancaire!

Après plusieurs recherches sur internet, j’ai pu trouver une combine sur un forum. Cette combine nous oblige a passer via iTunes.

iTunesUtiliserUnCode

Il faut cliquer sur « Utiliser un code » sans être connecté. C’est à ce moment là que l’on doit s’authentifier et suivre la procédure de vérification. Une fois cette procédure terminée, on peut retourner sur l’Apple Store qui nous demandera de faire une vérification. Cette fois-ci, notre numéro de carte bancaire ne nous sera pas demandé.

Merci Apple!

It’s Oversimple, isn’t it?

Point d’accès wifi avec un Raspberry Pi

raspberry-ban

Nous avons récemment eu besoin d’avoir un point d’accès sur le Raspberry Pi. Cet article a pour but de faire un petit rappel lorsque l’on va en avoir de nouveau besoin!

Tout d’abord, nous allons commencer par installer le firmware pour le dongle USB :

apt-get install zd1211-firmware

Petite erreur que j’avais avec un freeze du raspberry (dmesg) :

[   43.500170] usb 1-1.3: Could not load firmware file zd1211/zd1211b_ub. Error number -2
[   43.500204] zd1211rw 1-1.3:1.0: couldn't load firmware. Error number -2

Une fois le dongle USB installé sur notre raspberry pi, on configure le serveur DHCPD sur l’interface wifi.

sudo apt-get install isc-dhcp-server
sudo vi /etc/dhcp/dhcpd.conf
sudo ifconfig wlan0 192.168.3.1 netmask 255.255.255.0
sudo /etc/init.d/isc-dhcp-server start

Dans mon cas, j’ai choisi de mettre comme adresse sur notre interface wifi 192.168.3.1

Pour faire le hostspot wifi, j’ai choisi hostapd

sudo apt-get install hostapd
sudo vi /etc/hostapd/hostapd.conf

La configuration est la suivante :

# Configuration récupère sur http://doc.ubuntu-fr.org/hostapd
# interface wlan du Wi-Fi
interface=wlan0
 
# nl80211 avec tous les drivers Linux mac80211
driver=nl80211
 
# Nom du spot Wi-Fi
ssid=oversimple
 
# mode Wi-Fi (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g)
hw_mode=g
 
# canal de fréquence Wi-Fi (1-14)
channel=8
 
#WPA2-PSK-CCMP
wpa=2
wpa_passphrase=oversimple
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP
rsn_pairwise=CCMP
 
# Beacon interval in kus (1.024 ms)
beacon_int=100
 
# DTIM (delivery trafic information message)
dtim_period=2
 
# Maximum number of stations allowed in station table
max_num_sta=255
 
# RTS/CTS threshold; 2347 = disabled (default)
rts_threshold=2347
 
# Fragmentation threshold; 2346 = disabled (default)
fragm_threshold=2346

On peut exécuter hostapd :

hostapd -d /etc/hostapd/hostapd.conf

Cependant, si l’on désire avoir notre point d’accès wifi au démarrage du raspberry , il faut configurer l’interface wifi avec une IP Fixe :

vi /etc/network/interfaces
 
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.3.1
netmask 255.255.255.0

On édite le fichier de config pour le démarrage de hostapd:

 sudo vi /etc/default/hostapd

Le contenu :

allow-hotplug wlan0
iface wlan0 inet static
address 192.168.3.1
netmask 255.255.255.0

On édite dans le fichier /etc/default/hostapd afin de pouvoir sélectionner la configuration requise :

DAEMON_CONF="/etc/hostapd/hostapd.conf"

Puis on active le tout au démarrage :

sudo update-rc.d hostapd enable
sudo update-rc.d isc-dhcp-server enable

Si vous avez besoin que le raspberry fasse une passerelle, il faut activer l’ip forwarding afin que les 2 interfaces(eth0 & wlan0) puissent communiquer.

It’s Oversimple, isn’t it?

Installation d’un Web Services sous Eclipse

Cet article va traiter uniquement de l’installation du Web Service. Un prochain article présentera le fonctionnement entre un Android et le Web Service.

Vous devez déjà avoir installé un serveur Tomcat. (J’ai écrit un article ici)

On utilisera comme web service le Apache Axis2.

La définition de Wikipédia :

Apache Axis2 is a core engine for Web services. It is a complete re-design and re-write of the widely used Apache Axis SOAP stack. Implementations of Axis2 are available in Java and C.

Axis2 not only provides the capability to add Web services interfaces to Web applications, but can also function as a standalone server application.

On va commencer par le télécharger ici

La dernière version pour moi est actuellement : 1.6.2 Release

On décompresse l’archive dans le répertoire /opt/ (et on met les droits utilisateurs)

$ unzip axis2-1.6.2-bin.zip
$ chown -R pierre:pierre axis2-1.6.2

Une fois l’archive décompressée, on va dans Eclipse :
Window > Preferences > Web Services > Axis2 Preferences.

On sélectionne le chemin où on a extrait notre archive : /opt/axis2-1.6.2
Et si tout va bien on a : Axis2 runtime loaded successfully

Après on va dans Server and Runtime (toujours dans Window > Preferences > Web Services).

On choisit notre serveur Tomcat avec la version désirée et on le met en Web Service : Apache Axis2

L’installation du Web Service est fonctionnel.

Création d’un projet pour tester notre Web Service.

File > New > Dynamic Web Project

On sélectionne la version du module à 2.5 Car la version 3.0 n’est pas compatible avec Axis2.

On va modifier notre configuration afin d’ajouter Axis2 Web Services (Core et Extensions).

Ci-dessous la configuration a réaliser :
ConfigurationAxis2WS

Si vous désirez pour les prochaines fois vous pouvez créer une configuration dédiée en cliquant sur « Save as ».

On peut cliquer sur terminer.

Je vais créer une classe Login qui aura une méthode login et prendra deux paramètres (un nom et mot de passe).

Voici le code :

public class Login {
 
	public String login(String username, String password){
		System.out.println("Appel WS : " + username +" "+ password);
		if(username.equals("oversimple") &amp;&amp; password.equals("oversimple")){
			return "Mot de passe OK";
		}
		return "Mot de passe KO";
	}
}

Une fois la classe créée, clic droit dessus > Web Services > Create Web Service :
On laisse la configuration par défaut c’est à dire :
Service implementation : Login et on laisse à l’état démarré
Client type : Java Proxy et on laisse à aucun client.

On termine. Il faut patienter environ une minute.

Notre serveur est démarré : On peut allé sur la page suivante : http://localhost:8080/Oversimple/ et cliquer sur « Services »
On peut voir notre service :
Axis2

On a un web service qui fonctionne, dans un prochain article je vais vous présenter le fonctionnement avec Android (ksoap2).

Installation du Serveur Apache Tomcat avec Eclipse

Avec Julien, on avait besoin besoin d’un serveur Tomcat pour notre Eclipse.

Pour ça on a besoin :

  • Un Eclipse Java EE (Disponible en téléchargement ici | Choisir Eclipse IDE for Java EE Developers )
  • Un Serveur Apache Tomcat (Disponible en téléchargement ici | Rubrique Download et choisir la version)

On se retrouve donc avec une archive Eclipse Java EE et une archive pour le serveur tomcat.

J’ai effectué l’installation sous Linux mais le principe est identique sous Windows.

On commence par extraire l’archive tomcat dans le repertoire /opt:
Si ZIP :

cd /opt && unzip apache-tomcat-7.0.39.zip

Si TAR.GZ :

 tar xzvf apache-tomcat-7.0.39.tar.gz -C /opt

Attention : Il faut que votre archive soit avec les droits de l’utilisateur et non les droits root. (sinon des problèmes apparaissent avec Eclipse).

On peut configurer notre serveur tomcat mais cela est optionnel pour le fonctionnement avec eclipse.
Cette étape est nécessaire quand on désire le déployer manuellement par exemple.

Le fichier de configuration est :

/opt/apache-tomcat-7.0.39/conf/tomcat-users.xml

J’ai ajouté les informations suivantes (entre les balises tomcat-users :

<role rolename="manager-gui"/>
<role rolename="admin-gui"/>
<user username="oversimple" password="oversimple" roles="admin-gui,manager-gui"/>

L’utilisateur est oversimple et son mot de passe est oversimple.

Pour démarrer tomcat il faut exécuter le script bin/startup.sh (ou .bat son Windows) et l’éteindre bin/shutdown.sh.

Après ce petit écart sur la configuration de tomcat, on va configurer notre eclipse.

On décompresse notre archive et puis on exécute le binaire Eclipse.

Une fois notre workspace choisi, il faut configurer pour la première fois notre serveur Tomcat.

Dans Eclipse :

Window > Preferences | Server > Runtime Environments

On ajoute un serveur (add) et on sélectionne un Apache Tomcat vX.0 (cela correspond à la version que vous avez téléchargé précédemment). Après avoir cliqué sur Next on sélectionne notre répertoire apache-tomcat. Dans mon cas : /opt/apache-tomcat-7.0.39

Après on sélectionne la vue Server. (Window > Show View > Other … Server).

On crée un nouveau serveur et on ajoute des projets JEE. Si aucun projet présent, on peut l’ajouter par la suite.

Pour l’ajouter par la suite, on effectue un clic droit sur notre serveur et « Add and Remove… ».

It’s oversimple isn’t it?

Désassembler une application Android (complément)

android

Cet article est un complément de celui de Julien.

Partons d’un APK Crackme01.apk. Le fichier est disponible ici.

Voici à quoi ressemble le Crack Me :
capture1Presentation

Deux methodes existent pour reverser une application android :

  1. La première avec dex2jar et jd-gui, cette méthode permet d’obtenir quasiment le code original, facile à analyser du code java et simple d’utilisation.Cependant avec cette méthode on ne peut pas modifier le code java (.class), nos ressources sont présentes sous la forme numérique uniquement dans les findviewbyid, par exemple.
  2. La seconde avec smali(assembleur) et baksmali(desassembleur), on retrouve ces outils dans apktool (d pour desassembler, b pour assembler).Lorsque l’on désassemble on obtient un code source smali, et on peut le réassembler. Une bible pour le code smali est présente ici : http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

 

Le but de ce crackme est de trouver le mot de passe pour la méthode 1.
Dans la seconde méthode, on ajoute un message rapide (Toasts) « Simple, non ? »

Methode 1 : Dex2jar et JD-GUI

On décompresse notre archive ZIP :

$ unzip Crackme01.apk 
Archive:  Crackme01.apk
  inflating: res/layout/activity_crack_me01.xml  
  inflating: res/menu/activity_crack_me01.xml  
  inflating: AndroidManifest.xml     
 extracting: resources.arsc          
 extracting: res/drawable-hdpi/ic_launcher.png  
 extracting: res/drawable-ldpi/ic_launcher.png  
 extracting: res/drawable-mdpi/ic_launcher.png  
 extracting: res/drawable-xhdpi/ic_launcher.png  
  inflating: classes.dex             
  inflating: META-INF/MANIFEST.MF    
  inflating: META-INF/CERT.SF        
  inflating: META-INF/CERT.RSA

Avant de continuer, on est obligé de vous parler de la machine Dalvik. Cette machine dalvik est une machine virtuelle utilisée par Android. Elle a été développée par Google pour ne pas utiliser la JVM. La différence notable avec la JVM est la gestion du registre. Pour la JVM, la gestion est basée sur la pile contrairement à la machine Dalvik qui est illimitée. Cette machine utilise un fichier .dex qui est le regroupement de l’ensemble des classes JAVA compilées.

Obtenons un jar de notre fichier .dex :
$ dex2jar classes.dex
dex2jar classes.dex -> classes-dex2jar.jar

Utilisons JD-GUI, afin de voir nos fichiers .class qui sont présents dans l’archive .JAR
jd-gui classes-dex2jar.jarjd-gui

Dans le fichier Crackme01.class on peut voir la ligne suivante :
final EditText localEditText = (EditText)findViewById(2131165185);

Cette ligne fait référence a un id, qui a pour intitulé motDePasse comme on peut le voir dans le fichier R.class :
public static final int motDePasse = 2131165185;

C’est l’EditText qui est utilisé pour saisir notre mot de passe.

On retourne dans le fichier Crackme01.class :

if ((localEditText.getText().toString() != null) &amp;&amp; (localEditText.getText().toString().equals("oversimple")))
          localToast.setText(2130968580);

On voit que l’on compare notre EditText avec une chaîne de caractère « oversimple ». Cette chaine de caractère « oversimple » est notre mot de passe.

Méthode 2 : Smali & backsmali

Pour la deuxieme méthode avec smali et backsmali, on utilisera apktool qui contient un ensemble d’outils. De plus, celui ci est simple d’utilisation alors pourquoi s’en priver ?

On décompile notre APK.

$ apktool d Crackme01.apk reverseCrackme01/
I: Baksmaling...
I: Loading resource table...
I: Loaded.
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/pierre/apktool/framework/1.apk
I: Loaded.
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Done.
I: Copying assets and libs...

On obtient un répertoire reverseCrackme01 :

$ cd reverseCrackme01/
$ ls   
AndroidManifest.xml  apktool.yml  res  smali

La premiere chose a regarder est le Manifest :

$ cat AndroidManifest.xml 
<!--?xml version="1.0" encoding="utf-8"?-->

On peut voir que notre main est le fichier CrackMe01 car celui-ci possède les intents nécessaires (MAIN et LAUNCHER)

Regardons maintenant les fichiers avec le code source smali :

$ ls smali/fr/oversimple/crackme01/
BuildConfig.smali  CrackMe01$1.smali  CrackMe01.smali  R$attr.smali  R$drawable.smali  R$id.smali  R$layout.smali  R$menu.smali  R$string.smali  R$style.smali  R.smali

Si on regarde dans le fichier CrackMe01\$1.smali, on peut voir la méthode onClick. Cette méthode correspond à un clic sur le bouton « Valider ». Voici un bref aperçu du code smali :

invoke-interface {v0}, Landroid/text/Editable;-&gt;toString()Ljava/lang/String;
move-result-object v0
const-string v1, "oversimple"
invoke-virtual {v0, v1}, Ljava/lang/String;-&gt;equals(Ljava/lang/Object;)Z
move-result v0

Ce bout de code permet de comparer notre mot de passe « oversimple » avec notre EditText(dans le but de simplifier, on affiche uniquement le retour du toString)

Et le test de comparaison final :

if-eqz v0, :cond_0
 
.line 29
iget-object v0, p0, Lfr/oversimple/crackme01/CrackMe01$1;-&gt;val$toast:Landroid/widget/Toast;
const v1, 0x7f040004
invoke-virtual {v0, v1}, Landroid/widget/Toast;-&gt;setText(I)V
 
.line 33
:goto_0
iget-object v0, p0, Lfr/oversimple/crackme01/CrackMe01$1;-&gt;val$toast:Landroid/widget/Toast;
invoke-virtual {v0}, Landroid/widget/Toast;-&gt;show()V
 
.line 34
return-void
 
.line 31
:cond_0
iget-object v0, p0, Lfr/oversimple/crackme01/CrackMe01$1;-&gt;val$toast:Landroid/widget/Toast;
const v1, 0x7f040005
invoke-virtual {v0, v1}, Landroid/widget/Toast;-&gt;setText(I)V
goto :goto_0

Si l’instruction if-eqz est égale à 0 alors nous allons à la condition cond_0. sinon on continue la suite donc .line 29.
Pour information, les valeurs qui nous intéressent se trouvent dans le fichier R$string.smali :
.field public static final ok:I = 0x7f040004
.field public static final ko:I = 0x7f040005

Le but de la deuxième méthode n’étant pas forcement de voir le mot de passe mais d’ajouter un message au démarrage de l’application.

Dans le fichier CrackMe01.smali, ligne 37 et après nous avons :

const-string v4, ""
 
const/4 v5, 0x1
 
invoke-static {v3, v4, v5}, Landroid/widget/Toast;-&gt;makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
 
move-result-object v1

Nous souhaitons juste ajouter notre message, donc à la place de «  » mettons : « Simple, non ? » et appelons la méthode afin de le rendre visible :
invoke-virtual {v1}, Landroid/widget/Toast;->show()V

Ce qui donne :

const-string v4, "Simple, non ?"
 
const/4 v5, 0x1
 
invoke-static {v3, v4, v5}, Landroid/widget/Toast;-&gt;makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
 
move-result-object v1
 
invoke-virtual {v1}, Landroid/widget/Toast;-&gt;show()V

On reconstruit l’application avec apktool b, il faut se placer dans le répertoire racineCrackme01 (ou ce trouve le fichier apktool.yml)

$ apktool b 
I: Checking whether sources has changed...
I: Smaling...
I: Checking whether resources has changed...
I: Building resources...
I: Building apk file...

Un nouveau repertoire apparait dist/

On crée une clé afin de signer notre application :
keytool -genkey -v -keystore oversimple.keystore -alias oversimple -keyalg RSA -validity 25000

Une fois la clé créée, on signe notre application :
jarsigner -digestalg SHA1 -sigalg MD5withRSA -verbose -keystore oversimple.keystore dist/Crackme01.apk oversimple

Notre apk est signée de source inconnu.

On envoie notre apk :

adb install dist/Crackme01.apk 
978 KB/s (184902 bytes in 0.184s)
	pkg: /data/local/tmp/Crackme01.apk
Success

Un article suivant présentera les commandes utiles de ADB.

Résultat au démarrage de notre APK :

resultatFinal

Conclusion

Pour cette introduction au reverse d’application Android, rien de bien difficile, plusieurs articles en tête, notammennt un article sur les commandes adb et les pouvoirs de cette commande 😉

Sources

dex2jar : http://code.google.com/p/dex2jar/
jd-gui : http://java.decompiler.free.fr/?q=jdgui
apktool : http://code.google.com/p/android-apktool/

It’s oversimple isn’t it?