Problema al atrapar excepcion en ensamblador cambiando [fs:0] manualmente (FASM)

Iniciado por harry_the_blogger, 14 Septiembre 2014, 03:51 AM

0 Miembros y 1 Visitante están viendo este tema.

harry_the_blogger

Hola, estoy desarrollando un programa. El programa busca las APIs sin usar la import table, él programa usa GetProcAddress y LoadLibrary para encontrar todas las APIs que necesita. Pero hay un problema: NO LLAMA A MI EXCEPTION HANDLER CUANDO HAY UNA EXCEPCION!!

El codigo, debería mostrar un mensaje "Exception catched!!" cuando haya una excepcion. Pero el programa sale sin más, aunque curiosamente, no crashea. Aún así la idea es que llame a mi manejador de excepciones, cosa que no hace

Aquí está mi codigo. Está escrito en FASM

Código (asm) [Seleccionar]



format pe console 4.0

section '.text' readable writable executable

start:
   call delta_offset       ;Calculates the delta offset

delta_offset:
   pop ebp                 ;Save the current address of the delta_offset routine in memory
   sub ebp, delta_offset   ;Current address of delta_offset ´- address of delta_offset at compilation time
                           ;is equal to current address of virus body in memory. Now we can access any part of
                           ;data embebbed in the code using [ebp+variable]

finding_kernel32:
mov ebx, [FS : 0x30]        ;FS:0x30 is a pointer to the address of Process Environment Block (PEB)
                               ;Now the Base Pointer (BX) points to the address of PEB in memory

mov ebx, [ebx + 0x0C]       ;Now we move 0x0C (12 bytes) from the address of PEB
                               ;We get the value of ebx+0x0c, in other words, the address that has the PEB->Ldr pointer

                               ;Now we are in Ldr structure. We move the ebx pointer following the address in the
                               ;PEB->Ldr pointer.

mov ebx, [ebx + 0x14]       ; get PEB->Ldr.InMemoryOrderModuleList.Flink (1st entry)
mov ebx, [ebx]            ;2nd Entry
mov ebx, [ebx]            ;3rd Entry
mov ebx, [ebx + 0x10]   ; Get Kernel32 Base
mov [ebp+dwKernelBase] , ebx
add ebx, [ebx+0x3C] ; Start of PE header
mov ebx, [ebx+0x78] ; RVA of export dir
add ebx, [ebp+dwKernelBase]  ; VA of export dir
mov [ebp+dwExportDirectory] , ebx

finding_address_of_getprocaddress:
lea edx,[ebp+api_GetProcAddress]    ;Load in ebp the address of the API function name.
mov ecx,[ebp+len_GetProcAddress]    ;Load in ecx the size of the API function name

call GetFunctionAddress           ;Call GetFunctionAddress

mov [ebp+AGetProcAddressA] , eax    ;The API function address in memory was stored by the
                                       ;GetFunctionAddress function in eax, now we save the address
                                       ;of the GetProcAddress in a variable for later use.

finding_address_of_loadlibrary:
lea edx,[ebp+api_LoadLibrary]       ;Load in edx the API function name of LoadLibrary
push edx                            ;edx could be a parameter for an API
push dword [ebp+dwKernelBase]       ;save in the stack the address of the kernel32 library
                                       ;dwKernelBase is used as handle
call eax                            ;Calls a function by its address (eax stores it)
                                       ;Could be GetProcAddress because in the instruction in
                                       ;the line 39 it moves the address of that API from eax
                                       ;and eax has no changes until 47 line.
loading_required_libraries:
mov [ebp+ALoadLibraryA] , eax       ;The last function could return the address of LoadLibrary in
                                       ;in eax. eax register could be used by the last function as a
                                       ;return value.

                                       ;Now the eax register contains the address of LoadLibrary
lea edx , [ebp+szUser32]            ;Loads in edx, the library name of User32.dll
push edx                            ;Put the edx value in the stack as a parameter for LoadLibrary
                                       ;I believe that the function could be LoadLibrary because
                                       ;it is an API that requires a string that contains the name of
                                       ;the library that you want to load.
call eax                            ;Call LoadLibrary API

   mov [ebp+hUser32], eax

finding_addresses_of_apis:

lea edx , [ebp+api_MessageBoxA]     ;Loads in edx the address of the name of MessageBoxA API
push edx                            ;Put the name of MessageBoxA as a parameter for a function
push eax                            ;I belive that eax is a handle to the loaded library
mov ebx,[ebp+AGetProcAddressA]      ;Moves to ebx the address of GetProcAddressA
call ebx                            ;Invokes GetProcAddressA using its address

mov [ebp+AMessageBoxAA] , eax       ;The last function (could be GetProcAddressA) returns the address of
                                       ;MessageBoxA in eax. We move the address of that API to a variable for
                                       ;later use.

                                       ;We start to search for functions inside
                                       ;kernel32.dll
set_exception_handler:
   ;A simple way to set a exception handler, avoiding the
   ;use of APIs that increase the size of the release.
   push exception_handler
   push dword [FS:0]
   mov  [FS:0], esp

main:
   push 0                              ;Put the HWND parameter
lea edx,[ebp+szTitle]               ;Put the caption of the MessageBox
push edx
lea edx,[ebp+szMsg]                 ;Put the message body of the MessageBox
push edx
push 0                              ;Buttons type (For example MB_OK)
call dword [ebp+AMessageBoxAA]          ;Calls MessageBoxA API

;The following code tries to make many exceptions
int3    ;Software breakpoints
int3
int3
mov esi, 0  ;Access violation
mov dword [esi], "fail"

exit:

ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  <<<<< GetFunctionAddress >>>>>> ;
; Extracts Function Address From Export Directory and returns it in eax   ;
; Parameters :  Function name in edx , Length in ecx  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

GetFunctionAddress:
push ebx    ;Save status of registers before execute the subroutine
push esi    ;to preserve its content. It could make some errors to the
push edi    ;caller function if modify the values that are common to the whole
               ;program

mov esi, [ebp+dwExportDirectory]
mov esi, [esi+0x20] ;RVA of ENT
add esi, [ebp+dwKernelBase]  ;VA of ENT
xor ebx,ebx
cld

looper:
 inc ebx
 lodsd     ;Load a byte from the string pointed by SI into al register
 add eax , [ebp+dwKernelBase]   ;eax now points to the string of a function
 push esi ;preserve it for the outer loop
 mov esi,eax
 mov edi,edx
 cld       ;The direction flag is clear, this means that the SI and DI pointers are
                   ;incremented. (The instructions works to the forward direction)

 push ecx  ;Save ecx. Why?? The next instruction named "repe" decrements the counter.
                   ;Because the ecx contains the length of the API name, we need to save it.
                   ;In other parts of subroutine the program uses ecx register to compare the function
                   ;with the kernel export table.

 repe cmpsb ;Compare each byte of the array pointed by DS:SI with the array pointed by ES:DI
                    ;Repeat until the counter is not equal to zero, in other words,
                    ;it only stops when it find a difference or the counter reachs the end of the string

 pop ecx   ;Pop the length of the string, and put it in the counter for another loop if it's needed
 pop esi   ;Pop the last stack variable, and put it in esi.
 jne looper

 dec ebx
 mov eax,[ebp+dwExportDirectory]
 mov eax,[eax+0x24]   ;RVA of EOT
 add eax,[ebp+dwKernelBase] ;VA of EOT
 movzx eax , word [ebx*2+eax] ;eax now holds the ordinal of our function
 mov ebx,[ebp+dwExportDirectory]
 mov ebx,[ebx+0x1C]   ;RVA of EAT
 add ebx,[ebp+dwKernelBase] ;VA of EAT
 mov ebx,[eax*4+ebx]
 add ebx,[ebp+dwKernelBase]
 mov eax,ebx

pop edi     ;Restore the registers to avoid generate a problem
pop esi     ;in the caller function.
pop ebx
ret

exception_handler:
   push 0                              ;Put the HWND parameter
lea edx,[ebp+szTitle]               ;Put the caption of the MessageBox
push edx
lea edx,[ebp+szMsgException]                 ;Put the message body of the MessageBox
push edx
push 0                              ;Buttons type (For example MB_OK)
call dword [ebp+AMessageBoxAA]          ;Calls MessageBoxA API

ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Data Shit ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
szMsgException db 'Exception catched!!', 0
api_ExitProcess dd 0

szTitle:  db  "From the heaven",0
szMsg: db "Greetings from hell",0
szUser32 db  "User32.dll",0
hUser32             dd 0
AGetProcAddressA:   dd  0
api_GetProcAddress:   db  "GetProcAddress"
len_GetProcAddress:   dd  $-api_GetProcAddress
ALoadLibraryA: dd  0
api_LoadLibrary:   db  "LoadLibraryA",0
AMessageBoxAA: dd  0
api_MessageBoxA:   db  "MessageBoxA",0
dwKernelBase: dd  0
dwExportDirectory:   dd  0


Intenté hacer el siguiente método:

Código (asm) [Seleccionar]

push exception_handler
   push dword [FS:0]
   mov  [FS:0], esp


El metodo que describí funciona en este pequeño ejemplo (no es la aplicacion que estoy escribiendo):

Código (asm) [Seleccionar]

format pe console 4.0 ;on 'dos_stub.exe'
include 'C:\fasm\INCLUDE\WIN32AX.inc'

.data
   msg_caption db 'SEH handler', 0
   msg_exception db 'I catched an exception!! Amazing!!', 0

.code

main:
   ;A simple way to set a exception handler, avoiding the
   ;use of APIs that increase the size of the release.
   push exception_handler
   push dword [FS:0]
   mov  [FS:0], esp

   mov esi, 0
   mov dword [esi], "Pwnd"

exit:
   invoke ExitProcess, 0

exception_handler:
   invoke MessageBox, NULL, addr msg_exception, addr msg_caption, MB_OK
   jmp exit
   ret

.end main



Por que en el primer codigo no trabaja, mientras que en el segundo si lo hace??? Alguien puede decirme porqué??? Gracias de antemano, y perdon por hacerlos leer tanto. (XD).

Ah, se me olvidaba, también intenté usar SetUnhandledExceptionFilter (API) para establecer mi funcion como manejador de excepciones, pero no funciono. ¿Será qué el uso que le doy a ciertos registros afecta lo que trato de hacer??
Vista mi blog es enriquemesa.blogspot.com

Eternal Idol

Tenes que aprender a depurar tu codigo, es un trabajo arduo y mucho mas para quien no lo escribio.

Estas confundido, si que es llamado tu exception handler, si pones un breakpoint en el mismo lo veras. EBP no tiene el valor que vos esperas ... y no hay ninguna garantia de que lo fuera a tener.
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

harry_the_blogger

#2
Gracias Eternal Idol.
Vista mi blog es enriquemesa.blogspot.com

daryo

Citar??? Será que si guardo el valor de ebp en una variable, antes de que ocurra la excepcion, podré usarlo para llamar las APIs???

mm veo un fallo en eso porque [ebp + direccion de la variable] te da la direccion pero si tienes una variable en ves de ebp como sabes donde  estara esa variable donde guarda esa direccion?
buenas

harry_the_blogger

#4
Hola daryo. Tienes razón. Será que me puedes decir alguna forma de preservar ebp sin usar variables??? O será que hay forma de acceder al último valor que tenían los registros antes de morir??

Estaría muy agradecido si me dijeras como puedo preservar ebp. También investigaré  más sobre SEH con google. Gracias por tu ayuda, daryo

[Nuevo]
Tengo otra idea, ¿Será que es posible usar el truco del delta offset para referenciar las variables de nuevo? Lo intentaré. Les comentaré los resultados.
Vista mi blog es enriquemesa.blogspot.com

Danyfirex

si quieres preservar alguna variable puedes usar el stack.

push ebp ;guardas.
pop ebp ;lo agarras.

Saludos

harry_the_blogger

Cita de: Danyfirex en 15 Septiembre 2014, 21:31 PM
si quieres preservar alguna variable puedes usar el stack.

push ebp ;guardas.
pop ebp ;lo agarras.

Saludos

Gracias Danyfirex. Disculpa, tengo una duda: ¿Puede corromperse la pila? Es decir, ¿que yo no sea capaz de recuperar los valores que tenía? Yo, hasta ahora, he creído que puede corromperse. Por eso intenté solucionarlo calculando el delta offset. Pero si me aclaras bien mi duda, usaré mejor tu codigo.

Vista mi blog es enriquemesa.blogspot.com