iOS逆向(7)-LLDB,自制LLDB指令碼,竄改微信紅包金額

一縷清風揚萬里發表於2019-04-08

在上篇文章從fishhook看runtime,hook系統C函式中已經提到了利用LLDB的部分命令。在我們玩逆向的時候在大多數時候其實是拿不到原始碼的。所以瞭解一些LLDB來輔助我對別人APP的學(破)習(壞),是非常有必要的。

自從開始玩逆向,總是會有一些大佬給我發一些轉賬資訊(為什麼不是發紅包?紅包金額有限制,拿不出手),金額還挺大。 都是類似於這樣的。

88888.88.png

那麼道友們想不想都收到這樣的紅包呢?看完這篇文章,你就可以。如果沒有人轉給你,評論區告訴我,我給你轉,說到做到!

廢話不多說,這篇文章內容很簡單,非常容易理解,但是需要記的東西比較多,理財師強烈推薦點個小心心,以備不時之需 O(∩_∩)O哈哈~。

今天的DEMO也比較簡單,可以在點選這裡下載到: LLDB

本文將介紹的內容如下:

  • LLDB
  • 自制LLDB指令碼
  • chisel
  • DerekSelander-LLDB
  • 實操竄改微信紅包

一、LLDB

預設內建於Xcode中的動態除錯工具。標準的 LLDB 提供了一組廣泛的命令,旨在與老版本的 GDB 命令相容。 除了使用標準配置外,還可以很容易地自定義 LLDB 以滿足實際需要。

命令格式如下

<command> [<subcommand> [<subcommand>...]] + <action> + [-options [option-value]] + [argument [argument...]]
複製程式碼
  • []表示命令是可選的,可以有也可以沒有
  • <command>(命令)和<subcommand>(子命令):LLDB除錯命令的名稱。命令和子命令按層級結構來排列:一個命令物件為跟隨其的子命令物件建立一個上下文,子命令又為其子命令建立一個上下文,依此類推。
  • <action>:我們想在前面的命令序列的上下文中執行的一些操作。
  • <options>:行為修改器(action modifiers)。通常帶有一些值。
  • <argument>:根據使用的命令的上下文來表示各種不同的東西。

The full lldb command names are often long, but any unique short form can be used. Instead of "breakpoint set", "br se" is also acceptable. 一般lldb的命令會很長,但是隻要能夠想出足夠斷,並且又能代表唯一性的縮寫,那麼縮寫命令也是同一生效的如:breakpoint set == br se

LLDB的所有命令在 LLVM官網或者Apple官網 都可以查詢到。筆者會在這篇文章中列舉一些比較常用的命令。

1、斷點設定

命令名稱 命令參樣例
使用名稱設定斷點 breakpoint set --name main
使用記憶體地址設定斷點 breakpoint -a 0xXXXXXXXX
刪除斷點 breakpoint delete 1
使斷點失效/生效 breakpoint disable/enable 2
檢視所有斷點 breakpoint list
OC中所有命名中包含為Test4的方法設定斷點 breakpoint set -r Test4

隨意上兩張樣式圖:

Breakpoint_1.png
Breakpoint_2.png

附帶一張官網截圖,這些命令都可以在 找到

12B131A8-D3DC-4256-ADA1-604932CB0071.png

2、斷點命令

命令名稱 命令參樣例
給某一個斷點增加命令 breakpoint command add 1
檢視所有斷點命令 breakpoint command list
刪除斷點命令 breakpoint command delete 1
使某個斷點命令生效/失效 breakpoint command enable/disable
給某一個斷點增加命令 breakpoint command delete

給某一處斷點加上一段程式碼,使其每次被斷住的時候都可以自動執行終端程式碼,如下圖:

breakpoint command add.png

3、執行程式碼

expression就是執行程式碼的命令,也就是常用的p,按照官網所說的縮寫唯一性原則eexpr,也是可以的。 如圖:

expression_2.png
expression_2.png

4、檢視堆疊,流程控制

命令名稱 命令參樣例
檢視當前所有堆疊 bt
返回上一步堆疊 up
檢視某一條堆疊 frame select 1
檢視當前堆疊的引數 frame variable
堆疊回滾到上一條 thread return
程式繼續執行 c
單步下一步 n
進入下一個函式(方法) s
彙編級別的單步下一步 ni
彙編級別的進入下一個函式(方法) si

同樣是一張樣式圖:

bt.png

5、記憶體斷點

某個屬性地址只要有改變,就觸發斷點。相當於對某個屬性設定了KVO。

