컨텐츠 바로가기

WriteProcessMemory를 사용한 코드 인젝션시 주의 사항

http://dstein.egloos.com/2335201

WriteProcessMemory를 사용한 코드 인젝션시 주의 사항

VirtualAllocEx()와 WriteProcessMemory()를 사용하여 리모트 프로세스에 코드를 인젝션 시키는 방법은 이미 많은 분들이 소개해서 모두 알고 있을것으로 생각된다.
이런 설명들을 보다보면 Release모드로 컴파일한 경우에서는 정상적으로 동작하지만 Debug모드로 컴파일일한 경우에는 리모트 프로세스가 Crash된다라고 언급이 되어 있으나 구체적으로 왜 이런 현상이 발생하는지에 대한 설명이 존재하지 않아 이부분에 대해 언급하려 한다.

아래 예제 코드는 리모트 프로세스에 인젝션될 스레드 함수 코드이다.











이 코드가 Release 모드와 Debug 모드에서 어떻게 코드(기계어)화 되는지 내용을 보면 그 원인을 알 수 있다.

Release 모드로 컴파일 한 경우
































Debug 모드로 컴파일 한 경우











































Releas모드와 Debug모드의 차이점이 명확이 구분된다.

Debug모드일 경우에는 런타임체크 코드가 자동으로 삽입되었다. 이렇게 자동으로 생성된 런타임체크 코드가 리모트 프로세스에 주입되어 실행되면 당연히 런타임체크 코드가 호출하는 주소에 해당 런타임체크 코드가 존재하지 않으므로 Crash가 발생한다.
그럼 이렇게 자동으로 삽입되는 런타임체크 코드를 생성하지 않게하기위해서는 어떻게 해야 할까? 방법은 두가지가 있다.

첫째. Debug모드일 경우 기본으로 설정되는 컴파일 옵션을 변경하여 코드 전체에 대해 적용하는 방법
C/C++ ->Code Generation의 Basic Runtime Checks의값을 Both (/RTC1, equiv. to /RTCsu)에서 Default로 변경한다.

둘째, 컴파일 지시자를 사용하여 해당 코드에 대해서만 적용하는 방법












또 하나 주의해야 할 사항이 있다. WriteProcessMemory로 코드를 리모트 프로세스에 쓰기위해 쓸 코드의 주소를 얻어야 하는데.. Debug모드일 경우 이 코드의 주소가 실제 주소가 아닌 해당 코드 주소를 가리키는 JMP문으로 기록되어 있는 경우가 존재한다.
이는 Debug모드일 경우 Link옵션이 Incremental Linking으로 설정되어 있어서 그렇다. 모두 알고 있겠지만 Incremental Linking은 링크 시간을 단축하기 위해 링크시점에 모든 코드의 호출 주소를 변경하지 않고 변경된 코드의 주소만 JMP문으로 변경하는 기능을 수행한다. 따라서 WriteProcessMemory로 기록하는 내용이 실제 코드의 내용이 아니라 JMP문에 해당하는 다른 내용의 코드가 기록된다.

단 해당함수가 static으로 구현되어 있을경우 Incremental Linking으로 설정되어 있더라도 실제 함수의 주소가 코드에 설정된다.
(위의 샘플소스를 보면 static으로 선언되어 있음.)

이설정은 Project의 Linker->General의 Enable Incremental Linking을 NO로 설정하여 해결 할 수 있다.



덧글|신고