Kết quả tìm kiếm

Cơ chế phát hiện và đối phó Frida trên Android

Cơ chế phát hiện và đối phó Frida trên Android

16/08/2026
227
Văn Hải
Chia sẻ:

Phân tích cơ chế phát hiện và đối phó Frida trên Android

1. Giới thiệu

Trong quá trình phân tích ứng dụng Android, đặc biệt khi làm reverse engineering, Frida là một công cụ rất hữu ích.

Frida cho phép chúng ta can thiệp trực tiếp vào ứng dụng đang chạy để theo dõi hàm, đọc tham số, xem giá trị trả về, quan sát bộ nhớ hoặc kiểm tra luồng xử lý của ứng dụng.

Tuy nhiên, chính khả năng can thiệp mạnh này khiến Frida thường trở thành mục tiêu của các cơ chế anti-Frida.

Một ứng dụng có thể chủ động kiểm tra xem môi trường hiện tại có đang bị Frida can thiệp hay không. Nếu phát hiện, ứng dụng có thể thoát, từ chối thực hiện một chức năng hoặc thay đổi hành vi.

Trong bài viết này, mình sẽ phân tích các phương pháp phát hiện Frida thường gặp trên Android, đồng thời giải thích cách tư duy khi nghiên cứu những cơ chế này.

Các nội dung chính gồm:

  • Kiểm tra port của Frida;

  • Kiểm tra ptrace;

  • Kiểm tra D-Bus;

  • Kiểm tra /proc/<pid>/fd;

  • Kiểm tra tên thread;

  • Kiểm tra /proc/self/maps;

  • Phát hiện Inline Hook;

  • Phát hiện Java Hook;

  • Kiểm tra CRC của mã máy.

Mục tiêu của bài viết không phải chỉ là ghi nhớ một vài chuỗi như frida-agent hay một vài port mặc định, mà quan trọng hơn là hiểu ứng dụng dựa vào dấu hiệu nào để nhận biết môi trường instrumentation và cách chúng ta có thể lần ngược từ dấu hiệu đó đến code thực hiện việc kiểm tra.


2. Frida hoạt động như thế nào?

Trước khi tìm hiểu anti-Frida, cần hiểu cơ bản Frida làm gì.

Có thể hình dung một ứng dụng Android như sau:

Android Application
        │
        ├── Java / Kotlin
        │
        ├── JNI
        │
        └── Native C/C++
                │
                └── *.so

Khi sử dụng Frida, chúng ta có thể can thiệp vào quá trình này:

                    Android App
                        │
                        ▼
                  Native / Java
                        │
                        ▼
                      Frida
                        │
              ┌─────────┼─────────┐
              │         │         │
            Hook      Read      Modify
            Function  Memory    Return

Ví dụ, một hàm native:

int checkLogin(const char *token);

có thể được theo dõi để biết:

checkLogin()
       │
       ├── token truyền vào là gì?
       │
       └── kết quả trả về là gì?

Hoặc một hàm xử lý dữ liệu:

encrypt()
    ↓
serialize()
    ↓
send()

có thể được theo dõi để biết dữ liệu thay đổi như thế nào trước khi được gửi đi.

Chính vì vậy, từ góc nhìn của nhà phát triển ứng dụng, việc một công cụ có khả năng hook và quan sát các hàm quan trọng xuất hiện trong process có thể được xem là một dấu hiệu bất thường.


3. Anti-Frida thực chất là gì?

Anti-Frida không phải chỉ có một phương pháp.

Ứng dụng có thể kiểm tra rất nhiều thứ:

                    Anti-Frida
                        │
        ┌───────────────┼────────────────┐
        │               │                │
      Network         Process          Memory
        │               │                │
      Port            ptrace           maps
      D-Bus           threads          hook
                      fd               CRC

Điều này rất quan trọng.

Nếu một ứng dụng chỉ kiểm tra:

127.0.0.1:27042

thì đây là một cơ chế tương đối đơn giản.

Nhưng nếu ứng dụng đồng thời kiểm tra:

Port
+
/proc
+
Thread
+
Memory
+
Code integrity

thì việc phân tích sẽ phức tạp hơn nhiều.

Vì vậy, khi gặp một ứng dụng có anti-Frida, mình thường không tìm một “cách bypass duy nhất”, mà trước tiên xác định ứng dụng đang kiểm tra những dấu hiệu nào.


4. Kiểm tra port của Frida

