안드로이드에서 Frida를 사용해 인터셉트한 함수의 패러미터 읽기와 관련해 질문이 있습니다

홈 > 커뮤니티 > 질문 게시판
질문 게시판

안드로이드에서 Frida를 사용해 인터셉트한 함수의 패러미터 읽기와 관련해 질문이 있습니다

2 보글보글 4 3629
Unity로 제작되어 IL2CPP로 빌드된 해외 게임을 둘러보고 있습니다.
게임의 에셋(이미지, 효과음 등)을 추출하고 싶어 살펴보다 암호화를 담당하고 있는 것으로 추정되는 함수를 확인할 수 있었습니다.

IDA와 Hex-Ray를 통해 디컴파일 된 소스코드를 확인한 결과 암호화의 선행 과정으로 Rfc2898DeriveBytes를 사용하여 키를 생성하는 것으로 추정하고 있습니다.
그래서 우선 Frida를 이용해 해당 함수(Rfc2898DeriveBytes.ctor())를 Intercept함으로써 패러미터의 값들을 획득하려 했으나 해당 과정에 어려움을 겪고 있습니다.

아래 사진은 il2CppDumper에서 생성된 Dummy DLL을 dnSpy에서 불러와 확인한 해당 함수입니다.


아래 사진은 IDA에서 확인한 해당 함수의 패러미터입니다.



두 결과 중 어느 것이 맞는것인지 고민하다가,
onEnter 콜백의 패러미터로 4번째 값을 가져오려 하면(args[3]) 전혀 다른 메모리 주소를 뱉는것을 보아 패러미터가 3개인 dnSpy쪽이 맞다고 결론을 내렸습니다.

그래서 아래와 같은 JS 코드로 패러미터들의 값을 확인하려고 시도했습니다.

Interceptor.attach(rfc2898_ctor, {
    onEnter: function (args) {
        console.log(args[0]);
        console.log(Memory.readByteArray(args[0], 256));
        console.log(args[1]);
        console.log(Memory.readByteArray(args[1], 256));
        console.log(args[2]);
        console.log(Memory.readByteArray(args[2], 256));
        console.log("");
    },
    onLeave: function (retval) {
    }
});

아, 이미지 첨부가 2개까지 되는군요...

아무튼, 위와 같은 코드로 아래 링크의 사진과 같은 출력을 확인했습니다.
https://i.ibb.co/h9J9xZ9/frida-res-0.png

각각의 블럭이 args[0], args[1], args[2] (패러미터 주소들)를 256바이트씩 읽어들여서 출력한 것인데,
dnSpy에서 본 string, byte[], 그리고 int형이 저장되어있다는 생각이 들지는 않는 정보들이었습니다.

그렇게 보다가 각 블럭의 첫 5바이트가 또다른 포인터 주소로 보임을 알았고, 이번에는 5바이트로부터 얻은 주소를 읽도록 해보았습니다.

var addr_x0 = args[0].readPointer();
console.log(Memory.readByteArray(addr_x0, 256));

이런 식으로...


아래 링크의 사진은 위 시도의 출력물입니다.
https://i.ibb.co/Pm0kXqX/frida-res-1.png

위에 해당하는 값들이 나오길 기대했는데 오히려 또 다른 포인터 주소가 나온데다가,
이번에는 또 세 블럭의 시작 모두 같은 포인터 값을 제시하고 있었습니다.

여기서부터 뭔가 이상하다 싶어서 혹시 il2cpp 구현체의 객체들은 메모리에 단순히 바이트 그대로 담기는 것이 아닌 다른 추가적인 헤더같은 정보가 붙어있는 것인가 고민도 해봤지만 좋은 답이나 해결책을 얻지는 못했습니다.

그래서 린포럼에서 도움을 얻을 수 있을까 싶어 질문 게시글을 남기게 되었습니다.
혹시 아시는 분이 계시다면 도움을 부탁드립니다. 감사합니다.
4 Comments
2 보글보글 2021.01.27 11:18  
추가적으로, IDA의 동적 분석 기능을 사용해보려고 여러 차례 시도를 했으나 Attach 이후 Breakpoint가 걸린 경우 애플리케이션이 SIGPWR를 보내며 뻗어버려서 확인은 못해보았습니다.
2 보글보글 2021.01.27 13:26  
자문 자답입니다.
아무래도 직접 코드를 작성해보고 컴파일해 대조해보는 것이 좋을 것 같아 동일한 버전의 Unity로 아래와 같은 코드를 작성하고 대조해서 비교했습니다.

void Start() {
    byte[] btarr_sample = new byte[] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    string str_sample = "This is an sample text for Rfc2898Derive Bytes method";
    int int_sample = 2021;
   
    ExampleMethod(str_sample, btarr_sample, int_sample);
}

void ExampleMethod(string password, byte[] salt, int iteration) {
    Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(password, salt, iteration);
}

본문에서 '전혀 다른 메모리 주소를 뱉는것을 보아' 라고 말했던 값이
이상한 메모리 주소가 아닌 해당 함수의 패러미터로 넘겨진 int 자료형의 HEX값이었습니다 -_-...
onEnter의 패러미터로 넘어오는 값들은 당연히 메모리 주소들만 있을것이라고 생각했는데 잘못된 지식임을 알고 고칠 수 있었습니다.

또, 본인이 직접 입력한 문자열이 Frida 출력 결과물에서 보이니 확실하게 어떤 구조로 저장되어 있는지 알 수 있었습니다. 여기서 드는 의문점은 왜 모든 글자 사이에 널 캐릭터(\x00)이 포함되어 있는건지... 잘 이해가 안가네요.
이 방법으로 byte 배열도 어떻게 읽어와야할지 대충 감 잡을 수 있었습니다.

역시 좋은 대조군을 하나 만들어두면 공부하기 훨씬 좋은 것 같습니다...
1 조금신 2021.04.12 11:42  
글자 사이에 널캐릭터가 포함되는건 wchar 라서 그런거 아닐까요?
5 킹왕짱 2021.01.29 14:30  
우와 고수님의 글이라 이해는 어렵지만
대단한 것 같습니다. 부럽습니다
모르는게 많아 서서히 많은 정보 익혀보고 싶네요
잘 부탁드립니다