Introdução: Servidor web em assembly
O objetivo deste tutorial é dar uma abordagem mais prática à programação em assembly. Os dois melhores jeitos de se aprender assembly é por engenharia reversa ou programando algo. Aqui iremos fazer um servidor web totalmente em assembly que irá rodar como um aplicativo normal em seu sistema operacional. A ideia é criar um programa totalmente em assembly próximo ao equivalente em C no final desta página. Como a linguagem assembly é totalmente dependende de arquitetura e as chamadas de sistema dependem do sistema operacional, algumas alternativas de tutoriais estarão aqui dispostas.
- Windows (x86) TODO
- Linux (x86) TODO
- Linux (ARM64) TODO
- Linux (RISC-V) TODO
- MacOSX (x86) TODO
- MacOSX (ARM64) TODO
// Servidor Web usado como exemplo alternativo em C
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
char *response = "<html>\
<head><title>Hello World</title></head>\
<body bgcolor=\"white\">\
<center><h1>This is a hello world!</h1></center>\
<hr><center>nginx/1.10.3 (Ubuntu) [ Just kidding ]</center>\
</body>\
</html>";
void sendHeader(int new_socket, int status_code, int content_length) {
char buffer[1024];
sprintf(buffer, "HTTP/1.1 %d\r\n", status_code);
send(new_socket, buffer, strlen(buffer), 0);
sprintf(buffer, "Content-Type: text/html\r\n");
send(new_socket, buffer, strlen(buffer), 0);
sprintf(buffer, "Connection: close\r\n");
send(new_socket, buffer, strlen(buffer), 0);
sprintf(buffer, "Content-Length: %d\r\n", content_length);
send(new_socket, buffer, strlen(buffer), 0);
sprintf(buffer, "\r\n");
send(new_socket, buffer, strlen(buffer), 0);
}
void parseRequest(int new_socket) {
char buffer[10240];
int valread = read(new_socket, buffer, 10240);
printf("%s\n", buffer );
sendHeader(new_socket, 200, strlen(response));
send(new_socket, response , strlen(response), 0 );
printf("Response sent\n");
}
int main(int argc, char const *argv[]) {
struct sockaddr_in address;
int addrlen = sizeof(address);
int server_fd, new_socket;
int opt = 1;
printf("ADDRLEN: %d\n", addrlen);
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8081
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
printf("SOCKANDO: %d %d\n", SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT);
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( 8081 );
printf("PORTA INVERSA: %d\n", address.sin_port);
// Forcefully attaching socket to the port 8081
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
perror("accept");
exit(EXIT_FAILURE);
}
parseRequest(new_socket);
return 0;
}