Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
frida-snippets — 직접 제작한 Frida 예제 | Kitploit
도구/GitHubGitHub/iddoeldor/frida-snippets
Android SecurityDynamic Analysis (Sandboxing)iOS SecurityReverse EngineeringDebuggersMobile SecurityBinary Analysis
GitHubiddoeldor/frida-snippets

frida-snippets

직접 제작한 Frida 예제

저장소 보기
2.5k4391년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

PRs Welcome & 출력 예제도 포함

목차

네이티브
  • C/C++ 모듈 로드
  • 일회성 워치포인트
  • 소켓 활동
  • open 인터셉트
  • 셸 명령 실행
  • 모듈 목록
  • SQLite 쿼리 기록
  • 메서드 인자 기록
  • 전체 모듈 인터셉트
  • 메모리 세그먼트 덤프
  • 메모리 스캔
  • Stalker
  • Cpp Demangler
  • 조기 후크
Android
  • Binder 트랜잭션
  • 시스템 속성 가져오기
  • 수동으로 등록된 네이티브 심볼 표시
  • 로드된 클래스 나열
  • 클래스 설명
  • WiFi 끄기
  • 프록시 설정
  • IMEI 가져오기
  • io InputStream 후크
  • Android Toast 띄우기
  • 특정 모듈 로드 대기
  • Webview URL
iOS
  • OS 로그
  • iOS 알림창
  • 파일 접근
  • 클래스 관찰
  • 애플리케이션 UUID 찾기
  • 쿠키 추출
  • 클래스 멤버 설명
  • 클래스 계층 구조
  • reflection 후크
  • 기기 속성
  • 스크린샷 캡처
  • SSH 명령 기록
Windows

HAHAHA. No.

Sublime 스니펫
root@kitploit:~
{
    "scope": "source.js",
    "completions": [
	{"trigger": "fridainterceptor", "contents": "Interceptor.attach(\n    ptr,\n    {\n        onEnter:function(args) {\n\n        },\n        onLeave: function(retval) {\n\n        }\n    }\n)"},
	{"trigger": "fridaperform", "contents": "function main(){\n    console.log('main()');\n}\n\nconsole.log('script loaded');\nJava.perform(main);"},
	{"trigger": "fridause", "contents": "var kls = Java.use('kls');"},
	{"trigger": "fridahex", "contents": "hexdump(\n    ptr,\n    {\n         offset: 0,\n         length: ptr_size\n     }\n);" },
	{"trigger": "fridabacktrace", "contents": "console.log('called from:\\n' +\n        Thread.backtrace(this.context, Backtracer.ACCURATE)\n        .map(DebugSymbol.fromAddress).join('\\n') + '\\n'\n);"},
	{"trigger": "fridamods", "contents": "var mods = Process.enumerateModules().filter(function(mod){\n    return mod.name.includes(\"<name>\");\n});"},
	{"trigger": "fridaexport", "contents": "Module.findExportByName(null, \"<export_name>\");"},
	{"trigger": "fridabase", "contents": "Module.findBaseAddress(name);"},
	{"trigger": "fridaoverload", "contents": "kls.method_name.overload().implementation=function(){}"}
    ]
}
Vim 스니펫

약어를 나열하려면 :ab

key와 <Space>를 입력해 확장합니다

  • ~/.vimrc에 추가``` ab fridaintercept Interceptor.attach(ptr, {onEnter: function(args) {},onLeave: function(retval) {}}) ab fridabacktrace console.warn(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n'));F(3; ab fridadescribe console.log(Object.getOwnPropertyNames(Java.use('$').proto).join('\n\t'))F$
root@kitploit:~
</details>


<details>
<summary>JEB</summary>	

키보드 단축키를 사용하는 Java 메서드 훅 생성기

1. `curl -o ~/$JEB$/scripts/FridaCodeGenerator.py https://raw.githubusercontent.com/iddoeldor/frida-snippets/master/scripts/FridaCodeGenerator.py` 
2. Java 메서드 시그니처에 커서를 놓습니다.
3. `Ctrl+Shift+Z`를 누릅니다.
4. 코드가 시스템 클립보드에 복사됩니다(`xclip` 사용).


</details>
<hr />
	

#### SSL 키 가져오기```js
var keylog_callback = new NativeCallback((ssl, line) => {
  send(Memory.readCString(line));
}, 'void', ['pointer', 'pointer']);

if (ObjC.available) {
  var CALLBACK_OFFSET = 0x2A8
  if (Memory.readDouble(Module.findExportByName('CoreFoundation', 'kCFCoreFoundationVersionNumber')) >= 1751.108) {
    CALLBACK_OFFSET = 0x2B8
  }
  Interceptor.attach(Module.findExportByName('libboringssl.dylib', 'SSL_CTX_set_info_callback'), {
    onEnter(args) {
      ptr(args[0]).add(CALLBACK_OFFSET).writePointer(keylog_callback)
    }
  })
} else if (Java.available) {
  var set_keylog_callback = new NativeFunction(Module.findExportByName('libssl.so', 'SSL_CTX_set_keylog_callback'), 'void', ['pointer', 'pointer']);
  Interceptor.attach(Module.findExportByName('libssl.so', 'SSL_CTX_new'), {
    onLeave(retval) {
      set_keylog_callback(retval, keylog_callback)
    }
  })
}


⬆ 맨 위로

소켓 활동```js

Process .getModuleByName({ linux: 'libc.so', darwin: 'libSystem.B.dylib', windows: 'ws2_32.dll' }[Process.platform]) .enumerateExports().filter(ex => ex.type === 'function' && ['connect', 'recv', 'send', 'read', 'write'].some(prefix => ex.name.indexOf(prefix) === 0)) .forEach(ex => { Interceptor.attach(ex.address, { onEnter: function (args) { var fd = args[0].toInt32(); var socktype = Socket.type(fd); if (socktype !== 'tcp' && socktype !== 'tcp6') return; var address = Socket.peerAddress(fd); if (address === null) return; console.log(fd, ex.name, address.ip + ':' + address.port); } }) })

root@kitploit:~
<details>
<summary>출력 예제</summary>
	
Android 예제```sh
# wrap the script above inside Java.perform
$ frida -Uf com.example.app -l script.js --no-pause
[Android Model-X::com.example.app]-> 117 write 5.0.2.1:5242
117 read 5.0.2.1:5242
135 write 5.0.2.1:4244
135 read 5.0.2.1:4244
135 read 5.0.2.1:4244


⬆ 맨 위로

Open 인터셉트

특정 파일이 열렸을 때 libc#open을 인터셉트하고 백트레이스를 기록하는 예시입니다.```js Interceptor.attach(Module.findExportByName("/system/lib/libc.so", "open"), { onEnter: function(args) { this.flag = false; var filename = Memory.readCString(ptr(args[0])); console.log('filename =', filename) if (filename.endsWith(".xml")) { this.flag = true; var backtrace = Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n\t"); console.log("file name [ " + Memory.readCString(ptr(args[0])) + " ]\nBacktrace:" + backtrace); } }, onLeave: function(retval) { if (this.flag) // passed from onEnter console.warn("\nretval: " + retval); } });

root@kitploit:~
I'm ready. Please provide the chunk content to translate.```js
var fds = {}; // for f in /proc/`pidof $APP`/fd/*; do echo $f': 'readlink $f; done
Interceptor.attach(Module.findExportByName(null, 'open'), {
  onEnter: function (args) {
    var fname = args[0].readCString();
    if (fname.endsWith('.jar')) {
      this.flag = true;
      this.fname = fname;
    }
  },
  onLeave: function (retval) {
    if (this.flag) {
      fds[retval] = this.fname;
    }
  }
});
['read', 'pread', 'readv'].forEach(fnc => {
  Interceptor.attach(Module.findExportByName(null, fnc), {
    onEnter: function (args) {
      var fd = args[0];
      if (fd in fds)
        console.log(`${fnc}: ${fds[fd]}
	\t${Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n\t')}`);
    }
  });
});
출력 예시 `com.android.chrome` 인터셉트 중


⬆ 맨 위로

셸 명령 실행```python

import frida from frida_tools.application import Reactor import threading import click

class Shell(object): def init(self, argv, env): self._stop_requested = threading.Event() self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait())

root@kitploit:~
    self._device = frida.get_usb_device()
    self._sessions = set()

    self._device.on("child-added", lambda child: self._reactor.schedule(lambda: self._on_child_added(child)))
    self._device.on("child-removed", lambda child: self._reactor.schedule(lambda: self._on_child_removed(child)))
    self._device.on("output", lambda pid, fd, data: self._reactor.schedule(lambda: self._on_output(pid, fd, data)))

    self.argv = argv
    self.env = env
    self.output = []  # stdout will pushed into array

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

def _start(self):
    click.secho("✔ spawn(argv={})".format(self.argv), fg='green', dim=True)
    pid = self._device.spawn(self.argv, env=self.env, stdio='pipe')
    self._instrument(pid)

def _stop_if_idle(self):
    if len(self._sessions) == 0:
        self._stop_requested.set()

def _instrument(self, pid):
    click.secho("✔ attach(pid={})".format(pid), fg='green', dim=True)
    session = self._device.attach(pid)
    session.on("detached", lambda reason: self._reactor.schedule(lambda: self._on_detached(pid, session, reason)))
    click.secho("✔ enable_child_gating()", fg='green', dim=True)
    session.enable_child_gating()
    # print("✔ resume(pid={})".format(pid))
    self._device.resume(pid)
    self._sessions.add(session)

def _on_child_added(self, child):
    click.secho("⚡ child_added: {}".format(child), fg='green', dim=True)
    self._instrument(child.pid)

@staticmethod
def _on_child_removed(child):
    click.secho("⚡ child_removed: {}".format(child), fg='green', dim=True)

def _on_output(self, pid, fd, data):
    # print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data)))
    # fd=0 (input) fd=1(stdout) fd=2(stderr)
    if fd != 2:
        self.output.append(data)

def _on_detached(self, pid, session, reason):
    click.secho("⚡ detached: pid={}, reason='{}'".format(pid, reason), fg='green', dim=True)
    self._sessions.remove(session)
    self._reactor.schedule(self._stop_if_idle, delay=0.5)

@staticmethod
def _on_message(pid, message):
    click.secho("⚡ message: pid={}, payload={}".format(pid, message), fg='green', dim=True)
root@kitploit:~
<details>
<summary>사용 예시</summary>

디렉터리 내용 나열:```python
def ls(folder):
    cmd = Shell(['/bin/sh', '-c', 'ls -la ' + folder], None)
    cmd.exec()
    for chunk in cmd.output:
        print(chunk.strip().decode())

