# AndroidMobilePentest101
## bài 1 - thiết lập môi trường
- tải virtualbox và genymotion

## bài 2 - ADB
- bật USB Debugging lên, chức này cho phép ta tương tác điện thoại ảo với máy thật

- Bây giờ bạn đã đủ điều kiện để cài 1 file apk bằng adb

- Cài file apk vào điện thoại ảo bằng câu lệnh:
```bash
adb install /path/to/apkfile
```
- vào shel
```bash
adb shell
```

- xem log
```bash
adb logcat
```

- để tải lên 1 file từ máy thật đến điện thoại ảo:
```bash
adb push /path/to/file/PC /path/to/file/device
```
- để tải 1 file từ điện thoại ảo đến máy thật :
```bash
addb pull /path/to/file/device /path/to/file/PC
```
## bài 3 - Phân tích tĩnh
### kiểm tra bằng tool
- MobSF là một bộ công cụ kiểm tra ứng dụng di động (Android / iOS / Windows) tự động, tất cả-trongmột, có khả năng thực hiện phân tích tĩnh, phân tích động, phân tích phần mềm độc hại và kiểm tra API
web.

- MobSF cung cấp nhiều thông tin cần thiết để chúng ta đánh giá độ bảo mật của chương trình

### kiểm tra bằng tay
- Để làm việc này, chúng ta sử dụng ByteCode Viewer, 1 tool dùng xem code nhanh trong file apk
- * Easily edit APKs via Smali/Baksmali integration
- * Scan for malicious code with the Malicious Code Scanner plugin.
- * Export as DEX, Jar, Class, Zip or Java Source File.
Ném file apk vào, Bytecode Viewer sẽ phân tích file apk và hiển thị code bên trong cho chúng ta

- Sử dụng Malicious Code Scanner plugin để scan những đoạn code có vẻ nguy hiểm

- https://the.bytecode.club/pages.php?page=bytecode-viewer
- demo Malicious Code Scanner
https://www.youtube.com/watch?v=I5GT6PoTGOw&t=1s




- Ví dụ: Tìm ra được đoạn code lạ trong com/android/insecurebankv2/DoLogin$RequestTask.class
- Nếu đăng nhập với nick "devadmin" thì tự động login được, không cần quan tâm password, chương trình gì
kì ha



- Trong quá trình phân tích tĩnh, chúng ta phải kiểm tra các cơ chế anti-root, anti-vm, cert-pinning có được
cài đặt hay không, và có lỏng lẻo hay không (sẽ nói ở bài khác)
- Kiểm tra xem key, mật khẩu, vv… có nằm trong code hay thư mục nào không.
- Kiểm tra xem các thông tin nhạy cảm (credit card, pass...) có được lưu trong database không

- Xem thử trong database có chứa thông tin đăng nhập nhạy cảm không

==> thấy không có thông tin nhạy cảm được lưu
### các bước kiểm tra
- Thông tin đăng nhập không được mã hoá trong cơ sở dữ liệu 
- Thông tin nhạy cảm lưu dưới dạng plain-text 
- Lưu trữ Cookie không an toàn 
- File Backup không được mã hoá 

 
- Thông tin nhạy cảm lộ trong log 
- Phương thức mã hoá yếu 

- Activity Hijacking 


```bash
am start -n com.android.insecurebankv2/.PostLm start -n com.android.insecurebankv2/.PostLogin
```
- xem thêm checklist tại đây : https://www.mediafire.com/file/fsx9gdpddgcpz2g/Android+Applicatio
## bài 4 - dịch ngược
### Inside the apk
- META-INF/: Thư mục này có ở trong file APK đã sign, nó bao gồm các danh sách file trong APK và chữ kí
của chúng
- lib/: Các file của thư viện native (file có đuôi *.so) được lưu vào thư mục con của lib/ như x86, x86_64
- res/: Folder này gồm tất cả các resource XML, drawables(PNG,JPEG) với các loại khác nhau từ mdpi, hdpi,
sw600dp... cho tới resource ngôn ngữ
- AndroidManifest.xml: Mô tả tên, phiên bản, và nội dung của file APK
- classes.dex: Bao gồm mã nguồn đã biên dịch, được chuyển đưới dạng Dex bytecode
- resources.arsc: Một số tài nguyên và định nghĩa được biên dịch và lưu trữ ở đây. Các resource này lưu vào
APK mà không cần nén để truy cập nhanh hơn lúc runtime.

