python中emuterate用法_跨平台模拟执行 - AndroidNativeEmu实用手册
原標題:跨平臺模擬執行 - AndroidNativeEmu實用手冊
本文為看雪論壇精華文章
看雪論壇作者ID:StriveMario
安裝
AndroidNativeEmu有什么用?
AndroidNativeEmu是基于Unicron實現的一個指令解析器, 讓您能夠跨平臺模擬Android Native庫函數,例如JNI_,Java_XXX_XX等函數。
特性
模擬 JNI Invocation API so JNI_ can be called properly.
模擬 memory、malloc、memcpy
支持攔截系統調用(SVC #0)
通過符號Hook
所有 JavaVM, JNIEnv 和 hooked functions 都可以用python來處理
支持 VFP
支持文件系統(也就是說你可以模擬maps、status等文件)
項目地址:
https://github.com/AeonLucid/AndroidNativeEmu
安裝過程
環境要求: python 3.7 (注意必須是3.7版本, 我使用3.6裝keystone的時候踩了坑)
自測系統環境: win7
1. Clone 該項目
git clone http s://github. com/AeonLucid/AndroidNativeEmu.git
2. 安裝需要的支持模塊
pip install-r requirements.txt
安裝keystone-engine可能會失敗(反正我是沒裝上)。
解決方案:
克隆keystone倉庫:git clone https://github.com/keystone-engine/keystone.git
打開keystonebindings文件夾安裝: python setup.py install
下載對應系統和版本dll(因為我是win), 下載鏈接: http://www.keystone-engine.org/download/
把dll復制到python的keystone目錄下: [python_path]Libsite-packageskeystone
3. 把androidemu文件夾復制至sample文件夾下,并刪除example.py文件下的關于"samples/"的目錄訪問路徑。
如
"samples/example_binaries/libc.so"
改為
"example_binaries/libc.so"
4. 運行例子。
pythonexample. py
5. 不出意外的話就可以看到結果了。
例子文件閱讀
example_binaries/ : 里面是需要加載的 so
vfs/ : 里面是虛擬的文件系統, 有需要可以自己添加文件
androidemu/ : android虛擬機
importlogging
importsys
fromunicorn importUC_HOOK_CODE
fromunicorn.arm_const import*
fromandroidemu.emulator importEmulator
# 配置日志相關設置
logging.basicConfig(
stream=sys.stdout, #標準輸出流
level=logging.DEBUG, #輸出等級
format= "%(asctime)s %(levelname)7s %(name)34s | %(message)s"#輸出格式
)
logger = logging.getLogger(__name__) #實例化對象
# 實例化虛擬機
emulator = Emulator
#加載Libc庫
emulator.load_library( "example_binaries/libc.so", do_init= False)
#加載要模擬器的庫
lib_module = emulator.load_library( "example_binaries/libnative-lib.so")
#打印已經加載的模塊
logger.info( "Loaded modules:")
formodule inemulator.modules:
logger.info( "[0x%x] %s"% (module.base, module.filename))
#trace 每步執行的指令, 方便調試, 其實也可以取消
defhook_code(mu, address, size, user_data):
instruction = mu.mem_read(address, size)
instruction_str = ''.join( '{:02x} '.format(x) forx ininstruction)
print( '# Tracing instruction at 0x%x, instruction size = 0x%x, instruction = %s'% (address, size, instruction_str))
emulator.mu.hook_add(UC_HOOK_CODE, hook_code)
#通過導出符號來調用函數
emulator.call_symbol(lib_module, '_Z4testv')
#通過R0來獲取調用結構
print( "String length is: %i"% emulator.mu.reg_read(UC_ARM_REG_R0))
自己寫個小Demo測試
Demo代碼
新建一個jni工程, demo的代碼很簡單, 就是一個加法。
JNIEXPORT intnativeAdd(inta, intb)
{
returna + b;
}
extern"C"JNIEXPORT jint JNICALL
Java_com_mario_testunicorn_MainActivity_myAdd(
JNIEnv* env,
jobject /*this*/,
inta,
intb){
returnnativeAdd(a,b);
}
emu代碼
注釋寫的很詳細, 具體看代碼吧。
importlogging
importposixpath
importsys
fromunicorn importUcError, UC_HOOK_CODE, UC_HOOK_MEM_UNMAPPED
fromunicorn.arm_const import*
fromandroidemu.emulator importEmulator
importdebug_utils
# 配置日志
logging.basicConfig(
stream=sys.stdout,
level=logging.DEBUG,
format= "%(asctime)s %(levelname)7s %(name)34s | %(message)s"
)
logger = logging.getLogger(__name__)
# 初始化模擬器
emulator = Emulator(
vfp_inst_set= True,
vfs_root=posixpath.join(posixpath.dirname(__file__), "vfs")
)
# 加載依賴的動態庫
emulator.load_library( "example_binaries/libdl.so")
emulator.load_library( "example_binaries/libc.so", do_init= False)
emulator.load_library( "example_binaries/libstdc++.so")
emulator.load_library( "example_binaries/libm.so")
lib_module = emulator.load_library( "example_binaries/libmytest.so")
# 當前已經load的so
logger.info( "Loaded modules:")
formodule inemulator.modules:
logger.info( "=> 0x%08x - %s"% (module.base, module.filename))
try:
# 運行jni 這里沒有, 但不影響執行
emulator.call_symbol(lib_module, 'JNI_', emulator.java_vm.address_ptr, 0x00)
#直接調用符號1, 計算1+2
emulator.call_symbol(lib_module, '_Z9nativeAddii', 1, 2)
print( "_Z9nativeAddii result call: %i"% emulator.mu.reg_read(UC_ARM_REG_R0))
#直接調用符號2, 計算1000 + 1000
emulator.call_symbol(lib_module, 'Java_com_mario_testunicorn_MainActivity_myAdd', 0, 0, 1000, 1000)
print( "myAdd result call: %i"% emulator.mu.reg_read(UC_ARM_REG_R0))
#執行完成, 退出虛擬機
logger.info( "Exited EMU.")
logger.info( "Native methods registered to MainActivity:")
exceptUcError ase:
print( "Exit at %x"% emulator.mu.reg_read(UC_ARM_REG_PC))
raise
RuntimeError: Unhandled syscall x (x) at 解決
這個錯誤是因為沒有實現對應syscall導致的, 缺少什么函數, 自己寫一個函數綁定一下, 返回給他需要的值就可以了, 比如getpid, 那么自己寫的函數隨便返回一個整形就可以了。
在syscall_hooks.py文件里, 可以看到作者已經實現的函數。
self._syscall_handler.set_handler( 0x4E, "gettimeofday", 2, self._handle_gettimeofday)
self._syscall_handler.set_handler( 0xAC, "prctl", 5, self._handle_prctl)
self._syscall_handler.set_handler( 0xF0, "futex", 6, self._handle_futex)
self._syscall_handler.set_handler( 0x107, "clock_gettime", 2, self._handle_clock_gettime)
self._syscall_handler.set_handler( 0x119, "socket", 3, self._socket)
self._syscall_handler.set_handler( 0x11b, "connect", 3, self._connect)
self._syscall_handler.set_handler( 0x159, "getcpu", 3, self._getcpu)
self._syscall_handler.set_handler( 0x14e, "faccessat", 4, self._faccessat)
self._syscall_handler.set_handler( 0x14, "getpid", 0, self._getpid)
self._syscall_handler.set_handler( 0xe0, "gettid", 0, self._gettid)
self._syscall_handler.set_handler( 0x180, "null1", 0, self._null)
set_handler函數參數:
arg1: 中斷號(intno),中斷號可以在 ndk中的 unistd.h中找到
arg2: 函數名
arg3: 參數數量
arg4: 綁定的自定義函數
執行結果
實戰一款風控SO
實戰目標
以下信息通過分析所得, 具體分析過程不是本文重點,這里不贅述。
目標文件: libtest.so
目標函數: a( char* buf, intbuf_len)
返回值: return_value > 0, 表示風險環境并且會在buf參數里寫入詳細風險環境信息;
return_value == 0, 表示正常環境
EMU代碼
詳情看注釋, 寫的很詳細。
importlogging
importposixpath
importsys
fromunicorn importUcError, UC_HOOK_CODE, UC_HOOK_MEM_UNMAPPED
fromunicorn.arm_const import*
fromandroidemu.emulator importEmulator
fromandroidemu.java.java_class_def importJavaClassDef
fromandroidemu.java.java_method_def importjava_method_def
# Create java class.
importdebug_utils
# 配置日志
logging.basicConfig(
stream=sys.stdout,
level=logging.DEBUG,
format= "%(asctime)s %(levelname)7s %(name)34s | %(message)s"
)
logger = logging.getLogger(__name__)
# 初始化模擬器
emulator = Emulator(
vfp_inst_set= True,
vfs_root=posixpath.join(posixpath.dirname(__file__), "vfs")
)
# 加載依賴的動態庫
emulator.load_library( "example_binaries/libdl.so")
emulator.load_library( "example_binaries/libc.so", do_init= False)
emulator.load_library( "example_binaries/libstdc++.so")
emulator.load_library( "example_binaries/liblog.so")
emulator.load_library( "example_binaries/libm.so")
#目標so
lib_module = emulator.load_library( "example_binaries/libtest.so")
# 當前已經load的so
logger.info( "Loaded modules:")
formodule inemulator.modules:
logger.info( "=> 0x%08x - %s"% (module.base, module.filename))
try:
# 運行jni 這里沒有, 但不影響執行
emulator.call_symbol(lib_module, 'JNI_', emulator.java_vm.address_ptr, 0x00)
# 增加properties, 該so或通過獲取一些properties來判斷環境
emulator.system_properties[ 'ro.build.fingerprint'] = 'google/passion/passion:2.3.3/GRI40/102588:user/release-keys'
emulator.system_properties[ 'ro.product.cpu.abi'] = 'arm'
emulator.system_properties[ 'microvirt.vbox_dpi'] = ''
#申請一塊buff, 用作參數
emulator.call_symbol(lib_module, 'malloc', 0x1000)
address = emulator.mu.reg_read(UC_ARM_REG_R0)
#在之前申請的buff讀取內存
detect_str = memory_helpers.read_utf8(emulator.mu, address)
print( "detect_str: "+ detect_str)
#執行完成, 退出虛擬機
logger.info( "Exited EMU.")
logger.info( "Native methods registered to MainActivity:")
exceptUcError ase:
print( "Exit at %x"% emulator.mu.reg_read(UC_ARM_REG_PC))
raise
執行結果:
可以看見, 函數已經調用成功, 并且已經成功獲取返回值和參數, 不過檢測出風險環境了(因為我的vfs文件都是從虛擬機里拷貝出來的), 接下來就可以分析檢測點了!~~
過檢測
1. 通過執行日志分析, 發現頻繁訪問了build.prop, maps等系統環境, 猜測可能是通過這些文件來判斷的, 這里列出個別幾個。
2019- 09- 2116: 08: 27, 677INFO androidemu.vfs.file_system | Reading 1024bytes from '/proc/cpuinfo'
2019- 09- 2116: 08: 27, 680DEBUG androidemu.cpu.syscall_handlers | Executing syscall read( 00000005, 02089000, 00000400) at 0xcbc1ba7c
2019- 09- 2116: 08: 27, 783INFO androidemu.vfs.file_system | Reading 1024bytes from '/proc/self/maps'
2019- 09- 2116: 08: 27, 784DEBUG androidemu.cpu.syscall_handlers | Executing syscall close( 00000008) at 0xcbc1a854
2019- 09- 2116: 08: 27, 886INFO androidemu.vfs.file_system | File opened '/proc/self/status'
2019- 09- 2116: 08: 27, 887DEBUG androidemu.cpu.syscall_handlers | Executing syscall fstat64( 0000000a, 000ff3e8) at 0xcbc1b314
2. 通過反復測試, 修改對應文件中的關鍵信息, 最終成功躲過該風控模塊的環境檢測。
如下:
總結
該項目是通過Unicron來實現的, Unicorn 是一款非常優秀的跨平臺模擬執行框架, 通過上帝視角來調試和調用二進制代碼, 幾乎可以很清晰發現反調試和檢測手段, 而Unicorn的應用絕不僅僅只是個虛擬機, 可以實現很多騷操作, 再次感謝QEMU, Unicron, AndroidNativeEmu等等這些開源大神, 是這些人的分享精神推進了整個圈子的技術迭代。
看雪ID:StriveMario
https://bbs.pediy.com/user-773600.htm
*本文由看雪論壇 StriveMario 原創,轉載請注明來自看雪社區
﹀
﹀
責任編輯:
總結
以上是生活随笔為你收集整理的python中emuterate用法_跨平台模拟执行 - AndroidNativeEmu实用手册的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pythonimportre_Pytho
- 下一篇: 极光尔沃切片软件_极光尔沃3D打印机走进