Pull binary from iOS```python cmd = Shell(['/bin/sh', '-c', 'cat /System/Library/PrivateFrameworks/Example.framework/example'], None) cmd.exec() with open('/tmp/example', 'wb+') as f: f.writelines(cmd.output)

$ file /tmp/example

/tmp/example: Mach-O 64-bit 64-bit architecture=12 executable

root@kitploit:~
</details>

<br>[⬆ 맨 위로](#table-of-contents)


#### 모듈 나열```js
Process.enumerateModulesSync()
    .filter(function(m){ return m['path'].toLowerCase().indexOf('app') !=-1 ; })
    .forEach(function(m) {
        console.log(JSON.stringify(m, null, '  '));
        // to list exports use Module.enumerateExportsSync(m.name)
    });

모듈 및 내보내기 나열```js sudo frida Process --no-pause --eval 'var x={};Process.enumerateModulesSync().forEach(function(m){x[m.name] = Module.enumerateExportsSync(m.name)});x' -q | less +F

root@kitploit:~
<details>
<summary>출력 예시</summary>```js
{
  "name": "app_process64",
  "base": "0x6313a1c000",
  "size": 40960,
  "path": "/system/bin/app_process64"
}
{
  "name": "libappfuse.so",
  "base": "0x749ab96000",
  "size": 53248,
  "path": "/system/lib64/libappfuse.so"
}
{
  "name": "[email protected]",
  "base": "0x749b448000",
  "size": 90112,
  "path": "/system/lib64/[email protected]"
}
{
  "name": "[email protected]",
  "base": "0x749ac9e000",
  "size": 94208,
  "path": "/system/lib64/[email protected]"
}
{
  "name": "[email protected]",
  "base": "0x74981e0000",
  "size": 98304,
  "path": "/system/lib64/[email protected]"
}
{
  "name": "[email protected]",
  "base": "0x73fb4cc000",
  "size": 40960,
  "path": "/vendor/lib64/hw/[email protected]"
}
{
  "name": "[email protected]",
  "base": "0x73fb51f000",
  "size": 90112,
  "path": "/system/lib64/vndk-sp-29/[email protected]"
}
{
  "name": "[email protected]",
  "base": "0x73fb542000",
  "size": 94208,
  "path": "/system/lib64/vndk-sp-29/[email protected]"
}
{
  "name": "base.odex",
  "base": "0x73ab4cd000",
  "size": 16965632,
  "path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/oat/arm64/base.odex"
}
{
  "name": "libfrida-gadget.so",
  "base": "0x73a2c05000",
  "size": 22876160,
  "path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libfrida-gadget.so"
}
{
  "name": "libmain.so",
  "base": "0x73fb894000",
  "size": 73728,
  "path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libmain.so"
}
{
  "name": "libunity.so",
  "base": "0x739bf88000",
  "size": 24461312,
  "path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libunity.so"
}
{
  "name": "libil2cpp.so",
  "base": "0x7396fe6000",
  "size": 25272320,
  "path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libil2cpp.so"
}
{
  "name": "DynamiteLoader.odex",
  "base": "0x73b7ee4000",
  "size": 376832,
  "path": "/data/user_de/0/com.google.android.gms/app_chimera/m/00000278/oat/arm64/DynamiteLoader.odex"
}
{
  "name": "base.odex",
  "base": "0x72f2ee3000",
  "size": 166838272,
  "path": "/data/app/com.google.android.gms-j7RpxBsNAd3ttAYEdp2ahg==/oat/arm64/base.odex"
}
{
  "name": "base.odex",
  "base": "0x7396e6d000",
  "size": 28672,
  "path": "/data/app/com.google.android.trichromelibrary_432418133-X7Kc2Mqi-VXkY12N59kGug==/oat/arm64/base.odex"
}
{
  "name": "base.odex",
  "base": "0x724f15e000",
  "size": 13225984,
  "path": "/data/app/com.google.android.webview-w6i6OBFZ7T_wK4W4TpDAiQ==/oat/arm64/base.odex"
}
{
  "name": "libmonochrome.so",
  "base": "0x73b8592000",
  "size": 76673024,
  "path": "/data/app/com.google.android.webview-w6i6OBFZ7T_wK4W4TpDAiQ==/base.apk!/lib/arm64-v8a/libmonochrome.so"
}
{
  "name": "libnativeNoodleNews.so",
  "base": "0x723add3000",
  "size": 962560,
  "path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libnativeNoodleNews.so"
}
{
  "name": "libconscrypt_gmscore_jni.so",
  "base": "0x7206629000",
  "size": 1130496,
  "path": "/data/app/com.google.android.gms-j7RpxBsNAd3ttAYEdp2ahg==/base.apk!/lib/arm64-v8a/libconscrypt_gmscore_jni.so"
}


⬆ 맨 위로

SQLite 쿼리 로그```js

Interceptor.attach(Module.findExportByName('libsqlite.so', 'sqlite3_prepare16_v2'), { onEnter: function(args) { console.log('DB: ' + Memory.readUtf16String(args[0]) + '\tSQL: ' + Memory.readUtf16String(args[1])); } });

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### system property get```js
Interceptor.attach(Module.findExportByName(null, '__system_property_get'), {
	onEnter: function (args) {
		this._name = args[0].readCString();
		this._value = args[1];
	},
	onLeave: function (retval) {
		console.log(JSON.stringify({
			result_length: retval,
			name: this._name,
			val: this._value.readCString()
		}));
	}
});
출력 예시```sh {"result_length":"0x0","name":"ro.kernel.android.tracing","val":""} {"result_length":"0x0","name":"ro.config.hw_log","val":""} {"result_length":"0x0","name":"ro.config.hw_module_log","val":""} {"result_length":"0x1","name":"ro.debuggable","val":"0"} {"result_length":"0x1","name":"persist.sys.huawei.debug.on","val":"0"} {"result_length":"0x1","name":"ro.logsystem.usertype","val":"6"} {"result_length":"0x6","name":"ro.board.platform","val":"hi6250"} {"result_length":"0x4","name":"persist.sys.enable_iaware","val":"true"} {"result_length":"0x1","name":"persist.sys.cpuset.enable","val":"1"} {"result_length":"0x4","name":"persist.sys.cpuset.subswitch","val":"1272"} {"result_length":"0x4","name":"persist.sys.boost.durationms","val":"1000"} {"result_length":"0x4","name":"persist.sys.boost.isbigcore","val":"true"} {"result_length":"0x7","name":"persist.sys.boost.freqmin.b","val":"1805000"} {"result_length":"0x4","name":"persist.sys.boost.ipapower","val":"3500"} {"result_length":"0x0","name":"persist.sys.boost.skipframe","val":""} {"result_length":"0x0","name":"persist.sys.boost.byeachfling","val":""} {"result_length":"0x1","name":"debug.force_rtl","val":"0"} {"result_length":"0x0","name":"ro.hardware.gralloc","val":""} {"result_length":"0x6","name":"ro.hardware","val":"hi6250"} {"result_length":"0x0","name":"ro.kernel.qemu","val":""} {"result_length":"0x0","name":"ro.config.hw_force_rotation","val":""} {"result_length":"0x0","name":"persist.fb_auto_alloc","val":""} {"result_length":"0x0","name":"ro.config.hw_lock_res_whitelist","val":""} {"result_length":"0x3","name":"ro.sf.lcd_density","val":"480"} {"result_length":"0x0","name":"persist.sys.dpi","val":""} {"result_length":"0x0","name":"persist.sys.rog.width","val":""} {"result_length":"0x4","name":"dalvik.vm.usejitprofiles","val":"true"} {"result_length":"0x1","name":"debug.atrace.tags.enableflags","val":"0"} {"result_length":"0x1","name":"ro.debuggable","val":"0"} {"result_length":"0x1","name":"debug.force_rtl","val":"0"} {"result_length":"0x0","name":"ro.config.hw_lock_res_whitelist","val":""} .... ```


⬆ 맨 위로

Binder 트랜잭션```js

var LAST_MSG = ''; Java.perform(() => { Interceptor.attach(Module.findExportByName('libbinder.so', 'ioctl'), { onEnter: function(args) { var binder_write_read_ptr = args[2]; if (args[1] == 0xC0306201) { // BINDER_WRITE_READ var binder_write_read = { // 'fd': args[0].toInt32(), 'write_size': binder_write_read_ptr.readU64(), 'write_consumed': binder_write_read_ptr.add(Process.pointerSize).readU64(), 'write_buffer': binder_write_read_ptr.add(Process.pointerSize * 2).readPointer(), } if (binder_write_read.write_size > 0) { var ptr = binder_write_read.write_buffer.add(binder_write_read.write_consumed + 4); switch (binder_write_read.write_buffer.readU32() & 0xff) { case 0: // BC_TRANSACTION case 1: // BC_REPLY var binder_transaction_data = { 'target': { 'handle': ptr.readU32(), 'ptr': ptr.readPointer() }, 'cookie': ptr.add(8).readPointer(), 'code': ptr.add(16).readU32(), 'flags': ptr.add(20).readU32(), 'sender_pid': ptr.add(24).readS32(), 'sender_euid': ptr.add(28).readU32(), 'data_size': ptr.add(32).readU64(), 'offsets_size': ptr.add(40).readU64(), 'data': { 'ptr': { 'buffer': ptr.add(48).readPointer(), 'offsets': ptr.add(56).readPointer() }, 'buf': ptr.add(48).readByteArray(8) } } var _log = hexdump(binder_transaction_data.data.ptr.buffer, { length: binder_transaction_data.data_size, ansi: true }); if (LAST_MSG.toString() != _log.toString()) { console.log(JSON.stringify(binder_transaction_data, null, 2)); console.log(_log); } break; } } } } }); });

root@kitploit:~
<details>
<summary>출력 예시</summary>```sh
{
  "target": {
    "handle": 16,
    "ptr": "0x10"
  },
  "cookie": "0x0",
  "code": 22,
  "flags": 16,
  "sender_pid": 0,
  "sender_euid": 0,
  "data_size": "68",
  "offsets_size": "0",
  "data": {
    "ptr": {
      "buffer": "0x78dce3dcf0",
      "offsets": "0x0"
    },
    "buf": {}
  }
}
             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
78dce3dcf0  04 00 40 01 1d 00 00 00 61 00 6e 00 64 00 72 00  [email protected].
78dce3dd00  6f 00 69 00 64 00 2e 00 6e 00 65 00 74 00 2e 00  o.i.d...n.e.t...
78dce3dd10  77 00 69 00 66 00 69 00 2e 00 49 00 57 00 69 00  w.i.f.i...I.W.i.
78dce3dd20  66 00 69 00 4d 00 61 00 6e 00 61 00 67 00 65 00  f.i.M.a.n.a.g.e.
78dce3dd30  72 00 00 00                                      r...


