Статья ASM для х86. (5.1.) WinSock – работа с портами

logo_2.png
После вводной части перейдём к практике..
Cетевое хозяйство лежит на балансе виндовых библиотек в числе которых и wsock32.dll. Эта устаревшая либа пришла в наш век из прошлого и опирается на сокеты Беркли юникса – версия её WinSock v1.1. Начиная с Win-2000 мелкософт отошла от старых принципов, и полностью обновила библиотеку до версии 2.0, поместив новоиспечённые функции внутрь отдельной либы ws2_32.dll. Прежняя версия тоже осталась для совместимости с уже написанными на ней программами, только все дорожки из неё ведут опять к усовершенствованной ws2_32.dll. Проверить это можно в Hiew'e, запросив у него экспорт последовательностью Enter->F8->F9:

w32_ws32.png


Таким образом, мы можем с чистой совестью вызывать старые функции, тем-более что некоторые из них wsock32 исполняет всё-таки сама – это getsockopt(), recv(), recvfrom() и т.д. на скрине выше. Однако в новой либе есть и функции, которых нет в предыдущей версии. В этом случае придётся звать их напрямую из ws2_32.dll - они начинаются с приставки WSA_xxx().

Под большим системным замком, в подвале сетевой архитектуры трудятся ещё и драйвера, во-главе которых стоит дров интерфейса с сетевым адаптером NDIS.SYS, и драйвер транспортного протокола TDI. Грязными красками иерархию программной части сети можно расписать так:

tcp_ip_01.png


На рисунке выше видно, что сетевые сокеты не вмешиваются в работу уровня приложений. В их задачи входит принять пакет-данных от софта и обернув его в красивый фантик, отправить получателю на другом конце связи. Сокеты – анархисты. Они не зависят ни от какого протокола, а наоборот подминают их под себя. При создании сокета, в его параметрах мы просто указываем уровень, на котором примем пакет отправителя. Например если в аргументе указать PROTO_IP, то пакет попадёт в наши руки уже после уровня TCP (или UDP). За это время протокол TCP уже мог что-нибудь сотворить с пакетом, и к нам он попадёт уже не "в чём мать родила".

С другой стороны, мы можем создать IP-сокет, который будет отправлять пакетики в сеть сразу с уровня IP. В этом случае TCP уже останется за бортом, и даже не будет знать о наших действиях. Другими словами, непосредственно из прикладной программы у нас имеется легальный доступ к любому уровню стека протоколов TCP/IP. Это открывает большие возможности. Что-то подобное делает например PING, доставая клиентов своими ICMP эхо-запросами.

Если-же мы хотим шифровать исходящий трафик, то делать это лучше на самом-верхнем уровне приложений, ..желательно вообще до стека протоколов, перехватывая непосредственно клавиатурный ввод юзера. А так.. ксорить траф можно на любом из уровней. Только если на другом конце связи его во-время не расшифровать, то из-за несовпадения контрольной суммы протоколы следующих уровней начнут просто дропать такие пакеты, отправляя их к праотцам. То-есть мы должны писать сразу клиент-серверное приложение и придумать для него свой протокол, которой будет расшифровывать наши данные. Это не так сложно, как может показаться на первый взгляд.

sockHome.png


Socket как сущность – это комбинация трёх составляющих: IP-адрес, порт, и протокол. При создании сокета мы должны указать именно эти три аргумента, чтобы он мог присутствовать в системе, как самостоятельная личность:
SOCKET = 127.0.0.1 :69 :UDP.

"Интернет сессия" – это один цикл связи клиента и сервером. Сессия может продолжаться бесконечно, пока одному из участников это не надоест. TCP-cессия состоит из трёх фаз: Привет -> Обмен данными -> Пока! Нужно помнить, что сокеты привязываются к сессиям, и если во-время сессии связь нечаянно оборвётся, то сокет этой сессии становится недействительным, и закрыв его – нужно создать новый. Это основная ошибка, которую допускают новички.

В штанинах XP и 7 для нас припрятаны 32768 резервных сокетов. Такое кол-во позволяет создавать их пачками, для каждой сессии отдельно. Причём половина сокетов может прослушивать входящий трафик (т.н. демоны), а половина работать на приём/передачу. На серверных системах резерва ещё больше, т.к. они обслуживают по-более клиентов за раз, и для каждого нужен свой сокет. При создании большого числа сокетов главное не потеряться в них.

