Random IRC quote :      <erg0t> yo me acuerdo cuando matabamos perros con unas tijeras <erg0t> que recuerdos, k lindo era ser crio

OllyTheBugger

Cuenta la leyenda que en algunas ocasiones en las frias mañanas de invierno ( y una mierda, a ver si nieva ya de una vez! ) es posible encuentrarse con un bug de esos que no sabes ni por donde agarrarlo, el caso que os presentamos es real y nos tuvo OllyTheBuggerentretenidos a Victor y a mi un buen rato …

Una de las aplicaciones que usamos en un entorno de producción estaba devolviendo unos valores de retorno inesperados, la aplicacion era muy sencilla y hacía uso de otras librerías también programadas por nosotros, con lo cual nos pusimos a depurar para ver dónde podía encontrarse el problema exactamente y ver cuantos programas podían estar afectados por el fallo.

El primer paso fue agregar una int 3 al propio programa, ya que al ser lanzado este desde otro, haciendo uso del JIT podíamos seguir depurando el programa de manera más cómoda y de la forma más parecida a la real en la que este se cargaba en el entorno de producción.
 
El desensamblado del programa es el que sigue a continuación:

 

 
.text:00401000     ; int __cdecl main(int argc,const char **argv,const char *envp)
.text:00401000     _main           proc near               ; CODE XREF: start+16Ep
.text:00401000
.text:00401000     var_11C         = dword ptr -11Ch
.text:00401000     var_10C         = dword ptr -10Ch
.text:00401000     Buffer          = byte ptr -108h
.text:00401000     var_4           = dword ptr -4
.text:00401000     argc            = dword ptr  4
.text:00401000     argv            = dword ptr  8
.text:00401000     envp            = dword ptr  0Ch
.text:00401000
.text:00401000 000                 sub     esp, 10Ch
.text:00401006 10C                 mov     eax, dword_407030
.text:0040100B 10C                 mov     [esp+10Ch+var_4], eax
.text:00401012 10C                 mov     eax, [esp+10Ch+argc]
.text:00401019 10C                 push    ebp
.text:0040101A 110                 xor     ebp, ebp
.text:0040101C 110                 cmp     eax, 2
.text:0040101F 110                 mov     [esp+110h+var_10C], ebp
.text:00401023 110                 jnz     loc_40112F
.text:00401029 110                 push    ebx
.text:0040102A 114                 push    esi
.text:0040102B 118                 push    edi
.text:0040102C 11C                 int     3               ; <- Nuestra Int 3 🙂 .text:0040102D 11C                 call    CualInitGAS     .text:00401032 11C                 mov     ebx, eax .text:00401034 11C                 lea     eax, [esp+11Ch+Buffer] .text:00401038 11C                 push    eax             ; lpBuffer .text:00401039 120                 push    104h            ; nBufferLength .text:0040103E 124                 call    ds:GetCurrentDirectoryA .text:00401044 11C                 lea     edi, [esp+11Ch+Buffer] .text:00401048 11C                 dec     edi .text:00401049 11C                 lea     esp, [esp+0] .text:00401050 .text:00401050     loc_401050:                             ; CODE XREF: _main+56j .text:00401050 11C                 mov     al, [edi+1] .text:00401053 11C                 inc     edi .text:00401054 11C                 test    al, al .text:00401056 11C                 jnz     short loc_401050 .text:00401058 11C                 mov     ecx, ds:dword_405144 .text:0040105E 11C                 mov     dx, ds:word_405148 .text:00401065 11C                 lea     eax, [esp+11Ch+Buffer] .text:00401069 11C                 mov     [edi], ecx .text:0040106B 11C                 push    ebx .text:0040106C 120                 push    eax .text:0040106D 124                 mov     [edi+4], dx .text:00401071 124                 call    CualSetTempPath .text:00401076 124                 push    ebp .text:00401077 128                 push    offset a_PluginsS; ".\\PLUGINS\\S.QAL" .text:0040107C 12C                 push    ebx .text:0040107D 130                 call    LoadPlugin .text:00401082 130                 push    ebp .text:00401083 134                 push    offset a_PluginsA ; ".\\PLUGINS\\A.QAL" .text:00401088 138                 push    ebx .text:00401089 13C                 call    LoadPlugin .text:0040108E 13C <-!!!           mov     ecx, [esp+13Ch+argv]          ; <- Accediendo a argv .text:00401095 13C                 mov     edx, [ecx+4]                  ; <- argv[1] !!! .text:00401098 13C                 push    edx .text:00401099 140                 push    ebx .text:0040109A 144                 call    CualOpenFile                  .text:0040109F 144                 mov     esi, eax .text:004010A1 144                 add     esp, 28h     Con el Ollydbg empezamos a depurar el programa hasta que llegamos al momento en el que se accedia a argv[1] viendo que se producía una excepcion, ECX contenía en ese momento el valor 0x2, con lo cual el cálculo de la posición del array de punteros a los parametros se estaba realizando mal, vimos que el dato que en realidad se había obtenido era argc!, ¿como podía ser?, en la pila argc y el puntero a argv están contiguos, lo cual quería decir que la pila se había movido 4 bytes y se había quedado desajustada. Lo primero que pensamos es que alguna de las funciones que usabamos no se estaba llamando con la convención correcta, en el código están mezcladas funciones stdcall (todas las del API de Win32) y cdecl (las de nuestra librería), quizá en algun momento estabamos llamando a alguna de la manera que no se debía y como resultado la pila se quedaba en ese estado. Una vez comprobamos que no era el caso, pasamos a abrir el programa con el IDA, que haríamos sin el! :-), si observamos el código,vemos que tras las llamadas a CualSetTempPath y las siguientes a LoadPlugin se acaba arreglando la pila de golpe ( en el add esp,28h ), esto es debido a que el binario estaba compilado con optimización ( /O2 concretamente ), antes de que la pila esté como debería estar es donde ese calcula el puntero, esto nos hizo pensar que quizá podría ser un bug del compilador que estuviera prediciendo mal el desplazamiento que tenía que aplicar sobre ESP, en el código observamos que accede a 13Ch + argv lo cual viene a ser 144h, nos pusimos a echar cuentas del estado de la pila en ese momento, despues de un par de minutos discutiendo por que pushes no habíamos contado nos acordamos de que el IDA tiene una opcion para mostrartelo auto-mágicamente! ( podeís activarla en General -> Options -> Stack Pointer ) y se muestra la columna esa que veís a la izquierda del código. Cual fue nuestra sorpresa cuando vimos que no, que la posicion a la que accedía era la correcta…

