安卓逆向(一)--Smali基礎

来源:https://www.cnblogs.com/ttxs69/archive/2018/08/13/9469911.html
-Advertisement-
Play Games

安卓逆向(一) Smali基礎 標簽(空格分隔): 安卓逆向 APK的組成 |文件夾|作用| |: |: | |asset文件夾|資源目錄1:asset和res都是資源目錄但有所區別,見下麵說明| |lib文件夾|so庫存放位置,一般由NDK編譯得到,常見於使用游戲引擎或JNI native調用的工 ...


安卓逆向(一)--Smali基礎

標簽(空格分隔): 安卓逆向


APK的組成

文件夾 作用
asset文件夾 資源目錄1:asset和res都是資源目錄但有所區別,見下麵說明
lib文件夾 so庫存放位置,一般由NDK編譯得到,常見於使用游戲引擎或JNI native調用的工程中
META-INF文件夾 存放工程一些屬性文件,例如Manifest.MF
res文件夾 資源目錄2:asset和res都是資源目錄但有所區別,見下麵說明
AndroidManifest.xml Android工程的基礎配置屬性文件
classes.dex Java代碼編譯得到的DalvikVM能直接執行的文件,下麵有介紹
resources.arsc 對res目錄下的資源的一個索引文件,保存了原工程中strings.xml等文件內容
其他文件夾 etc.

asset資源目錄和res資源目錄的不同之處:

res目錄下的資源文件在編譯時會自動生成索引文件(R.java),在Java代碼中用R.xxx.yyy來引用;
而asset目錄下的資源文件不需要生成索引,在Java代碼中需要用AssetManager來訪問;
一般來說,除了音頻和視頻資源(需要放在raw或asset下),使用Java開發的Android工程使用到的資源文件都會放在res下;使用C++游戲引擎(或使用Lua Unity3D等)的資源文件均需要放在asset下。

其中在Davlik位元組碼中,寄存器都是32位的,能夠支持任何類型,64位類型(Long/Double)用2個寄存器表示;Dalvik位元組碼有兩種類型:原始類型;引用類型(包括對象和數組)

原始類型:

