รวมคำสั่งติดตั้ง Frida และ Frida-Server รวดเดียว บนเครื่องจริง

บทความเป็นการอธิบายขั้นตอนในกระบวนการติดตั้งและใช้งานโปรแกรม Frida บนอุปกรณ์ Android ที่มีขั้นตอนเช่นการตรวจสอบสถาปัตยกรรม CPU, จับคู่สถาปัตยกรรม CPU กับการดาวน์โหลด, ดาวน์โหลดและแตกไฟล์ .xz, คัดลอกไฟล์เข้าสู่อุปกรณ์ Android, และเริ่มต้นเซิร์ฟเวอร์ Frida บนอุปกรณ์ Android ผ่าน Script python ที่ชื่อว่า LazyFrida เพื่อช่วยในการทำเจาะระบบ Application บน Android (Android Mobile Application Penetration Test) เร็วขึ้นและสะดวกมากยิ่งขึ้น

Warunyou Sunpachit และ Boonperm Mark
Cybersecurity consultant

คำสั่งรวดเดียวในการติดตั้ง

คำสั่งนี้ใช้สำหรับการเตรียมการ Download Frida และ Frida Server จาก https://github.com/frida/frida/releases เรียบร้อยแล้ว

adb push frida-server /data/local/tmp && adb shell "su -c 'chmod 755 /data/local/tmp/frida-server && ./data/local/tmp/frida-server &'"

คำสั่งดังกล่าวเป็นคำสั่งที่ใช้ในการส่งและเริ่มต้นการทำงานของเซิร์ฟเวอร์ของเครื่องมือ Frida ในอุปกรณ์ Android ผ่าน adb (Android Debug Bridge) และใช้สิทธิ์ root เพื่อเปิดใช้งานเซิร์ฟเวอร์นั้นในพื้นที่ /data/local/tmp

อธิบายได้ดังนี้:

  1. adb push frida-server /data/local/tmp – คำสั่งนี้จะส่งไฟล์ frida-server ไปยังพาธ /data/local/tmp ในอุปกรณ์ Android โดยใช้ adb
  2. adb shell "su -c 'chmod 755 /data/local/tmp/frida-server && ./data/local/tmp/frida-server &'" – คำสั่งนี้จะทำการเรียกใช้ adb shell เพื่อใช้สิทธิ์ root (su -c) และดำเนินการทำงานในอุปกรณ์ Android คำสั่งที่ดำเนินการภายในคำสั่ง su -c คือ chmod 755 /data/local/tmp/frida-server ที่ใช้เปลี่ยนสิทธิ์การเข้าถึงของไฟล์ frida-server เป็น 755 (อ่าน, เขียน, และเรียกใช้ได้ สำหรับเจ้าของไฟล์) และ ./data/local/tmp/frida-server & ที่ใช้เริ่มต้นการทำงานของ frida-server ในพื้นที่ /data/local/tmp โดยใช้ & เพื่อให้โปรแกรมทำงานในพื้นหลัง (Background process)

สำหรับท่านที่มีปัญหาการติดตั้ง หรือความสะดวกในการติดตั้ง Frida และ Frida-server สำหรับ Android สามารถใช้งาน Script ดังนี้

LazyFrida

อุปกรณ์จัดเตรียม

  • เครื่อง Android Device ที่ Root เรียบร้อยแล้ว
  • เปิด USB debugging แล้ว (แต่ละเครื่องอาจการเข้าเมนู Developer options ไม่เหมือนกัน)
  • สาย USB
  • ลง Python3
  • ลง PIP

ตัวอย่างการใช้งาน

สำหรับคำสั่งรวดเดียวตั้งแต่ดาวน์โหลดติดตั้งเชื่อมต่อสามารถใช้งาน LazyFrida ดังนี้

ตัวอย่างการใช้งาน Command เพื่อติดตั้ง Frida

python3 lazyfrida.py install-frida

ตัวอย่างทดสอบการเชื่อมต่อ

 python lazyfrida.py -q runn

ดูตัวอย่างการใช้งานอื่น ๆ

positional arguments:
  {install-frida,install-cert,patch-apk}
                        installation commands
    install-frida       installs frida and frida-server on Android
    install-cert        installs CA Burp suite certificate
                        defines [ip] of Burp Suite: default: 127.0.0.1
    patch-apk           installs frida gadget to apk

