Debugging Session : Anti-Anti-ptrace() or Fooling The Debugger Fooler



Documents pareils
ERESI : une plate-forme d analyse binaire au niveau noyau

IFT Systèmes d exploitation - TP n 1-20%

Les vulnérabilités du noyau. LECORNET Olivier LEGROS Bruno VIGIER Nicolas Promo 2005

Les techniques de protection du logiciel

Playing with ptrace() for fun and profit

Programmation système en C/C++

ERESI : une plate-forme d'analyse binaire au niveau noyau. The ERESI team

Logiciel de base. Première année ENSIMAG

Structure d un programme

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

SSTIC Désobfuscation automatique de binaires. Alexandre Gazet. Yoann Guillot. Et autres idyles bucoliques...

Arguments d un programme

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu.

Architecture des ordinateurs

Mon premier rpm. 7 juin Avant de commencer RPM URPMI RPMBUILD... 2

Le Projet BINSEC. Automatiser l analyse de sécurité au niveau binaire. Airbus group, CEA, IRISA, LORIA, Uni. Joseph Fourier. p.

Machines virtuelles. Brique ASC. Samuel Tardieu Samuel Tardieu (ENST) Machines virtuelles 1 / 40

Débogage de code* Mardi 13 décembre Romaric DAVID Université de Strasbourg - Direction Informatique Pôle HPC. hpc.unistra.

INFO-F-404 : Techniques avancées de systèmes d exploitation

Introduction au langage C

Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie

Quelques éléments de compilation en C et makefiles

Résumé Génération de code Le code intermédiaire

OS Réseaux et Programmation Système - C5

Malicious debugger! Fred Raynal & Jean-Baptiste Bedrune Sogeti IS / ESEC. 14 mai 2007

Les failles Format String

Formation à Linux Embarqué. Jérôme Pouiller

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

Le prototype de la fonction main()

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51

Programmation système de commandes en C

How to Login to Career Page

Programmation assembleur : aperçu

Une introduction à Java

Programmation système I Les entrées/sorties

Couche application. La couche application est la plus élevée du modèle de référence.

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Génération de code binaire pour application multimedia : une approche au vol

Premiers Pas en Programmation Objet : les Classes et les Objets

IN Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

Le Langage C Version 1.2 c 2002 Florence HENRY Observatoire de Paris Université de Versailles florence.henry@obspm.fr

lundi 3 août 2009 Choose your language What is Document Connection for Mac? Communautés Numériques L informatique à la portée du Grand Public

Rappels Entrées -Sorties

Cours Programmation Système

calls.paris-neuroscience.fr Tutoriel pour Candidatures en ligne *** Online Applications Tutorial

France SMS+ MT Premium Description

Architecture des ordinateurs

Chapitre 10. Les interfaces Comparable et Comparator 1

Analyse de sécurité de logiciels système par typage statique

Chapitre I Notions de base et outils de travail

Désobfuscation automatique de binaire - The Barbarian Sublimation

Conventions d écriture et outils de mise au point

Un serveur web léger et ouvert

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Exceptions. 1 Entrées/sorties. Objectif. Manipuler les exceptions ;

Application Form/ Formulaire de demande

WDpStats Procédure d installation

Introduction à la Programmation Parallèle: MPI

Derrière toi Une machine virtuelle!

Corrigés des premiers exercices sur les classes

DNS Server RPC Interface buffer overflow. Céline COLLUMEAU Nicolas BODIN

INGÉNIEUR - DÉVELOPPEUR SENIOR Logiciels Audio - DSP - Embedded C - C/C++ 35 ans - 10 ans d'expérience

TwinCAT 3 C++ Création de modules C++ sous TwinCAT 3 VERSION : 1.0 / PH

Java Licence Professionnelle CISII,

GlobalScape Secure FTP Server Buffer Overflow

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Plan du cours. Historique du langage Nouveautés de Java 7

Supervision et infrastructure - Accès aux applications JAVA. Document FAQ. Page: 1 / 9 Dernière mise à jour: 15/04/12 16:14

INSTALLATION ET CONFIGURATION DE OPENLDAP

Perl Console. Votre compagnon pour développer en Perl. Les Journées du Perl , 17 novembre, Lyon. Alexis Sukrieh

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

Programmation en C/C++

UE Programmation Impérative Licence 2ème Année

Compilation (INF 564)

Initiation à la sécurité

Table des matières PRESENTATION DU LANGAGE DS2 ET DE SES APPLICATIONS. Introduction

04/05/2011 Amundi Liquidity A creative market introduction Date

