반응형

주로 단말기에서 frida-server 구동하고 attach 를 하였습니다.

attach 방향이 Device <----- Local 입니다.

 

문득 Reverse TCP 처럼 방향이 Device ----> Local 은 될 수 없는 것일까? 라는 생각이 들었습니다만,

이미 frida-portal 이라고 frida 15.0 버전에 도입되었더군요...허허

(https://frida.re/news/2021/07/18/frida-15-0-released/,

https://frida.re/docs/gadget/#connect)

 

아무튼 사용법은 다음과 같습니다.

로컬에서 frida-portal 파이썬 코드 작성해서 구동시켜줍니다. (출처: https://github.com/frida/frida-python/blob/bbdcdfaca821276361399775bd81599710ec0625/examples/portal_server.py)

cluster_params 는 gadget 이 attach 시도할 내 컴퓨터의 ip address 입니다. 192.168.0.76:27052 로 설정하였구요.

control_params 는 gadget 이 내 컴퓨터에 attach 되었을때, 이를 컨트롤 할 수 있게끔 노출되는 인터페이스입니다. 127.0.0.1:27042 로 설정하였습니다.

# -*- coding: utf-8 -*-
import json

import frida
from frida_tools.application import Reactor

ENABLE_CONTROL_INTERFACE = True


def on_message(message, data):
    message = json.loads(message)
    if message is not None and 'payload' in message and message['payload'] is not None:
        print(message['payload'])


class Application:
    def __init__(self):
        self._reactor = Reactor(run_until_return=self._process_input)

        cluster_params = frida.EndpointParameters(address="192.168.0.76",
                                                  port=27052)

        if ENABLE_CONTROL_INTERFACE:
            control_params = frida.EndpointParameters(address="::1",
                                                      port=27042)
        else:
            control_params = None

        service = frida.PortalService(cluster_params, control_params)
        self._service = service
        self._device = service.device

        service.on('node-connected', lambda *args: self._reactor.schedule(lambda: self._on_node_connected(*args)))
        service.on('node-joined', lambda *args: self._reactor.schedule(lambda: self._on_node_joined(*args)))
        service.on('node-left', lambda *args: self._reactor.schedule(lambda: self._on_node_left(*args)))
        service.on('node-disconnected', lambda *args: self._reactor.schedule(lambda: self._on_node_disconnected(*args)))
        service.on('controller-connected', lambda *args: self._reactor.schedule(lambda: self._on_controller_connected(*args)))
        service.on('controller-disconnected', lambda *args: self._reactor.schedule(lambda: self._on_controller_disconnected(*args)))

    def run(self):
        self._reactor.schedule(self._start)
        self._reactor.run()

    def _start(self):
        self._service.start()
        self._device.enable_spawn_gating()

    def _stop(self):
        self._service.stop()

    def _process_input(self, reactor):
        while True:
            try:
                command = input("Enter command: ").strip()
            except KeyboardInterrupt:
                self._reactor.cancel_io()
                return

            if len(command) == 0:
                print("Processes:", self._device.enumerate_processes())
                pid = self._device.enumerate_processes()[0].pid
                session = self._device.attach(pid)
                self._device.resume(pid)
                self.script = session.create_script('''
                    send("hello world");
                ''')
                self.script.on('message', on_message)
                self.script.load()
                continue

            if command == "stop":
                self._reactor.schedule(self._stop)
                break

    def _on_node_connected(self, connection_id, remote_address):
        print("on_node_connected()", connection_id, remote_address)

    def _on_node_joined(self, connection_id, application):
        print("on_node_joined()", connection_id, application)
        print("\ttags:", self._service.enumerate_tags(connection_id))

    def _on_node_left(self, connection_id, application):
        print("on_node_left()", connection_id, application)

    def _on_node_disconnected(self, connection_id, remote_address):
        print("on_node_disconnected()", connection_id, remote_address)

    def _on_controller_connected(self, connection_id, remote_address):
        print("on_controller_connected()", connection_id, remote_address)

    def _on_controller_disconnected(self, connection_id, remote_address):
        print("on_controller_disconnected()", connection_id, remote_address)


if __name__ == '__main__':
    app = Application()
    app.run()

 

 

그 다음 frida-gadget 을 앱에 인젝션 시켜줍니다. 여러가지 방법이 있습니다만, 기본적으로 https://hackcatml.tistory.com/58 참고해서 인젝션 할 수 있겠죠.

config 파일을 위치시켜줘야 하는데, frida-gadget 과 동일 디렉터리에 확장자가 .config.so 라는 이름으로 위치시켜주면 됩니다.

lib
└── arm64-v8a
    ├── libgadget.config.so
    ├── libgadget.so

 

 

config 내용은 다음과 같습니다. 

{
  "interaction": {
    "type": "connect",
    "address": "192.168.0.76",
    "port": 27052
  }
}

 

 

그다음 앱을 실행시켜주면, node 가 connect, join 했다는 알림이 뜹니다. Gadget 이 내 컴퓨터에 attach 한 것이지요.

엔터 입력하면, script 가 실행되어 "hello world"가 출력됩니다.

 

 

물론, frida -H 명령어로 control interface 에 frida 를 붙여줄수도 있습니다.

반응형

+ Recent posts