MainActivity에서 프리다 탐지 로직을 로드 하고 있다.
음 소스코드가 되게 짧다.
Android Developer에 검색해보자.
https://developer.android.com/reference/java/lang/System#loadLibrary(java.lang.String)
System | Android Developers
developer.android.com
그으래요..... native library를 로드한다는 건 알겠는데... 사용법을 좀 검색해보자.
역시 킹갓 제너럴 형님들의 포스팅을 봐보자.
https://re-build.tistory.com/7
[Android] 안드로이드 스튜디오에서 JNI 사용하기
이번 포스팅은 제가 이번에 프로젝트를 진행하면서 JNI를 사용해야 할 상황이 생겨 구현하면서, 알게 된 것들을 기록하는 목적으로 작성합니다. JNI?JNI란 Java Native Interface의 약자로서, 자바 외의
re-build.tistory.com
System.loadLibrary(...) couldn't find native library in my case
I want to use a existing native library from another Android project, so I just copied the NDK built library (libcalculate.so) to my new Android project. In my new Android project I created a folde...
stackoverflow.com
음 대충 C, C++ 같은 네이티브 언어를 사용할 수 있고, 패키지 안에 존재해야하는 것 같다. 그럼 apk를 압축해제해서 'frida-check'파일을 검색해보자.
음....근데 파일이 4개네. 이중에 뭐지. 검색해보자.
https://codechacha.com/ko/support-64-bit-app-in-android/
안드로이드 앱이 32/64bit 기기에서 동작하도록 만들기
최근 구글 플레이스토어는 64비트를 지원하는 앱만 등록되도록 정책을 변경하였습니다. Analyze APK를 이용하여 앱이 32 또는 64비트를 지원하는지 확인하고, 64비트를 지원할 수 있게 만드는 방법을
codechacha.com
역시 킹갓 제너럴 형님들은 다 알고 계신다. 아래의 명령어로 디바이스 지원 아키텍처를 알아보자.
# getprop ro.product.cpu.abilist
분석은 IDA, ghidra를 사용해서 하면된다. ghidra는 무료다. 나는 IDA를 사용하긴 하는데 ghidra를 사용하는 사람들 보면 뭔가 멋있다. ghidra로 도저어어어어어어언.
근데 사용법을 잘 모른다.
https://www.varonis.com/blog/how-to-use-ghidra
How to Use Ghidra to Reverse Engineer Malware | Varonis
An overview of the malware analysis tool Ghidra. This article covers how to install and navigate the Ghidra interface.
www.varonis.com
libfrida-check.so 파일을 ghidra로 로드시키고 위에서 알려준대로 'Symbol Tree'를 봐보자. 확실히 해당 파일이 import된 모듈과 export 된 함수들이 보인다. 이 파일의 목적은 특정 기능을 export 해서 프리다라는 도구를 체크하는 것이 목적일터...
'Exports' 탭에서 제일 길고 수상한 메소드에 접근해보자.
음... 주로 보이는 함수가.... socket, inet_pton, connect 함수들이 보인다.
https://blockdmask.tistory.com/212
[이론] socket() 함수에 대해서
안녕하세요. BlockDMask 입니다. 오늘은 socket() 함수에 대해서 알아보겠습니다. 이전 글 2017/11/03 - [/[TCP/IP 소켓]] - [이론] 서버와 클라이언트 소켓의 흐름 에서 흐름을 보셨다면 아시겠지만 서버와
blockdmask.tistory.com
https://techlog.gurucat.net/317
[네트워크/C reference] inet_pton 함수
기능 요약 (Summary)inet_pton( ) 함수는 사람이 알아보기 쉬운 텍스트(human-readable text)형태의 IPv4 와 IPv6 주소를 binary 형태로 변환 하는 기능을 한다. 헤더 (Header files)이 함수를 사용하려면 다음 헤더파
techlog.gurucat.net
connect(2) - 서버로 접속하기
connect(2) #include int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 서버의 주소(addr)로 접속하여 connection을 유지합니다. connect(2) 함수는 socket(2)의 type 설정시 SOCK_STREAM, SOCK_SEQPACKET 등으로 설정
www.it-note.kr
음.... 그래요......
그러니까 socket()을 뚫어주고, inet_pton()를 이용해서 "127.0.0.1"같은 주소를 binary의 형태로 변환 후, connect()함수로 연결 후 그 결과 값을 가지고 판단을 한다는 거네?
여기서 바로 프리다 코드로 넘어가도 되지만, 나는 솔루션이나 특정 의심 포인트를 찾았을 때 frida-trace로 1차적으로 돌려보는 편이다.
자... 그럼 정상적으로 찾은 함수들이 돌아가는 것도 알았고. connect, socket, inet_pton이 저기 libc.so 라는 것이 뭔지 좀 알아봐야겠다. 딱 봐도 android 공유 라이브러리 같은데. 형님들께 물어보자.
https://stackoverflow.com/questions/35329621/where-are-all-the-shared-libraries-stored-on-android
Where are all the shared libraries stored on android?
Where are all the shared libraries (.so) stored on Android? I was able to find the /system/lib directory but I'm sure there are more. Not being able to use the find command doesn't help either.
stackoverflow.com
껄껄껄껄껄. 찾음
libc.so 파일도 ghidra로 열어보쟈.
우선 핵심 트리거가 되는 포인트는 connect() 함수라는 것을 알겠다.
그럼 connect()함수를 후킹해보자.
function hook_libc_connect() {
var connect_addr = Module.getExportByName(null, "connect");
Interceptor.attach(connect_addr, {
onLeave (retval) {
console.log(retval);
retval.replace(-1);
}
})
}
근데..... 안타깝게도 이 방식은 실무에서 안먹힌다.
왜냐면 connect() 함수가 사용되는 곳은 리얼 정말 다양하다. 지금까지의 나는 특정 분기문이나 레지스터 변경을 통하여 우회를 해왔지만, 솔루션 우회 자동화 툴 제작을 목표로 하고 있는 나는 다른 방식이 필요하다.
여기서부터는 리얼 야생이다. 나도 처음하는 거임. ㅇㅇ 같이 ㄱㄱ
나는 한가지를 주목했다. 바로 connect() 함수의 2번째 파라미터이다. 해당 파라미터는 소켓의 구조체에 대한 포인터를 가지고 있다고 명시되어있다.
https://www.ibm.com/docs/en/zos/2.2.0?topic=functions-connect-connect-socket
connect() — Connect a socket
Standards Standards / Extensions C or C++ Dependencies XPG4.2 Single UNIX Specification, Version 3 both Format X/Open: #define _XOPEN_SOURCE_EXTENDED 1 #include int connect(int socket, const struct sockaddr *address, socklen_t address_len); Berkeley soc
www.ibm.com
우리 갓갓 형님께서 친절히 알려주셨다.
struct sockaddr - Address Family에 따른 구조체
struct sockaddr의 상세 유형 #include struct sockaddr { sa_family_t sa_family; char sa_data[14]; }; struct sockaddr 구조체는 socket 통신에서 사용하는 주소를 관리용 구조체로서 이 구조체를 직접사용하지 않고 Address Fam
www.it-note.kr
https://nroses-taek.tistory.com/20
connect 함수
Windows Version #include Linux Version #include #include Function Prototype int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); connect 함수는 연결 대기 중인 서버로 실제 연결을 맺는 함수이다. 소켓을 생성할
nroses-taek.tistory.com
https://jhnyang.tistory.com/261
[네트워크/소켓 C언어 프로그래밍] 주소 체계 저장 방법 sockaddr, sockaddr_in, sockaddr_in6 구조체 알아
안녕하세요!! 저번시간에는 가장 기초적인 서버/클라이언트 프로그램을 작성해보았어요. 전체적인 흐름을 잡는데는 이해가 되었을 거 같으나, 내부적으로 코드 한줄 한줄이 궁금한 사람이 있을
jhnyang.tistory.com
음.... 그렇다면 이제 구조체를 후킹하는 방법을 검색해보자..
https://stackoverflow.com/questions/73099271/how-can-i-hook-structure-members-in-frida
How can I hook structure members in frida
I have a code like this: class CURLNetRequest : public CNetRequestBase { DEFINE_LOGCLASS; struct ProxySettings { void initFromConfig(); String host; ...
stackoverflow.com
다시 검색.
https://poxyran.github.io/poxyblog/src/pages/02-11-2019-calling-native-functions-with-frida.html
Calling native functions with Frida
poxyran’s blog
poxyran.github.io
역시 킹갓 형님들은 국적을 가리지 않는다.
https://azurda.github.io/posts/reading-structs-frida/
AZURDA.386
We are able to read function arguments with FRIDA using the args:NativePointer[] array. However, this is not possible with arguments that are not simple types such as structs. Where can we find structs? We can find structs in the Unix time libraries for ex
azurda.github.io
위의 포스팅을 토대로 접근을 한번 해보려고한다. 어떤식으로 실제 구조체 형식이 뽑히는지 궁금해서 readByteArray를 통해 찍어보았다. 아.... 가히 아름다운 광경이 아닐수가 없다...
function hook_connect() {
var connect_addr_ptr = Module.getExportByName(null, 'connect');
var connect_addr = new NativeFunction(connect_addr_ptr, 'int', ['int', 'pointer', 'int']);
Interceptor.replace(connect_addr, new NativeCallback(function (fd, pointer, r) {
console.log(pointer.readShort()); // short sin_family;
console.log(pointer.add(2).readByteArray(2)); // u_short sin-port;
console.log(pointer.add(4).readByteArray(4)); // struct in_addr;
},'int', ['int','pointer','int']));
}
음 일단 후킹을 위해선 저 문자열을 직관적으로 포트번호(27042 형식)로 만들고 싶었는데, 굳이 그럴 필요가 있나 싶었다.
그래서 버퍼의 메모리를 일반 문자열로 변환시켜서 스크립트를 짜보았다.
https://github.com/frida/frida/issues/329
how can I access to the bytes returned by ReadByteArray? · Issue #329 · frida/frida
Hi, how can I access to the bytes returned by ReadByteArray? Example code: a = Memory.readByteArray(this.buf, this.count); should I use a[0]? My goal is to identify the position of the first 0 in t...
github.com
function hook_connect() {
const connect_addr_ptr = Module.getExportByName(null, 'connect');
const connect_addr = new NativeFunction(connect_addr_ptr, 'int', ['int', 'pointer', 'int']);
Interceptor.replace(connect_addr, new NativeCallback(function (fd, pointer, r) {
const sin_port = Memory.readByteArray(pointer.add(2), 2);
const in_addr = Memory.readByteArray(pointer.add(4), 4);
var sin_port_str = convert_byte_to_String_Array(sin_port);
var in_addr_str = convert_byte_to_String_Array(in_addr);
console.log(sin_port_str, in_addr_str);
if (sin_port_str == "69a2" && in_addr_str == "7f001")
return -1;
},'int', ['int','pointer','int']));
}
function convert_byte_to_String_Array(bufferAddress) {
var new_Array = new Uint8Array(bufferAddress);
var str = "";
for(var i = 0; i < new_Array.length; i++) {
str += (new_Array[i].toString(16) + "");
}
return str;
}
근데 내가 못하는 건지, 안되는 건지 모르겠는데. Interceptor.replace() 를 사용하면 버퍼에 대하여 직접적인 변조가 되질 않았다. 그래서 Interceptor.attach() 로도 짜봤다.
function hook_connect2() {
var connect_addr = Module.getExportByName(null, 'connect');
Interceptor.attach(connect_addr, {
onEnter (args) {
Memory.protect(args[1], 16, 'rwx'); // Memory 권한 설정
this.sin_port = args[1].add(2);
this.in_addr = args[1].add(4);
const sin_port = Memory.readByteArray(this.sin_port, 2);
const in_addr = Memory.readByteArray(this.in_addr, 4);
var sin_port_str = convert_byte_to_String_Array(sin_port);
var in_addr_str = convert_byte_to_String_Array(in_addr);
console.log('Before Hook : ',sin_port_str, in_addr_str);
Memory.writeByteArray(this.sin_port, [0x69, 0xa4]);
console.log('After Hook : ',sin_port_str, in_addr_str);
}
})
}
오. 구조체 정복 성공^^
응용 분야가 꽤 많을 듯.
사실, 프리다 기본 포트번호는 27042를 사용한다. 그렇기 때문에 해당 로직은 기본 통신 포트만 변경해주면 해결된다.
./frida-server -l 0.0.0.0:8484 &
frida -H 192.168.0.2:8484 -f com.test.fl -l test.js
끗.
추가, 검색하다가 우연히 발견한 사이트. 나중에 도움이 될지도.
Frida: How to read a struct or a struct pointer or a pointer of a struct pointer?
Frida: How to read a struct or a struct pointer or a pointer of a struct pointer? - frida-struct-pointer-pointer.js
gist.github.com
https://github.com/frida/frida/issues/166
Can't get Interceptor to work with NativeFunction calls · Issue #166 · frida/frida
Hi, I'd like to Intercept calls to a Win32 API that are made inside a function which I instrument with a NativeFunction object. However, the Interceptor callback is only called when the origina...
github.com
'Mobile > Android' 카테고리의 다른 글
[Android] Damn-Vulnerable-Bank - 1 루팅 탐지 우회 (feat. Frida) (0) | 2022.12.29 |
---|---|
[Android] Damn-Vulnerable-Bank 환경구축(Feat. AWS) (0) | 2022.12.29 |
[Android ] adb shell 편하게 잡자(feat. 가상머신) (0) | 2022.10.19 |