* 아직은 많이 부족하기 때문에 제가 자신이 생길 때 까지 본 글은 제 블로그에 대한 링크만 허용합니다. 핸들 핸들은 프로세스에서 커널 객체를 조작하기 위해 사용하는 말 그대로 운전대 입니다. 쉬운 예로 파일을 조작한다면 프로세스는 객체 관리자로부터 파일을 조작하기 위해 해당 오브젝트에 대한 핸들을 넘겨 받아야 합니다. 다시 말해 Process 에서 파일 이나 레지스트리 세마포등의 자원을 이용하기 위해서는 해당 파일을 컨트롤 할 수 있는 API를 이용한다는 것은 핸들을 사용하는 것으로 표현 할 수 있습니다.. 예를 들어 파일을 오픈 하거나 만들기 위해서 CreateFile 함수를 사용하게 된다면 윈도우에서는 해당 객체들을 조정할 수 있도록 해당 프로세스의 핸들 테이블에 요청된 객체의 핸들을 추가해 줍니다. 실제로 프로세스 주소 공간 내에 해당 핸들 테이블이 있는 건 아닙니다. 실제로는 커널의 Paged Pool에 핸들 테이블이 저장되고, 프로세스에서는 해당 핸들에 대한 포인터만 가지고 있는 거죠. (커널의 Paged Pool에 대해서는 이후에 설명하도록 하겠습니다.) 핸들은 객체에 대한 포인터 입니다. 이런 핸들은 각 프로세스당 최대 16,777,216 개 까지 할당 받을 수 있습니다. (이는 OS 상에 하드 코딩되어 있습니다.) 하지만 실제로 이렇게 많은 수를 오픈하지는 않습니다. 실제로는 10,000 개 이상의 핸들을 동시에 오픈하는 프로세스의 경우 개발자가 “개”발 한 것이거나 핸들릭이 있다고 볼 수 있습니다. 핸들 테이블의 entry에는 실제 해당 오브젝트에 대한 포인터와 권한 정보를 포함하고 있습니다. 권한에 대한 정보는 32Bit의 길이를 갖으나 포인터의 경우 32비트는 8Byte의 길이를 64비트의 경우 12Byte의 길이를 갖습니다. 하지만 실제로는 64비트 윈도우의 경우 실제로 64비트 주소공간을 모두 이용하기 위하여 16Byte (64bit) 길이의 오브젝터 포인터를 갖게 됩니다. 아래 그림은 32비트 운영제체의 핸들 엔트리 입니다. 위에서 설명한 것과 같이 이 8Byte 길이의 핸들 엔트리는 객체에 대한 포인터와 권한 부로 나누어 집니다. 그리고 제가 64비트의 경우 12Byte 라고 위에서 이야기했는데 이는 핸들에 대한 포인터는 2배로 (8Byte)로 늘어나지만 Access mask는 여전이 4Byte만 사용하기 대문에 12Byte 가 됩니다. 하지만 할당해서 사용하는 것은 16Byte를 사용하고 있습니다. 실행부가 제공 하는 핸들 테이블은 Page 즉 4K Byte의 크기를 가지고 있습니다. 그러므로 32 비트 운영체제에서는 8 Byte의 객체 포인터이기 때문에 512가 저장될 수 있고, 64비트 운영체제의 경우 256개가 저장될 수 있습니다. 다시 위에서 언급한 16,777,216 개의 핸들을 표현 하기 위해서는 단일 프로세스가 소유 할 수 있는 핸들 테이블은 32비트 운영체제의 경우 총 32,768 개 64비트 운영체제의 경우 총 65,536개가 됩니다. 그리고 마지막으로 이 핸들 테이블이 위치하는 커널의 Paged Pool은 16,777,216가 할당되게 될 경우 최대 32비트의 경우 16,777,216*8Byte 즉 128MB가 64비트의 경우 최대 16,777,216*16Byte즉 256MB 정도가 됩니다. 프로세스가 생성되게 되면 먼저 가장 낮은 레벨의 핸들 테이블이 생성 됩니다. 그리고 필요에 따라 추가적으로 레벨들이 생성이 됩니다. 한 테이블의 크기는 4K 이기 때문에 512개의 핸들 엔트리가 위치할 수 있습니다. 하지만 이중 1개의 엔트리는 감사를 위해서 사용되게 됩니다. 즉 최초에 511개의 핸들 테이블이 생성된 이 후 필요에 따라 16,777,216 개의 핸들을 표현하기 위한 테이블들이 필요할 경우 추가로 생성되게 됩니다. 이 핸들 테이블의 각 엔트리를 이용하는 방식은 Virtual to physical memory transaction과 비슷합니다. 핸들 살펴 보기 !handle 구문 : !handle < handle index> < flags> < processid> 1. lkd> !handle 0 7 acc |