0

나는 잘못 작성된 코드의 수정 불가능한 라이브러리를 수용하기 위해 약간의 코드 해킹 문제에 다시 직면했다.함수의 주소를 가져올 때의 이상한 행동

조사 후 (함수 포인터에 어떤 종류의 상태도 넘길 수 없다는 것을 알게 된 후) EAX를 0xCCCCCCCC로 재설정하는 함수 헤더 내의 ASM 바이트를 NOP로 추출해야합니다.

내장 된 VC++ 디버거를 사용하여 함수의 '주소'를 가져 와서 치트 엔진에 바이트 항목 배열을 수동으로 생성하면 (이는 이런 종류의 일에 놀랍게 유용합니다), 바이트와 5 바이트 시퀀스를 수동으로 NOP 할 수 있습니다.

그러나 프로그래밍 방식으로 처리하는 것은 조금 다릅니다.

다음 중 하나를 수행 할 때 주소가 디버거에서보고하는 것보다 상당히 높습니다.이 주소는 잘못된 바이트를 가리키는 포인터입니다.

unsigned int ptr = reinterpret_cast<unsigned int>(testhack); 
unsigned char* tstc = (unsigned char*)&testhack; 
FARPROC prc = GetProcAddress(GetModuleHandle("mod.dll"), "testhack"); // Still 
        // returns the incorrect address (same as the previous two) 

올바른 주소를 찾으려면 디버거가 무엇을 수행합니까? 프로그래밍 방식으로 올바른 주소를 찾는 방법은 무엇입니까?

+0

왜 downvote? 이를 수행 할 수있는 다른 방법이 없습니다. – Qix

+0

'EAX'를 저장하고 clobbered 후에 복원 하시겠습니까? –

+0

@ MarkB 나는 그것을 제어 할 수 없다. – Qix

답변

0

알아 냈어.

(내가 무엇이라고 부름) 조회 테이블을 완전히 잊었습니다. 내가 수신 한 주소는 real 함수 본문에 대한 간단한 5 바이트 무조건 JMP 인 조회 테이블 항목에 대한 포인터입니다. 오프셋을 가져 와서 조회 테이블 항목 끝에 추가 한 다음 올바른 주소를 입력해야했습니다.

다음은 함수의 올바른 시작 주소에 도달하는 코드입니다.

// Get the lookup table address 
const char* ptr = (const char*)&testhack; 
// Get the offset (+ 1 byte retrieved as a long) 
unsigned int offset = (unsigned int)(*((unsigned int*)(ptr + 1))); 
// Add to the original look up pointer, +5 (the offset starts after the 
// end of the instruction) 
const char* tst = (const char*)(ptr + offset + 5); 

tst 올바른 주소를 보유하고 있습니다.

현재 ASM 호출 명령어는 함수 포인터가 들어있는 구조체에 포인터를 EAX에 넣습니다. 일반적으로 콜백 함수는 EAX를 재설정합니다. 그러나, 나는이 해킹을 적용했고 그 부분을 NOP로 처리했다. 함수 내에서 코드의 첫 번째 줄은 로컬 포인터를 만든 다음 mov [ptr],eax 인라인 어셈블리에서 포인터로 주소를 만듭니다. 그런 다음 포인터를 정상적으로 사용할 수 있습니다.

1

아마도 함수 주소는 DLL에 있습니다. 이 경우보고있는 것은 예를 들어 &testhack의 주소를 프로그램이로드 된 메모리의 올바른 위치로 재배치하는 로더입니다. 디버거는 이미 재배치에 대해 알고 있으며 바이트를 수정할 수 있도록 자동으로 도움을줍니다.

불행히도이 문제를 해결할 수있는 메커니즘을 알지 못하지만 정적으로 링크하면 런타임보다 링크 타임에 주소가 고정됩니다.