Một trong những phương pháp đơn giản nhất là kiểm tra port mà Frida thường sử dụng.

Frida thường sử dụng:

27042
27043

Ứng dụng có thể kiểm tra các port trên localhost:

127.0.0.1:27042
127.0.0.1:27043

Nếu phát hiện service đang lắng nghe tại đây, ứng dụng có thể coi đó là dấu hiệu đáng ngờ.

Mô hình:

Application
    │
    ├── kiểm tra 27042
    │
    ├── kiểm tra 27043
    │
    └── phát hiện service
             │
             ▼
       nghi ngờ Frida

Đây là một ví dụ điển hình của detection dựa trên dấu hiệu môi trường.

Điểm cần lưu ý là không nên hiểu rằng:

Có port 27042 = chắc chắn có Frida.

Thực tế một port có thể được sử dụng bởi nhiều chương trình khác nhau.

Ngược lại:

Không có port 27042 cũng không có nghĩa là chắc chắn không có Frida.

Do đó, đây chỉ nên được xem là một lớp kiểm tra.


5. ptrace và cơ chế chống attach

ptrace là một cơ chế của Linux cho phép một process theo dõi hoặc debug process khác.

Debugger sử dụng cơ chế này để:

  • đọc trạng thái process;

  • theo dõi thread;

  • kiểm tra register;

  • can thiệp quá trình thực thi.

Một số ứng dụng sử dụng ptrace như một biện pháp anti-debug.

Ý tưởng được đề cập trong bài viết là ứng dụng tự gọi:

ptrace(...)

để chiếm trạng thái trace trước.

Có thể hình dung:

App khởi động
      │
      ▼
App tự thiết lập ptrace
      │
      ▼
Debugger / instrumentation
      │
      ▼
Không thể attach theo cách thông thường

Đây là lý do thời điểm instrumentation rất quan trọng.

Nếu ứng dụng thực hiện anti-debug ngay khi khởi động, việc chờ ứng dụng chạy hoàn toàn rồi mới attach có thể không còn hiệu quả.

Khi nghiên cứu trường hợp này, điều quan trọng là xác định:

ptrace()
   ↓
Ai gọi?
   ↓
Gọi ở đâu?
   ↓
Gọi lúc nào?
   ↓
Điều kiện nào dẫn tới việc gọi?

Từ đó có thể lần ngược call chain trong IDA hoặc Ghidra.


6. D-Bus và dấu hiệu giao tiếp của Frida

Một hướng khác được đề cập là kiểm tra dấu hiệu liên quan đến D-Bus.

D-Bus là một cơ chế IPC/RPC được sử dụng trong môi trường Linux.

Theo bài viết, ứng dụng có thể tìm các dấu hiệu liên quan đến Frida, trong đó có chuỗi:

frida:rpc

Ngoài việc tìm string, ứng dụng còn có thể thực hiện các phép kiểm tra liên quan đến giao tiếp và phân tích phản hồi.

Mô hình tổng quát:

Application
     │
     ├── tìm string
     │
     ├── kiểm tra IPC
     │
     └── phân tích response
              │
              ▼
       phát hiện dấu hiệu

Điểm thú vị ở đây là ứng dụng không nhất thiết phải nhìn thấy trực tiếp một process có tên frida.

Nó có thể suy luận sự tồn tại của Frida thông qua hành vi hoặc dấu vết mà Frida để lại.

Đây là một tư duy rất quan trọng trong reverse engineering.


7. Kiểm tra /proc/<pid>/fd

Android sử dụng nền tảng Linux nên có hệ thống /proc.

Một process có thể được quan sát thông qua:

/proc/<pid>/

Trong đó:

/proc/<pid>/fd/

chứa thông tin về các file descriptor của process.

File descriptor có thể đại diện cho:

  • file;

  • socket;

  • pipe;

  • device;

  • các tài nguyên khác.

Vì vậy, ứng dụng có thể đọc thư mục này để tìm dấu hiệu bất thường.

Sau khi Frida được inject, một số dấu hiệu có thể xuất hiện trong khu vực này, chẳng hạn:

frida-helper
frida-agent
magisk

và có thể được dùng làm dữ liệu detection.

Mô hình:

/proc/<pid>/fd/
        │
        ▼
Enumerate FD
        │
        ▼
Đọc target / path
        │
        ▼
Tìm pattern đáng ngờ
        │
        ▼
Detection

8. Kiểm tra tên thread

Đây là một phương pháp khá trực quan.