命令名稱 命令參樣例
直接觀察一個變數 watchpoint set variable global_var
直接觀察一個變數的地址 watchpoint set expression -- 0xxxxxx
刪除斷點 watchpoint delete 1
使斷點失效/生效 watchpoint disable/enable 2
檢視所有斷點 watchpoint list

06BE6F9B-09CD-4CCA-89B4-0CD068B5FC0B.png

5、庫檔案image

命令名稱 命令參樣例
檢視工程中使用的庫(包括MachO自己) image list
查詢可執行檔案或共享庫的原始地址 image lookup --address 0x0000000100000de0
輸出NSURL的成員變數及屬性資訊。 image lookup --type NSURL
匯出可執行檔案和共享庫的所有符號表 image dump symtab

7、HOOK每個斷點

給每個斷點,都執行一段程式碼。

命令名稱 命令參樣例
增加一個HOOK target stop-hook add -o "frame variable"
直接所有HOOK target stop-hook list
刪除HOOK target stop-hook disable 1
使HOOK失效/生效 target stop-hook disable/enable 2

stop-hook.png

8、暫存器&&記憶體

命令名稱 命令參樣例
顯示當前執行緒所有暫存器的值 register read --all
將0x01寫入x2暫存器 register write x2 0x01
讀取記憶體0x0002A8A2D中的的值 memory read 0x0002A8A2D (縮寫x 0x0002A8A2D )

9、支援Python

例如:

script print "Here is some text"
複製程式碼

Python.png

二、自制LLDB指令碼

1、.lldbinit

LLDB本質上就跟一個程式(或者說程式)一樣,每次啟動LLDB的時候都會主動載入一個初始化檔案,這個檔案就是.lldbinit,他的地址位於根目錄下:

~/
複製程式碼

如果你的根目錄沒有這個檔案,那就只用touch建立一個吧

// 建立.lldbinit
touch ~/.lldbinit
// 寫入
vi ~/.lldbinit
// 檢視
cat ~/.lldbinit
複製程式碼

.lldbinit中寫入如下程式碼

target stop-hook add -o "frame variable"
複製程式碼

重啟Xcode,執行工程,在任意一個地方加上斷點。
會發現當斷點斷住的時候,自動執行了frame variable

lldbinit效果.png

讀到這就有一個很有意思的事情了:
.lldbinit可以幫我們預載入部分命令,LLDB又支援Python語法,那麼是不是可以將部分Python的程式碼封裝起來,再利用.lldbinit的機制,進而就可以實現用我們自己的封裝好的程式碼,讓我們更方便的使用LLDB

說幹就幹。

2、指令碼實操

之前我們使用過命令image list命令檢視,檢視App執行後再記憶體中的首地址(ASLR),這個地址其實是加上了pagezero的值,其實使用命令image list -o可以直接檢視ASLR,如圖:

ASLR.png
然而我們每次只需要取的是第一個值,卻列印出這麼多的資訊,有點煩人。這就可以寫一個指令碼每次取出第一個值,並且列印出來,就是我們要的結果:
fy_get_ASLR.png
程式碼如下很短,當然也可以在這下載到:網站

import lldb
import re

# 獲取ASLR偏移地址
def fy_get_ASLR(debugger, command, result, internal_dict):
    # 獲取'image list -o'命令的返回結果
    interpreter = lldb.debugger.GetCommandInterpreter()
    returnObject = lldb.SBCommandReturnObject()
    interpreter.HandleCommand('image list -o', returnObject)
    output = returnObject.GetOutput();
    # 正則匹配出第一個0x開頭的16進位制地址
    match = re.match(r'.+(0x[0-9a-fA-F]+)', output)
    if match:
        print match.group(1)
    else:
        return None
# And the initialization code to add your commands 
def __lldb_init_module(debugger, internal_dict):
    # 'command script add fy_get_ASLR' : 給lldb增加一個'fy_get_ASLR'命令
    # '-f lldbPyDemo.fy_get_ASLR' : 該命令呼叫了lldbPyDemo檔案的fy_get_ASLR函式
    debugger.HandleCommand('command script add fy_get_ASLR -f lldbPyDemo.fy_get_ASLR')
    print 'The "fy_get_ASLR" python command has been installed and is ready for use.'
複製程式碼

同樣的,每次都主動載入lldbPyDemo.py也有點煩,將其路徑加入.lldbinit中,即可實現每次自動載入。

lldbinit_2.png

LLDB所有開放出來的介面都可以在官方網站中找到,有興趣的同學可以研究研究。

三、chisel

Chisel is a collection of LLDB commands to assist in the debugging of iOS apps. Chisel是一個使用者Debug iOS Apps 的LLDB命令集合

