A thought for WTF code...



  • I've always thought it would be a really cool idea to create a C program that, through very well-controlled stack smashing, [b]arbitrarily[/b] jumps between functions.  That is, it saves the start addresses of the functions in global variables and then hops to them, and by smashing the stack in exactly the right way it can do things like have main call function A call B which calls C, and then have C return directly to A, which then smashes itself into B, which then returns to main.  Or better yet, entirely eschew the "return" operation in favor of stack smashing.

     If there isn't anything stopping it from working, this would be a most ingenious idea to make obfuscated code.

     
    And best of all it would be completely architecture-dependent.
     



  • That's pretty much how you would go about exploiting a program with buffer overflow vulnerabilities to have it execute arbitrary code. There's a really good 10-year-old article on doing just that: http://insecure.org/stf/smashstack.html



  • Hi!

     
    Sometimes I've had an idea similar to yours: instead of returning to caller, skip some calls and return to the caller of the caller, by example. The next Java code can do that.

    Let's say we have an hierarchical structure, where A can contain some Bs, and every B can contain some Cs. A, B and C would be the data objects, the value objects. Let's have a function A.find() that returns A, B or C, depending on the number of parameters received. The tricky part begins here: A, B and C are declared as subclasses of Throwable, and the find method returns void, but can throw any of those classes.

     

    public final class A extends Throwable {
       
        private static final long serialVersionUID = 1L;

        private String id;
       
        private List bList; // List of B's
       
        public A(final String id) {
            super();
            this.id = id;
            this.bList = new ArrayList();
        }
       
        public final void find(final String idA, final String idB, final String idC) throws A, B, C {
            if (this.id.equals(idA)) {
                if (idB == null) {
                    throw this;
                }
                for (Iterator it = this.bList.iterator(); it.hasNext(); ) {
                    ((B) it.next()).find(idB, idC);
                }
            }
        }

    }

     

    public final class B extends Throwable {
       
        private static final long serialVersionUID = 1L;

        private String id;
       
        private List cList; // List of C's
       
        public B(final String id) {
            super();
            this.id = id;
            this.cList = new ArrayList();
        }
       
        public final void find(final String idB, final String idC) throws B, C {
            if (this.id.equals(idB)) {
                if (idC == null) {
                    throw this;
                }
                for (Iterator it = this.cList.iterator(); it.hasNext(); ) {
                    ((C) it.next()).find(idC);
                }
            }
        }

    }

     

    public final class C extends Throwable {
       
        private static final long serialVersionUID = 1L;
       
        private String id;
       
        public C(final String id) {
            super();
            this.id = id;
        }
       
        public final void find(final String idC) throws C {
            if (this.id.equals(idC)) {
                throw this;
            }
        }

    }

     

    Now, let's suppose we have a three-tier architecture, with the three basic layers: presentation, business and persistence. In that architecture, we have a use case that receives some codes, and shows the object identified by them. Now, we add some things to add flavour to our example: B objects have an additional field that need special persistence processing, and A objects shouldn't be shown in the page (business rule). Here's the code:

    public final class App {
       
        private A aObject;
       
        public final void firstLayer(final String idA, final String idB, final String idC) {
            try {
                this.secondLayer(idA, idB, idC);
               
                // Nothing found
                System.out.println("nothing found");
               
            } catch (B b) {
                // B object found
                System.out.println(b.toString());
               
            } catch (C c) {
                // C object found
                System.out.println(c.toString());
            }
        }
       
        public final void secondLayer(final String idA, final String idB, final String idC) throws B, C {
            try {
                this.thirdLayer(idA, idB, idC);
               
            } catch (A a) {
                // we don't want to do anything with A objects
            }
        }
       
        public final void thirdLayer(final String idA, final String idB, final String idC) throws A, B, C {
            try {
                this.aObject.find(idA, idB, idC);
               
            } catch (B b) {
                // additional processing for B objects goes here
                throw b;
            }
        }
    }

     

    As you can see, the call to the find() method in the last layer (the persistence one) can...

    - ...return gracefully when nothing is found. The execution flow would return in a classic manner, slowly, layer by layer, back to the presentation layer

    - ...throw an A object. The execution flow inmediately goes to the second layer (the business layer), to the part that processes the A objects (in this case, "we don't want to do anything with A objects").

    - ...throw a B object. The execution flow keeps into the third layer (the persistence layer), but goes inmediately to the fragment of code with the additional processing for B objects.

    - ...throw a C object. The execution flow jumps back to the first layer (the presentation layer).

     

    Isn't it funny!? Fortunately for my job mates, I'm not allowed to use this technique in real projects :D



  • You're actually thinking of a system that works well enough to be a preferred method to compile purely functional code. It's known as the "continuation passing style": every 'call' has one extra argument that is a code address, and when the 'function' is finished, it jumps to that address instead of using a stack-based return.
    This approach has some interesting properties when optimising code, that happen to work particularly well with a purely functional language - optimising 'across function boundaries' stops being such a hard problem, which is important in a language where people naturally create huge numbers of very simple functions.

    (It's not as fast as an optimally-compiled stack-based system, but it's awfully close and lets current compiler technology do better than it otherwise would, so it can work out faster overall in many cases)

    There is nothing intrinsically obfuscated or architecture-dependent about it. Trying to do it in C might make a mess, but doing it in a functional language is really slick. 



  • I did that for my calculator entry in OMGWTF. The fact that I was a finalist should reflect poorly on that paradigm.



  • @Welbog said:

    I did that for my calculator entry in OMGWTF. The fact that I was a finalist should reflect poorly on that paradigm.

    Not really, most ideas can be used for evil. 


Log in to reply