標籤:
一、摘要
好長時間沒寫blog了,之前換了一家公司。表示工作更有戰鬥力了,可惜就是沒時間寫文章了。在這段時間其實是遇到很多問題的,只是都是記錄下來,並沒有花時間去研究解決。但是這周遇到這個問題沒辦法讓我繼續前進了。必須記錄一下。以被後人使用。不多說了,進入主題。
二、前提
1、對於GA的瞭解(自行google)
2、對CampaignTrackingReceiver類的瞭解,他是當從GP上下載並且安裝完成一個app的時候,發送一個廣播,會在Intent中攜帶一些資料,一般是Refer值,這裡可以區分從哪裡下載的,具體簡單的例子:A應用是我需要發布到GP上的應用,但是我們可能會在各個渠道上推廣A,所以我們可能需要加上渠道號進行統計,所以這時候需要在A應用添加CampaignTrackingReceiver廣播接收器,然後處理接收到的廣播中的Intent的內容,解析出具體的渠道號,進行上報即可。所以說GP發送這個廣播還是很奇特的,他發送了這個廣播,然後等我們安裝A並且運行了之後就可以接收到這個廣播,等於這個廣播發出去了,他會等待有一個接收器接受他。
3、本文中需要用到的工具:http://download.csdn.net/detail/jiangwei0910410003/8679153,下載完之後,首先要看一下txt文檔中的說明。
三、問題描述
工程中接入了GA統計(Google提供的一種app統計功能的SDK),但是我們自己可能需要統計app從GP上下載的統計(這裡一般是註冊一個CampaignTrackingReceiver的廣播),但是有問題就是GA的SDK中已經包含了CampaignTrackingReceiver類了,當時在弄的時候進入到了一個誤區:就是認為如果app中想接收到這個廣播的話。廣播接收器的包名必須是:com.google.analytics.tracking.android,類名:CampaignTrackingReceiver,類似於下面的註冊代碼:
<receiverandroid:name="com.google.analytics.tracking.android.CampaignTrackingReceiver"android:exported="true"><intent-filter> <action android:name="com.android.vending.INSTALL_REFERRER" /></intent-filter></receiver>
但是之後發現不需要這樣的,只要包名一樣即可,其實從Android中發送廣播的機制就可以知道。類名沒有關係的,但是當時這個東西沒辦法測試的(需要發布一個測試app到GP上,時間上也是不允許的,只能聽前輩的)。最後也是自己發布了一個測試app測試了才知道,不需要類名一樣的,這個也算是一種收穫,那麼既然類名不一樣的話,這裡就沒有問題了。就不會和GA中的類重複了。但是我在沒有解釋這個誤區前用了另外的一種方法解決了這個問題。既然GA中有這個廣播接收類,我們不能定義的話,可以在它的SDK中的這個廣播類中插入一段代碼:發送一個廣播,把Intent中的資料帶出來即可。思路有了,下面來看一下具體操作:
四、技術介紹
下面講述的內容是基於上面的誤區沒有被解釋的情況下說的,而且側重點也不是解釋誤區。而是如何修改Jar中內容
首先說一下這個過程中的三個角色:jar,dex,smali
四個工具:dx.bat,dex2jar.bat,baksmali.jar,smali.jar
關係圖如下:
我們這裡需要修改jar中的代碼,
首先說明一下,關於修改jar中的代碼其實有很多方法的:
1、直接用壓縮包工具開啟jar中的class檔案進行修改(除非你對指令集很熟悉,反正我是不願意嘗試)
2、使用jd-gui工具直接開啟jar,進行修改(這個雖然能看懂代碼,但是有一個問題就是如果代碼被混淆了,那個難度還不如第一種方法了,所以也沒有嘗試)
好吧,那麼第三種方法就是修改smali檔案,這個檔案的好處在於:指令簡單,而且如果混淆了,也是沒有關係的。關於smail的指令說明,可以自行google一下。很簡單這裡就不做解釋了。
那麼問題來了,如何將jar變成smali呢?這裡沒有發現他們兩之間的直接轉化工具,所以就曲線救國的方式做了。
首先將jar==>dex==>smali
然後修改smail中的內容
修改完之後會變成jar
smail==>dex==>jar
相當於dex是中轉站了。
五、項目示範
技術實現說明完之後,下面來看一下Demo:
ReceiverLib工程
1、BtnReceiver.java
package com.example.receiverdemo;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.util.Log;public class BtnReceiver extends BroadcastReceiver{private String action = "demo.action.myreceiver";@Overridepublic void onReceive(Context context, Intent intent) {Log.i("demo", "action:"+intent.getAction());}}接收到廣播然後列印log一下
2、MyReceiver.java
package com.example.receiverdemo;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.util.Log;public class MyReceiver extends BroadcastReceiver{private String action = "demo.action.myreceiver";@Overridepublic void onReceive(Context context, Intent intent) {Log.i("demo", "action:"+intent.getAction());}}
3、Utils.java
package com.example.receiverdemo;import android.content.Context;import android.content.Intent;public class Utils {public static void sendBroadcast(Context context,String action){Intent intent = new Intent();intent.setAction(action);context.sendBroadcast(intent);}}說明:BtnReceiver是點擊Button之後發送的一個類比廣播,相當於上面需要改的CampaignTrackingReceiver類,MyReceiver是我們需要自己添加的廣播接收器。
項目下載:http://download.csdn.net/detail/jiangwei0910410003/8679113
ReceiverDemo工程(需要匯入ReceiverLib匯出的jar)
package com.example.receiverdemo;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.View;import android.view.View.OnClickListener;public class MainActivity extends ActionBarActivity {private String action = "demo.action.btnreceiver";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.btn).setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {Utils.sendBroadcast(MainActivity.this, action);}});}}類比發送一個廣播
項目下載:http://download.csdn.net/detail/jiangwei0910410003/8679123
效果:
點擊Button之後,發送了廣播,BtnReceiver也接收到了。
那麼下面就開始在BtnReceiver.java中插入代碼,發送一個MyReceiver
首先使用dx命令,將我們上面ReceiverLib匯出的jar變成dex檔案:
dx命令的使用方式:dx --dex --output C:\receiver.dex receiver.jar
然後在將receiver.dex轉化成smali:
baksmali.jar的使用方式:java -jar baksmali-2.0.5.jar -o c:\classout/ c:\receiver.dex
我們可以查看smali檔案,我們重點看BtnReceiver.smali檔案,因為我們要在這裡插入代碼:
.class public Lcom/example/receiverdemo/BtnReceiver;.super Landroid/content/BroadcastReceiver;.source "BtnReceiver.java"# direct methods.method public constructor <init>()V .registers 1 .prologue .line 8 invoke-direct {p0}, Landroid/content/BroadcastReceiver;-><init>()V return-void.end method# virtual methods.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V .registers 7 .param p1, "context" # Landroid/content/Context; .param p2, "intent" # Landroid/content/Intent; .prologue .line 12 invoke-virtual {p2}, Landroid/content/Intent;->getAction()Ljava/lang/String; move-result-object v0 .line 13 .local v0, "action":Ljava/lang/String; const-string v1, "demo" new-instance v2, Ljava/lang/StringBuilder; const-string v3, "action:" invoke-direct {v2, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v2 invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v2 invoke-static {v1, v2}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I const-string v4, "demo.action.myreceiver" invoke-static {p1, v4}, Lcom/example/receiverdemo/Utils;->sendBroadcast(Landroid/content/Context;Ljava/lang/String;)V const-string v5, "sendbroadcast" invoke-static {v1, v5}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I .line 14 return-void.end method
關於smali指令網上自行搜尋,很簡單的,我們需要插入一行代碼就是:
Utils.sendBroadcast方法:
這個過程中沒有難度的,就不做解釋了
下面我們就需要還原成jar了:
使用smali.jar工具將samli變成dex
用法:java -jar smali-2.0.5.jar c:\classout/ -o c:\receiver.dex
然後使用dex2jar命令將dex變成jar
用法:dex2jar receiver.dex
這時候我們就產生了修改之後的jar,我們將這個jar替換ReceiverDemo中的jar,然後運行結果:
成功顯示了。我們的MyReceiver接收到了BtnReceiver中發送出來的廣播了。
問題:
在這個過程中可能使用一些命令的時候會出現問題:
這個是class版本號碼不對,需要修改一下Eclipse中的Java編譯器版本在編譯匯出jar就可以了。
其他的問題我這裡沒有遇到了。如果在開發的過程中遇到問題,記得回複留言,我盡量解答一下~~
六、總結
1、關於上面說到的問題,就是GA包中的類重複的問題,再次在說明一下,那個是個誤區,我們自定一個Receiver也是可以的,不需要類名必須是:CampaignTrackingReceiver,所以有同學如果用到這個類的話,一定要記得,不要在入這個誤區了。
2、關於修改jar中的內容,其實用途還是很多的,但是不是正規的解決方案,這個有點偏向於破解的方向了,這個是不符合開發原則的,這裡說明一下就是為了多一條解決問題的辦法,而且對逆向領域的一種知識補充,這個內容對逆向領域用處還是很大的。
3、關於這種方式使用與所有Java編寫的程式,這裡可能偏向於Android移動端了,但是如果JavaWeb中遇到這樣的問題,也是可以使用這種方式解決的,不僅僅局限於Android方向。
Java中如何修改Jar中的內容