- có thể đọc được smali code


### Patching android app
- Patch đơn giản là tác động và làm thay đổi code của chương trình, khiến nó hoạt động theo ý mình.

```bash
apktool d InsecureBankv2.apk
```






```bash
apktool b InsecureBankv2
```

- File apk vừa recompile sẽ nằm ở thư mục “dist”


- Cài nó thôi nhỉ?

- Oops, Failed! Bởi vì Every new compiled Android .apk needs to be signed if it is going to be installed on a
phone (nôm na là file compiled Android .apk mới phải được sign trước khi cài đặt)
tiến hành tạo chứng chỉ
- Đầu tiên tạo 1 cái key:
```bash
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
```
keystore password: 123456

- Sau đó xài jarsigner với key vừa tạo để sign:
```bash
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore InsecureBankv2.apk alias_name
```
- https://www.youtube.com/watch?v=FaGCRQLxuoA

- khi tải xong jarsigner có thể chạy được sign in


- Chúng ta đổi tên file để tránh nhầm lẫn:


- Oh, vẫn có vấn đề! Lỗi này là do chương trình cũ đã được cài đặt rồi, do đó ta gỡ nó ra và cài cái mới vào

- tải app-release_patched.apk thành công


```bash
$ apktool d <source.apk> -o <destination_directory>/
```
1. Recompile and recompress the application using Apktool.
```bash
$ apktool b <source_directory>/ -o <patched.apk>
```
2. Create a signing key using Keytool.
```bash
$ keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
```
3. Sign the resulting APK with Java’s JarSigner.
```bash
$ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore <patched.apk> alias_name
```
4. Install the application on our device once more using Android’s ADB.
```bash
$ adb install <patched.apk>
```
### Detection

#### Detection -> Anti-emu







#### Detection -> Anti-root

- Chúng ta sẽ nói về vấn đề tại sao anti-root code không phát hiện được. Đoạn code check root như sau:
- Nó kiểm tra /system/app/Superuser.apk có tồn tại không?
- Nếu có => phát hiện, không thì thôi.


## bài 5 - phân tích động
- dùng burp suit và cấu hình bắt request qua burp

- Sử dụng tab Scanner (BurpSuite pro mới có nha) để tiến hành scan tìm lỗi trong request được
chỉ định

- thấy trong server có gửi các request liên tục

- kết quả thấy phát hiện lỗi XSS






## bài 6 - SSL Pinning
- SSL Pinning là quá trình liên kết host với chứng chỉ X.509 certificate hoặc public key. Khi chứng chỉ hoặc key
đã được chỉ định cho host, nó được gọi là ‘pinned’ với host.
- Phần mềm giao tiếp với server thông qua giao thức https và có pinning sẽ khiến kiểu tấn công Man-In-TheMiddle attack thất bại, và cũng không lấy được dữ liệu dưới dạng clear text khi sử dụng các công cụ proxy
(như burpsuite)
Có 3 lựa chọn dùng để pin:
- Certificate Pinning (Chủ yếu nói về cái này) 
- Public Key 
- Hashing 
### Detect Pinning
Để kiểm tra xem app có ssl pinning hay không thường sử dụng các cách sau:
1. Chỉ intercept được request đầu tiên (hoặc không được request nào)
2. Tìm string “Trusted”
Hoặc sử dụng MobSF:
(menu trái) Security Analysis tab -> File Analysis.
Nếu thấy "Certificate/Key Files Hard-coded inside the App” hoặc chỗ nào có chuỗi “Pinning” => Pinning

