2009-07-08

Плагин для Windbg

Плагин определяет сколько времени прошло между двумя точками в програме.
Используеться так:
!ct breakpoint1 breakpoint2

Пример на блокноте (notepad.exe):
Правда плагин считает только секунды, и для больших таймаутов не подходит
0:000> u winmain
notepad!WinMain:
005a138d 8bff mov edi,edi
005a138f 55 push ebp
005a1390 8bec mov ebp,esp
005a1392 83ec1c sub esp,1Ch
005a1395 56 push esi
005a1396 57 push edi
005a1397 6a06 push 6
005a1399 33f6 xor esi,esi
0:000> !ct 005a1392 005a1399
0:000> bl
0 e 005a1392 0001 (0001) 0:**** notepad!WinMain+0x5
1 d 005a1399 0001 (0001) 0:**** notepad!WinMain+0xc
0:000> g
...
Breakpoint 0 hit
Debug session time: Wed Jul 8 16:58:41.358 2009 (GMT+3)
System Uptime: 6 days 2:43:43.142
Process Uptime: 0 days 0:00:20.215
Kernel time: 0 days 0:00:00.015
User time: 0 days 0:00:00.000
------------------------------- 0 hit ------- 43.142000
Breakpoint 1 hit
Debug session time: Wed Jul 8 16:58:41.359 2009 (GMT+3)
System Uptime: 6 days 2:43:43.143
Process Uptime: 0 days 0:00:20.216
Kernel time: 0 days 0:00:00.015
User time: 0 days 0:00:00.000
------------------------------- 1 hit ------- 43.143000
Quick diff: 0.001000
---------------------------------------------
eax=0000000a ebx=00000000 ecx=00000065 edx=00000004 esi=00272d06 edi=005aa21c
eip=005a1399 esp=000afc50 ebp=000afc78 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216
notepad!WinMain+0xc:
005a1399 33f6 xor esi,esi

0.001000 - это 1 милискунда
http://cid-eea2a7c767291ff9.skydrive.live.com/self.aspx/.Public/windbg|_catch|_time.rar

2009-06-25

Отладка драйвера в Windbg

Во время отладки драйвера с помощью vmware и Windbg часто возникает необходимость остановиться на точке входа драйвера. Если драйвер наш, и нам доступны исходники, можно просто добавить int 3 в код и перекомпилировать драйвер, но что делать если исходные коды не доступны?

Можно конечно вписать 0xCC в нужное место с помощью хексредактора, но тут есть ряд неудобств. Во-первых, нужно будет востанавливать оригинальный байт, а во-вторых у меня драйвер с изменённым байтом отказался загружаться, наверно нужно исправить контрольную сумму в заголовке? Дополнительная трата времени... Но можно поступить иначе.

Дизассемблируем ntkrnlpa.exe (или ntoskrnl.exe), находим там неэкспортируемую функцию IopLoadDriver, запоминаем/записываем адресс. В моём случае - 0049DEE4.

Прокручиваем листинг вниз, ищем примерно такой код:
PAGE:0049E546 0C4                 push    [ebp+Object]
PAGE:0049E54C 0C8 push edi
PAGE:0049E54D 0CC call dword ptr [edi+2Ch]
PAGE:0049E550 0C4 cmp eax, ebx
PAGE:0049E552 0C4 mov ecx, [ebp+var_98]
PAGE:0049E558 0C4 mov [ebp+var_54], eax
PAGE:0049E55B 0C4 mov [ecx], eax
PAGE:0049E55D 0C4 jge short loc_49E566
PAGE:0049E55F 0C4 mov [ebp+var_54], 0C0000365h

call dword ptr [edi+2Ch] - это переход на точку входа в загружаемого драйвера, значит находим смещение этого кода относительно начала функции IopCallDriver. В моём сулучае: 0x0049E54D - 0x0049DEE4 = 0x669. И ставим в windbg точку останова:
bp IopLoadDriver+0x669

Когда windbg останавливаеться на этой точке - нажимаем F11, и попадаем на EP драйвера =)
Конечно подразумеваеться что установленны корректные отладочне символы.

Вместо выполнения "сложных" арифметических операций (0x0049E54D - 0x0049DEE4 = 0x669) можно пойти в Options -> General -> Disassembly и поставить галочку "Function Offsets", тогда IDA выдаст что-то такое:
IopLoadDriver(x,x,x,x)+662  0C4                 push    [ebp+Object]
IopLoadDriver(x,x,x,x)+668 0C8 push edi
IopLoadDriver(x,x,x,x)+669 0CC call dword ptr [edi+2Ch]
IopLoadDriver(x,x,x,x)+66C 0C4 cmp eax, ebx
IopLoadDriver(x,x,x,x)+66E 0C4 mov ecx, [ebp+var_98]
IopLoadDriver(x,x,x,x)+674 0C4 mov [ebp+var_54], eax
IopLoadDriver(x,x,x,x)+677 0C4 mov [ecx], eax
IopLoadDriver(x,x,x,x)+679 0C4 jge short loc_49E566
IopLoadDriver(x,x,x,x)+67B 0C4 mov [ebp+var_54], 0C0000365h

2009-05-18

Чтиво

Для себя несколько заметок, чтоб не забыть дочитать, а вообще весьма интересно:

http://phrack.org/issues.html?issue=61&id=14#article
http://phrack.org/issues.html?issue=61&id=13#article
http://phrack.org/issues.html?issue=55&id=12#article

2009-05-10

hki - кейлогер

Отладил наконец-то свой кейлогер. Работает через перехват IRP. В лог-файл (по умолчанию C:\124.txt) пишет коды клавиш, и заголовок активного окна. Тестировался на Windows Vista SP1 и Windows XP Sp2 на двухядерном прцессоре. В комплекте простой парсер лог-файлов, парсер написан на коленке и скорей всего будет передалан, но как-нибудь в другой раз. При написании парсера использовалась часть кода из r0keylog barton'а.

