Looking in to the mirror ============================ ## Introduction This challenge was about employing reflection techniques to modify and view internal structures of the virtual machine. Pharo is a Smalltalk environment, most widely known for its metaprogramming and reflection capabilities. Everything in Smalltalk is an object, and every object is an instance of a class, even a class itself is an instance of something (a metaclass). The syntax of a Smalltalk program is relatively simple, the most important part is how to send messages (in other object oriented languages also called: invoking a method). Lets say we want to send a message `newWithName` to a class `Person`, this can be achieved as follows: ``` p := Person newWithName:'Bram'. ``` Now the variable `p` contains a reference to an instance of the class `Person`. Messages that can be send to classes themselves are defined on the metaclass of a class. In this case the metaclass is the `Person class` class. We can obtain a reference to a method itself by using the `>>` (lookup) operator: ``` (Person class)>>#newWithName ``` ## The Challenge The challenge consisted of connecting to a remote endpoint using netcat, which provided a Smalltalk REPL where Smalltalk expressions could be executed. The Pharo VM contained serveral user-defined classes: * Challenge * Squeak The REPL suggested that you could obtain the flag by using: ``` Challenge new flag ``` however, when trying to do this, the REPL would yield that `only a Squeak could to that`, which means that the method `flag` could only be called from an instance of the class `Squeak`. Luckily, the `Squeak` class contained a method named `fetchFlag`. So lets try to do this: ``` Squeak new fetchFlag. ``` This however, yields an initialisation error, suggesting that no instance of a `Squeak` could be created. ## Solution(s) As Pharo has many ways to interact with classes and objects, the challenge has many solutions. Here, I will only present two possible solutions. One involves inspecting the method dictionnary of the `Challenge` class, the other involves overwriting the behaviour in the `Squeak` class that prevents its instance creation. ### Inspecting the Challenge class Its is clear that we need to obtain some representation of the source of the `flag` method of the `Challenge` class. We can try to obtain a reference to this method by using the lookup operator: ``` Challenge>>#flag ``` however, this results in a `LookupError`, the `Challenge` class seems to be too well protected. However, Pharo has many ways to get references to methods, so we can try another one: ``` Challenge methodDict at:#flag ``` This seems to work well. Now we only need to print its source code. ``` (Challenge methodDict at:#flag) ast nodesDo: [:n | Transcript show: n; cr. ] ``` Which yields: ``` RBTemporaryNode(caller) RBAssignmentNode(caller := thisContext client) RBMessageNode(thisContext client) RBThisContextNode(thisContext) RBTemporaryNode(caller) RBMessagifTrue: [ ^ 'IG{ImSoMetaEvenThisAcronym}' ]) RBMessageNode(caller class = Squeak) RBMessageNode(caller class) RBTemporaryNode(caller) RBGlobalNode(Squeak) RBBlockNode([ ^ 'IG{ImSoMetaEvenThisAcronym}' ]) RBSequenceNode(^ 'IG{ImSoMetaEvenThisAcronym}') RBReturnNode(^ 'IG{ImSoMetaEvenThisAcronym}') RBLiteralValueNode('IG{ImSoMetaEvenThisAcronym}') RBReturnNode(^ 'Only a Squeak can do that (see Squeak>>#fetchFlag)') RBLiteralValueNode('Only a Squeak can do that (see Squeak>>#fetchFlag)') ``` And there is our flag. ### Recompiling the Squeak class Another way to solve this challenge is to allow the `Squeak` class to be initialised. At first, we are not entirely sure why the `Squeak` class fails to initialise. It could be that its `initialize` method has been overridden. We can find out which methods have been overriden by retrieving the methods of the `Squeak` class. ``` Squeak methods ``` which only yields `Squeak>>#fetchFlag`. We can conclude that the `InitialisationError` is signaled elsewhere. Maybe it is at the class side? ``` (Squeak class) methods ``` which yields `(Squeak class)>>#basicNew`. Obtaining a reference to this method using `(Squeak class)>>#basicNew` yields: ``` basicNew InitialisationError signal. ``` Hence, we found the culprit. We can disable this behaviour by recompiling that method to something that just delegates the `basicNew` message to its parent: ``` (Squeak class) compile: 'basicNew ^ super basicNew' ``` Now, we can try to get an instance of our `Squeak` again. ``` Squeak new. ``` Which, indeed, yields `a Squeak`, mission accomplished. The last part of this solution consisted of calling the `fetchFlag` method on that instance: ``` Squeak new fetchFlag. ``` Which yields: ``` IG{ImSoMetaEvenThisAcronym} Challenge ``` Success!