options:
  -h, --help            show this help message and exit
  -q [QUERY ...], --query [QUERY ...]
                        connects to frida server and accepts multiple parameters.
                        potential parameters: apps, proc, runn
  -u USB_PROXY [USB_PROXY ...], --usb-proxy USB_PROXY [USB_PROXY ...]
                        start and stop the usb proxy
                        potential parameters: start, stop
  -f FRIDA [FRIDA ...], --frida FRIDA [FRIDA ...]
                        start, stop, check version of frida server
                        potential parameters: start, stop, version
ตัวอย่างการใช้งานฟังก์ชัน connect เพื่อตรวจสอบการเชื่อมต่อสมบูรณ์

อธิบายการทำงานที่สำคัญ

ติดตั้ง Frida-Tools ลงเครื่อง Computer

ฟังก์ชัน install_or_upgrade_frida_tools() ใช้ในการติดตั้งหรืออัปเกรดเครื่องมือ Frida-tools ผ่านการใช้งานคำสั่ง pip ใน Python.

def install_or_upgrade_frida_tools():
	print_green("\nStart installing or upgrading frida-tools...")
	try:
		subprocess.check_call(['pip', 'install', '--index-url=https://pypi.python.org/simple/', '--upgrade', 'frida-tools'])
		print_green("Frida-tools installed or upgraded successfully.")
		return True
	except subprocess.CalledProcessError as e:
		print_red("Failed to install or upgrade Frida-tools. Error:", e)
		return False

ฟังก์ชันนี้จะดำเนินการดังนี้:

  1. ใช้ subprocess.check_call() เพื่อเรียกใช้คำสั่ง pip install --index-url=https://pypi.python.org/simple/ --upgrade frida-tools เพื่อติดตั้งหรืออัปเกรด Frida-tools
  2. ถ้าการดำเนินการเสร็จสมบูรณ์และไม่เกิดข้อผิดพลาด (ไม่เกิด subprocess.CalledProcessError) ฟังก์ชันจะพิมพ์ข้อความสีเขียวเพื่อแสดงว่า Frida-tools ได้ถูกติดตั้งหรืออัปเกรดสำเร็จแล้ว และจะคืนค่า True
  3. ถ้าการดำเนินการล้มเหลวหรือเกิดข้อผิดพลาด (เกิด subprocess.CalledProcessError) ฟังก์ชันจะพิมพ์ข้อความสีแดงเพื่อแสดงว่าไม่สามารถติดตั้งหรืออัปเกรด Frida-tools ได้ พร้อมกับแสดงข้อความข้อผิดพลาด และจะคืนค่า False

ฟังก์ชันนี้จำเป็นต้องมี import subprocess และฟังก์ชัน print_green() และ print_red() เพื่อแสดงข้อความสีเขียวและสีแดงตามลำดับในส่วนของโค้ด

ตรวจสอบ CPU ของเครื่อง Android

ฟังก์ชัน check_android_cpu() ใช้ในการตรวจสอบสถาปัตยกรรม CPU ของอุปกรณ์ Android ผ่าน adb (Android Debug Bridge).

def check_android_cpu():
	print_green("\nStart checking Android CPU...")
	try:
		result = subprocess.run(['adb', 'shell', 'getprop', 'ro.product.cpu.abi'], capture_output=True, text=True)
		output = result.stdout.strip()
        
		if output:
			print("CPU Architecture:", output)
			return output
		else:
			print_red("Unable to retrieve CPU architecture.")
			return ""

	except FileNotFoundError:
		print_red("ADB is not installed or not found.")
		return ""

ฟังก์ชันนี้จะดำเนินการดังนี้:

  1. ใช้ subprocess.run() เพื่อเรียกใช้คำสั่ง adb shell getprop ro.product.cpu.abi เพื่อรับค่าสถาปัตยกรรม CPU ของอุปกรณ์ Android
  2. ตรวจสอบผลลัพธ์ที่ได้จากคำสั่ง ถ้ามีผลลัพธ์ (ไม่เป็นค่าว่าง) ฟังก์ชันจะพิมพ์ข้อความว่า “CPU Architecture:” ตามด้วยค่าสถาปัตยกรรม CPU และจะคืนค่าสถาปัตยกรรม CPU นั้น
  3. ถ้าไม่สามารถรับค่าสถาปัตยกรรม CPU ได้ ฟังก์ชันจะพิมพ์ข้อความสีแดงเพื่อแสดงว่าไม่สามารถดึงข้อมูลสถาปัตยกรรม CPU ได้ และจะคืนค่าว่างเปล่า (“”)
  4. หากพบข้อผิดพลาดในการรันคำสั่ง adb (ไม่พบไฟล์หรือโปรแกรม adb) ฟังก์ชันจะพิมพ์ข้อความสีแดงเพื่อแสดงว่า ADB ไม่ได้ติดตั้งหรือไม่พบ และจะคืนค่าว่างเปล่า (“”)

