Post

Anti debugging

packer / protector

packer

패킹은 실행 압축이다. 압축으로 PE file의 크기를 줄이는게 목적이다.

런타임에 언패킹 코드를 먼저 실행해 패킹이 풀리기 때문에, 메모리에 올라가는 코드는 차이가 없다.

압축하다보니 언패킹 하기 전 바이너리나 섹션, IAT 등이 안보이는 부수효과도 있다.
언패커가 공개되지 않은 패커일 경우 메뉴얼 언패킹 해야 하는데, 이 경우 리버싱을 어렵게 하는 효과도 있다.
근데 어차피 리버싱을 어렵게 할거라면 안티 디버깅 등등이 들어가게 되기 때문에 사실상 packer 보다는 protector가 걸렸다고 봐야하는 경우가 대부분이다.

언패킹 루틴을 빼면 성능의 차이는 없다고 봐야한다.

protector

리버싱을 막는게 목적이다.

패킹에 Anti-Debugging, Code Obfuscation, Garbage Code 등 안티 리버싱 기법이 추가된 것이라고 생각하면 된다.

메모리에 올라가서 패킹이 풀려도 난독화, 삽입된 가비지 코드 등으로 바이너리 따라가기가 힘들다. 쓸데 없이 JMP를 계속 타게 한다던가 하는 가비지 코드가 삽입되면 성능이 느려지기는 할 것 같다. 큰 차이는 없겠지만.

기타

OutputDebugString

OutputDebugString 함수는 내부적으로 RaiseException()의 매개변수로 DBG_PRINTEXCEPTION_C를 전달하여 호출한다. 이를 Debugger에서 처리하면서 메시지를 출력하게 되는 방식.

디버깅 중 일때와 디버깅이 아닐 때 fs:[34] 위치에 저장되는 LastError의 값이 다르기 때문에 이를 비교해서 디버깅 여부를 판단할 수 있다.

직접 fs:[34]의 값을 추출해도 되고, GetLastError()를 사용해도 된다.
또는 eax값을 비교하는 방법을 사용해도 된다.

If we call OutputDebugString in order to pass a string to the debugger, and a debugger is attached, then when we return back to the user code, the value in EAX will be a valid address inside the process address space.
However, if a debugger is not attached, then the value in EAX will be either 0 in Windows 7 (probably the same also in Vista) or 1 in Windows XP (tested in WinXP SP3), which are not of course valid addresses.
So in that case if we try to read the contents of an invalid memory address, an exception will be raised ( EXCEPTION_ACCESS_VIOLATION – 0xc0000005 ) and we will know that a debugger is not attached.
On the other hand if an exception does not occur then we know that a debugger is attached.

This post is licensed under CC BY 4.0 by the author.