⬆ 맨 위로

네이티브 메서드 노출

registerNativeMethods는 네이티브 .so 라이브러리에 대한 안티 리버싱 기법으로 사용될 수 있습니다. 예를 들어 심볼을 최대한 숨기고, 익스포트된 심볼을 난독화하며, 궁극적으로 JNI 브리지에 일부 보호 기능을 추가하는 것입니다. 출처```js var RevealNativeMethods = function() { var pSize = Process.pointerSize; var env = Java.vm.getEnv(); var RegisterNatives = 215, FindClassIndex = 6; // search "215" @ https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html var jclassAddress2NameMap = {}; function getNativeAddress(idx) { return env.handle.readPointer().add(idx * pSize).readPointer(); } // intercepting FindClass to populate Map<address, jclass> Interceptor.attach(getNativeAddress(FindClassIndex), { onEnter: function(args) { jclassAddress2NameMap[args[0]] = args[1].readCString(); } }); // RegisterNative(jClass*, .., JNINativeMethod methods[nMethods], uint nMethods) // https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#977 Interceptor.attach(getNativeAddress(RegisterNatives), { onEnter: function(args) { for (var i = 0, nMethods = parseInt(args[3]); i < nMethods; i++) { / https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#129 typedef struct { const char* name; const char* signature; void* fnPtr; } JNINativeMethod; / var structSize = pSize * 3; // = sizeof(JNINativeMethod) var methodsPtr = ptr(args[2]); var signature = methodsPtr.add(i * structSize + pSize).readPointer(); var fnPtr = methodsPtr.add(i * structSize + (pSize * 2)).readPointer(); // void fnPtr var jClass = jclassAddress2NameMap[args[0]].split('/'); var methodName = methodsPtr.add(i * structSize).readPointer().readCString(); console.log('\x1b[3' + '6;01' + 'm', JSON.stringify({ module: DebugSymbol.fromAddress(fnPtr)['moduleName'], // https://www.frida.re/docs/javascript-api/#debugsymbol package: jClass.slice(0, -1).join('.'), class: jClass[jClass.length - 1], method: methodName, // methodsPtr.readPointer().readCString(), // char* name signature: signature.readCString(), // char* signature TODO Java bytecode signature parser { Z: 'boolean', B: 'byte', C: 'char', S: 'short', I: 'int', J: 'long', F: 'float', D: 'double', L: 'fully-qualified-class;', '[': 'array' } https://github.com/skylot/jadx/blob/master/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java address: fnPtr }), '\x1b[39;49;00m'); } } }); }

Java.perform(RevealNativeMethods);

root@kitploit:~
@OldVersion```js
var fIntercepted = false;