### Bypass The Pinning
#### Method 1: Adding a Custom CA to the User Certificate Store
- Mặc định thì các kết nối bảo mật (sử dụng protocols như TLS and HTTPS) từ các app
sẽ tin tưởng vào các pre-installed system CAs, và các app trên Android 6.0 (API level 23) trở xuống cũng tin tưởng vào user-added CA

- Nếu chúng ta có 1 cái certificated trusted hợp lệ trong user CA ở máy android 6.0 api
level 23- thì sẽ bypass được

- Đôi khi người dev bắt ta sử dụng android 7 để tránh trường hợp trên, thường định nghĩa trong file
AndroidManifest.xml

- Ta decompile nó sử dụng apktool, đổi thành:

- Rồi recompile nó lại, nếu app chỉ check dựa trên valid certificate, kĩ thuật này sẽ giúp chúng ta bypass ssl pinning
==> thay đổi viết lại chương trình
#### Method 2: Overwrite Packaged CA Certificate with Custom CA Certificate
- Đôi khi decompile file apk ra sẽ thấy 1 cái custom cert trong đó, có thể app sẽ dùng
nó để check

- Ghi đè ‘CustomCA.cer’ certificate với cert của ta, từ đó làm cho app nghĩ rằng cert
của ta hợp lệ
==> thay đổi viết lại cert của chương trình
#### Method 3: Patch the app
- Decompile file apk, đọc code, tìm đoạn check ssl pinning, patch nó

Một số case-study thực tế:
1. Bypassing OkHTTP3 Certificate Pinning
https://blog.securityevaluators.com/bypassing-okhttp3-certificate-pinning-c68a872ca9c8
2. Bypassing certificate pinning/hardcoded ssl certificate/certificate pinning
https://www.youtube.com/watch?v=uEndLXB4tfA
3. Facebook Bypassing Certificate Pinning
https://blog.dewhurstsecurity.com/2015
==> thay đổi viết lại chương trình
#### Method 4: Hook
- dùng Frida ==> không tthayy đổi chương trình mà thay đổi hành vi tiến trình lúc chạy chương trình
## bài 7 - Hooking Với Frida
Installation -> Client (máy thật)
Cài đặt Frida CLI Tools:
pip3 install frida-tools
- Cài đặt Frida Python bindings (Sử dụng chính trong bài viết)
pip3 install frida
- Kiểm tra lại xem frida đã cài thành công chưa:

Installation -> Server (điện thoại ảo)
- frida-server version phải đúng với Frida version.

### Hook mã nguồn Java
Việc hook vào phần mã nguồn Java đơn giản hơn nhiều so với hook vào mã nguồn Native. Với mã nguồn Native chúng ta sẽ gặp những vấn đề cần giải quyết bằng kỹ thuật dịch ngược, kiểu dữ liệu hạn chế,... thì với phần mã nguồn Java, những thứ này đều dễ hơn nhiều. Nếu phần mã nguồn Native có nhiều API khác nhau để hỗ trợ chúng ta làm 1 việc là tìm địa chỉ hàm cần hook, chúng ta có thể tùy từng trường hợp để lựa chọn các API cần thiết, thì khi hook vào phần mã nguồn Java chúng ta chỉ cần quan tâm đến 2 API chính, đó là:
- Java.choose()
- Java.use()
Hai API này sẽ hỗ trợ chúng ta hook thẳng vào bất cứ hàm nào chúng ta muốn, và chúng ta chỉ cần biết tên hàm đó là được.
##### API Java.choose()
API Java.choose() hoạt động theo nguyên lý tìm kiếm các Object được tạo sẵn trên vùng nhớ Heap.