Le système de gestion des fichiers, les entrées/sorties.

Township of Russell: Recreation Master Plan Canton de Russell: Plan directeur de loisirs

Systeme d'exploitation

Paris Airports - Web API Airports Path finding

WEB page builder and server for SCADA applications usable from a WEB navigator

A.P.I. Kuka Manuel de l utilisateur Version 0.0.5

Notice Technique / Technical Manual

Tutoriel de formation SurveyMonkey

REMBO Version 2.0. Mathrice 2004 DESCRIPTION MISE EN OEUVRE CONCLUSION.

Module.NET 3 Les Assemblys.NET

Les attaques par corruption de mémoire Synopsis Mickael Deloison 22/10/2008

Algorithmique et Programmation, IMA

Cours Langage C/C++ Programmation modulaire

Tutoriel code::blocks

UE C avancé cours 1: introduction et révisions

Architecture des ordinateurs. Loïc Cuvillon. 20 novembre 2013

Introduction aux Systèmes et aux Réseaux

Cours d initiation à la programmation en C++ Johann Cuenin

Connaître la version de SharePoint installée

Instructions Mozilla Thunderbird Page 1

LEs processus coopèrent souvent pour traiter un même problème. Ces

27/11/12 Nature. SDK Python et Java pour le développement de services ACCORD Module(s)

Transcription:

Debugging Session : Anti-Anti-ptrace() or Fooling The Debugger Fooler DarKPhoeniX - [French Reverse Engineering Team] 30 août 2005 Contents 1 Introduction 1 2 Exemple de binaire protégé 2 3 Contourner la protection 4 3.1 Méthode 1 : Patching................................. 4 3.2 Méthode 2 : Hijacking ptrace()........................... 4 3.3 Méthode 3 : Hooking the syscall........................... 6 3.3.1 Création d un Loadable Kernel Module................... 7 3.3.2 Compilation du module........................... 9 3.3.3 Utilisation du module............................ 9 3.4 Méthode 4 : Ne pas utiliser ptrace()........................ 10 4 Remerciements 10 1 Introduction Dans le domaine du reverse engineering, et plus particulièrement dans l analyse de binaires éxecutables protegés, on distingue les techniques offensives et défensives. Le reverser essaie simplement d étudier, par analyse statique et dynamique, le code machine éxecuté par une application. De l autre bord, la defense consistera a tout faire pour ralentir sa tâche, en utilisant des techniques d anti-reversing consistant a brouiller toute analyse statique ou dynamique (anti-debug, false disassembly, etc...). Un anti-debugging bien connu sous la plate-forme UN*X est l utilisation de l appel système ptrace(). long ptrace(enum ptrace request request, pid t pid, void *addr, void *data) ; Celui-ci permet en temps normal de debugger un processus, mais il peut etre utiliser à des fins d anti-reversing dans la mesure ou un processus en cours de debugging ne pourra pas se ptrace()lui-même. Autrement dit, un processus pourra tenter de se ptrace()lui-même et ainsi vérifier s il n est pas soumis â un debugger. L article présent traite des méthodes pour contourner cette protection. 1

2 Exemple de binaire protégé Commencons par créer un simple éxecutable en langage C qui compare le premier argument passé avec une constante. #include < unistd. h> #include < s t d i o. h> #include < s t d l i b. h> #include < s t r i n g. h> Listing 1: Simple binaire non protégé const char password [ ] = foobar ; int main ( int argc, char argv ) { int r e t = 0 ; i f ( argc < 2 ) { p r i n t f ( Usage : % s <password>\n, argv [ 0 ] ) ; return 0 ; r e t = strcmp ( argv [ 1 ], password ) ; i f ( r e t == 0 ) p r i n t f ( Access granted! \ n ) ; else p r i n t f ( Access denied! \ n ) ; return r e t ; $./binary barfoo Access denied! $./binary foobar Access granted! A présent, ajoutons à ceci de quoi détecter un éventuel debugging. #include < unistd. h> #include < s t d i o. h> #include < s t d l i b. h> #include < s t r i n g. h> #include < sys / ptrace. h> const char password [ ] = foobar ; int main ( int argc, char argv ) { Listing 2: Detection de ptrace() 2