function revealNativeMethods() {
    if (fIntercepted === true) {
        return;
    }
    var jclassAddress2NameMap = {};
    var androidRunTimeSharedLibrary = "libart.so"; // may change between devices
    Module.enumerateSymbolsSync(androidRunTimeSharedLibrary).forEach(function(symbol){
        switch (symbol.name) {
            case "_ZN3art3JNI21RegisterNativeMethodsEP7_JNIEnvP7_jclassPK15JNINativeMethodib":
                /*
                    $ c++filt "_ZN3art3JNI21RegisterNativeMethodsEP7_JNIEnvP7_jclassPK15JNINativeMethodib"
                    art::JNI::RegisterNativeMethods(_JNIEnv*, _jclass*, JNINativeMethod const*, int, bool)
                */
                var RegisterNativeMethodsPtr = symbol.address;
                console.log("RegisterNativeMethods is at " + RegisterNativeMethodsPtr);
                Interceptor.attach(RegisterNativeMethodsPtr, {
                    onEnter: function(args) {
                        var methodsPtr = ptr(args[2]);
                        var methodCount = parseInt(args[3]);
                        for (var i = 0; i < methodCount; i++) {
                            var pSize = Process.pointerSize;
                            /*
                                https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#129
                                typedef struct {
                                    const char* name;
                                    const char* signature;
                                    void* fnPtr;
                                } JNINativeMethod;
                            */
                            var structSize = pSize * 3; // JNINativeMethod contains 3 pointers
                            var namePtr = Memory.readPointer(methodsPtr.add(i * structSize));
                            var sigPtr = Memory.readPointer(methodsPtr.add(i * structSize + pSize));
                            var fnPtrPtr = Memory.readPointer(methodsPtr.add(i * structSize + (pSize * 2)));
                            // output schema: className#methodName(arguments)returnVal@address
                            console.log(
                                // package & class, replacing forward slash with dot for convenience
                                jclassAddress2NameMap[args[0]].replace(/\//g, '.') +
                                '#' + Memory.readCString(namePtr) + // method
                                Memory.readCString(sigPtr) + // signature (arguments & return type)
                                '@' + fnPtrPtr // C side address
                            );
                        }
                    },
                    onLeave: function (ignoredReturnValue) {}
                });
                break;
            case "_ZN3art3JNI9FindClassEP7_JNIEnvPKc": // art::JNI::FindClass
                Interceptor.attach(symbol.address, {
                    onEnter: function(args) {
                        if (args[1] != null) {
                            jclassAddress2NameMap[args[0]] = Memory.readCString(args[1]);
                        }
                    },
                    onLeave: function (ignoredReturnValue) {}
                });
                break;
        }
    });
    fIntercepted = true;
}

Java.perform(revealNativeMethods);
출력 예시```sh $ frida -Uf com.google.android.apps.photos --no-pause -l script.js ``` (Empty response due to missing input)```sh {"class":"org/chromium/net/GURLUtils","method":"nativeGetOrigin","signature":"(Ljava/lang/String;)Ljava/lang/String;","address":"0x..da910"} .. ```


⬆ 맨 위로

메서드 인자 로깅```python

def on_message(m, _data): if m['type'] == 'send': print(m['payload']) elif m['type'] == 'error': print(m)

def switch(argument_key, idx): """ c/c++ variable type to javascript reader switch implementation # TODO handle other arguments, [long, longlong..] :param argument_key: variable type :param idx: index in symbols array :return: javascript to read the type of variable """ argument_key = argument_key.replace(' ', '') return '%d: %s' % (idx, { 'int': 'args[%d].toInt32(),', 'unsignedint': 'args[%d].toInt32(),', 'std::string': 'Memory.readUtf8String(Memory.readPointer(args[%d])),', 'bool': 'Boolean(args[%d]),' }[argument_key] % idx)

def list_symbols_from_object_files(module_id): import subprocess return subprocess.getoutput('nm --demangle --dynamic %s' % module_id)

def parse_nm_output(nm_stdout, symbols): for line in nm_stdout.splitlines(): split = line.split() open_parenthesis_idx = line.find('(') raw_arguments = [] if open_parenthesis_idx == -1 else line[open_parenthesis_idx + 1:-1] if len(raw_arguments) > 0: # ignore methods without arguments raw_argument_list = raw_arguments.split(',') symbols.append({ 'address': split[0], 'type': split[1], # @see Symbol Type Table 'name': split[2][:split[2].find('(')], # method name 'args': raw_argument_list })

def get_js_script(method, module_id): js_script = """ var moduleName = "{{moduleName}}", nativeFuncAddr = {{methodAddress}}; Interceptor.attach(Module.findExportByName(null, "dlopen"), { onEnter: function(args) { this.lib = Memory.readUtf8String(args[0]); console.log("[] dlopen called with: " + this.lib); }, onLeave: function(retval) { if (this.lib.endsWith(moduleName)) { Interceptor.attach(Module.findBaseAddress(moduleName).add(nativeFuncAddr), { onEnter: function(args) { console.log("[] hook invoked", JSON.stringify({{arguments}}, null, '\t')); } }); } } }); """ replace_map = { '{{moduleName}}': module_id, '{{methodAddress}}': '0x' + method['address'], '{{arguments}}': '{' + ''.join([switch(method['args'][i], i + 1) for i in range(len(method['args']))]) + '}' } for k, v in replace_map.items(): js_script = js_script.replace(k, v) print('[+] JS Script:\n', js_script) return js_script

def main(app_id, module_id, method): """ $ python3.x+ script.py --method SomeClass::someMethod --app com.company.app --module libfoo.so :param app_id: application identifier / bundle id :param module_id: shared object identifier / known suffix, will iterate loaded modules (@see dlopen) :param method: method/symbol name :return: hook native method and print arguments when invoked """ # TODO extract all app's modules via adb shell -c 'ls -lR /data/app/' + app_if + '*' | grep "\.so"

root@kitploit:~
nm_stdout = list_symbols_from_object_files(module_id)

symbols = []
parse_nm_output(nm_stdout, symbols)

selection_idx = None
for idx, symbol in enumerate(symbols):
    if method is None:  # if --method flag is not passed
        print("%4d) %s (%d)" % (idx, symbol['name'], len(symbol['args'])))
    elif method == symbol['name']:
        selection_idx = idx
        break
if selection_idx is None:
    if method is None:
        selection_idx = input("Enter symbol number: ")
    else:
        print('[+] Method not found, remove method flag to get list of methods to select from, `nm` stdout:')
        print(nm_stdout)
        exit(2)

method = symbols[int(selection_idx)]
print('[+] Selected method: %s' % method['name'])
print('[+] Method arguments: %s' % method['args'])

from frida import get_usb_device
device = get_usb_device()
pid = device.spawn([app_id])
session = device.attach(pid)
script = session.create_script(get_js_script(method, module_id))
script.on('message', on_message)
script.load()
device.resume(app_id)
# keep hook alive
from sys import stdin
stdin.read()

if name == 'main': from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument('--app', help='app identifier "com.company.app"') parser.add_argument('--module', help='loaded module name "libfoo.2.so"') parser.add_argument('--method', help='method name "SomeClass::someMethod", if empty it will print select-list') args = parser.parse_args() main(args.app, args.module, args.method)

root@kitploit:~
<details>
<summary>심볼 유형 표</summary>
<pre>
    "A" 심볼의 값은 절대값이며, 이후 링크 과정에서 변경되지 않습니다.
    "B" 심볼은 초기화되지 않은 데이터 섹션(BSS)에 있습니다.
    "C" 심볼은 공통(common) 심볼입니다.  공통 심볼은 초기화되지 않은 데이터입니다.
       링크할 때 여러 공통 심볼이 동일한 이름으로	나타날 수 있습니다.  
       심볼이 어디에서든 정의되어 있으면 공통 심볼은 정의되지 않은	참조로 취급됩니다.
    "D" 심볼은 초기화된 데이터 섹션에 있습니다.
    "G" 심볼은 작은 객체를 위한 초기화된 데이터 섹션에 있습니다.
       일부 객체 파일 형식은 전역 int 변수와 같은 작은 데이터 객체에 더 효율적으로 접근할 수 있게 해 주며, 
       이는 대규모 전역 배열과는 대조적입니다.
    "I" 심볼은 다른 심볼에 대한 간접 참조입니다.
       이것은 거의 사용되지 않는 a.out 객체 파일 형식에 대한 GNU 확장입니다.
    "N" 심볼은 디버깅 심볼입니다.
    "R" 심볼은 읽기 전용 데이터 섹션에 있습니다.
    "S" 심볼은 작은 객체를 위한 초기화되지 않은 데이터 섹션에 있습니다.
    "T" 심볼은 텍스트(코드) 섹션에 있습니다.
    "U" 심볼은 정의되어 있지 않습니다.
    "V" 심볼은 약한 객체입니다. 약한 정의 심볼이 일반 정의 심볼과 링크되면 
        일반 정의 심볼이 오류 없이 사용됩니다.  
        약한 정의되지 않은 심볼이 링크되고 심볼이 정의되어 있지 않으면, 약한 심볼의 값은 
        오류 없이 0이 됩니다.
    "W" 심볼은 약한 객체 심볼로 특별히 태그되지 않은 약한 심볼입니다. 
        약한 정의 심볼이 일반 정의 심볼과 링크되면 
        일반 정의 심볼이 오류 없이 사용됩니다.  
        약한 정의되지 않은 심볼이 링크되고 심볼이 정의되어 있지 않으면, 심볼의 값은 
        오류 없이 시스템별 방식으로 결정됩니다.  
        일부 시스템에서는 대문자가 기본값이 지정되었음을 나타냅니다.
    "-" 심볼은 a.out 객체 파일의 stabs 심볼입니다.  
        이 경우 다음에 출력되는 값은 stabs other 필드, stabs desc 필드, stab 유형입니다.  
        stabs 심볼은 디버깅 정보를 저장하는 데 사용됩니다.
    "?" 심볼 유형이 알 수 없거나 객체 파일 형식에 따라 다릅니다.
</pre>
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### 로드된 클래스 열거

그리고 `pkg.classes`라는 파일로 저장합니다.```bash
$ frida -U com.pkg -qe 'Java.perform(function(){Java.enumerateLoadedClasses({"onMatch":function(c){console.log(c);}});});' -o pkg.classes
출력 예시 TODO


⬆ 맨 위로

클래스 설명

클래스 메서드 및 멤버를 가져옵니다.```js Object.getOwnPropertyNames(Java.use('com.company.CustomClass').proto).join('\n\t')

root@kitploit:~
이름 충돌이 있는 경우, 메서드와 멤버가 같은 이름을 가지면 멤버에 밑줄이 추가됩니다. [출처](https://github.com/frida/frida-java/pull/21)```js
	let fieldJsName = env.stringFromJni(fieldName);
	while (jsMethods.hasOwnProperty(fieldJsName)) {
		fieldJsName = '_' + fieldJsName;
	}
출력 예시 TODO


⬆ 맨 위로

WiFi 끄기

첫 번째 Activity가 생성될 때 WiFi를 끕니다.```js var WifiManager = Java.use("android.net.wifi.WifiManager"); Java.use("android.app.Activity").onCreate.overload("android.os.Bundle").implementation = function(bundle) { var wManager = Java.cast(this.getSystemService("wifi"), WifiManager); console.log('isWifiEnabled ?', wManager.isWifiEnabled()); wManager.setWifiEnabled(false); this.$init(bundle); }

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### 프록시 설정

제공된 IP 주소와 포트를 사용하여 시스템 전체에 프록시를 설정합니다.```js
var ActivityThread      = Java.use('android.app.ActivityThread');
var ConnectivityManager = Java.use('android.net.ConnectivityManager');
var ProxyInfo           = Java.use('android.net.ProxyInfo');

var proxyInfo           = ProxyInfo.$new('192.168.1.10', 8080, ''); // change to null in order to disable the proxy.
var context = ActivityThread.currentApplication().getApplicationContext();
var connectivityManager = Java.cast(context.getSystemService('connectivity'), ConnectivityManager);
connectivityManager.setGlobalProxy(proxyInfo);
출력 예시 TODO


⬆ 맨 위로

IMEI 가져오기

또한 IMEI를 후킹하고 변경할 수 있습니다.```js function getIMEI(){ console.log('IMEI =', Java.use("android.telephony.TelephonyManager").$new().getDeviceId()); } Java.perform(getIMEI)

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### io InputStream 후킹

`InputputStream`을 후킹하고 버퍼를 `ascii`로 출력하며 문자 제한 및 제외 목록을 지원합니다.```js
function binaryToHexToAscii(array, readLimit) {
    var result = [];
    // read 100 bytes #performance
    readLimit = readLimit || 100;
    for (var i = 0; i < readLimit; ++i) {
        result.push(String.fromCharCode( // hex2ascii part
            parseInt(
                ('0' + (array[i] & 0xFF).toString(16)).slice(-2), // binary2hex part
                16
            )
        ));
    }
    return result.join('');
}

function hookInputStream() {
    Java.use('java.io.InputStream')['read'].overload('[B').implementation = function(b) {
        // execute original and save return value
        var retval = this.read(b);
        var resp = binaryToHexToAscii(b);
        // conditions to not print garbage packets
        var reExcludeList = new RegExp(['Mmm'/*, 'Ping' /*, ' Yo'*/].join('|'));
        if ( ! reExcludeList.test(resp) ) {
            console.log(resp);
        }
        var reIncludeList = new RegExp(['AAA', 'BBB', 'CCC'].join('|')); 
        if ( reIncludeList.test(resp) ) {
            send( binaryToHexToAscii(b, 1200) );
        }
        return retval;
    };
}

Java.perform(hookInputStream);
출력 예제 TODO


⬆ 맨 위로

Android에서 Toast 만들기```js

// 0 = // https://developer.android.com/reference/android/widget/Toast#LENGTH_LONG Java.scheduleOnMainThread(() => { Java.use("android.widget.Toast") .makeText(Java.use("android.app.ActivityThread").currentApplication().getApplicationContext(), Java.use("java.lang.StringBuilder").$new("Text to Toast here"), 0).show(); });

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>
<br>[⬆ 맨 위로](#table-of-contents)

#### 조건 대기
Unity 앱에서 특정 DLL이 로드될 때까지 대기하며, hot swap을 구현할 수 있습니다.```javascript
var awaitForCondition = function(callback) {
    var int = setInterval(function() {
        if (Module.findExportByName(null, "mono_get_root_domain")) {
            clearInterval(int);
            callback();
            return;
        }
    }, 0);
}

function hook() {
    Interceptor.attach(Module.findExportByName(null, "mono_assembly_load_from_full"), {
        onEnter: function(args) {
            this._dll = Memory.readUtf8String(ptr(args[1]));
            console.log('[*]', this._dll);
        },
        onLeave: function(retval) {          
            if (this._dll.endsWith("Assembly-CSharp.dll")) {
                console.log(JSON.stringify({
                    retval: retval,
                    name: this._dll
                }, null, 2));
            }
        }
    });
}
Java.perform(awaitForCondition(hook));
출력 예시 TODO


⬆ 맨 위로

Webview URLS

WebView가 URL을 전환할 때마다 기록합니다.```js Java.use("android.webkit.WebView").loadUrl.overload("java.lang.String").implementation = function (s) { send(s.toString()); this.loadUrl.overload("java.lang.String").call(this, s); };

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### 런타임 문자열 출력 

StringBuilder/Buffer의 `toString`을 후킹하고 스택트레이스를 출력합니다.```js
Java.perform(function() {
  ['java.lang.StringBuilder', 'java.lang.StringBuffer'].forEach(function(clazz, i) {
    console.log('[?] ' + i + ' = ' + clazz);
    var func = 'toString';
    Java.use(clazz)[func].implementation = function() {
      var ret = this[func]();
      if (ret.indexOf('') != -1) {
        // print stacktrace if return value contains specific string
        Java.perform(function() {
          var jAndroidLog = Java.use("android.util.Log"), jException = Java.use("java.lang.Exception");
          console.log( jAndroidLog.getStackTraceString( jException.$new() ) );
        }); 
      }   
      send('[' + i + '] ' + ret);
      return ret;
    }   
  }); 
});
출력 예시 TODO


⬆ 맨 위로

공유 환경설정 업데이트 출력```js

Java.perform(function() { var shared_pref_class = Java.use('android.app.SharedPreferencesImpl$EditorImpl');

root@kitploit:~
shared_pref_class.putString.overload('java.lang.String', 'java.lang.String').implementation = function(k, v) {
    console.log('Shared preference updated: ', k, '=', v);
    return this.putString(k, v);
}

shared_pref_class.putInt.overload('java.lang.String', 'int').implementation = function(k, v) {
    console.log('Shared preference updated: ', k, '=', v);
    return this.putInt(k, v);
}


shared_pref_class.putFloat.overload('java.lang.String', 'float').implementation = function(k, v) {
    console.log('Shared preference updated: ', k, '=', v);
    return this.putFloat(k, v);
}

shared_pref_class.putBoolean.overload('java.lang.String', 'boolean').implementation = function(k, v) {
    console.log('Shared preference updated: ', k, '=', v);
    return this.putBoolean(k, v);
}

shared_pref_class.putLong.overload('java.lang.String', 'long').implementation = function(k, v) {
    console.log('Shared preference updated: ', k, '=', v);
    return this.putLong(k, v);
}

shared_pref_class.putStringSet.overload('java.lang.String', java.util.Set).implementation = function(k, v) {
    console.log('Shared preference updated: ', k, '=', v);
    return this.putStringSet(k, v);
}

});

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)




#### 문자열 비교```js
Java.perform(function() {
    var str = Java.use('java.lang.String'), objectClass = 'java.lang.Object';
    str.equals.overload(objectClass).implementation = function(obj) {
        var response = str.equals.overload(objectClass).call(this, obj);
        if (obj) {
            if (obj.toString().length > 5) {
                send(str.toString.call(this) + ' == ' + obj.toString() + ' ? ' + response);
            }
        }
        return response;
    }
});
출력 예시 TODO


⬆ 맨 위로

주소로 JNI 후킹

모듈 이름과 메서드 주소로 네이티브 메서드를 후킹하고 인수를 출력합니다.```js var moduleName = "libfoo.so"; var nativeFuncAddr = 0x1234; // $ nm --demangle --dynamic libfoo.so | grep "Class::method("

Interceptor.attach(Module.findExportByName(null, "dlopen"), { onEnter: function(args) { this.lib = Memory.readUtf8String(args[0]); console.log("dlopen called with: " + this.lib); }, onLeave: function(retval) { if (this.lib.endsWith(moduleName)) { console.log("ret: " + retval); var baseAddr = Module.findBaseAddress(moduleName); Interceptor.attach(baseAddr.add(nativeFuncAddr), { onEnter: function(args) { console.log("[-] hook invoked"); console.log(JSON.stringify({ a1: args[1].toInt32(), a2: Memory.readUtf8String(Memory.readPointer(args[2])), a3: Boolean(args[3]) }, null, '\t')); } }); } } });

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### Hook 생성자```js
Java.use('java.lang.StringBuilder').$init.overload('java.lang.String').implementation = function(stringArgument) {
      console.log("c'tor");
      return this.$init(stringArgument);
};
출력 예시 TODO


⬆ 맨 위로

Hook 리플렉션

`java.lang.reflect.Method#invoke(Object obj, Object... args, boolean bool)````javascript Java.use('java.lang.reflect.Method').invoke.overload('java.lang.Object', '[Ljava.lang.Object;', 'boolean').implementation = function(a,b,c) { console.log('hooked!', a, b, c); return this.invoke(a,b,c); };

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### Trace 클래스

클래스 메서드를 추적하며, 보기 좋은 색상과 JSON 및 스택트레이스로 출력하는 옵션을 제공합니다.

TODO: c'tor에 대한 trace를 추가하세요.```js

var Color = {
    RESET: "\x1b[39;49;00m", Black: "0;01", Blue: "4;01", Cyan: "6;01", Gray: "7;11", Green: "2;01", Purple: "5;01", Red: "1;01", Yellow: "3;01",
    Light: {
        Black: "0;11", Blue: "4;11", Cyan: "6;11", Gray: "7;01", Green: "2;11", Purple: "5;11", Red: "1;11", Yellow: "3;11"
    }
};

/**
 *
 * @param input. 
 *      If an object is passed it will print as json 
 * @param kwargs  options map {
 *     -l level: string;   log/warn/error
 *     -i indent: boolean;     print JSON prettify
 *     -c color: @see ColorMap
 * }
 */
var LOG = function (input, kwargs) {
    kwargs = kwargs || {};
    var logLevel = kwargs['l'] || 'log', colorPrefix = '\x1b[3', colorSuffix = 'm';
    if (typeof input === 'object')
        input = JSON.stringify(input, null, kwargs['i'] ? 2 : null);
    if (kwargs['c'])
        input = colorPrefix + kwargs['c'] + colorSuffix + input + Color.RESET;
    console[logLevel](https://github.com/iddoeldor/frida-snippets/blob/HEAD/input);
};

var printBacktrace = function () {
    Java.perform(function() {
        var android_util_Log = Java.use('android.util.Log'), java_lang_Exception = Java.use('java.lang.Exception');
        // getting stacktrace by throwing an exception
        LOG(android_util_Log.getStackTraceString(java_lang_Exception.$new()), { c: Color.Gray });
    });
};

function traceClass(targetClass) {
    var hook;
    try {
        hook = Java.use(targetClass);
    } catch (e) {
        console.error("trace class failed", e);
        return;
    }

    var methods = hook.class.getDeclaredMethods();
    hook.$dispose();

    var parsedMethods = [];
    methods.forEach(function (method) {
        var methodStr = method.toString();
        var methodReplace = methodStr.replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1];
         parsedMethods.push(methodReplace);
    });

    uniqBy(parsedMethods, JSON.stringify).forEach(function (targetMethod) {
        traceMethod(targetClass + '.' + targetMethod);
    });
}


function traceMethod(targetClassMethod) {
    try {
        var delim = targetClassMethod.lastIndexOf('.');
        if (delim === -1)
            return;

        var targetClass = targetClassMethod.slice(0, delim);
        var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length);

        var hook = Java.use(targetClass);
        var overloadCount = hook[targetMethod].overloads.length;

        LOG({ tracing: targetClassMethod, overloaded: overloadCount }, { c: Color.Green });

        for (var i = 0; i < overloadCount; i++) {
            hook[targetMethod].overloads[i].implementation = function () {
                var log = { '#': targetClassMethod, args: [] };

                for (var j = 0; j < arguments.length; j++) {
                    var arg = arguments[j];
                    // quick&dirty fix for java.io.StringWriter char[].toString() impl because frida prints [object Object]
                    if (j === 0 && arguments[j]) {
                        if (arguments[j].toString() === '[object Object]') {
                            var s = [];
                            for (var k = 0, l = arguments[j].length; k < l; k++) {
                                s.push(arguments[j][k]);
                            }
                            arg = s.join('');
                        }
                    }
                    log.args.push({ i: j, o: arg, s: arg ? arg.toString(): 'null'});
                }

                var retval;
                try {
                    retval = this[targetMethod].apply(this, arguments); // might crash (Frida bug?)
                    log.returns = { val: retval, str: retval ? retval.toString() : null };
                } catch (e) {
                    console.error(e);
                }
                LOG(log, { c: Color.Blue });
                return retval;
            }
        }
    } catch(error) {
        LOG({ tracing: targetClassMethod, "overloaded": 0}, { c: Color.Red });
    }
}
// remove duplicates from array
function uniqBy(array, key) {
    var seen = {};
    return array.filter(function (item) {
        var k = key(item);
        return seen.hasOwnProperty(k) ? false : (seen[k] = true);
    });
}


