효투의 세상 로딩중...
효투의 세상 로딩중...
반응형

모의해킹을 하면 HTTP 프로토콜로 통신을 하는 웹/모바일 뿐만 아니라

그보다 아래 레이어에서 통신을 하는 CS프로그램도 종종 진단을 해야하는 경우가 생긴다.

이럴 경우 평범한 HTTP 프록시 도구를 사용해서 데이터를 변조하는 등의 진단은 불가능한데

이 때 Frida를 이용해서 진단을 수행할 수 있다.

 

원리는 간단하다

윈도우에서 HTTP 통신을 포함한 모든 TCP/IP 네트워크 통신은 Window Socket을 통해서 요청과 응답을 주고 받는다.

그 통신을 도와주는 파일이 WS2_32.dll 파일이다.

 

이 라이브러리 파일을 통해 데이터를 주고받는 다면 

라이브러리 파일을 후킹해서 HTTP 프로토콜로 이루어지는 통신이 아니더라도 그 내용을 볼 수 있다.

frida로 이 라이브러리를 후킹하는 방법은 아래 코드로 간단하게 할 수 있다.

var hook = Module.getExportByName("WS2_32.dll", "send");
Interceptor.attach(hook, {
  onEnter(args) {
    var bufferDump = hexdump(args[1]);
    bufferDump = bufferDump.slice(75);
    console.log("size : " + args[2].toString());
    console.log("Buffer Dump : " + bufferDump);
  },

  onLeave(result) {
  }
});

먼저

var hook = Module.getExportByName("WS2_32.dll", "send"); 코드를 통해

WS2_32.dll 을 후킹한다. 그냥 후킹한 것이 아니라 오른쪽 send 함수를 후킹하는 것이다.

라이브러리에서 send 함수를 사용할 때 2개의 인자를 받는데

그 2개의 인자는 위 코드에서 각각 args[1], args[2]로 가져오게된다.

첫번째 인자는 데이터를 저장하고있는 주소값과 그 데이터, 두번째 인자는 데이터의 크기이다

Interceptor를 통해서 send함수가 호출될 때마다 그 전후로 인터셉터를 호출하게되며 onEnter를 실행한다.

hexdump를 이용해서 덤프 후 데이터를 저장하고있는 주소값 args[1]을 Hex값으로 변환하고

마찬가지로 두번째 인자로 덤프 후 변환 그리고 로그를 출력한다.

 

실제로 실행해보면 아래와 같이 통신 내용을 볼 수 있다.

 

출력 결과를 보면 알 수있듯이  

size : 의 로그 출력결과는 데이터의 크기를 나타내고

Buffer Dump : 로그의 출력결과는 데이터의 주소와 데이터를 출력해준다.

 var bufferDump = hexdump(args[1]);
    bufferDump = bufferDump.slice(75);
    console.log("size : " + args[2].toString());
    console.log("Buffer Dump : " + bufferDump);

위 코드에서 bufferdump도 hexdump(args[1]) 정도로 간단하게 출력할 수 있는데

좀 더 보기편하게  출력되는 로그를 자르기 위해 slice 함수를 이용해먹으려고 굳이 코드 몇줄이 추가됐다.

 

이렇게 간단하게 특정 프로그램에서 주고받는 통신 내용을 볼 수 있다면 이제 변조를 해야한다.

아래 코드는 내가 참조한 블로그의 예시 스크립트이다

//"use strict";
var hookAddr = Module.getExportByName("WS2_32.dll", "send");
console.log("[-] Send Address: " + hookAddr.toString());

var strPtr = Memory.allocUtf8String("Modified Message!!");

Interceptor.attach(hookAddr, {
  onEnter(args) {

    this.sock = args[0];
    this.buf = args[1];
    this.size = args[2];
    this.flag = args[3];

    //console.log("size : " + this.size);
    //console.log("Buffer Dump : \\n" + hexdump(args[1]));

    args[1] = strPtr;
    args[2] = ptr(Memory.readCString(strPtr).length);
    console.log("strPtr Length : "+ Memory.readCString(strPtr).length);
    console.log("Modified Dump : \\n" + hexdump(strPtr));

  },

  onLeave(result) {
  }
});

 

반응형

위 스크립트를 동작하면 아래와 같이 메모리값이 변조된 것을 볼 수있는데