Trong:

/proc/<pid>/task/

có thông tin về các thread của process.

Mỗi thread có thể có tên riêng.

Ví dụ bài viết đề cập đến một số tên như:

gmain
gdbus
gum-js-loop
pool-frida

Những tên này có thể trở thành dấu hiệu để ứng dụng nhận biết môi trường Frida.

Quá trình kiểm tra có thể hình dung:

Process
   │
   ▼
/proc/<pid>/task/
   │
   ├── Thread 1
   ├── Thread 2
   ├── Thread 3
   └── ...
          │
          ▼
      đọc tên thread
          │
          ▼
      so sánh pattern

Điểm đáng chú ý là detection kiểu này rất đơn giản về mặt kỹ thuật.

Ứng dụng chỉ cần enumerate thread rồi kiểm tra tên.

Tuy nhiên nó cũng có nhược điểm: tên thread không phải bằng chứng tuyệt đối.

Một chương trình khác hoàn toàn có thể sử dụng tên tương tự.

Vì vậy, đây thường chỉ là một trong nhiều lớp kiểm tra.


9. /proc/self/maps — một trong những điểm detection quan trọng

Đây là phần mình thấy đáng chú ý nhất khi nghiên cứu anti-Frida.

File:

/proc/self/maps

chứa thông tin về các vùng memory mapping của process hiện tại.

Ví dụ nó có thể cho biết:

Địa chỉ bắt đầu
Địa chỉ kết thúc
Quyền memory
Offset
Tên file/library

Có thể hình dung:

Process memory

┌───────────────────────────────┐
│ libart.so                     │
├───────────────────────────────┤
│ libc.so                       │
├───────────────────────────────┤
│ liblog.so                     │
├───────────────────────────────┤
│ application.so                │
├───────────────────────────────┤
│ anonymous mapping             │
└───────────────────────────────┘

Khi một thư viện liên quan đến Frida được load, nó có thể xuất hiện trong maps.

Bài viết đề cập các dấu hiệu như:

frida-agent-64.so
frida-agent-32.so

Do đó application có thể làm:

open("/proc/self/maps")
        │
        ▼
      read()
        │
        ▼
tìm "frida-agent"
        │
        ▼
    detected

10. Vì sao /proc/self/maps rất hữu ích khi reverse Android?

Không chỉ anti-Frida, maps còn cực kỳ hữu ích khi reverse native.

Khi xem maps, chúng ta có thể biết:

  • thư viện .so nào đã được load;

  • địa chỉ base của thư viện;

  • vùng nào có quyền execute;

  • vùng nào là read/write;

  • các memory mapping bất thường.

Ví dụ:

7a00000000-7a00200000 r-xp ... libnative.so

Từ đó có thể xác định địa chỉ base runtime của libnative.so.

Khi kết hợp với IDA/Ghidra:

Static address
      +
Runtime base
      ↓
Runtime address

Đây là một kỹ thuật rất quan trọng khi chuyển từ static analysis sang dynamic analysis.


11. Ý tưởng IO Redirection

Bài viết đưa ra một hướng xử lý đối với detection thông qua /proc, đó là IO redirection.

Ý tưởng cơ bản:

Application
     │
     │ open("/proc/self/maps")
     ▼
   Hook open()
     │
     ▼
Đọc dữ liệu thật
     │
     ▼
Thay đổi dữ liệu
     │
     ▼
Trả dữ liệu đã xử lý
     │
     ▼
Application

Tức là thay vì để ứng dụng trực tiếp nhận nội dung thật, chúng ta can thiệp vào đường đi của dữ liệu.

Ví dụ trong bài, tác giả hook open() của libc.so, phát hiện khi ứng dụng mở đường dẫn chứa /proc/maps, sau đó đọc nội dung, thay thế những chuỗi liên quan đến Frida rồi tạo một file maps đã được chỉnh sửa.

Đây là một ví dụ rất điển hình về intercept API + modify result.


12. Phân tích logic của mapsRedirect

Không cần đi sâu vào từng dòng code, có thể chia đoạn code trong bài thành các bước.

Bước 1: tìm open()

Đầu tiên lấy địa chỉ hàm:

libc.so
   │
   └── open()

Sau đó tạo một wrapper để có thể gọi hàm gốc.


Bước 2: tìm read()

Tiếp tục lấy địa chỉ:

libc.so
   │
   └── read()

Mục đích là đọc nội dung file descriptor.