var Main = function() {
    Java.perform(function () { // avoid java.lang.ClassNotFoundException
        [
            // "java.io.File",
            'java.net.Socket'
        ].forEach(traceClass);

        Java.use('java.net.Socket').isConnected.overload().implementation = function () {
            LOG('Socket.isConnected.overload', { c: Color.Light.Cyan });
            printBacktrace();
            return true;
        }
    });
};

Java.perform(Main);


출력 예시 TODO


⬆ 맨 위로

Android ID 가져오기

ANDROID_ID는 Android의 각 애플리케이션에서 고유합니다.```javascript function getContext() { return Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(); }

function logAndroidId() { console.log('[-]', Java.use('android.provider.Settings$Secure').getString(getContext(), 'android_id')); }

root@kitploit:~
<details>
<summary>출력 예시</summary>
https://stackoverflow.com/a/54818023/2655092
</details>

<br>[⬆ 맨 위로](#table-of-contents)


#### 위치 변경```js
Java.perform(() => {
	var Location = Java.use('android.location.Location');
	Location.getLatitude.implementation = function() {
		return LATITUDE;
	}
	Location.getLongitude.implementation = function() {
		return LONGITUDE;
	}
})
출력 예시 TODO


⬆ 맨 위로

FLAG_SECURE 우회

스크린샷 방지 우회 stackoverflow 질문```javascript Java.perform(function() { Java.use('android.view.SurfaceView').setSecure.overload('boolean').implementation = function(flag){ console.log('[1] flag:', flag); this.call(false); }; var LayoutParams = Java.use('android.view.WindowManager$LayoutParams'); Java.use('android.view.ViewWindow').setFlags.overload('int', 'int').implementation = function(flags, mask){ console.log('flag secure: ', LayoutParams.FLAG_SECURE.value); console.log('before:', flags); flags = (flags.value & ~LayoutParams.FLAG_SECURE.value); console.log('after:', flags); this.call(this, flags, mask); }; });

root@kitploit:~
<details>
<summary>출력 예제</summary>
https://stackoverflow.com/a/54818023/2655092
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### Shared Preferences 업데이트```javascript
function notifyNewSharedPreference() {
  Java.use('android.app.SharedPreferencesImpl$EditorImpl').putString.overload('java.lang.String', 'java.lang.String').implementation = function(k, v) {
    console.log('[SharedPreferencesImpl]', k, '=', v);
    return this.putString(k, v);
  }
}
출력 예시 TODO


⬆ 맨 위로

훅 오버로드```javascript

function hookOverloads(className, func) { var clazz = Java.use(className); var overloads = clazz[func].overloads; for (var i in overloads) { if (overloads[i].hasOwnProperty('argumentTypes') || overloads[i]['argumentTypes'] != undefined) { var parameters = [];

root@kitploit:~
  var curArgumentTypes = overloads[i].argumentTypes, args = [], argLog = '[';
  for (var j in curArgumentTypes) {
    var cName = curArgumentTypes[j].className;
    parameters.push(cName);
    argLog += "'(" + cName + ") ' + v" + j + ",";
    args.push('v' + j);
  }
  argLog += ']';

  var script = "var ret = this." + func + '(' + args.join(',') + ") || '';\n"
    + "console.log(JSON.stringify(" + argLog + "));\n"
    + "return ret;"

  args.push(script);
  clazz[func].overload.apply(this, parameters).implementation = Function.apply(null, args);
}

} }

Java.perform(function() { hookOverloads('java.lang.StringBuilder', '$init'); })

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)


#### 브로드캐스트 리시버 등록```javascript
Java.perform(() => {
    const MyBroadcastReceiver = Java.registerClass({
        name: 'MyBroadcastReceiver',
        superClass: Java.use('android.content.BroadcastReceiver'),
        methods: {
            onReceive: [{
                returnType: 'void',
                argumentTypes: ['android.content.Context', 'android.content.Intent'],
                implementation: function(context, intent) {
                    // ..
                }
            }]
        },
    });
    let ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
    ctx.registerReceiver(MyBroadcastReceiver.$new(), Java.use('android.content.IntentFilter').$new('com.example.JAVA_TO_AGENT'));
});
출력 예제 TODO


⬆ 맨 위로

인터페이스를 구현하는 클래스 목록```js

function listClassesImplementsInterface(aInterface) { let classLoaders = Java.enumerateClassLoadersSync() Java.enumerateLoadedClassesSync().forEach(className => { for (let i = 0; i < classLoaders.length; i++) { let classLoader = classLoaders[i] Java.classFactory.loader = classLoader try { let jclass = Java.use(className).class let ifaces = jclass.getInterfaces().toString() jclass = null if (ifaces.indexOf(aInterface) != -1) { console.log(JSON.stringify({ name: className, loader: classLoader.toString(), interfaces: ifaces })) break // we found one ClassLoader, that's enough } } catch (e) { // continue to next ClassLoader } } }) }

root@kitploit:~
<br>[⬆ 맨 위로](#table-of-contents)


#### 단계 수 증가```js
Java.perform(() => {
  var customSensorEventListener = null;
  var curSteps = 0;
  var totalNumberOfRequiredSteps = 10000;

  function incSteps() {
    Java.perform(() => {
      var sEvent = Java.use('android.hardware.SensorEvent').$new(1);
      sEvent.values.values = Java.array('float', [curSteps]); // https://developer.android.com/reference/android/hardware/SensorEvent#values
      sEvent.timestamp = Java.use('java.lang.Long').$new(Java.use('java.lang.System').nanoTime());
      sEvent.accuracy = Java.use('java.lang.Integer').$new(3); // https://developer.android.com/reference/android/hardware/SensorManager#SENSOR_STATUS_ACCURACY_HIGH
      customSensorEventListener.onSensorChanged(sEvent);
      
      if (curSteps < totalNumberOfRequiredSteps) {
        setTimeout(() => {
          curSteps += 50;
          incSteps();
        }, 1500)
      }
    });
  }

  Java.choose('.CustomSensorEventListener', {  // class that implements SensorEventListener
    onMatch: function (instance) {
      customSensorEventListener = instance;
    },
    onComplete: function () {
      incSteps();
    }
  });
});
출력 예시 TODO