Конечно код далёк от совершенства, но тем-не менее, вот сcылка для скачивания:
http://cid-eea2a7c767291ff9.skydrive.live.com/self.aspx/.Public/hki.rar

2009-05-04

blackhat style

Из исходников migbot'а, 2004-й год...

// migsys, kernel part of m1gB0t, Greg Hoglund, 2004
//
// I got the blackhat style
// my code is evil and elite
// with capitalized guile
// fuckn the welfare vendors
// and their mothefuckin deceit
// hide behind the mask of good-will-defender
// I cut like a file
// slow hone on your vulns
// This aint no fuzz
// This is deeper
// I'm in your states
// like the motherfukn Reaper
// You want something for free?
// pay naught for my pursuit?
// my mission occupation
// gonna put me in refute
// your gonna come along
// cuz this is bigger than you
// its gonna take you by balls
// your paybacks are due

2009-05-02

Пример кода epoll

Очень базовый пример обработки входящих соединений с epoll:

#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <strings.h>

#define EPOLL_RUN_TIMEOUT 1000
#define MAXEVENTS 50

int got_connect(fd) {
printf("got data\n");
return 0;
}

int main(int argc, char *argv[]){
if(argc<2){
printf("Usage: %s <port>\n",argv[0]);
return -1;
}

int port=atoi(argv[1]);
int epfd = epoll_create(512);
int nfds, cs, i;

struct epoll_event ev, *events;
struct sockaddr_in serv, cli;
int connected_fd;
int listenfd=socket(AF_INET, SOCK_STREAM, 0);

bzero(&serv,sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_addr.s_addr = htonl(INADDR_ANY);
serv.sin_port = htons(port);

bind(listenfd,(struct sockaddr*)&serv,sizeof(serv));
listen(listenfd, 50);

ev.events = EPOLLIN | EPOLLET | EPOLLHUP;
ev.data.fd = listenfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
int addrlen = sizeof(cli);

while(1){
nfds = epoll_wait(epfd,events,MAXEVENTS,EPOLL_RUN_TIMEOUT);
if(nfds<0){
printf("epoll_wait error\n");
return -1;
}
for (i=0;i<nfds;++i){
if(events[i].data.fd == listenfd){
connected_fd = accept(listenfd, (struct sockaddr *) &cli,&addrlen);
printf("addr: %s\n",inet_ntoa(cli.sin_addr.s_addr));
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = connected_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, connected_fd, &ev);
}
else{
got_connect(events[i].data.fd);
}
}
}
close(epfd);
return 0;
}

Сцылки по теме:
http://www.kegel.com/c10k.html

http://www.monkey.org/~provos/libevent/
http://www.xmailserver.org/linux-patches/nio-improve.html

2009-04-22

Linux kernel debugging

Всем известно, что в vmware 6-й ветки появилась возможность отлаживать ядро гостевой операционной системы. Для включения отладки необходимо в конфиг виртуальной машины (файл *.vmx) добавить строку debugStub.listen.guest32=1 либо debugStub.listen.guest64=1. Vmware откроет порт 8832 (или 8864 для 64-битных систем) на главной системе(хосте):
>netstat -an | grep 88
TCP 127.0.0.1:8832 0.0.0.0:0 LISTENING

Как видим, подключиться можно только с локалхоста. Используеться протокол gdb, соответственно, берём gdb (версию для Windows в сети найти не трудно), и подключаемся:
> gdb -q
(gdb) target remote localhost:8832

Для удобного ковыряния в ядре, потребуеться собрать ядро с отладочными сиволами, обчычно ядра, установленные в различных дистрибутивах по умолчанию собраны без отладочных символов (что и не удевительно, поскольку включение символов несколько увеличивает размер образа ядра). Чтобы пересобрать ядро используя текущюю рабочюю конфигурацию, переходим в каталог исходников ядра (обычно /usr/src/linux), и выролняем:
make oldconfig
make menuconfig

В меню включаем отладочные символы:
Kernel hacking  --->
[*] Compile the kernel with debug info

или "CONFIG_DEBUG_KERNEL=y" в конфиге ядра (/usr/src/linux/.config). На стадии конфигурирования ядра желательно отключить всё лишнее (например можно отключть поддержку IPv6, если она не нужна, и ненужные драйвера), и всё что возможно вкомпилить в ядро, а не в виде модулей. Однако netfilter и драйвера сетевых интерфейсов я бы посоветовал всё-таки собрать в виде модулей. Можно вместо make oldconfig, сделать make defconfig, что-бы создать минимальный конфиг по умолчанию для данной архитектуры, а потом в make menuconfig включать необходимые опции, и добавить нужные драйвера (lspci может в этом помоч). Далее собираем ядро:
make
make modules_install

Файл /usr/src/linux/vmlinux - это несжатый образ ядра, его переносим с гостевой системы на основную. Желательно так-же иметь на основной стсиеме исходные коды ядра соответсвующей версии. Кладём файл vmlinux на основную систему в папку где находяться исходники ядра (у меня D:\kernel\). Устанавливаем новое ядро и перезагружаем гостевую систему. Теперь можно спокойно отлаживать ядро загрузив в gdb несжатый образ ядра с отладочнымм символами:
> gdb -q
(gdb) target remote localhost:8832
<...>
(gdb) file vmlinux

P.S.
по этой ссылке http://wiki.opennet.ru/Linux_kernel_debug рекомендуют включить в ядре такие опции:
Kernel hacking  --->
[*] Compile the kernel with debug info
[*] Compile the kernel with frame pointers

Архив