B---byte
C---char
D---double
F---float
I---int
J---long
S---short
V---void
Z---boolean
[XXX---array
Lxxx/yyy---object

數組的表示方式是:在基本類型前加上前中括弧“[”,例如int數組和float數組分別表示為:[I、[F;對象的表示則以L作為開頭,格式是LpackageName/objectName;(註意必須有個分號跟在最後),例如String對象在smali中為:Ljava/lang/String;,其中java/lang對應java.lang包,String就是定義在該包中的一個對象。或許有人問,既然類是用LpackageName/objectName;來表示,那類裡面的內部類又如何在smali中引用呢?答案是:LpackageName/objectName$subObjectName;。也就是在內部類前加“$”符號,關於“$”符號更多的規則將在後面談到。

方法:

方法的定義一般為:Func-Name (Para-Type1Para-Type2Para-Type3...)Return-Type
註意參數與參數之間沒有任何分隔符,同樣舉幾個例子就容易明白了

  1. hello ()V
    沒錯,這就是void hello()
  2. hello (III)Z
    這個則是boolean hello(int, int, int)
  3. hello (Z[I[ILjava/lang/String;J)Ljava/lang/String;
    看出來這是String hello (boolean, int[], int[], String, long) 了嗎?

    Smali基本語法:

    .field private isFlag:z  定義變數
    .method  方法
    .parameter  方法參數
    .prologue  方法開始
    .line 123  此方法位於第123行
    invoke-super  調用父函數
    const/high16  v0, 0x7fo3  把0x7fo3賦值給v0
    invoke-direct  調用函數
    return-void  函數返回void
    .end method  函數結束
    new-instance  創建實例
    iput-object  對象賦值
    iget-object  調用對象
    invoke-static  調用靜態函數

    條件跳轉分支:

    "if-eq vA, vB, :cond_**"   如果vA等於vB則跳轉到:cond_**
    "if-ne vA, vB, :cond_**"   如果vA不等於vB則跳轉到:cond_**
    "if-lt vA, vB, :cond_**"    如果vA小於vB則跳轉到:cond_**
    "if-ge vA, vB, :cond_**"   如果vA大於等於vB則跳轉到:cond_**
    "if-gt vA, vB, :cond_**"   如果vA大於vB則跳轉到:cond_**
    "if-le vA, vB, :cond_**"    如果vA小於等於vB則跳轉到:cond_**
    "if-eqz vA, :cond_**"   如果vA等於0則跳轉到:cond_**
    "if-nez vA, :cond_**"   如果vA不等於0則跳轉到:cond_**
    "if-ltz vA, :cond_**"    如果vA小於0則跳轉到:cond_**
    "if-gez vA, :cond_**"   如果vA大於等於0則跳轉到:cond_**
    "if-gtz vA, :cond_**"   如果vA大於0則跳轉到:cond_**
    "if-lez vA, :cond_**"    如果vA小於等於0則跳轉到:cond_**

    Smali中的包信息:

    .class public Lcom/aaaaa; .super Lcom/bbbbb; .source "ccccc.java"
    這是一個由ccccc.java編譯得到的smali文件(第3行)
    它是com.aaaaa這個package下的一個類(第1行)
    繼承自com.bbbbb這個類(第2行)

    關於寄存器的知識補充:

    在smali里的所有操作都必須經過寄存器來進行:本地寄存器用v開頭數字結尾的符號來表示,如v0、v1、v2。
    參數寄存器則使用p開頭數字結尾的符號來表示,如p0、p1、p2、...
    特別註意的是,p0不一定是函數中的第一個參數,在非static函數中,p0代指“this”,p1表示函數的第一個參數,p2代表函數中的第二個參數…而在static函數中p0才對應第一個參數(因為Java的static方法中沒有this方法。
    寄存器簡單實例分析:
    const/4 v0, 0x1 iput-boolean v0, p0, Lcom/aaa;->IsRegistered:Z
    我們來分析一下上面的兩句smali代碼,首先它使用了v0本地寄存器,並把值0x1存到v0中,然後第二句用iput-boolean這個指令把v0中的值存放到com.aaa.IsRegistered這個成員變數中。
    即相當於:this.IsRegistered = true;(上面說過,在非static函數中p0代表的是“this”,在這裡就是com.aaa實例)。

    smali中的成員變數

    成員變數格式是:
    .field public/private [static] [final] varName:<類型>
    對於不同的成員變數也有不同的指令。
    一般來說,獲取的指令有:
    iget、sget、iget-boolean、sget-boolean、iget-object、sget-object等。
    操作的指令有:
    iput、sput、iput-boolean、sput-boolean、iput-object、sput-object等。
    沒有“-object”尾碼的表示操作的成員變數對象是基本數據類型,帶“-object”表示操作的成員變數是對象類型,特別地,boolean類型則使用帶“-boolean”的指令操作。

    Smali成員變數指令簡析:

    sget-object v0, Lcom/aaa;->ID:Ljava/lang/String;
    sget-object就是用來獲取變數值並保存到緊接著的參數的寄存器中,本例中,它獲取ID這個String類型的成員變數並放到v0這個寄存器中。
    註意:前面需要該變數所屬的類的類型,後面需要加一個冒號和該成員變數的類型,中間是“->”表示所屬關係。
    iget-object v0, p0, Lcom/aaa;->view:Lcom/aaa/view;
    可以看到iget-object指令比sget-object多了一個參數,就是該變數所在類的實例,在這裡就是p0即“this”.
    獲取array的話我們用agetaget-object,指令使用和上述一致
    put指令的使用和get指令是統一的如下:
const/4 v3, 0x0
sput-object v3, Lcom/aaa;->timer:Lcom/aaa/timer;

相當於:this.timer = null;
註意,這裡因為是賦值object 所以是null,若是boolean的話,大家想應該相當於什麼呢?

.local v0, args:Landroid/os/Message;
const/4 v1, 0x12
iput v1, v0, Landroid/os/Message;->what:I

相當於:args.what = 18;argsMessage的實例)

Smali中函數的調用:

smali中的函數和成員變數一樣也分為兩種類型,分別為directvirtual之分。
那麼direct methodvirtual method有什麼區別呢?
簡單來說,direct method就是private函數,其餘的publicprotected函數都屬於virtual method。所以在調用函數時,有invoke-directinvoke-virtual,另外還有invoke-staticinvoke-super以及invoke-interface等幾種不同的指令。
當然其實還有invoke-XXX/range 指令的,這是參數多於4個的時候調用的指令,比較少見,瞭解下即可。

1.invoke-static:用於調用static函數的

例如:
invoke-static {}, Lcom/aaa;->CheckSignature()Z
這裡註意到invoke-static後面有一對大括弧“{}”,其實是調用該方法的實例+參數列表,由於這個方法既不需參數也是static的,所以{}內為空,再看一個:

const-string v0, "NDKLIB" 
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V

這個是調用static void System.loadLibrary(String)來載入NDK編譯的so庫用的方法,同樣也是這裡v0就是參數"NDKLIB"了。

2.invoke-super:調用父類方法用的指令,一般用於調用onCreate、onDestroy等方法。

3.invoke-direct:調用private函數:

invoke-direct {p0}, Landroid/app/TabActivity;-><init>()V
這裡init()就是定義在TabActivity中的一個private函數

4.invoke-virtual:用於調用protected或public函數,同樣註意修改smali時不要錯用invoke-direct或invoke-static:

sget-object v0, Lcom/dddd;->bbb:Lcom/ccc;
invoke-virtual {v0, v1}, Lcom/ccc;->Messages(Ljava/lang/Object;)V

這裡相信大家都已經很清楚了:
v0是bbb:Lcom/ccc
v1是傳遞給Messages方法的Ljava/lang/Object參數。

5.invoke-xxxxx/range:當方法的參數多於5個時(含5個),不能直接使用以上的指令,而是在後面加上“/range”,range表示範圍,使用方法也有所不同:

invoke-direct/range {v0 .. v5}, Lcmb/pb/ui/PBContainerActivity;->h(ILjava/lang/CharSequence;Ljava/lang/String;Landroid/content/Intent;I)Z

需要傳遞v0到v5一共6個參數,這時候大括弧內的參數採用省略形式,且需要連續。

Smali中函數返回的結果的操作:

在Java代碼中調用函數和返回函數結果可以用一條語句完成,而在Smali里則需要分開來完成,在使用上述指令後,如果調用的函數返回非void,那麼還需要用到move-result(返回基本數據類型)和move-result-object(返回對象)指令:

const-string v0, "Eric"
invoke-static {v0}, Lcmb/pbi;->t(Ljava/lang/String;)Ljava/lang/String;
move-result-object v2

v2保存的就是調用t方法返回的String字元串。

Smali中函數實體分析--if函數分析:

.method private ifRegistered()Z
    .locals 2   //在這個函數中本地寄存器的個數
    .prologue
    const/4 v0, 0x1     // v0賦值為1
    .local v0, tempFlag:Z   
    if-eqz v0, :cond_0            // 判斷v0是否等於0,等於0則跳到cond_0執行
    const/4 v1, 0x1            // 符合條件分支
    :goto_0 //標簽
    return v1   //返回v1的值
    :cond_0 //標簽
    const/4 v1, 0x0            // cond_0分支
    goto :goto_0    //跳到goto_0執行 即返回v1的值  這裡可以改成return v1  也是一樣的
.end method

Smali中函數實體分析--for函數分析:

const/4 v0, 0x0   //vo =0;
.local v0, i:I
:goto_0
if-lt v0, v3, :cond_0     //  v0小於v3 則跳到cond_0並執行分支 :cond_0
return-void
    :cond_0                // 標簽
iget-object v1, p0, Lcom/aaa/MainActivity;->listStrings:Ljava/util/List;        // 引用對象
const-string v2, "Eric"
invoke-interface {v1, v2}, Ljava/util/List;->add(Ljava/lang/Object;)Z    // List是介面, 執行介面方法add
add-int/lit8 v0, v0, 0x1    // 將第二個v0寄存器中的值,加上0x1的值放入第一個寄存器中, 實現自增長
goto :goto_0                // 回去:goto_0標簽

Smali課後習題,翻譯成Java代碼,做完後可以回帖答案再@我。給CB哦!

    .locals 4
    const/4 v2, 0x1
    const/16 v1, 0x10
    .local v1, "length":I
    if-nez v1, :cond_1
    :cond_0
    :goto_0
    return v2
    :cond_1
    const/4 v0, 0x0
    .local v0, "i":I
    :goto_1
    if-lt v0, v1, :cond_2
    const/16 v3, 0x28
    if-le v1, v3, :cond_0
    const/4 v2, 0x0
    goto :goto_0
    :cond_2
    xor-int/lit8 v1, v1, 0x3b
    add-int/lit8 v0, v0, 0x1
    goto :goto_1

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 之前只用phpmyadmin登錄本地的mysql,管理另一個遠程資料庫的時候發現,單純用命令行處理字元串、換行符實在是不好使,所以配置了遠程登錄mysql,很簡單的問題結果沒有搜到合適的方法,所以記錄下我的配置方式。 phpmyadmin/libraries/config.default.php $ ...
  • 今天來介紹新手學習hadoop的入門註意事項。這篇文章一來談談hadoop核心知識學習。 首先hadoop分為hadoop1.X和hadoop2.X,並且還有hadoop生態系統,那麼下麵我們以hadoop2.x為例進行詳細介紹: Hadoop的核心是mapreduce和hdfs。 Mapreduc ...
  • 一、sql server日期時間函數Sql Server中的日期與時間函數 1. 當前系統日期、時間 select getdate() 2. dateadd 在向指定日期加上一段時間的基礎上,返回新的 datetime 值 例如:嚮日期加上2天 select dateadd(day,2,'2004- ...
  • 一. 概述 在sql server 備份與恢復系列的第一篇里,有講到大容量模式下備份與還原的相關知識。這篇重點來演示在大容量模式下常用的備份與還原模式“完整備份+差異備份+日誌備份”。 在大容量恢復模式下,特別要註意的是在什麼情況下會導致數據還原丟失風險,帶著這個問題,來進行演示說明。備份策略如下圖 ...
  • 線上上進行DDL操作時,相對於其可能帶來的系統負載,其實,我們最擔心的還是MDL其可能導致的阻塞問題。 一旦DDL操作因獲取不到MDL被阻塞,後續其它針對該表的其它操作都會被阻塞。典型如下,如阻塞稍久的話,我們會看到Threads_running飆升,CPU告警。 如果發生線上上,無疑會影響到業務。 ...
  • 眾所周知,MongoDB包括社區版和企業版,但不止如此,MongoDB公司還有MongoDB Atlas:Database as a Service. MongoDB Atlas delivers the world’s leading database for modern application ...
  • APK文件只能包含一個AndroidManifest.xml文件,但Android Studio項目可以包含多個文件(通過buildSrc、導入的庫引入)。因此,在構建應用時,Gradle構建會將所有清單文件合併到一個封裝的APK的清單文件中。 清單文件合併優先順序 清單合併工具 可以使用Merged ...
  • 至最新的Android P, Google已經提供了世界絕大多數語言的支持。但是對許多發往海外的項目,可能還是會有一些國家的語言google預設沒有支持。下麵將介紹下對於某一特定語言如何判斷Google是否支持這種語言、如何添加一種語言(如果google預設沒有支持)。 還有,自Android N以 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...