함수 개요
DuplicateHandle 함수는 특정 커널 객체에 대한 핸들을 다른 프로세스의 핸들 테이블로 복제하는 역할을 합니다. 복제된 핸들은 원본 핸들과 동일한 커널 객체를 참조하므로, 한쪽에서 객체 상태를 변경하면 다른 쪽에도 즉시 반영됩니다. 예를 들어 파일 핸들의 경우, 파일 포인터 위치가 양쪽 프로세스에서 공유됩니다.
함수 선언 및 파라미터
BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
LPHANDLE lpTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions
);
주요 인자는 다음과 같습니다:
- hSourceProcessHandle: 소스 프로세스의 핸들입니다. 호출한 프로세스 기준으로 유효한 프로세스 객체여야 합니다.
- hSourceHandle: 복제할 소스 프로세스 내의 객체 핸들입니다.
- hTargetProcessHandle: 핸들을 복사할 대상 프로세스의 핸들입니다.
- lpTargetHandle: 복제된 핸들 값을 저장할 변수의 주소입니다.
- dwOptions:
DUPLICATE_SAME_ACCESS등을 사용하여 접근 권한을 동일하게 유지할 수 있습니다.
주요 사용 시나리오
1. 의사 핸들 (Pseudo Handle) 을 실제 핸들로 변환
GetCurrentProcess() 와 같은 의사 핸들은 현재 프로세스 컨텍스트에서만 유효합니다. 이를 실제 커널 핸들로 변환하여 다른 프로세스에 전달하거나 저장하려면 복제가 필요합니다.
HANDLE hRealProcess = NULL;
DuplicateHandle(
GetCurrentProcess(), GetCurrentProcess(),
GetCurrentProcess(), &hRealProcess,
0, FALSE, DUPLICATE_SAME_ACCESS
);
// 사용 후 CloseHandle(hRealProcess) 호출 필요
2. 현재 프로세스의 핸들을 다른 프로세스에 전달
현재 프로세스에서 생성된 파일 핸들 등을 대상 프로세스가直接使用할 수 있도록 복제합니다.
HANDLE hDupHandle = NULL;
DuplicateHandle(
GetCurrentProcess(), hSourceFileHandle,
hTargetProcess, &hDupHandle,
0, FALSE, DUPLICATE_SAME_ACCESS
);
3. 다른 프로세스의 핸들을 현재 프로스로 가져오기
디버깅 또는 분석 목적으로 대상 프로세스가 가진 핸들을 현재 프로세스에서 사용 가능하도록 가져올 수 있습니다. 이 경우 대상 프로세스를 PROCESS_DUP_HANDLE 권한으로 열어야 합니다.
실습: 핸들 복제를 통한 파일 잠금 시뮬레이션
다음 예제는 현재 프로세스에서 생성한 파일 핸들을 explorer.exe 프로세스에 복제합니다. 이후 현재 프로세스에서 핸들을 닫더라도 대상 프로세스가 핸들을 보유하고 있으므로 파일이 잠긴 상태로 유지됩니다.
#include <windows.h>
#include <stdio.h>
// 디버그 권한 설정 함수
bool EnableDebugPrivilege() {
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return false;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
CloseHandle(hToken);
return false;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
CloseHandle(hToken);
return GetLastError() == ERROR_SUCCESS;
}
// 안전한 핸들 닫기
void SafeClose(HANDLE h) {
if (h && h != INVALID_HANDLE_VALUE) {
DWORD flags = 0;
if (GetHandleInformation(h, &flags) && !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE)) {
CloseHandle(h);
}
}
}
int main() {
// 대상 프로세스 (explorer.exe) 열기
// 실제 환경에서는 Process ID 를 동적으로 찾아야 함
DWORD targetPid = 1234;
EnableDebugPrivilege();
HANDLE hTargetProc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, targetPid);
if (!hTargetProc) {
printf("Failed to open target process.\n");
return 1;
}
// 파일 생성 및 핸들 획득
HANDLE hFile = CreateFile(TEXT("LockTest.txt"), GENERIC_READ, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
SafeClose(hTargetProc);
return 1;
}
// 핸들 복제
HANDLE hDupFile = NULL;
BOOL result = DuplicateHandle(
GetCurrentProcess(), hFile,
hTargetProc, &hDupFile,
0, FALSE, DUPLICATE_SAME_ACCESS
);
// 현재 프로세스에서는 핸들 닫기
SafeClose(hFile);
SafeClose(hTargetProc);
if (result) {
printf("Handle duplicated to target process. File is now locked by target.\n");
}
return 0;
}
위 코드를 실행하면 대상 프로세스가 파일 핸들을 보유하게 되므로, 사용자가 해당 파일을 삭제하거나 수정하려 할 때 접근 거부 오류가 발생합니다. 대상 프로세스가 종료되거나 핸들을 명시적으로 닫을 때까지 파일 잠금은 유지됩니다.