В природе имеются блокирующие и неблокирующие сокеты. Первые работают в синхронном режиме, а вторые в асинхронном. Разница их в том, что блокирующий сокет останавливает ход программы до тех пор, пока не выполнит свою задачу. Этим отличаются устаревшие функции из библиотеки wsock32.dll. Соответственно, неблокирующий НЕ ждёт ответа от сервера, а отправив запрос сразу передаёт управление на сл. участок кода программы. В этом случае, следить за состоянием неблокирующего сокета должна отдельная Call-Back функция. Управлять режимом работы сокета позволяет функция ioctlsocket(), с кодом операции FIONBIO No Blocket I/O.
зы, прелюдия что-то растянусь..


5.1. Под копотом..

Если мы планируем работать с сокетами, то промышленная реализация алгоритма одной сессии выглядит так:
  1. WSAStartup() – инициализация библиотеки wsock32.dll;
  2. soсket() – создание сокета определённого типа;
  3. bind() – привязать к этому сокету сетевой адрес собеседника (IP, порт, протокол);
  4. connect() – попытка соединения с ним..;
  5. send() – если связь установлена, то отправить собеседнику пакет данных;
  6. recv() – принять от него ответный пакет;
  7. --- здесь если надо, то крутим цикл send() ---
  8. shutdown() – попрощаться с абонентом, и разорвать соединение;
  9. closesocket() – освободить занимаемый сокет.
Мда.. не радужная перспектива..
На самом деле не всё так плохо, ведь перед нами самый сложный протокол из всех – протокол надёжной связи TCP. Если сокет у нас TCP, то мы можем убрать bing(), поскольку функция connect() сама привязывает сетевой адрес к сокету. А вот в случае с UDP ничто не мешает отправить на скамейку запасных функции connect() и shutdown(), т.к. это протокол без предварительной установки связи. Однако пролог алгоритма в виде первых трёх функций должен присутствовать всегда.

Ещё одна тонкость связана с форматом сетевых адресов, таких как IP и номер порта – функциям WinSock их нужно передавать в прямом порядке Big-Endian, в то время-как процессоры Intel/AMD используют обратный порядок байт Litle-Endian. Например IP-адрес 127.0.0.1 будет находится в памяти процессора как 4-байтное значение: 01 00 00 7F – это и есть LitleEndian, когда младший байт первый. Но функции WinSock требуют прямого порядка как мы записываем их на бумажке, т.е. 7F 00 00 01 или Big-Endian. Под этот-же каток попадают и номера портов, только они не 4-байтные, а 2. На сишном жаргоне размер определяется как LONG(4) и SHORT(2).

Для преобразования порядка байт из обычного в сетевой, предусмотрены WinSock функции htonl() и htons(). В дословном переводе это означает "Hex-To-Net-Long" (для преобразования 4 байтных IP-адресов) и "Hex-To-Net-Short" (для 2 байтных номеров порта). Когда сервер нам будет отвечать, ясный-перец он тоже отправит нам IP-адрес и порт в сетевом порядке байт. Если мы захотим их вывести на экран, то должны применить обратное преобразование, для чего имеются функции ntohl() и ntohs() – соответственно для LONG и SHORT. Такая вот хрень с этими адресами..

Ну и альфа-самцом во всей этой кухне является конечно-же файл с инклудами, которыми FASM к сожалению не может похвастаться. В его папке include\api есть wsock32.inc, в котором перечислены все знакомые ему сетевые функции. Ещё в одном дире include\equates под таким-же названием лежит инклуд с описанием служебных WinSock-структур. Здесь конечно разраб фасма Томаш Грыштар чуток подкачал, и перечислил только критические структуры без которых ну совсем уж никак. Поэтому я дополнил этот инклуд своими структурами, которые собирал со-всех источников. Он лежит в скрепке этого топика, а вам нужно просто заменить им текущий, из папки ..\equates. В нём я описал форматы заголовков всех уровней стека, от TCP и до Ethernet фрейма. Внимание!!! Без этого инклуда, представленные ниже программы работать не будут!

