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
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:
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):
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??
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.
Gracias Eternal Idol.
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?
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.
si quieres preservar alguna variable puedes usar el stack.
push ebp ;guardas.
pop ebp ;lo agarras.
Saludos
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.