某天在應用商店挑選「幸运儿」时,一不小心選到了NP保護的,我想這便是天意。
自那天起便開啟了這段漫長的分析之旅,數以百次的調試,最後留下本文。
樣本: anAuZ29vZHNtaWxlLnRvdWhvdWxvc3R3b3JkX2FuZHJvaWQ=
1. libcompatible.so分析
NP的關鍵so為libcompatible.so、libstub.so和libengine.so,三者之間環環相扣,先看libcompatible.so。
1.1 導出符號混淆
通過readelf找到.init_proc在0x154028。
# readelf -d libcompatible.so
readelf: Error: no .dynamic section in the dynamic segment
Dynamic section at offset 0x1abd80 contains 29 entries:
Tag Type Name/Value
0x000000000000000c (INIT) 0x154028
發現.init_proc被一些導出符號分割了,導致IDA無法F5。

image.png (51.06 KB, 下载次数: 0)
下载附件
2025-9-20 16:37 上传
用乐佬那篇文章的解決思路,手動把位於.init_proc範圍內的導出符號置空即可。
import struct
input_path = r"libcompatible.so"
output_path = r"libcompatible_p.so"
sym_start = 0x2F8
sym_end = 0xACD8
sym_size = 0x18
init_proc_start = 0x154028
init_proc_end = 0x15B06C
data = None
with open(input_path, mode = "rb") as f:
data = bytearray(f.read())
for sym in range(sym_start, sym_end, sym_size):
st_value = struct.unpack("= init_proc_start and st_value
patch後就能順利F5了,發現.init_proc中有如下虛假控制流。

image1.png (25.24 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
bcf的解決思路可參考oacia大佬的這篇文章:https://oacia.dev/ollvm-study/
1.2 init_proc分析
計算獲取libcompatible.so的基址,保存在libcompatible_base中。然後調用give_load_seg_rwx()。

image2.png (16.05 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
give_load_seg_rwx()的實現如下,根據libcompatible_base解析 & 遍歷phdr,記錄最後一個loadable seg的結束位置,記為last_loadseg_end。
將last_loadseg_end對齊內存頁大小後的值作為mprotect()的size,保證基本上全部代碼段、數據段都有rwx權限。

image3.png (65.02 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
回到.init_proc繼續向下看。
調用了mmap系統調用,映射了一頁rwx權限的內存,記為這片內存為mmap_buf。

image4.png (37.09 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
調用decrypt_something1(),解密了一些數據,結果存放在data_from_dec中。

image5.png (31.22 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
調用decrypt_something2(),根據data_from_dec來解密args[1]。記解密後的數據為data_from_dec2。

image6.png (28.27 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
然後會根據data_from_dec2來對mmap_buf賦值。

image7.png (64.17 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
由於mmap_buf有執行權,因此嘗試將賦予mmap_buf的數據解析為代碼,發現是svc。

image8.png (34.03 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
之後svc會被保存到全局變量中。

image9.png (55.17 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
完成svc的賦值後,調用了cache_maintenance()來更新mmap_buf的cache緩存。

image10.png (57.03 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
調用decrypt_some_str()解密了一些字符串,保存在全局變量中。
它的字符串解密邏輯如下:
[ol]
[/ol]
解密了一些ro.屬性,大概是在做兼容。

image11.png (40.38 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
之後獲取了當前so的.dynamic段。

image12.png (43.65 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
解析.dynamic,獲取重定向相關信息,如RELA表,JMPREL表等。

image13.png (59.28 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
清空重定向表。

image14.png (69.6 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传

image15.png (60.92 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
最後會分別調用I1 ~ I3這3個導出函數( 是在上面被解密的 ),調用後會把函數加密回去( 那些異或操作一開始以為是解密,後來才發現是加密 )。

image16.png (101.6 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
簡單看了下I1和I2,沒有太特別的地方,重點在I3這個導出函數。
1.3 I3函數分析
sub_7A635BF48C()設置了某些導出符號的其中幾個字節,不知在干什麼。
之後mmap了一片rw權限的內存,記為mmap_buf2。

image17.png (37.5 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
對mmap_buf2進行賦值。

image18.png (23.97 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
之後會來到下圖的地方,若F7單步步入紅框慢慢跟,IDA似乎會crash,而F8直接步過則不會?

image19.png (44.39 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
把某個函數賦給了some_func1變量

image20.png (26.98 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
1.3.1 解密libcompatible.so的JNI_OnLoad
之後就來到第1處fla,顯然是關鍵邏輯處。

image21.png (63.5 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
簡單看看這個fla。
這個地方在解密一段代碼,把v144指向的地址減去基址,得到的偏移記為off。

image22.png (23.54 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
從dump出來的libcompatible.so中搜off,發現off在JNI_OnLoad()中,由此可知上述解密的代碼正是JNI_OnLoad()。

image23.png (24.3 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
第2處解密JNI_OnLoad()的地方,由此可知JNI_OnLoad()是分段解密的。

image24.png (32.86 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
第3處解密JNI_OnLoad()的地方。

image25.png (26.84 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
JNI_OnLoad()的解密應該只分成了3段,解密完後會調用cache_maintenance(),似乎每次解密完代碼後都會調用該函數做cache相關的處理。
cache_maintenance()的args[0]是被解密代碼的起始地址,args[1]是結束地址,這個地址範圍中包含多個解密後的函數。

image26.png (32.99 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
1.3.2 一些檢測邏輯
然後就是第2處fla,記為fla2。

image27.png (59.84 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
同樣是一段代碼解密邏輯,解密的是0xF70D0處的代碼。

image28.png (31.65 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
解密後發現只是一個功能函數。

image29.png (14.19 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
fla2中第2處代碼解密邏輯。

image30.png (28.5 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
fla2中第3處代碼解密邏輯。

image31.png (24.5 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
注:上述的代碼解密邏輯可能會被交替調用來對同一個函數進行解密。
解密完成後,同樣調用了cache_maintenance()。

image32.png (25.14 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
然後調用了check_something()進行一些檢測,其中又大概可分成check1() ~ check5()5個小檢測。

image33.png (72.44 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
先看check1(),一開始調用了prctl("PR_SET_DUMPABLE"),不知為何。
然後調用newfstatat系統調用獲取/proc//environ相關信息。

image34.png (49.17 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
將statbuf設置為struct stat statbuf類型後,可以看出調用newfstatat()是為了獲取時間戳來實現時間檢測。

image35.png (22.62 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传

image36.png (71.8 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
接下來看check2()。
解密了"magisk",然後調用openat系統調用打開"/proc/self/mounts",顯然是在檢測magisk。

image37.png (56.16 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
調用read系統調用讀取/proc/self/mounts,每次讀2048字節,其中包含換行符,要手動處理。
處理完後就是檢查/proc/self/mounts每行是否包含magisk字樣,以此來檢測magisk。

image38.png (50.85 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
然後check3()是經典的root檢測。

image39.png (69.29 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传

image40.png (25.43 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
check4()是動調檢測。

image41.png (46.43 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
最後是check5()。

image42.png (27.13 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
check5_func1()打開了/proc/self/maps,解密了解析maps文件的格式化字符串,保存在a1中。

image43.png (68.24 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
check5_func2()調用read系統調用讀取maps文件,同樣手動處理換行符後,調用自實現的sscanf解析maps信息,最後保存到a1中。

image44.png (20.68 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
調用完check5_func2()後,解密出了"/system/bin/app_process"字串,然後與maps_lib_path對比。
這裡是為了匹配maps中的/system/bin/app_process。

image45.png (59.27 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
匹配成功後,調用process_app_process()。

image46.png (29.01 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
process_app_process()會遍歷內存中的/system/bin/app_process64,看看其中是否存在magisk字串。

image47.png (67.03 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
process_app_process()檢查完之後,會調用check5_func3()。

image48.png (23.55 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
check5_func3()同樣是一些magisk檢測,如下:
[ol]
[/ol]

image49.png (29.65 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
[ol]
[/ol]

image50.png (41.35 KB, 下载次数: 0)
下载附件
2025-9-20 16:45 上传
[ol]
[/ol]

image51.png (38.14 KB, 下载次数: 0)
下载附件
2025-9-20 17:29 上传
至此分析完check_something()。
1.3.3 調用.init_array函數 & 收尾
回到I3函數向下看。
有個while循環不斷從一個類似函數列表的地方取函數並調用,這個函數列表大概就是解密後的.init_array。

image52.png (29.2 KB, 下载次数: 0)
下载附件
2025-9-20 17:29 上传
.init_array[0]中調用了unsetenv("LD_PRELOAD"),這大概是一種反注入的機制。unsetenv()還會再遍歷一次PATH環境變量,確保LD_PRELOAD真的被unset掉,否則會直接exit()。

image53.png (46.29 KB, 下载次数: 0)
下载附件
2025-9-20 17:29 上传
除了.init_array[0]外,其他.init_array函數似乎都與檢測無關。
1.4 JNI_OnLoad分析 (part1)
由上述分析可知,I3函數執行完後,JNI_OnLoad()也被解密完成。因此在那時機下斷點跳過去分析JNI_OnLoad()。
開始分析JNI_OnLoad()。
調用了mprotect系統調用,賦予某片內存rwx的權限。

image54.png (23.46 KB, 下载次数: 0)
下载附件
2025-9-20 17:29 上传
保存了JNI_OnLoad的前0x10字節,暫時未知用來做什麼。

image55.png (27.54 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
然後就是熟悉的控制流。

image56.png (33.75 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
同樣是一些函數解密的邏輯。

image57.png (25.52 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传

image58.png (25.94 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
最終同樣會調用cache_maintenance()。
之後調用了sub_777F32BB58(),其中會間接調用a1 + 48指向的函數。

image59.png (25.63 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
跟進去後發現是GetEnv()。

image60.png (33.45 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
然後又判斷了一次package name是否以_zygote結尾。

image61.png (38.94 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
之後調用了JNI_OnLoad_func1()進行一些檢測。

image62.png (18.79 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
JNI_OnLoad_func1()中解密了以下字符串:( 都是模擬器的特徵 )
檢測的邏輯同樣是按上述方式解析/proc/self/maps後,看看是否存在這些so,是則代表是模擬器。

image63.png (84.84 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
之後反射調用了一個Java層的函數。

image64.png (55.33 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
發現只是一個固定返回true函數?

image65.png (16.08 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
然後動態注冊了一些JNI函數。

image66.png (24.77 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
第1個register_natives()注冊了以下Java類的native函數:
第2個register_natives()注冊了以下Java類的native函數:

image67.png (64.24 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
然後又解密了一個函數( 下圖的sub_777E313F98() ) ,記該函數為JNI_OnLoad_decfunc1()。

image68.png (32.34 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
1.5 JNI_OnLoad_decfunc1分析 (part1)
進行了一些咚汜幔{用了KM4PI0Z7J8QMILO5G6P6()。

image69.png (53.4 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
KM4PI0Z7J8QMILO5G6P6()記錄了以下目錄的「最後存取時間」之和,但不知有什麼用。

image70.png (75.99 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
之後又在一處fla中解密了某個函數,記該函數為big_func()。

image71.png (47.35 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
1.6 big_func分析
之所以叫big_func(),是因為該函數的F5偽代碼有六千多行。
1.6.1 sapi初始化
一開始解密了一些與libc相關的字串,通過sprintf()組裝後傳入了parse_libc()。

image72.png (64.07 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
parse_libc()先從/proc/self/maps獲取libc.so的相關信息,然後調用do_parse_libc()進行解析。

image73.png (23.99 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
do_parse_libc()開頭解析了libc的dynamic。

image74.png (44.74 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
do_parse_libc()最後分別調用了get_libc_info()來將ELF GNU Hash Table和dynamic等信息保存在args[0]中。
然後調用save_some_libc_sym()獲取了libc中的一些符號偏移,如clone()、__libc_sysinfo、_ZL13g_thread_list。

image75.png (20.45 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
回到big_func()繼續向下看。之後調用了lookup_libc_sym()。

image76.png (37.68 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
lookup_libc_sym()中調用了find_symbol_by_name()來根據函數名獲取對應的符號地址( 原理是gnu hash ),保存在全局變量g_libc_funcs中。

image77.png (66.94 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传

image78.png (23.85 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
之後又解密了一些函數來加載自己的libc,主要邏輯在load_mylibc()中,加載後的libc記為mylibc。

image79.png (50.92 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
load_mylibc()主要干了以下事情:
[ol]
[/ol]

image80.png (29.86 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
[ol]
[/ol]

image81.png (45.13 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
[ol]
[/ol]

image82.png (48.57 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
注:分析過程中會發現在LoadSection()和ClearShdr()最後都有以下函數調用,其args[3]似乎就代表了所在函數的功能。
// 在LoadSection()最後:
sub_777F3E56B0(1u, 0x64u, 9u, (__int64)"LoadSection", 0x120u);
// 在ClearShdr()最後:
sub_777F3E56B0(1u, 0x64u, 9u, (__int64)"ClearShdr", 0x344u);
load_mylibc()執行完之後,從mylibc獲取了一些函數單獨保存下來,如malloc、calloc、realloc等等。

image83.png (57.33 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
之後調用prepare_for_inline_hook()來保存指定mylibc函數的前0x32字節,結果保存在args[0]中,然後傳入inline_hook()進行hook。

image84.png (60.96 KB, 下载次数: 0)
下载附件
2025-9-20 17:30 上传
以mylibc的calloc()為例,在inline_hook()後,前0x10字節被改為跳到原libc的calloc()。

image85.png (35.84 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
之後又繼續從mylibc獲取了一堆函數單獨保存到全局變量中,不一一列出了。
但獲取的目的並不是為了像上面那樣inline hook,而大概是之後會用到,所以提前保存下來。

image86.png (59.81 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
1.7 JNI_OnLoad_decfunc1分析 (part2)
big_func()執行完後,回到JNI_OnLoad_decfunc1()。
同樣的形式解密了一段代碼。

image87.png (39.12 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
1.7.1 anti xposed & anti debugging
check_xposed()中遍歷了maps,看看是否存在XposedBridge.jar。

image88.png (56.51 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
之後會來到一個反調試的函數,記為anti_debugging()

image89.png (28.34 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
調用mylibc的pthread_create()創建了一個線程。

image90.png (26.84 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
調用mylibc的fork()創建了兩個子線程,之後調用signal(17, 1)忽略子線程結束時送出的SIGCHILD信號。
嘗試動調此處邏輯,但總會發生一些非預期的結果,因此無法詳細分析anti_debugging()的具體實現原理。
唯一確定的是它調用了兩次mylibc的fork(),使得此時機後將IDA無法attach,記這種反調試為三進程保護。

image91.png (45.67 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
之後調用mylibc裡的pthread_create()創建一個線程,線程回調函數記為JOdf1_pthread_func3()。

image92.png (37.1 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
1.7.2 JOdf1_pthread_func3分析
一開始調用了check5() ( 上面已經分析過該函數,不再重複 )。
然後調用NativeBridge_check()進行NativeBridge注入檢測。

image93.png (62.19 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
NativeBridge注入檢測的原理參考這篇文章,檢測流程如下:
[ol]
[/ol]

image94.png (26.73 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
[ol]
[/ol]

image95.png (49.96 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
[ol]
[/ol]

image96.png (53.1 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
1.8 JNI_OnLoad分析 (part2)
JNI_OnLoad_decfunc1()執行完後,回到JNI_OnLoad(),又調用了mylibc的pthread_create()創建了線程。
之後會間接調用一個不正常地址導致SIGSEV?但pass to app後可以繼續執行,過段時間後才會真正crash?

image97.png (34.58 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
2. bypass三進程保護
要先bypass掉libcompatible.so的反調試,也能繼續動調後面的libstub.so。
2.1 bypass嘗試
嘗試直接patch掉anti_debugging()。
function hook_anti_debugging(base) {
Interceptor.replace(base.add(0x18C148), new NativeCallback(function (arg0) {
console.log("[hook_anti_debugging] a0: ", hexdump(arg0.readPointer()));
return ptr(0);
}, 'pointer', ['pointer']));
}
但報了SIGSEGV的錯,報錯時的PC在0x7130,十分奇怪。

image98.png (47.22 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
用frida + IDA動調後發現報錯點在下圖這裡。

image99.png (36.58 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
這種情況有兩種可能性:
[ol]
[/ol]
而情況1基本可以排除掉,因為直接動調( 沒有patch anti_debugging() ),走到上圖位置時同樣是0x7130,而且用trace排查時,顯示的也是0x7130。
因此大概率是情況2,而且調用的大概率也是mylibc的sigaction。
嘗試hook mylibc的sigaction(),但沒有觸發。
改為hook原libc的sigaction,反而有觸發,看來NP無法使用mylibc的sigaction()來注冊信號回調?
Interceptor.attach(Module.findExportByName("libc.so", "sigaction"), {
onEnter: function (args) {
console.log("[hook_sigaction] a0: ", (args[0]));
if (args[1].toInt32()) {
console.log("[hooksigaction] a1: ", hexdump(args[1]));
console.log("[hook_sigaction] a1: ", JSON.stringify(Process.findModuleByAddress(args[1].add(0x8).readPointer())));
console.log("[hook_sigaction] a1: ", ptr(args[1].add(0x8).readPointer() - base));
}
},
onLeave: function (retval) {
console.log("[hook_mylibc_sigaction] retval: ", retval);
}
});
輸出如下,0xb正是SIGSEGV,信號回調函數在libcompatible.so!0xaa994。
[hook_sigaction] a0: 0xb
[hooksigaction] a1: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
7fc4082ba0 04 00 00 08 00 00 00 00 94 99 81 9e 71 00 00 00 ............q...
7fc4082bb0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7fc4082bc0 12 ba 85 03 7c 62 4e 70 00 00 00 00 00 00 00 00 ....|bNp........
7fc4082bd0 80 2d 08 c4 7f 00 00 00 2c be 8f 9e 71 00 00 00 .-......,...q...
7fc4082be0 ac f4 8f 9e 71 00 00 00 9c 38 ba 84 00 00 00 00 ....q....8......
7fc4082bf0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7fc4082c00 50 36 92 9e 71 00 00 00 00 00 00 00 00 00 00 00 P6..q...........
7fc4082c10 70 56 93 9e 71 00 00 00 b4 56 93 9e 71 00 00 00 pV..q....V..q...
7fc4082c20 7c 31 92 9e 71 00 00 00 ac f4 8f 9e 71 00 00 00 |1..q.......q...
7fc4082c30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7fc4082c40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7fc4082c50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7fc4082c60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7fc4082c70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7fc4082c80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7fc4082c90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[hook_sigaction] a1: {"name":"libcompatible.so","base":"0x719e76f000","size":1863680,"path":"/data/app/jp.goodsmile.touhoulostword_android-KNfNiSYf49IV5K_x4TTh3Q==/lib/arm64/libcompatible.so"}
[hook_sigaction] a1: 0xaa994
[hook_mylibc_sigaction] retval: 0x0
0xaa994如下,記為SIGSEGV_cb()

image100.png (55.23 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
在sub_187310()中可以看到0x7130。

image101.png (39.49 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
SIGSEGV_cb()最終會根據fault address分發不同的函數,之後會看到。
3. libstub.so分析
在bypass掉三進程保護後,終於可以動調分析後續的流程,首先是libstub.so的加載。
3.1 SoLibraryStart分析
libstub.so的.init_proc中會調用libcompatible.so!SoLibraryStart()來解密。
SoLibraryStart()中的qword_1B41E0固定是0x4580,因此必然會觸發SIGSEGV的信號回調SIGSEGV_cb()。

image102.png (21.37 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
SIGSEGV_cb()會根據導致異常的地址來執行對應的函數,如0x4580會執行func_4580()。

image103.png (45.49 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
3.2 func_4580分析 (part1)
打斷點跳到func_4580()進行分析。
調用了check_and_decrypt_libstub()。

image104.png (30.16 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
check_and_decrypt_libstub()中會先調用check_enc_flag()確定libstub.so是加密的。

image105.png (29.76 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
check_enc_flag()具體實現如下,打開本地的libstub.so並檢查最後20字節是否與固定的加密標誌相等。

image106.png (56.68 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
而decrypt_libstub_data()一開始先獲讀取了libstub[0:0xB758],然後再讀取libstub[0x1CAA8: 0x1CAA8 + 0x3EFEE],記為後者為libstub_enc_data1。

image107.png (62.05 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
注:從010可知0x1CAA8正好在section header後面。

image108.png (61.79 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
第1處解密libstub_enc_data1的地方。

image109.png (26.09 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
第2處解密libstub_enc_data1的地方。

image110.png (23.8 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
第3處解密libstub_enc_data1的地方。

image111.png (27.51 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
調用LZ4_decompress_fast()對解密後的libstub_enc_data1進行解壓。

image112.png (41.94 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
解壓後的數據如下,可以看到包含一些重定向信息,記為dec_data1。

image113.png (20.23 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
讀取了libstub[0x5BA96:0x5BA96 + 0x15C0],記為libstub_enc_data2,然後解密,再解壓。

image114.png (59.02 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
解壓後的數據如下,可以看出應該是符號表,記為sym。

image115.png (18.06 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
讀取了libstub[0x5D056:0x5D056+ 0x1230],記為libstub_enc_data3,然後解密,再解壓。

image116.png (59.47 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
解壓後的數據如下,可以看出是字符串表,記為strtab。

image117.png (40.73 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
讀取了libstub[0x5E286:0x5E286 + 0x29B0],記為libstub_enc_data4,然後解密,再解壓。

image118.png (55.98 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
解壓後的數據如下,可以看到同樣是一些重定向信息( 403重定向 ),記為relocate1。

image119.png (21.47 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
讀取了libstub[0x60C36:0x60C36 + 0x4F0],記為libstub_enc_data5,然後解密,再解壓。

image120.png (59.36 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
解壓後的數據如下,可以看到同樣是一些重定向信息( 402重定向 ),記為relocate2。

image121.png (18.94 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
讀取了libstub[0x61126:0x61126 + 0x30],記為libstub_enc_data6,然後解密,再解壓…

image122.png (55.48 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
解壓後的數據如下,可以看出是libstub.so的依賴庫。

image123.png (17.25 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
最後讀取了libstub[0x61146:0x61146 + 0x20],但似乎沒有用到,大概只是加密數據的結束標誌?

image124.png (61.01 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
至此大致分析完check_and_decrypt_libstub()。回到func_4580()。
調用set_w_perm_to_libstub()賦予libstub.so可寫的權限。dlopen_needs()會調用dlopen()加載libstub.so的所有DT_NEED庫。
MEMORY[0x7510]()會觸發SIGSEGV_cb(),然後跳到func_7510()。

image125.png (43.97 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
3.3 func_7510分析
看到"ldrRestoreDynSymInfo",見名知意,大概是在恢復libstub.so的一些動態符號信息。

image126.png (28.52 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
忽略前面一些不太知道在干什麼的邏輯後,來到下圖這裡,解密了一些符號名。

image127.png (51.05 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传

image128.png (58.2 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传

image129.png (45.03 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
然後會對比libstub.so的字符串表( 上面解密出來的那個 ),若包含上述的符號名,則會把對應函數( 如下圖的some_func2(),它是libcompatible.so的函數 )保存到某個地方。
猜測是libstub.so之後會用到libcompatible.so中的一些函數,因而用這種方式提前保存函數地址到某處。

image130.png (19.48 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
3.4 func_4580分析 (part2)
func_7510()之後,回到func_4580()會執行重定向的邏輯,然後調用.init_array的函數。
3.4.1 relocate
一開始解密了"dlopen"、"dlsym"、"il2cpp.so"等字符串,不知道干什麼。

image131.png (90.28 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
然後就是熟悉的重定向操作:

image132.png (46.73 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传

image133.png (41.02 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
注:重定向的對象並非maps中的libstub.so,而是內存中的libstub.so。

image134.png (51.18 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
通過maps查看內存中的libstub.so範圍,然後把這片內存dump下來,記為libstub_dump.so。

image135.png (15.18 KB, 下载次数: 0)
下载附件
2025-9-20 17:31 上传
import idaapi
data = idaapi.dbg_read_memory(0x7c61330000, 0x7c613d2000 - 0x7c61330000)
fp = open(r'libstub_dump.so', 'wb')
fp.write(data)
fp.close()
3.4.2 call_constructors
調用libstub.so的.init_array函數。

image136.png (27.56 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
.init_array的偏移為0x8FDE0。

image137.png (48.76 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
3.5 修復libstub.so
將dec_data1 dump下來會發現,其中包含了relocate1和relocate2,還有.dynamic信息。

image138.png (45.98 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
至於解密後的代碼段和數據段,應該已經在libstub_dump.so中,但libstub_dump.so中並不包含strtab、sym和.dynamic的信息。
也不包含shdr和shstrtab字符串表,這兩者可從原libstub.so中獲取,前者在修復時直接覆蓋到原位置,後者隨便寫到最後的一片空區域即可。

image139.png (21.02 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
從原libstub.so提取shstrtab。

image140.png (48.08 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
section修複,大概只有.dynstr、.dynamic、.shstrtab是必要的,第0個section要為0,拉入IDA時才不會報錯。

image141.png (13.43 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
把修復後的libstub.so拉入IDA,發現只有少量的符號。

image142.png (70.56 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
3.6 init_array_func1分析
大概只有第1個.init_array函數是檢測的邏輯,同樣也是對環境變量的檢測,具體做法是在unsetenv("LD_PRELOAD")後,遍歷environ數組,若發現其中仍有LD_PRELOAD則直接exit()。

image143.png (64.49 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
3.7 JNI_OnLoad分析
保存了一些libdl.so、libc.so的函數到某個全局變量中。

image144.png (75.55 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
嘗試尋找"com/inca/security/DexProtect/SecureApplication"類,但在本例會返回0。

image145.png (44.55 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
動態注冊了"com/inca/security/Native/AppGuardAssistantNative"、"com/inca/security/AppGuard/TestCase"中的一些JNI函數。

image146.png (56.44 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
第1處register_func()動態注冊了9個JNI函數,如startEngine()、stopEngine()等等。

image147.png (64.51 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
第2處register_func()動態注冊了4個JNI函數,如下圖所示。

image148.png (24.37 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
最後創建了兩個線程,暫時不知有什麼用。

image149.png (38.45 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
3.8 startEngine分析
startEngine()被控制流混淆了,如下所示。

image150.png (20.02 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
同時其中充斥著大量的空函數,或許也是一種混淆。

image151.png (8.77 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
分析的思路是,忽略上面這樣的空函數,關注那些有內容的函數,下斷點跳過去調試。
最終可把stratEngine()分成三部份,第一部份如下。

image152.png (35.83 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
第二部份。

image153.png (37.37 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
第三部份。

image154.png (44.13 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
在這三個部份中,都會調用某片匿名內存中的函數,一開始沒有多想,直接單步跟了進去調試,後來才想起這會不會就是libengine.so?
記那片匿名內存為mem_libengine,對比mem_libengine和libengine.so後發現,它們前面的字節的確是一樣的。( 本以為startEngine()會是加載libengine.so的邏輯,其實不然 )。

image155.png (37.03 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传

image156.png (65.47 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
4. libengine.so分析
4.1 哪裡加載的libengine.so?
知道了mem_libengine就是libengine.so後,以此作為入手點,分析哪裡加載的。
在libstub.so!JNI_OnLoad leave時機,maps中仍未有mem_libengine。在getVersion、setContext時,maps中有mem_libengine。
而在上面的分析中提過,libstub.so!JNI_OnLoad最後創建了一些線程,最終確定大概率是在sub_53AC4中加載的libengine.so。
通過frida stalker確定了sub_53AC4中會調用libcompatible.so!0xA1990。

image157.png (17.29 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
4.2 libengine.so加載
接下來看看libcompatible.so!0xA1990是怎麼加載libengine.so的。
首先調用了LoadEngineLibrary(),其中一開始拼接了libengine.so的絕對路徑。

image158.png (54.73 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
然後調用sys_mmap()映射一片匿名內存,調用sys_lseek() + sys_read()讀取libengine.so。

image159.png (71.15 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
LoadEngineLibrary()之後會來到熟悉的解密函數( 在上方被我命名為check_and_decrypt_libstub )。

image160.png (31.17 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
注:邏輯基本相同,不再重複分析,將所需數據dump下來。

image161.png (9.2 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
之後同樣調用了dlopen_needs()。

image162.png (21.66 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
然後是ldrRestoreDynSymInfo(),但這次是直接調用,而非通過信號回調的形式來間接調用。

image163.png (20.39 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
然後是relocate()。

image164.png (13.3 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
可以在403重定向的位置,把內存中的libengine.so dump下來。

image165.png (25.03 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
注:libengine_base是由*(a1 + 2680)而來,2560則是libstub.so的。

image166.png (23.18 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
4.3 修復libengine.so
大致跟修復libstub.so一樣,都需要從dump出來的libengine中提取.dynamic和shstrtab。
不同的是這次連ehdr和phdr都沒有,需要手動補上,而且dump出來的libengine.so中也不帶重定向信息,也需要手動補。
好消息是修復相對簡單,壞消息是只有一些無用的符號!!!

image167.png (23.84 KB, 下载次数: 0)
下载附件
2025-9-20 17:32 上传
4.4 一些檢測
通過hook libengine.so的get_data_string()簡單看看其中的一些檢測點。
[ol]
[/ol]
[libengine_get_data_string2] LD_PRELOAD
[libengine_get_data_string2] LD_PRELOAD
[libengine_get_data_string2] LD_PRELOAD
[libengine_get_data_string2] LD_PRELOAD
[libengine_get_data_string2] LD_PRELOAD
[ol]
[/ol]
[libengine_get_data_string2] libhoudini.so
[libengine_get_data_string2] lib3btrans.so
[libengine_get_data_string2] /lib/arm/nb/libc.so
[libengine_get_data_string2] /lib64/arm64/nb/libc.so
[ol]
[/ol]
[libengine_get_data_string2] Unknown
[libengine_get_data_string2] UserPattern
[libengine_get_data_string2] GameGuardian
[libengine_get_data_string2] GameKiller
[libengine_get_data_string2] TeamCrakMemoryDump
[libengine_get_data_string2] YouXiXiuGaiQi
[libengine_get_data_string2] ChaoHaoWanXiuGaiQi
[libengine_get_data_string2] ParadiseIslandTraniner
[libengine_get_data_string2] QuanQuanYouXiZhouShou
[libengine_get_data_string2] HuangHL
[libengine_get_data_string2] GameCIH
[libengine_get_data_string2] GameSpeeder
[libengine_get_data_string2] SBTools
[libengine_get_data_string2] GameCheater
[libengine_get_data_string2] GameMaster
[libengine_get_data_string2] HexEditor
[libengine_get_data_string2] HaXplorer
[libengine_get_data_string2] DaxAttack
[libengine_get_data_string2] GMDSpeedTime
[libengine_get_data_string2] CoolBoyTimer
[libengine_get_data_string2] Freedom
[libengine_get_data_string2] RootCloak
[libengine_get_data_string2] LuckyPatcher
[libengine_get_data_string2] CheatEngine
[libengine_get_data_string2] BaMenYouXiXiuGaiShenQi
[libengine_get_data_string2] SpeedWizard
[libengine_get_data_string2] XiongMaoXiaYouXiZhuShou
[libengine_get_data_string2] TransGameHacker
[libengine_get_data_string2] AppCIH
[libengine_get_data_string2] xxAssistant
[libengine_get_data_string2] RepetiTouch
[libengine_get_data_string2] BotMaker
[libengine_get_data_string2] AnJianJingLing
[libengine_get_data_string2] YouXiFengWo
[libengine_get_data_string2] FingerReplayer
[libengine_get_data_string2] HiroMacro
[libengine_get_data_string2] SmartMacro
[libengine_get_data_string2] TheToucher
[libengine_get_data_string2] AutoTouch
[libengine_get_data_string2] ScreencastVideoRecorder
[libengine_get_data_string2] SCRScreenRecorder
[libengine_get_data_string2] LiziModifier
[libengine_get_data_string2] ZhuoMuNiao
// ...
[ol]
[/ol]
[libengine_get_data_string2] com.vqs.iphoneassess
[libengine_get_data_string2] com.huluxia.gametools
[libengine_get_data_string2] com.huluxiakajkia
[libengine_get_data_string2] com.huluxia.gametoolsdwaf
[libengine_get_data_string2] com.huati
[libengine_get_data_string2] com.zhushou.cc
[libengine_get_data_string2] com.jbelf.imei
[libengine_get_data_string2] com.mostwanted.crackzxc
[libengine_get_data_string2] com.paojiao.youxia
[libengine_get_data_string2] com.yx.youxia
[libengine_get_data_string2] com.yx.youxia_shuih
[libengine_get_data_string2] com.medroid.sbjiaqiangban
[libengine_get_data_string2] com.burakgon.gamebooster2
[libengine_get_data_string2] com.anzhuo.GameToos
[libengine_get_data_string2] mobi.infolife.gamebooster
[libengine_get_data_string2] com.android.gamespeedup
[libengine_get_data_string2] com.iplay.assistant
[libengine_get_data_string2] org.game.master
[libengine_get_data_string2] com.mjmcmdjijkjnjn.wdjdy
[libengine_get_data_string2] com.mnmfmnmfnnmhmo.wdmc
[libengine_get_data_string2] com.jjjnjmjljnjljpjmjl.wd
[libengine_get_data_string2] com.kkckchbjbe.ywwd
[libengine_get_data_string2] cn.com.opda.gamemaster
[libengine_get_data_string2] com.surcumference.xsposed
// ...
[ol]
[/ol]
[libengine_get_data_string2] /dev/input
[libengine_get_data_string2] /system/bin/input
[libengine_get_data_string2] /system/bin/monkey
[libengine_get_data_string2] /proc/self/maps
[libengine_get_data_string2] /proc/%d/maps
[libengine_get_data_string2] /proc/self/mem
[libengine_get_data_string2] /proc/%d/mem
[libengine_get_data_string2] /system/bin/dnsmasq
[libengine_get_data_string2] /system/bin/dnsmasq
[libengine_get_data_string2] /system/bin/efsks
[libengine_get_data_string2] /system/bin/efsks
[libengine_get_data_string2] /system/bin/pam_server
[libengine_get_data_string2] /system/bin/pam_server
[libengine_get_data_string2] pam_server
[libengine_get_data_string2] pam_server
[libengine_get_data_string2] /system/bin/pppd
[libengine_get_data_string2] /system/bin/pppd
[libengine_get_data_string2] /system/bin/ip6tables
[libengine_get_data_string2] /system/bin/ip6tables
[libengine_get_data_string2] /system/bin/iptables
[libengine_get_data_string2] /system/bin/iptables
[libengine_get_data_string2] /system/bin/ip
[libengine_get_data_string2] /system/bin/ip
[libengine_get_data_string2] /system/xbin/spritebud
[libengine_get_data_string2] /system/xbin/spritebud
[libengine_get_data_string2] /system/xbin/vold
[libengine_get_data_string2] /system/xbin/vold
[libengine_get_data_string2] /system/xbin/netd
[libengine_get_data_string2] /system/xbin/netd
[libengine_get_data_string2] /system/xbin/installd
[libengine_get_data_string2] /system/xbin/installd
[libengine_get_data_string2] /sbin/ueventd
[libengine_get_data_string2] /sbin/ueventd
[libengine_get_data_string2] /system/xbin/tcd
[libengine_get_data_string2] /system/xbin/tcd
[libengine_get_data_string2] /sbin/fsck_msdos
[libengine_get_data_string2] /sbin/fsck_msdos
// ...
[ol]
[/ol]
[libengine_get_data_string2] Magisk v16.3
[libengine_get_data_string2] 24576:Q3LvBhUvgZiPYOvdwpohg+A6ht6vDM3Wr/ZLpzuzK:iqCc/Qo3WN0K
[libengine_get_data_string2] 24576:ODIjkIhUvgZicFNM3WFPn7IfyG+K6BACjYDlZfjzW:vw3WF7ji0EY
[libengine_get_data_string2] 192:b60cVwbwmw1m1SMzRvyOEgRphVdKT+GxLSpyijl:u0cV+wmw1m1SMzRvyOEgRphVdY5LSXjl
[libengine_get_data_string2] 192:01gS1jU9ywbtTgRt7r+k1Sv1QspVmT+3Pv3WWvP8h:01gSi9ywbtTgRRr+k1Sv1QspV0CPvWWu
[libengine_get_data_string2] Magisk v16.4
[libengine_get_data_string2] 24576:TRAT0nEPHDSDC3N1Jd6/HIXaXfOO2SYC05PWIuul:aeDCfJd6/HIXa8PWIvl
[libengine_get_data_string2] 24576:i0yPElnEPHDSV4a5PWbzEDCHWJqV8/UcX+3fKh2pdG1Vtm:8reyAPWkDC+qV8/UcX+As
[libengine_get_data_string2] 192:x5kTwoH/w1m1SMzRvyOEgRphVdKT+GcLSpl+2i2pb:x2TwoH/w1m1SMzRvyOEgRphVdY0LSi2X
[libengine_get_data_string2] 192:x5kTwoH/w1m1SMzRvyOEgRphVdKT+GcLSpl+2i2pb:x2TwoH/w1m1SMzRvyOEgRphVdY0LSi2X
// ...
[libengine_get_data_string2] MagiskManager v5.7.0
[libengine_get_data_string2] 24576:TRAT0nEPHDSDC3N1Jd6/HIXaXfOO2SYC05PWIuul:aeDCfJd6/HIXa8PWIvl
[libengine_get_data_string2] 24576:i0yPElnEPHDSV4a5PWbzEDCHWJqV8/UcX+3fKh2pdG1Vtm:8reyAPWkDC+qV8/UcX+As
[libengine_get_data_string2] 192:x5kTwoH/w1m1SMzRvyOEgRphVdKT+GcLSpl+2i2pb:x2TwoH/w1m1SMzRvyOEgRphVdY0LSi2X
[libengine_get_data_string2] 192:a1gSyU9ywbtTgRt7r+k1Sv1eH6spVmT+wPv3WWvptY:a1gS/9ywbtTgRRr+k1Sv1eH6spV0FPvs
// ...
[ol]
[/ol]
[libengine_get_data_string2] YouXiFengWo v8.0.0
[libengine_get_data_string2] 98304:XXQYQqjBZK5eP/a8eOClHMyj4+/nc/FO1X7H:VJK5K/axTnc/FO9z
[libengine_get_data_string2] 98304:/U5oslClHMmj4+/O4qq8amgdG74GqDpU:M5oHTO4kamgQ4GYU
[libengine_get_data_string2] 1536:T7riB4iWRZdXOyOzdd0mFbOn6RYj/tIbGoH:XbeyOzddW6/bGoH
[libengine_get_data_string2] 1536:T7riB4iWRZdXOyOzdd0mFbOn6RYj/tIbGoH:XbeyOzddW6/bGoH
[libengine_get_data_string2] LuckyPatcher v4.1.9
[libengine_get_data_string2] 12288:k7glLaM1QMzMuK4PFSGOtB8j1n3A8ldEGt/tt3R3Mt/+8+C+ZtEt/3U33tR+i+PM:0M19DFLOD8j1blb41dXzo0agrJ0Wcug
[libengine_get_data_string2] 24576:agtzGv0XzvsaCEdoupLodt9KIIqCh8SOnSPNcHpeZ0s7:yYdCQpLodtgOnW+Yz
[libengine_get_data_string2] 192:psgSGHUf7u3yFOVrT8dK171SX14gDwFuL/D1+h8CYpm:psgSdf7u3yFOVrT8dK171SX14gDouL/A
[libengine_get_data_string2] 192:5sgSGHUf7u3yFOVrT8dK171SX14gDwFuL/D1NAOtr84mn:5sgSdf7u3yFOVrT8dK171SX14gDouL/Y
[libengine_get_data_string2] GameHacker v2.6.3
[libengine_get_data_string2] 6144:jV4GcAmz53H1eaMkCtqJr74+/zWZ7ZOR6p9xK5LeEXmkiMxh5UBWF9dCEOCiqop+:jacqNYZ7ZOR6pgLL8GhIWx9yJHXQ
[libengine_get_data_string2] 6144:jV4GcAmz53H1eaMkCtqJr74+/zWZ7ZOR6p9xK5LeEXmkiMxh5UBWF9dCEOCiqop+:jacqNYZ7ZOR6pgLL8GhIWx9yJHXQ
[libengine_get_data_string2] 96:ep3JWcOdtBV7ngScytHD6h+DTypBxRl3stWtEtVr3StC1tVtRHt/5tatWntBZt8s:eZOBhgSt4qTypBxRl3Wr7vhAQWbTij9D
[libengine_get_data_string2] 96:ep3JWcOdtBV7ngScytHD6h+DTypBxRl3stWtEtVr3StC1tVtRHt/5tatWntBZt8s:eZOBhgSt4qTypBxRl3Wr7vhAQWbTij9D
[libengine_get_data_string2] GameKiller v3.4.3
[libengine_get_data_string2] 98304:swAXGSs/B1OsdbM1Ccc5JiOienK628BjFMihcTgFR:NAXGSs/BYisc5JioDagR
[libengine_get_data_string2] 98304:D1Osd9K628B6eIj4eDhqT/+0BFGnktk7uQ/:DYD9rwi0BFUX7N
[libengine_get_data_string2] 768:zXgSdA13ryngSai6zO0o8co3ukZmtfrQN5Ato25o6kckWkQkBkSckkk/kikrkpk7:cRAkHtbySHvc5IRgoBnbIlbIO
[libengine_get_data_string2] 768:yXgSFA13ryngSai6zO0o8co3ukZmtfrQN5Ato25o6kckWkQkBkSckkk/kikrkpki:RRAkHtbySHvc5IRgoBnbwleUQ
[libengine_get_data_string2] xxAssistant v2.4.0
[libengine_get_data_string2] 49152:JbZEnH3yH8BBZGVDg3BaCe3JeiQw8zWC0s376e5HO17A0X8OBctF+pSCzbdLyUZC:JKnHAJv8R0s/ROA0iFUvdmUg
[libengine_get_data_string2] 49152:ut4+T3yH8BBZGVDg3BaCwAOBctF+p9m+k6oMNZ+69P+YHigdr0bZSd9MITAMltTH:K4CdF7L6FNZ+KHiw0VstAMltRL1
[libengine_get_data_string2] 768:pDmpgSqyD9mtGvOeSHSbzMNUXZZtPwci2ArFZQzRTBvy57U3RV5FYQwDbo60mSvu:9gMztdc81Se
[libengine_get_data_string2] 768:/DmpgSyyD9mtGvOeSHSbzMNUXZZtPwci2ArFZQzRTBvy57U3RV5FYQwDbo60mSvZ:L4MzDyQH7M
// ...
[ol]
[/ol]
[libengine_get_data_string2] GenyMotion
[libengine_get_data_string2] genymotion
[libengine_get_data_string2] GenyMotion
[libengine_get_data_string2] genymotion
[libengine_get_data_string2] Windroy
[libengine_get_data_string2] windroy
[libengine_get_data_string2] Windroy
[libengine_get_data_string2] windroy
[libengine_get_data_string2] Droid4X
[libengine_get_data_string2] droid4x
[libengine_get_data_string2] Droid4X
[libengine_get_data_string2] droid4x
[libengine_get_data_string2] TianTian
[libengine_get_data_string2] TianTian
[libengine_get_data_string2] TianTian
[libengine_get_data_string2] TianTian
[libengine_get_data_string2] CanPlay
[libengine_get_data_string2] canplay
[libengine_get_data_string2] CanPlay
[libengine_get_data_string2] canplay
[libengine_get_data_string2] VPhoneGaGa
[libengine_get_data_string2] VPhoneGaGa
[libengine_get_data_string2] BlueStacks
[libengine_get_data_string2] com.bluestacks.*
[libengine_get_data_string2] BlueStacks
[libengine_get_data_string2] com.bluestacks.*
[libengine_get_data_string2] MEmu
[libengine_get_data_string2] com.microvirt.*
[libengine_get_data_string2] MEmu
[libengine_get_data_string2] com.microvirt.*
[libengine_get_data_string2] Andy
[libengine_get_data_string2] org.greatfruit.andy.*
[libengine_get_data_string2] Andy
[libengine_get_data_string2] org.greatfruit.andy.*
[libengine_get_data_string2] DuOS
[libengine_get_data_string2] com.ami.syncduosservices
[libengine_get_data_string2] DuOS
[libengine_get_data_string2] com.ami.syncduosservices
[libengine_get_data_string2] TianTian
[libengine_get_data_string2] com.tiantian.ime
[libengine_get_data_string2] TianTian
[libengine_get_data_string2] com.tiantian.ime
[libengine_get_data_string2] RemixOS
[libengine_get_data_string2] com.jide.*
[libengine_get_data_string2] RemixOS
[libengine_get_data_string2] com.jide.*
[libengine_get_data_string2] CanPlay
[libengine_get_data_string2] com.huidong.canplay
[libengine_get_data_string2] CanPlay
[libengine_get_data_string2] com.huidong.canplay
[libengine_get_data_string2] Nox
[libengine_get_data_string2] /system/bin/nox
[libengine_get_data_string2] Nox
[libengine_get_data_string2] /system/bin/nox
[libengine_get_data_string2] TianTian
[libengine_get_data_string2] /system/bin/ttVM-prop
[libengine_get_data_string2] TianTian
[libengine_get_data_string2] /system/bin/ttVM-prop
[libengine_get_data_string2] MoMo
[libengine_get_data_string2] /system/app/MOMOStore/MOMOStore.apk
[libengine_get_data_string2] MoMo
[libengine_get_data_string2] /system/app/MOMOStore/MOMOStore.apk
5. 結語
看到這的讀者應該可以大致感受到NP的強大,自實現linker、自加載libc、信號回調的應用、反調試、各種檢測點、混淆,任何一點都值得仔細分析。除了這些,其實還有很多東西沒有分析到,但礙於時間和水平有限,筆者也只能分析到這裡,後續有時間或許可以再看看其他部份。
最後感謝乐佬的那篇文章,時至今日還是很有參考價值,還要感謝Code大佬,沒有他的的那句提點,或許就沒有這篇文章。
歡迎交流安卓手遊安全相關的內容,不論是攻方或防方的^^。