Спасибо за загрузку файла.Как я и подозревал, он был разорван, поэтому имена функций остались.Помимо стандартного стандартного кода я мог определить функции main
, register_broker
, connect_exchange
(неиспользуемые и пустые) и handle_requests
.
Я провел немного времени в IDA Pro, и это было не слишкомтрудно восстановить функцию main()
.Во-первых, вот оригинальный, неизмененный список main()
от IDA: http://pastebin.com/sBxhRJMM
Чтобы продолжить, вам необходимо ознакомиться с соглашением о вызовах AMD64 .Подводя итог, первые четыре аргумента передаются в RDI (EDI), RSI (ESI), RDX (EDX) и RCX (ECX).Остальное передается в стеке, но все вызовы в main()
используют только до четырех аргументов, поэтому нам не нужно об этом беспокоиться.
IDA помеченно помечает аргументы стандартных функций C и дажепереименовал некоторые локальные переменные.Однако, это может быть улучшено и прокомментировано далее.Например, поскольку мы находимся в main()
, мы знаем, что argc
(первый аргумент) происходит от EDI (поскольку это int
означает 32-битный, он использует только младшую половину RDI) и argv
происходит от RSI (это указатель, поэтому он использует все 8 байтов регистра).Итак, мы можем переименовать локальные переменные, в которые копируются EDI и RSI:
mov [rbp+argc], edi
mov [rbp+argv], rsi
Далее идет простой условный блок:
cmp [rbp+argc], 2
jz short loc_400EB3
mov rax, cs:stderr@@GLIBC_2_2_5
mov rdx, rax
mov eax, offset aUsage ; "Usage"
mov rcx, rdx ; s
mov edx, 5 ; n
mov esi, 1 ; size
mov rdi, rax ; ptr
call _fwrite
mov edi, 1 ; status
call _exit
Здесь мы сравниваем argc с 2, и еслиРовно, прыгаем дальше в коде.Если оно не равно, мы называем fwrite()
.Первый аргумент для этого находится в rdi
, и rdi
загружается из rax
, который содержит адрес константной строки «Использование».Второй аргумент находится в esi
и равен 1, третий в edx
и равен 5, четвертый в rcx
, который загружается из rdx
, который имеет значение stderr@@GLIBC_2_2_5
, что в основном необычноссылка на переменную stderr
из libc.Собрав все воедино, мы получим:
fwrite("Usage", 1, 5, stderr);
Исходя из моего опыта, я могу сказать, что, скорее всего, это встроенный fprintf
, поскольку 5 - это длина строки.Т.е. исходный код, вероятно, был:
fprintf(stderr, "Usage");
Следующий вызов простой exit(1);
.Комбинируя и сравнение, мы получаем:
if ( argc != 2 )
{
fprintf(stderr, "Usage");
exit(1);
}
Продолжая в том же духе, мы можем идентифицировать другие вызовы и переменные, которые они используют.Все это утомительно описывать, поэтому я загрузил закомментированную версию разборки, где я попытался показать эквивалентный код C для каждого вызова.Вы можете увидеть это здесь: http://pastebin.com/p5sRSwgQ
Из этой закомментированной версии не очень сложно представить возможную версию main()
:
int main(int argc, char **argv)
{
if ( argc != 2 )
{
fprintf(stderr, "Usage");
exit(1);
}
char name[256];
gethostname(name, sizeof(name));
struct hostent* _hostent = gethostbyname(name);
struct in_addr *_addr0 = (struct in_addr *)(_hostent->h_addr_list[0]);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
addr.sin_addr.s_addr = _addr0->s_addr;
char *tmp = (char *)malloc(6);
sprintf(tmp, "%d", addr.sin_port);
char *ip_str = inet_ntoa(*_addr0);
char *newbuf = (char *)malloc(strlen(argv[1]) + strlen(ip_str) + strlen(tmp) + 5);
strcpy(newbuf, "r");
strcat(newbuf, " ");
strcat(newbuf, argv[1]);
strcat(newbuf, " ");
strcat(newbuf, ip_str);
strcat(newbuf, " ");
strcat(newbuf, tmp);
register_broker(newbuf);
int fd = socket(PF_INET, SOCK_STREAM, 0);
if ( fd < 0 )
{
perror("Error creating socket");
exit(1);
}
if ( bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("Error binding socket");
exit(1);
}
if ( listen(fd, 0x80) != 0 )
{
perror("Error listening on socket");
exit(1);
}
handle_requests(fd);
}
Восстановление двух других функций осталосьупражнение для читателя:)