¿Qué narices podía estar pasando?, between whistles and flutes nos pusimos a depurar también en otro ordenador y aquí fue cuando casi nos da un patatús,,, el programa en el otro ordenador llegaba a ese punto sin problemas!!!, el binario era el mismo exactamente y la instalación parecida si no idéntica, el fallo tenía que estar en algo del sistema operativo o en el debugger!, después de mirar un poco más, llegamos a la raiz del asunto … parecía que el Ollydbg a la hora de obtener el contexto del proceso con la opción de Just In Time debugging, no se detenía en la interrupción, sino que lo hacía una instrucción antes, gracias a esto la instrucción previa «push edi» se ejecutaba dos veces, dejando la pila movida los 4 bytes que comentabamos antes y dejandonos a nosotros con el fallo real por localizar :-(.

La versión afectada por este fallo es la 1.09d, por cierto, ¿alguien sabe si se espera la v2 y para cuando? 😉

5 Comentarios para “OllyTheBugger”

  1. Comment por vmalvarez | 01/17/07 at 9:22 pm

    El título está genial: OllyTheBugger, xD

  2. Comment por Jorge | 01/21/07 at 6:09 pm

    Pero la version 1.09d del Ollydbg es muy antigua, la ultima version que hay publicada es la version 1.10 final y con esa version el fallo no funciona.

    Como es que habeis trabajo con esa version?

    De todas formas aunque sea un fallo en una version antigua muy buen trabajo para ti Mario y al tal Victor.

    Sobre lo que decias de la version 2.0 del Ollydbg en su momento se hablo de que traeria soporte para ring0 pero debido al trabajo ( mas o menos reescribir todo el debugger 🙂 ) que seria eso pero al final parece que fue solo un rumor.

    Lo unico nuevo que se sabe del Ollydbg tambien por el momento es esto:
    http://www.ollydbg.de/version2.html

    Como veis las fechas no se cumplieron 🙂 yo todavia estoy esperando a las nuevas capturas jeje

  3. Comment por Señor X | 02/02/07 at 4:43 am

    Eso es lo unico q podes opinar??? jajaaja!!! q ignorante del OllyDbg!!
    jajaja
    jajajajaja
    jajawqeja!!!

  4. Comment por svch0st | 02/06/07 at 12:58 pm

    Anda que no hay otros «TheBuggers» por ahí sueltos…maaadreee…

  5. Comment por mballano | 02/08/07 at 1:33 pm

    Yo trabajo con la 1.10, pero se ve que Victor no actualiza sus programas!! :-\

Se han cerrado los comentarios