以上介紹來自chisel官網

由於其支援brew,安裝使用的方法很簡單:

brew update
brew install chisel
複製程式碼

如果本地沒有.lldbinit檔案,先在根目錄建立再開啟,否則直接開啟

// 建立.lldbinit檔案 
touch .lldbinit 
// 開啟.lldbinit檔案
open .lldbinit 
複製程式碼

然後在.lldbinit檔案中追加如下命令

command script import /path/to/fblldb.py
複製程式碼

重啟Xcode即可使用。

以下挑了一些實用的命令:

命令名稱 命令描述 iOS OS X
pviews 列印當前KeyWindow的所有View Yes Yes
pvc 列印當前KeyWindow的所有VC Yes No
fv 根據正規表示式列印查詢並列印View Yes No
fvc 根據正規表示式列印查詢並列印VC Yes No
show/hide 在不需要continue的情況下顯示/隱藏View或者Layer Yes Yes
bmessage 在類的方法或例項的方法上設定符號斷點,就算沒有實現顯示的實現該剛發,也會觸發。如viewWillAppear這個方法,在當前控制器中沒有實現它,但是又想在呼叫它的時機觸發中斷。 Yes Yes
wivar 相當於watchpoint Yes Yes

下圖是pviews和pvc的用例圖:

pviews&&pvc.png

四、DerekSelander-LLDB

DerekSelander-LLDBchisel一樣是一個LLDB的指令碼集合,大部分功能一致,但DerekSelander-LLDB有一個非常好用的功能:
sbt:檢視當前堆疊,並且儘可能的恢復符號表!
這就很牛逼了,要知道在我們逆向的過程中,大部分研究的APP都是已經去符號的!
[站外圖片上傳中...(image-57c79-1554654483282)]

具體使用同樣也可以參照官網: DerekSelander-LLDB

DerekSelander-LLDB的安裝過程沒有chisel那麼花哨,不需要用到brew,安裝過程如下(官網複製的,我就不翻譯了):

1、 To Install, copy the lldb_commands folder to a dir of your choosing.
2、 Open up (or create) ~/.lldbinit
3、 Add the following command to your ~/.lldbinit file: command script import /path/to/lldb_commands/dslldb.py
複製程式碼

五、實操竄改微信紅包

LLDB既然這麼好用,那麼我們就利用LLDB來繼續分析一下我們可愛的微信,O(∩_∩)O哈哈~。

利用之前文章iOS逆向(4)-程式碼注入,竊取微信密碼講到的方法,直接利用Xcode將微信執行在手機上。

隨意讓一個小夥伴自己的微訊號發一個最大的紅包(0.01元),進入聊天頁面如下圖:

紅包_1.png

在這個地方斷住程式,進入LLDB的除錯頁面。

Stop.png
輸入上文提到的Chisel命令pviews,會發現終端列印出了非常多的檢視結構。直接搜尋紅包金額0.01,找到對應的Label,如下圖:
pviews.png

0.01.png

從上圖可以發現顯示金額的控制元件是MMUILabel,很像一個UILabel,而且地址為0x10e6c7d00。 在根據LLDB的p命令執行更改文字的程式碼,如下:

p ((UILabel *)0x10e6c7d00).text = @"¥88888.88"
複製程式碼

改金額.png
然後程式繼續執行。可以看到微信的金額已經被改!
金額被改.png

此時的金額只是一個靜態被改變的字串而已,實際上並不會讓我們多一分錢或者少一分錢。

在普通的生活中,逆向其實是一件非常有意思的事情,在增加自己的知識面的同時,也能給予我們很多的歡樂,想想看這樣一張截圖往朋友圈一放是不是賊有面子。哈哈,也許你的朋友圈中各種紅包轉賬截圖也是這樣來的呢?尤其是經常發這樣的轉賬資訊的代購們。

六、總結

這片文章的內容其實非常簡單,首先介紹了一下LLDB的一下基本用法,從而得知其可以支援Python語法,又有.lldbinit檔案可以幫我們自動載入指令碼,所有就有了一個簡單的LLDB指令碼案例,之後又引出facebook出品的ChieslDerekSelander-LLDB兩個指令碼集合。最後就是利用LLDB進行一些簡單的UI分析和執行簡單的程式碼了。

但是,每次使用LLDB都需要斷住程式,體驗不是很好。那是不是有一種能力,可以讓程式在正常執行的時候,我們也可以對APP進行實時的動態分析呢?
答案是肯定的,神器Cycript就是這麼一個存在,在下一篇文章中,將會圍繞Cycript講解一些逆向工程中非常非常重要的內容!

參考:

相關文章