Khi các Object được tạo ra từ Class, chúng sẽ được đặt trong vùng nhớ heap cho tới khi được huỷ để giải phóng bộ nhớ. API Java.choose() sẽ tìm kiếm trên heap xem có Object nào được tạo ra từ Class chúng ta cần hook vào chưa. Nếu tìm thấy thì nó sẽ hook vào cho chúng ta.
Với nguyên lý hoạt động như này thì Java.choose() thường được sử dụng để sử dụng lại các hàm. Lúc này chúng ta có thể gọi lại hàm nhiều lần, thử truyền vào các đối số khác nhau,... qua đó hiểu hơn về cách hàm này hoạt động. Chúng ta cũng có thể gọi lại hàm để lấy được ra những giá trị chúng ta muốn. VD như gọi lại hàm giải mã và truyền vào đúng dữ liệu mã hoá, từ đó lấy được bản gốc.
API này có 2 event là:
- onMatch: được thực hiện mỗi khi tìm thấy một instance (mình hiểu đơn giản là một đối tượng sinh ra từ Class, mỗi Object đều độc lập nên chúng là các instance).
- onComplete: được thực hiện khi hoàn thành tìm ra toàn bộ các instance.
Vì thế nếu muốn hook vào các hàm thì chúng ta nên viết trong onMatch.
##### API Java.use()
Khác với Java.choose() chỉ lấy bánh, API Java.use() xử lý triệt để bằng cách kiểm soát cái khuôn. Lúc này muốn tạo ra bánh mới, huỷ bánh vừa tạo đi, thay đổi một chút trong khuôn bánh thì đều được. Hiểu đơn giản thì Java.use() cho phép chúng ta thay đổi logic của hàm ngay từ lúc nó được tạo ra bằng cú pháp new. Vì thế thường thì chúng ta sẽ sử dụng API này nhiều hơn.

API này không có event nào cả, đơn giản là chúng ta muốn viết lại nội dung hàm như nào thôi. Chúng ta sẽ sử dụng như sau:
```javascript
// frida -U -l hook.js -f <tên-package>
Java.perform(function () {
// Hook 1 hàm của class
Java.use("tên-class").<tên-hàm>.implementation = function() {
// Nội dung thực hiện khi hook thành công
};
// Hook nhiều hàm cùng class
var hookClass = Java.use("tên-class");
hookClass.<tên-hàm-1>.implementation = function() {
// Nội dung thực hiện khi hook thành công
};
hookClass.<tên-hàm-2>.implementation = function() {
// Nội dung thực hiện khi hook thành công
};
// Hook hàm có tham số
Java.use("tên-class").<tên-hàm>.implementation = function(var_1, var_2,...) {
// Nội dung thực hiện khi hook thành công
};
});
```
Trong trường hợp hàm chúng ta muốn hook có những hàm overloading thì chúng ta cần chỉ rõ hàm muốn hook bằng cách khai báo rõ số lượng và kiểu tham số.
```javascript
Java.perform(function () {
// Hook 1 hàm của class
Java.use("tên-class").<tên-hàm>.override("kiểu-biến-1", "kiểu-biến-2",...).implementation = function(var_1, var_2,...) {
// Nội dung thực hiện khi hook thành công
};
});
```
### Python bindings
- Spawn app: Khi bạn sử dụng lệnh "spawn" trong Frida, bạn yêu cầu Frida khởi động ứng dụng mục tiêu trong trạng thái tạm dừng (not yet started) để bạn có thể bắt đầu chèn mã vào ngay từ thời điểm đầu tiên ứng dụng được khởi chạy. Điều này hữu ích trong việc phân tích các hành vi xảy ra ngay khi ứng dụng bắt đầu hoạt động, ví dụ như khi ứng dụng tải mã hoặc thiết lập các biến môi trường quan trọng.
```bash
frida -U -f [app_id] -l [script.js] --no-pause
```