Bước 3: tạo buffer

Một vùng nhớ tạm được cấp phát để chứa dữ liệu đọc từ maps.

maps
 ↓
read()
 ↓
buffer

Bước 4: hook open()

Sau khi hook, mọi lần ứng dụng gọi open() đều đi qua callback.

Logic có thể mô tả:

open(path)
   │
   ├── path bình thường
   │       ↓
   │   open gốc
   │
   └── path chứa /proc/ + maps
           ↓
       xử lý riêng

Bước 5: đọc nội dung thật

Nếu phát hiện ứng dụng đang mở maps, code đọc nội dung thật từ file descriptor.


Bước 6: lọc thông tin

Dữ liệu đọc được sẽ được kiểm tra và thay thế các chuỗi liên quan đến Frida.

Ví dụ về mặt ý tưởng:

frida-agent-64.so

được biến thành một tên khác không còn chứa dấu hiệu ban đầu.


Bước 7: tạo dữ liệu maps đã chỉnh sửa

Dữ liệu sau khi xử lý được ghi vào một file khác.

Cuối cùng application nhận file descriptor trỏ tới dữ liệu đã xử lý.

Có thể hình dung toàn bộ quá trình:

              /proc/self/maps
                      │
                      ▼
                   open()
                      │
                   Hook
                      │
                      ▼
                  read()
                      │
                      ▼
             Dữ liệu thật
                      │
                      ▼
             Filter / Modify
                      │
                      ▼
              Fake Maps File
                      │
                      ▼
                 Application

Điểm quan trọng ở đây là chúng ta không sửa trực tiếp logic detection của application.

Thay vào đó, chúng ta thay đổi dữ liệu mà detection nhận được.

Đây là một khái niệm rất quan trọng trong dynamic instrumentation.


13. Một hạn chế của phương pháp này

Hook open() không có nghĩa là mọi cách đọc maps đều bị kiểm soát.

Một ứng dụng có thể sử dụng API khác hoặc đi xuống tầng thấp hơn.

Ví dụ:

Java
 ↓
libc API
 ↓
syscall

Nếu detection không đi qua API mà chúng ta đang hook thì hook đó sẽ không bắt được.

Vì vậy khi reverse một cơ chế detection, không nên mặc định:

“Hook hàm X là xong.”

Mà phải xác định đường thực thi thực tế.

Đây chính là điểm khác nhau giữa việc sử dụng tool theo kiểu thử nghiệm và reverse engineering có phương pháp.


14. Phát hiện Inline Hook

Một hướng khác được bài viết đề cập là detection trực tiếp việc function bị hook.

Để hiểu phần này, trước tiên cần biết Inline Hook hoạt động như thế nào.

Giả sử một function ban đầu:

Function A

instruction 1
instruction 2
instruction 3
instruction 4
...

Khi bị inline hook, phần đầu function có thể được thay đổi để chuyển hướng sang một đoạn code khác:

Function A
    │
    └── Jump
          │
          ▼
       Hook Code
          │
          ▼
     Original Code

Do đó, byte đầu của function trước và sau hook có thể khác nhau.

Bài viết đưa ra ví dụ trên ARM64, trong đó một số byte đầu của function thay đổi sau khi hook.


15. Kiểm tra byte đầu của function

Nếu nhà phát triển biết trước byte code nguyên bản, họ có thể lưu lại một đoạn byte chuẩn.

Ví dụ:

Original:

AA BB CC DD EE FF ...

Sau khi bị hook:

Current:

11 22 33 44 55 66 ...

So sánh:

Original != Current

→ có khả năng function đã bị sửa.

Bài viết đề cập việc kiểm tra khoảng 16 byte đầu của function để phát hiện sự thay đổi.

Đây là phương pháp đơn giản nhưng có hiệu quả trong một số trường hợp.


16. CRC và kiểm tra tính toàn vẹn của code

Thay vì so sánh từng byte, application có thể sử dụng checksum hoặc CRC.

Ví dụ:

Function nguyên bản
       │
       ▼
      CRC
       │
       ▼
0x12345678

Sau khi code bị thay đổi:

Function hiện tại
       │
       ▼
      CRC
       │
       ▼
0x87654321

Sau đó so sánh:

CRC chuẩn
    vs
CRC hiện tại

Nếu khác nhau, application có thể kết luận rằng vùng code đã bị thay đổi.