Чтобы было без соли, код будем писать консольный, а для ввода-вывода на экран подключим msvcrt.dll с её функциями printf() и scanf(). Первой можно передавать не ограниченное число аргументов, что позволит выводить сразу кучу информации. Вторая scanf() – для ввода с клавиатуры и считается уязвимой (юзер может переполнить приёмный буфер), поэтому выделим для неё резиновый буфф в конце секции-данных и пусть переполняет эту 4К-байтную секцию, пока не надоест. Её можно было-бы заменить на ReadConsole(), которая ограничивает ввод. Но эта read слишком громоздкая для обычного ввода, а мы стремимся к минимализму.


5.1.0. Программа перечисления портов

Начнём с того, что перечислим все зарезервированные порты на своей машине.
Нужно сказать, что среди WinSock-функций есть информационные функции, для которых не нужно создавать сокеты. Они работаю в офф-лайн и тупо предоставляют нам различную инфу. Две из таких функций я оформил в программу ниже – это WSAStartup() и getservbyport(). Первая загружает библиотеку WinSock и возвращает в структуру "WSADATA" её паспорт. Запрашивая смещения из этой структуры, мы можем выводит из неё инфу на экран. Если функция выполняется удачно, то возвращает нуль:

C-подобный:
invoke  WSAStartup, 0x0101, wsa     ;// 0x0101 = запрашиваемая версия v1.1
                                    ;// wsa = указатель на структуру WSADATA
;//-------------------------------------------------------------------------
struct WSADATA                      ;// всего 400 байт (0x190)
   wVersion       dw  0               ; мин.версия WinSock (обычно v1.1)
   wHighVersion   dw  0               ; макс.версия (обычно v2.2)
   szDescription  db  256+1 dup(0)    ; строка с текущей версией
   szSystemStatus db  128+1 dup(0)    ; строка с текущим статусом (Run/Stop)
   iMaxSockets    dw  0               ; сколько TCP-сокетов можно создать
   iMaxUdpDg      dw  0               ; макс.размер UDP-датаграммы
   _padding_      db  2 dup(0)        ; резерв (байты выравнивания)
   lpVendorInfo   dd  0               ; указатель на данные производителя
ends

Вторая функция getservbyport() занимается тем, что по номеру порта заполняет уже свою структуру "servent". Если вызов успешный, то возвращает в EAX указатель на эту структуру, иначе нуль. Смысловая нагрузка приёмного буфера "servent" выглядит так:

C-подобный:
invoke  getservbyport, port, 0      ;// port = номер порта, о котором хотим собрать инфу
                                    ;// 0 = все протоколы (можно фильтровать TCP или UDP)
;//-------------------------------------------------------------------------------------
struct servent          ;// getservbyport (port, *proto)
   s_name       dd  0      ; линк на строку с именем сервиса
   s_aliases    dd  0      ; линк на NULL-массив альтернативных имён
   s_port       dw  0      ; номер порта
   s_zero       dw  0      ; резерв
   s_proto      dd  0      ; линк на строку с именем протокола
ends

Как говорилось выше, WinSock-функции насилуют драйвера TDI и NDIS. Понаблюдать за этим процессом в замочную скважину можно так.. Запускаем системный "Дисчетчер задач" и в меню вид устанавливаем галку "Вывод времени ядра". Теперь в окне "Быстродействие" диспетчера появится вторая шкала красного цвета, которая и покажет время обращения нашей софтины к ядерному уровню драйверов. Как выяснилось, не все функции прибегают к услугам драйвера – некоторые вполне самостоятельны.

Программа ниже выполняет перечисленные действия, и выводит инфу по каждому порту на экран. Вся нагрузка лежит тут на функции getservbyport(), которой в цикле подставляю следующий порт, пока счётчик не достигнет максимального порта под номером 65535. Ещё одна с прозрачным именем gethostname() возвращает имя нашего узла и сбрасывает его в буфер, на который указывает аргумент. Если выполнилась удачно – в EAX возвращает нуль:

C-подобный:
format   pe console
entry    start
include 'win32ax.inc'
;----------
.data
wsa        WSADATA
sPort      servent
wsaInfo    db  13,10,' %s         %s'
           db  13,10,' Sockets count.....: %d'
           db  13,10,' UDP-datagramm size: %d',0
hName      db  13,10,' Host name.........: %s',0
capt       db  13,10
           db  13,10,' Enum Host Port-name v0.1'
           db  13,10,' ============================',0
mes0       db  13,10,' Port  %05d  %s - %s',0
mesEnd     db  13,10,' ============================'
           db  13,10,' Total: %d ports',13,10,0