1. Kết nối đến thiết bị USB:
```bash!
device = frida.get_usb_device()
```
Dòng lệnh này kết nối với thiết bị Android đang kết nối qua USB. get_usb_device() là hàm của Frida để lấy thông tin về thiết bị USB hiện tại.
2. Spawn ứng dụng:
```bash!
pid = device.spawn("com.android.insecurebankv2")
```
Bạn sử dụng spawn() để khởi động ứng dụng mục tiêu trong trạng thái tạm dừng. Ở đây, "com.android.insecurebankv2" là tên của gói ứng dụng (package name) mà bạn muốn phân tích.
3. Resume ứng dụng:
```bash
device.resume(pid)
```
Sau khi spawn ứng dụng, nó sẽ bị tạm dừng. Lệnh resume() sẽ tiếp tục cho phép ứng dụng chạy bình thường.
4. Attach vào ứng dụng:
```bash
session = device.attach(pid)
```
Lệnh attach() này gắn Frida vào quá trình (process) của ứng dụng vừa spawn, để có thể thực hiện các thao tác tiếp theo, như chèn mã JavaScript vào.
5. Inject script vào ứng dụng:
```bash
script = session.create_script(hook_script)
script.load()
```
- create_script(hook_script) tạo một script dựa trên đoạn mã JavaScript mà bạn đã viết, dùng để hook vào các chức năng của ứng dụng.
- script.load() sẽ tải đoạn script đó vào ứng dụng, cho phép bạn bắt đầu phân tích hoặc thao tác các phần của ứng dụng theo cách bạn muốn.
```python
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode = """
Java.perform(() => {
// Function to hook is defined here
const MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');
// Whenever button is clicked
const onClick = MainActivity.onClick;
onClick.implementation = function (v) {
// Show a message to know that the function got called
send('onClick');
// Call the original onClick handler
onClick.call(this, v);
// Set our values after running the original onClick handler
this.m.value = 0;
this.n.value = 1;
this.cnt.value = 999;
// Log to the console that it's done, and we should have the flag!
console.log('Done:' + JSON.stringify(this.cnt));
};
});
"""
process = frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors')
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()
```
- frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors'): Kết nối đến thiết bị Android qua USB và attach vào ứng dụng mục tiêu.
- process.create_script(jscode): Tạo một script Frida từ đoạn mã JavaScript đã định nghĩa.
- script.on('message', on_message): Gắn hàm xử lý thông điệp với script.
- script.load(): Tải script vào tiến trình của ứng dụng.
- sys.stdin.read(): Giữ chương trình Python hoạt động để tiếp tục nhận các thông điệp từ script.


#### hook vào Java code
##### Java.choose()

```java
package com.android.insecurebankv2;
import android.util.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CryptoClass {
String base64Text;
byte[] cipherData;
String cipherText;
byte[] ivBytes = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
String key = "This is the super secret key 123";
String plainText;
public static byte[] aes256decrypt(byte[] var0, byte[] var1, byte[] var2) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
IvParameterSpec var4 = new IvParameterSpec(var0);
SecretKeySpec var3 = new SecretKeySpec(var1, "AES");
Cipher var5 = Cipher.getInstance("AES/CBC/PKCS5Padding");
var5.init(2, var3, var4);
return var5.doFinal(var2);
}
public static byte[] aes256encrypt(byte[] var0, byte[] var1, byte[] var2) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
IvParameterSpec var4 = new IvParameterSpec(var0);
SecretKeySpec var3 = new SecretKeySpec(var1, "AES");
Cipher var5 = Cipher.getInstance("AES/CBC/PKCS5Padding");
var5.init(1, var3, var4);
return var5.doFinal(var2);
}
public String aesDeccryptedString(String var1) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] var2 = this.key.getBytes("UTF-8");
this.cipherData = aes256decrypt(this.ivBytes, var2, Base64.decode(var1.getBytes("UTF-8"), 0));
this.plainText = new String(this.cipherData, "UTF-8");
return this.plainText;
}
public String aesEncryptedString(String var1) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] var2 = this.key.getBytes("UTF-8");
this.plainText = var1;
this.cipherData = aes256encrypt(this.ivBytes, var2, this.plainText.getBytes("UTF-8"));
this.cipherText = Base64.encodeToString(this.cipherData, 0);
return this.cipherText;
}
}
```
- Vậy gọi function lên bằng Frida như nào? Chúng ta sẽ sử dụng ```Java.choose()```

