抖音數據採集教程,Unicorn 模擬 CPU 指令並 Hook CPU 執行狀態

抖音數據採集教程,Unicorn 模擬 CPU 指令並 Hook CPU 執行狀態

短視頻、直播數據實時採集接口,請查看文檔: TiToData架構


免責聲明:本文檔僅供學習與參考,請勿用於非法用途!不然一切後果自負。
app

添加內存訪問 hook 回調

參數函數

  • type: 內存操做類型 READ, or WRITE
  • address: 當前指令地址
  • size: 讀或寫的長度
  • value: 寫入的值(type=read時無視)
  • user_data: hook_add 設置的 user_data 參數

添加內存訪問異常處理 hook 回調

參數學習

  • type: 內存操做類型 READ, or WRITE
  • address: 當前指令地址
  • size: 讀或寫的長度
  • value: 寫入的值(type=read時無視)
  • user_data: hook_add 設置的 user_data 參數
  • 返回值: 真(繼續模擬執行) 假(中止模擬執行)

模擬 cpu 執行 mov 指令

目標:
執行普通的 彙編代碼, 模擬讓他跑起來
.text:00008ACA 0A 46 MOV R2, R1 ; Rd = Op2 // 將 R1 放到 R2
.text:00008ACC 03 46 MOV R3, R0 ; Rd = Op2 // 將 R0 放到 R3
上面的指令代碼爲: \x0A\x46\x03\x46測試

import unicorn
import capstone
import binascii
CODE = b'\x0A\x46\x03\x46'  # 測試指令 IDA 中拉來的, mov 命令,未涉及到內存讀寫命令
def print_result(mu):
    """輸出調試結果, 源碼中,這些都是常量
    UC_ARM_REG_R0 = 66
    UC_ARM_REG_R1 = 67
    UC_ARM_REG_R2 = 68
    UC_ARM_REG_R3 = 69
    UC_ARM_REG_R4 = 70
    """
    msg = """
    寄存器輸出 --------
    寄存器[R0], 值:{}
    寄存器[R1], 值:{}
    寄存器[R2], 值:{}
    寄存器[R3], 值:{}
    """.format(
        mu.reg_read(66),  # UC_ARM_REG_R0 源碼對應常量 66
        mu.reg_read(67),
        mu.reg_read(68),
        mu.reg_read(69),
    )
    print(msg.strip().replace(' ', ''))
def capstone_print(code):
    """capstone 測試"""
    print("\033[1;32m-------- capstone 輸出--------\033[0m")
    CP = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB)  # 指定 THUMB 指令集
    for i in CP.disasm(code, 0, len(code)):  
        print('\033[1;32m地址: %s | 操做碼: %s | 內容: %s\033[0m'%(i.address, i.mnemonic, i.op_str))
def uni_test():
    "將彙編片斷,映射到 unicorn 虛擬內存中,將 pc 指向第一條指令處並執行"
    print('-------- unicorn 執行前--------')
    # 1. 建立實例
    mu = unicorn.Uc(unicorn.UC_ARCH_ARM, unicorn.UC_MODE_THUMB)  # 要指定架構和模式, 這裏用 arm 架構, 指定 THUMB 指令集
    # 2. 將代碼片斷映射到模擬器的虛擬地址
    ADDRESS = 0x1000 # 映射開始地址
    SIZE = 1024  # 分配映射大小
    # 3. 開始映射
    mu.mem_map(ADDRESS, SIZE)  # 初始化映射 參數1:地址 參數2:空間大小  默認初始化後默認值:0
    mu.mem_write(ADDRESS, CODE)  # 寫入指令 參數1: 寫入位置 參數2:寫入內容
    # 4. 測試讀取 [測試]
    bytes=mu.mem_read(ADDRESS, 10)  # 參數1: 讀出位置 參數2:讀出字節數
    print('地址:%x, 內容:%s'%(ADDRESS, binascii.b2a_hex(bytes)))  # 讀出來是 bates, 要用 binascii 轉換一下
    # 寫入寄存器
    # 5. 寄存器初始化 指令集涉及到 R0,R1,R2,R3 4個寄存器
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0, 0x100)  # 在 r0 寄存器上寫入 0x100
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R1, 0x200)  # 在 r1 寄存器上寫入 0x200
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R2, 0x300)  # 在 r2 寄存器上寫入 0x100
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R3, 0x400)  # 在 r3 寄存器上寫入 0x200
    # 6. pc 指針指向地址開始執行
    follow_cpu(mu)  # 跟蹤 CPU 進行 hook
    print_result(mu)  # 輸出
    mu.emu_start(ADDRESS+1, ADDRESS+4)  # THUMB 指令集因此要 ADDRESS +1,    參數1:起始位置,參數2:結束位置
    print('-------- unicorn 執行後--------')
    print_result(mu)  # 輸出
def follow_cpu(mu):
    """跟蹤 cpu 執行狀態進行 hook 堆棧顯示"""
    mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)  # 這裏默認跟蹤全部,具體也能夠配置
def hook_code(mu, address, size, user_data):
    """定義回調函數, 在進入彙編指令以前就會先運行這裏
    mu: 模擬器
    address: 執行地址
    size: 彙編指令大小
    user_data: 經過 hook_add 添加的參數
    """
    code=mu.mem_read(address,size)  # 讀取
    print('\033[1;32m=== Hook cpu ===\033[0m')
    capstone_print(code)
    return
if __name__ == "__main__":
    capstone_print(CODE)
    uni_test()

Python
_ 複製_
指針

執行 STR 等內存操做命令

在上面例子中加入一條 STR 指令
.text:00008B04 04 92 STR R2, [SP,#0x40+var_30] ; Store to Memory // 存寄存器
整個指令代碼變成\x0A\x46\x03\x46\x04\x92
這種狀況下若是隻是像上面那樣寫就不行了,由於須要內存操做,與提早映射,不然 hook cpu 操做的時候就會報錯。
須要自行添加一個回調函數來主動映射調試

def hook_mem_write_unmapped(mu, type, address, size, value, user_data):
    print('\033[1;32m=== Hook cpu ===\033[0m')
    if type==unicorn.UC_MEM_WRITE_UNMAPPED:
        mu.mem_map(0x0,0x1000)  # 主動映射進去 注意:映射的時候須要對齊!!和最開始設定的位置和大小!
        print("\033[1;32m[主動映射]地址: 0x%x | hook_mem 類型: %d | 大小:%d | 值:0x%x\033[0m" % (address, type, size, value))
    return True  # 返回 True 繼續執行,返回 False 則不執行後面的

Python
_ 複製_
如此才能執行 STR 指令併成功 Hook CPU 狀態
code

執行系統指令與基本塊

若是要模擬執行彙編系統指令與基本塊的 Hook, 那麼咱們也要自行添加回調函數orm

def hook_syscall(mu,intno,user_data):
    print("\033[1;36mhook 系統調用 系統調用號: 0x%d"%intno)
    if intno==2:  # 例子 2 是退出
        print("系統調用退出!!")
    print_result(mu)
    print("\033[0m")
    return
def hook_block(mu, address, size, user_data):
    # code = mu.mem_read(address,size)
    print("\033[1;36mhook 基本塊")
    print_result(mu)
    print("\033[0m")
    return

Python
_ 複製_
固然這只是個例子代碼,執行推出的
視頻

相關文章
相關標籤/搜索