int r e t = 0 ; i f ( ptrace (PTRACE TRACEME, 0, 1, 0 ) < 0 ) { p r i n t f ( Are you t r y i n g to debug me?\ n ) ; return 1 ; i f ( argc < 2 ) { p r i n t f ( Usage : % s <password>\n, argv [ 0 ] ) ; return 0 ; r e t = strcmp ( argv [ 1 ], password ) ; i f ( r e t == 0 ) p r i n t f ( Access granted! \ n ) ; else p r i n t f ( Access denied! \ n ) ; return r e t ; $./antiptrace Usage :./antiptrace <password> $ gdb -q./antiptrace (no debugging symbols found)...using host libthread db library /lib/tls/libthread db.so.1. Starting program : /home/judecca/antiptrace (no debugging symbols found)...(no debugging symbols found)...are you trying to debug me? Program exited with code 01. En debuggant le programme, gdb utilise l appel système ptrace(). Le programme le détecte alors et quitte immédiatement. 3

3 Contourner la protection 3.1 Méthode 1 : Patching La méthode la plus simple et la moins propre consiste à simplement patcher physiquement l appel à ptrace()dans l ELF. Bien entendu cette méthode n est pas conseillée étant donné que le programme peut facilement détecter ce changement en effectuant un contrôle d intégrité. De plus, si le programme modifie certaines parties de son code dynamiquement (s il est packé par exemple) tout patching direct devient impossible. On recherche simplement l appel à ptrace()dans le binaire. Un simple objdump -t permet de le retrouver rapidement. push 0 push 1 push 0 push 0 call sub_80482fc ; ptrace() add esp, 10h test eax, eax jns short loc_8048424 ; positif? sub esp, 0Ch push offset aareyoutryingto ; "Are you trying to debug me?\n" call sub_804831c On repère rapidement le passage des arguments à ptrace(). On nop le saut conditionnel et c est terminé. On pourrait modifier aussi dynamiquement le contenu de EAX ou du flag SF avant le test et le jns. Un outil existe pour patcher automatiquement un binaire en effectuant un tracing sur celui-ci : http://www.packetstormsecurity.org/groups/electronicsouls/ 0x4553_Exorcist.tar.gz 3.2 Méthode 2 : Hijacking ptrace() La méthode la plus efficace à mon goût est celle consistant à intercepter les appels ptrace()afin d en modifier la valeur de retour. Pour cela, nous allons crér une librairie dynamique qui surchargera la fonction ptrace()avant la résolution des fonctions de l ELF par le linker dynamique ld. Cette bibliotèque sera donc chargée et linkée en priorité grâce à l utilisation de la variable d environnement LD PRELOAD. Notre librairie contiendra la définition d une nouvelle fonction ptrace()qui sera chargée d handler les éventuels appels à la véritable fonction ptrace(). Voici le code de l ELF qui sera chargé dynamiquement. 4

#include < unistd. h> #include < s t d i o. h> #include < l i n u x / ptrace. h> Listing 3: Hooking de ptrace() / notre f o n c t i o n hook / long ptrace ( int r e q u e s t, int pid, void addr, void data ) { p r i n t f ( ptrace ( ) has been invoked! \ n ) ; / l e processus e s s a i e de se p t r a c e? / i f ( r e q u e s t == PTRACE TRACEME ) p r i n t f ( This p r o c e s s i s t r y i n g to ptrace ( ) i t s e l f... \ n ) ; / e l s e { asm v o l a t i l e ( movl 20(% ebp ), % e s i \n movl 16(% ebp ), % edx \n movl 12(% ebp ), % ecx \n movl 8(% ebp ), % ebx \n movl $0x1A, % eax \n i n t $0x80 \n ) ; / return 0 ; // never f a i l $ gcc -Wall -c antiantiptrace.c -o antiantiptrace.o $ gcc -shared -o antiantiptrace.so antiantiptrace.o $ gdb -q./antiptrace (no debugging symbols found)...using host libthread db library /lib/tls/libthread db.so.1. gdb>set args foobar (no debugging symbols found)...(no debugging symbols found)... Are you trying to debug me? Program exited with code 01. gdb>set environment LD PRELOAD./antiantiptrace.so (no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)... ptrace() has been invoked! This process is trying to ptrace() itself... Access granted! Program exited normally. Le programme antiptrace appelle à présent la fonction ptrace()contenue dans notre librairie dynamique en croyant appeler celle contenue dans la libc. Cette fonction renvoyant toujours 0, le programme est dupé et continue de s éxecuter normalement ce qui permet de continuer l analyse. 5

3.3 Méthode 3 : Hooking the syscall Cette dernière protection n est pas efficace dans tous les cas : elle ne fait qu intercepter l appel à la fonction ptrace()contenue dans la libc. Or ptrace()est en réalité une fonction kernel accessible via l appel système 26. Autrement dit, un programme pourra directement accédé à ptrace()via l utilisation de l interruption logicielle 0x80. Listing 4: Appel de ptrace()via syscall #include < unistd. h> #include < s t d i o. h> #include < s t d l i b. h> #include < s t r i n g. h> #include < sys / ptrace. h> const char password [ ] = foobar ; int main ( int argc, char argv ) { int r e t = 0 ; a s m ( x o r l %ebx, % ebx\n // %ebx = 0 movl %ebx, % ecx \n movl %ebx, % edx\n // %edx = 0 i n c l %ecx \n // %ecx = 1 movl $0x1A, % eax\n // p t r a c e i n t $0x80\n // s y s c a l l movl %eax, 4(% ebp )\n // addr de r e t sur l a s t a c k ) ; i f ( r e t < 0 ) { p r i n t f ( Are you t r y i n g to debug me?\ n ) ; return 1 ; i f ( argc < 2 ) { p r i n t f ( Usage : % s <password>\n, argv [ 0 ] ) ; return 0 ; r e t = strcmp ( argv [ 1 ], password ) ; i f ( r e t == 0 ) p r i n t f ( Access granted! \ n ) ; else p r i n t f ( Access denied! \ n ) ; return r e t ; 6

En essayant de réutiliser notre librairie dynamique présentée en 3.2, nous obtenons : (no debugging symbols found)...(no debugging symbols found)... Are you trying to debug me? gdb>set environment LD PRELOAD./antiantiptrace.so (no debugging symbols found)...(no debugging symbols found)...(no debugging symbols found)... Are you trying to debug me? Le ptrace()ne peut plus être hijack via notre librairie. Il va donc falloir l intercepter directement dans le kernel. 3.3.1 Création d un Loadable Kernel Module Nous allons donc coder un LKM que nous injecterons dans Linux. La table des syscalls contient les differents pointeurs pour rediriger les appels vers leur fonction. Le module kernel se chargera de patcher le pointeur de ptrace()pour le faire pointer vers notre propre fonction. Celle-ci comparera le PID du processus appelant avec celui du processus débuggué et laissera passer le syscall en fonction. Le code source ci-après est destiné a un kernel 2.6.x. En effet, Linux n exporte plus sa table des syscalls depuis cette version. Nous récupérons donc son adresse hardcodée dans System.map $ grep sys call table /boot/system.map- uname -r c03b4740 D sys call table #include < l i n u x / unistd. h> #include < l i n u x / k e r n e l. h> #include < l i n u x /module. h> #include < l i n u x /moduleparam. h> #include < l i n u x / sched. h> #include <asm/ u access. h> Listing 5: Loadable Kernel Module // e x t e r n void s y s c a l l t a b l e [ ] ; // f o r l i n u x <= 2.4 / hardcoded from System. map on my 2. 6. 1 2 / #define SYS CALL TABLE 0 xc03b4740 static unsigned int pid = 0 ; int savedpid ; static asmlinkage long ( o l d p t r a c e ) ( long, long, void, void ) ; module param ( pid, int, S IRUSR S IWUSR S IRGRP S IWGRP ) ; MODULE PARM DESC( pid, Process ID to r e s t r i c t ) ; 7

asmlinkage long my sys ptrace ( long r e q u e s t, long pid, void addr, void data ) { / Check i f our proggy i s using p t r a c e / i f ( c u r r e n t >pid == savedpid ) { p r i n t k ( c a l l has been caught! \ n ) ; return 0 ; else o l d p t r a c e ( r e q u e s t, pid, addr, data ) ; / entry of lkm / int i n i t m o d u l e ( void ) { p r i n t k (KERN INFO Anti ptrace ( ) LKM loaded \n ) ; / Save the o r i g i n a l p o i n t e r / o l d p t r a c e = ( long ( ) ) ( SYS CALL TABLE+ NR ptrace sizeof ( void ) ) ; p r i n t k ( ptrace at 0 x%x, o l d p t r a c e ) ; / Replace i t with our f u n c t i o n / ( long ( ) ) ( SYS CALL TABLE+ NR ptrace sizeof ( void ) ) = &my sys ptrace ; p r i n t k ( S y s c a l l hooked\n ) ; p r i n t k ( Spying PID = %u\n, pid ) ; savedpid = pid ; void cleanup module ( void ) { i f ( ( long ( ) ) ( SYS CALL TABLE+ NR ptrace sizeof ( void ) )!= & my sys ptrace ) { p r i n t k (KERN ALERT S y s c a l l has been overwriten ) ; p r i n t k (KERN ALERT by somebody e l s e! \ n ) ; p r i n t k (KERN ALERT System can now be unstable... \ n ) ; ( long ( ) ) ( SYS CALL TABLE+ NR ptrace sizeof ( void ) ) = o l d p t r a c e ; p r i n t k ( O r i g i n a l s y s c a l l r e s t o r e d \n ) ; p r i n t k (KERN INFO Anti ptrace ( ) LKM unloaded \n ) ; La fonction init module, équivalente à main pour un programme classique, patche la table tandis que cleanup module (équivalente à atexit) la restaure. Le danger de cette opération provient du fait qu un autre module pourrait tenter de hooker ce syscall en même ce qui entrainerait un conflit dans la restauration des pointeurs. Ce module a testé sur un kernel 2.6.12 non-patché (sans PaX, rsbac, ou autre grsec...). Il faut penser à changer l adresse de sys call table avant de vouloir le recompiler. 8

3.3.2 Compilation du module Il est nécessaire de posséder les sources de son kernel pour pouvoir compiler le module. Celles-ci sont disponibles sur http://www.kernel.org Voici le contenu du fichier Makefile nécessaire pour compiler le module. obj m += noptrace. o Listing 6: Makefile a l l : make C / l i b / modules / uname r / b u i l d M= pwd modules c l e a n : make C / l i b / modules / uname r / b u i l d M= pwd $ make Building modules, stage 2. MODPOST CC /home/judecca/noptrace.mod.o LD [M] /home/judecca/noptrace.ko c l e a n Et voila notre LKM noptrace.ko prêt à l emploi! 3.3.3 Utilisation du module Le module a besoin du PID du processus débuggué pour fonctionner efficacement. Nous lancons donc une session gdb. $ gdb -q./antiptrace (no debugging symbols found)...using host libthread db library /lib/tls/libthread db.so.1. gdb>b main Breakpoint 1 at 0x80483a6 (no debugging symbols found)...(no debugging symbols found)... Breakpoint 1, 0x080483a6 in main () $ ps aux grep antiptrace judecca 6247 0.2 0.9 10460 4648 pts/2 S+ 20 :20 0 :00 gdb -q./antiptrace judecca 6248 0.0 0.0 1388 232 pts/2 T 20 :20 0 :00 /home/judecca/antiptrace judecca 6252 0.0 0.1 3752 720 pts/1 R+ 20 :20 0 :00 grep antiptrace $ su Password : # /sbin/insmod noptrace.ko pid=6248 # lsmod grep noptrace # on vérifie s il est bien chargé noptrace 2444 0 gdb> c Usage : /home/judecca/antiptrace <password> 9

Le processus n a donc pas detecté le ptrace()et gdb s est éxecuté correctement. Le module a donc bien marché! On peut alors le décharger du kernel. # /sbin/rmmod noptrace # dmesg tail -n6 Anti-ptrace() LKM loaded ptrace at 0xC0107A96 - Syscall hooked Spying PID = 6248 call has been caught! Original syscall restored Anti-ptrace() LKM unloaded 3.4 Méthode 4 : Ne pas utiliser ptrace() La fonction ptrace()n est en fait pas indispensable pour débugguer un binaire ELF, de nombreux debuggers permettent un tracing sans avoir recours à cet appel système : c est le cas des debuggers kernel comme LinICE ou PrivateICE, TheDude. La récente version de elfsh (http://elfsh.segfault.net/) propose un debugger, e2dbg, n utilisant pas ptrace(). En matière de reverse engineering, la très peu discrète fonction ptrace()trouve vite ses limites, c est pourquoi il est naturellement pensable que gdb soit mis de coté face aux plus récents debuggers. 4 Remerciements Merci à kryshaam d avoir relu mon article, à Z pour son coup de main, ainsi qu à toute la FRET et aux personnes qui animent le forum. References [1] French Reverse Engineering Team, http://reverseengineering.online.fr/forum/ [2] Beginners Guide To Basic Linux Anti Anti Debugging Techniques, http://home.pages. at/f001/linux_anti_anti_debugging4cbj.txt [3] The Linux Kernel Module Programming Guide, http://www.tldp.org/ldp/lkmpg/2.6/ html/lkmpg.html [4] Mammon Homepage, http://www.eccentrix.com/members/mammon/ [5] The ELFsh Project, http://elfsh.segfault.net/ [6] Linice Kernel Debugger, http://www.linice.com/ 10