|
|
|
@ -1,42 +1,83 @@ |
|
|
|
|
\chapter{Debug}\index{Debug} |
|
|
|
|
\label{chap:debug} |
|
|
|
|
|
|
|
|
|
Quand plus rien ne marche, il existe encore un espoir... |
|
|
|
|
Quand plus rien ne marche, reste-il encore un espoir ? |
|
|
|
|
Il existe bien entendu des outils \textsl{mainstream} |
|
|
|
|
tels que le classique \texttt{gdb}\index{gdb}, mais il en existe |
|
|
|
|
une foultitude d'autres, injustement méconnus. |
|
|
|
|
En voici quelques-uns. |
|
|
|
|
|
|
|
|
|
\section{strace}\index{strace} |
|
|
|
|
|
|
|
|
|
% ============================================================== |
|
|
|
|
|
|
|
|
|
\section{Strace}\index{strace} |
|
|
|
|
|
|
|
|
|
Strace permet de tracer les appels systèmes d'un processus. |
|
|
|
|
Comme vous le savez tous, un appel système |
|
|
|
|
(aka syscall\index{syscall}) |
|
|
|
|
est \textbf{le} moyen de communication qu'utilise un process |
|
|
|
|
utilisateur pôur demander un service au noyau. |
|
|
|
|
|
|
|
|
|
\begin{verbatim} |
|
|
|
|
strace -o toto ./kluge |
|
|
|
|
\end{verbatim} |
|
|
|
|
|
|
|
|
|
% ============================================================== |
|
|
|
|
|
|
|
|
|
\section{LD\_PRELOAD}\index{LD\_PRELOAD} |
|
|
|
|
|
|
|
|
|
D'accord, aves \texttt{strace} nous pouvons voir passer les |
|
|
|
|
appels systèmes, mais dans la vie d'un process, certaines |
|
|
|
|
opérations ne sortent pas de la \texttt{libc}\index{libc}. |
|
|
|
|
L'une d'entre elles, \texttt{getenv(3)}, va nous servir d'exemple. |
|
|
|
|
|
|
|
|
|
\begin{verbatim} |
|
|
|
|
NAME |
|
|
|
|
getenv - get an environment variable |
|
|
|
|
SYNOPSIS |
|
|
|
|
#include <stdlib.h> |
|
|
|
|
char *getenv(const char *name); |
|
|
|
|
DESCRIPTION |
|
|
|
|
The getenv() function searches the environment list to find the envi‐ |
|
|
|
|
ronment variable name, and returns a pointer to the corresponding value |
|
|
|
|
string. |
|
|
|
|
\end{verbatim} |
|
|
|
|
|
|
|
|
|
Cette fonction est utilisée par un logiciel pour avoir accès à |
|
|
|
|
son contexte extérieur, son environnement, dans lequel on |
|
|
|
|
peut trouver (entre autres) la variable \texttt{\$LOGNAME} qui, |
|
|
|
|
oh surprise, contient votre nom de login. |
|
|
|
|
|
|
|
|
|
Et justement, vous avez un programme sous la main que vous suspecter |
|
|
|
|
d'avoir un problème relationnel avec cette variable. |
|
|
|
|
Il nius faut donc remplacer le getenv de la libc par notre propre |
|
|
|
|
version qui va écouter et exfiltrer l'utilisation de cette |
|
|
|
|
fonction. |
|
|
|
|
|
|
|
|
|
\begin{lstlisting}[language=C] |
|
|
|
|
/* |
|
|
|
|
spy_getenv.so: spy_getenv.c Makefile |
|
|
|
|
spy_getenv.so: spy_getenv.c Makefile |
|
|
|
|
gcc -Wall -shared -fPIC $< -ldl -o $@ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
|
|
#define __USE_GNU |
|
|
|
|
#include <dlfcn.h> |
|
|
|
|
|
|
|
|
|
typedef char * (*original_getenv)(const char *envname); |
|
|
|
|
|
|
|
|
|
char *getenv(char *envname) |
|
|
|
|
{ |
|
|
|
|
static char *arrow = "--getenv--> "; |
|
|
|
|
static char *wtf = " --> WTF ?"; |
|
|
|
|
|
|
|
|
|
char *content; |
|
|
|
|
original_getenv orig_getenv; |
|
|
|
|
|
|
|
|
|
original_getenv orig_getenv; |
|
|
|
|
orig_getenv = (original_getenv)dlsym(RTLD_NEXT, "getenv"); |
|
|
|
|
|
|
|
|
|
write(STDERR_FILENO, arrow, strlen(arrow)); |
|
|
|
|
write(STDERR_FILENO, envname, strlen(envname)); |
|
|
|
|
|
|
|
|
|
content = orig_getenv(envname); |
|
|
|
|
if (NULL != content) { |
|
|
|
|
write(STDERR_FILENO, "=", 1); |
|
|
|
@ -47,9 +88,13 @@ else { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
write(STDERR_FILENO, "\n", 1); |
|
|
|
|
|
|
|
|
|
return content; |
|
|
|
|
} |
|
|
|
|
\end{lstlisting} |
|
|
|
|
|
|
|
|
|
Simple et efficace. |
|
|
|
|
|
|
|
|
|
% ============================================================== |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
% ============================================================== |
|
|
|
|