ASM IRC Bot

Download (7z)

An IRC bot coded in x86 assembly for linux.

The code isn't very clean; I did this back in 2008. It also doesn't do much other than sitting in a channel waiting for someone to make it quit. The bot does not pong the server back after the first pong so it eventually timeouts.

Code

; This program is free software. It comes without any warranty, to
; the extent permitted by applicable law. You can redistribute it
; and/or modify it under the terms of the Do What The Fuck You Want
; To Public License, Version 2, as published by Sam Hocevar. See
; COPYING for more details.
;
;---------
;INTRODUCTION
;---------
;IRCBOT for Linux

;---------
;COMMENTS
;---------
;General information to recall:
;esi holds the socket descriptor
;edi points to the string received from the server (on stack)
;To call send, first push the length of the string to send,
;then a pointer to the string, and afterwards call send.

;---------
;DATA
;---------

BITS 32

section .data
logincmd db ': NICK asmbot',0xd,0xa,'USER asmbot asmbot irc.host.net :asmbot',0xd,0xa
quit db 'QUIT :Did you hear that?',0xd,0xa
joinchannels db 'JOIN #botground',0xd,0xa
msg_priv db 'PRIVMSG '
msg_quit db 'quit'

section .text
global _start

;---------
;CODE
;---------
;Alright, code goes here.
;Basically, it is divided into three main parts:
; Initialisation -> setting up, connecting to the server, making space for buffer.
; Main loop -> receiving and parsing commands.
; Ending -> send quit message, disconnect from server, and exit.


_start:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx

;Make space for variables.
sub esp, 4
mov ebp, esp

;[ebp] int: 1 when channels have been joined, 0 otherwise.
;[ebp+4] int: holds the number of bytes received by recv().

;Initialise variables.
mov dword [ebp], 0

socket:
push edx
push 0x1
push 0x2
mov ecx, esp
inc bl
mov al, 102
int 0x80
mov esi, eax
cmp eax, 0
jb near socket_fail

connect:
push edx
push dword 0x4bb8b2c3
push dword 0x0B1A0002
mov ecx, esp
push 0x10
push ecx
push esi
mov ecx, esp
mov bl, 3
mov al, 102
int 0x80
test eax, eax
jnz near connect_fail

prepare_buffer:
;We will need a buffer later on
;to receive messages from the server.
push edx
sub esp, 127+28
mov edi, esp

login:
;Send the login information to the server.
push dword 0 ;Flags
push dword 67 ;Length
push logincmd ;String
push esi
call send

recv:
push dword 0 ;Flags
push dword 128 ;Len
push edi ;buf
push esi ;socket
mov ecx, esp
mov ebx, 10
mov eax, 102
int 0x80
mov [ebp+4], eax
test eax, eax
jz near connection_closed
jbe near recv_fail
pop ecx
pop ecx
pop ecx
pop ecx

check_for_ping:
;String long enough to
;deal with parsing?
cmp dword [ebp+4], 6
jbe recv

mov edx, edi
mov ecx, 124

check_ping_repeat:
cmp dword [edx], 0x474E4950 ;GNIP
je pong

inc edx
dec ecx
jnz check_ping_repeat

jmp check_channels

pong:
;Now we need to substitute the I
;in PING for O, so that is reads
;PONG, and reply to the server with
;our new string. O = 0x47.
mov byte [edx+1], 0x4F

;Send the reply
push 16
push edx
call send

check_channels:
;Have channels already been joined?
;If so, jump straight into the message parsing block.
mov eax, [ebp]
test eax, eax
jnz check_message

join_channels:
;Prudential wait time.
mov eax, 162
push dword 0
push dword 1
mov ebx, esp
xor ecx, ecx
int 0x80

;Once the server has welcomed us, we can join channels.
push dword 0 ;Flags
push dword 17
push joinchannels
push esi
call send

mov dword [ebp], 1 ;Channels have been joined.

check_message:

;user@host PRIVMSG #botground :asmbot, quit

;String long enough to
;deal with parsing?
mov ecx, [ebp+4]
cmp ecx, 9
jb recv

mov edx, edi

check_message_next:
;PRIVMSG ?
cmp dword [edx], 0x56495250 ;VIRP
jne check_message_iterate

cmp dword [edx+4], 0x2047534D ; GSM
je check_message_continue

check_message_iterate:
inc edx
dec ecx
jz recv
jmp check_message_next

check_message_continue:

;Now find the : in the message.
add edx, 8

recheck_msg:
cmp byte [edx], 0x3A
je parse_command
inc edx
dec ecx
jz recv
jmp recheck_msg

parse_command:

;PRIVMSG #Botground :asmbot, quit

;Is edx pointing near the end of the buffer?
;If so, there is no need to parse the string.
cmp ecx, 10
jb recv

;Get past the :
inc edx

;Now we read whatever was said after
;the : and check for commands.

;Was our name said ? asmbot, (space)
cmp dword [edx], 0x626D7361 ;bmsa
cmp dword [edx+4], 0x202C746F ; ,to
jne recv

;Get past the name
add edx, 8

;Was quit said?
push 4
push msg_quit
push edx
call compare
test eax, eax
je bye_bye

jmp recv

;cmp dword [edx], 0x74697571 ;tiuq
;jne recv

bye_bye:
;We say good bye!
push dword 0 ;Flags
push dword 26
push quit
push esi
call send

shutdown:
;Close the socket.
;SHUT_RDWR = 0x2
push 0x2
push esi
mov ecx, esp
mov ebx, 0xD
mov eax, 102
int 0x80
test eax, eax
jnz near shutdown_fail

;Set ebx to 0 for a clean exit call.
xor ebx, ebx

exit:
mov eax, 1
int 0x80

send:
mov ecx, esp
add ecx, 4
mov ebx, 9
mov eax, 102
int 0x80
cmp eax, 0
jb near send_fail
pop eax ;ret
pop ecx ;socket
pop ecx ;buf
pop ecx ;len
pop ecx ;flags
push eax
ret

compare:
pop eax ;ret
pop edx ; ptr one
pop ebx ; ptr two
pop ecx ; Length
push eax

compare_loop:
mov al, [edx]
xor al, [ebx]
test al, al
jnz compare_return

dec ecx
test ecx, ecx
jz compare_equal

inc edx
inc ebx
jmp compare_loop

compare_equal:
xor eax, eax

compare_return:
ret

fail:
pop ecx
pop edx
mov ebx, 0x1
mov eax, 0x4
int 0x80

;Set ebx to 1 as an error code.
mov ebx, 1
jmp exit

;-----------------
;FAIL "FUNCTIONS"
;-----------------
;The fail functions are all listed here.
;The tags are pretty self explanatory.
;Remember to push the length of the string to print
;before calling fail.

recv_fail:
push 14
call fail
db 'recv() failed',0xa

socket_fail:
push 16
call fail
db 'socket() failed',0xa

connection_closed:
push 48
call fail
db'The server closed the connection.',0xa

connect_fail:
push 17
call fail
db 'connect() failed',0xa

send_fail:
push 14
call fail
db 'send() failed',0xa

shutdown_fail:
push 18
call fail
db 'shutdown() failed',0xa