Java.choose: liệt kê
Object (Đối tượng):
- Định nghĩa: Một object là một thực thể cụ thể trong bộ nhớ, được tạo ra từ một lớp (class). Nó bao gồm cả dữ liệu (thuộc tính) và hành vi (phương thức) mà lớp định nghĩa.
- Ngữ cảnh sử dụng: Từ "object" được sử dụng phổ biến nhất để chỉ một thực thể đang tồn tại trong bộ nhớ, có thể được tương tác bằng cách gọi các phương thức hoặc truy cập các thuộc tính của nó.
- Ví dụ: Khi nói "car1 là một object của lớp Car", chúng ta đang nói về một thực thể cụ thể của lớp Car.
Instance (Thực thể):
- Định nghĩa: Instance cũng là một đối tượng, nhưng từ "instance" thường được dùng để nhấn mạnh rằng đối tượng này là một "thực thể" của một lớp cụ thể.
- Ngữ cảnh sử dụng: "Instance" được sử dụng để nhấn mạnh mối quan hệ giữa đối tượng và lớp của nó. Khi bạn nói một đối tượng là một "instance" của một lớp nào đó, bạn đang nhấn mạnh rằng đối tượng này đã được tạo ra từ lớp đó.
- Ví dụ: Khi nói "car1 là một instance của lớp Car", chúng ta nhấn mạnh rằng car1 được tạo ra từ lớp Car.
Sự khác biệt chính:
- Ngữ cảnh: "Object" là thuật ngữ chung, có thể dùng cho mọi thực thể trong lập trình hướng đối tượng. "Instance" nhấn mạnh vào việc đối tượng là một thực thể của một lớp cụ thể.
- Sử dụng: Mọi instance đều là một object, nhưng không phải mọi object đều được gọi là instance. "Instance" thường được sử dụng khi nói về việc khởi tạo một đối tượng từ một lớp.

- trong ```mySharedPreferences``` chứa ```superSecurePassword``` và ```EncryptedUsername```




Found instance: com.android.insecurebankv2.CryptoClass@45c9ffd

- Như đã biết, Dinesh@123$ là password của user dinesh

```python
import frida
import sys
import time
device = frida.get_usb_device()
pid = device.spawn("com.android.insecurebankv2")
device.resume(pid)
time.sleep(0.5) # Without it Java.perform silently fails
session = device.attach(pid)
# with open("frida_script.js") as f:
# script = session.create_script(f.read())
# script.load()
hook_script = """
Java.perform(
function ()
{
console.log('Inside the hook_script');
class_CryptoClass = Java.choose('com.android.insecurebankv2.CryptoClass',
{
onMatch: function(instance) {
console.log('Found instance: ' + instance);
console.log('Result of decrypt: ' + instance.aesDeccryptedString('DTrW2VXjSoFdg0e61fHxJg=='));
},
onComplete: function() {console.log('end');}
}
);
}
);
"""
script=session.create_script(hook_script)
script.load()
input('[!] Press <Enter> at any time to detach from instrumented program.\n\n')
```
- nhưng khi chạy file riêng trong frida do có độ trễ khi khởi động không nhanh được như code nên instance đã bị giải phóng khỏi heap -> không bắt được

##### Java.use()




```python
import frida
import sys
import time
device = frida.get_usb_device()
pid = device.spawn("com.android.insecurebankv2")
device.resume(pid)
time.sleep(3) # Without it Java.perform silently fails
session = device.attach(pid)
# with open("frida_script.js") as f:
# script = session.create_script(f.read())
# script.load()
hook_script = """
Java.perform(
function ()
{
console.log('Inside the hook_script');
class_PostLogin = Java.use('com.android.insecurebankv2.PostLogin');
class_PostLogin.doesSuperuserApkExist.implementation = function(var1) {
return true;
};
}
);
"""
script=session.create_script(hook_script)
script.load()
input('[!] Press <Enter> at any time to detach from instrumented program.\n\n')
```


#### hook vào code Native
- đa số các app đều có client-side filter, giờ sử dụng frida để bypass thử xem
- Nhìn đoạn code này trong com/android/insecurebankv2/ChangePassword$RequestChangePasswordTask.class:

- Để ý đoạn regex:
((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})
Đoạn này kiểm tra độ phức tạp của password, nghĩa là nếu chúng ta đổi password dễ quá thì sẽ không được
- Mình là người đơn giản nên mình đổi thử password thành “1234”:

- Fail, vì pw phải từ 6->20 kí tự
“1234” chỉ có 4 thôi
- Chúng ta sẽ sử dụng frida để bypass. Lần này không inject vào app class nữa, vì regex method là từ java package,
không phải từ code của dev.

- Hook:
regex_Pattern_hook = Java.use('java.util.regex.Pattern')
- Khác với lần trước, ta không thể xài regex_Pattern_hook.compile.implementation bởi vì trong Pattern package có
nhiều loại compile methods ( compile(String x); compile(String x,int y); etc…), do đó frida sẽ bị rối!
- Chúng ta phải nói với frida chính xác method nào để hook, ở đây là: compile(String x)
- Sử dụng overload:
regex_Pattern_hook.compile.overload("java.lang.String").implementation
```python
import frida
import sys
import time
device = frida.get_usb_device()
pid = device.spawn("com.android.insecurebankv2")
device.resume(pid)
# time.sleep(1) # Without it Java.perform silently fails
session = device.attach(pid)
hook_script = """
Java.perform(
function ()
{
console.log('Inside the hook_script');
regex_Pattern_hook = Java.use('java.util.regex.Pattern');
regex_Pattern_hook.compile.overload('java.lang.String').implementation = function(x) {
console.log('Inside the compile function');
console.log('Pattern: ' + x);
return this.compile(".*");
};
}
);
"""
script=session.create_script(hook_script)
script.load()
input('[!] Press <Enter> at any time to detach from instrumented program.\n\n')
```

## bài 7.5 - frida lab
yeswehack
- Dịch ngược phần mềm, sử dụng frida để crack pin, lấy flag
### bước 1: dùng thử

### bước 2: dịch ngược đọc code và đọc log
- Không thấy thêm gì, nên chuyển qua dịch ngược file apk để phân tích

- bật logcat lên và sử dụng app để có cái nhìn tổng quan



- Như đã thấy trong log, ta có thể đoán rằng nếu pin length < 6, chương trình in ra số pin hiện tại
- Nếu pin length = 6, nó sẽ tạo ra 1 chuỗi kí tự (nhìn giống cái key) và búng ra lỗi
- Sau đó in ra stack trace:
- Có thể “123456” không phải là mã pin đúng => “Ciphertext failed verification” => Error!
- Bây giờ chúng ta sẽ xem qua code để biết chính xác chuyện gì xảy ra
- Class MainActivity.class:


- Chúng ta có thể thấy 1 thứ thú vị nè, cipherText được gán bằng giá trị của Hex().decode của một đoạn hex
string
- Sau đó chương trình sử dụng PinLockListener để thực hiện các thao tác check pin UI
- Trong MainActivity$1.class, ta có thể thấy:

- onPinChange, onComplete biểu hiện giống những gì chúng ta đoán dựa vào logcat, bây giờ chúng ta tập
trung vào onComplete để biết chương trình làm gì khi input 6-length pin


- chạy fail
## bài 8 - các công cụ hỗ trợ
- Root Detection Bypass

- Emulator Detection Bypass

- SSL Pinning Bypass -> JustTrustMe


```bash
objection patchapk --source InsecureBankv2.apk
```



```bash
objection --gadget "com.android.insecurebankv2" explore
```

- Với Objection chúng ta có thể thu thập thông tin về app, ví dụ lệnh env sẽ trả về vị trí của các thư mục Files,
Caches và nhiều thư mục khác:

-Hoặc liệt kê các Activities mà app có:


- Sử dụng activities liệt kê được, invoking arbitrary activities:
- android intent launch_activity com.android.insecurebankv2.PostLogin ==> cho ta vào luôn trang chủ

```bash
android sslpinning disable
```
- để bypass SSL Pinning sử dụng Objection, gõ lệnh (mặc dù app của chúng ta
không có ssl pinning, ví dụ thôi J):

- đọc thêm tại https://book.hacktricks.xyz/mobile-pentesting/android-app-pentesting/frida-tutorial/objection-tutorial
## bài 9 - ví dụ thực tế
## bài 10 - code app android