การตรวจสอบสถาปัตยกรรม CPU ที่จะดาวน์โหลด

ฟังก์ชัน match_cpu_architecture_with_download(cpu_architecture, cpu_download, selected_cpu) ใช้ในการตรวจสอบสถาปัตยกรรม CPU ที่จะดาวน์โหลดสอดคล้องกันหรือไม่

def match_cpu_architecture_with_download(cpu_architecture, cpu_download, selected_cpu):
	print_green("\nStart checking architecture...")
	architecture_mapping = dict(zip(cpu_architecture, cpu_download))

	if selected_cpu in architecture_mapping:
		matching_download = architecture_mapping[selected_cpu]
		print("The matching CPU download for '{}' is: {}".format(selected_cpu, matching_download))
		return matching_download
	else:
		print_red("No matching CPU download found for '{}'.".format(selected_cpu))
		return None

ฟังก์ชันนี้จะดำเนินการดังนี้:

  1. สร้างตัวแปล Dictionary architecture_mapping โดยใช้ฟังก์ชัน dict(zip(cpu_architecture, cpu_download)) เพื่อผูกคู่ค่าสถาปัตยกรรม CPU กับการดาวน์โหลดที่สอดคล้องกัน
  2. ตรวจสอบว่า selected_cpu อยู่ใน architecture_mapping หรือไม่ ถ้าใช่ ฟังก์ชันจะคืนค่าการดาวน์โหลดที่สอดคล้องกัน (matching_download) และพิมพ์ข้อความว่า “The matching CPU download for ‘{selected_cpu}’ is: {matching_download}”
  3. ถ้า selected_cpu ไม่อยู่ใน architecture_mapping ฟังก์ชันจะพิมพ์ข้อความสีแดงเพื่อแสดงว่าไม่พบการดาวน์โหลดที่สอดคล้องกับ CPU (selected_cpu) ที่ระบุ และจะคืนค่า None

ระบุสถาปัตยกรรม CPU ที่จะใช้เพื่อดาวน์โหลด

cpu_architecture = [
	"armeabi-v7a",
	"arm64-v8a",
	"x86",
	"x86_64"
]

cpu_download = [
	"android-arm",
	"android-arm64",
	"android-x86",
	"android-x86_64"
]

ในรายการ cpu_architecture สถาปัตยกรรม CPU แต่ละรายการจะมีการดาวน์โหลดที่สอดคล้องกันในรายการ cpu_download โดยอ้างอิงจากลำดับที่เหมือนกันของสถาปัตยกรรม CPU ในทั้งสองรายการ ซึ่งจะช่วยในกรณีที่ต้องการเลือกรูปแบบการดาวน์โหลดที่ถูกต้องสำหรับสถาปัตยกรรม CPU ที่ระบุ.

ตรวจสอบ URL สำหรับดาวน์โหลด Frida Server

ฟังก์ชัน download_frida_server_url(architecture) ใช้ในการตรวจสอบ URL สำหรับดาวน์โหลด Frida Server ที่สอดคล้องกับสถาปัตยกรรม CPU ที่ระบุ

def download_frida_server_url(architecture):
	print_green("\n---> Start checking Frida Download URL...")
	try:
		curl_command = 'curl -s https://api.github.com/repos/frida/frida/releases/latest | grep "browser_download_url.*frida-server.*{}.xz"'.format(architecture)
		result = subprocess.run(curl_command, capture_output=True, text=True, shell=True)
		output = result.stdout.strip()
		print(curl_command)

		if output:
			download_url = output.split('"')[3]
			print("Download URL:", download_url)
			return download_url
		else:
			return None

	except FileNotFoundError:
		print_red("curl command not found.")
		print_red("Unable to find the download URL for frida-server.")
		return None

