
모의해킹을 하면 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이 되며 카카오톡이 에러를 뱉어내거나 정상적으로 응답이 돌아오지않는다.
이런식으로 윈도우 소켓 라이브러리를 후킹하여 메모리 변조를 할 수 있으며
스크립트를 좀더 다양하게 활용하여 사용할 수도 있다.
'CS&하드웨어&시스템' 카테고리의 다른 글
치트엔진(CheatEngine) 기본 사용법 2 - WindowSocket 통신 메모리 변조 (0) | 2023.05.24 |
---|---|
치트엔진(CheatEngine) 기본 사용법 - 피카츄배구 (1) | 2023.05.23 |
DLL 하이재킹(DLL Hijacking)을 통한 프로그램 해킹 (1) | 2022.07.27 |