안티치트 우회에 필요한 드라이버와 유저 프로그램과 통신방법 중 하나인 data ptr hook입니다.
원본 소스코드입니다.
설명을 위해 소스코드 수정했습니다.
기본적인 C문법은 알고 있어야 합니다.
DbgPrintEx는 의미 없어서 주석 설명 안 했습니다.
INT64(__fastcall* Qword_ptrOriginal)(PVOID, PVOID, PVOID, PVOID, PVOID);//원본 함수 포인터입니다
INT64 __fastcall Qword_ptrHooked(PVOID a1, PVOID a2, PVOID a3, PVOID a4, PVOID a5)
{
DbgPrintEx(0, 0, "후킹 함수 진입!\n");
DbgPrintEx(0, 0, "a3: 0x%p\n", a3);
//여기서 내 프로그램에서 보냈는지 체크하기 위해 체크를 해줍니다
if(a3 == 0x787878) //뭐 이런 식으로 체크
{
return 0; //내 프로그램이면 작업 후 정상적으로 리턴 시켜줍니다
}
return Qword_ptrOriginal(a1, a2, a3, a4, a5); //내 프로그램이 아니면 원래 함수로 리턴 시킵니다
}
NTSTATUS DriverEntry(PVOID lpBaseAddress, DWORD32 dwSize) { //드라이버 진입점입니다
UNREFERENCED_PARAMETER(lpBaseAddress); //사용 안 하는 파라미터 처리 해주는 거임
UNREFERENCED_PARAMETER(dwSize); //사용 안 하는 파라미터 처리 해주는 거임
//"get_module_base"이 함수는 따로 작성해야 합니다
// 시스템 모듈 베이스주소를 구해주는 함수입니다
PVOID KernelBase = (PVOID)get_module_base("\\SystemRoot\\System32\\win32kbase.sys");
if (!KernelBase) { // 구했는지 체크
DbgPrintEx(0, 0, "베이스 주소 찾지 못했음!\n");
return 1;
}
DbgPrintEx(0, 0, "베이스 주소: 0x%p\n", KernelBase);
//"FindPatternImage"이 함수도 따로 작성해야 합니다
//모듈 PE헤더를 이용해서 패턴을 찾아 주소를 구하는 함수입니다
//"ApiSetEditionGetUserObjectInformationEntryPoint" 함수의 data ptr 패턴을 찾는 겁니다
PVOID qword_ptr = FindPatternImage((PCHAR)KernelBase, "\x74\x20\x48\x8B\x44\x24\x00\x44", "xxxxxx?x");
if (!qword_ptr) {
DbgPrintEx(0, 0, "qword_ptr 찾지 못함!\n");
return 1;
}
DbgPrintEx(0, 0, "Qword_ptr: 0x%p\n", qword_ptr);
//밑에 상세 설명 있습니다
//패턴 스캔으로 찾은 주소에서 0xA 만큼 빼기
UINT64 qword_ptr_derf = (UINT64)(qword_ptr)-0xA;
//그리고 주소에 3을 더하고 참조해서 4바이트만큼 저장하고 7을 더함
qword_ptr_derf = (UINT64)qword_ptr_derf + *(PINT)((PBYTE)qword_ptr_derf + 3) + 7;
//InterlockedExchangePointer 함수로 주소 바꿔치기(후킹 완료)
*(PVOID*)&Qword_ptrOriginal = InterlockedExchangePointer((PVOID*)qword_ptr_derf, (PVOID)Qword_ptrHooked);
DbgPrintEx(0, 0, "드라이버 로드 완료!\n");
return 0;
}
봐도 이해 안 되는 부분이 있었는데요.
UINT64 qword_ptr_derf = (UINT64)(qword_ptr)-0xA;
0xA를 빼주는 이유는 패턴 스캔으로 찾은 주소는 0x1C0092F5F인데
진짜 찾아야 하는 곳은 0x1C0092F55이기 때문입니다.
계산기로 주소를 빼보면 0x1C0092F5F - 0x1C0092F55 = 0xA입니다.


0x1C0092F55 주소를 찾았으니
"cs:qword_1C0251E20" 이곳에 올라오는 data ptr 주소를 찾는 게 다음 목적입니다.
qword_ptr_derf = (UINT64)qword_ptr_derf + *(PINT)((PBYTE)qword_ptr_derf + 3) + 7;
사진을 보면 0xFFFF9B9973692F55가 0xA를 뺀 주소입니다.

0x3을 더하는 이유는 data ptr 주소를 찾기 위한 오프셋을 구하기 위함입니다.
0xFFFF9B9973692F55 + 0x3을 더하고 4바이트만 참조하면 오프셋 0x1BEEC4이 나옵니다.

이 오프셋에 0x7을 더해주는 이유는 0x7을 더해야 정확한 주소가 나옵니다.
안 더했을 경우 : 0xFFFF9B9973851E19
더했을 경우 : 0xFFFF9B9973851E20
0x1BEECB 을 만들고 0xFFFF9B9973692F55와 더해주면
0xFFFF9B9973851E20 주소가 나옵니다.
치트엔진으로 살펴본 주소와 똑같습니다.

이 주소는 무슨 테이블 같은 곳으로 연결되는 것 같은데
테이블의 주소를 내 드라이버 주소와 바꿔치기하는 것입니다.

후킹을 하니 변하는 주소

저 함수 말고 다른 함수를 후킹 하고 싶으면
후킹함수 찾는 법을 읽어보세요.
https://cpgood.tistory.com/4
[게임 해킹] data ptr hook 후킹 할 함수 찾는 방법 (안티치트 우회)
드라이버와 유저 모드 통신방법 중 하나인 data ptr hook의 후킹 할 함수를 찾는 법 알아보겠습니다. 이 글이랑 보면 좋습니다! 게임해킹(안티치트 우회)에 활용됩니다. 후킹 할 함수를 찾는 이유는
cpgood.tistory.com
data ptr hook이라고 알려진 기술을 살펴봤는데
이렇게 후킹 했을 경우 탐지할 수 있는 방법은
0xFFFF9B9973851E20에 있는 포인터가 이상 없는 모듈을 가리키면 정상이고 아니면 후킹 된 거겠죠
그래서 포인터에 포인터를 후킹 하면 안전하다고 하는 거 같습니다.
머리 아프니 이제 그만 알아봅시다.
이 코드는 작동하지만 템플릿입니다.
게임에 사용하려면 커널에서 베이스 주소 가져오기,
커널에서 메모리 읽기 쓰기를 구현해야 사용할 수 있습니다.
디스코드 : cpgood#0780
메일 : qmffhrm@protonmail.com
'게임해킹 > 커널 게임 해킹' 카테고리의 다른 글
[게임해킹] 커널에서 PEB로 베이스주소 가져오는 방법 (0) | 2023.01.01 |
---|---|
안티 치트가 프로세스 핸들을 보호하는 방법 (치트엔진 검색 안 되는 이유) [게임해킹] (0) | 2022.10.08 |
[게임 해킹] 드라이버 통신방법 text ptr hook 설명 (안티치트 우회) (0) | 2022.07.02 |
[게임 해킹] data ptr hook 후킹 할 함수 찾는 방법 (안티치트 우회) (0) | 2022.06.28 |