buff       db  64 dup(0)
count      dd  0
frmt       db  '%s',0
;----------
.code
start:
;// инициализация библиотеки WinSock, и вывод инфы о ней
         invoke  WSAStartup,0x0101,wsa       ;
         push    0 0                         ; обнулить регистры
         pop     ecx edx                     ; ^^^
         mov     eax,wsa.szDescription       ; версия WinSock
         mov     ebx,wsa.szSystemStatus      ; текущий статус
         mov     cx,[wsa.iMaxSockets]        ; всего сокетов в резерве
         mov     dx,[wsa.iMaxUdpDg]          ; макс.размер UDP-датаграммы
        cinvoke  printf,wsaInfo,eax,ebx,ecx,edx   ; выводим шапку

;// Получить имя своего узла
         invoke  gethostname,buff,64
        cinvoke  printf,hName,buff

;// Начало сканирования зарегистрированных портов
        cinvoke  printf,frmt,capt         ; выводим шапку
         mov     ecx,0xffff               ; всего портов 65535 (word)
         xor     eax,eax                  ; начинать с нулевого
@scan:   push    eax ecx                  ; запомнить номер порта и счётчик!
         invoke  htons,eax                ; переводим #порта в сетевой порядок (..s это Short)
         invoke  getservbyport,eax,0      ; заполняем структуру "servent" по номеру порта
         or      eax,eax                  ; если EAX=0 значит ошибка
         jz      @fuck                    ; пропустить..
         inc     [count]                  ; иначе: "servent" заполнена, и счётчик найденых +1
         xor     ebx,ebx                  ; очистить EBX (в EAX сейчас лежит указатель на "servent")
         mov     bx,word[eax+8]           ; BX = номер порта из структуры "servent"
         xchg    bh,bl                    ; поменять байты местами (из Net в Hex порядок)
         mov     edx,[eax+12]             ; EDX = указатель на имя протокола
         mov     ecx,[eax]                ; ECX = указатель на имя связанного с портом сервиса
        cinvoke  printf,mes0,ebx,edx,ecx  ; выводим инфу порта на экран
@fuck:   pop     ecx eax                  ; порт и счётчик на родину!
         inc     eax                      ; следующий номер порта..
         dec     ecx                      ; счётчик -1
         jnz     @scan                    ; повторить, если счётчик не нуль

;// Выводим кол-во найденных портов
        cinvoke  printf,mesEnd,[count]    ;
        cinvoke  scanf,frmt,frmt+5        ; ждём нажатия клавиши..
         invoke  ExitProcess,0            ; на выход!

;//--- Cекция импорта программы  ------
section '.idata' import data readable   ;
library  kernel32,'kernel32.dll',\      ; импортируемые библиотеки
         wsock32,'wsock32.dll',\        ;
         msvcrt,'msvcrt.dll'            ;
import   msvcrt,printf,'printf',scanf,'scanf'  ; эту FASM не знает, опишем вручную

include 'api\kernel32.inc'         ; остальные функции есть в инклудах фасма.
include 'api\wsock32.inc'          ;

byPort.png


На своей тестовой XP я получил всего 86 занятых портов, хотя на семёрке их уже 174.
Здесь видно, что например порт(43) работает по-протоколу TCP и его прослушивает сервис "NicName - Network Information Center", а это WHOIS. Со всеми этими сервисами нужно будет работать по их собственному протоколу! Получается такая каша, разгребсти которую мы сможем только ко-второму пришествию. Для каждого из них имеется своя документация RFC , в которой описывается способ общения.


5.1.1. Сканер открытых портов

Допустим мы получили список портов. Теперь можно просканировать их и посмотреть, к какому именно порту мы имеем удалённый доступ. Злейшим врагом сканера является файервол (брэндмауэр), который перекрывает кислород всем портам кроме тех, которые админ внёс в список исключений. Таким образом, из 86 портов моей портянки могут быть открыты только некоторые, и наша цель узнать – какие именно.

Суть в том, что мы выбираем узел и пробуем подключиться к каждому из его портов. Если к порту нет доступа, то встречаем ошибку. Поскольку нам нужно устанавливать связь, значит протокол UDP для этих целей не подходит и нужен TCP. Для передачи адреса-узла сокетам и функциям, в WinSock имеется специальная структура "sockaddr_in". Для секетов Беркли это была (теперь устаревшая) структура " in_addr", но её уже отправили на покой и с версии 2.0 заменили новой:

C-подобный:
struct sockaddr_in             ;// всего 16 байт
   sin_family    dw  0            ; тип протокола (всегда AF_INET)
   sin_port      dw  0            ; номер порта
   sin_addr      dd  0            ; 4 байтный IP-адрес узла
   sin_zero      db  8 dup(0)     ; резерв (выравнивание)
ends

Здесь мы видим важное для нас поле sin_port – его и будем менять в цикле, чтобы просканировать все порты данного IP-адреса. Выше говорилось, что с каждому сокету можно привязать только один адрес, но т.к. нам нужно менять в адресном пакете номер порта, значит это будет уже другой адрес. Придётся на каждом шаге закрывать старый сокет, и создавать новый. Если этого не сделать, то функция connect() начнёт атаковать наоборот нас, своими вечными ошибками. Запишем этот факт в свой кэш.. Вот прототип этой функции:

C-подобный:
;// Функция установки связи с удалённым узлом
;//-------------------------------------------
invoke  connect, [s], addr, addr_len

       s – дескриптор сокета;
    addr – указатель на структуру "sockaddr_in";
addr_len – размер этой структуры.

Теперь перенесём всё сказанное в окно FASM'a и получим демонстрационный сканер портов. Скорость его перебора оставляет желать лучшего, и я специально добавил функцию вывода на экран не только открытых портов, но и закрытых, чтобы наглядно видеть шаг (получилось ~1 сек/порт). Чтобы ускорить этот процесс, нужно создать неблокирующий сокет, т.к. в этом примере он блокирующий. Поэтому connect() ждёт результата, что и тормозит повозку.

C-подобный:
format   pe console
entry    start
include 'win32ax.inc'
;//----------
.data
addr     sockaddr_in
wsa      WSADATA
capt     db  13,10
         db  13,10," Port-Scan v0.1"
         db  13,10,' ====================='
         db  13,10,' Please wait...',0
open     db  13,10,' Port  %05d  ***** open',0
close    db  13,10,' Port  %05d  close',0
mes1     db  13,10,' ========================'
         db  13,10,' Scan OK!',0

port     dd  0                       ; текущий порт
s        dd  0                       ; под дескриптор сокета
host     db '127.0.0.1',0            ; кого сканируем
frmt     db  '%s',0                  ; для scanf(), и дальше буфер ввода (там болото нулей)
;//----------
.code
start:  cinvoke  printf,frmt,capt         ; выводим шапку
         invoke  WSAStartup,0x0101,wsa    ; инициализация WinSock

;// Заполняем адресный пакет "sockaddr_in"
         invoke  inet_addr, host            ; IP из строки в Hex
         mov     [addr.sin_addr],eax        ; записать его в поле адреса
         mov     [addr.sin_family],AF_INET  ; протокол = Интернет

;// Начинаем сканирование портов..
@scan:   invoke  htons,[port]               ; #порта в сетевой порядок байт
         mov     [addr.sin_port],ax         ; в пакет адреса его..

         invoke  socket, AF_INET, SOCK_STREAM,0          ; создать TCP сокет (Stream/поток)
         mov     [s],eax                                 ; запомнить его дексриптор
         invoke  connect,[s], addr, sizeof.sockaddr_in   ; пробуем подключиться по адресу
         cmp     eax,-1                                  ; ошибка?
         jnz     @ok                        ; если нет..
        cinvoke  printf,close,[port]        ; иначе: мессага Close и #порта
         jmp     @next                      ;

@ok:    cinvoke  printf,open,[port]         ; порт открыт!
@next:   invoke  closesocket,[s]            ; отработанный сокет на свалку
         inc     [port]                     ; следующий порт..
         cmp     [port],0xffff              ; все порты просканировали?
         jnz     @scan                      ; нет - повторить

;// После (примерно) двух часов - прощальный диалог с юзером
        cinvoke  printf,frmt,mes1         ;
        cinvoke  scanf,frmt,frmt+5        ; ждём нажатия клавиши..
         invoke  ExitProcess,0            ; на выход!

;//---- Секция импорта программы  -----
section '.idata' import data readable
library  kernel32,'kernel32.dll',\
         wsock32,'wsock32.dll',\
         msvcrt,'msvcrt.dll'
