프로그래밍
XP 유저모드에서 커널메모리 접근(읽고쓰기)
friday13th
2011. 6. 22. 14:06
일반적으로 유저모드에서 커널메모리 접근은 차단되어있다.
단, 예외적으로 XP에서 관리자 권한을 가지고있고 SE_DEBUG_NAME 특근을 얻을 수 있으면
ntdll.dll 의 ZwSystemDebugControl Native API 함수를 이용하요 커널메모리에 접근이 가능하다.
KernelMemory.h
#pragma once
//NTSTATUS값이 0이상이면 보통 성공한 상태를 의미한다
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
typedef LONG NTSTATUS;
typedef struct _MEMORY_CHUNKS
{
PVOID pVirtualAddress;
PVOID pBuffer;
DWORD dwBufferSize;
} MEMORY_CHUNKS, *PMEMORY_CHUNKS;
typedef enum _SYSDBG_COMMAND
{
SysDbgCopyMemoryChunks_0 = 0x08, //가상 메모리로부터 데이터를 읽을 때
SysDbgCopyMemoryChunks_1 = 0x09, //가상 메모리에 데이터를 쓸 때
} SYSDBG_COMMAND;
typedef NTSTATUS ( __stdcall *ZWSYSTEMDEBUGCONTROL ) ( IN SYSDBG_COMMAND SysDbgChunks,
IN OUT PMEMORY_CHUNKS pQueryBuff,
DWORD dwSize, DWORD, DWORD, NTSTATUS *pResult);
IN OUT PMEMORY_CHUNKS pQueryBuff,
DWORD dwSize, DWORD, DWORD, NTSTATUS *pResult);
class CKernelMemory
{
ZWSYSTEMDEBUGCONTROL m_ZwSystemDebugControl;
public:
CKernelMemory(void);
~CKernelMemory(void);
CKernelMemory(void);
~CKernelMemory(void);
BOOL Init(HANDLE hProcess);
BOOL ReadVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize);
BOOL WriteVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize);
BOOL WriteVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize);
protected:
BOOL EnablePrivilege(LPCSTR lpName, HANDLE hProcess);
BOOL GetNativeAPIAddress();
BOOL EnablePrivilege(LPCSTR lpName, HANDLE hProcess);
BOOL GetNativeAPIAddress();
};
KenelMemory.cpp
#include "stdafx.h"
#include "KernelMemory.h"
#include "KernelMemory.h"
CKernelMemory::CKernelMemory(void)
{
m_ZwSystemDebugControl = NULL;
}
{
m_ZwSystemDebugControl = NULL;
}
CKernelMemory::~CKernelMemory(void)
{
}
{
}
BOOL CKernelMemory::Init(HANDLE hProcess)
{
if (!EnablePrivilege(SE_DEBUG_NAME, hProcess))
{
return FALSE;
}
{
if (!EnablePrivilege(SE_DEBUG_NAME, hProcess))
{
return FALSE;
}
return GetNativeAPIAddress();
}
//Native API의 주소를 얻어온다
BOOL CKernelMemory::GetNativeAPIAddress()
{
//ntdll.dll로드
HMODULE hNTDll;
BOOL CKernelMemory::GetNativeAPIAddress()
{
//ntdll.dll로드
HMODULE hNTDll;
if( (hNTDll = GetModuleHandle("ntdll.dll")) == NULL )
{
if( (hNTDll = LoadLibrary("ntdll.dll")) == NULL )
{
return FALSE;
}
}
{
if( (hNTDll = LoadLibrary("ntdll.dll")) == NULL )
{
return FALSE;
}
}
//ZwSystemDebugControl로드
if( (m_ZwSystemDebugControl = (ZWSYSTEMDEBUGCONTROL)GetProcAddress(
hNTDll, "ZwSystemDebugControl")) == NULL )
{
return FALSE;
}
if( (m_ZwSystemDebugControl = (ZWSYSTEMDEBUGCONTROL)GetProcAddress(
hNTDll, "ZwSystemDebugControl")) == NULL )
{
return FALSE;
}
return TRUE;
}
}
//가상 메모리 공간을 읽어온다
BOOL CKernelMemory::ReadVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize)
{
NTSTATUS result;
//메모리 청크 구조체
MEMORY_CHUNKS QueryBuff;
QueryBuff.pVirtualAddress = pAddress; //가상 메모리 주소
QueryBuff.pBuffer = pBuffer; //버퍼의 주소
QueryBuff.dwBufferSize = dwBufferSize; //버퍼의 크기
MEMORY_CHUNKS QueryBuff;
QueryBuff.pVirtualAddress = pAddress; //가상 메모리 주소
QueryBuff.pBuffer = pBuffer; //버퍼의 주소
QueryBuff.dwBufferSize = dwBufferSize; //버퍼의 크기
//가상 메모리 공간을 읽어서 버퍼에 기록한다
m_ZwSystemDebugControl(SysDbgCopyMemoryChunks_0, &QueryBuff,
sizeof(MEMORY_CHUNKS), NULL, 0, &result);
m_ZwSystemDebugControl(SysDbgCopyMemoryChunks_0, &QueryBuff,
sizeof(MEMORY_CHUNKS), NULL, 0, &result);
return NT_SUCCESS(result);
}
}
//가상 메모리 공간에 데이터를 쓴다
BOOL CKernelMemory::WriteVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize)
{
NTSTATUS result;
BOOL CKernelMemory::WriteVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize)
{
NTSTATUS result;
//메모리 청크 구조체
MEMORY_CHUNKS QueryBuff;
QueryBuff.pVirtualAddress = pAddress; //가상 메모리 주소
QueryBuff.pBuffer = pBuffer; //버퍼의 주소
QueryBuff.dwBufferSize = dwBufferSize; //버퍼의 크기
MEMORY_CHUNKS QueryBuff;
QueryBuff.pVirtualAddress = pAddress; //가상 메모리 주소
QueryBuff.pBuffer = pBuffer; //버퍼의 주소
QueryBuff.dwBufferSize = dwBufferSize; //버퍼의 크기
//버퍼로 부터 값을 읽어서 가상 메모리 공간에 기록한다
m_ZwSystemDebugControl(SysDbgCopyMemoryChunks_1, &QueryBuff,
sizeof(MEMORY_CHUNKS), NULL, 0, &result);
m_ZwSystemDebugControl(SysDbgCopyMemoryChunks_1, &QueryBuff,
sizeof(MEMORY_CHUNKS), NULL, 0, &result);
return NT_SUCCESS(result);
}
}
BOOL CKernelMemory::EnablePrivilege(LPCSTR lpName, HANDLE hProcess)
{
//권한 토큰 구조체
TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
//lpName으로 지정된 권한 이름에 대한 LUID를 얻어낸다
LookupPrivilegeValue(0, lpName, &priv.Privileges[0].Luid);
{
//권한 토큰 구조체
TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
//lpName으로 지정된 권한 이름에 대한 LUID를 얻어낸다
LookupPrivilegeValue(0, lpName, &priv.Privileges[0].Luid);
//프로세스의 토큰 핸들을 얻고
HANDLE hToken;
OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);
HANDLE hToken;
OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);
//입력받은 권한으로 프로세스 권한을 바꾼다
AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof(TOKEN_PRIVILEGES), 0, 0);
AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof(TOKEN_PRIVILEGES), 0, 0);
BOOL rv = GetLastError() == ERROR_SUCCESS;
CloseHandle(hToken);
return rv;
}
return rv;
}