똑같이 

var hookAddr = Module.getExportByName("WS2_32.dll", "send"); 에서 라이브러리의 send함수를 후킹하고

그 밑에 바로 후킹한 주소를 콘솔에 찍어낸다.

그리고 실질적으로 변조가 되는 부분은

var strPtr = Memory.allocUtf8String("Modified Message!!"); 5번째줄인데 

Memory.allocUtf8String 함수로 메모리에 값을 할당해주는 기능을 한다.

그 밑으로 onEnter의 코드는 this.sock=args[0],this.buf = args[1]와 같은 코드로

소켓 핸들, 버퍼 포인터, 크기, 플래그 값 등을 가져오고

 args[1] = strPtr;
    args[2] = ptr(Memory.readCString(strPtr).length);

가져온 메모리에 Modified Message!! 할당하고 버퍼의 크기도  Modified Message!! 길이로 설정해준다.

이렇게 Frida로 통신 시 윈도우 소켓 라이브러리의 Send함수에 전달되는 메모리 변조를 수행할 수 있다.

하지만 실제 진단시에는 특정 문자열을 변조해야 의미가 있는데 위 코드를 활용해서 그 변조를 가능하게 할 수있다.

  var hookAddr = Module.getExportByName("WS2_32.dll", "send");
  
    Interceptor.attach(hookAddr, {
        onEnter(args) {

            this.sock = args[0];
            this.buf = args[1];
            this.size = args[2];
            this.flag = args[3];

            var patched = false;
            var pattern = "6B 61 6B 61 6F"; // kakao

            var s_r = Memory.scanSync(this.buf, Number(this.size), pattern);

            if (s_r.length == 0) {
                return;
            } else {
                var match = s_r[0];

                console.log('[*] Find Address ' + match.address);
                console.log(hexdump(match.address, {offset: 0, length: 32}));

                Memory.writeByteArray(match.address, [0x68,0x79,0x6F,0x74,0x77,0x6F]);
                
                console.log('[*] Patched String ' + match.address);
                console.log(hexdump(match.address,{offset: 0, length: 32}));
                
                s_r.length = 0;
                patched = true;
            }
        },
        onComplete: function() {}
    }

위 코드는 예시코드와 같은 원리로 동작하지만  pattern을 통해  특정 문자열을 패턴으로 설정해서 찾고

그 부분만 변조하는 코드이다.

또한 patched = false; 부분은 플래그 값이며 패치가 적용이 되었는지에 대한 여부를 알 수있다.

하지만 true일 경우에 Memory.writeByteArray 함수가 제대로 동작하지않아서 메모리 변조를 할 수가 없다.

어찌됐든 원리는 비슷하고 

var pattern 으로 kakao 라는 문자열을 hex값으로 설정한 후

var s_r = Memory.scanSync(this.buf, Number(this.size), pattern); 이 줄에서 메모리 내 데이터에서 패턴을 검색하고

일치하는 주소를 배열에 저장한다.

   if (s_r.length == 0) {
                return;
            } else {
                var match = s_r[0];

배열이 비어있으면 return으로 종료하고

배열이 있다면 첫번째 주소를 호출하고 그 밑의 코드로 콘솔에 주소값을 찍어준다.

그리고  Memory.writeByteArray(match.address, [0x68,0x79,0x6F,0x74,0x77,0x6F]); 이 코드에 의해서

패턴을 찾았던 메모리 주소에 hyotwo 라는 문자열을 덮어씌워주며 변조가 되고

마지막으로 플래그를 true로 설정하며 전송하게된다. 그 결과는 아래 사진과 같다

전송되는 메모리에서 kakao 문자열을 정확히 찾아 hyotwo로 변조한것을 볼수있다.

send 함수가 실행되기전 후킹을 하여 변조가 된 것이기에 실제로 전송되는 값은

hyotwo.com이 되며 카카오톡이 에러를 뱉어내거나 정상적으로 응답이 돌아오지않는다.

 

이런식으로 윈도우 소켓 라이브러리를 후킹하여 메모리 변조를 할 수 있으며

스크립트를 좀더 다양하게 활용하여 사용할 수도 있다.

 

반응형
  • hyotwo7658@gmail.com

복사 완료 👍