⬆ 맨 위로

OS 로그```js

var m = 'libsystem_trace.dylib'; // bool os_log_type_enabled(os_log_t oslog, os_log_type_t type); var isEnabledFunc = Module.findExportByName(m, 'os_log_type_enabled'); // _os_log_impl(void *dso, os_log_t log, os_log_type_t type, const char *format, uint8_t *buf, unsigned int size); var logFunc = Module.findExportByName(m, '_os_log_impl');

// Enable all logs Interceptor.attach(isEnabledFunc, { onLeave: function (ret) { ret.replace(0x1); } });

Interceptor.attach(logFunc, { onEnter: function (a) { /* OS_ENUM(os_log_type, uint8_t, OS_LOG_TYPE_DEFAULT = 0x00, OS_LOG_TYPE_INFO = 0x01, OS_LOG_TYPE_DEBUG = 0x02, OS_LOG_TYPE_ERROR = 0x10, OS_LOG_TYPE_FAULT = 0x11); */ var type = a[2]; var format = a[3]; if (type !== 0x2) { console.log(JSON.stringify({ type: type, format: format.readCString(), //buf: a[4].readPointer().readCString() // TODO }, null, 2)); } } })

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)



#### iOS 알림 상자```js
var UIAlertController = ObjC.classes.UIAlertController;
var UIAlertAction = ObjC.classes.UIAlertAction;
var UIApplication = ObjC.classes.UIApplication;
var handler = new ObjC.Block({ retType: 'void', argTypes: ['object'], implementation: function () {} });

ObjC.schedule(ObjC.mainQueue, function () {
  var alert = UIAlertController.alertControllerWithTitle_message_preferredStyle_('Frida', 'Hello from Frida', 1);
  var defaultAction = UIAlertAction.actionWithTitle_style_handler_('OK', 0, handler);
  alert.addAction_(defaultAction);
  // Instead of using `ObjC.choose()` and looking for UIViewController instances on the heap, we have direct access through UIApplication:
  UIApplication.sharedApplication().keyWindow().rootViewController().presentViewController_animated_completion_(alert, true, NULL);
})
출력 예시 TODO


⬆ 맨 위로

파일 접근

각 파일 열기를 기록```js Interceptor.attach(ObjC.classes.NSFileManager['- fileExistsAtPath:'].implementation, { onEnter: function (args) { console.log('open' , ObjC.Object(args[2]).toString()); } });

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### Observe 클래스```js
function observeClass(name) {
    var k = ObjC.classes[name];
    k.$ownMethods.forEach(function(m) {
        var impl = k[m].implementation;
        console.log('Observing ' + name + ' ' + m);
        Interceptor.attach(impl, {
            onEnter: function(a) {
                this.log = [];
                this.log.push('(' + a[0] + ',' + Memory.readUtf8String(a[1]) + ') ' + name + ' ' + m);
                if (m.indexOf(':') !== -1) {
                    var params = m.split(':');
                    params[0] = params[0].split(' ')[1];
                    for (var i = 0; i < params.length - 1; i++) {
                        try {
                            this.log.push(params[i] + ': ' + new ObjC.Object(a[2 + i]).toString());
                        } catch (e) {
                            this.log.push(params[i] + ': ' + a[2 + i].toString());
                        }
                    }
                }

                this.log.push(
                    Thread.backtrace(this.context, Backtracer.ACCURATE)
                        .map(DebugSymbol.fromAddress)
                        .join('\n')
                );
            },

            onLeave: function(r) {
                try {
                    this.log.push('RET: ' + new ObjC.Object(r).toString());
                } catch (e) {
                    this.log.push('RET: ' + r.toString());
                }

                console.log(this.log.join('\n') + '\n');
            }
        });
    });
}
출력 예시

`observeClass('Someclass$innerClass');```` Observing Someclass$innerClass - func Observing Someclass$innerClass - empty (0x174670040,parameterName) Someclass$innerClass - func 0x10048dd6c libfoo!0x3bdd6c 0x1005a5dd0 libfoo!0x4d5dd0 0x1832151c0 libdispatch.dylib!_dispatch_client_callout 0x183215fb4 libdispatch.dylib!dispatch_once_f RET: 0xabcdef

root@kitploit:~
</details>

<br>[⬆ Back to top](#table-of-contents)


#### iOS 애플리케이션 UUID 찾기 

앱에 연결되면 각 앱 컨테이너 아래의 plist 파일을 읽어 특정 경로의 UUID를 가져옵니다.```js
var PLACEHOLDER = '{UUID}';
function extractUUIDfromPath(path) {
    var bundleIdentifier = String(ObjC.classes.NSBundle.mainBundle().objectForInfoDictionaryKey_('CFBundleIdentifier'));
    var path_prefix = path.substr(0, path.indexOf(PLACEHOLDER));
    var plist_metadata = '/.com.apple.mobile_container_manager.metadata.plist';
    var errorPtr = Memory.alloc(Process.pointerSize); 
    Memory.writePointer(errorPtr, NULL); 
    var folders = ObjC.classes.NSFileManager.defaultManager().contentsOfDirectoryAtPath_error_(path_prefix, errorPtr);
    var error = Memory.readPointer(errorPtr);
    if (errorPtr) 
    	console.error( new ObjC.Object( error ) );
    for (var i = 0, l = folders.count(); i < l; i++) {
        var uuid = folders.objectAtIndex_(i);
        var metadata = path_prefix + uuid + plist_metadata;
        var dict = ObjC.classes.NSMutableDictionary.alloc().initWithContentsOfFile_(metadata);
        var enumerator = dict.keyEnumerator();
        var key;
        while ((key = enumerator.nextObject()) !== null) {
            if (key == 'MCMMetadataIdentifier') {
                var appId = String(dict.objectForKey_(key));
                if (appId.indexOf(bundleIdentifier) != -1) {
                    return path.replace(PLACEHOLDER, uuid);
                }
            }
        }
    }
}
console.log( extractUUIDfromPath('/var/mobile/Containers/Data/Application/' + PLACEHOLDER + '/Documents') );


⬆ Back to top

클래스 멤버 설명

각 클래스 인스턴스에 대한 멤버 맵(값 포함)을 출력합니다.```js ObjC.choose(ObjC.classes[clazz], { onMatch: function (obj) { console.log('onMatch: ', obj); Object.keys(obj.$ivars).forEach(function(v) { console.log('\t', v, '=', obj.$ivars[v]); }); }, onComplete: function () { console.log('onComplete', arguments.length); } });

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO	
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### 클래스 계층 구조

Object.keys(ObjC.classes)는 사용 가능한 모든 Objective C 클래스를 나열하지만,
실제로는 현재 프로세스에 로드된 모든 클래스(시스템 프레임워크 포함)를 반환합니다.
weak_classdump처럼 실행 파일 자체의 클래스만 나열하려면, Objective C 런타임에 이미 그러한 함수가 제공됩니다 [objc_copyClassNamesForImage](#https://developer.apple.com/documentation/objectivec/1418485-objc_copyclassnamesforimage?language=objc)```js
var objc_copyClassNamesForImage = new NativeFunction(
    Module.findExportByName(null, 'objc_copyClassNamesForImage'),
    'pointer',
    ['pointer', 'pointer']
);
var free = new NativeFunction(Module.findExportByName(null, 'free'), 'void', ['pointer']);
var classes = new Array(count);
var p = Memory.alloc(Process.pointerSize);

Memory.writeUInt(p, 0);

var path = ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String();
var pPath = Memory.allocUtf8String(path);
var pClasses = objc_copyClassNamesForImage(pPath, p);
var count = Memory.readUInt(p);
for (var i = 0; i < count; i++) {
    var pClassName = Memory.readPointer(pClasses.add(i * Process.pointerSize));
    classes[i] = Memory.readUtf8String(pClassName);
}

free(pClasses);

var tree = {};
classes.forEach(function(name) {
    var clazz = ObjC.classes[name];
    var chain = [name];
    while (clazz = clazz.$superClass) {
        chain.unshift(clazz.$className);
    }

    var node = tree;
    chain.forEach(function(clazz) {
        node[clazz] = node[clazz] || {};
        node = node[clazz];
    });
});

send(tree);
출력 예시 TODO


⬆ 맨 위로

Hook 리플렉션

objc_msgSend 후킹```py import frida, sys

f = open('/tmp/log', 'w')

def on_message(msg, _data): f.write(msg['payload']+'\n')

frida_script = """ Interceptor.attach(Module.findExportByName('/usr/lib/libobjc.A.dylib', 'objc_msgSend'), { onEnter: function(args) { var m = Memory.readCString(args[1]); if (m != 'length' && !m.startsWith('_fastC')) send(m); } }); """ device = frida.get_usb_device() pid = device.spawn(["com.example"]) # or .get_frontmost_application() session = device.attach(pid) script = session.create_script(frida_script) script.on('message', on_message) script.load() device.resume(pid) sys.stdin.read()

root@kitploit:~
```sh
$ sort /tmp/log | uniq -c | sort -n
출력 예시 TODO


⬆ 맨 위로

전체 모듈 인터셉트

UI 관련 기능을 줄이기 위해 다음 단계를 사용합니다:

  1. -o /tmp/log1을 사용하여 로그를 파일로 출력합니다
  2. $ sort /tmp/log1 | uniq -c | sort -rn | head -n20 | cut -d# -f2 | paste -sd "," -을 사용하여 MRU를 excludesList에 복사합니다```js var mName = 'MyModule', excludeList = ['Alot', 'Of', 'UI', 'Related', 'Functions']; Module.enumerateExportsSync(mName) .filter(function(e) { var fromTypeFunction = e.type == 'function';· var notInExcludes = excludeList.indexOf(e.name) == -1; return fromTypeFunction && notInExcludes; }) .forEach(function(e) { Interceptor.attach(Module.findExportByName(mName, e.name), { onEnter: function(args) { console.log(mName + "#'" + e.name + "'"); } }) })