import   msvcrt,printf,'printf',scanf,'scanf'

include 'api\kernel32.inc'
include 'api\wsock32.inc'

Любой сканер – это не есть гуд, и чтобы не насканировать себе билеты в Магадан, лучше вообще не заниматься этим (мало-ли хороших дел на свете?). Этот пример тут только для того, чтобы знать откуда исходит угроза, и закрыть все порты на своём узле. Я установил у себя Small-Http-Server (145 Кб для тестов то-что доктор прописал), и вот его реакция на эту прожку..

Здесь видно, что установка с ним связи на порт(80) прошла успешно, но пока он собирался отправить мне ответ, я уже сбросил соединение, прихлопнув свой сокет внутри цикла как таракана. Остальные порты у меня под фаером, а вы можете проверить свои:

portScan.png


В следующий раз рассмотрим несколько протоколов, попробуем создать свои, пошифруем трафик и много ещё. Было-бы желание и время. Обитать на этом уровень очень интересно, и вдохновляет огромный запас возможностей. Ограничивает их - только наша фантазия.
 
Последнее редактирование:
Файл с инклудом не вижу.
 
..забыл вложить:
 

Вложения

Очень круто ! Как всегда - на высоте !
 
Спасибо, ..только круто это для тех, кто впервые попал в программную часть сети. Это лишь мои попытки донести до начинающих общие принципы сетевой архитектуры, поэтому стараюсь объяснять на пальцах. Те-кто уже в курсе дел, такой материал и читать не будут, т.к. это основы. Однако за бортом остаётся огромная армия неосведомлённых новичков, под которых и заточено сие повествование. Я рад, что это хоть кто-то читает ..значит не зря прожигаю жизнь.
 
Спасибо, ..только круто это для тех, кто впервые попал в программную часть сети. Это лишь мои попытки донести до начинающих общие принципы сетевой архитектуры, поэтому стараюсь объяснять на пальцах. Те-кто уже в курсе дел, такой материал и читать не будут, т.к. это основы. Однако за бортом остаётся огромная армия неосведомлённых новичков, под которых и заточено сие повествование. Я рад, что это хоть кто-то читает ..значит не зря прожигаю жизнь.
Всегда стоит вернуться к началу, чтобы проверить - не упустил ли ты какую нибудь мелочь. А вообще, всегда думаешь что жизнь проживёшь максимально эффективно, а в итоге 90% всей жизни прожигание её непойми на что, не стоит из-за этого переживать. Мне интересно, вот попробовать не используя какие либо библиотеки, а всё самому, ни на что не опираясь написать.
Кстати, в одной из ваших статей про скрытие процесса было, пользуясь случаем, хочу узнать, а зачем нам нужно парсить включение диспетчера задач, если можно сразу заинжектить ? Или это потому, что сразу это сделать невозможно ? И ещё, а вот будет какая нибудь статья про написание демосцен (ну работа с графикой и тд) ?
 
а зачем нам нужно парсить включение диспетчера задач, если можно сразу заинжектить ?
Обычно инжектят в память, а для этого процесс диспетчера должен быть запушен. Если-же править образ диспетчера на диске (taskmgr.exe из папки system32), то это грязный способ и его модификацию может обнаружить системный механизм SFC (System Files Checker) - проверка целостности системных файлов и всякие гуарды. Так-что оптимальным вариантом будет поиск диспетчера в памяти, и инжект шела в его пространство.

будет какая нибудь статья про написание демосцен (ну работа с графикой и тд) ?
Когда-то интересовался демо/сценами, но то было под досом, и уже ничего не помню.
В реальном режиме выводил правда картинки BMP и даже писал для этого конвертор. А под виндой графикой не занимался. Предпочитаю хардкор в реальном режиме, где нет ничего, а только BIOS и порты - вот это руль и захватывает не по-детски.
 
Обычно инжектят в память, а для этого процесс диспетчера должен быть запушен. Если-же править образ диспетчера на диске (taskmgr.exe из папки system32), то это грязный способ и его модификацию может обнаружить системный механизм SFC (System Files Checker) - проверка целостности системных файлов и всякие гуарды. Так-что оптимальным вариантом будет поиск диспетчера в памяти, и инжект шела в его пространство.


