Je me prends la tete depuis qqes jours/semaines de temps en temps sur la doc
CUDA,
tout n'est pas très clair, mais ça l'est devenu un peu plus grâce a ce lien
:
http://www.caam.rice.edu/~timwar/RMMC/CUDA.html
Enjoy!
Aller au contenu | Aller au menu | Aller à la recherche
mercredi 3 avril 2013
Par eau le mercredi 3 avril 2013, 11:40 - geeking
Je me prends la tete depuis qqes jours/semaines de temps en temps sur la doc
CUDA,
tout n'est pas très clair, mais ça l'est devenu un peu plus grâce a ce lien
:
http://www.caam.rice.edu/~timwar/RMMC/CUDA.html
Enjoy!
samedi 15 septembre 2012
Par poz le samedi 15 septembre 2012, 01:39 - geeking
Salut les gens !
Oui oui, vous l'aurez deviné, je présente (façon de parler) ici un truc que je viens de coder : un filesystem FUSE au-dessus des fichiers au format ELF.
Bon alors là, tout de suite, logiquement vous me dites "euh ok c'est bien gentil ton truc mais ça sert à quoi ?", ce à quoi je réponds "rien !". Plus sérieusement, ça sert à se faire un peu la main sur FUSE (donc vous pouvez regarder le code pour vous faire une idée, j'ose espérer qu'il n'est pas trop cracra). Ça peut également servir à des fins pédagogiques : voir la structure d'un fichier ELF, tout ça...
Bon, le but avoué, c'est qu'à terme, on puisse modifier un binaire, ou carrément un processus en cours via le point de montage. Par exemple en faisant un truc du genre :
echo 0x424242 > /mnt/elf/entrypoint sed -i "s:generic_func:myhook_func:g" /mnt/elf/symbols
Ou autres trucs du genre ! Amusant non ? Non ? Bon.. ok... j'retourne coder d'autres crottes en silence...
Sinon pour l'instant on peut juste faire 2-3 trucs en read-only:
$ elfs /usr/bin/screen /mnt/elf ou $ sudo elfs -p $(pidof screen) /mnt/elf
$ ls -l /mnt/elf/libs total 0 -rwxrwxrwx 0 root root 9 1970-01-01 01:00 libc.so.6 -rwxrwxrwx 0 root root 9 1970-01-01 01:00 libm.so.6 -rwxrwxrwx 0 root root 11 1970-01-01 01:00 libX11.so.6 -rwxrwxrwx 0 root root 11 1970-01-01 01:00 libXaw.so.7 -rwxrwxrwx 0 root root 11 1970-01-01 01:00 libXft.so.2 -rwxrwxrwx 0 root root 15 1970-01-01 01:00 libxkbfile.so.1 -rwxrwxrwx 0 root root 11 1970-01-01 01:00 libXmu.so.6 -rwxrwxrwx 0 root root 15 1970-01-01 01:00 libXrender.so.1 -rwxrwxrwx 0 root root 10 1970-01-01 01:00 libXt.so.6
$ cat /mnt/elf/info Ident: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Version: 1 Class: 64 Type: EXEC (Executable file) Version: 1 ELF Header size: 64 bytes Entry point: 0x402550 Program Header offset: 64 bytes Program Header entry size: 56 bytes Number of Program Header entries: 9 Section Header offset: 40768 bytes Section Header entry size: 64 bytes Number of Section Header entries: 28 SH string table index: 27
$ ls -l /mnt/elf/sections/ total 0 drw------- 1 root root 0 1970-01-01 01:00 bss drw------- 1 root root 0 1970-01-01 01:00 ctors drw------- 1 root root 0 1970-01-01 01:00 data drw------- 1 root root 0 1970-01-01 01:00 dtors drw------- 1 root root 0 1970-01-01 01:00 dynamic dr-------- 1 root root 0 1970-01-01 01:00 dynstr dr-------- 1 root root 0 1970-01-01 01:00 dynsym [...]
$ ls -l /mnt/elf/sections/dynsym/|tail -5 d--------- 1 root root 0 1970-01-01 01:00 XtStrings d--------- 1 root root 0 1970-01-01 01:00 XtWidgetToApplicationContext d--------- 1 root root 0 1970-01-01 01:00 XtWindow d--------- 1 root root 0 1970-01-01 01:00 XtWindowOfObject d--------- 1 root root 0 1970-01-01 01:00 XUnionRectWithRegion
$ ls -l /mnt/elf/sections/symtab/dup_regex_free/ total 0 ---------- 0 root root 363 1970-01-01 01:00 code.asm ---------- 0 root root 78 1970-01-01 01:00 code.bin ---------- 0 root root 69 1970-01-01 01:00 info $ cat /mnt/elf/sections/symtab/dup_regex_free/code.asm push rbp mov rbp, rsp sub rsp, 0x10 mov [rbp-0x8], rdi mov rax, [rbp-0x8] mov rax, [rax+0x48] test rax, rax jz 0x35 mov rax, [rbp-0x8] mov rax, [rax+0x48] mov rdi, rax call dword 0xfffffd9c mov rax, [rbp-0x8] mov qword [rax+0x48], 0x0 mov rax, [rbp-0x8] mov eax, [rax+0x50] test eax, eax jz 0x4c mov rax, [rbp-0x8] mov rdi, rax call dword 0xfffffeac leave ret
Ouala pour l'instant c'est tout....
J'essaie d'ajouter des trucs quand j'ai le temps mais bon, d'une part j'suis pas mal occupé à faire des trucs pas intéressants, et en plus je code comme une buse et à la lenteur d'un cloporte arthritique, c'est pas gagné...
Le code : c'est par ici !
Bref, see ya dudes!
Ah j'oubliais un truc important : c'est Linux-only... hey ouais, j'ai pas trouvé de truc plus malin que checker /proc/pid/exe pour avoir l'adresse de mapping du binaire depuis le PID. On me souffle dans l'oreille de faire des trucs sioux avec ptrace() + les registres, qui donnent un emplacement dans le code, puis checker en arrière les adresses modulo _sysconf(_SC_PAGESIZE) pour essayer de retomber sur les 4 bytes ELF_MAGIC du header. Plus tard plus tard... déjà on va essayer de faire en sorte que ça SIGSEGV pas trop :P
EDIT: hop, apparemment maintenant ça compile/tourne sous freebsd (j'ai pas pu tester mais le bon sbz m'a envoyé un patch qui fait le taff)
lundi 20 août 2012
Par eau le lundi 20 août 2012, 14:36 - geeking
Un paper marrant sur le fonctionnement de l'implementation de filevault2 sous OS/X, interessant pour voir comment sont derives les user keys, les recovery keys et comme ils se faisaient chier, ils ont decide de fournir une lib pour mounter/acceder a ton volume CoreStorage/Filevault depuis ailleurs ou ecrire tes tools avec, a lire, vraiment! :)
Enjoy!
jeudi 7 juin 2012
Par poz le jeudi 7 juin 2012, 15:14 - geeking
Une petite news pour dire qu'on vit encore, et j'en profite pour vous vendre un tool bien sympathoche.
Un collègue de bureau m'a montré l'existence de cppcheck, et je dois dire que c'est pas mal du tout, ce truc.
C'est un outil d'analyse statique pour du C/C++. Il est intégré (ou intégrable) à des IDE, pour ceux qui s'en servent, pour plus de facilité d'utilisation.
Ça sort des rapports au format xml/html faciles à exploiter, il y a relativement peu de faux positifs, trouve aisément des memory leaks, etc.
Bref, une petite passe sur chaque projet aide à trouver des bugs en très peu de temps.
Ouala, c'est tout, enjoy ! :)
Edit : il y a aussi l'utilitaire de la suite clang, le bien nommé `scan-build'. Dans un repository il suffit de taper `scan-build make' puis `scan-view <nom du rapport>'. Ça marche bien et c'est un bon complément à cppcheck.
mardi 20 mars 2012
Par eau le mardi 20 mars 2012, 16:31 - geeking
Ok j'ai dû chercher, alors si je peux faire gagner un peu de temps à d'autres âmes perdues comme la mienne! J'avais envie de pouvoir sniffer les i/o sur n'importe quel process avec des filtres genre sur les file descriptors (ou FD), sur le type de FD ou sur le nom du process, etc.. histoire de voir dans les protocoles de communication locaux (genre via socket unix de pute de merde $@#!$!@#) comment un daemon communique avec son environnement ou comment (exemple d'OS/X) un programme peut communiquer avec le kernel, oui oui sous OS/X ça "peut" se passer via une socket() et pas via un /dev/bla, ioctl() etc.. ca existe aussi mais dans mon cas c'était dans mon cul... bref...
Donc j'ai commencé par ecrire un LD_PRELOAD, mais ce n'est pas le sujet, je me suis amusé avec dtrace(1) pour voir; pas mal d'outils sous OS/X utilisent dtrace(1), comme "dtruss(1m)" (fourni par default sous OS/X), je vous laisse chercher pour tous les trouver, mais voila un premier pas:
J'en reviens a mon process, je sais pas ce qu'il fait, j'aimerais voir ses read()/write(), je passe un coup d'"lsof" (aka LiSt Open Files) pour voir les FDs (File Descriptors, je me répète et j'en vois plein... alors je me dis merde, j'aimerais bien voir où il écrit, juste voir ce qui se passe sur ce FD, etc... je cherche un peu et je tombe sur:
Content, je m'en vais essayer, mais deception...:
# rwsnoop -p 377 UID PID CMD D BYTES FILE 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx
Beuh il me print pas le contenu du read()/write(), genre un bel hexdump aurait été bien agréable, ensuite je ne peux pas filtrer par file descriptor (genre je veux voir juste le #6, je sais ce que c'est $#@!$@#!) et j'aimerais aussi pouvoir voir (quand ça n'est pas un fichier) le type de socket (vu que le type n'est pas fourni par la variable interne dtrace "fds"), histoire de savoir ce qui se passe vraiment et pas croire que c'est une vnode alors qu'en fait c'est une socket à la noix... bref...
Donc la première étape, c'est de dumper le contenu du read()/write() et le return code, c'est parti... je vais expliquer rapidement:
syscall::read:entry
/<predicate>/
{
self->fd = arg0;
self->rarg1 = arg1;
self->rarg2 = arg2;
[...]
}
En gros à l'entrée de read() je sauve les arguments, oui je veux afficher mon code de retour et le read() n'a pas encore été exécuté donc le buffer est toujours vide... du coup :
syscall::read:return
/<predicate>/
{
buffer = copyin(self->rarg1, arg0);
tracemem(buffer, $opt_dumpsz);
printf(\"\n\");
}
donc la à la fin de l'exec, je prends le code de retour (arg0), je copie tout ca dans un buffer local (oui oui on est dans l'addressage du noyau là...) et j'affiche le contenu de la mémoire avec tracemem() tout joli en fonction du type, mais si comme moi vous préférez TOUJOURS avoir un hexdump, magie, simplicité, élasticité... on rajoute ça au debut de son script:
#pragma D option rawbytes
voilà là on voit le contenu avec ce format:
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
0: 03 4f 42 7e 3b 39 35 3b 63 a8 11 16 01 00 00 00 .OB~;95;c.......
10: 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ................
20: 36 00 18 00 00 00 00 00 f0 f0 52 00 01 00 00 00 6.........R.....
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
autre galère, retrouver le type de FD, apres avoir parcouru, diverses choses, je conseille donc aux gens qui se cassent la tête, de farfouiller dans ces liens:
je finis par aller voir si dans les struct du noyau je peux accéder à la struct proc (oui elle contient les FDs du process!!), je resume vite fait et simplement il faut passer par la struct task puis récupérer la struct proc (via bsd_info de la structure task), struct filedesc, blablabla jusqu'à la struct fileglob et on finit par voir que la struct proc est accessible via curproc dans dtrace(1), apres du déréferencement à la main on arrive à ça:
curproc->p_fd->fd_ofiles[<FD_num_as_index_of_this_array>]->f_fglob->fg_type
c'est un int avec pour valeurs possibles:
/* file types */ 145#define DTYPE_VNODE 1 /* file */ 146#define DTYPE_SOCKET 2 /* communications endpoint */ 147#define DTYPE_PSXSHM 3 /* POSIX Shared memory */ 148#define DTYPE_PSXSEM 4 /* POSIX Semaphores */ 149#define DTYPE_KQUEUE 5 /* kqueue */ 150#define DTYPE_PIPE 6 /* pipe */ 151#define DTYPE_FSEVENTS 7 /* fsevents */ 152
And voilà....!! maintenant vous reste plus qu'à faire l'amas de ces informations et hop vous avez vos filtres dans votre gentil script dtrace(1)! :)
Maintenant répétez les operations pour avoir filename, socket endpoint, en fonction du type, etc... vous aurez tout ce que vous voulez.
Bon je suis fatigué d'écrire ce truc... j'espère que ça servira à quelqu'un, je retourne lire mes trucs de glands...
jeudi 16 février 2012
Par poz le jeudi 16 février 2012, 13:45 - geeking
Dans la même veine qu'un précédent ticket, j'avais besoin de faire une tâche particulière : calculer la distance de Hamming entre plusieurs fichiers, dans un objectif absolument top secret de ouf.
Contrairement à fdup(1), cette fois j'ai (rapidement) cherché dans les dépôts debian/ubuntu si un truc existait déjà. En regardant un peu kdiff3, xdelta, etc, j'ai rien trouvé de bien satisfaisant, alors je l'ai codé. C'est absolument bidon, je préviens, mais ptet que ça servira à quelqu'un, sait-on jamais...
C'est par ici : hamming.
lundi 13 février 2012
Par poz le lundi 13 février 2012, 10:42 - geeking
Bon, ce week end je me faisais passablement chier, et en explorant le contenu de mon $HOME je me suis rendu compte que c'était un peu le bordel, quand même. Des fichiers inutiles, des doublons, etc.
Du coup, illumination, le doigt du génie a effleuré mon front obtus l'espace d'un instant : et si je codais un truc-machin pour repérer tous les fichiers identiques sur ma machine ?!
Et voilà, fdup est né (c'est du C, parce que comme je m'embêtais je voulais pas faire un "one-liner" en shell avec find(1) + awk(1), faut bien s'occuper) ! C'est super minimaliste pour l'instant, hein, y'a genre 2-3 options qui se tirent la bourre, et pis c'est tout.
Je vous entends ricaner d'ici : bien sûr qu'il y a d'autres outils qui font le même boulot (fdupes(1), duff, y'a même un fdup déjà présent sur github -- bon, la description dans le README est un peu nawak mais on s'en fout !), mais ça, je m'en suis aperçu qu'après mon premier commit. Comme d'hab'.
mardi 18 octobre 2011
Par eau le mardi 18 octobre 2011, 17:50 - geeking
En ces temps de gang bang d'ego généralisé, de benchmarking de performance sur l'échelle Ritchie (RIP) et autre courses a la réussite sociale, il reste des gens dont la carriere et la publication frénétique d'information pour voir son nombre de hits et ses fans augmenter toute en mimant le désintérêt et le detachement n'est pas au centre de leur vie et arrivent a s'amuser et surtout a avoir de l'auto derision, ca m'a fait hurler de rire alors que c'est completement debile, mais c'est pas grave, j'ai ris, ca fait du bien! donc je "share" :)
Sa premiere idee farfelue (hahahaha):
/* ** pam_happy_hour.c - PAM happy hour auth module. Solaris 2.6+ ** During happy hour passwords aren't required, any will do. ** [...]
Allez j'en pioche une autre dans le tas (:~)):
# maybe - companion to /usr/bin/true and /usr/bin/false. # # This should be installed in your system location, eg /usr/bin/maybe. [...]
Et il en a fait pleins d'autre aussi farfelue a voir la:
vendredi 7 octobre 2011
Par poz le vendredi 7 octobre 2011, 15:15 - geeking
Beh voilà, encore un peu d'auto-promotion. Et en fait j'ai un peu menti, ça fait plusieurs mois que je ne commit qu'un bout de code par-ci ou par-là.
Ma société a écrit une bibliothèque en open source pour travailler sur le cloud (différents protocoles supportés, mais je vous laisse découvrir ça). Bref, je me suis basé sur cette lib pour implémenter un filesystem en utilisant FUSE : dropletfs ; c'est lent (car le design est simpliste et pas optimisé), mais rigolo.
Toutes les features d'un FS posix ne sont pas présentes, loin de là (gérer les hardlinks est plutôt compliqué), mais pour un usage basique, ça 'juste marche'.
Une petite démo intéractive (nécessite le package ttyrec) : ici
samedi 18 juin 2011
Par eau le samedi 18 juin 2011, 10:50 - geeking
Apres quelques conversations avec un pote sur cette nouvelle "monnaie" électronique, il m'a fait constater un ensemble de propriétés marrantes et interessantes (pas de trusted third party, la resolution d'un problème mathématique pour limiter l'emission de monnaie, etc..), j'ai beaucoup de lacunes quand au fonctionnement économique actuel, mais le fonctionnement de cette monnaie et l'utilisation de la crypto et du réseau pour definir ces propriétés, a lire et suivre!
jeudi 17 février 2011
Par poz le jeudi 17 février 2011, 13:26 - geeking
Yo yo yo.
J'avais une base de code, avec pas mal de fonctions déjà implémentées, et
puis je me suis dit "ooooomm, faudrait que je trace le temps d'exécution de
chacune de ces fonctions, pour savoir où concentrer mes efforts, en faisant
telle et telle stat'". Bon alors je vous entends déjà barir au loin "hey mais
pauvre naze, y'a plein d'outils de profiling", et c'est vrai. Seulement je
voulais faire un truc à ma sauce d'une part (histoire de voir un peu comment ça
fonctionne), et surtout pouvoir ajouter les stats qui m'intéressent, faire des
trucs aux p'tits oignons quoi. Et puis c'est pas comme si ça prenait des jours
à coder.
Alors après avoir cherché un peu, je tombe sur la doc GCC (même le man en parle, à vrai dire) :
void __cyg_profile_func_enter(void *func, void *callsite); void __cyg_profile_func_exit(void *func, void *callsite);
Ces fonctions sont appelées respectivement à l'entrée et la sortie de
chacune des fonctions de votre programme. Il y a une linuxerie ensuite pour
obtenir le nom de l'appelant, ie. passer par dladdr() ou
__build_return_address(0). Ensuite vous stockez les infos comme
vous voulez, perso j'utilise une hashtable dont les clefs sont les symboles
(aka noms de fonctions), avec chaque cellule contenant des stats, sur le nombre
d'appel, le temps d'exécution moyen, etc.
J'ai utilisé ça pour un code sur lequel je passe un peu de temps en ce moment, et la sortie ressemble à (le > correspond à l'entrée dans la fonction, le < à la sortie, faudrait rendre le truc plus joli avec un système de pile pour avoir la profondeur d'appel de chacune en fonction d'un décalage horizontal, mais bon, ça viendra après) :
[...]
1297941768.719531 > dfs_mkdir@0x40f534
1297941768.719607 > dfs_mkdir_timeout@0x41398f
1297941769.416415 < dfs_mkdir_timeout@0x41398f -- 696ms
1297941769.416445 < dfs_mkdir@0x40f534 -- 696ms
1297941769.416469 > dfs_getattr@0x40c16c
1297941769.416684 > dfs_namei_timeout@0x413ef7
1297941769.534098 < dfs_namei_timeout@0x413ef7 -- 117ms
1297941769.534161 > dfs_getattr_timeout@0x413690
1297941770.104592 < dfs_getattr_timeout@0x413690 -- 570ms
1297941770.104874 < dfs_getattr@0x40c16c -- 570ms
-- report --
symbol dfs_getattr_timeout: #calls: 46, average call duration: 266ms
symbol dfs_opendir_timeout: #calls: 1, average call duration: 780ms
symbol dfs_namei_timeout: #calls: 47, average call duration: 299ms
symbol dfs_chdir_timeout: #calls: 1, average call duration: 0ms
symbol dfs_mkdir: #calls: 1, average call duration: 696ms
symbol dfs_getattr: #calls: 48, average call duration: 275ms
symbol dfs_mkdir_timeout: #calls: 1, average call duration: 696ms
Le code (crados, pas encore nettoyé) est visible ici.
Comme je disais, le truc vraiment sympa c'est juste d'avoir à appeler
profile_init() et profile_fini() dans mon code. Et
encore, on peut faire mieux en générant un .so qu'on charge avec
LD_PRELOAD, histoire d'avoir vraiment 0 code impacté. Faut juste
compiler les objets avec -fPIC et
-finstrument-functions. That's all folks.
OK c'est un profiler du pauvre, mais ici à unix4fun, on est prolos. Et on vous emmerde !
mardi 9 novembre 2010
Par eau le mardi 9 novembre 2010, 23:15 - geeking
Je lis du code généré en ce moment... en particulier du code généré par Visual C++ avec des options "star-wars-security" blablabla mais c'est pas le sujet du jour...
Le sujet du jour c'est ma relative incompétence face a des choses comme:
[...] .text:0069979F mov eax, 66666667h .text:006997A4 imul ecx .text:006997A6 sar edx, 1 .text:006997A8 mov eax, edx .text:006997AA shr eax, 1Fh .text:006997AD add eax, edx [...]
alors dans ecx, j'ai la valeur 0x20000, après des tentatives rapides de compréhension, je me suis bon les "magic values", j'en vois de temps en temps, ca pue la "magic value" des trucs de compilo-salaud pour tenter d'avoir de la précisions en continuant a travailler avec des entiers et en base2, bref..
En cherchant un peu je suis tombe la dessus:
Et j'ai enfin compris ce que ce petit snippet de code faisait, alors d’après vous il se passe quoi ? et quel est l’algèbre applique a la valeur dans ecx!? :) (je mettrais a jour avec une explication si le lien n'est vraiment pas clair...)
peace!
jeudi 4 novembre 2010
Par poz le jeudi 4 novembre 2010, 16:31 - geeking
Un billet assez exhaustif, avec des exemples de code et d'output assembleur : c'est ici
jeudi 7 octobre 2010
Par poz le jeudi 7 octobre 2010, 15:26 - geeking
Yo. Dans ce post je vais expliquer comment je me suis battu pour faire un
truc assez simple avec la libpcap sous linux.
Au début était un sniffer, je voulais écouter sur une interface à grands
coups de SOCK_RAW + recvfrom(). À l'ancienne, quoi. L'idée était de ne pas
utiliser de handler pcap (pcap_t *). Au bout d'un moment je me dis "tiens, ça
serait sympa d'ajouter les filtres BPF comme dans tcpdump". Brillante idée,
non ? Non, ok. Bref, le code de départ est le suivant :
// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
// vim:sw=4 ts=4 sts=4 expandtab
#include <limits.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>
#include <netpacket/packet.h>
#include <poll.h>
#include <linux/types.h>
#include <errno.h>
#include <pcap.h>
#include <linux/filter.h>
#define FRAME_SIZE 65536
/* iface_setprom() sets "device" in promiscuous mode */
static int
iface_setprom(int sock_fd, const char *device)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof ifr);
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", device);
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
printf("[%s] ioctl: %s.\n", device, strerror(errno));
return -1;
}
ifr.ifr_flags |= (IFF_PROMISC | IFF_UP);
if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
printf("[%s] ioctl: %s.\n", device, strerror(errno));
return -1;
}
printf("[%s] enter in promiscuous mode\n", device);
return 0;
}
À partir d'une chaîne de caractère entrée, par exemple "tcp and port 22", on
veut obtenir une structure comprise par pcap_compile*(). Comme dit
précédemment, je ne veux pas de pcap_t* à manipuler, je vais donc utiliser
pcap_compile_nopcap() (non mentionné dans le man de pcap_compile sous linux,
évidemment).
/* iface_setfilter() applies a LSF filter to the file descriptor */
static int
iface_setfilter(int sock_fd, const char * const device, const char * const filter)
{
if (!filter || !*filter) {
printf("[%s] no filter to install\n", device);
return 0;
}
struct bpf_program bpf;
memset(&bpf, 0, sizeof bpf);
char errbuf[PCAP_ERRBUF_SIZE = "";
if (-1 == pcap_compile_nopcap(FRAME_SIZE, DLT_RAW, &bpf, filter, 1, 0)) {
printf("[%s] pcap_compile_nopcap failed for '%s'\n", device, filter);
return -1;
}
if (-1 == setsockopt(sock_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof bpf)) {
printf("[%s] setsockopt: %s (filter '%s')\n", device, strerror(errno), filter);
return -1;
}
printf("[%s] filter '%s' successfully installed\n", device, filter);
return 0;
}
/* iface_init() is the main device initialization function */
static int
iface_init(struct pollfd *fds, const char * const device, const char * const filter)
{
printf("Initializing interface %s (filter '%s')\n", device, filter);
fds->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (fds->fd == -1) {
printf("[%s] socket: %s. Exiting...\n", device, strerror(errno));
exit(EXIT_FAILURE);
}
fds->events = POLLIN | POLLPRI;
if (0 != iface_setprom(fds->fd, device)) return -1;
if (0 != iface_bind(fds->fd, device)) return -1;
if (0 != iface_setfilter(fds->fd, device, filter)) return -1;
return 0;
}
static void
frame_manager(const char * const device, struct pollfd *fd, struct timeval const *now)
{
uint32_t i;
if ((fd->revents & (POLLIN | POLLPRI)) == 0)
return;
unsigned char buf[1500] = "";
ssize_t n = recvfrom(fd->fd, buf, sizeof buf, MSG_DONTWAIT, NULL, NULL);
if (n < 0) {
printf("[%s] recvfrom: %s (i=%d, fd=%d)\n", device, strerror(errno), i, fd->fd);
return;
}
printf("[%d,%d] packet received\n", (int)now->tv_sec, (int)now->tv_usec);
}
int main(int ac, char **av)
{
char *filter = "";
char *device = "dummy0";
if (ac > 1) {
filter = av[1];
}
struct pollfd fd;
(void)iface_init(&fd, device, filter);
while (/*CONSTCOND*/ 1) {
if (poll(&fd, 1, -1) > 0) {
struct timeval now;
gettimeofday(&now, NULL);
frame_manager(device, &fd, &now);
}
}
close(fd.fd);
return EXIT_SUCCESS;
}
Tout d'abord, je monte une interface virtuelle pour éviter le bruit généré
par les paquets circulants sur mes vraies interfaces :
$ sudo modprobe dummy $ sudo ifconfig dummy0 mtu 1600 up
Maintenant, si je compile et j'exécute le code, et que je balance du ssh sur
dummy0, j'ai ça :
$ cc -o cap cap.c -lpcap $ sudo ./cap "tcp and port 22" [...]
Et dans un autre terminal :
$ sudo tcpreplay -i dummy0 ssh.pcap
Mais aucun "packet received" ne s'affiche. Damned ! En inspectant un
peu le code, on voit ça :
if (-1 == setsockopt(sock_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof bpf)) {
Ça a l'air bien comme ça, hein. Malheureusement, le 'struct bpf_program'
n'est pas compris sous linux, qui, ne voulant pas faire comme ses potes *BSD
attend un 'struct sock_fprog *' en avant dernier argument. Bon, ici je me dis
"il doit bien y avoir une fonction qui fait la conversion, cherchons dans le
source de libpcap". En jetant un coup d'oeil rapide, on tombe sur
ça :
libpcap-0.9.8/pcap-linux.c:215 static int fix_program(pcap_t *handle, struct sock_fprog *fcode);
Je suis content, mais visiblement je dois passer par un pcap_t. Du coup, je
reprends le code en l'adaptant pour taper directement dans la structure interne
du handler pcap, et j'écris la fonction suivante :
#define SLL_HDR_LEN 16
static int lcc = 0; // linux cooked capture
static int
fix_offset(struct bpf_insn *p)
{
if (p->k >= SLL_HDR_LEN) {
p->k -= SLL_HDR_LEN;
} else if (p->k == 14) {
p->k = SKF_AD_OFF + SKF_AD_PROTOCOL;
} else {
return -1;
}
return 0;
}
static int
fix_code(struct bpf_program *bpf, struct sock_fprog *fcode)
{
size_t prog_size;
register int i;
register struct bpf_insn *p;
struct bpf_insn *f;
int len;
len = bpf->bf_len;
prog_size = sizeof(bpf->bf_insns) * len;
f = malloc(prog_size);
if (f == NULL) {
printf("malloc: %s\n", strerror(errno));
return -1;
}
memcpy(f, bpf->bf_insns, prog_size);
fcode->len = len;
fcode->filter = (struct sock_filter *)f;
for (i = 0; i < len; ++i) {
p = &f[i];
switch (BPF_CLASS(p->code)) {
case BPF_RET:
if (BPF_MODE(p->code) == BPF_K) {
if (p->k != 0)
p->k = 65535;
}
break;
case BPF_LD:
case BPF_LDX:
switch (BPF_MODE(p->code)) {
case BPF_ABS:
case BPF_IND:
case BPF_MSH:
if (lcc) {
if (fix_offset(p) < 0) {
return 0;
}
}
break;
}
break;
}
}
return 1; /* success! */
}
Maintenant je réécris ma fonction iface_setfilter() pour convertir le code
BPF :
static int
iface_setfilter(int sock_fd, const char * const device, const char * const filter)
{
if (! filter || ! *filter) {
printf("[%s] no filter to install\n", device);
return 0;
}
struct bpf_program bpf;
memset(&bpf, 0, sizeof bpf);
if (-1 == pcap_compile_nopcap(FRAME_SIZE, DLT_RAW, &bpf, filter, 1, 0)) {
printf("[%s] pcap_compile_nopcap failed for '%s'\n", device, filter);
return -1;
}
struct sock_fprog fcode;
memset(&fcode, 0, sizeof fcode);
int ret = fix_code(&bpf, &fcode);
if (1 != ret) {
printf("[%s] fix_code failed (rcode = %d) for filter '%s'\n", device, ret, filter);
return -1;
} else {
printf("[%s] fix_code worked (rcode = %d) for filter '%s'\n", device, ret, filter);
}
if (-1 == setsockopt(sock_fd, SOL_SOCKET, SO_ATTACH_FILTER, &fcode, sizeof fcode)) {
printf("[%s] setsockopt: %s (filter '%s')\n", device, strerror(errno), filter);
return -1;
}
printf("[%s] filter '%s' successfully installed\n", device, filter);
return 0;
}
Là, logiquement je me dis "Youpi les knakis¸ ça va marcher !". Mais si je
reteste, toujours rien. Rien ne s'affiche. La blague est même que si
j'invoque :
$ sudo ./cap "not port 80"
... et que je joue du traffic http (sur le port 80 bien sûr), mon outil
logue qu'il a vu un paquet ! Par contre avec "port 80" il n'affiche rien.
Bon je me suis pas mal gratté la tête ici, j'avoue. Du coup j'appelle mon
copain strace à la rescousse, et je compare le raw des filtres passés à
setsockopt() entre mon code et l'appel tcpdump :
$ sudo strace -s 256 -f -v ./cap "port 80" 2>&1 | grep ATTACH_FILTER setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, "\33\0\0\0\0\0\0\0\20\240\363\0\0\0\0\0", 16) = 0 ^C $ sudo strace -s 256 -f -v tcpdump -ni dummy0 port 80 2>&1 | grep ATTACH_FILTER setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, "\1\0\0\0\0\0\0\0h\303\315E(\177\0\0", 16) = 0 setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, "\30\0\0\0\0\0\0\0\360V1G(\177\0\0", 16) = 0 ^C
Les outputs ne sont pas les mêmes. La génération du filtre est donc
foireuse, je vérifie maintenant comme suit :
$ sudo tcpdump -nd port 80 (000) ldh [12] (001) jeq #0x86dd jt 2 jf 10 (002) ldb [20] (003) jeq #0x84 jt 6 jf 4 (004) jeq #0x6 jt 6 jf 5 (005) jeq #0x11 jt 6 jf 23 (006) ldh [54] (007) jeq #0x50 jt 22 jf 8 (008) ldh [56] (009) jeq #0x50 jt 22 jf 23 (010) jeq #0x800 jt 11 jf 23 (011) ldb [23] (012) jeq #0x84 jt 15 jf 13 (013) jeq #0x6 jt 15 jf 14 (014) jeq #0x11 jt 15 jf 23 (015) ldh [20] (016) jset #0x1fff jt 23 jf 17 (017) ldxb 4*([14]&0xf) (018) ldh [x + 14] (019) jeq #0x50 jt 22 jf 20 (020) ldh [x + 16] (021) jeq #0x50 jt 22 jf 23 (022) ret #96 (023) ret #0
Et j'invoque
if (-1 == pcap_compile_nopcap(FRAME_SIZE, DLT_RAW, &bpf, filter, 1, 0)) {
printf("[%s] pcap_compile_nopcap failed for '%s'\n", device, filter);
return -1;
}
bpf_dump(&bpf, 0);
J'ai en sortie :
Initializing interface dummy0 (filter 'port 80') [dummy0] enter in promiscuous mode [dummy0] bind succeed: index 1634 <--> dummy0 (000) ldb [0] (001) and #0xf0 (002) jeq #0x60 jt 3 jf 11 (003) ldb [6] (004) jeq #0x84 jt 7 jf 5 (005) jeq #0x6 jt 7 jf 6 (006) jeq #0x11 jt 7 jf 26 (007) ldh [40] (008) jeq #0x50 jt 25 jf 9 (009) ldh [42] (010) jeq #0x50 jt 25 jf 26 (011) ldb [0] (012) and #0xf0 (013) jeq #0x40 jt 14 jf 26 (014) ldb [9] (015) jeq #0x84 jt 18 jf 16 (016) jeq #0x6 jt 18 jf 17 (017) jeq #0x11 jt 18 jf 26 (018) ldh [6] (019) jset #0x1fff jt 26 jf 20 (020) ldxb 4*([0]&0xf) (021) ldh [x + 0] (022) jeq #0x50 jt 25 jf 23 (023) ldh [x + 2] (024) jeq #0x50 jt 25 jf 26 (025) ret #65536 (026) ret #0 [dummy0] fix_code worked (rcode = 1) for filter 'port 80' [dummy0] filter 'port 80' successfully installed ^C
On voit bien que c'est différent au début. Le reste est plutôt
cohérent
(016) jeq #0x6 jt 18 jf 17 # 0x06 c'est l'IPPROTO_TCP (6) (017) jeq #0x11 jt 18 jf 26 # 0x11 = 17 = IPPROTO_UDP
Si on n'est dans aucun des deux cas, on saute en 26 (jf 26), soit la fin.
Sinon, on regarde si le port vaut 80 (0x50) :
(022) jeq #0x50 jt 25 jf 23 (023) ldh [x + 2] (024) jeq #0x50 jt 25 jf 26
Le problème est vraiment le prologue. Et là je on me souffle à l'oreille que
c'est peut-être le datalink type. Réaction: "bon dieu de !#@@!#@!# mais c'est
bien sûr, ça doit être mon datalink (DLT) qui est moisi !" Si
j'écris :
if (-1 == pcap_compile_nopcap(FRAME_SIZE, DLT_IEEE802, &bpf, filter, 1, 0)) {
J'obtiens en sortie :
$ cc -o cap cap.c -lpcap && sudo ./cap "port 80" Initializing interface dummy0 (filter 'port 80') [dummy0] enter in promiscuous mode [dummy0] bind succeed: index 1634 <--> dummy0 (000) ldh [20] (001) jeq #0x86dd jt 2 jf 10 # 0x86dd est l'ethertype IPv6 (002) ldb [28] (003) jeq #0x84 jt 6 jf 4 (004) jeq #0x6 jt 6 jf 5 (005) jeq #0x11 jt 6 jf 23 (006) ldh [62] (007) jeq #0x50 jt 22 jf 8 (008) ldh [64] (009) jeq #0x50 jt 22 jf 23 (010) jeq #0x800 jt 11 jf 23 # 0x800 est l'ethertype IPv4 [...]
Mais toujours rien n'est logué si je joue du http ! En remplaçant
DLT_IEEE802 par DLT_EN10MB en revanche...
[...] [dummy0] enter in promiscuous mode [dummy0] bind succeed: index 1634 <--> dummy0 [dummy0] fix_code worked (rcode = 1) for filter 'port 80' [dummy0] filter 'port 80' successfully installed [1286457559,615193] packet received
Hallelujah ! Hosanna hosanna !
Enfin bon, c'est quand même moche d'écrire le DLT en dur dans le code, donc
je l'ai récupéré via la libpcap (mais on est obligé de passer par un handler
pcap_t *, ce que je ne voulais pas trop au début...)
char errbuf[256] = "";
pcap_t *p = pcap_open_live(device, FRAME_SIZE, 1, 0, errbuf);
if (! p) {
printf("[%s] pcap_open_live failed: %s\n", device, errbuf);
return -1;
}
int dlt = pcap_datalink(p);
pcap_close(p);
if (-1 == pcap_compile_nopcap(FRAME_SIZE, dlt, &bpf, filter, 1, 0)) {
printf("[%s] pcap_compile_nopcap failed for '%s'\n", device, filter);
return -1;
}
En fait, comme on dispose du handler pcap_t, on peut même dégager pcap_compile_nopcap() et utiliser pcap_compile(), qui lui n'a même pas besoin d'un DLT en paramètre... Tout ça parce que j'ai voulu me passer de ce foutu handler, en somme. Bref le code est disponible ici
mercredi 15 septembre 2010
Par eau le mercredi 15 septembre 2010, 10:36 - geeking
Pendant ma petite pause lecture du matin, je suis tombé sur ce post concernant les nouvelles updates de la GNU toolchain, et en particulier un nouvel attribut: "ifunc"
Ca permet de définir dynamiquement une fonction qui va "résoudre" vers la fonction de votre choix en fonction de critères que vous pouvez définir, le monsieur @ http://nickclifton.livejournal.com/6612.html donne un exemple très simple et très clair (plus clair que mes explications foireuses) que je reproduirais ici :
void *slow_memcpy (void *dst, const void *src, size_t len)
{
char *d = dst; char *s = src;
while (len--)
*d++ = *s++;
return dst;
}
void *fast_memcpy (void *dst, const void *src, size_t len)
{
__asm("foo %0 %1 %2" : "=m" (dst) : "m" (src), "r" (len) : memory);
return dst;
}
static void (* resolve_memcpy (void)) (void)
{
return __cpu_has_foo () ? fast_memcpy : slow_memcpy;
}
void *memcpy (void *, const void *, size_t) __attribute__ ((ifunc ("resolve_memcpy")));
Les details chez http://nickclifton.livejournal.com/6612.html
lundi 16 août 2010
Par eau le lundi 16 août 2010, 17:29 - geeking
Je suis une grosse feignasse et je lis pas énormément de code, en ce moment je lis des trucs fait sur de l'ARM. En bonne grosse tanche, je n'avais jamais vu ces CMP suivi d'un CMPNE et d'un BXX ou un MOVXX etc.. (c'est en mode ARM only) ailleurs:
CMP R1,#1 CMPNE R2,#2 BEQ bleh
Heureusement qu'il y a l'internet poilu pour éclairer et donner des belles recettes.
J'ai trouve des gens qui parlent de comment on fait un poulet roti et comment voir si il est bien cuit!
Apparemment tu peux chainer des conditions tranquillement avec un petit "suffix" dans l'instruction (il y a des bits réservés dans l'instruction pour ces options ARM-only)
voila ca m'a rendu service aujourd'hui enjoy!
mercredi 9 juin 2010
Par frl le mercredi 9 juin 2010, 11:43 - geeking
Pour un premier post, désolé, c'est sur du win32 :). Je lisais dernièrement
"GrayHat Python"
et je découvre Pydbg (un debugger écrit en python) que je ne connaissais pas
(bon je ne connais pas grand chose non plus, du coup c'est plus facile d'être
émerveillé) et dans le chapitre sur le hooking je tombe sur un exemple de
"soft-hooking" (le hooking avec un breakpoint soft (INT3) sur la fonction qui
t'intéresse) pour "sniffer" les connections SSL dans firefox (hook sur une
fontion specifique de firefox).
Ca me rappelle des discussions avec eau qui avait déjà commence a
bosser dessus, en voyant comment le truc est tout con ca m'a donne envie de
voir si hooker les "CryptoAPI"s de MS que IE utilise est tout aussi
simple.
Donc une fois recup Pydbg, un petit "import pydbg" et on peut
instancier un object debugger mydbg=pybdg.pydbg().
Et voila! maintenant qu'on a notre debugger instancié, on peut s'attacher a des
process, mettre des breakpoints, lire l'etats des registres etc.. Un peu comme
scripter a l'interieur d'IDA ou ImmunityDebugger.
Du coup c'est vrai que le soft hooking comme ca c'est tout bidon. Un petit
breakpoint dans la fonction qui nous intéresse, une callback fonction pour
effectuer des opérations sur cette fonction et on release le breakpoint pour
que le process continue normalement.
Bon, c'est pas efficace du tout côté perf, c'est clair...
Mais pour un ptit hooking rapido histoire de tester/fuzzer un truc ca peut etre
sympa et utile.
Alors voila j'ai matte les CryptoAPI de MS et j'ai pense d'abord hooker
"CryptEncrypt()" et "CryptDecrypt()" exportées par
"Advapi32.dll".
Ok finalement en cherchant un peu, il y a eut pleins de présentations sur le
hooking de ces 2 fonctions (par exemple celle-ci) et en effet c'est tout bon mais pour sniffer
uniquement.
Si on veut modifier les requêtes envoyées par exemple, alors la on voit
qu'on tombe sur un os, en tracant les appels un certain
"CryptHashData()" est appelé avant "CryptEncrypt()"
et donc dommage.. Difficile de modifier un truc hashe préalablement sans que ca
se voit! Et la ce cher eau me dit qu'il avait regarde
"EncryptMessage()" et "DecryptMessage()" et il avait
raison le bougre!
En effet "EncryptMessage()" prend la requête, appele
"CryptHashData()" puis "CryptEncrypt()" et balance
tout ca hashé/chiffré ensuite au fonctions résal(réseaux). Du coup hooker
"EncryptMessage()" est bien plus intéressant puisqu'avant le hash
donc possible de modifier la requête.
Je n'ai pas encore réussi a faire tout ce que je voulais sur
"EncryptMessage()", modifier la requête...ok, mais uniquement si
sa nouvelle taille est <= a l'originale. Pour en générer une de taille >
a la requête originale, je coince.
J'ai essaye de mettre a jour la taille a plusieurs endroits, re-ecrire la requête en allouant assez de place ailleurs et updater les pointeurs/références sur ma nouvelle requête mais niet... je dois merder, quelque chose m'échappe.
Voyant que des fonctions appelées avant "EncryptMessage()"
manipulaient aussi la requête HTTP et utilisaient la taille pour différents
trucs que je n'ai pas exploré je me suis résigné a hooker la dedans et c'est
passé. Enfin, j'ai finalement hooke une fonction qui se trouve dans
"Wininet.dll" mais elle semble tres specifique a IE donc pas super
fonctionnel pour autre chose qu'IE... (i.e. Thick Client)...
Pour ceux que ca intéresse, voila un petit bout de code tout bidon (et pas
beau je sais :)..) mais c'est juste pour tester et voir comment jouer avec
pydbg et le soft-hooking:
J'ai teste ca sur XP SP2 en anglais avec IE7.
Un petit print screen aussi pour voir ce que ca donne:
Pydbg fait parti du framework Paimei (du coup ca m'a donne envi de revoir
kill bill2..):
Paimei
svn checkout http://paimei.googlecode.com/svn/trunk/pydbg
paimei-read-only
CryptEncrypt(), CryptDecrypt(), EncryptMessage(), DecryptMessage()
Ca passe ok avec python 2.6 sur ma VM XP mais quelques posts disent que pydasm ne passe bien qu'avec python 2.5.
lundi 26 avril 2010
Par eau le lundi 26 avril 2010, 23:31 - geeking
En ce moment je bricole des trucs en assembleur x86/x86-64 et MIPS (wouhouu j'ai un loongson 2f!), alors du coup j'ai qqes liens:
Et j'en profite pour dire que pour tester il y a:
Et il y a aussi qqes petits liens classiques:
vendredi 29 janvier 2010
Par eau le vendredi 29 janvier 2010, 22:57 - geeking
Un projet marrant et que je trouve super drole, j'ai a peine commence a lire et j ai pas poste depuis des lustres, allez hop c'est la fete :)
Un projet pour "eviter" les deadlock sans avoir a recompiler quoique ce soit, vais tester ca gentillement ce soir!
Le project:
Le paper:
Le code:
jeudi 17 décembre 2009
Par eau le jeudi 17 décembre 2009, 23:26 - geeking
Un projet super poilu, qui a pour but de construire une machine entiere "au travers d'"/"via" un FPGA, alors que je commence a peine a comprendre les debut de bases de VHDL et a faire mes premiers debuts d'embryons de tests, de trucs tout moisis, on me souffle ce lien, je vois ca et la pouf, je bande....mais j'y comprends encore rien, je vous rassure..
Le lien erectile:
« billets précédents - page 1 de 4