Bài viết đề cập rằng khi Frida thực hiện hook vào các thư viện như libc.so, nội dung code có thể thay đổi, từ đó giá trị CRC cũng thay đổi.

Đây là một ví dụ của code integrity check.


17. Java Hook Detection

Không phải tất cả hook đều xảy ra ở native.

Android có nhiều tầng:

Java / Kotlin
      │
      ▼
     JNI
      │
      ▼
Native C/C++
      │
      ▼
    .so

Frida có thể hook Java method.

Theo bài viết, một phương pháp detection là kiểm tra trạng thái của những Java method quan trọng để xem chúng có xuất hiện dấu hiệu bất thường, chẳng hạn method bị chuyển sang trạng thái native.

Điều này cho thấy anti-Frida có thể được thực hiện ở nhiều tầng:

Java Layer
     │
     ▼
JNI Layer
     │
     ▼
Native Layer
     │
     ▼
Process / Memory
     │
     ▼
Kernel / proc

Do đó nếu chỉ kiểm tra một tầng thì chưa chắc đã đủ.


18. Tổng hợp các phương pháp phát hiện

Sau khi phân tích từng phương pháp, có thể tổng hợp như sau:

Phương phápThứ được kiểm tra
Port detectionPort/service của Frida
ptraceTrạng thái tracing/debug
D-BusDấu hiệu giao tiếp
/proc/<pid>/fdFile descriptor và target
Thread detectionTên thread
/proc/self/mapsMemory mapping và thư viện
Inline HookByte đầu của function
Java HookTrạng thái Java method
CRCTính toàn vẹn của code

Một hệ thống anti-Frida hoàn chỉnh có thể kết hợp nhiều phương pháp:

                  Application
                       │
        ┌──────────────┼──────────────┐
        │              │              │
      Network        Process        Memory
        │              │              │
       Port          ptrace          maps
       D-Bus         thread          hook
                      fd              CRC
        │              │              │
        └──────────────┼──────────────┘
                       ▼
                Detection Engine
                       │
                       ▼
                  Suspicious?

Vì vậy, nếu một phương pháp không phát hiện được Frida thì không có nghĩa toàn bộ hệ thống anti-Frida đã bị vô hiệu hóa.


19. Điều quan trọng nhất: tìm "điểm detection"

Khi reverse một ứng dụng có anti-Frida, mình không nên bắt đầu bằng việc đoán xem nó dùng kỹ thuật nào.

Cách tiếp cận tốt hơn là bắt đầu từ hiện tượng quan sát được.

Ví dụ:

Ứng dụng chạy bình thường
        │
        ▼
Attach Frida
        │
        ▼
Ứng dụng thoát

Lúc này cần đặt câu hỏi:

Ứng dụng thoát ở đâu?

Có thể lần theo:

exit()
abort()
kill()

Sau đó tìm caller:

exit()
  ↑
function A
  ↑
function B
  ↑
detection()

Từ đây mới xác định được:

detection()
     │
     ├── check port?
     ├── check maps?
     ├── check thread?
     ├── check ptrace?
     └── check memory?

Đây là tư duy reverse engineering quan trọng hơn việc thuộc lòng một đoạn script.


20. Static Analysis kết hợp Dynamic Analysis

Khi phân tích Android native, mình thường kết hợp hai hướng.

Static Analysis

Các công cụ thường dùng:

JADX
Apktool
IDA
Ghidra
strings
Smali

Mục tiêu:

Tìm class
Tìm method
Tìm JNI
Tìm string
Tìm native function
Tìm call graph

Ví dụ tìm thấy:

"frida"
"gum-js-loop"
"/proc/self/maps"

thì đây có thể là đầu mối để tiếp tục phân tích.


Dynamic Analysis

Sau đó dùng các công cụ instrumentation/debugging để quan sát runtime.

Mục tiêu:

Function có được gọi không?
Argument là gì?
Return value là gì?
Memory thay đổi thế nào?
Ứng dụng đọc file nào?
Ứng dụng gọi API nào?

Hai phương pháp này bổ trợ lẫn nhau:

Static Analysis
      │
      │ tìm function đáng ngờ
      ▼
Dynamic Analysis
      │
      │ xác nhận runtime
      ▼
Static Analysis
      │
      │ hiểu sâu logic
      ▼
Hoàn thiện mô hình

21. Liên hệ với reverse socket

Phương pháp nghiên cứu trong anti-Frida cũng có thể áp dụng cho việc phân tích giao thức socket.

