본문 바로가기

My Study/Programming&Theory

내부적으로 ZwCreateFile 구현해서 사용하기

 어떤 패킹된 프로그램을 보거나 바이러스 같은걸 보다보면 내부적으로 
그냥 SYSENTER를 사용하고 있는 것을 볼수 있습니다.
main함수 같은 곳에서 SYSENTER가 나와버리는거죠;;

그래서 저도 파일을 생성시키는 ZwCreateFile 함수를 직접 구현해봤습니다.

파일을 생성시키는 코드를 작성해 해당 API를 쭉 따라가봤습니다.
아래는 사용된 함수입니다.
CreateFileW(
L"C:\\SYSENTER",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);

해당 함수는 내부적으로 ntdll.dll에 있는 ZwCreateFile을 호출하게 되므로 SYSENTER를 하기전에 스택에 push된 인자 값들을 똑같이 설정해줘야합니다.
첫번째 인자 : HANDLE 포인터 out
두번째 인자 : 0xC0100080
세번째 인자 : OBJECT_ATTRIBUTES 포인터

typedef struct _OBJECT_ATTRIBUTES {
  ULONG           Length; //0x18
  HANDLE          RootDirectory; //0x00
  PUNICODE_STRING ObjectName; //UNICODE_STRING포인터
  ULONG           Attributes; //0x40
  PVOID           SecurityDescriptor; //0x00
  PVOID           SecurityQualityOfService; //0x00
}  OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

typedef struct _LSA_UNICODE_STRING {
  USHORT Length; //0x001E
  USHORT MaximumLength;         //0x021A
  PWSTR  Buffer;         //"\\??\\C:\\SYSENTER" 문자열 주소
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;

네번째 인자 : IO_STATUS_BLOCK 포인터 out
다섯번째인자: 0x00000000
여섯번째인자: 0x00000080
일곱번째인자: 0x00000000
여덟번째인자: 0x00000005 //FILE_MAXIMUM_DISPOSITION
아홉번째인자: 0x00000060 //FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
열번째인자  : 0x00000000
열한번째인자: 0x00000000

이렇게 총 11개의 인자가 들어가는데 그중에 UNICODE_STRING과 OBJECT_ATTRIBUTES같은 경우는 그냥 함수와 메크로로 초기화시켜줬습니다.

main 함수입니다.
main 함수는 뭐 볼게 없군요;;

이제 제가 만든 MyZwCreateFile 함수 내부를 보도록 하겠습니다.
그냥 인라인 어셈으로 ZwCreateFile 인자를 쭉 넣어주고 ZwCreateFileKiFastSystemCall 내부를 전부 적어준것입니다.

인자를 push하는 부분은 크게 볼게 없는데 push 0xDEADCAFE 부분부터는 유심히 봐야합니다.
( MS에선 0xBAADF00D 같은걸 사용하길래... 저도 죽은카페? 라는 걸로 만들어봤습니다 :-) 하핫;; )
저기서 주위해야할 점은 
SYSENTER를 수행하고 나면 스택에 있는 값으로 retn을 하게 되는데 그 값을 SYSENTER 다음 주소로 설정해놔야한다는 것! SYSENTER를 수행하기 위해 push된 값 만큼 스택을 정리해줘야된다는 것!
2가지만 주의해서 코드를 작성하면 됩니다. 저렇게 하지 않을 경우 프로그램은 뻑이나버리죠;;

그리고 전 VS 2010을 쓰는데 인라인 어셈할 때 sysenter는 사용을 못하더군요.
그래서 _emit을 사용해 sysenter를 정의해놨습니다.

#define sysenter __asm _emit 0x0f __asm _emit 0x34

이렇게 말이죠.
파일 생성은 정상적으로 잘 됩니다 :-)

마지막으로 eax에는 KiServiceTable에서 Nt함수 주소를 가져올 때 Index값으로 사용이 되는데요.
저 Index 값은 OS마다 다르기 때문에 글로벌하게 동작을 하려면 위와 같이 코드를 작성하는게 아닌 
GetVersionEx 함수를 사용해 OS버전을 알아와서 그 버전에 맞는 Index 값으로 설정을 해주는게 좋습니다.
( 위 설정된 0x42라는 값은 커널 버전 6.1 에서 사용되는 NtCreateFile Index값 )

이런 방법을 언제 써먹을진 모르겠지만 나중에 재미삼아 CrackMe를 만든다거나 할 때 사용해볼 것 같습니다.


'My Study > Programming&Theory' 카테고리의 다른 글

Python Eclipse에서 코딩하기  (1) 2011.02.25
병렬 프로그래밍  (1) 2011.02.10
Driver 정적로딩 시 OS작동 방식  (0) 2011.01.20
Filter Driver를 이용한 키로거 제작  (4) 2011.01.14
전역적 필터 드라이버  (0) 2011.01.12