| RFOG's profileEl Loco de la ColinaBlogListsNetwork | Help |
|
|
February 08 El Guille busca ficheros por ti¿Te peleas con la nueva forma de buscar que trae el Vista? ¿Lo consideras barroco, retorcido y sin mucho sentido? ¿Funciona lento, no encuentra lo que buscas o simplemente no te gusta? ¿Se te corrompe el índice y entonces sí que no encuentras nada de nada? Pues bien, la solución a todos esos males está aquí: se llama gsBuscarTexto, la ha parido el incomparable Guille, y la puedes conseguir gratis de trinca aquí. El programa da la opción de anclarse en el menú contextual del explorador para poder realizar las búsquedas sobre una carpeta o un grupo de carpetas, y usado desde la línea de comandos tiene como una espuerta de opciones, y también permite arrastrar y soltar carpetas sobre el campo de la búsqueda… Sólo le falta hablar y decir “papá”. No voy a explicar nada más sobre él excepto poner una captura, ya que cuando te lo vayas a bajar verás las instrucciones completas sobre cómo funciona… Y si te apasiona esto de programar, también tienes acceso al código fuente del mismo… El que esto escribe lo ha probado en XP en una máquina virtual y en Vista de 64 bits en su ordenador principal… y te asegura que esa utilidad siempre estará en su Caja de Herramientas. December 25 Hemos leído: Reversing. Secrets of Reverse Engineering (Eldad Eilam, Wiley)Sí, ya sé, muchos libros técnicos estoy leyendo últimamente, pero es que voy por rachas, y ciertamente este lo he disfrutado casi como una novela. El título es correcto: Ingeniería inversa con pelos y señales. Toda una gozada pese a lo denso del contenido, aunque el que esto suscribe en su juventud tuvo cierta etapa sobre la que es mejor correr un Tras una larga introducción de más de 130 páginas, justificativa de la ingeniería inversa, y en la que se explica muy por encima todo lo que se debe saber antes de sentarse a realizar una sesión de este tipo, incluyendo qué herramientas usar y cómo funcionan, el autor entra de lleno en materia. El capítulo 5, primero de la segunda parte, incluye una lección magistral (de magnífica, no de magisterio) en la que se realiza ingeniería inversa sobre un subconjunto del API incluido en NTDLL.DLL, perteneciente a las tripas de Windows. En concreto indaga en las funciones del grupo RtlGenericTable, y nos va demostrando paso a paso cómo, en un alarde de inteligencia y buen hacer, qué hacen dichas funciones y cómo. Llega hasta a reconstruir la estructura de datos no trivial que usan dichas funciones: una variante optimizada de los árboles-B que coloca los nodos más visitados encima del todo. Lo dicho: todo un alarde de inteligencia, deducción y aplicación de la ingeniería inversa. El lector realmente ve lo que el autor está haciendo y no le quedan dudas sobre el funcionamiento de dichas funciones. El siguiente capítulo tampoco se queda chiquito. Se nos demuestra paso a paso cómo obtener la estructura de un fichero… que guarda ficheros encriptados con encriptación fuerte. Ahí es nada. Partiendo de la picardía, de la inspección del código ejecutable del programa que crea el fichero y el visionado hexadecimal del propio fichero, nos va reconstruyendo paso a paso todo el proceso, llegando a obtener la información suficiente para poder realizar un nuevo programa que podría usar dicho formato de fichero. Evidentemente, no rompe el algoritmo de encriptación, pero sí lo identifica y llega a mimetizar el comportamiento del programa original… y eso que el fichero en sí también está encriptado. No me canso de repetirlo: una verdadera gozada de inteligencia y deducción aplicada. El siguiente es algo más flojito, aunque desde luego suficiente. Nos explica cómo se puede auditar un ejecutable para detectar problemas potenciales de seguridad (como, por ejemplo, sobreescrituras de buffer), y en el octavo vuelve a dejarnos con la boca abierta: tras explicarnos por encima los tipos de malware más comunes, destripa el Backdoor.Hackarmy.D, obteniendo incluso la lista de comandos remotos que acepta, así como la vía de infección e instalación. En el 9 nos cuenta las técnicas de protección anti copia y anti pirateo y nos explica las vías de entrada para saltárnoslas, pero sin profundizar mucho. También afirma algo que muchos fabricantes de software no se enteran o no quieren enterarse: que no existe ninguna protección por software (aunque se apoye parcialmente en hardware) que no pueda ser reventada tarde o temprano. El capítulo 10 cubre las técnicas existentes para evitar la ingeniería inversa y vuelve a darnos las pautas para eliminarlas, y en el 11 nos vuelve a dejar, de nuevo, perplejos, saltándose varias protecciones avanzadas de forma sencilla y eficiente mediante el uso de un programa de ejemplo. También nos cuenta que hay un sitio en internet dedicado a este tipo de técnicas tomadas como juego, es decir, que alguien propone programas de ejemplo para que otros los rompan. La web es http://www.crackmes.de. La cuarta parte tiene dos capítulos. En el primero nos cuenta cosas sobre el .NET y cómo invertir las ofuscaciones y demás protecciones, sin profundizar mucho (ya que ciertamente la mayoría de este tipo de tareas son poco menos que triviales dentro del .NET), y en el siguiente nos cuenta el estado del arte (en 2005) de las técnicas de descompilación, es decir, de las técnicas existentes para convertir un programa ejecutable en un código fuente equivalente en algún lenguaje de alto nivel, en general C. Estando de acuerdo con el autor y con otros muchos estudiosos del tema, en el proceso de compilación existe cierto grado de pérdida de información que es irreversible, sobre todo con compiladores optimizadores agresivos. El libro termina con varios apéndices que explican cómo detectar estructuras de datos, prólogos y epílogos de las llamadas de función, y la traducción de ciertas secuencias binarias a un código fuente equivalente. Como ya he dicho, y pese a lo arduo de la lectura, el libro es toda una gozada si eres de esas personas inquietas a las que les gusta emplear la deducción y la inteligencia a tareas aparentemente imposibles de realizar… para descubrir que un poco de picardía, de intelecto y de conocimientos son suficientes para asombrarse incluso de uno mismo. C++/CLI VII: Usando hilos... con hilosSi ayer hablaba sobre cómo usar hilos sin hilos, ahora vamos a hablar de hacer lo mismo pero utilizando el componente Thread, que es como se deben manejar, o mejor dicho, una de las formas adecuadas de trastearlos. Ayer comentábamos que lo habitual a la hora de crear un hilo para que realice una tarea es usar algo como esto: 1: Thread ^hilo=gcnew Thread(gcnew ThreadStart(this,&Clase::Método)); 2: hilo->Start();En donde &Clase::Método es la dirección del método que va a realizar el trabajo. Pero vamos a completar el ejemplo. Supongamos que tenemos que realizar una tarea X que se pueda realizar de forma asíncrona sin necesidad de que el usuario intervenga. La solución pasa por realizar algo como lo que explicamos ayer o como lo que vamos a contar ahora. Pero primero el código fuente: 1: #include "stdafx.h" 2: 3: using namespace System; 4: using namespace System::Threading; 5: 6: ref class Worker 7: { 8: Thread ^m_thread;9: public: 10: Worker(void) 11: { 12: }13: void DoWork(void) 14: {15: Console::WriteLine("Empiezo a currar"); 16: Thread::Sleep(10000);17: Console::WriteLine("Termino de currar"); 18: }19: void StartWorking(void) 20: {21: m_thread=gcnew Thread(gcnew ThreadStart(this,&Worker::DoWork)); 22: m_thread->Start(); 23: }24: void WaitFinished(void) 25: {26: while(m_thread->IsAlive) 27: {28: Console::WriteLine("¿Terminaste?"); 29: Thread::Sleep(1000); 30: } 31: } 32: }; 33: 34: int main(array<System::String ^> ^args) 35: { 36: Worker ^w=gcnew Worker(); 37: w->StartWorking(); 38: w->WaitFinished();39: Console::WriteLine("Ya terminó"); 40: Console::ReadKey(true); 41: return 0; 42: }Primero hemos definido una clase que llamamos Worker y que es la clase que va a hacer la tarea. Pero esto es un ejemplo, y en general todo lo que aparece en la clase podría aparecer dentro de una ficha normal y corriente. Tenemos un método llamado DoWork() que se encarga de hacer una tarea más o menos pesada; en nuestro caso el hilo se duerme durante 10 segundos. También disponemos de un método para iniciar el trabajo que hemos llamado, en un asombroso alarde de imaginación, StartWorking(). Asimismo hemos creado otro más, encargado de esperar mediante un bucle hasta que se termine de realizar la faena. En main() instanciamos la clase, hacemos una llamada a StartWorking() para que se inicie el trabajo y finalmente esperamos a que éste termine. Como el lector habrá podido darse cuenta, la utilidad de hacer esto es poca, ya que seguimos teniendo bloqueado el hilo principal del programa, por lo que podríamos transformar la función de espera por un temporizador que comprobara si el hilo ha acabado o no periódicamente, o instalar un delegado que nos notifique cuando el hilo acaba haciendo una llamada a dicho delegado al finalizar el mismo, pero entonces nos estamos acercando al modelo de ejecución asíncrona mediante delegados ya explicados. Ahora imaginemos algo más sencillo: necesitamos imprimir un documento largo y, aunque el .NET lo suele hacer rápido con el componente PrintDocument, siempre congelará nuestra interfaz, por lo que lo usual sería utilizar la primera parte de lo explicado para lanzar un hilo que imprima y dejarlo que muera él solo. Incluso podríamos lanzar varios hilos simultáneamente y olvidarnos de ellos, aunque para eso tenemos los Thread Pools y los BackgrounWorkers, que quizás explique en algún momento más adelante. Otro acercamiento El caso típico en mi trabajo consiste en que estoy hablando con un periférico (o manteniendo el estado del mismo) mediante un hilo y el usuario decide cerrar el programa. Pero hay periféricos a los que no se puede dejar de atender así como así, y menos aún si están realizando una tarea crítica, como procesando cualquier transacción. Dicha transacción ha de finalizar, y luego hemos de decirle al periférico que se deshabilite. También debemos implicar al usuario, informándole de que el hilo está terminando. Veamos la aproximación más sencilla. Primero el código. 1: #include "stdafx.h" 2: 3: using namespace System; 4: using namespace System::Threading; 5: 6: ref class Tareas 7: {8: private: 9: volatile bool m_bTerminateThread; 10: volatile bool m_bThreadIsFinished; 11: 12: Thread ^m_thread;13: void ThreadHazTareas(void) 14: {15: m_bThreadIsFinished=false; 16: int tarea=0; 17: for(;;) 18: {19: Console::WriteLine("Tarea {0}.1",tarea); 20: Thread::Sleep(1000);21: Console::WriteLine("Tarea {0}.2",tarea); 22: Thread::Sleep(1000);23: Console::WriteLine("Tarea {0}.3",tarea); 24: Thread::Sleep(1000);25: Console::WriteLine("Tarea {0}.4",tarea); 26: Thread::Sleep(1000); 27: tarea++;28: if(m_bTerminateThread) 29: {30: m_bThreadIsFinished=true; 31: return; 32: } 33: } 34: }35: public: 36: property bool HaTerminado 37: {38: bool get(void){return m_bThreadIsFinished;} 39: }40: void IniciaTareas(void) 41: {42: m_bTerminateThread=false; 43: m_thread=gcnew Thread(gcnew ThreadStart(this,&Tareas::ThreadHazTareas)); 44: m_thread->Start(); 45: }46: void TerminaTareas(void) 47: {48: m_bTerminateThread=true; 49: } 50: };51: int main(array<System::String ^> ^args) 52: { 53: Tareas ^t=gcnew Tareas(); 54: t->IniciaTareas(); 55: Thread::Sleep(5000);56: Console::WriteLine("Orden: finalizar"); 57: t->TerminaTareas();58: while(!t->HaTerminado) 59: ;60: Console::WriteLine("Finalizó"); 61: Console::ReadKey(true); 62: return 0; 63: }Aparentemente es algo más complicado que el anterior, pero sólo a simple vista. Luego pondremos un resumen del mismo. Hemos creado una clase llamada Tareas que engloba varios métodos y propiedades. En primer lugar tenemos el método ThreadHazTareas(), que es el método que hará de hilo. En él tenemos un bucle infinito que realiza una tarea en cuatro etapas que podría significar una máquina de estados de cuatro fases que deban hacerse en secuencia y no ser interrumpidas. Observamos que la primera sentencia dentro del hilo es 1: m_bThreadIsFinished=false; Estamos afirmando que el hilo está es marcha. Tras la realización de las tareas, tenemos otro bloque interesante: 1: if(m_bTerminateThread) 2: {3: m_bThreadIsFinished=true; 4: return; 5: }Aquí estamos indicando que si externamente se nos ha indicado que el hilo debe terminar, lo terminamos aquí y sólo aquí. Estamos evitando que el proceso que creó el hilo lo mate en una situación inadecuada. Lo siguiente es trivial. Una propiedad que nos devuelve cierto si el hilo ha terminado (es decir, se ha ejecutado el código anterior), otro método para arrancar el hilo y uno más para decirle que debe terminar. En main() lo habitual: la creación del objeto, la iniciación de las tareas, un rato de espera y el envío de la orden de finalización, con la espera hasta que termine. En un programa más serio, dicho código podría ir en un temporizador, o incluso como ya hemos indicado antes, con la llamada de un delegado. También podríamos haber utilizado m_thread->IsAlive pero al autor le gusta esta forma, ya que tiene más control. Muy importante Una variable de tipo bool es lo que se llama una variable atómica, es decir, está garantizado que la variable se actualiza mediante una sola instrucción máquina y que no hay pasos intermedios, y si pudiera haber alguno, lo hemos eliminado al calificarla como volátil. Si no fuera así, podría ocurrir que el hilo principal accediera a la misma y, a medio hacer alguna operación sobre ella, el sistema conmutara al hilo y que éste también realizara alguna otra operación. El estado final de la misma quedaría completamente indeterminado, y es un problema habitual con los programas multihilo. Para eso están los bloqueos y las secciones críticas, pero nosotros nos las hemos arreglado sin necesidad de ellos y sin complicarnos mucho la vida, dado que es físicamente imposible que se acceda de forma simultánea a la variable desde dos hilos diferentes ya que si el micro está leyéndola o escribiéndola, la operación se realiza en una sola instrucción máquina. Se podría poner una última pega a esta aproximación simplificada de una sección crítica, y es que justo una vez la variable haya sido leída e introducida en un registro del micro, el sistema operativo conmutara a otro hilo y éste variara su valor en memoria. Pero no existe ningún problema, ya que cuando retornáramos, tendríamos el valor anterior y tomaríamos el bueno en el siguiente ciclo ya que se ha especificado como volátil. Como se trata de una variable bi-estado, y sólo la usamos una vez, no existe problema de ningún tipo. Ojo, pero siempre, siempre, calificándola como volátil, ya que entonces el compilador podría cachearla dentro de un registro y no atender a cambios externos. Por último, una captura de lo que le ha ocurrido al autor en su máquina: Finalmente comentar que aunque los ejemplos estén escritos en C++/CLI, los conceptos son perfectamente válidos para cualquier lenguaje en el que una variable de tipo bool sea una variable atómica, como C# ó C++. December 16 Hemos leído: C++/CLI in Action (Nishant Sivakumar, Manning)Esto sí que es un libro técnico, y lo demás son tonterías. En otras palabras: el libro es bueno, muy bueno, de lo mejorcito que he leído de cualquier tema técnico relacionado con la programación. Como el título indica, se trata de una obra eminentemente práctica y profunda que trata la mayoría de los aspectos del C++/CLI sin entrar para nada en detalles sobre el .NET excepto al final, cuando explica algo sobre WPF y tecnologías asociadas. El libro parte de que al menos sabes C++ a nivel de programador profesional, y si tus conocimientos incluyen algo de C++/CLI, mejor que mejor. Dividido en tres partes de tres, dos y tres capítulos respectivamente, lo más interesantes a mi modo de ver son las dos primeras partes. Tras una introducción a C++/CLI explicando todos los aspectos básicos, como la declaración y la sintaxis del lenguaje, prestando especial atención al tema de los manejadores (el equivalente a los punteros del código nativo) y al encajado y desencajado y consecuentemente cómo y dónde se asignan las variables dentro del .NET, en el segundo capítulo nos cuenta las extensiones del lenguaje. Vemos las propiedades, los delegados y los eventos, los arrays CLI, todo ello mezclado y relacionado con el código nativo, las diferencias que hay entre los dos modelos y, sobre todo, profundizando sobre los temas tratados. Pero no al nivel del libro de Heege, sino que el tema viene tratado desde un punto de vista práctico, es decir, en relación a lo que un buen programador debe saber a la hora de conocer qué está usando y por qué está usando eso y no otra cosa. La verdad es que me asombra la profundidad y la sencillez con la que están expuestos los temas en todo el libro. El último capítulo de la primera parte cubre lo que nos queda: la semántica de la pila y la destrucción determinista, la sobrecarga de funciones, los genéricos y las plantillas y cómo todo ello se interrelaciona entre sí, explicado con la profundidad adecuada para que sepamos cómo y por qué funcionan las cosas. La segunda parte todavía es más interesante que la primera, y de hecho es el núcleo y razón de ser de todo el libro. El capítulo 4 nos habla de los punteros en .NET. Sí, de los punteros, ya que una referencia no es más que un puntero móvil, y como tal se puede fijar y operar con él como si fuera uno. O apuntar al interior de un objeto y trastearlo. Luego nos cuenta cómo utilizar una biblioteca nativa en un programa manejado y justo al revés, una biblioteca manejada en un programa nativo, y de paso nos explica cómo convertir variables nativas a manejadas y viceversa. El siguiente punto que trata es el uso de elementos nativos dentro de clases manejadas y de nuevo lo contrario, con todos los aspectos que debemos tener en cuenta a la hora de operar de esta forma. Incluso nos da clases que nos hagan de puente. Finalmente el capítulo termina explicándonos cómo podemos convertir delegados en punteros a funciones y cómo incluso podemos ejecutar un bloque de código nativo desde código manejado (cosa que haría saltar al DEP si se hiciera todo desde código nativo), etc. Verdaderamente apasionante, interesante y práctico (bueno, lo último no mucho). En el quinto volvemos a la mezcla de código nativo y manejado, profundizando en las conversiones, para pasar a ver cómo podemos envolver una biblioteca nativa con un código en C++/CLI para que pueda ser utilizado por otros lenguajes .NET sin necesidad de Interop de ningún tipo, y finalmente termina explicándonos cómo envolver una DLL MFC y COM. El último punto que trata tiene un interés enorme: una misma DLL que se puede usar tanto para código manejado como nativo, todo un tour de forcé. La tercera parte me ha resultado menos interesante, ya que es una cosa que al menos a mi no me importa mucho, pero que sí puede resultar valiosa para aquellos que tengan mucho código antiguo y quieran aprovechar las nuevas características del .NET 3.0 sin tener que reescribir toda su aplicación. Tres capítulos que cubren cómo insertar controles .NET en un cuadro de diálogo MFC (y lo contrario, un control MFC en una Ficha manejada), lo mismo con una ventana WPF con y sin XAML, y finalmente repetimos, pero ahora con WCF. Evidentemente se tratan las tres combinaciones, código WPF/XAML/WCF en código C++/CLI que directamente no soporta dichas APIs, código WPF/XAML/WCF en código C++ nativo y sus inversas. Resumiendo: un libro enormemente interesante que trata todos los temas desde un punto de vista práctico y útil y que, creo, no deja casi nada del lenguaje C++/CLI sin cubrir, incluso ampliándolo a veces mediante alguna que otra idea de concepto. Verdaderamente resulta el libro de cabecera para cualquiera que desee aprender C++/CLI de verdad, tras haber estudiado cualquier otro libro básico o incluso las entradas de este BLOG. El libro es este. November 13 Disponible un QFE (parche) para Visual Studio 2005SP1 y C++Acaban de publicarlo en el blog del Team de Visual C++: Intenta solucionar los enormes problemas que el Intellisense tiene en C++, así como mejorar la experiencia del usuario (joer qué bien queda) en cuanto al funcionamiento del editor en relación con el Intellisense, de forma que sea más cómodo y fácil trabajar, sobre todo cuando se trata de proyectos grandes y/o soluciones con muchos proyectos. Esta actualización estará disponible e integrada en el no ya tan lejano Visual Studio 2008, y los autores se comprometen a seguir investigando y avanzando en mejorar lo que yo llamo la pifia del Intellisense. Entiendo que es algo muy difícil de integrar en un compilador de C++ con la tira de años y de parches, pero si nos fijamos en soluciones de terceros (como Visual Assist X de Whole Tomato, que tampoco es la panacea pero ayuda un montón -a veces casi "adivina" lo que vas a picar a continuación, y no me refiero a que después de un gcnew te coloque la clase correcta, que por cierto no hace), y que están en ello. Lo cierto es que la entrada del blog explica muy bien -en pitinglis- qué han cambiado y cómo lo han hecho. Bueno, finalmente, si no quieren pasar por el blog citado, aquí tienen la descarga directa, que requiere que nos identifiquemos con nuestra ID de Windows Live. November 09 Gillian Bradshaw: El heredero de CleopatraOtra insulsa novelita de Egipto, aunque bastante entretenida. Cleopatra se ha suicidado, y su hijo Cesarión escapa por los pelos de una muerte segura a manos del ejército de Marco Antonio, que se ha impuesto a los dos rivales amantes de la insigne mujer. Pues bien, este libro cuenta la hipotética huida de Cesarión y lo que en ella acontece hasta que se pierde como comerciante en las rutas del Mar Negro. Entretenida, ligerita y muy bien construida, aunque demasiado blandengue: desde luego no creo que en aquella época se tratara de esa forma ni a los fugitivos ni a los culpados de traición, pero buen, siempre queda enmarcada como lectura para pasar el rato. El Loco de la ColinaNo hay que tener una colina propia para estar loco |
|
|||||||||||||||||||||||
|
|