| ESTUDIO COLECTIVO DE DESPROTECCIONES Última Actualizacion: 25/10/2001 |
Programa | America - no peace beyond the lines | W95 / W98 / WNT
Descripción | Juego de ESTRATEGIA
Tipo | Protección comercial anticopia de CD's
Tipo de Tutorial | [X]Original, []Adaptación, []Aplicación, []Traducción
Url | NO DISPONIBLE
Protección | VOB 3.32-3.42
Dificultad | 1) Principiante, 2) Amateur, 3) Aficionado, 4) Profesional, 5) Especialista
Herramientas | SoftIce v4.2.1, IceDump 6.023, PEditor 1.7, ProcDump 1.62, ADump, Hex WorkShop
Objetivo | Reconstruir un fichero protegido por VOB-ProtectCD
Cracker | Mr.Ocean [WkT!]
Grupo | http://www.whiskeykontekila.org
Fecha | 3 de Julio de 2001
INTRODUCCION
Lo primero deciros que aquí en España sólo me he encontrado un juego que lleve esta protección. Pero eso es lo de menos no? El juego en cuestión es "America - no peace beyond the lines", y primeramente no le hice demasiado caso ya que sólo te pide el CD la primera vez que lo ejecutas. Esta primera vez te crea un pequeño fichero con el cual ya no te pide el CD. No te lo pide en tu ordenador, ya que para mi sorpresa llevé el juego a casa de un amigo, puse ese fichero y me pidió el CD. En ese fichero se guarda pues, información del ordenador-usuario. Finalmente me puede hacer con una ISO de un juego alemán con esta protección(con una versión más nueva, la 3.42) y comprobar que el método funciona (sólo que este juego pedía siempre el CD) La protección no es fácil, requiere, entre otras cosas, un conocimiento total del formato PE y de las IAT's. Lleva también JUNKCODE y OBFUSCATION CODE (aunque yo os he pasado las rutinas importantes ya "limpitas"). Junk Code, como su propio nombre indica es "código basura". Por ejemplo "mov eax,eax", "push edi - mov edi,68234 - pop edi". Obfuscation Code son saltos en medio de funciones, consiguiendo así ocultar el código al desensamblado. Un ejemplo: 0177:007E7A69 JMP 007E7A6D ; Salta a la dirección 7E7A6D, que como podemos ver "no está visible" 0177:007E7A6B SBB BYTE PTR [EBP+7A41B58D],44 0177:007E7A72 ADD BL,CH 0177:007E7A6D LEA ESI,[EBP+00447A41] ; Y esta es la instrucción obfuscada(escondida) Es importantísimo pues, que distingáis entre el código "real" y el código "basura". Sino os tirais horas trazando inutilmente.
AL ATAQUE
PASO 1- OCULTAR EL DEBUGGER VOB utiliza dos métodos para detectar si está corriendo junto a un debugger. El primero es un simple 'MeltICE' que se basa en comprobar con CreateFileA si están cargados los drivers del Sice (\\.\SICE, \\.\SIWVID para Win9x y \\.\NTICE para WinNT). Si el SoftIce no está cargado el valor esperado es -1 (FFFFFFFFh). El nombre del fichero es el último parámetro en ser empujado a la pila, por lo tanto (una vez dentro de la API) lo encontraremos en *(esp+4) (en *esp estará la dirección de retorno). Gracias a los breakpoints condicionales y las macros del Sice vamos a poder cambiar lo que apunta a esp+4: BPX CreateFileA if *(esp->4+4)=='SICE' || *(esp->4+4)=='SIWV' do "e *(esp+4) 0;x" El segundo lo que hace es comprobar que no hallamos puesto ningún BPX en las APIS que llama el juego. Para ello comprueba que el primer byte de la API no sea 'CCh' (recordad que en realidad un brekpoint (BPX) es una INT 3 cuyo opcode es 'CCh'). ¿Cómo rompemos entonces en la API que queremos? En este caso, muy fácil: con un BPM. PASO 2 - ENCONTRAR EL OEP (Original Entry Point) El primer método con el cual lo hallé, fue muy "al tuntún": rompiendo en las APIs en que muchos programas llaman al iniciarse y trazando a la "retro". Pero bueno.....conseguí mi objetivo, hallar el OEP: 0047606F Y ahora viene lo interesante. Fue de esta forma que viene a continuación, con la cual hallé la forma de hallar el "verdadero" Entry Point de cualquier juego protegido con VOB 3. Poned un BPM en esa dirección (recordad poner siempre BPM y no BPX en zonas de memoria que vayan a ser descomprimidas/desencriptadas), cerrad el programa y lo volverlo a ejecutar. El SoftIce rompe en el OEP. Es un buen momento para volcar el fichero :) :a eip :0047606F JMP EIP Le damos al F5 para volver a Windows, abrimos el ProcDump...coño!!! Dónde está nuestro proceso??? Umm, vamos a investigar dónde puede estar la causa....me huele a que nuestro querido VOB debe crear un thread que compruebe si hemos parado en el OEP. Ejecutamos de nuevo nuestro juego, con lo cual volvemos a romper en el OEP. Borramos este breakpoint y lo cambiamos por uno de lectura y escritura (RW). F5 again y salta el Sice. VOB está rellenando de ceros toda la sección .code!!! Será maricón. Si trazamos esta rutina no llegamos a ninguna conclusión con la cual evitar esto....Vamos a poner un BPM en CreateThread. "F12" tras romper en CreateThread y trazando un poco veremos que EAX va cogiendo forma de nuestro OEP. (en ese thread vemos un sospechoso WaitForSingleObject....me lo imaginaba es un pequeño truco de sincronización. Nuestro juego debe activar algún "flag" que le diga a VOB que hemos pasado por el OEP. El truco no tiene mayor importancia, si trazamos 3 o 4 instrucciones podremos usar tranquilamente el truquillo del "jmp eip". Pero todavía es pronto para volcar, las APIS están rederigidas) PASO 3 - CORREGIR LAS LLAMADAS A LAS APIS Vamos a ver como corregirlas. Nos situamos en el OEP y vemos lo siguiente: 018F:0047606F 6AFF PUSH FF 018F:00476071 6840314800 PUSH 00483140 018F:00476076 68D0614700 PUSH 004761D0 018F:0047607B 64A100000000 MOV EAX,FS:[00000000] 018F:00476081 50 PUSH EAX 018F:00476082 64892500000000 MOV FS:[00000000],ESP 018F:00476089 83EC68 SUB ESP,68 018F:0047608C 53 PUSH EBX 018F:0047608D 56 PUSH ESI 018F:0047608E 57 PUSH EDI 018F:0047608F 8965E8 MOV [EBP-18],ESP 018F:00476092 33DB XOR EBX,EBX 018F:00476094 895DFC MOV [EBP-04],EBX 018F:00476097 6A02 PUSH 02 018F:00476099 E8CEE53A00 CALL 0082466C <-- PRIMERA LLAMADA A LA API 018F:0047609E 90 NOP <-- ¿¿?? 018F:0047609F 59 POP ECX ¿Qué pinta ese NOP hay? Muy fácil. Las APIS, lo habitual y más común, es llamarlas mediante un CALL DWORD PTR a la IAT, que son 2 bytes(FF15) + 4 de offset-dirección a la que llama. Pero aquí lo que hace VOB es una CALL "NORMAL" a una zona de memoria alojada por el mismo. Un CALL ocupa 1 byte(E8)+4 bytes que es la longitud del salto. De ahí el "NOP", de ese byte de menos. Y esa CALL va a parar a: PUSH F32B009F ; "valor mágico" usado para desencriptar la API correspondiente PUSH 007E9ECE ; mete en la pila el offset de la rutina que desencripta la API RET ; salta a esa dirección Y la rutina que la desencripta es: PUSHAD ; guarda todos los registros MOV EDX,003D9F4C MOV ESI,[EDX+00449847] ; ESI=IMAGE BASE MOV ECX,[ESI+3C] ; ECX=110h (ESI+ECX=comienzo de la cabecera PE) MOV EBX,[ECX+ESI+00000080] ; EBX=RVA de la IAT MOV EAX,[ESI+ECX+28] ; EAX=EntryPoint (no OEP) ADD EBX,[ECX+ESI+00000084] ; le añade a EBX el tamaño de la IAT SUB EAX,01FE6EFE LEA ESI,[ESP+20] MOV EDI,[ESI] ; obtiene el "valor mágico" SUB EBX,66EFCEFE SUB EDI,EBX ; marea EDI SUB EDI,EAX ; hasta conseguir ROR EDI,03 ; la dirección ADD EDI,550BFACF ; de retorno MOV [ESI],EDI ; mete en la pila la dirección de retorno POPAD ; restaura todos los registros RET ; Atentos a este RET porque también haré mención a él mas adelante Y el RET nos lleva a: 0177:007F946B E9EAA98077 JMP MSVCRT!__set_app_type Si le damos al F8 saltamos a: MSVCRT!__set_app_type 0177:78003E5A 8B442404 MOV EAX,[ESP+04] Y la pregunta es: ¿cómo pillamos a dónde salta la rutina? Muy fácil calculando la longitud del salto.....lo primero que vamos a hacer es cambiar ese RET por un salto a nuestra memoria ADUMP. Y en la memoria ADUMP ensamblamos esto: MOV EBX,[ESP] ; Pillamos la dirección a la que saltaría el RET (es decir el 007F946B de arriba) MOV EDX,[EBX+01] ; En EBX+1 tenemos la longitud del salto, la metemos en EDX ADD EBX,0 5 ; La longitud del salto es respecto a la siguiente instrucción al salto (SALTO LEJANO=5 bytes) ADD EBX,EDX ; Le añadimos a la instrucción siguiente al salto la longitud del mismo Bien, si hemos hecho todo correctamente, EBX debe valer 78003E5A. Ya tenemos lo que buscabamos. Ahora tenemos que buscar ese valor en la IAT(en la del fichero original) Arrrgggghhhh!!! Si buscamos ese valor no lo encontramos..... pueden pasar tres cosas: - Que la IAT esté dañada o encriptada - Que no esté inicializada - Simplemente que no exista Pues está dañada y no inicializada. Vamos a ver cómo deducir ésto. Ejecutamos de nuevo el juego y rompemos en el OEP. Usaremos el comando "/DUMP" del IceDump, ya que como veremos en el fichero volcado VOB daña la cabecera PE.......pero un momento, vamos a ver primero algo de información del exe:
SECCIÓN | Virtual Size | Virtual Offset | Raw Size | Raw Offset
.code | 3D7000 | 1000 | 3D7000 | 1000
.rsrc | AFC0 | 3D8000 | AFC0 | 3D8000
.idata | 1000 | 3E3000 | 200 | C000
.data | 41000 | 3E4000 | 40778 | C200
También miramos el EntryPoint y vemos que es 003E4000. Qué casualidad no? Justo el inicio de la última sección.....sacamos la conclusión de que en esa sección está alojado el código del packer. Por tanto ese código no nos hará falta en el "dumpeado". La sección .idata tampoco se va a salvar. En esta sección está la IAT pero la de VOB, no la del fichero original. Ahora sí: INICIO LONGITUD /DUMP 400000 3E3000 DUMPED.EXE "400000" es la IMAGEBASE y 3E3000 el final de la sección ".rsrc" Nos llama la atención dos cosas: - El icono del fichero no se ve - El fichero a pasado de 533kb a 3980kb El primero es un "problema" muy común en ficheros dumpeados. Es debido a que los VirtualOffsets y Raw Offsets no coinciden. Afortunadamente esto es fácil de arreglar. Abrimos el fichero dumpeado con PEditor, vamos a Section y le damos a "DumpFixer". Pero NO! Como os decía más arriba, VOB daña la cabecera PE en tiempo de ejecución, con lo cual en el volcado la cabecera está dañada. "No problem again", cogeremos la cabecera del fichero original. Abrimos el fichero original(america.exe) y el dumpeado(dumped.exe) con HexWorkShop y pegamos la cabecera del original en la del dumpeado. Ahora sí le damos a "DumpFixer". Bien, en la cabecera PE todavía están ".idata" y ".data". Las borramos con PEditor. Nos debe quedar una cosa así:
SECCIÓN | Virtual Size | Virtual Offset | Raw Size | Raw Offset
.code | 3D7000 | 1000 | 3D7000 | 1000
.rsrc | AFC0 | 3D8000 | AFC0 | 3D8000
Bueno y ahora a lo que ibamos, a por nuestra IAT. Usaremos la técnica de buscar la cadena "kernel32.dll". ÑASCAS! No la encuentra :( Pensemos. VOB debe por fuerza inicializar los imports y cargar las dll's que el juego va a usar. Y para ello usará LoadLibraryA/GetModuleHandleA. Vamos a poner un BPM en LoadLibraryA. Ejecutar el proceso. En *(esp+4) tendréis el nombre de la librería. Las seis primeras llamadas a esta función no tienen mayor importancia. Pero atentos a la 7ª. F12, trazad un poco hasta llegar a un POP EDI. Le damos a F8 y vemos como EDI pasa a valer 487836. Si miramos en esa dirección de memoria: 017F:00487836 00 00 00 00 00 00 00 00-00 00 00 00 00 00 5B 02 ..............[.. 017F:00487846 C8 FE EF CC F2 F5 FF F4-EC CB F4 E8 9B 00 5C 01 ..............\.. En principio nada significativo, pero si subimos unas páginas hacia arriba: 017F:00487418 FF FF FF FF 90 A3 47 00 00 00 00 00 98 A3 47 00 ......G.......G. 017F:00487428 48 75 08 00 00 00 00 00 00 00 00 00 36 78 08 00 Hu..........6x.. 017F:00487438 30 B0 07 00 44 76 08 00 00 00 00 00 00 00 00 00 ...Dv.......... 017F:00487448 AC 79 08 00 2C B1 07 00 38 75 08 00 00 00 00 00 .y..,...8u...... 017F:00487458 00 00 00 00 E8 79 08 00 20 B0 07 00 18 75 08 00 .....y.. ....u.. 017F:00487468 00 00 00 00 00 00 00 00 02 7A 08 00 00 B0 07 00 .........z...... 017F:00487478 2C 77 08 00 00 00 00 00 00 00 00 00 34 7A 08 00 ,w..........4z.. 017F:00487488 14 B2 07 00 20 75 08 00 00 00 00 00 00 00 00 00 .... u.......... 017F:00487498 52 7A 08 00 08 B0 07 00 28 75 08 00 00 00 00 00 Rz......(u...... 017F:004874A8 00 00 00 00 72 7A 08 00 10 B0 07 00 30 75 08 00 ....rz......0u.. 017F:004874B8 00 00 00 00 00 00 00 00 7E 7A 08 00 18 B0 07 00 ........~z...... 017F:004874C8 C4 76 08 00 00 00 00 00 00 00 00 00 F4 7C 08 00 .v...........|.. 017F:004874D8 AC B1 07 00 9C 76 08 00 00 00 00 00 00 00 00 00 .....v.......... 017F:004874E8 AC 7D 08 00 84 B1 07 00 90 75 08 00 00 00 00 00 .}.......u...... 017F:004874F8 00 00 00 00 E4 7E 08 00 78 B0 07 00 00 00 00 00 .....~..x....... 017F:00487508 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ Bien, este "churro de colores" es nuestra IAT con sus IMAGE_IMPORT_DESCRIPTOR's(Original First Thunk, TimeDateStamp y ForwardChain (habitualmente 0's), Name, First Thunk) y finalmente el DESCRIPTOR FINAL NULO. Los más avispados sacaréis de aquí mismo el tamaño de la IAT. Con el SoftIce: ? 487518-487428=F0. (trabajamos siempre en hexadecimal) Bueno, vamos a ver esa dirección de memoria en nuestro fichero dumpeado. Abrimos HexWorkShop y vamos al offset 87428h (= 487428-ImageBase, recordad que esto es así porque hemos equiparado los Virtual Offsets con los Raw Offsets). En ese offset: 00087428 48 75 08 00 00 00 00 00 00 00 00 00 36 78 08 00 30 B0 07 00 Vamos al offset 00087836 (que es el "NAME" del primer IMAGE_IMPORT_DESCRIPTOR) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5B 02 53 65 . . . . . . . . . . . . . .[.Se 74 57 69 6E 64 6F 77 50 6F 73 00 00 5C 01 47 65 74 57 tWindowPos..\.GetW Coño! El muy cabrón nos ha borrado el nombre de las dll's!!! Bueno, no pasa nada ;) recordáis los LoadLibraryA--POP EDI? Pues se corresponden. Me explico. Tras el POP EDI en EDI tendréis la dirección donde va el nombre de la librería. Pos ya está. Cada LoadLibraryA nos apuntamos el nombre de la librería en un papel (jeje OldSchool), trazamos hasta el POP EDI y nos apuntamos al lado la dirección que nos da EDI. Nos vamos al fichero dumpeado y las corregimos. Otra posibilidad es pillarla todavía intacta. Para ello ponemos un BPM de escritura en la IAT y cuando salte el Sice nos fijamos donde acaba la rutina y ponemos un breakpoint ahí. Volcamos la IAT y la pegamos en el fichero que habíamos volcado antes. Pues ya tenemos nuestra IAT corregida, ya sólo nos queda inicializarla. Cómo la inicializamos? Muy fácil, dejaremos que sea el propio Windows quien nos haga la "faenita". Cada vez que ejecutamos un proceso el windoze(CreateProcessA) inicializa la IAT. Pos ya está. Cargamos el fichero con el Loader del Sice (que es como si lo cargasemos suspendido). Si nos fijamos en los "First Thunk" de la tabla de arriba vemos que los pointers a las importaciones empiezan en 7B000 (47B000 en memoria) 017F:00487468 00 00 00 00 00 00 00 00 02 7A 08 00 00 B0 07 00 .........z...... Bien ahora lo que tenemos que hacer es copiarlos a nuestra memoria ADump. Para ello usaremos el comando "M" del Sice. Cogemos una longitud considerable, mejor de más que de menos. Con 1000h tendremos de sobra. Y como destino final la memoria ADump+200h (en esos primeros 200h bytes meteremos la rutina de corrección de API's). : m 47B000 L 1000 ADumpAddress+200 Ahora ya podemos saber donde está el pointer correcta a la API correspondiente. Arrancamos el fichero original y una vez ya sabemos la dirección de la API (calculando el salto recordad), codificamos una rutinilla tal como: mov eax,0047b000 ; dirección donde empiezan los thunks en nuestro fichero volcado xor edx,edx mov edi,ADumpAddress+200 loop_busca: cmp dword ptr[edi+edx],ebx ; buscamos la API en nuestros thunks jz encontrado inc edx ; incrementa el contador cmp edx,00001000 jnz loop_busca int 3 ; int3/bpint3 si algo falla pararemos aquí encontrado: add eax,edx ; 47b000+CONTADOR (EDX) mov word ptr [ecx],15ff ; ECX=dirección de la llamada a la API a corregir (FF15=call dword ptr) mov dword ptr[ecx+02],eax ; EAX=dirección correcta a nuestro thunk Si trazamos unas cuantas llamadas a las APIS vemos que el "byte de menos" puede ser tanto un NOP como un CLD y que puede estar antes o después de la CALL: 0177:00476099 E8CEE53A00 CALL 0082466C ; CALL a VOB 0177:0047609E 90 NOP <--- 0177:004760BC E874E53A00 CALL 00824635 ; CALL a VOB 0177:004760C1 FC CLD <--- 0177:004760E8 FC CLD <--- 0177:004760E9 E85DE53A00 CALL 0082464B ; CALL a VOB 0177:00476194 90 NOP <--- 0177:00476195 E82EE03A00 CALL 008241C8 ; CALL a VOB mov eax,00401000 ; inicio de la sección de código mov ecx,0047b000 ; VOB mete a excepción de .rsrc todas las secciones, por tanto ; no podemos saber con exactitud donde acaba esta sección. Pero ; como sabemos que los thunks empiezan en 47b000 como mucho ; llegará hasta ahí ;) loop_busca: cmp byte ptr [eax],e8 ; E8=OPCODE DE CALL jz encontrado incrementa: inc eax cmp ecx,eax ; Hemos llegado al final de la sección de código? jnz loop_busca ; No? Pos sigue buscando... :b int 3 ; BPINT3 y cuando no halla más llamadas romperemos aquí encontrado: ---- AHORA MIRAMOS SI EL "BYTE DE MENOS" ESTÁ ANTES O DESPUÉS ---- cmp byte ptr [ecx+5],90 ; 90 = OPCODE de NOP jz ya_bien cmp byte ptr [ecx+5],fc ; FC = OPCODE de CLD jz ya_bien dec ecx ; El "byte de menos" está antes del "CALL", decrementamos ECX en 1 ya_bien: ----- AQUÍ CALCULARIAMOS LA LONGITUD DEL SALTO, EVITANDO "TOCAR" ECX QUE ES ----- ----- DONDE TENEMOS LA DIRECCION DE LA LLAMADA A VOB ----- (Momento de recordar este fragmento de código a la que saltan todas "las calls de VOB": 0177:0082466C 689F002BF3 PUSH F32B009F 0177:00824671 68 CE9E7E00 PUSH 007E9ECE 0177:00824676 C3 RET ) ---- SUPONIENDO QUE EAX ES LA DIRECCION A LA QUE NOS LLEVA EL SALTO: ---- cmp byte ptr[eax+6],68 ; Chequeamos si está el PUSH 007E9ECE jnz incrementa ; si no incrementa y sigue buscando cmp dword ptr [eax+7],CE9E7E00 jnz incrementa --- AQUÍ YA SABEMOS QUE EL CALL PERTENECE A VOB --- jmp ecx ; Saltamos a esa dirección para que la rutina VOB nos devuelva ; la API correcta Como VOB deja "intactos" los registros, se nos queda en ECX la dirección para corregir a "FF15" ;) Más de uno seguro que esto ya está llegando a su fin, pero estáis equivocados, VOB no tiene reservada alguna sorpresita. Si trazamos unas cuantas llamadas más a las API's vemos que el RET nos lleva a: 0177:007F945D EB01 JMP 007F9460 0177:007F9460 55 PUSH EBP <-------- 0177:007F9461 EB01 JMP 007F9464 · Ojito a esto 0177:007F9464 8BEC MOV EBP,ESP <--- 0177:007F9466 E908AA8077 JMP 78003E73 ; MSVCRT!__getmainargs 0177:78003E70 55 PUSH EBP 0177:78003E71 8BEC MOV EBP,ESP 0177:78003E73 8B4518 MOV EAX,[EBP+18] ; <--- Salta directamente aquí Ostras.......ejecuta parte del código de la API en su propio código. De nuevo nuestro ingenio puede más que el de los programadores de VOB ;) xor edx,edx cmp byte ptr [ebx],e9 jz salta_directamente ; si es salto directo a la API (E9) nos vamos --- CALCULARIAMOS A QUE API NOS LLEVA EL SALTO EN EBX --- mov al,byte ptr[ebx] ; pillamos del código de VOB el primer byte de la API incrementa: ; (que en este caso sería el "55" de arriba) inc ebx cmp byte [ebx],al ; comprobamos que no se repita ese valor jnz es_salto_a_API? inc edx ; si encontramos otra coincidencia aumentamos nuestro contador es_salto_a_API?: cmp byte ptr [ebx],e9 ; hemos encontrado ya el salto a la API??? jnz incrementa --- AQUI CALCULARIAMOS A QUE API NOS LLEVA EL SALTO Y... --- reduce: dec ebx ; buscamos cmp byte ptr[ebx],al ; en la API el primer byte jnz reduce cmp edx,0 ; se repetía ese valor??? jz salta_directamente dec edx ; reduce el contador y busca de nuevo ese valor jmp reduce salta_directamente: Casi, casi pero no......aún nos queda una cosilla.....VOB también redirige los SALTOS A LAS APIS. Aquí tenéis un ejemplillo: 0177:004761FE FC CLD 0177:004761FF E9D9E33A00 JMP 008245DD De nuevo el "CLD" ese por el byte de menos, en este caso por un "JMP DWORD PTR" cuyos opcodes son FF25. La rutina para corregir los saltos a las APIS será igual que la las CALL, salvo que: - Logicamente en vez de corregir el NOP/CLD-E8 por FF15 lo sustituiremos por FF25 - En vez de buscar los E8 para buscar las llamadas(CALLS) a VOB, buscaremos E9 que es el OPCODE de salto lejano Bueno pues una vez hallamos corregido todas las llamadas y saltos a las APIS, volcamos la sección code y la pegamos en el fichero en el que habíamos reconstruido la IAT. Nos aseguramos de haber corregido el OEP, el RVA de la IAT y su tamaño, ejecutamos el fichero y........EYYY FUNCIONA! :) Pero nuestro fichero reconstruido todavía tiene "un pero". El fichero ocupa casi 4 megas, mucho si tenemos en cuenta que el fichero original ocupaba 533 Kb. A qué es debido? Pues a que hemos volcado con el tamaño del fichero en memoria(SizeOfImage), que nada tiene que ver con el tamaño del fichero en disco. Abrimos nuestro fichero con HexWorkShop. Ponemos un poco de vista y vemos que desde el offset 8B452h hasta el 3D8000h(que es el principio de la sección .rsrc) son todo 0's. Ahí están esos 3,460,014 bytes "de más" ;) Seleccionamos los primeros 8C000h bytes de nuestro fichero recontruido y los insertamos en un fichero nuevo. Después nos vamos al offset 3D8000h, seleccionamos hasta el final y lo pegamos a continuación en el fichero nuevo que habiamos creado. Salvamos el fichero y salimos. Umm ahora no se nos ve el iconito del fichero...esto es debido a que el Raw Offset de la sección .rsrc es incorrecto y debemos corregirlo con PEditor. También actualizamos el Raw Size de la sección .CODE que será "Raw Offset de .rsrc - Raw Offset de .CODE" (8C000h-1000h=8B000h). Nos debe quedar así:
SECCIÓN | Virtual Size | Virtual Offset | Raw Size | Raw Offset
.code | 3D7000 | 1000 | 8B000 | 1000
.rsrc | AFC0 | 3D8000 | AFC0 | 8C000
Ahora sí........VOB is DEAD! :) Mr.Ocean [WkT!]
[ Entrada | Documentos Genéricos | WkT! Web Site ]
[ Todo el ECD | x Tipo de Protección | x Fecha de Publicación | x Orden Alfabético ]
(c) Whiskey Kon Tekila [WkT!] - The Original Spanish Reversers. Si necesitas contactar con nosotros , lee esto antes e infórmate de cómo puedes ayudarnos