日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

初识Frida--Android逆向之Java层hook (二)

發布時間:2025/3/15 Android 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初识Frida--Android逆向之Java层hook (二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 初識Frida--Android逆向之Java層hook (二)
  • ?????????apk的安裝與分析
  • ?????????????????流程分析
  • ?????????????????hook點分析
  • ?????????JavaScript代碼構造與執行
  • ?????????????????0x00 hook getMac()
  • ?????????????????0x01 計算秘鑰Key
  • ?????????????????0x02 調用showPremium獲取答案
  • ?????????總結

?

?

今天繼續一個新的示例,同樣采用CTF作為例子,難度稍微加大了一點,如果對Frida基本的使用還不是很了解,建議先看看之前的文章初識Frida--Android逆向之Java層hook (一)
博客同步:訪問

?

文章涉及到的知識點:

  • 怎么使用javascript實例化類并調用類方法
  • 怎么在"jscode"中增加自定義javascript方法
  • 怎么較為靈活的hook類方法

apk的安裝與分析

示例下載:whyshouldIpay

?

下載apk后安裝,一樣還是先來看看是什么功能,這是一個比較簡單的驗證程序,簡單的使用后,了解到PREMIUM CONETNT內容需要輸入License驗證后才能查看。那估計PREMIUM CONETNT按鈕中的內容應該就是答案了吧。

流程分析

使用jadx將apk反編譯出來,分析,在AndroidManifest.xml中找到了啟動的Activity是LauncherActivity。

?

?

找到其中驗證的主要代碼verifyClick,分析如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

public void verifyClick(View v) {

????//第一個驗證,將輸入的Licese通過網絡驗證,但這個肯定是通不過的,這是一個可能需要繞過的點。

????????try?{

????????????InputStream?in?=?new URL("http://broken.license.server.com/query?license="?+?((EditText) findViewById(R.id.text_license)).getText().toString()).openConnection().getInputStream();

????????????StringBuilder responseBuilder?=?new StringBuilder();

????????????byte[] b?=?new byte[0];

????????????while?(in.read(b) >?0) {

????????????????responseBuilder.append(b);

????????????}

????????????String response?=?responseBuilder.toString();

?????//網絡驗證需要服務器返回?"LICENSEKEYOK",才能進行下一步

????????????if?(response.equals("LICENSEKEYOK")) {

??????//當網絡驗證成功后,生成激活秘鑰,并寫入到preferences文件中

????????????????String activatedKey?=?new String(MainActivity.xor(getMac().getBytes(), response.getBytes()));

????????????????Editor editor?=?getApplicationContext().getSharedPreferences("preferences",?0).edit();

????????????????editor.putString("KEY", activatedKey);

????????????????editor.commit();

??????//這樣便成功激活

????????????????new Builder(this).setTitle((CharSequence)?"Activation successful").setMessage((CharSequence)?"Activation successful").setIcon(17301543).show();

????????????????return;

????????????}

????????????new Builder(this).setTitle((CharSequence)?"Invalid license!").setMessage((CharSequence)?"Invalid license!").setIcon(17301543).show();

????????} catch (Exception e) {

????????????new Builder(this).setTitle((CharSequence)?"Error occured").setMessage((CharSequence)?"Server unreachable").setNeutralButton((CharSequence)?"OK", null).setIcon(17301543).show();

????????}

????}

在verifyClick中可以知道生成激活秘鑰的算法是MainActivity.xor。

1

String activatedKey?=?new String(MainActivity.xor(getMac().getBytes(), response.getBytes()));

來到MainActivity中,查看該方法,看上去筆算起來還是比較麻煩。

1

2

3

4

5

6

7

public static byte[] xor(byte[] val, byte[] key) {

??????byte[] o?=?new byte[val.length];

??????for?(int?i?=?0; i < val.length; i++) {

??????????o[i]?=?(byte) (val[i] ^ key[i?%?key.length]);

??????}

??????return?o;

??}

接下來當程序被激活成功后,點擊PREMIUM CONETNT按鈕,會調用MainActivity中的方法,可以看到它將MAC,以及生成的Key發送到了MainActivity中。

1

2

3

4

5

6

public void showPremium(View view) {

???????Intent i?=?new Intent(this, MainActivity.class);

???????i.putExtra("MAC", getMac());

???????i.putExtra("KEY", getKey());

???????startActivity(i);

???}

在MainActivity的onCreate方法中,看到了最終答案生成的native方法stringFromJNI(key, mac)。

1

2

3

4

5

6

7

8

9

10

11

12

13

protected void onCreate(Bundle savedInstanceState) {

?//獲取Intent傳遞過來的值

????????String key?=?getIntent().getStringExtra("KEY");

????????String mac?=?getIntent().getStringExtra("MAC");

????????if?(key?==?"" || mac == "") {

????????????key?=?"";

????????????mac?=?"";

????????}

????????super.onCreate(savedInstanceState);

????????setContentView((int) R.layout.activity_main);

?????//調用native函數,算出答案

????????((TextView) findViewById(R.id.sample_text)).setText(stringFromJNI(key, mac));

????}

好,現在源代碼分析基本上能夠理清楚了,大概的過程就是這樣。

  • 輸入License,進行驗證
  • 通過網絡驗證獲取返回值“LICENSEKEYOK”后,然后調用MainActivity.xor在本地preferences文件中生成秘鑰,激活成功。
  • 本地獲取MAC地址及秘鑰Key傳入MainActivity得出答案。
  • hook點分析

    接下來重點就是要尋找hook點,經過剛才解題流程的分析,得出hook思路如下:

  • 獲取getMac()函數的返回值,與“LICENSEKEYOK"字符串進行xor運算得出秘鑰Key.
  • hook getKey方法,讓它不從preferences文件讀取Key,而是我們自己構造。
  • hook?verifyClick,讓它調用showPremium方法
  • JavaScript代碼構造與執行

    0x00 hook getMac()

    先來一個簡單的示例,看看getMac()方法返回的的是什么,采用的方法是hook?showPremium,這樣就能通過點擊PREMIUM CONETNT按鈕直接得到getMac()的返回值。

    ?

    JavaScript代碼如下:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    js_code?=?'''

    ????Java.perform(function(){

    ????????var hook_Activity = Java.use('de.fraunhofer.sit.premiumapp.LauncherActivity');

    ????????//hook showPremium從而方便直接點擊按鈕得出Mac值

    ????????hook_Activity.showPremium.implementation = function(v){

    ????????????//因為showPremium,getMac()均在LauncherActivity類中,所有直接通過this就能直接調用getMac()方法

    ????????????var Key = this.getKey();

    ????????????var Mac = this.getMac();

    ????????????send(Key);

    ????????????send(Mac);

    ?

    ????????}

    ????});

    '''

    完整python代碼如下:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    import?frida,sys

    ?

    ?

    def?on_message(message, data):

    ????if?message['type']?==?'send':

    ????????print("[*] {0}".format(message['payload']))

    ????else:

    ????????print(message)

    ?

    ?

    js_code?=?'''

    ????Java.perform(function(){

    ????????var hook_Activity = Java.use('de.fraunhofer.sit.premiumapp.LauncherActivity');

    ????????hook_Activity.showPremium.implementation = function(v){

    ????????????var Key = this.getKey();

    ????????????var Mac = this.getMac();

    ????????????send(Key);

    ????????????send(Mac);

    ?

    ????????}

    ????});

    '''

    ?

    ?

    session?=?frida.get_usb_device().attach("de.fraunhofer.sit.premiumapp")

    script?=?session.create_script(js_code)

    script.on('message',on_message)

    script.load()

    sys.stdin.read()

    運行看看結果:

    0x01 計算秘鑰Key

    接下來開始真正第一步的hook,將mac值與“LICENSEKEYOK"通過MainActivity.xor獲取秘鑰Key。那就直接hook?getKey方法吧,這樣可以自己來構造秘鑰Key。
    仔細分析,會發現在這一步中可能會遇到下面的問題:

  • 怎么調用xor方法。
  • java是強類型語言,javascript是弱類型語言,怎么將javascript參數進行類型轉換并傳遞到java語言中。
  • 怎么將javascript參數進行類型轉換并傳遞到java語言中?其實方法很簡單,既然java是強類型語言,那就根據它要求的類型傳遞對應參數即可,看看它參數的類型。

    1

    2

    3

    4

    5

    6

    7

    public static byte[] xor(byte[] val, byte[] key) {

    ????????byte[] o?=?new byte[val.length];

    ????????for?(int?i?=?0; i < val.length; i++) {

    ????????????o[i]?=?(byte) (val[i] ^ key[i?%?key.length]);

    ????????}

    ????????return?o;

    ????}

    那么,在javascript代碼中,先準備一個將字符串類型轉換為byte[]類型的方法stringToBytes,再通過實例化MainActivity類的方式調用xor(),然后還需要一個將byte[]回轉為String的方法,因為秘鑰key是Sting類型的。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    js_code?=?'''

    ?????//字符串轉換byte[]的方法

    ?????stringToBytes = function(str) {?

    ????????var ch, st, re = [];

    ????????for (var i = 0; i < str.length; i++ ) {

    ????????????ch = str.charCodeAt(i);?

    ????????????st = [];????????????????

    ?

    ???????????do {?

    ????????????????st.push( ch & 0xFF );?

    ????????????????ch = ch >> 8;?????????

    ????????????}???

    ????????????while ( ch );?

    ????????????re = re.concat( st.reverse() );

    ????????}?

    ????????return re;?

    ????}

    ????//將byte[]轉成String的方法

    ?????function byteToString(arr) {?

    ????????if(typeof arr === 'string') {?

    ????????????return arr;?

    ????????}?

    ????????var str = '',?

    ????????????_arr = arr;?

    ????????for(var i = 0; i < _arr.length; i++) {?

    ????????????var one = _arr[i].toString(2),?

    ????????????????v = one.match(/^1+?(?=0)/);?

    ????????????if(v && one.length == 8) {?

    ????????????????var bytesLength = v[0].length;?

    ????????????????var store = _arr[i].toString(2).slice(7 - bytesLength);?

    ????????????????for(var st = 1; st < bytesLength; st++) {?

    ????????????????????store += _arr[st + i].toString(2).slice(2);?

    ????????????????}?

    ????????????????str += String.fromCharCode(parseInt(store, 2));?

    ????????????????i += bytesLength - 1;?

    ????????????} else {?

    ????????????????str += String.fromCharCode(_arr[i]);?

    ????????????}?

    ????????}?

    ????????return str;?

    ????}

    ????//hook 代碼

    ????Java.perform(function(){

    ????????var hook_Activity = Java.use('de.fraunhofer.sit.premiumapp.LauncherActivity');

    ????????var MainActivity = Java.use('de.fraunhofer.sit.premiumapp.MainActivity')

    ????????var LicenseStr = "LICENSEKEYOK";

    ????????//hook getKey()方法,直接構造密碼,而不從preferences讀取

    ????????hook_Activity.getKey.implementation = function(){

    ????????????//獲取Mac

    ????????????var Mac = this.getMac();

    ????????????//實例化MainActivity

    ????????????var instance = MainActivity.$new();

    ????????????//類型轉換

    ????????????var MacByte =stringToBytes(Mac);

    ????????????var LicenseByte = stringToBytes(LicenseStr);

    ?

    ????????????send("MacByte:"+MacByte)

    ????????????send("LicenseByte:"+LicenseByte)

    ????????????//調用實例化對象的xor方法

    ????????????xorResult = instance.xor(MacByte,LicenseByte);

    ????????????send(xorResult);

    ????????????//類型回轉

    ????????????var Key = byteToString(xorResult)

    ????????????send(Key);

    ????????????return Key;

    ????????}

    ????????hook_Activity.verifyClick.implementation = function(view){

    ????????????this.showPremium(view);

    ????????}

    ????});

    '''

    接下來,執行看看,能不能獲取秘鑰Key。
    不知道怎么啟動模擬器中的frida-server,以及端口轉發,可以先看看初識Frida--Android逆向之Java層hook (一)
    啟動python腳本,在模擬器中直接點擊PREMIUM CONTENT,即可看到執行結果。

    0x02 調用showPremium獲取答案

    前面2個步驟,可以說是已經完成90%了,接下來只需要在hook一個能夠觸發showPremium方法的即可。方法就隨意了,這里采用hook verifyClick的方式,這樣點擊app上的VERIFY按鈕,觸發verifyClick方法去調用showPremium,進而獲得最終答案。

    1

    2

    3

    hook_Activity.verifyClick.implementation?=?function(view){

    ???????????this.showPremium(view);

    ???????}

    啟動腳本,點擊app上的VERIFY按鈕看看執行結果:

    ?

    完整python代碼:下載

    總結

    通過上面的例子,可以學習在java層怎么使用frida實現:

  • 任意類方法調用。
  • 任意類方法重實現。
    以及學會怎么構造和使用自定義javascript方法。
    當然這還僅僅只是一個開始.....
  • ?

    https://bbs.pediy.com/thread-227233.htm

    總結

    以上是生活随笔為你收集整理的初识Frida--Android逆向之Java层hook (二)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。