Ví dụ khi muốn hiểu một packet được tạo như thế nào, thay vì chỉ nhìn PCAP:

PCAP
  │
  ▼
Hex packet

có thể lần ngược vào ứng dụng:

PCAP
  │
  ▼
Xác định thời điểm gửi
  │
  ▼
Tìm hàm gửi dữ liệu
  │
  ├── send()
  ├── sendto()
  ├── write()
  └── SSL_write()
  │
  ▼
Quan sát buffer
  │
  ▼
Tìm function serialize
  │
  ▼
Tìm encryption/compression

Khi đó ta có thể nối ba lớp:

                Network
                   │
                 PCAP
                   │
                   ▼
             Packet bytes
                   ▲
                   │
                   │
              Memory buffer
                   ▲
                   │
                   │
              Native function
                   ▲
                   │
                   │
                APK / .so

Đây là cách rất hiệu quả để hiểu một protocol tự định nghĩa.

Ví dụ:

Packet trên mạng
01 00 00 15 AA BB CC ...

        │
        ▼

Buffer trong memory
01 00 00 15 AA BB CC ...

        │
        ▼

Native function
serialize()
    ↓
encrypt()
    ↓
send()

Khi ba phần này khớp với nhau, chúng ta có thể bắt đầu xác định:

  • byte nào là command;

  • byte nào là length;

  • byte nào là sequence;

  • dữ liệu được serialize thế nào;

  • encryption nằm ở đâu;

  • packet được tạo ra tại function nào.


22. Từ anti-Frida đến reverse engineering nói chung

Điểm mình thấy đáng học nhất từ những kỹ thuật trên là:

Khi một ứng dụng thực hiện một hành vi nào đó, hãy tìm dấu vết mà hành vi đó để lại rồi lần ngược từ dấu vết về code.

Ví dụ:

Ứng dụng kiểm tra Frida

/proc/self/maps
        ↓
open()
        ↓
detection()

Ứng dụng kiểm tra thread

/proc/self/task/
        ↓
read thread name
        ↓
compare string
        ↓
detection()

Ứng dụng kiểm tra hook

function bytes
        ↓
compare / CRC
        ↓
detection()

Ứng dụng gửi packet

serialize()
        ↓
encrypt()
        ↓
send()

Tất cả đều có cùng một tư duy:

Hiện tượng
   ↓
Dấu vết
   ↓
API / syscall
   ↓
Function
   ↓
Caller
   ↓
Logic

23. Kết luận

Qua việc phân tích các cơ chế anti-Frida trên Android, có thể thấy rằng một ứng dụng không cần phải có một cơ chế “thần kỳ” để phát hiện instrumentation.

Nó có thể dựa vào rất nhiều dấu hiệu nhỏ:

Port
Thread
File descriptor
/proc
Memory map
Function bytes
CRC
Java method
ptrace

Mỗi dấu hiệu chỉ là một mảnh ghép.

Khi kết hợp nhiều mảnh ghép lại, ứng dụng có thể xây dựng một hệ thống phát hiện instrumentation tương đối phức tạp.

Đối với người làm reverse engineering, điều quan trọng nhất không phải là nhớ từng tên file hay từng port, mà là hiểu cách lần ngược từ dấu hiệu đến nguyên nhân.

Quy trình tổng quát có thể rút gọn thành:

Quan sát hành vi
       ↓
Xác định dấu hiệu bất thường
       ↓
Tìm API / syscall liên quan
       ↓
Theo dõi runtime
       ↓
Xác định function
       ↓
Phân tích call chain
       ↓
Hiểu logic detection

Khi đã quen với cách tư duy này, chúng ta không chỉ có thể phân tích anti-Frida mà còn có thể áp dụng vào rất nhiều bài toán khác như:

  • Android Reverse Engineering;

  • JNI và native .so;

  • phân tích mã hóa;

  • phân tích serialization;

  • reverse binary protocol;

  • phân tích socket;

  • packet processing;

  • anti-debug;

  • anti-hook;

  • anti-tamper;

  • kiểm tra tính toàn vẹn của code.

Bài viết liên quan (1)

Xem tất cả

Điều khoản sử dụng

Bạn cần đồng ý với điều khoản sử dụng của Army2.Net - Tải Game, Ứng Dụng & Tài Liệu Lập Trình Miễn Phí | Chia Sẻ Công Nghệ Mỗi Ngày trước khi tiếp tục xem nội dung.

Xem đầy đủ điều khoản