root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO	
</details>

<br>[⬆ 맨 위로](#table-of-contents)



#### 메모리 세그먼트 덤프```js
Process.enumerateRanges('rw-', {
	onMatch: function (range) {
		var fname = `/sdcard/${range.base}_dump`;
		var f = new File(fname, 'wb');
		f.write(instance.base.readByteArray(instance.size));
		f.flush();
		f.close();
		console.log(`base=${range.base} size=${range.size} prot=${range.protection} fname=${fname}`);
	},
	onComplete: function () {}
});
출력 예시 TODO


⬆ 맨 위로

메모리 스캔```js

function memscan(str) { Process.enumerateModulesSync().filter(m => m.path.startsWith('/data')).forEach(m => { var pattern = str.split('').map(letter => letter.charCodeAt(0).toString(16)).join(' '); try { var res = Memory.scanSync(m.base, m.size, pattern); if (res.length > 0) console.log(JSON.stringify({m, res})); } catch (e) { console.warn(e); } }); }

root@kitploit:~
httpx의 소스 코드를 탐색하거나 문제를 보고하거나 지속적인 개발에 기여하려면 [GitHub 리포지토리](https://github.com/projectdiscovery/httpx)를 방문하세요. 고급 사용법, 지원되는 프로브, 실제 통합 예제를 다루는 포괄적인 문서는 [공식 httpx 문서](https://docs.projectdiscovery.io/tools/httpx/overview)에서 확인하세요.

---

BLE-Security-Attack-Defense를 사용하면 Bluetooth Low Energy(BLE) 트래픽을 손쉽게 가로채고 분석하며 수정할 수 있습니다. 이 다목적 프레임워크는 BLE 보안 연구 및 테스트를 위해 설계되었습니다. 이 도구는 공격적```js
var memscn = function (str) {
	Process.enumerateModulesSync().forEach(function (m) {
		var pattern = str.split('').map(function (l) { return l.charCodeAt(0).toString(16) }).join(' ');
		try {
			var res = Memory.scanSync(m.base, m.size, pattern);
			if (res.length > 0)
				console.log(JSON.stringify({m, res}, null , 2));
		} catch (e) {
			console.warn(e);
		}
	});
}
출력 예시 pattern [ 52 41 4e 44 4f 4d ] { "name": "Test", "base": "0x1048fc000", "size": 147000, "path": "/var/containers/Bundle/Application/CD74EB00-9D90-4600-BF5D-F6E5E0CDF878/Test.app/Test" } [{"address":"0x10491f211","size":6}]


⬆ 맨 위로

Stalker```js

var _module = Process.findModuleByName('myModule'); var base = ptr(_module.base); var startTraceOffset = 0xabcd1234, numInstructionsToTrace = 50; var startTrace = base.add(startTraceOffset), endTrace = startTrace.add(4 * (numInstructionsToTrace - 1));

Interceptor.attach(ObjC.classes.CustomClass['- func'].implementation, { onEnter: function (args) { var tid = Process.getCurrentThreadId(); this.tid = tid; console.warn(onEnter [ ${tid} ]);
Stalker.follow(tid, { transform: function (iterator) { var instruction; while ((instruction = iterator.next()) !== null) { // condition to putCallout if (instruction.address <= endTrace && instruction.address >= startTrace) {
// print instruction & registers values iterator.putCallout(function(context) { var offset = ptr(context.pc).sub(base); var inst = Instruction.parse(context.pc).toString(); var modified_inst = inst; inst.replace(/,/g, '').split(' ').forEach(op => { if (op.startsWith('x')) modified_inst = modified_inst.replace(op, context[op]); else if (op.startsWith('w')) modified_inst = modified_inst.replace(op, context[op.replace('w', 'x')]); }); modified_inst = '\x1b[35;01m' + modified_inst + '\x1b[0m'; console.log(x8=${context.x8} x25=${context.x25} x0=${context.x0} x21=${context.x21}) console.log(${offset} ${inst} # ${modified_inst}); }); } iterator.keep(); } } }) },
onLeave: function (retval) { console.log(onLeave [ ${this.tid} ]); // cleanup Stalker.unfollow(this.tid); Stalker.garbageCollect(); }
})

root@kitploit:~
<details>
<summary>출력 예시</summary>
mul x5, x2, x21 # mul 0x3, 0x4, 0x5
</details>

<br>[⬆ 맨 위로](#table-of-contents)






#### Cpp 디맹글러```sh
$ npm i frida-compile demangler-js -g

스크립트에 추가하세요```js const demangle = require('demangler-js').demangle; ... Module.enumerateExportsSync('library.so') .filter(x => x.name.startsWith('_Z')) .forEach(x => { Interceptor.attach(x.address, { onEnter: function (args) { console.log('[-] ' + demangle(x.name)); } }); });

root@kitploit:~
컴파일```sh
$ frida-compile script.js -o out.js

run```sh $ frida -Uf com.app -l out.js

root@kitploit:~
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)


#### 초기 훅

DT_INIT_ARRAY 전에 훅을 설정합니다 ( [소스](https://cs.android.com/android/platform/superproject/+/master:bionic/linker/linker_soinfo.cpp;l=386;drc=android-8.0.0_r1?q=call_constructor&ss=android%2Fplatform%2Fsuperproject) )```js
let base;
let do_dlopen = null;
let call_ctor = null;
const target_lib_name = 'targetlib.so';

Process.findModuleByName('linker64').enumerateSymbols().forEach(sym => {
    if (sym.name.indexOf('do_dlopen') >= 0) {
        do_dlopen = sym.address;
    } else if (sym.name.indexOf('call_constructor') >= 0) {
        call_ctor = sym.address;
    }
})

Interceptor.attach(do_dlopen, function (args) {
    if (args[0].readUtf8String().indexOf(target_lib_name) >= 0) {
        Interceptor.attach(call_ctor, function () {
            const module = Process.findModuleByName(target_lib_name);
            base = module.base;
            console.log('loading', target_lib_name, '- base @', base);
	    
	    // DoStuff
        })
    }
})

크레딧: iGio90

출력 예시 TODO


⬆ 맨 위로

기기 속성

대충 빠르게 구현한 iOS 기기 속성 추출 예시```js var UIDevice = ObjC.classes.UIDevice.currentDevice(); UIDevice.$ownMethods .filter(function(method) { return method.indexOf(':') == -1 /* filter out methods with parameters / && method.indexOf('+') == -1 / filter out public methods */ }) .forEach(function(method) { console.log(method, ':', UIDevicemethod) }) console.log('executablePath =', ObjC.classes.NSBundle.mainBundle().executablePath().toString());

root@kitploit:~
`pwn` - CTF에서 사용되는 패딩 생성기 및 고급 ROP 페이로드 생성기.

기능:

- 패딩 생성: 특정 길이 또는 특정 문자를 포함하는 패딩을 생성합니다.
- 페이로드 생성: `ret2win`, `ret2shellcode`, `ret2libc`, `ret2csu`, `ret2dlresolve`, `ret2syscall`, `srop` 공격에 대한 고급 ROP 페이로드를 생성합니다.
- 보호 기능 확인: ELF 바이너리에서 활성화된 보호 기능을 표시합니다.
- 가젯 검색: 바이너리에서 ROP 가젯을 검색합니다.

사용법: pwn [옵션] <바이너리>

인자: 바이너리 대상 바이너리

옵션: -h, --help 도움말 메시지를 표시하고 종료합니다. -v, --version 프로그램 버전을 표시하고 종료합니다. -p, --padding 패딩 생성 (기본값: 100) -f, --format 패딩 형식 (기본값: 'A') -o, --offset 오프셋 계산 -r, --rop ROP 페이로드 생성 -g, --gadget ROP 가젯 검색 -c, --checksec 바이너리 보호 기능 확인

root@kitploit:~
if (ObjC.available) { 
	var processInfo = ObjC.classes.NSProcessInfo.processInfo();
	var versionString = processInfo.operatingSystemVersionString().toString();
	// E.g. "Version 13.5 (Build 17F75)"
	var ver = versionString.split(' ');
	var version = ver[1];
	// E.g. 13.5
	console.log("iOS version: " + version);  
}
```
<details>
<summary>출력 예시</summary>```
- adjTrackingEnabled : true
- adjFbAttributionId : 
- adjVendorId : 4AAAAAAA-CECC-4BBB-BDDD-DEEEEEEEED18
- adjDeviceType : iPhone
- adjDeviceName : iPhone8,2
- adjCreateUuid : dfaaaa2-ebbd-4ccc-addd-eaeeeeeeee7c
- adjIdForAdvertisers : 7AAAAA3A-4BBB-4CCC-BDDD-0EEEEEEEE8A6
- sbf_bannerGraphicsQuality : 100 
- sbf_controlCenterGraphicsQuality : 100 
- sbf_homeScreenFolderGraphicsQuality : 100 
- sbf_searchTransitionGraphicsQuality : 100 
- sbf_dashBoardPresentationGraphicsQuality : 100 
- sbf_homeScreenBlurGraphicsQuality : 100 
- userInterfaceIdiom : 0 
- _supportsDeepColor : false
- name : iPhone
- _keyboardGraphicsQuality : 100 
- isGeneratingDeviceOrientationNotifications : true
- orientation : 1 
- _backlightLevel : 1 
- isProximityMonitoringEnabled : false
- systemVersion : 11.1.1
- _graphicsQuality : 100 
- beginGeneratingDeviceOrientationNotifications : undefined
- endGeneratingDeviceOrientationNotifications : undefined
- buildVersion : 15C222
- systemName : iOS 
- _isSystemSoundEnabled : true
- _feedbackSupportLevel : 1 
- model : iPhone
- _supportsForceTouch : true
- localizedModel : iPhone
- identifierForVendor : 4A7B44DB-AAAA-BBB-CCC-D8819581DDD
- isBatteryMonitoringEnabled : false
- batteryState : 0 
- batteryLevel : -1
- proximityState : false
- isMultitaskingSupported : true
- playInputClick : undefined
- _softwareDimmingAlpha : 0 
- _playInputSelectSound : undefined
- _playInputDeleteSound : undefined
- _hasGraphicsQualityOverride : false
- _hasTouchPad : false
- _clearGraphicsQualityOverride : undefined
- _predictionGraphicsQuality : 100 
- _nativeScreenGamut : 0 
- _tapticEngine : <_UITapticEngine: 0x1c06257c0>
```
</details>

<br>[⬆ 맨 위로](#table-of-contents)


#### 스크린샷 찍기```js
function screenshot() {
  ObjC.schedule(ObjC.mainQueue, function() {
    var getNativeFunction = function (ex, retVal, args) {
      return new NativeFunction(Module.findExportByName('UIKit', ex), retVal, args);
    };
    var api = {
      UIWindow: ObjC.classes.UIWindow,
      UIGraphicsBeginImageContextWithOptions: getNativeFunction('UIGraphicsBeginImageContextWithOptions', 'void', [['double', 'double'], 'bool', 'double']),
      UIGraphicsBeginImageContextWithOptions: getNativeFunction('UIGraphicsBeginImageContextWithOptions', 'void', [['double', 'double'], 'bool', 'double']),
      UIGraphicsEndImageContext: getNativeFunction('UIGraphicsEndImageContext', 'void', []),
      UIGraphicsGetImageFromCurrentImageContext: getNativeFunction('UIGraphicsGetImageFromCurrentImageContext', 'pointer', []),
      UIImagePNGRepresentation: getNativeFunction('UIImagePNGRepresentation', 'pointer', ['pointer'])
    };
    var view = api.UIWindow.keyWindow();
    var bounds = view.bounds();
    var size = bounds[1];
    api.UIGraphicsBeginImageContextWithOptions(size, 0, 0);
    view.drawViewHierarchyInRect_afterScreenUpdates_(bounds, true);

    var image = api.UIGraphicsGetImageFromCurrentImageContext();
    api.UIGraphicsEndImageContext();

    var png = new ObjC.Object(api.UIImagePNGRepresentation(image));
    send('screenshot', Memory.readByteArray(png.bytes(), png.length()));
  });
}

rpc.exports = {
  takescreenshot: screenshot
}
```
**최신 업데이트:**

- 특정 주요 브라우저를 스크래핑하여 오류 메시지를 생성하기 위해 제가 처음 작성한 것 중 하나입니다.
- 이 모듈은 기본적으로 도구에 필요한 모든 종류의 것들을 가져오기 위한 새 함수를 생성합니다.
- :warning: 때때로 버전 등에 따라 둘 다 약 2~5% 정도의 변동이 있으므로, 오차 범위라고 부르겠습니다.
- 가짜 메시지를 만들기 위해 실제 데이터를 얻을 수 없는 경우, 대체 헤더인 `sec-` 및 `proxy-`를 사용하여 공백을 메웁니다.
- 이들은 딕셔너리로 전송되므로, 값과 가격이 설정된 것들을 정리해야 합니다.```py
...
def save_screenshot(d):
    f = open('/tmp/screenshot.png', 'wb')
    f.write(d)
    f.close()

def on_message(msg, data):
    save_screenshot(data)
 
 script.exports.takescreenshot()
 
 # open screenshot & invoke rpc via input 
 # <Ctrl+C> will take screenshot, open it with eog & wait for export function name to invoke via input
 def on_message(msg, data):
    if 'payload' in msg:
        if msg['payload'] == 'screenshot':
            i = '/tmp/screenshot.png'
            f = open(i, 'wb')
            f.write(data)
            f.close()
            subprocess.call(['eog', i])
	   
 while True:
    try:
        time.sleep(1)
    except KeyboardInterrupt:
        script.exports.takescreenshot()
        try:
            getattr(script.exports, input())()
        except (KeyboardInterrupt, frida.core.RPCException) as e:
            print('[!]', e)

```
<details>
<summary>출력 예시</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)


#### SSH 명령 로깅```js
Interceptor.attach(ObjC.classes.NMSSHChannel['- execute:error:timeout:'].implementation, {  
  onEnter: function(args) {  
    this.cmd = ObjC.Object(args[2]).toString();
    this.timeout = args[4];
  }, 
  onLeave: function(retv) {  
    console.log(`CMD: ${ObjC.Object(args[2]).toString()} Timeout: ${args[4]} Ret: ${retv}`);
  }  
}); 
```
<details>
<summary>출력 예제</summary>
TODO
</details>

<br>[⬆ 맨 위로](#table-of-contents)

#### 할 일 
- GIF 및 예제 추가
- /scripts에 링크 추가
- 범용 SSL unpinning 확장 대상: [ios](https://codeshare.frida.re/@dki/ios10-ssl-bypass/) [andoid 1](https://github.com/Fuzion24/JustTrustMe/blob/master/app/src/main/java/just/trust/me/Main.java) [android
도구 다운로드
  • 모든 런타임 문자열 및 스택 트레이스 출력
  • SharedPreferences 업데이트 출력
  • 문자열 비교
  • 주소로 JNI 후크
  • 생성자 후크
  • Java reflection 후크
  • 클래스 추적
  • Unity3d 후킹
  • Android ID 가져오기
  • 위치 변경
  • FLAG_SECURE 우회
  • SharedPreferences 업데이트
  • 모든 메서드 오버로드 후크
  • 브로드캐스트 수신자 등록
  • 걸음 수 증가
  • 클래스 로더로 인터페이스를 구현하는 클래스 나열
  • 파일 시스템 접근 후크 $ frida --codeshare FrenchYeti/android-file-system-access-hook -f com.example.app --no-pause
  • Java 후크를 제거/비활성화하는 방법? implementation 속성에 null을 할당하세요.

  • ⬆ Back to top

    CPP 모듈 로드```cpp

    #include #include

    extern "C" { void* create_stdstr(char data, int size) { std::string s = new std::string(); (*s).assign(data, size); return s; } }

    root@kitploit:~
    ### 사용하지 않는 환경 변수를 탐지, 표시, 보호하여 보안 강화```sh
    $ ./android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++ a.cpp -o a -shared -static-libstdc++ && adb push a /data/local/tmp/a
    

    번역할 Markdown 콘텐츠가 제공되지 않았습니다.```js [device]-> function readStdString(str) { if ((str.readU8() & 1) === 1) { // size LSB (=1) indicates if it's a long string return str.add(2 * Process.pointerSize).readPointer().readUtf8String();
    } return str.add(1).readUtf8String();
    } [device]-> Module.load('/data/local/tmp/a'); [device]-> var fp_create_stdstr = Module.findExportByName('a', 'create_stdstr'); [device]-> var createStdString = new NativeFunction(fp_create_stdstr, 'pointer', ['pointer', 'int']); [device]-> var stdstr1 = createStdString(Memory.allocUtf8String("abcd"), 3); "0x07691234567" [device]-> readStdString(stdstr1); "abc"

    root@kitploit:~
    #### C 모듈 로드
    
    * https://frida.re/docs/javascript-api/#cmodule
    * https://frida.re/news/2019/09/18/frida-12-7-released/```sh
    $ ./aarch64-linux-android21-clang /tmp/b.c -o /tmp/a -shared ../sysroot/usr/lib/aarch64-linux-android/21/liblog.so && adb push /tmp/a /data/local/tmp/a
    

    I don't see any content to translate — the input after "INPUT:" is empty. Please provide chunk 13 of 166 and I'll translate it into Korean.```c #include <stdio.h> #include <stdlib.h> #include <android/log.h>

    #define TAG "TEST1" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, VA_ARGS) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, VA_ARGS)

    void test(void) { FILE* fp = popen("ls -l /sdcard 2>&1", "r"); if (fp == NULL) LOGE("executing cmd failed"); char b[256]; while (fgets(b, sizeof(b), fp) != NULL) { LOGI("%s", b); } pclose(fp); }

    root@kitploit:~
    The input chunk is empty — no source text was provided to translate.```sh
    $ frida -Uf com.app --no-pause --enable-jit -e "Module.load('/data/local/tmp/a')"
    [ ] -> new NativeFunction(Module.findExportByName('a', 'test'), 'void', [])()
    


    ⬆ Back to top

    일회성 워치포인트

    funcPtr를 가로채서 mprotect로 권한을 제거해 x2에 읽기/쓰기를 수행한 대상을 기록합니다.```js Process.setExceptionHandler(function(exp) { console.warn(JSON.stringify(Object.assign(exp, { _lr: DebugSymbol.fromAddress(exp.context.lr), _pc: DebugSymbol.fromAddress(exp.context.pc) }), null, 2)); Memory.protect(exp.memory.address, Process.pointerSize, 'rw-'); // can also use new NativeFunction(Module.findExportByName(null, 'mprotect'), 'int', ['pointer', 'uint', 'int'])(parseInt(this.context.x2), 2, 0) return true; // goto PC });

    Interceptor.attach(funcPtr, { onEnter: function (args) { console.log('onEnter', JSON.stringify({ x2: this.context.x2, mprotect_ret: Memory.protect(this.context.x2, 2, '---'), errno: this.errno }, null, 2)); }, onLeave: function (retval) { console.log('onLeave'); } });

    root@kitploit:~
    <details>
    <summary>출력 예시</summary>```
    [iOS Device::com.app]-> onEnter {
      "x2": "0x1c145c6e0",
      "mprotect_ret": true,
      "errno": 2
    }
    {
      "type": "access-violation",
      "address": "0x1853b0198",
      "memory": {
        "operation": "read",
        "address": "0x1c145c6e0"
      },
      "context": {
        "lr": "0x100453358",
        "fp": "0x16fb2e860",
        "x28": "0x0",
        "x27": "0x0",
        "x26": "0x104312600",
        "x25": "0x0",
        "x24": "0x0",
        "x23": "0x0",
        "x22": "0x0",
        "x21": "0xb000000422bbda03",
        "x20": "0x1c4a22560",
        "x19": "0xb000000422bbda03",
        "x18": "0x0",
        "x17": "0x100d25290",
        "x16": "0x1853b0190",
        "x15": "0x0",
        "x14": "0x5",
        "x13": "0xe5a1c4119597",
        "x12": "0x10e80ca30",
        "x11": "0x180000003f",
        "x10": "0x10e80ca00",
        "x9": "0x1020ad7c3",
        "x8": "0x0",
        "x7": "0x0",
        "x6": "0x0",
        "x5": "0x0",
        "x4": "0xb000000422bbda03",
        "x3": "0x1c4a22560",
        "x2": "0x1c145c6e0",
        "x1": "0x1020ad7c3",
        "x0": "0x1c145c6e0",
        "sp": "0x16fb2e790",
        "pc": "0x1853b0198"
      },
      "nativeContext": "0x16fc42b24"
    }
    onLeave
    
    출력 예시 TODO


    ⬆ 맨 위로 돌아가기

    쿠키 추출```js

    var cookieJar = {}; var cookies = ObjC.classes.NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies(); for (var i = 0, l = cookies.count(); i < l; i++) { var cookie = cookies'- objectAtIndex:'; cookieJar[cookie.Name()] = cookie.Value().toString(); // "- expiresDate".toString() } console.log(JSON.stringify(cookieJar, null, 2));

    root@kitploit:~
    <details>
    <summary>출력 예시</summary>```js
    {
      "key1": "value 1",
      "key2": "value 2"
    }