ฟังก์ชันนี้จะดำเนินการดังนี้:

  1. ใช้คำสั่ง curl เพื่อเรียกดูข้อมูลจาก URL ของ Frida Server โดยใช้คำสั่ง curl -s https://api.github.com/repos/frida/frida/releases/latest | grep "browser_download_url.*frida-server.*{}.xz" โดยใส่สถาปัตยกรรม CPU (architecture) ลงในเครื่องหมาย {} เพื่อค้นหา URL สำหรับดาวน์โหลด Frida Server ที่สอดคล้องกับสถาปัตยกรรม CPU ที่ระบุ
  2. ดำเนินการรับผลลัพธ์จากคำสั่ง curl และนำมาเก็บในตัวแปร output
  3. พิมพ์คำสั่ง curl เพื่อแสดงให้เห็นว่าคำสั่งที่ใช้เป็นอย่างไร
  4. ถ้ามีผลลัพธ์ (output) ฟังก์ชันจะดำเนินการแยก URL ดาวน์โหลด (download_url) จากผลลัพธ์ที่ได้ โดยใช้การแบ่งสตริง " " และเลือกตำแหน่งที่ 3 ในลิสต์ที่ได้ เพื่อรับ URL ที่แท้จริงที่ต้องการ
  5. พิมพ์ข้อความว่า “Download URL: {download_url}” และคืนค่า download_url
  6. ถ้าไม่มีผลลัพธ์ (output) หรือพบข้อผิดพลาดในการรันคำสั่ง curl หรือไม่พบคำสั่ง curl ฟังก์ชันจะพิมพ์ข้อความสีแดงเพื่อแสดงว่าไม่สามารถค้นหา URL สำหรับดาวน์โหลด Frida Server ได้ และจะคืนค่า None

ดาวน์โหลด Frida-server

ฟังก์ชัน download_frida(url, output_path) ใช้ในการดาวน์โหลด Frida Server จาก URL และบันทึกไฟล์ลงในพาธที่ระบุ

def download_frida(url, output_path):
	print_green("\nStart downloading Frida-server...")
	try:
		urllib.request.urlretrieve(url, output_path)
		print("File downloaded successfully.")
		return True
	except Exception as e:
		print_red("An error occurred while downloading the file: {}".format(str(e)))
		return False
	except KeyboardInterrupt:
			# Handle Ctrl+C keyboard interrupt
			print("\nKeyboard interrupt detected. Exiting...")

ฟังก์ชันนี้จะดำเนินการดังนี้:

  1. ใช้ urllib.request.urlretrieve() เพื่อดาวน์โหลดไฟล์จาก URL และบันทึกลงในพาธที่ระบุใน output_path
  2. พิมพ์ข้อความว่า “File downloaded successfully.”
  3. คืนค่า True เพื่อบ่งชี้ว่าดาวน์โหลดเสร็จสมบูรณ์

ในกรณีที่เกิดข้อผิดพลาดขึ้นระหว่างดาวน์โหลด ฟังก์ชันจะแสดงข้อความสีแดงเพื่อแสดงข้อผิดพลาดที่เกิดขึ้นและจะคืนค่า False เพื่อบ่งชี้ว่าเกิดข้อผิดพลาดในการดาวน์โหลด

แตกไฟล์ Frida-server ที่ดาวน์โหลดมา

ฟังก์ชัน extract_xz(xz_path, extract_path) ใช้ในการแตกไฟล์ .xz

def extract_xz(xz_path, extract_path):
	print_green("\nStart extracting .xz file...")
	try:
		with lzma.open(xz_path, 'rb') as xz_file:
			with open(extract_path, 'wb') as extract_file:
				extract_file.write(xz_file.read())
		print("XZ file extracted successfully.")
		return True
	except Exception as e:
		print_red("An error occurred while extracting the XZ file: {}".format(str(e)))
		return False

ฟังก์ชันนี้จะดำเนินการดังนี้:

  1. ใช้ lzma.open() เพื่อเปิดไฟล์ .xz (xz_path) ในโหมดอ่านเป็นไบนารี (rb)
  2. ใช้ open() เพื่อเปิดไฟล์สำหรับการแตกไฟล์ (extract_path) ในโหมดเขียนเป็นไบนารี (wb)
  3. อ่านเนื้อหาจากไฟล์ .xz และเขียนเนื้อหาลงในไฟล์ที่แตกไฟล์ได้
  4. พิมพ์ข้อความว่า “XZ file extracted successfully.”
  5. คืนค่า True เพื่อบ่งชี้ว่าการแตกไฟล์เสร็จสมบูรณ์

