Здесь планируется выкладывать готовые проекты написанные на VB6, с кратким описанием. Если проект большой (описание не помещается в лимит одного сообщения), то нужно создать новую тему, а сюда указать ссылку с кратким описанием. Тоже самое если проект оформлен как статья.
3D ёлка на рабочий стол Процедурно-генерируемая ёлка с множеством регулируемых параметров. Для работы нужна dx8vb.dll (внутри архива, положить в папку с программой). Выход по двойному клику. С наступающим новым годом!
Круговой визуализатор спектра Представляю исходный код и скомпилированную программу графического визуализатора звукового спектра. Звук анализируется через стандартное устройство записи Windows, т.е. можно выбрать микрофон и просматривать спектр с него, либо выбрать стереомикшер и просматривать спектр воспроизводимого звука. В данном визуализаторе имеется возможность регулировки количества отображаемых октав, регулировка прозрачности фона, усиления. Также имеется возможность загрузки палитры из внешних файлов формата PNG в формате 32ARGB, эффекты затухания "размытие" и "горение". Данный визуализатор позволяет просматривать спектр в двух режимах, в виде дуг (колец) и в виде секторов. В первом виде радиальная координата отвечает за частоту по октавам, угловая - между октавами. Гармоники отстоящие от друг друга на октавы, находятся по одну линию, цвет - интенсивность. Во втором режиме, радиальная координата - уровень громкости, цвет - частота, угловая координата - частота (период - 1 октава). Данную идею мне предложил Владислав Петровкий aka Хакер, только в его задумке немного по другому должен был отображаться спектр в виде кривой, я сделал в виде секторов.
Фрактал Julia. Мне очень нравятся фракталы и фрактальные множества. Написал несколько тестовых программ, где можно генерировать и менять параметры у разных фракталов. В этом примере можно генерировать множество Жюлиа а также менять все параметры генерации (в том числе загружать палитру из картинок). Чтобы программа не подвисала, я генерацию и отрисовку засунул в другой поток. Пример не работает в IDE, работает только в скомпилированном виде.
4d гиперкуб (тессеракт) У меня всегда вызывали интерес четырехмерные фигуры, и вообще многомерные пространства. Решил написать небольшую програмку где можно покрутить 4-хмерный гиперкуб в 4-хмерном простанстве в 6-ти плоскостях. В принципе, таких программ много, но я решил написать на любимом VB6, к тому же, с небольшой доработкой можно сделать и другие фигуры. Куб состоит из 6-ти граней, квадратов. Т.к. отрисовка идет линиями, вполне можно рисовать 4 грани, аналогично и гипеперкуб, можно нарисовать всего 4-куба, а не все 8, остальные будут состоять из примыкающих граней этих фигур. Для наглядности, на вершинах гиперкуба я сделал окружности, цвет и размер которых соостветствует Т координате (меньше и темнее - дальше по оси Т).
FM-синтезатор на VB6 (Trick FM) Как-то давно занимался изучением синтеза звука, в частности FM (частотная модуляция) методом. Была написана тестовая программка-синтезатор. Сегодня я ее подправил немного, сделал GUI и т.п. Характеристики: 6 осцилляторов 6 форм волн ADSR огибающая для каждого осциллятора Модуляционная матрица 6x6 + 6 для вывода звука. Гейт на 16 частей с регулировкой жесткости В общем полноценный FM синтезатор. Клавиши: Z-C5 S-C#5 X-D5 D-D#5 C-E5 V-F и т.д Q-C6 I-C7 Для работы нужна библиотека dx8vb.dll
Создание GIF-анимации с прозрачным фоном на VB6 Максимальный размер картинок 640х640. В принципе для анимаций без прозрачного фона, а также анимаций с ColorKey цветом прозрачности эта задача очень просто решается с помощью библиотеки GDI+, но у нее, как я выяснил при написании этой тестовой программы, есть недостаток - она не позволяет задать свойство восстановления фона анимации, по крайней мере в MSDN про это ни слова. Это проявляется в виде неприятного наложения кадров друг на друга, когда фон непрозрачен - это не заметно. Для предотвращения этого явления, я решил вручную находить нужные байты и править их "руками". В своем примере я также вычисляю оптимальную палитру с помощью октодерева, поэтому качество получаемых GIF-анимаций получается довольно-таки хорошим. Также имеется возможность настройки каждого кадра (длительность, порог прозрачности) и счетчика повторов. Для отключения прозрачности достаточно в поле Threshold выставить 0, чем выше значение в этом поле, тем больше полупрозрачных пикселей станут полностью прозрачными. Пример я хорошо прокомментировал , особенно в местах, где идет преобразование и сохранение. Тестировалось на Win7 x64. На WinXP - не работает сохранение.
Library info 2 Проект который позволяет просматривать некоторую информацию о 32 битных PE файлах, а именно: Export; Import; Delay import; Для библиотек типов и PE файлов содержащих библиотеки типов внутри: Interfaces; CoClasses; Types; Enumerations; Aliases. Для компиляции нужна библиотека Edanmo's OLE interfaces & functions (olelib.tlb) (конечный EXE не требует ее).
"Линза" на VB6 С помощью этой простой программы можно просматривать под увеличением определенный участок экрана, увеличение можно изменять колесиком, выход - ESC.
Наглядный пример FM (PM) синтеза на VB6 Наглядный пример FM (PM) синтеза, форму волны можно визуально наблюдать. Регулятором Tone добейтесь "стабильной" картинки и регулируйте параметры. Элементы матрицы регулируются зажатием и перемещением мыши в соответствующем текстбоксе. Для работы нужен dx8vb.dll
Всем привет! Сегодня я хотел бы поговорить о криптографии. Я сделал пример использования специальной криптографии - стеганографии. Этот метод скрывает сам факт шифрования данных. Существует множество видов стеганографии. Я бы хотел поговорить о LBS-методе, в котором данные скрываются в младших битах аудио данных. Это выглядит так, как-будто пользователи обмениваются аудио файлами, но на самом деле они обмениваются секретными данными. Тот кто не знает об этом методе не будет даже подозревать о обмене секретными данными. В некоторых случаях это может быть очень полезно. Как это работает? WAVE-PCM файл (без компрессии) содержит аудио данные. На самом деле звук является аналоговым событием, т.е. непрерывным. Для того чтобы перевести его в цифровую форму нужно проквантовать его с некоторыми потерями. Этот процесс характеризуется двумя параметрами: разрядностью и частотой дискретизации. Разрядность влияет на то как много уровней сигнала может содержаться в каждом семпле. Частота дискретизации влияет на то какая максимальная частота может содержатся в аудиоданных: В нашем случае нас интересует только разрядность аудиоданных. Она может быть 32, 24, 16, ... бит на семпл. Главная идея стеганографии (в нашем случае) - переписать младшие биты аудиоданных. Чем больше бит мы будем использовать, тем сильнее будут искажения. Наглядно: Как видно из рисунка метод сохраняет все шифруемые данные в определенных битах аудиоданных (в данном случае 4 бита на каждый семпл). Также заметьте что для сохранения данных нужно использовать аудио файл бо́льший по размеру чем шифруемый файл. Для примера, если мы будем использовать 3 бита для кодирования, аудиофайл должен будет иметь размер как минимум в 16/3 раза больше чем кодируемый. Я говорю 16 потому что я использую 16 бит на семпл в моем примере. В прикрепленном примере я также сохраняю оригинальное имя файла. Формат данных наглядно: Когда происходит упаковка берется каждый байт из шифруемого файла. Затем извлекается необходимые биты из очередного байта, а также очищаются соответственные биты в аудиоданных. Далее эти биты устанавливаются посредством операции побитовое-ИЛИ. Для извлечения необходимых бит используются маски и сдвиги. Маски оставляют необходимые биты, а сдвиги размещают их в начале байта. Распаковка происходит с точностью наоборот. Извлекаются биты из аудио файла и собирается исходный файл. Спектр аудиофайла в зависимости от битности: Надеюсь что этот небольшой обзор будет полезным. Спасибо за внимание.
Внедрение в чужой процесс на VB6 (без DLL) Всем известна утилита SPYXX. С помощью нее можно делать много чего интересного. В числе ее возможностей - просмотр сообщений отправленных окну и результаты их обработки. Я решил сделать что-то подобное только на VB6 (не в качестве создания программы типа SPYXX, а в качестве демонстрации возможности внедрения кода из VB6, так что функционал проги очень маленький). Как известно SPYXX делает это с помощью глобальных хуков, но мне была интересна идея внедрения без DLL (c DLL все гораздо проще можно сделать, у Рихтера описано как можно несколькими функциями внедрится в чужой код с помощью DLL) и я решил сделать немного по другому. В моем примере код вместе с оконной процедурой непосредственно копируется в АП нужного процесса и там запускается (работает только с 32 разрядными приложениями). Там я размещаю код, который устанавливает новую процедуру обработки сообщений, для окна и усыпляю поток. В новой процедуре, я всего лишь передаю параметры, которые получило чужое окно, моему окну (frmSpy), далее вызывается оригинальная процедура окна. Скажу сразу - передача осуществляется не самым эффективным способом, можно было сделать гораздо эффективнее напрямую работая с FileMapping'ом, либо асинхронно передавать 2 сообщения подряд. Но я не стал заморачиваться лишним кодом, т.к. моя конечная цель не эффективность. Отмена инъекции осуществляется пробуждением потока и завершению его естественным образом, после чего из своей программы я освобождаю ресурсы. Работу я проверял в отладчике все работает, как и задумывалось. Приведу здесь текст шеллкода: Код (Visual Basic): ' Данный код выполняется в АП чужого процесса, поэтому он не имеет понятия ни о каких глобальных или локальных переменных ' уровня этого модуля, единственная область памяти с которой он может работать передаеться ему указателем на структуру ' TrickThreadData, который в последствии сохраняется в свойстве окна 'pInject'. Вызов наших функций, ведет к перенапрвлению ' к соответствующим API функциям. Здесь выполняется код, который вообще не использует рантайм. Для использования функций ' рантайма (сейчас о функциях которые не требуют инициализацию контекста потока), нужно его предварительно загрузить, через ' LoadLibrary() и получить адреса функций через GetProcAddress(). Все символьные имена и переменные, нужно хранить в ' в выделенной для этого предварительно памяти. Так что обращение к любой глобальной переменной или константе ' (пример s$="VB6 best language") может вызвать ошибку доступа ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ' Процедура, выполняемая в чужом процессе, передаем ей указатель на данные Private Sub InjectionProc(Dat As TrickThreadData) Dim lpOldProc As Long ' Мы в чужом процессе )) mySetProp Dat.SrcWnd, PropCur, Dat.AddrStructure ' Устанавливаем окну свойство с указателем на данные lpOldProc = mySetWindowLong(Dat.SrcWnd, GWL_WNDPROC, Dat.AddrWindowProc) ' Устанавливаем окну новый оконный обработчик ' Вместо нового адреса процедуры пишем старое Dat.AddrWindowProc = lpOldProc ' Замораживаем поток myWaitForSingleObject Dat.EventHandle, INFINITE ' Поток разморожен, значит надо возвращать все на место mySetWindowLong Dat.SrcWnd, GWL_WNDPROC, Dat.AddrWindowProc myRemoveProp Dat.SrcWnd, PropCur ' Закрываем описатель события myCloseHandle Dat.EventHandle ' Все поток закончен, теперь Clear разморозится и очистит занимаемую память End Sub ' Прцедуры вызова соответствующих API c помощью сплайсинга Private Function myCopyMemory(dst As TrickThreadData, ByVal src As Long, ByVal Length As Long) As Long myCopyMemory = -1 End Function Private Function myCopyMemory2(ByVal dst As Long, src As TrickThreadData, ByVal Length As Long) As Long myCopyMemory2 = -2 End Function Private Function mySetProp(ByVal hwnd As Long, ByRef Name As Currency, ByVal Value As Long) As Long mySetProp = -3 End Function Private Function myGetProp(ByVal hwnd As Long, ByRef Name As Currency) As Long myGetProp = -4 End Function Private Function myRemoveProp(ByVal hwnd As Long, ByRef Name As Currency) As Long myRemoveProp = -5 End Function Private Function mySetWindowLong(ByVal hwnd As Long, ByVal Index As Long, ByVal Data As Long) As Long mySetWindowLong = -6 End Function Private Function myWaitForSingleObject(ByVal hEvent As Long, ByVal Millisecond As Long) As Long myWaitForSingleObject = -7 End Function Private Function mySendMessage(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, lParam As COPYDATASTRUCT) As Long mySendMessage = -8 End Function Private Function myCallWindowProc(ByVal addr As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long myCallWindowProc = -9 End Function Private Function myCloseHandle(ByVal Handle As Long) As Long myCloseHandle = -10 End Function ' Оконная функция, которая будет работать в чужом процессе Private Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Dim lpDat As Long, Dat As TrickThreadData, CDS As COPYDATASTRUCT lpDat = myGetProp(hwnd, PropCur) myCopyMemory Dat, lpDat, Len(Dat) ' Копируем параметры ' Устанавливаем параметры сообщения Dat.Msg.Msg = uMsg Dat.Msg.wParam = wParam Dat.Msg.lParam = lParam myCopyMemory2 lpDat, Dat, Len(Dat) ' Копируем параметры обратно CDS.cbData = Len(Dat.Msg) CDS.lpData = lpDat + 20 ' Смещение структуры MessageInfo, относительно данных ' Отправляем нашему окну уведомление mySendMessage Dat.DesthWnd, WM_COPYDATA, hwnd, CDS ' Вызываем процедуру по умолчанию WindowProc = myCallWindowProc(Dat.AddrWindowProc, hwnd, uMsg, wParam, lParam) End Function ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ' Эта функция также служит маркером конца функции и в процесс не копируется Private Function AddrOf(Value As Long) As Long AddrOf = Value End Function При работе в другом процессе, вообще не используется рантайм, хотя можно его загрузить и использовать (про инициализацию контекста потока отдельно) его функции, массивы строки и т.п. Также возникает проблема работы с переменными, т.к. глобальных переменных "не существует", и соответственно обращение к любым таким переменным может оказаться фатальным для всего процесса. Для вызова API я использую сплайсинг "псевдофункций API", заменяю вызов на безусловный переход к нужной функции. Работа с переменными осуществляеться в выделенной для этого области. Для того чтобы ее сохранить я использую SetProp, т.к. из WindowProc я могу что-то идентифицировать только через hWnd. Если надо добавить еще какие-либо глобальные переменные, то можно в этой области выделить место под строки и т.п. (например для вызова LoadLibrary с нужным параметром). Если бы в VB была непосредственная работа с указателями (без VarPtr, GetMem и т.п. функций), то было намного проще. Можно делать сразу ассемблерный переходник и в нем можно узнать значения переменных переданных в поток без SetProp и CopyMemory, но это детали, кто захочет - тот сделает.
Запись данных в ресурсы своего EXE из "себя" VB6 Бывают ситуации, когда хочется где-то сохранить данные после работы программы, но не хочется иметь внешних файлов-зависимостей, записей в реестре и т.п. Зато можно хранить данные в своем EXE, но Windows не позволяет писать в работающий EXE (NTFS потоки не рассматриваю), и любая попытка будет отвергнута с ошибкой ERROR_ACCESS_DENIED. Можно еще переименовать свой EXE файл и создать новую копию со старым именем и в нее уже писать данные, но это не так интересно ). Если процесс завершить, то можно из другого процесса уже в него спокойно записывать данные. Вот по этому пути я и решил пойти. В моем примере я запускаю cmd.exe в приостановленном состоянии, создаю код, который будет внедряться в него и изменять ресурсы нашего EXE, и запускаю его. В свою очередь тот код ждет завершения нашего процесса и по завершении переписывает нужные нам данные (мы их предварительно туда передали) и завершается: Код (ASM): ' Код на ассемблере (NASM) '[BITS 32] '; ThreadProc 'mov esi,dword [esp+0x04]; ESI = &dat 'xor ebx,ebx ; Const 0& 'push ebx ; Dim hRes As Long 'push 0xFFFFFFFF ; INFINITE 'push dword [esi+0x00] ; dat.hParent 'call [esi+0x14] ; WaitForSingleObject dat.hParent, INFINITE 'push dword [esi+0x00] ; dat.hParent 'call [esi+0x18] ; CloseHandle dat.hParent 'push ebx ; False 'push dword [esi+0x04] ; dat.lpFileName 'call [esi+0x1c] ; BeginUpdateResource(dat.lpFileName, False) 'mov [esp],eax ; hRes = eax 'test eax,eax ; IF hRes=0 'je ExtProc ; GoTo ExtProc 'push dword [esi+0x10] ; dat.dwDataCount 'push dword [esi+0x0c] ; dat.lpData 'push ebx ; 0 'push dword [esi+0x08] ; dat.lpRsrcName 'push 0x0000000a ; RT_RCDATA 'push dword [esp+0x14] ; hRes 'call [esi+0x20] ; UpdateResource hRes, RT_RCDATA, dat.lpRsrcName, 0, ByVal dat.lpData, dat.dwDataCount 'push ebx ; False 'push dword [esp+0x04] ; hRes 'call [esi+0x24] ; EndUpdateResource hRes, False 'ExtProc: 'push ebx ; 0 'call [esi+0x28] ; ExitProcess 0 Дабы не мудрить с VB-шным кодом и ограничиться одной формой, я решил внедряемый код сделать на ассемблере, так и проще и меньше кода писать (исходник прилагаю). Т.к. код написан исключительно для ознакомления и тестирования в нем нет синхронизации (например можно запустить копию, прежде чем запишутся данные, или запустить несколько экземпляров), т.к. для примера она не нужна, по хорошему ее надо поставить, но это уже отдельный разговор.
MP3 -> WAV конвертер. Всем привет! Представляю простую реализацию конвертера MP3 файлов в WAV используя ACM.
Анатолий Анатольевич (Thetrik), здравствуйте! Благодарю Вас! Совершенно замечательный проект! У меня есть два вопроса: 1. Я хочу этот проект переложить на VBA. Не возражаете ли Вы против этого? 2. Если не возражаете, то второй вопрос - в листинге встречается конструкция "frmTest.hwnd". Интуитивно понимаю, что "hwnd" это шестнадцатеричный хэндл окна, в котором спектр живет. Не могу по коду найти точку, в которой этот хэндл рождается и наполняется содержанием. Расскажите, пожалуйста об этом. Спасибо!
Не возражаю, даже рад. hWnd - это хендл окна. В VB6 я использовал готовую форму. Для VBA можно, я думаю использовать UserForm, либо создать окно вручную через WinAPI.
Спасибо за ответ! Я попытался так сделать до того, как Вам написал. Проблемой оказалось то, что у формы VBA "UserForm" нет свойства hWnd. Такое свойство есть у объекта Application. Но я сомневаюсь в том, что Application.Hwnd получится использовать. Прошу Вас пояснить какая очередность создания объектов: 1. окно через WinAPI, выполняет роль контейнера и предоставляет свойство hWnd; 2. форма VBA "UserForm" размещается в окне (как-то их связать между собой нужно?) Или все это не правильно? Напишите, пожалуйста, если Вам не тяжело.
Другими словами, нужно создать конструкцию "frmTest.hwnd". В моем понимании это объект форма VBA "frmTest" с присущим свойством от другого объекта окна ОС "hwnd". Если этот вывод правильный, то не понимаю, как из того можно вывернуться.
Можно получить HWND UserForm, вот к примеру метод. Также можно создать простое немодальное окно через CreateDialogIndirectParam (функция вернет HWND). Просто оберни в класс логику.
Thetrik, немного не в тему, но - как работает вб6 на новых 64 битных десятках? Нет ли тенденции к выпиливанию этой дллки (если мне не изменяет память, vb6 не развивается с 98 или какого года).