{"action":"created","comment":{"url":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/comments/23769643","id":23769643,"diff_hunk":"@@ -0,0 +1,968 @@\n+============================================================\n+Introduction on turning good code into attrocities with LLVM\n+============================================================\n+\n+Objective\n+=========\n+The objective of this post is to explain the basics of LLVM bytecode obfuscation.\n+*'But why obfuscate the LLVM bytecode? Why not the source code? Or the binary?'*, you may ask.\n+\n+Well it's because LLVM is *super swag* right now and using it is cool.\n+But, regarding the engineering aspects, it is because there are lots of front-ends converting different languages into the same LLVM bytecode (Clang/Clang++ for C/C++, Mono LLVM for C#, Pyston for ... Python and so on).\n+Hence by working at the bytecode level we can obfuscate programs produced by many languages without even knowing them.\n+Another good thing is that the obfuscation can be easily integrated with the compilation chain.\n+\n+Now let's talk about what we're going to do.\n+Our mission (and we have no choice but to accept it) is to obfuscate all null literals in the code.\n+It means that we are going to replace (almost) all the zeroes in the code by a non-trivial boolean expression always false.\n+\n+        prime1 * ((x | any1)**2) != prime2 * ((y | any2)**2)\n+\n+    - prime1 and prime2 are *distinct* prime numbers\n+    - any1 and any2 are *distinct* strictly positive random numbers\n+    - x and y are two variables picked from the program (they have to be reachable from the obfuscation instructions)\n+\n+This expression will always return a boolean zero (false). The idea is to insert this test into our code, just before the 0 we want to obfuscate and to replace this 0 by the result of our comparison.\n+As you have probably noticed we will have to pay attention to the type of the original 0 and make sure we cast the result of our expression to its type.\n+\n+This obfuscation may not be the most sophisticated ever written but it's enough to learn the basics of LLVM bytecode obfuscation (and to annoy our reverse engineer friends.)\n+\n+Requirements\n+============\n+\n+Programming background\n+**********************\n+To go through this tutorial you only need to be able to read C/C++ code. We will learn the basics of LLVM API and LLVM bytecode together.\n+\n+Environment\n+***********\n+If you want to experiment along with this tutorial (which is strongly recommended) you will need to set up an LLVM development environment.\n+\n+    * First let's download the LLVM sources...\n+        ``>$ git clone --depth=1 --branch=release_35 https://github.com/llvm-mirror/llvm llvm_src``\n+\n+    * Now download the clang sources inside the llvm_src/tools directory.\n+        ``>$ cd llvm_src/tools && git clone --depth=1 --branch=release_35 https://github.com/llvm-mirror/clang``\n+\n+    * Create a build directory somewhere *out of the llvm source tree*:\n+        ``>$ mkdir path/to/llvm/build/llvm``\n+\n+    * Let's build LLVM:\n+        ``>$ cd ~/llvm && cmake path/to/llvm/sources``\n+        ``>$ make -j``\n+\n+    * And... wait....\n+        ``>IRL sleep 1000``\n+\n+    * (Optional) You should set your path to include the freshly baked LLVM tools and clang:\n+        ``>$ export PATH=~path/to/llvm/build/llvm/bin:$PATH``\n+\n+    * (Optional) You can run the test suite to make sure that LLVM was built correctly:\n+        ``>$ make check``\n+\n+You have just built LLVM and clang but we going to build the passes out of the LLVM source tree. To do so we have prepared a git repository with the basic infrastructure.\n+\n+        ``>$ git clone https://github.com/quarkslab/llvm-passes``\n+\n+From now on we will be working exclusively inside the ``llvm-passes`` folder (we will refer to it as ``$PASSDIR``). So let's visit our new office:\n+    * *cmake*: cmake definitions to check the python environment. Required to generate our passes test suites.\n+    * *doc*: contains the sources of this tutorial, in case you find a shaming typo.\n+    * *llvm-passes*: contains one subdirectory per pass, and a ``CMakeList.txt`` used to generate the passes.\n+    * *tests*: tests and validation for our passes, contains one directory per pass. The tests are using llvm-lit, the LLVM integrated validation tool.\n+    * *CMakeList.txt*: the file used to generate the required Makefiles\n+\n+\n+Let's obfuscate!\n+================\n+\n+Now that the environment is ready we will start writing our obfuscating pass. You may have noticed that there already is an ``ObfuscateZero`` dir in ``$PASSDIR/llvm-passes``.\n+This is the pass we are going to reproduced step by step. So unless you want to get spoiled don't look at it yet.\n+\n+Now we have to deal with the hardest part of LLVM pass development (and software development in general), namely finding a name for our project.\n+Since I am not really inspired and ``ObfuscateZero`` is already taken, let's call our new pass *MyPass*.\n+\n+We need a new directory for our pass:\n+    ``>$ mkdir $PASSDIR/llvm-passes/MyPass``\n+\n+And we will write the pass in ``$PASSDIR/llvm-passes/MyPass/MyPass.cpp``.\n+\n+\n+One with nothing\n+****************\n+\n+The minimal compiling code for an LLVM pass is the following. It is explained `there <http://llvm.org/docs/WritingAnLLVMPass.html#basic-code-required>`_ so I won't explain it again and focus on the obfuscation part.\n+\n+.. code:: C++\n+\n+    #include \"llvm/Pass.h\"\n+    #include \"llvm/IR/Function.h\"\n+    #include \"llvm/Support/raw_ostream.h\"\n+\n+    #include \"llvm/IR/LegacyPassManager.h\"\n+    #include \"llvm/Transforms/IPO/PassManagerBuilder.h\"\n+\n+    using namespace llvm;\n+\n+    namespace {\n+    class MyPass : public BasicBlockPass {\n+    public:\n+      static char ID;\n+\n+      MyPass() : BasicBlockPass(ID) {}\n+\n+      virtual bool runOnBasicBlock(BasicBlock &BB) override {\n+        errs() << \"I m running on a block...\\n\";\n+        return false;\n+      }\n+\n+    };\n+    }\n+\n+    char MyPass::ID = 0;\n+    static RegisterPass<MyPass> X(\"MyPass\", \"Obfuscates zeroes\",\n+                                         false, false);\n+\n+    // register pass for clang use\n+    static void registerMyPassPass(const PassManagerBuilder &,\n+                                   PassManagerBase &PM) {\n+      PM.add(new MyPass());\n+    }\n+    static RegisterStandardPasses\n+        RegisterMBAPass(PassManagerBuilder::EP_EarlyAsPossible,\n+                        registerMyPassPass);\n+\n+If you have been paying attention so far you should remember that we are going to obfuscate null literals.\n+And to do so we will randomly pick two variables reachable from where the replacement occurs.\n+So, in order to keep the pass as simple as possible we are going to work at the basic bloc level, this way there will be no reachability problems with the variables we encounter.\n+This is why our class derives from the ``BasicBlockPass`` class.\n+\n+.. code:: C++\n+\n+    class MyPass : public BasicBlockPass\n+\n+\n+Do or do not there is no ... test\n+*********************************\n+\n+I am sure that your are eager to compile and run this empty pass. Thanks to the files provided in the Quarkslab git it's actually quite easy.\n+First you need to tell cmake that your pass should be compiled by adding it in the file ``$PASSDIR/llvm-passes/CMakeList.txt``.\n+It should now look like this:\n+\n+.. code:: cmake\n+\n+    set(EPONA_LLVM_MODULES\n+        ObfuscateZero\n+        MyPass\n+    )\n+\n+Now we are going to build the pass:\n+\n+.. code:: bash\n+\n+    >$ cd $PASSDIR\n+    >$ mkdir build\n+    >$ cd build\n+    >$ cmake -DLLVM_ROOT=path/to/your/llvm/build ..\n+    >$ make\n+\n+And now let's run our pass with clang. But we need a test file, write the following code somewhere:\n+\n+.. code:: c\n+\n+    #include <stdio.h>\n+\n+    int foo(){return 1;}\n+\n+    int main() {\n+        printf(\"Hello world\\n\");\n+\n+        return 0;\n+    }\n+\n+\n+And compile it with our awesome pass using:\n+\n+.. code:: bash\n+\n+    >$ clang++ -Xclang -load -Xclang $PASSDIR/build/llvm-passes/LLVMMyPass.so path/to/test/file -o /tmp/awesome.out\n+\n+Since there are two blocks in our code (foo and main), we see the message \"I m running on a block...\" twice!\n+\n+Congratulations you have compiled your first program with an LLVM pass! (You can test the executable, it should work... should)\n+\n+Playtime is over\n+****************\n+\n+The method we have to implement is ``runOnBasicBlock`` which takes as parameter a reference to the current block. We will proceed step by step.\n+\n+Finding null literals\n++++++++++++++++++++++\n+\n+To find the null literals we need to iterate over every instruction of the block and check if one of the operands is null.\n+\n+.. code:: C++\n+\n+  //Add the following to your headers\n+  #include \"llvm/IR/Constants.h\"\n+  #include \"llvm/IR/Instructions.h\"\n+\n+  //Add the following to MyPass\n+  virtual bool runOnBasicBlock(BasicBlock &BB) override {\n+    // Not iterating from the beginning to avoid obfuscation of Phi instructions\n+    // parameters\n+    for (typename BasicBlock::iterator I = BB.getFirstInsertionPt(),\n+                                       end = BB.end();\n+         I != end; ++I) {\n+      Instruction &Inst = *I;\n+      // We are not using an iterator because we will need i later.\n+      for (size_t i{0}; i < Inst.getNumOperands(); ++i) {\n+        if (Constant *C = isValidCandidateOperand(Inst.getOperand(i))) {\n+          errs() << \"I've found one sir!\\n\";\n+        }\n+      }\n+    }\n+    return false;\n+   }\n+\n+  Constant *isValidCandidateOperand(Value *V) {\n+    if (Constant *C = dyn_cast<Constant>(V)) {\n+      // Checking constant eligibility\n+      if (isa<PointerType>(C->getType())) {\n+        // dbgs() << \"Ignoring NULL pointers\\n\";\n+        return nullptr;\n+      } else if (C->getType()->isFloatingPointTy()) {\n+        // dbgs() << \"Ignoring Floats 0\\n\";\n+        return nullptr;\n+      } else if (C->isNullValue()) {\n+        return C;\n+      } else {\n+        return nullptr;\n+      }\n+    } else {\n+      return nullptr;\n+    }\n+  }\n+\n+The ``runOnBasicBlock`` method is going to iterate through all the instructions of the block (for loop) and check if any operand of those instructions is an eligible null literal.\n+If any of the operand is a null literal we print a message on the debug stream and we continue.\n+You may have noticed the for loop is initialized with ``BB.getFirstInsertionPt()``.\n+We could have iterated through the block with a foreach like:\n+\n+.. code:: C++\n+\n+    for(auto &I : BB) {\n+    }\n+\n+But we do not want to modify the special instructions located at the begining of the block (the `phi instructions <http://en.wikipedia.org/wiki/Static_single_assignment_form#Converting_out_of_SSA_form>`_), so we skip them altogether and set the iterator to the first 'normal' instruction.\n+\n+The ``isValidCandidateOperand`` method checks if its parameter is a literal (constant means literal in LLVM, not variable declared ``const``).\n+It also checks the type of the literal, it must not be a pointer or a floating point value (you will see later why).\n+The type checks are done with the ``isa<>`` function which checks if its parameter can be cast to the type given by the template parameter.\n+If all those conditions are satisfied and the litteral is null we return a pointer to the operand (cast as a Constant) else ``nullptr``.\n+\n+If you compile and run the pass on our test code it finds **two** when we just expected it to find the ``return 0``.\n+\n+Let's take a look at the llvm bytecode generated by clang:\n+\n+.. code:: bash\n+\n+    # The pass is not necessary now since it doesn't change anything, but it will be later.\n+    >$ clang++ -S -emit-llvm -Xclang -load -Xclang $PASSDIR/build/llvm-passes/LLVMMyPass.so path/to/test/file -o /tmp/awesome.ll\n+\n+We get the following:\n+\n+.. code:: llvm\n+\n+    ; Function Attrs: nounwind uwtable\n+    define i32 @foo() #0 {\n+      ret i32 1\n+    }\n+\n+    ; Function Attrs: nounwind uwtable\n+    define i32 @main() #0 {\n+      %1 = alloca i32, align 4\n+      store i32 0, i32* %1\n+      %2 = call i32 @puts(i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0))\n+      ret i32 0\n+    }\n+\n+The two 0 that triggered the debug message from our pass are in the ``store`` and ``ret`` instructions.\n+As you can see the compilation to bytecode introduced an expression not present in the source code. This will probably happen quite often when developing LLVM passes.\n+While debugging your future passes you will probably have to read a lot of bytecode so you should familiarize yourself with it.\n+Lucky for you it's pretty easy to read (at least compared to asm).\n+\n+\n+We've found your replacement\n+++++++++++++++++++++++++++++\n+\n+Now that we can find null literals, we need to be able to replace them.\n+To do so we need:\n+\n+    1. To know the variables reachable from the instruction we replace\n+    2. To generate the instructions of the arithmetic expression seen earlier\n+    3. To insert those expressions back into the code\n+    4. (Optional) Generate random prime numbers\n+\n+Reachable variables\n+~~~~~~~~~~~~~~~~~~~\n+\n+To be sure to have a pool of **reachable** variable during our obfuscation, we are going to register all the Integers we come across while we iterate through the bloc instructions.\n+\n+To do so we need:\n+    * a class member vector storing pointers to the interesting Integer/values. We will empty it at the end of every block.\n+    * a method to check the type of the instruction and store it in the vector if it is eligible.\n+    * call the above mentioned method from the main loop.\n+\n+Our class becomes:\n+\n+.. code:: C++\n+\n+    //Add this to your includes\n+    #include <vector>\n+\n+\n+    class MyPass : public BasicBlockPass {\n+      std::vector<Value *> IntegerVect;\n+\n+    public:\n+\n+      static char ID;\n+\n+      MyPass() : BasicBlockPass(ID) {}\n+\n+      virtual bool runOnBasicBlock(BasicBlock &BB) override {\n+        IntegerVect.clear();\n+\n+        // Not iterating from the beginning to avoid obfuscation of Phi instructions\n+        // parameters\n+        for (typename BasicBlock::iterator I = BB.getFirstInsertionPt(),\n+                                           end = BB.end();\n+             I != end; ++I) {\n+          Instruction &Inst = *I;\n+            for (size_t i{0}; i < Inst.getNumOperands(); ++i) {\n+              if (Constant *C = isValidCandidateOperand(Inst.getOperand(i))) {\n+                errs() << \"I've found one sir!\\n\";\n+              }\n+          }\n+          registerInteger(Inst);\n+        }\n+        return false;\n+      }\n+\n+    private:\n+      void registerInteger(Value &V) {\n+        if (V.getType()->isIntegerTy()) {\n+          IntegerVect.emplace_back(&V);\n+          errs() << \"Registering an integer!\" << V << \"\\n\";\n+        }\n+      }\n+\n+      Constant *isValidCandidateOperand(Value *V) {\n+        if (Constant *C = dyn_cast<Constant>(V)) {\n+          // Checking constant eligibility\n+          if (isa<PointerType>(C->getType())) {\n+            // dbgs() << \"Ignoring NULL pointers\\n\";\n+            return nullptr;\n+          } else if (C->getType()->isFloatingPointTy()) {\n+            // dbgs() << \"Ignoring Floats 0\\n\";\n+            return nullptr;\n+          } else if (C->isNullValue()) {\n+            return C;\n+          } else {\n+            return nullptr;\n+          }\n+        } else {\n+          return nullptr;\n+        }\n+      }\n+    };\n+\n+\n+and replace your test code by this updated version:\n+\n+.. code:: c\n+\n+    #include <stdio.h>\n+\n+    int foo(){return 1;}\n+\n+    int main() {\n+        int a = 2;\n+        printf(\"Hello world\\n\");\n+        a *= 3;\n+\n+        return 0;\n+    }\n+\n+\n+If you run the pass on our new test file you'll notice that the pass finds **3** integers to register corresponding to %2, %3 and %4 in the following bytecode:\n+\n+.. code:: llvm\n+\n+    ; Function Attrs: nounwind uwtable\n+    define i32 @main() #0 {\n+      %1 = alloca i32, align 4\n+      %a = alloca i32, align 4\n+      store i32 0, i32* %1\n+      store i32 2, i32* %a, align 4\n+      %2 = call i32 @puts(i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0))\n+      %3 = load i32* %a, align 4\n+      %4 = mul nsw i32 %3, 3\n+      store i32 %4, i32* %a, align 4\n+      ret i32 0\n+    }\n+\n+\n+There are a few things that you should remember from this little modification:\n+* The LLVM bytecode is in `SSA form <http://en.wikipedia.org/wiki/Static_single_assignment_form>`_, so you will see variables that you didn't explicitly declared appear in the bytecode. Typically temporary result or ``load``s.\n+* A variable declaration in your code returns a **pointer** in the bytecode not an instance of the type of the variable.\n+* You *need* to look at the bytecode to understand what you're *actually* telling LLVM to do (at least at first :p).\n+* Using the ``operator<<`` is **very** useful for debug. (You can even use it on blocks, functions, ...)\n+\n+I will make this entire pig disappear!\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Ok we're almost done, the only thing left is to generate the new instructions and insert them into the code.\n+For those of you who forgot (or skipped the intro) we are going to replace the null integer literals by the result of the expression:\n+\n+        prime1 * ((x | any1)**2) != prime2 * ((y | any2)**2)\n+\n+    - prime1 and prime2 are *distinct* prime numbers\n+    - any1 and any2 are *distinct* strictly positive random numbers\n+    - x and y are two variables picked from the program (they have to be reachable from the obfuscation instructions)\n+\n+We will write a new method ``replaceZero`` that will do all the funny stuff. However given the size of the function we will detail it step by step:\n+\n+First please add the following to your source file.\n+\n+.. code:: C++\n+\n+  // Insert with the other #include\n+  #include \"llvm/IR/IRBuilder.h\"\n+  #include <random>\n+\n+  // Insert just before the MyClass declaration\n+  using prime_type = uint32_t;\n+\n+Our ``replaceZero`` method will replace the null operand(s) of an instruction and return a pointer to the new operand(s) (or ``nullptr`` if a problem occurs). This gives us the following signature:\n+.. code:: C++\n+\n+  Value* replaceZero(Instruction &Inst, Value* VReplace) {\n+    // Replacing 0 by:\n+    // prime1 * ((x | any1)^2) != prime2 * ((y | any2)^2)\n+    // with prime1 != prime2 and any1 != 0 and any2 != 0\n+\n+To generate our new formula we need 2 distinct prime numbers:\n+\n+.. code:: C++\n+\n+    prime_type p1 = getPrime(),\n+               p2 = getPrime(p1);\n+\n+    if(p2 == 0 || p1 == 0)\n+        return nullptr;\n+\n+The LLVM bytecode is strongly typed so will need to play a little with the types.\n+The important types are the type of the operand we are going to replace and the type in which we will do the operations of the obfuscation expression.\n+For the intermediary operations we will use the ``prime_type`` we've just declared (in this case ``uint32_t``).\n+However we need to be careful about type conversions and the type overflows (we will see later why and how).\n+\n+.. code:: C++\n+\n+    Type *ReplacedType = VReplace->getType(),\n+         *IntermediaryType = IntegerType::get(Inst.getParent()->getContext(),\n+                                              sizeof(prime_type) * 8);\n+\n+Next we need to choose randomly two reachable variables (possibly twice the same) and two random strictly positive integers.\n+For the variables we are going to randomly pick values in ``IntegerVect``.\n+\n+.. code:: C++\n+\n+    // Abort the obfuscation if we have encontered no integers so far\n+    if (IntegerVect.size() < 1) {\n+      return nullptr;\n+    }\n+\n+    // Random distribution to pick variables from IntegerVect\n+    std::uniform_int_distribution<size_t> Rand(0, IntegerVect.size() - 1);\n+    // Random distribution to pick Any1 and Any2 from [1, 10]\n+    std::uniform_int_distribution<size_t> RandAny(1, 10);\n+\n+    // Indexes chosen for x and y\n+    size_t Index1 = Rand(Generator), Index2 = Rand(Generator);\n+\n+If we overflow our intermediary type in one of the new instructions we could loose the property that the obfuscating comparison is always false.\n+We could replace a zero by... something else.\n+So we could change the result(s) produced by the code, and we want to avoid that all costs.\n+To prevent overflowing we have set the maximum for Any1 and Any2 to 10, but this is not enough.\n+We need to make sure that x and y are not too big. The trick is that we have no information on their value at compile time.\n+The solution we chose is to apply a bitmask to x and y in order to obtain a variable of which we know the max value.\n+\n+.. code:: C++\n+\n+    // Creating the LLVM objects representing literals\n+    Constant *any1 = ConstantInt::get(IntermediaryType, 1 + RandAny(Generator)),\n+             *any2 = ConstantInt::get(IntermediaryType, 1 + RandAny(Generator)),\n+             *prime1 = ConstantInt::get(IntermediaryType, p1),\n+             *prime2 = ConstantInt::get(IntermediaryType, p2),\n+             // Bitmasks to prevent overflow\n+             *OverflowMaskLHS = ConstantInt::get(IntermediaryType, 0x00000007),\n+             *OverflowMaskRHS = ConstantInt::get(IntermediaryType, 0x00000007);\n+\n+Now that we have everything we need we will create our new instructions.\n+To insert new instructions **before** a specific instruction we use an ``IRBuilder``.\n+This object will create instructions and insert them before the instruction given to its constructor.\n+And we need to insert our new instructions before the instruction we are working on. That's why ``replaceZero`` takes an Instruction as parameter. We will forward it to the builder.\n+\n+.. code:: C++\n+\n+    IRBuilder<> Builder(&Inst);\n+\n+    // lhs\n+    // Casting x to our intermediary type\n+    Value *LhsCast =\n+        Builder.CreateZExtOrTrunc(IntegerVect.at(Index1), IntermediaryType);\n+    // Registering the new integers for a future obfuscation\n+    registerInteger(*LhsCast);\n+    // To avoid overflow and truncate x\n+    Value *LhsAnd = Builder.CreateAnd(LhsCast, OverflowMaskLHS);\n+    registerInteger(*LhsAnd);\n+    // Creating LhsOr = (x | any1)\n+    Value *LhsOr = Builder.CreateOr(LhsAnd, any1);\n+    registerInteger(*LhsOr);\n+    // LhsOr * LhsOr\n+    Value *LhsSquare = Builder.CreateMul(LhsOr, LhsOr);\n+    registerInteger(*LhsSquare);\n+    // prime1 * LhsOr^2\n+    Value *LhsTot = Builder.CreateMul(LhsSquare, prime1);\n+    registerInteger(*LhsTot);\n+\n+    // rhs\n+    // The same as lhs with prime2, any2 and y\n+    Value *RhsCast =\n+        Builder.CreateZExtOrTrunc(IntegerVect.at(Index2), IntermediaryType);\n+    registerInteger(*RhsCast);\n+    Value *RhsAnd = Builder.CreateAnd(RhsCast, OverflowMaskRHS);\n+    registerInteger(*RhsAnd);\n+    Value *RhsOr = Builder.CreateOr(RhsAnd, any2);\n+    registerInteger(*RhsOr);\n+    Value *RhsSquare = Builder.CreateMul(RhsOr, RhsOr);\n+    registerInteger(*RhsSquare);\n+    Value *RhsTot = Builder.CreateMul(RhsSquare, prime2);\n+    registerInteger(*RhsTot);\n+\n+    // The final comparison always returning false\n+    Value *comp =\n+        Builder.CreateICmp(CmpInst::Predicate::ICMP_EQ, LhsTot, RhsTot);\n+    registerInteger(*comp);\n+    // Casting the boolean '0' back to the type of the replaced operand\n+    Value *castComp = Builder.CreateZExt(comp, ReplacedType);\n+    registerInteger(*castComp);\n+\n+    return castComp;\n+  }\n+\n+OK!\n+Almost there... we need to call our new function in the main loop and explicitly replace the operand:\n+\n+.. code:: C++\n+\n+  virtual bool runOnBasicBlock(BasicBlock &BB) override {\n+    IntegerVect.clear();\n+    bool modified = false;\n+\n+    for (typename BasicBlock::iterator I = BB.getFirstInsertionPt(),\n+                                       end = BB.end();\n+         I != end; ++I) {\n+      Instruction &Inst = *I;\n+        for (size_t i{0}; i < Inst.getNumOperands(); ++i) {\n+          if (Constant *C = isValidCandidateOperand(Inst.getOperand(i))) {\n+            if (Value *New_val = replaceZero(Inst, C)) {\n+              Inst.setOperand(i, New_val);\n+              modified = true;\n+            } else {\n+              // If sthg wrong happens during the replacement,\n+              // almost certainly because IntegerVect is empty\n+              errs() << \"MyPass: could not rand pick a variable for replacement\\n\";\n+            }\n+          }\n+        }\n+      registerInteger(Inst);\n+    }\n+    return modified;\n+  }\n+\n+and here is the code full code (with the random prime generation):\n+\n+.. code:: C++\n+\n+    namespace {\n+      using prime_type = uint32_t;\n+\n+    static const prime_type Prime_array[] = {\n+         2 ,    3 ,    5 ,    7,     11,     13,     17,     19,     23,     29,\n+         31,    37,    41,    43,    47,     53,     59,     61,     67,     71,\n+         73,    79,    83,    89,    97,    101,    103,    107,    109,    113,\n+        127,   131,   137,   139,   149,    151,    157,    163,    167,    173,\n+        179,   181,   191,   193,   197,    199,    211,    223,    227,    229,\n+        233,   239,   241,   251,   257,    263,    269,    271,    277,    281,\n+        283,   293,   307,   311,   313,    317,    331,    337,    347,    349,\n+        353,   359,   367,   373,   379,    383,    389,    397,    401,    409,\n+        419,   421,   431,   433,   439,    443,    449,    457,    461,    463,\n+        467,   479,   487,   491,   499,    503,    509,    521,    523,    541,\n+        547,   557,   563,   569,   571,    577,    587,    593,    599,    601,\n+        607,   613,   617,   619,   631,    641,    643,    647,    653,    659,\n+        661,   673,   677,   683,   691,    701,    709,    719,    727,    733,\n+        739,   743,   751,   757,   761,    769,    773,    787,    797,    809,\n+        811,   821,   823,   827,   829,    839,    853,    857,    859,    863,\n+        877,   881,   883,   887,   907,    911,    919,    929,    937,    941,\n+        947,   953,   967,   971,   977,    983,    991,    997};\n+\n+    class MyPass : public BasicBlockPass {\n+      std::vector<Value *> IntegerVect;\n+      std::default_random_engine Generator;\n+\n+    public:\n+\n+      static char ID;\n+\n+      MyPass() : BasicBlockPass(ID) {}\n+\n+      virtual bool runOnBasicBlock(BasicBlock &BB) override {\n+        IntegerVect.clear();\n+        bool modified = false;\n+\n+        // Not iterating from the beginning to avoid obfuscation of Phi instructions\n+        // parameters\n+        for (typename BasicBlock::iterator I = BB.getFirstInsertionPt(),\n+                                           end = BB.end();\n+             I != end; ++I) {\n+          Instruction &Inst = *I;\n+            for (size_t i{0}; i < Inst.getNumOperands(); ++i) {\n+              if (Constant *C = isValidCandidateOperand(Inst.getOperand(i))) {\n+                if (Value *New_val = replaceZero(Inst, C)) {\n+                  Inst.setOperand(i, New_val);\n+                  modified = true;\n+                } else {\n+                  errs() << \"ObfuscateZero: could not rand pick a variable for replacement\\n\";\n+                }\n+              }\n+            }\n+          registerInteger(Inst);\n+        }\n+\n+        return modified;\n+      }\n+\n+    private:\n+\n+      Constant *isValidCandidateOperand(Value *V) {\n+        if (Constant *C = dyn_cast<Constant>(V)) {\n+          // Checking constant eligibility\n+          if (isa<PointerType>(C->getType())) {\n+            // dbgs() << \"Ignoring NULL pointers\\n\";\n+            return nullptr;\n+          } else if (C->getType()->isFloatingPointTy()) {\n+            // dbgs() << \"Ignoring Floats 0\\n\";\n+            return nullptr;\n+          } else if (C->isNullValue()) {\n+            return C;\n+          } else {\n+            return nullptr;\n+          }\n+        } else {\n+          return nullptr;\n+        }\n+      }\n+\n+      void registerInteger(Value &V) {\n+        if (V.getType()->isIntegerTy())\n+          IntegerVect.emplace_back(&V);\n+      }\n+\n+      // Return a random prime number not equal to DifferentFrom\n+      // If an error occurs returns 0\n+      prime_type getPrime(prime_type DifferentFrom = 0) {\n+          static std::uniform_int_distribution<prime_type> Rand(0, sizeof(Prime_array) / sizeof(prime_type));\n+          size_t MaxLoop = 10;\n+          prime_type Prime;\n+\n+          do {\n+                Prime = Prime_array[Rand(Generator)];\n+          } while(Prime == DifferentFrom && --MaxLoop);\n+\n+          if(!MaxLoop) {\n+              return 0;\n+          }\n+\n+          return Prime;\n+      }\n+\n+      Value *replaceZero(Instruction &Inst, Value *VReplace) {\n+        // Replacing 0 by:\n+        // prime1 * ((x | any1)**2) != prime2 * ((y | any2)**2)\n+        // with prime1 != prime2 and any1 != 0 and any2 != 0\n+        prime_type p1 = getPrime(),\n+                   p2 = getPrime(p1);\n+\n+        if(p2 == 0 || p1 == 0)\n+            return nullptr;\n+\n+        Type *ReplacedType = VReplace->getType(),\n+             *IntermediaryType = IntegerType::get(Inst.getParent()->getContext(),\n+                                                  sizeof(prime_type) * 8);\n+\n+        if (IntegerVect.size() < 1) {\n+          return nullptr;\n+        }\n+\n+        std::uniform_int_distribution<size_t> Rand(0, IntegerVect.size() - 1);\n+        std::uniform_int_distribution<size_t> RandAny(1, 10);\n+\n+        size_t Index1 = Rand(Generator), Index2 = Rand(Generator);\n+\n+        // Masking Any1 and Any2 to avoid overflow in the obsfuscation\n+        Constant *any1 = ConstantInt::get(IntermediaryType, 1 + RandAny(Generator)),\n+                 *any2 = ConstantInt::get(IntermediaryType, 1 + RandAny(Generator)),\n+                 *prime1 = ConstantInt::get(IntermediaryType, p1),\n+                 *prime2 = ConstantInt::get(IntermediaryType, p2),\n+                 // Bitmasks to prevent overflow\n+            *OverflowMaskLHS = ConstantInt::get(IntermediaryType, 0x00000007),\n+                 *OverflowMaskRHS = ConstantInt::get(IntermediaryType, 0x00000007);\n+\n+        IRBuilder<> Builder(&Inst);\n+\n+        // lhs\n+        // To avoid overflow\n+        Value *LhsCast =\n+            Builder.CreateZExtOrTrunc(IntegerVect.at(Index1), IntermediaryType);\n+        registerInteger(*LhsCast);\n+        Value *LhsAnd = Builder.CreateAnd(LhsCast, OverflowMaskLHS);\n+        registerInteger(*LhsAnd);\n+        Value *LhsOr = Builder.CreateOr(LhsAnd, any1);\n+        registerInteger(*LhsOr);\n+        Value *LhsSquare = Builder.CreateMul(LhsOr, LhsOr);\n+        registerInteger(*LhsSquare);\n+        Value *LhsTot = Builder.CreateMul(LhsSquare, prime1);\n+        registerInteger(*LhsTot);\n+\n+        // rhs\n+        Value *RhsCast =\n+            Builder.CreateZExtOrTrunc(IntegerVect.at(Index2), IntermediaryType);\n+        registerInteger(*RhsCast);\n+        Value *RhsAnd = Builder.CreateAnd(RhsCast, OverflowMaskRHS);\n+        registerInteger(*RhsAnd);\n+        Value *RhsOr = Builder.CreateOr(RhsAnd, any2);\n+        registerInteger(*RhsOr);\n+        Value *RhsSquare = Builder.CreateMul(RhsOr, RhsOr);\n+        registerInteger(*RhsSquare);\n+        Value *RhsTot = Builder.CreateMul(RhsSquare, prime2);\n+        registerInteger(*RhsTot);\n+\n+        // comp\n+        Value *comp =\n+            Builder.CreateICmp(CmpInst::Predicate::ICMP_EQ, LhsTot, RhsTot);\n+        registerInteger(*comp);\n+        Value *castComp = Builder.CreateZExt(comp, ReplacedType);\n+        registerInteger(*castComp);\n+\n+        return castComp;\n+      }\n+    };\n+    }\n+\n+DOOOOOOOOOOOOOOOOOOOOONE!\n+\n+Let's try this awesome pass, if we use it on the last version of our test code we get:\n+\n+.. code:: llvm\n+\n+    ; Function Attrs: nounwind uwtable\n+    define i32 @main() #0 {\n+      %1 = alloca i32, align 4\n+      %a = alloca i32, align 4\n+      store i32 0, i32* %1\n+      store i32 2, i32* %a, align 4\n+      %2 = call i32 @puts(i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0))\n+      %3 = load i32* %a, align 4\n+      %4 = mul nsw i32 %3, 3\n+      store i32 %4, i32* %a, align 4\n+      %5 = and i32 %3, 7\n+      %6 = or i32 %5, 2\n+      %7 = mul i32 %6, %6\n+      %8 = mul i32 %7, 719\n+      %9 = and i32 %2, 7\n+      %10 = or i32 %9, 8\n+      %11 = mul i32 %10, %10\n+      %12 = mul i32 %11, 397\n+      %13 = icmp eq i32 %8, %12\n+      %14 = zext i1 %13 to i32\n+      ret i32 %14\n+    }\n+\n+Look at the assignments %5 to %14, looks familiar? We have successfully obfuscated the ``return 0`` instruction with the expression we gave at the beginning.\n+\n+But there are a few important things left to read, so stay tunned!\n+\n+\n+You didn' think it would be that easy?\n+++++++++++++++++++++++++++++++++++++++\n+\n+The optimizer is your enemy\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+So far we have not tried to optimize our code.\n+But the compiler can optimize away some of your obfuscations and turn the code back to its original form.\n+Our obfuscation depends on some rather complex arithmetic properties so we are safe but you should keep in mind that the compiler might be working against you.\n+\n+Even though our arithmetic is optimization-proof the rest of the code is not. The optimizer can still modify your code and delete all the candidate variables for x and y. If you want to see this effect, comment out the ``puts`` call in our test code and add the -O3 flag to your compilation command.\n+\n+You should get this:\n+\n+.. code:: llvm\n+\n+    ; Function Attrs: nounwind readnone uwtable\n+    define i32 @main() #0 {\n+      ret i32 0\n+    }\n+\n+In this case the compiler has optimized out ``a`` which was the only integer available for the obfuscation.\n+This explains why the obfuscation aborted.\n+\n+Even if it is frustrating it is not a real problem, since the compiler won't delete all the potential integer in a real code.\n+However this is very annoying when writing tests.\n+The easiest work-around is to declare ``volatile`` the variables you don't want to be optimized out.\n+\n+You might think that not using the optimizer is a good solution but:\n+    * If your obfuscation can't resist an optimizer, it won't resist reverse engineers.\n+    * Obfuscation often makes your program run slower, take more memory, ... So optimizing your obfuscated code might help mitigate these drawbacks.\n+    * Optimization can introduce some randomness in your obfuscations which would make your obfuscation patterns harder to recognize.\n+\n+\n+Final modification\n+~~~~~~~~~~~~~~~~~~\n+\n+Now let's go back to our pass code for the last time.\n+So far we have supposed that we could replace *any* integer operand of *any* instruction.\n+Well, this is not actually true. Let's study the following code:\n+\n+.. code:: C\n+\n+    struct s {\n+        char a;\n+        int b;\n+    };\n+\n+    int main() {\n+        struct s s1;\n+        int a = 3;\n+\n+        s1.a = a;\n+\n+        return 0;\n+    }\n+\n+In LLVM bytecode access to structure members turns into the ``GetElementPointer`` instruction. It looks like this:\n+\n+.. code:: llvm\n+\n+    %4 = getelementptr inbounds %struct.s* %s1, i32 0, i32 0\n+\n+As you can there are to integer operands at the end. The first one is used when going through an array, so in our case it will always be 0.\n+The second one is the index of structure member we are accessing. If you access ``s.a`` it will be 0 and it will be 1 for ``s.b``.\n+\n+The array index can be a literal, or a variable, this is why we can write ``array[i]``.\n+So our obfuscation can safely replace this operand by a variable if it was a literal 0.\n+**But** the tricky thing is that the second index *has* to be a literal, it can not be a variable.\n+But our obfuscation is going to replace this literal by a new variable if it is equal to zero.\n+\n+I'm sure you want to know what happens when our pass breaks LLVM laws (clue: nothing to do with the FBI).\n+Well compile the above code with your pass and no optimizations and see for yourself.\n+Don't generate the LLVM bytecode, generate the binary (i.e remove the ``-S -emit-llvm`` options).\n+You should get a segfault... Not ideal, our pass makes compilation crash...\n+\n+To solve this we just have to filter the type of instruction we are obfuscating.\n+We need to add a new function and add a new condition in our main loop:\n+\n+.. code:: C++\n+\n+  virtual bool runOnBasicBlock(BasicBlock &BB) override {\n+    IntegerVect.clear();\n+    bool modified = false;\n+\n+    // Not iterating from the beginning to avoid obfuscation of Phi instructions\n+    // parameters\n+    for (typename BasicBlock::iterator I = BB.getFirstInsertionPt(),\n+                                       end = BB.end();\n+         I != end; ++I) {\n+      Instruction &Inst = *I;\n+      if (isValidCandidateInstruction(Inst)) {\n+        for (size_t i{0}; i < Inst.getNumOperands(); ++i) {\n+          if (Constant *C = isValidCandidateOperand(Inst.getOperand(i))) {\n+            if (Value *New_val = replaceZero(Inst, C)) {\n+              Inst.setOperand(i, New_val);\n+              modified = true;\n+            } else {\n+              //dbgs() << \"ObfuscateZero: could not rand pick a variable for replacement\\n\";\n+            }\n+          }\n+        }\n+      }\n+      registerInteger(Inst);\n+    }\n+\n+\n+  bool isValidCandidateInstruction(Instruction &Inst) {\n+    if (isa<GetElementPtrInst>(&Inst)) {\n+      // dbgs() << \"Ignoring GEP\\n\";\n+      return false;\n+    } else if (isa<SwitchInst>(&Inst)) {\n+      // dbgs() << \"Ignoring Switch\\n\";\n+      return false;\n+    } else if (isa<CallInst>(&Inst)) {\n+      // dbgs() << \"Ignoring Calls\\n\";\n+      return false;\n+    } else {\n+      return true;\n+    }\n+  }\n+\n+Pretty easy, no? Well the hard part is that this kind of problems is almost impossible to anticipate unless you know all the LLVM instructions.\n+The only solution to find this id to run your passes on big projects, see where it crashes and find out why.\n+\n+Your code should now be the same as the ObfuscateZero pass.\n+And since I don't want to dump all the code on this page (again) from now on we are going to use the ObfuscateZero pass for our tests.\n+\n+Tests, tests and more tests\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+I hope this last part made you understand that validation is crutial before using your obfuscations in prod.\n+For ObfuscateZero we used the ``llvm-lit`` testing tool, shipped with LLVM.\n+This tool runs the tests you specify with a particular syntax. Take a look in the files in the ``$PASSDIR/tests/ObfuscateZero`` folder to learn how to use it.\n+\n+For ObufuscateZero we have two types of tests:\n+    * Simple tests checking if the pass actually does what we want and doesn't crash in some tricky cases (GEP :p)\n+    * The validation scripts (*.sh files). Those files download the sources from openssl and zlib, compile them with our pass and run their validation suite. If the project compiles without error *and* passes the validation suite, we can suppose that our pass doesn't introduce bugs.\n+\n+If you want to run the tests you first need to install `pip <https://pypi.python.org/pypi/pip>`_ (python-pip). Then use it to install lit:\n+\n+.. code:: bash\n+\n+    >$ pip install lit\n+\n+Then go to ``$PASSDIR/build`` and run :\n+.. code:: bash\n+\n+    >$ cmake -DLLVM_ROOT=path/to/your/llvm/build ..\n+    >$ make check\n+\n+This will run the ``ObfuscateZero`` tests, which you can modify to test your pass. But it's going to take some time.\n+To validate ``ObfuscateZero`` we also compiled a C++ code since some constructs are not present when compiling from C.\n+However the test file has not been shipped in the git.\n+\n+Bye Bye\n+=======\n+\n+This tutorial was just an introduction to writing LLVM passes and using them for obfuscation.\n+There are many more funny things to do to make your code very annoying for reverse engineers.\n+I hope this will help you get started.","path":"doc/llvm_obfuscation_tutorial.rst","position":968,"original_position":968,"commit_id":"00a81cc0dd0ad84d7f6f13ae27ee4a742fe90a3e","original_commit_id":"00a81cc0dd0ad84d7f6f13ae27ee4a742fe90a3e","user":{"login":"serge-sans-paille","id":863807,"avatar_url":"https://avatars.githubusercontent.com/u/863807?v=3","gravatar_id":"","url":"https://api.github.com/users/serge-sans-paille","html_url":"https://github.com/serge-sans-paille","followers_url":"https://api.github.com/users/serge-sans-paille/followers","following_url":"https://api.github.com/users/serge-sans-paille/following{/other_user}","gists_url":"https://api.github.com/users/serge-sans-paille/gists{/gist_id}","starred_url":"https://api.github.com/users/serge-sans-paille/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/serge-sans-paille/subscriptions","organizations_url":"https://api.github.com/users/serge-sans-paille/orgs","repos_url":"https://api.github.com/users/serge-sans-paille/repos","events_url":"https://api.github.com/users/serge-sans-paille/events{/privacy}","received_events_url":"https://api.github.com/users/serge-sans-paille/received_events","type":"User","site_admin":false},"body":" But rember, if you choose the quick and easy path as Vader did - you will become an agent of evil. ","created_at":"2015-01-29T14:18:15Z","updated_at":"2015-01-29T14:18:15Z","html_url":"https://github.com/quarkslab/llvm-passes/pull/3#discussion_r23769643","pull_request_url":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/3","_links":{"self":{"href":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/comments/23769643"},"html":{"href":"https://github.com/quarkslab/llvm-passes/pull/3#discussion_r23769643"},"pull_request":{"href":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/3"}}},"pull_request":{"url":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/3","id":28279129,"html_url":"https://github.com/quarkslab/llvm-passes/pull/3","diff_url":"https://github.com/quarkslab/llvm-passes/pull/3.diff","patch_url":"https://github.com/quarkslab/llvm-passes/pull/3.patch","issue_url":"https://api.github.com/repos/quarkslab/llvm-passes/issues/3","number":3,"state":"open","locked":false,"title":"Adding LLVM obuscation tutorial","user":{"login":"artas360","id":1293130,"avatar_url":"https://avatars.githubusercontent.com/u/1293130?v=3","gravatar_id":"","url":"https://api.github.com/users/artas360","html_url":"https://github.com/artas360","followers_url":"https://api.github.com/users/artas360/followers","following_url":"https://api.github.com/users/artas360/following{/other_user}","gists_url":"https://api.github.com/users/artas360/gists{/gist_id}","starred_url":"https://api.github.com/users/artas360/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artas360/subscriptions","organizations_url":"https://api.github.com/users/artas360/orgs","repos_url":"https://api.github.com/users/artas360/repos","events_url":"https://api.github.com/users/artas360/events{/privacy}","received_events_url":"https://api.github.com/users/artas360/received_events","type":"User","site_admin":false},"body":"Adding tutorial & Modifying an outdated comment in ObfuscateZero.cpp","created_at":"2015-01-29T13:41:31Z","updated_at":"2015-01-29T14:18:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f629ad05563d629f25803a89ad28e21589bb47e1","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/3/commits","review_comments_url":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/3/comments","review_comment_url":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/comments/{number}","comments_url":"https://api.github.com/repos/quarkslab/llvm-passes/issues/3/comments","statuses_url":"https://api.github.com/repos/quarkslab/llvm-passes/statuses/00a81cc0dd0ad84d7f6f13ae27ee4a742fe90a3e","head":{"label":"artas360:master","ref":"master","sha":"00a81cc0dd0ad84d7f6f13ae27ee4a742fe90a3e","user":{"login":"artas360","id":1293130,"avatar_url":"https://avatars.githubusercontent.com/u/1293130?v=3","gravatar_id":"","url":"https://api.github.com/users/artas360","html_url":"https://github.com/artas360","followers_url":"https://api.github.com/users/artas360/followers","following_url":"https://api.github.com/users/artas360/following{/other_user}","gists_url":"https://api.github.com/users/artas360/gists{/gist_id}","starred_url":"https://api.github.com/users/artas360/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artas360/subscriptions","organizations_url":"https://api.github.com/users/artas360/orgs","repos_url":"https://api.github.com/users/artas360/repos","events_url":"https://api.github.com/users/artas360/events{/privacy}","received_events_url":"https://api.github.com/users/artas360/received_events","type":"User","site_admin":false},"repo":{"id":29475401,"name":"llvm-passes","full_name":"artas360/llvm-passes","owner":{"login":"artas360","id":1293130,"avatar_url":"https://avatars.githubusercontent.com/u/1293130?v=3","gravatar_id":"","url":"https://api.github.com/users/artas360","html_url":"https://github.com/artas360","followers_url":"https://api.github.com/users/artas360/followers","following_url":"https://api.github.com/users/artas360/following{/other_user}","gists_url":"https://api.github.com/users/artas360/gists{/gist_id}","starred_url":"https://api.github.com/users/artas360/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artas360/subscriptions","organizations_url":"https://api.github.com/users/artas360/orgs","repos_url":"https://api.github.com/users/artas360/repos","events_url":"https://api.github.com/users/artas360/events{/privacy}","received_events_url":"https://api.github.com/users/artas360/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/artas360/llvm-passes","description":"Collection of various llvm passes","fork":true,"url":"https://api.github.com/repos/artas360/llvm-passes","forks_url":"https://api.github.com/repos/artas360/llvm-passes/forks","keys_url":"https://api.github.com/repos/artas360/llvm-passes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/artas360/llvm-passes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/artas360/llvm-passes/teams","hooks_url":"https://api.github.com/repos/artas360/llvm-passes/hooks","issue_events_url":"https://api.github.com/repos/artas360/llvm-passes/issues/events{/number}","events_url":"https://api.github.com/repos/artas360/llvm-passes/events","assignees_url":"https://api.github.com/repos/artas360/llvm-passes/assignees{/user}","branches_url":"https://api.github.com/repos/artas360/llvm-passes/branches{/branch}","tags_url":"https://api.github.com/repos/artas360/llvm-passes/tags","blobs_url":"https://api.github.com/repos/artas360/llvm-passes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/artas360/llvm-passes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/artas360/llvm-passes/git/refs{/sha}","trees_url":"https://api.github.com/repos/artas360/llvm-passes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/artas360/llvm-passes/statuses/{sha}","languages_url":"https://api.github.com/repos/artas360/llvm-passes/languages","stargazers_url":"https://api.github.com/repos/artas360/llvm-passes/stargazers","contributors_url":"https://api.github.com/repos/artas360/llvm-passes/contributors","subscribers_url":"https://api.github.com/repos/artas360/llvm-passes/subscribers","subscription_url":"https://api.github.com/repos/artas360/llvm-passes/subscription","commits_url":"https://api.github.com/repos/artas360/llvm-passes/commits{/sha}","git_commits_url":"https://api.github.com/repos/artas360/llvm-passes/git/commits{/sha}","comments_url":"https://api.github.com/repos/artas360/llvm-passes/comments{/number}","issue_comment_url":"https://api.github.com/repos/artas360/llvm-passes/issues/comments/{number}","contents_url":"https://api.github.com/repos/artas360/llvm-passes/contents/{+path}","compare_url":"https://api.github.com/repos/artas360/llvm-passes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/artas360/llvm-passes/merges","archive_url":"https://api.github.com/repos/artas360/llvm-passes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/artas360/llvm-passes/downloads","issues_url":"https://api.github.com/repos/artas360/llvm-passes/issues{/number}","pulls_url":"https://api.github.com/repos/artas360/llvm-passes/pulls{/number}","milestones_url":"https://api.github.com/repos/artas360/llvm-passes/milestones{/number}","notifications_url":"https://api.github.com/repos/artas360/llvm-passes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/artas360/llvm-passes/labels{/name}","releases_url":"https://api.github.com/repos/artas360/llvm-passes/releases{/id}","created_at":"2015-01-19T14:47:09Z","updated_at":"2015-01-29T13:40:14Z","pushed_at":"2015-01-29T13:40:14Z","git_url":"git://github.com/artas360/llvm-passes.git","ssh_url":"git@github.com:artas360/llvm-passes.git","clone_url":"https://github.com/artas360/llvm-passes.git","svn_url":"https://github.com/artas360/llvm-passes","homepage":null,"size":191,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"quarkslab:master","ref":"master","sha":"1b0b9ea145cf27a038495dc7cb1cdc97bbf6e1bf","user":{"login":"quarkslab","id":3357711,"avatar_url":"https://avatars.githubusercontent.com/u/3357711?v=3","gravatar_id":"","url":"https://api.github.com/users/quarkslab","html_url":"https://github.com/quarkslab","followers_url":"https://api.github.com/users/quarkslab/followers","following_url":"https://api.github.com/users/quarkslab/following{/other_user}","gists_url":"https://api.github.com/users/quarkslab/gists{/gist_id}","starred_url":"https://api.github.com/users/quarkslab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quarkslab/subscriptions","organizations_url":"https://api.github.com/users/quarkslab/orgs","repos_url":"https://api.github.com/users/quarkslab/repos","events_url":"https://api.github.com/users/quarkslab/events{/privacy}","received_events_url":"https://api.github.com/users/quarkslab/received_events","type":"Organization","site_admin":false},"repo":{"id":29474475,"name":"llvm-passes","full_name":"quarkslab/llvm-passes","owner":{"login":"quarkslab","id":3357711,"avatar_url":"https://avatars.githubusercontent.com/u/3357711?v=3","gravatar_id":"","url":"https://api.github.com/users/quarkslab","html_url":"https://github.com/quarkslab","followers_url":"https://api.github.com/users/quarkslab/followers","following_url":"https://api.github.com/users/quarkslab/following{/other_user}","gists_url":"https://api.github.com/users/quarkslab/gists{/gist_id}","starred_url":"https://api.github.com/users/quarkslab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quarkslab/subscriptions","organizations_url":"https://api.github.com/users/quarkslab/orgs","repos_url":"https://api.github.com/users/quarkslab/repos","events_url":"https://api.github.com/users/quarkslab/events{/privacy}","received_events_url":"https://api.github.com/users/quarkslab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/quarkslab/llvm-passes","description":"Collection of various llvm passes","fork":false,"url":"https://api.github.com/repos/quarkslab/llvm-passes","forks_url":"https://api.github.com/repos/quarkslab/llvm-passes/forks","keys_url":"https://api.github.com/repos/quarkslab/llvm-passes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/quarkslab/llvm-passes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/quarkslab/llvm-passes/teams","hooks_url":"https://api.github.com/repos/quarkslab/llvm-passes/hooks","issue_events_url":"https://api.github.com/repos/quarkslab/llvm-passes/issues/events{/number}","events_url":"https://api.github.com/repos/quarkslab/llvm-passes/events","assignees_url":"https://api.github.com/repos/quarkslab/llvm-passes/assignees{/user}","branches_url":"https://api.github.com/repos/quarkslab/llvm-passes/branches{/branch}","tags_url":"https://api.github.com/repos/quarkslab/llvm-passes/tags","blobs_url":"https://api.github.com/repos/quarkslab/llvm-passes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/quarkslab/llvm-passes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/quarkslab/llvm-passes/git/refs{/sha}","trees_url":"https://api.github.com/repos/quarkslab/llvm-passes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/quarkslab/llvm-passes/statuses/{sha}","languages_url":"https://api.github.com/repos/quarkslab/llvm-passes/languages","stargazers_url":"https://api.github.com/repos/quarkslab/llvm-passes/stargazers","contributors_url":"https://api.github.com/repos/quarkslab/llvm-passes/contributors","subscribers_url":"https://api.github.com/repos/quarkslab/llvm-passes/subscribers","subscription_url":"https://api.github.com/repos/quarkslab/llvm-passes/subscription","commits_url":"https://api.github.com/repos/quarkslab/llvm-passes/commits{/sha}","git_commits_url":"https://api.github.com/repos/quarkslab/llvm-passes/git/commits{/sha}","comments_url":"https://api.github.com/repos/quarkslab/llvm-passes/comments{/number}","issue_comment_url":"https://api.github.com/repos/quarkslab/llvm-passes/issues/comments/{number}","contents_url":"https://api.github.com/repos/quarkslab/llvm-passes/contents/{+path}","compare_url":"https://api.github.com/repos/quarkslab/llvm-passes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/quarkslab/llvm-passes/merges","archive_url":"https://api.github.com/repos/quarkslab/llvm-passes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/quarkslab/llvm-passes/downloads","issues_url":"https://api.github.com/repos/quarkslab/llvm-passes/issues{/number}","pulls_url":"https://api.github.com/repos/quarkslab/llvm-passes/pulls{/number}","milestones_url":"https://api.github.com/repos/quarkslab/llvm-passes/milestones{/number}","notifications_url":"https://api.github.com/repos/quarkslab/llvm-passes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/quarkslab/llvm-passes/labels{/name}","releases_url":"https://api.github.com/repos/quarkslab/llvm-passes/releases{/id}","created_at":"2015-01-19T14:26:01Z","updated_at":"2015-01-23T20:17:00Z","pushed_at":"2015-01-23T20:17:00Z","git_url":"git://github.com/quarkslab/llvm-passes.git","ssh_url":"git@github.com:quarkslab/llvm-passes.git","clone_url":"https://github.com/quarkslab/llvm-passes.git","svn_url":"https://github.com/quarkslab/llvm-passes","homepage":null,"size":147,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":1,"forks":3,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/3"},"html":{"href":"https://github.com/quarkslab/llvm-passes/pull/3"},"issue":{"href":"https://api.github.com/repos/quarkslab/llvm-passes/issues/3"},"comments":{"href":"https://api.github.com/repos/quarkslab/llvm-passes/issues/3/comments"},"review_comments":{"href":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/3/comments"},"review_comment":{"href":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/quarkslab/llvm-passes/pulls/3/commits"},"statuses":{"href":"https://api.github.com/repos/quarkslab/llvm-passes/statuses/00a81cc0dd0ad84d7f6f13ae27ee4a742fe90a3e"}}}}