ในกรณีที่เกิดข้อผิดพลาดขึ้นระหว่างการแตกไฟล์ .xz ฟังก์ชันจะแสดงข้อความสีแดงเพื่อแสดงข้อผิดพลาดที่เกิดขึ้นและจะคืนค่า False เพื่อบ่งชี้ว่าเกิดข้อผิดพลาดในการแตกไฟล์

คัดลอกไฟล์ frida-server เข้าสู่อุปกรณ์ Android

ฟังก์ชัน copy_to_device() ใช้ในการคัดลอกไฟล์ frida-server เข้าสู่อุปกรณ์ Android

def copy_to_device():
	print_green("\nStart coppting frida-server to an android device...")
	try:
		# Push frida-server to /data/local/tmp
		subprocess.run(['adb', 'push', 'frida-server', '/data/local/tmp'], check=True)
		subprocess.run(['adb', 'shell', 'su', '-c', 'chmod +x /data/local/tmp/frida-server'], check=True)
		print("Frida server coppied successfully.")
		return True

	except subprocess.CalledProcessError as e:
		print_red("An error occurred while coppied Frida server: {}".format(str(e)))
		return False

ฟังก์ชันนี้จะดำเนินการดังนี้:

  1. ใช้ subprocess.run() เพื่อเรียกใช้คำสั่ง adb push frida-server /data/local/tmp เพื่อคัดลอกไฟล์ frida-server เข้าสู่พาธ /data/local/tmp ในอุปกรณ์ Android
  2. ใช้ subprocess.run() เพื่อเรียกใช้คำสั่ง adb shell su -c chmod +x /data/local/tmp/frida-server เพื่อกำหนดสิทธิ์การเข้าถึงและให้สามารถเรียกใช้ไฟล์ frida-server ในพาธ /data/local/tmp ในอุปกรณ์ Android
  3. พิมพ์ข้อความว่า “Frida server copied successfully.”
  4. คืนค่า True เพื่อบ่งชี้ว่าการคัดลอก frida-server เข้าสู่อุปกรณ์ Android เสร็จสมบูรณ์

ในกรณีที่เกิดข้อผิดพลาดขึ้นระหว่างการคัดลอก frida-server ฟังก์ชันจะแสดงข้อความสีแดงเพื่อแสดงข้อผิดพลาดที่เกิดขึ้นและจะคืนค่า False เพื่อบ่งชี้ว่าเกิดข้อผิดพลาดในการคัดลอก frida-server

เริ่มต้นเซิร์ฟเวอร์ของ Frida

ฟังก์ชัน start_frida_server() ใช้ในการเริ่มต้นเซิร์ฟเวอร์ของ Frida

def start_frida_server():
	print_green("\nStart Frida Server...")
	try:
		subprocess.run(['adb', 'shell', 'su', '-c', '/data/local/tmp/frida-server &'], check=True)
		print("Frida server started successfully.")
	except FileNotFoundError:
		print("ADB is not installed.")

	except subprocess.CalledProcessError as e:
		print_red("An error occurred while starting Frida server:: {}".format(str(e)))
	except KeyboardInterrupt:
		# Handle Ctrl+C keyboard interrupt
		print("\nKeyboard interrupt detected. Exiting...")

ฟังก์ชันนี้จะดำเนินการดังนี้:

  1. พิมพ์ข้อความสีเขียวเพื่อแสดงข้อความว่าเริ่มต้นเซิร์ฟเวอร์ของ Frida
  2. ใช้ subprocess.run() เพื่อเรียกใช้คำสั่ง adb shell su -c /data/local/tmp/frida-server & เพื่อเริ่มต้นเซิร์ฟเวอร์ของ Frida ในอุปกรณ์ Android
  3. พิมพ์ข้อความว่า “Frida server started successfully.”

ในกรณีที่เกิดข้อผิดพลาดระหว่างเริ่มต้นเซิร์ฟเวอร์ของ Frida ฟังก์ชันจะแสดงข้อความสีแดงเพื่อแสดงข้อผิดพลาดที่เกิดขึ้น

อ้างอิงจาก