Когда-то интересовался демо/сценами, но то было под досом, и уже ничего не помню.
В реальном режиме выводил правда картинки BMP и даже писал для этого конвертор. А под виндой графикой не занимался. Предпочитаю хардкор в реальном режиме, где нет ничего, а только BIOS и порты - вот это руль и захватывает не по-детски.

Прикольно, а я пробовал делать на OpenGL. Но что-то у меня выходит сделать демку на 4кб. Вот если бы узнать вот какие то хитрости, методы определённые, то было бы классно.
Кстати, есть код (под DOS правда) :
Это 32байтная демка.
C-подобный:
;S equ 0B1h -
S equ 0E5h
org 100h

mov al,13h
int 10h
lds bx,[bx]

M:
cmp [bx],cl
adc [bx],ah
imul bx,S
mov cl,[bx]
add cl,[bx+di]
add cl,[bx-321]
add cl,[bx+si+63]
dec bx

in al,60h
dec al
jnz M
ret
 
  • Нравится
Реакции: Marylin
Не посоветуете ли какую-нибудь документацию по сокетам на asm? Хотел попробовать заменить сокет на неблокирующий, но нахожу статьи только на c++ и т.д.
 
Не посоветуете ли какую-нибудь документацию по сокетам на asm? Хотел попробовать заменить сокет на неблокирующий, но нахожу статьи только на c++ и т.д.

Как говорил мой преподаватель по инженерной графике: "Найдите десять отличий".
(троиточие - пропуск кода, остальное - это то, что требуется для реализации функции)
C++:
#include <winsock2.h>

...

int WSAStartup(
  WORD      wVersionRequired,
  LPWSADATA lpWSAData
);

и

C-подобный:
...

.data
wsa      WSADATA; значение WSADATA можно посмотреть в wsock32.inc который инклюдится ниже

...

invoke WSAStartup,0x0101,wsa ; инициализация WinSock

...

section '.idata' import data readable
library   wsock32,'wsock32.dll',\
...
include 'api\wsock32.inc'

То есть, как вы понимаете, это работает со всеми командами. Если же значений в функции много, а вам нужно заполнить лишь некоторые, перед invoke ставьте 'c' -> cinvoke.
 
но нахожу статьи только на c++
Лично я на асме по сокетам доков не встречал, и тоже разбирался на сишных примерах. Если определите проблему конкретней, то может вместе как-то осилим её. Кстати чтобы постоянно не рыскать по MSDN, имеется справочник по сокетам в формате CHM, на всякий цепляю его в скрепке, может кому пригодится.

Если же значений в функции много, а вам нужно заполнить лишь некоторые, перед invoke ставьте 'c' -> cinvoke.
Не совсем так..
invoke и cinvoke отличаются "соглашением о вызове" процедур и функций. В большей степени соглашение определяет то, кто именно будет очищать стек от аргументов на выходе из функции.

В первом случае - это классический __stdcall, когда стек очищает сама вызываемая функция. По такому соглашению работают все виндовые API.

Второй метод назвали __cdecl и это как-раз cinvoke, когда стек от аргументов очищает вызывающий. Если посмотреть в отладчике, то после "cinvoke" всегда идёт add esp, кол-во аргументов.
 

Вложения

  • sock2.zip
    sock2.zip
    330,4 КБ · Просмотры: 717
Если определите проблему конкретней
Сканер открытых портов в примере работает 1 сек/порт, мне стало интересно оптимизировать его работу. Пока только увеличил скорость в 2 раза, добавив второй поток, основываясь на пример из статьи "(4.0) Системные механизмы Windows" (перебираю вторую половину портов в этом потоке). Есть идеи добавить массив потоков, массив сокетов в 1 потоке, заменить блокирующий сокет на неблокирующий, но для реализации пока что не хватает моих знаний в asm, вот я и попросил что-нибудь на подобие того справочника, который вы закрепили.
 
  • Нравится
Реакции: bin1101d и Marylin
заменить блокирующий сокет на неблокирующий,
Потоки это руль, а вот с неблокирующими сокетами есть детали..
Во-первых нужно понимать, при каких обстоятельствах сокет блокирует поток, и только потом использовать неблокирующие сокеты. Дело в том, что профита от неблокируемых мы можем и не получить, поскольку в некоторых ситуациях они выполняются абсолютно одинаково по времени:

1. connect - никогда не блокирует UDP-сокеты, зато практически всегда останавливает (блокирует) поток для TCP-соединений, т.к. в этом случае ей требуется время на установление связи с удалённым сокетом.​
2. recv - блокирует поток, только если на момент вызова буфер удалённого сокета пуст, т.е. нечего принимать.​
3. send - блокирует, если в буфере удалённого сокета недостаточно места, чтобы сбросить туда передаваемую информацию.​

Если применение неблокирующих принципиально, то сначала нужно перевести сокет в этот режим функцией ioctlsocket() с параметром FIONBIO =0x8004667E (аргумент =1), и дальше прослушивать состояние сокета функцией select(). К селект привязывается структура FD_SET (см.инклуд), в которой хранится массив дескрипторов прослушиваемых сокетов (можно прослушивать до 64 сокета):

C-подобный:
struct fd_set                   ;// для функции select()
   fd_count      dd  0            ; число сокетов в массиве
   fd_array      dd  64 dup(0)    ; массив сокетов
ends

Есть хорошая книга: Григорьев А.Б. "О чем не пишут в книгах по Delphi", где достаточно внятно объясняются детали работы с сокетами - советую обзавестись, тем-более что она лежит в свободном доступе.
 
Потоки это руль, а вот с неблокирующими сокетами есть детали..
Во-первых нужно понимать, при каких обстоятельствах сокет блокирует поток, и только потом использовать неблокирующие сокеты. Дело в том, что профита от неблокируемых мы можем и не получить, поскольку в некоторых ситуациях они выполняются абсолютно одинаково по времени:

1. connect - никогда не блокирует UDP-сокеты, зато практически всегда останавливает (блокирует) поток для TCP-соединений, т.к. в этом случае ей требуется время на установление связи с удалённым сокетом.​
2. recv - блокирует поток, только если на момент вызова буфер удалённого сокета пуст, т.е. нечего принимать.​
3. send - блокирует, если в буфере удалённого сокета недостаточно места, чтобы сбросить туда передаваемую информацию.​

Если применение неблокирующих принципиально, то сначала нужно перевести сокет в этот режим функцией ioctlsocket() с параметром FIONBIO =0x8004667E (аргумент =1), и дальше прослушивать состояние сокета функцией select(). К селект привязывается структура FD_SET (см.инклуд), в которой хранится массив дескрипторов прослушиваемых сокетов (можно прослушивать до 64 сокета):

C-подобный:
struct fd_set                   ;// для функции select()
   fd_count      dd  0            ; число сокетов в массиве
   fd_array      dd  64 dup(0)    ; массив сокетов
ends

Есть хорошая книга: Григорьев А.Б. "О чем не пишут в книгах по Delphi", где достаточно внятно объясняются детали работы с сокетами - советую обзавестись, тем-более что она лежит в свободном доступе.
Мощно, спасибо большое за инфу, а как заставить asm работать с http?
 
Мощно, спасибо большое за инфу, а как заставить asm работать с http?
Автора долго нет в сети, по-этому постараюсь ответить я.
Во первых, посмотрите что такое GET и POST запросы и чем они отличаются. Потом, посмотрите следующую статью 5.2 WinSock протокол WHOIS, там очень хороший пример отправки POST-запроса. При этом, ничего трудного там нет, всё строится на вызовах из wsock32.dll, если присмотреться, то структура тоже не сложная: получить ip по имени, создать TCP-сокет, подключение, отправка, принятие, и вывод того что приняли на экран.
 
а как заставить asm работать с http?
можно конечно сокетами, только это нижний уровень.
есть ещё специальные функции из библиотеки Httpapi.dll
примеры реализации сервера можно найти на MSDN например здесь
 
  • Нравится
Реакции: Mikl___
На форуме приветствуется уважительное отношение к участникам. ПРЕДУПРЕЖДЕНИЕ!
можно конечно сокетами, только это нижний уровень.
есть ещё специальные функции из библиотеки Httpapi.dll
примеры реализации сервера можно найти на MSDN например здесь

Похоже это пример для твоих друганов из LGBT :) А пример на асме не выложил - спиздить негде?
 
Это второе предупреждение за хамское поведение. Аккаунт заблокирован бессрочно.
мерень... ты свой круг мне не навязывай,

Я один раз только и прочитал твою писанину , в которой ты с васма взял тул столетеней давности и пару картинок приклеил своих . Ееби мозги пионерам и кушай свою пионерскую славу :)
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab