Todos los lenguajes de computadora son esencialmente instrucciones para una (o más de una) CPU, en la forma de "haga esto. Ahora haga eso". De modo que siempre "llegue al montaje" tarde o temprano. Los lenguajes de alto nivel son marcos (¿andamios?) Para evitar repeticiones extensas de código de ensamblaje, y permiten la programación de una manera más intuitiva; Este aumento en la comprensión, la flexibilidad y la capacidad de mantenimiento tienen un precio: en tamaño, rendimiento y requisitos.
Cuando tenga éxito en obtener el control del proceso de la aplicación, independientemente de los medios (desbordamiento del búfer, etc.), básicamente tiene solo un área de memoria donde puede colocar lo que quiera, y esto es en su mayoría independiente en cómo tienes en este punto.
Ahora, por un lado, el ensamblaje tiene la mayor "densidad" de instrucciones sobre el tamaño del código, al menos para los tamaños de código pequeños, por lo que, naturalmente, es su primera opción si desea abarrotar al máximo en el área que acaba de "conquistar". .
En segundo lugar, y probablemente más importante, cuando golpeas en un área de memoria, sabes poco o nada sobre el "contexto" , no tienes una configuración de contexto . Por ejemplo, en el lenguaje C, su función main()
es de hecho una función - recibe el nombre de ejecución de C , que ya ha preparado un entorno para que se ejecute el programa en, una especie de sistema de soporte de vida para su código. Con un Shellcode, no tiene tal soporte, y necesita poder prescindir (es decir, ensamblar) o construir el suyo propio (nuevamente en ensamblaje, ya que el código de construcción de soporte vital no puede necesitar un soporte vital en sí mismo) .
Entonces, en teoría, podría preparar un "código auxiliar de tiempo de ejecución de shellcode" inicializando un entorno y "vinculando" su código C al sistema. Una vez que tuvo esto, simplemente podría adjuntar un código de shell C al tiempo de ejecución y poder referir las funciones del sistema operativo por nombre. Varios shellcodes tienen un código auxiliar para hacer esto, pero generalmente está escrito en Assembly porque la razón número uno todavía se mantiene: el espacio es un bien escaso.
Esas explotaciones que permiten la ejecución de un binario independiente (en la forma más básica y trivial, un archivo adjunto ejecutable a un correo electrónico en el que la víctima hará clic) tienen restricciones de tamaño pequeñas y (generalmente) no tienen requisitos de tiempo de ejecución, por lo que necesitan no, y para fines de mantenimiento casi nunca están escritos en lenguajes de bajo nivel.