| Index: syzygy/experimental/protect/protect_lib/integrity_check_transform.cc
 | 
| diff --git a/syzygy/experimental/protect/protect_lib/integrity_check_transform.cc b/syzygy/experimental/protect/protect_lib/integrity_check_transform.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..a96a1ebca55db028d28d75322fe74283cec2c925
 | 
| --- /dev/null
 | 
| +++ b/syzygy/experimental/protect/protect_lib/integrity_check_transform.cc
 | 
| @@ -0,0 +1,2136 @@
 | 
| +// Copyright 2015 Google Inc. All Rights Reserved.
 | 
| +//
 | 
| +// Licensed under the Apache License, Version 2.0 (the "License");
 | 
| +// you may not use this file except in compliance with the License.
 | 
| +// You may obtain a copy of the License at
 | 
| +//
 | 
| +//     http://www.apache.org/licenses/LICENSE-2.0
 | 
| +//
 | 
| +// Unless required by applicable law or agreed to in writing, software
 | 
| +// distributed under the License is distributed on an "AS IS" BASIS,
 | 
| +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
| +// See the License for the specific language governing permissions and
 | 
| +// limitations under the License.
 | 
| +#include "syzygy/experimental/protect/protect_lib/integrity_check_transform.h"
 | 
| +#include <fstream>
 | 
| +#include <stack>
 | 
| +#include <algorithm>
 | 
| +#include <random>
 | 
| +#include "syzygy/assm/assembler.h"
 | 
| +#include "syzygy/assm/assembler_base.h"
 | 
| +#include "syzygy/block_graph/basic_block_assembler.h"
 | 
| +#include "syzygy/block_graph/basic_block_decomposer.h"
 | 
| +#include "syzygy/block_graph/basic_block_subgraph.h"
 | 
| +#include "syzygy/block_graph/block_builder.h"
 | 
| +#include "syzygy/block_graph/block_util.h"
 | 
| +#include "syzygy/optimize/transforms/subgraph_transform.h"
 | 
| +#include "syzygy/experimental/protect/protect_lib/code_randomizer.h"
 | 
| +#include "syzygy/experimental/protect/protect_lib/protect_utils.h"
 | 
| +#include <iostream>
 | 
| +//#define PRINT_BLOCK_NAMES
 | 
| +namespace protect {
 | 
| +
 | 
| +namespace {
 | 
| +
 | 
| +using block_graph::BasicBlockDecomposer;
 | 
| +using block_graph::BasicBlockSubGraph;
 | 
| +using block_graph::BlockBuilder;
 | 
| +using block_graph::BlockGraph;
 | 
| +using block_graph::BlockVector;
 | 
| +using block_graph::BasicBlock;
 | 
| +using block_graph::BasicCodeBlock;
 | 
| +using block_graph::Instruction;
 | 
| +using block_graph::BasicBlockReference;
 | 
| +
 | 
| +typedef BasicBlockSubGraph::BBCollection BBCollection;
 | 
| +typedef BasicBlock::Instructions Instructions;
 | 
| +typedef BlockGraph::Block::ReferrerSet ReferrerSet;
 | 
| +typedef std::list<BlockGraph::Block*> BlockOrdering;
 | 
| +
 | 
| + // Retrieves a unique identifier for a basic block.
 | 
| + // @param bb the basic block to be uniquely identifed.
 | 
| + // @param subgraph basic block subgraph in which the basic block resides.
 | 
| + // @return a unique ID for the basic block.
 | 
| +uint64_t GetBasicBlockId(const BasicBlock *bb,
 | 
| +                         const BasicBlockSubGraph *subgraph) {
 | 
| +  DCHECK(bb);
 | 
| +  DCHECK(subgraph);
 | 
| +
 | 
| +  auto original_block = subgraph->original_block();
 | 
| +  DCHECK(original_block);
 | 
| +
 | 
| +  return ((uint64_t)bb->offset() << 32) + original_block->id();
 | 
| +}
 | 
| +
 | 
| + // Retrieves the block where the _putwch_nolock function is declared.
 | 
| + // @param bragph block graph where to search of the function.
 | 
| + // @return the block where the function is declared.
 | 
| +block_graph::BlockGraph::Block* GetPutwchNolock(
 | 
| +    block_graph::BlockGraph* bgraph) {
 | 
| +  DCHECK(bgraph);
 | 
| +  block_graph::BlockGraph::Block *putwch_nolock = nullptr;
 | 
| +
 | 
| +  auto it = bgraph->blocks().begin();
 | 
| +  for (; it != bgraph->blocks().end(); ++it)
 | 
| +   if ((*it).second.name().compare("_putwch_nolock") == 0) {
 | 
| +    putwch_nolock = bgraph->GetBlockById((*it).second.id());
 | 
| +    break;
 | 
| +   }
 | 
| +  return putwch_nolock;
 | 
| +}
 | 
| +
 | 
| + // Adds assembly code for response function to a block graph.
 | 
| + // @param bgraph the block graph from where the response function is inserted.
 | 
| + // @return the block containing the newly inseted response function.
 | 
| +BlockGraph::Block* AddResponseFunction(BlockGraph* bgraph) {
 | 
| +  DCHECK(bgraph);
 | 
| +  //TODO:BlockGraph::Block *response_function = GetPutwchNolock(bgraph);
 | 
| +  BasicBlockSubGraph* subgraph = new BasicBlockSubGraph();
 | 
| +  BlockGraph::Section* code_section = bgraph->FindOrAddSection(".text",
 | 
| +   0x60000000);
 | 
| +  std::string bb_name = "response_bb1";
 | 
| +  // Create the thunk for standard "load/store" (received address in EDX).
 | 
| +  BasicBlockSubGraph::BlockDescription* block_desc =
 | 
| +   subgraph->AddBlockDescription(bb_name, code_section->name(),
 | 
| +   BlockGraph::CODE_BLOCK, code_section->id(),
 | 
| +   1, 0);
 | 
| +
 | 
| +  BasicCodeBlock* bb = subgraph->AddBasicCodeBlock(bb_name);
 | 
| +  block_desc->basic_block_order.push_back(bb);
 | 
| +
 | 
| +  BasicBlock::Instructions::iterator inst_iter = bb->instructions().begin();
 | 
| +  block_graph::BasicBlockAssembler assm(inst_iter,
 | 
| +   &bb->instructions());
 | 
| +
 | 
| +  assm.push(assm::eax); // eax contains the actual hash value
 | 
| +  // add size of instructions from hash function return up to response return
 | 
| +  assm.add(assm::ebx, block_graph::Immediate(0xe));
 | 
| +  assm.push(assm::ebx); // edx contains the address where to continue execution
 | 
| +  //TODO:assm.call(block_graph::Immediate(response_function, 0)); // print char
 | 
| +  assm.pop(assm::ebx); // edx gets changed by the previous call
 | 
| +  assm.mov(assm::ebx, block_graph::Immediate((uint32_t)0x0));
 | 
| +  assm.jmp(assm::ebx); // continue normal execution
 | 
| +
 | 
| +  // Condense into a block.
 | 
| +  block_graph::BlockBuilder block_builder(bgraph);
 | 
| +  if (!block_builder.Merge(subgraph))
 | 
| +   return nullptr;
 | 
| +
 | 
| +  return block_builder.new_blocks().rbegin()[0];
 | 
| +}
 | 
| +
 | 
| + // Adds assembly code for hash function in a block graph.
 | 
| + // @param bgraph the block graph where the hash function is inserted.
 | 
| + // @return the block containing the newly inserted hash function.
 | 
| +BlockGraph::Block* AddHashFunction(BlockGraph* bgraph) {
 | 
| +  DCHECK(bgraph);
 | 
| +  BlockGraph::Section* code_section = bgraph->FindOrAddSection(".text",
 | 
| +                                                               0x60000000);
 | 
| +  std::string bb_name = "hash_add_bb1";
 | 
| +  BasicBlockSubGraph* subgraph = new BasicBlockSubGraph();
 | 
| +  // Create the thunk for standard "load/store" (received address in EDX).
 | 
| +  BasicBlockSubGraph::BlockDescription* block_desc =
 | 
| +   subgraph->AddBlockDescription(bb_name, code_section->name(),
 | 
| +   BlockGraph::CODE_BLOCK, code_section->id(),
 | 
| +   1, 0);
 | 
| +
 | 
| +  BasicCodeBlock* bb = subgraph->AddBasicCodeBlock(bb_name);
 | 
| +  block_desc->basic_block_order.push_back(bb);
 | 
| +
 | 
| +  auto inst_iter = bb->instructions().begin();
 | 
| +  block_graph::BasicBlockAssembler assm(inst_iter,
 | 
| +   &bb->instructions());
 | 
| +
 | 
| +  // Create following BB that contains outer loop head.
 | 
| +  bb_name = "hash_add_bb2";
 | 
| +  block_desc = subgraph->AddBlockDescription(bb_name, code_section->name(),
 | 
| +   BlockGraph::CODE_BLOCK,
 | 
| +   code_section->id(), 1, 0);
 | 
| +
 | 
| +  bb = subgraph->AddBasicCodeBlock(bb_name);
 | 
| +  block_desc->basic_block_order.push_front(bb);
 | 
| +
 | 
| +  // Function prolog.
 | 
| +  assm.push(assm::ebp);
 | 
| +  assm.mov(assm::ebp, assm::esp);
 | 
| +
 | 
| +  assm.pop(assm::eax); // pop ebp
 | 
| +  assm.pop(assm::ebx); // pop return addres
 | 
| +  assm.xor(assm::eax, assm::eax); // set eax to 0
 | 
| +  // Get the base address of code section of this PE/DLL.
 | 
| +  auto block_it = bgraph->blocks().begin();
 | 
| +  for (; block_it != bgraph->blocks().end(); ++block_it) {
 | 
| +    BlockGraph::BlockType type = block_it->second.type();
 | 
| +    if (type == BlockGraph::BlockType::DATA_BLOCK)
 | 
| +      break;
 | 
| +  }
 | 
| +  BlockGraph::Block* first_block = bgraph->GetBlockById(block_it->second.id());
 | 
| +  // Get the start address of this basic block.
 | 
| +  assm.mov(assm::ebx, block_graph::Immediate(first_block, 0));
 | 
| +  // Compute hash of address.
 | 
| +  assm.add(assm::al, assm::bl);
 | 
| +  assm.add(assm::al, assm::bh);
 | 
| +  assm.shr(assm::ebx, block_graph::Immediate(0x10));
 | 
| +  assm.add(assm::al, assm::bl);
 | 
| +  assm.add(assm::al, assm::bh);
 | 
| +  // Save this hash of the address on the stack.
 | 
| +  assm.pop(assm::ebx); // This is the designeated slot for the hash of address.
 | 
| +  assm.pop(assm::ebx); // This is the designeated slot for the accumulator.
 | 
| +  assm.xor(assm::ebx, assm::ebx); // Set accumulator to 0.
 | 
| +  assm.push(assm::ebx); // Save accumulator.
 | 
| +  assm.push(assm::eax); // Save hash of address.
 | 
| +
 | 
| +  assm.j(assm::ConditionCode::kEqual,
 | 
| +   block_graph::Immediate(bb));
 | 
| +
 | 
| +  inst_iter = bb->instructions().begin();
 | 
| +  block_graph::BasicBlockAssembler assm2(inst_iter,
 | 
| +   &bb->instructions());
 | 
| +
 | 
| +  // Begin outer loop over all checkees passed to the hash function.
 | 
| +  assm2.pop(assm::ebx); // Hash of address.
 | 
| +  assm2.pop(assm::eax); // Accumulator for hash.
 | 
| +  assm2.pop(assm::edx); // Get address of bb to hash.
 | 
| +  assm2.sub(assm::ecx, block_graph::Immediate(1));
 | 
| +  assm2.xchg(assm::ecx,
 | 
| +   assm::OperandBase<block_graph::UntypedReference>(assm::esp));
 | 
| +  assm2.push(assm::eax); // Accumulator for hash.
 | 
| +  assm2.push(assm::ebx); // Hash of address.
 | 
| +  assm2.sub(assm::eax, assm::eax); // Set eax to zero.
 | 
| +
 | 
| +  // Create following BB that contains inner loop over bytes of checkee.
 | 
| +  bb_name = "hash_add_bb3";
 | 
| +  block_desc = subgraph->AddBlockDescription(bb_name,
 | 
| +                                             code_section->name(),
 | 
| +                                             BlockGraph::CODE_BLOCK,
 | 
| +                                             code_section->id(), 1, 0);
 | 
| +
 | 
| +  BasicCodeBlock* bb2 = subgraph->AddBasicCodeBlock(bb_name);
 | 
| +  block_desc->basic_block_order.push_front(bb2);
 | 
| +
 | 
| +  assm2.jmp(block_graph::Immediate(bb2));
 | 
| +
 | 
| +  inst_iter = bb2->instructions().begin();
 | 
| +  block_graph::BasicBlockAssembler assm3(inst_iter,
 | 
| +   &bb2->instructions());
 | 
| +
 | 
| +  // Begin inner loop over instruction bytes of current checkee.
 | 
| +  assm3.mov(assm::ebx,
 | 
| +   assm::OperandBase<block_graph::UntypedReference>(assm::edx));
 | 
| +  assm3.add(assm::al, assm::bl);
 | 
| +  assm3.add(assm::edx, block_graph::Immediate(1));
 | 
| +  assm3.sub(assm::ecx, block_graph::Immediate(1));
 | 
| +  assm3.test(assm::ecx, assm::ecx);
 | 
| +  assm3.j(assm::ConditionCode::kNotEqual, block_graph::Immediate(bb2));
 | 
| +  // End inner loop.
 | 
| +
 | 
| +  // Subtract the hash of address from computed hash.
 | 
| +  assm3.pop(assm::ebx); // Hash of address.
 | 
| +  assm3.pop(assm::edx); // Accumulator for hash.
 | 
| +  assm3.pop(assm::ecx); // Ourter loop counter.
 | 
| +  assm3.xchg(assm::eax, // Load #checkees of checkee.
 | 
| +   assm::OperandBase<block_graph::UntypedReference>(assm::esp));
 | 
| +  assm3.imul(assm::ebx, assm::eax); // Multiply hash of address with #chekees
 | 
| +  assm3.and(assm::ebx, block_graph::Immediate(0xFF)); // Modulo 256.
 | 
| +  assm3.pop(assm::eax); // Get hash of the current checkee.
 | 
| +  assm3.sub(assm::al, assm::bl); // Cancel base addresses of checkees in hash.
 | 
| +  assm3.pop(assm::ebx); // Coeficient of current basic block.
 | 
| +  assm3.imul(assm::eax, assm::ebx); // Multiply hash with coeficient.
 | 
| +  assm3.and(assm::eax, block_graph::Immediate(0xFF)); // Modulo 256
 | 
| +  assm3.add(assm::dl, assm::al); // Accumulate hash.
 | 
| +  assm3.push(assm::edx); // Store accumulator for hash.
 | 
| +  // The hash of the address is on the stack at a distance of 4 stack slots.
 | 
| +  // Recover it because it was lost when ebx was multiplied by the #checkees of
 | 
| +  // this checkee.
 | 
| +  assm3.mov(assm::edx, block_graph::Operand(assm::esp,
 | 
| +   block_graph::Displacement((unsigned int)-0x10)));
 | 
| +  assm3.push(assm::edx); // Store hash of address.
 | 
| +  // Check outer loop boundary.
 | 
| +  assm3.test(assm::ecx, assm::ecx);
 | 
| +  assm3.j(assm::ConditionCode::kNotEqual, block_graph::Immediate(bb));
 | 
| +  // End outer loop.
 | 
| +
 | 
| +  assm3.pop(assm::eax); // Throw away hash of adddress.
 | 
| +  assm3.pop(assm::eax); // Load final hash value.
 | 
| +
 | 
| +  // Function epilog.
 | 
| +  assm3.mov(assm::esp, assm::ebp);
 | 
| +  assm3.pop(assm::ebp);
 | 
| +  // Jump over pivot byte.
 | 
| +  assm3.add(assm::OperandBase<block_graph::UntypedReference>(assm::esp),
 | 
| +            block_graph::Immediate(1));
 | 
| +  // Load return address of edx into ebx, to be used by response function.
 | 
| +  assm3.mov(assm::ebx,
 | 
| +            assm::OperandBase<block_graph::UntypedReference>(assm::esp));
 | 
| +  assm3.ret();
 | 
| +
 | 
| +  // Condense into a block.
 | 
| +  block_graph::BlockBuilder block_builder(bgraph);
 | 
| +  if (!block_builder.Merge(subgraph))
 | 
| +   return nullptr;
 | 
| +
 | 
| +  return block_builder.new_blocks().begin()[0];
 | 
| +}
 | 
| +
 | 
| +
 | 
| + // Adds assembly code for xor hash function
 | 
| + // @param bgraph - the block graph from where the subgraph was taken
 | 
| + // @param subgraph - the subgraph containing basic blocks we want to transform
 | 
| + // @return the block containing the hash function
 | 
| + // Adds assembly code for hash function
 | 
| + // @param bgraph - the block graph from where the subgraph was taken
 | 
| + // @param subgraph - the subgraph containing basic blocks we want to transform
 | 
| + // @return the block containing the hash function
 | 
| +BlockGraph::Block* AddXorHashFunction(BlockGraph* bgraph) {
 | 
| +  BlockGraph::Section* code_section = bgraph->FindOrAddSection(".text",
 | 
| +   0x60000000);
 | 
| +  std::string bb_name = "get_xeip";
 | 
| +  BasicBlockSubGraph* subgraph = new BasicBlockSubGraph();
 | 
| +  // Create the thunk for standard "load/store" (received address in EDX).
 | 
| +  BasicBlockSubGraph::BlockDescription* block_desc =
 | 
| +   subgraph->AddBlockDescription(bb_name, code_section->name(),
 | 
| +   BlockGraph::CODE_BLOCK, code_section->id(),
 | 
| +   1, 0);
 | 
| +
 | 
| +  BasicCodeBlock* bb = subgraph->AddBasicCodeBlock(bb_name);
 | 
| +  block_desc->basic_block_order.push_back(bb);
 | 
| +
 | 
| +  auto inst_iter = bb->instructions().begin();
 | 
| +  block_graph::BasicBlockAssembler assm(inst_iter, &bb->instructions());
 | 
| +
 | 
| +  // Create following BB that contains outer loop head
 | 
| +  bb_name = "get_xeip2";
 | 
| +  block_desc = subgraph->AddBlockDescription(bb_name, code_section->name(),
 | 
| +   BlockGraph::CODE_BLOCK,
 | 
| +   code_section->id(), 1, 0);
 | 
| +
 | 
| +  bb = subgraph->AddBasicCodeBlock(bb_name);
 | 
| +  block_desc->basic_block_order.push_front(bb);
 | 
| +
 | 
| +  // function prolog
 | 
| +  assm.push(assm::ebp);
 | 
| +  assm.mov(assm::ebp, assm::esp);
 | 
| +
 | 
| +  assm.pop(assm::eax); // pop ebp
 | 
| +  assm.pop(assm::eax); // pop return addres
 | 
| +  assm.j(assm::ConditionCode::kEqual,
 | 
| +   block_graph::Immediate(bb));
 | 
| +
 | 
| +  inst_iter = bb->instructions().begin();
 | 
| +  block_graph::BasicBlockAssembler assm2(inst_iter,
 | 
| +   &bb->instructions());
 | 
| +
 | 
| +  // begin outer loop
 | 
| +  assm2.pop(assm::eax); // accumulator for hash
 | 
| +
 | 
| +  assm2.pop(assm::edx); // get address of bb to hash
 | 
| +  assm2.sub(assm::ecx, block_graph::Immediate(1)); // decrement outer loop iter
 | 
| +  assm2.xchg(assm::ecx, // swap outer loop iter with inner loop iter
 | 
| +  assm::OperandBase<block_graph::UntypedReference>(assm::esp));
 | 
| +  assm2.push(assm::eax); // save accumulator for hash
 | 
| +  assm2.sub(assm::eax, assm::eax); // set eax to zero
 | 
| +
 | 
| +  // Create following BB that contains inner loop
 | 
| +  bb_name = "get_xeip3";
 | 
| +  block_desc = subgraph->AddBlockDescription(bb_name, code_section->name(),
 | 
| +                                             BlockGraph::CODE_BLOCK,
 | 
| +                                             code_section->id(), 1, 0);
 | 
| +
 | 
| +  BasicCodeBlock* bb2 = subgraph->AddBasicCodeBlock(bb_name);
 | 
| +  block_desc->basic_block_order.push_front(bb2);
 | 
| +
 | 
| +  assm2.jmp(block_graph::Immediate(bb2));
 | 
| +
 | 
| +  inst_iter = bb2->instructions().begin();
 | 
| +  block_graph::BasicBlockAssembler assm3(inst_iter,
 | 
| +   &bb2->instructions());
 | 
| +
 | 
| +  // begin inner loop
 | 
| +  assm3.mov(assm::ebx,
 | 
| +      assm::OperandBase<block_graph::UntypedReference>(assm::edx));
 | 
| +  assm3.xor(assm::al, assm::bl);
 | 
| +  assm3.add(assm::edx, block_graph::Immediate(1));
 | 
| +  assm3.sub(assm::ecx, block_graph::Immediate(1));
 | 
| +  assm3.test(assm::ecx, assm::ecx);
 | 
| +  assm3.j(assm::ConditionCode::kNotEqual, block_graph::Immediate(bb2));
 | 
| +  // end inner loop
 | 
| +
 | 
| +  assm3.pop(assm::ebx); // hash accumulator
 | 
| +  assm3.pop(assm::ecx); // ourter loop counter
 | 
| +  assm3.xchg(assm::ecx, // swap outer loop iter with inner loop iter
 | 
| +             assm::OperandBase<block_graph::UntypedReference>(assm::esp));
 | 
| +  assm3.push(assm::ebx); // save accumulator for hash
 | 
| +
 | 
| +  // Create following BB that contains 2nd inner loop
 | 
| +  bb_name = "get_xeip4";
 | 
| +  block_desc = subgraph->AddBlockDescription(bb_name, code_section->name(),
 | 
| +                                             BlockGraph::CODE_BLOCK,
 | 
| +                                             code_section->id(), 1, 0);
 | 
| +
 | 
| +  BasicCodeBlock* bb3 = subgraph->AddBasicCodeBlock(bb_name);
 | 
| +  block_desc->basic_block_order.push_front(bb3);
 | 
| +
 | 
| +  assm3.cmp(assm::ecx, block_graph::Immediate(0, assm::ValueSize::kSize32Bit));
 | 
| +  assm3.j(assm::ConditionCode::kNotEqual, block_graph::Immediate(bb3));
 | 
| +
 | 
| +  inst_iter = bb3->instructions().begin();
 | 
| +  block_graph::BasicBlockAssembler assm4(inst_iter,
 | 
| +                                         &bb3->instructions());
 | 
| +
 | 
| +  // begin 2nd inner loop
 | 
| +  assm4.mov(assm::ebx,
 | 
| +            assm::OperandBase<block_graph::UntypedReference>(assm::edx));
 | 
| +  assm4.add(assm::al, assm::bl);
 | 
| +  assm4.add(assm::edx, block_graph::Immediate(1));
 | 
| +  assm4.sub(assm::ecx, block_graph::Immediate(1));
 | 
| +  assm4.test(assm::ecx, assm::ecx);
 | 
| +  assm4.j(assm::ConditionCode::kNotEqual, block_graph::Immediate(bb3));
 | 
| +  assm4.mov(assm::ecx, block_graph::Immediate(bb));
 | 
| +  assm4.add(assm::ecx, block_graph::Immediate(0x34));
 | 
| +  assm4.jmp(assm::ecx);
 | 
| +  // end 2nd inner loop
 | 
| +
 | 
| +  assm3.pop(assm::edx); // load hash accumulator
 | 
| +  assm3.pop(assm::ecx); // ourter loop counter
 | 
| +  assm3.and(assm::eax, block_graph::Immediate(0xFF));
 | 
| +
 | 
| +  assm3.add(assm::dl, assm::al); // accumulate hash
 | 
| +  assm3.xor(assm::eax, assm::eax); // set eax to 0
 | 
| +  assm3.sub(assm::al, assm::dl); // al = -hash
 | 
| +  assm3.push(assm::eax); // store hash accumulator
 | 
| +  // check outer loop boundary
 | 
| +  assm3.test(assm::ecx, assm::ecx);
 | 
| +  assm3.j(assm::ConditionCode::kNotEqual, block_graph::Immediate(bb));
 | 
| +  // end outer loop
 | 
| +  assm3.pop(assm::eax); // final hash value
 | 
| +
 | 
| +  // function epilog
 | 
| +  assm3.mov(assm::esp, assm::ebp);
 | 
| +  assm3.pop(assm::ebp);
 | 
| +  assm3.ret();
 | 
| +
 | 
| +  // Condense into a block.
 | 
| +  block_graph::BlockBuilder block_builder(bgraph);
 | 
| +  if (!block_builder.Merge(subgraph))
 | 
| +   return NULL;
 | 
| +
 | 
| +  return block_builder.new_blocks().begin()[0];
 | 
| +}
 | 
| +
 | 
| +// Traverse the call-graph in reverse call order (callee to caller) and push
 | 
| +// blocks in post-order. The resulting ordering can be iterated to visit all
 | 
| +// blocks from leaf to root. The ordering has the guarantee that all callees
 | 
| +// have been visited before their callers (except for recursive calls and
 | 
| +// indirect calls).
 | 
| +// TODO(etienneb): Hoist this function into block_graph.
 | 
| +void FlattenCallGraphPostOrder(BlockGraph* block_graph, BlockOrdering* order) {
 | 
| +  DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 | 
| +  DCHECK_NE(reinterpret_cast<BlockOrdering*>(NULL), order);
 | 
| +
 | 
| + // The algorithms uses a std::stack allocated in the heap to avoid stack
 | 
| + // overflow.
 | 
| +  std::stack<BlockGraph::Block*> stack;
 | 
| +  std::set<BlockGraph::Block*> visiting;
 | 
| +
 | 
| + // Traverse the call-graph in depth-first.
 | 
| +  BlockGraph::BlockMap& blocks = block_graph->blocks_mutable();
 | 
| +  auto block_iter = blocks.begin();
 | 
| +  for (; block_iter != blocks.end(); ++block_iter) {
 | 
| +   BlockGraph::Block* block = &block_iter->second;
 | 
| +
 | 
| +   // This block is already visited.
 | 
| +   if (!visiting.insert(block).second)
 | 
| +    continue;
 | 
| +
 | 
| +   // This block needs to be visited, add it to the stack.
 | 
| +   stack.push(block);
 | 
| +
 | 
| +   // Follow the referrers.
 | 
| +   while (!stack.empty()) {
 | 
| +    block = stack.top();
 | 
| +
 | 
| +    // Put unvisited referrers on the stack.
 | 
| +    typedef std::map<BlockGraph::BlockId,
 | 
| +     BlockGraph::Block*> OrderedBlockMap;
 | 
| +    OrderedBlockMap missing;
 | 
| +    bool missing_referrers = false;
 | 
| +    if (block->type() == BlockGraph::CODE_BLOCK) {
 | 
| +     const ReferrerSet& referrers = block->referrers();
 | 
| +     auto referrer = referrers.begin();
 | 
| +     for (; referrer != referrers.end(); ++referrer) {
 | 
| +      BlockGraph::Block* from = referrer->first;
 | 
| +      if (visiting.insert(from).second) {
 | 
| +       missing.insert(std::make_pair(from->id(), from));
 | 
| +       missing_referrers = true;
 | 
| +      }
 | 
| +     }
 | 
| +    }
 | 
| +
 | 
| +    // Push missing referrers into the stack, ordered by block id.
 | 
| +    auto referrer = missing.begin();
 | 
| +    for (; referrer != missing.end(); ++referrer)
 | 
| +     stack.push(referrer->second);
 | 
| +
 | 
| +    // When there are no missing referrers, this block is fully visited and
 | 
| +    // can be pushed in the ordering (post-order).
 | 
| +    if (!missing_referrers) {
 | 
| +     order->push_front(block);
 | 
| +     // Remove this block from the stack.
 | 
| +     DCHECK_EQ(block, stack.top());
 | 
| +     stack.pop();
 | 
| +    }
 | 
| +   }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// Retrieves the basic block in the given subgraph at the given offset.
 | 
| +// @param subgraph the basic block subgraph where to search.
 | 
| +// @param offset the offset of the basic block to search for.
 | 
| +// @return the basic block object if found and NULL otherwise.
 | 
| +BasicBlock* GetBasicBlockAtOffset(const BasicBlockSubGraph *subgraph,
 | 
| +                                  const BasicBlock::Offset offset) {
 | 
| +  DCHECK(subgraph);
 | 
| +  DCHECK_LE(0, offset);
 | 
| +
 | 
| +  auto it(subgraph->basic_blocks().begin());
 | 
| +  for (; it != subgraph->basic_blocks().end(); ++it) {
 | 
| +   if ((*it)->offset() == offset)
 | 
| +    return *it;
 | 
| +  }
 | 
| +
 | 
| +  return nullptr;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +}
 | 
| +// namespace
 | 
| +
 | 
| +void IntegrityCheckTransform::PatchBlockReference(
 | 
| +    BasicBlock::Instructions::iterator inst_itr,
 | 
| +    block_graph::BlockGraph::Block* new_block,
 | 
| +    block_graph::BlockGraph::Offset new_offset,
 | 
| +    bool use_new_block = false){
 | 
| +  DCHECK(new_block);
 | 
| +  Instruction::BasicBlockReferenceMap &ref_block_map = inst_itr->references();
 | 
| +  auto instruction_references_it = ref_block_map.begin();
 | 
| +  BlockGraph::Offset reference_offset = instruction_references_it->first;
 | 
| +
 | 
| +  BasicBlockReference old_bb_ref = instruction_references_it->second;
 | 
| +  BasicBlockReference new_bb_ref(old_bb_ref.reference_type(),
 | 
| +                                 old_bb_ref.size(),
 | 
| +                                 use_new_block ? new_block : old_bb_ref.block(),
 | 
| +                                 new_offset,
 | 
| +                                 new_offset);
 | 
| +
 | 
| +  ref_block_map[reference_offset] = new_bb_ref;
 | 
| +}
 | 
| +
 | 
| +void SplitChunkReferencelabels(const std::string label,
 | 
| +                               uint64_t *checkee_id,
 | 
| +                               int *chunkIndex){
 | 
| +  //split the string
 | 
| +  std::istringstream iss(label);
 | 
| +  std::vector<std::string> tokens;
 | 
| +  copy(std::istream_iterator<std::string>(iss),
 | 
| +       std::istream_iterator<std::string>(),
 | 
| +       back_inserter(tokens));
 | 
| +
 | 
| +  *checkee_id = std::stoull(tokens.at(1));
 | 
| +  *chunkIndex = std::stoi(tokens.at(2));
 | 
| +}
 | 
| +
 | 
| +void IntegrityCheckTransform::GenerateLabelToBlockMap(BlockGraph *bgraph) {
 | 
| +  BlockGraph::BlockMap &blocks = bgraph->blocks_mutable();
 | 
| +  auto it(blocks.begin());
 | 
| +  this->label_name_to_block_->clear();
 | 
| +
 | 
| +  for (; it != blocks.end(); ++it) {
 | 
| +    auto label_map = it->second.labels();
 | 
| +    auto lab_it(label_map.begin());
 | 
| +    for (; lab_it != label_map.end(); ++lab_it) {
 | 
| +      (*this->label_name_to_block_)[lab_it->second.name()] =
 | 
| +        std::make_pair(&it->second, lab_it->first);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void IntegrityCheckTransform::UpdateLabelToBlockMap(BlockGraph::Block *block) {
 | 
| +  auto label_map = block->labels();
 | 
| +  auto lab_it(label_map.begin());
 | 
| +  for (; lab_it != label_map.end(); ++lab_it) {
 | 
| +    (*this->label_name_to_block_)[lab_it->second.name()] =
 | 
| +        std::make_pair(block, lab_it->first);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +bool IntegrityCheckTransform::PopulatePartitionKey(
 | 
| +    const block_graph::Instruction instr,
 | 
| +    uint8_t *num_abs_references) {
 | 
| +  auto references = instr.references();
 | 
| +  if (references.size() < 1)
 | 
| +    return false;
 | 
| +
 | 
| +  auto it = references.begin();
 | 
| +  for (; it != references.end(); ++it) {
 | 
| +    block_graph::BlockGraph::ReferenceType type = it->second.reference_type();
 | 
| +
 | 
| +    if (type == block_graph::BlockGraph::ReferenceType::ABSOLUTE_REF) {
 | 
| +      (*num_abs_references)++;
 | 
| +    }
 | 
| +  }
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +void IntegrityCheckTransform::PopulateCheckMaps(std::set<uint64_t> part_block) {
 | 
| +  std::set<uint64_t> tmp = part_block;
 | 
| +
 | 
| +  while (tmp.size() > 0) {
 | 
| +    // chose a random element
 | 
| +    int index = rand() % tmp.size();
 | 
| +    auto set_it = tmp.begin();
 | 
| +    std::advance(set_it, index);
 | 
| +
 | 
| +    index = rand() % part_block.size();
 | 
| +    auto set_it2 = part_block.begin();
 | 
| +    std::advance(set_it2, index);
 | 
| +
 | 
| +    // pick different blocks as the pair of checkees
 | 
| +    for (; set_it2 != part_block.end(); ++set_it2)
 | 
| +      if ((uint32_t)(*set_it) != (uint32_t)(*set_it2))
 | 
| +        break;
 | 
| +
 | 
| +    // if reached the end of the list then start from beginning
 | 
| +    if (set_it2 == part_block.end())
 | 
| +      set_it2 = part_block.begin();
 | 
| +
 | 
| +    // pick different blocks as the pair of checkees
 | 
| +    int i = 0;
 | 
| +    for (; i < index; ++i) {
 | 
| +      if ((uint32_t)(*set_it) != (uint32_t)(*set_it2))
 | 
| +        break;
 | 
| +
 | 
| +      ++set_it2;
 | 
| +    }
 | 
| +
 | 
| +    if (((uint32_t)(*set_it) == (uint32_t)(*set_it2)) && (i >= index)) {
 | 
| +      // skip this block of the partition
 | 
| +      tmp.erase(set_it);
 | 
| +      continue;
 | 
| +    }
 | 
| +
 | 
| +    // use this when checkers are allowed to be in the same block as checkees
 | 
| +    std::map<uint64_t, int> tuple;
 | 
| +    tuple.insert(std::pair<uint64_t, int>(*set_it, 1));
 | 
| +    tuple.insert(std::pair<uint64_t, int>(*set_it2, -1));
 | 
| +    // use this when checkers are NOT allowed in the same block as checkees
 | 
| +    std::list<uint32_t> tuple_blocks;
 | 
| +    tuple_blocks.push_back((uint32_t)*set_it);
 | 
| +    tuple_blocks.push_back((uint32_t)*set_it2);
 | 
| +
 | 
| +    uint64_t checker_id;
 | 
| +    if (!RandomlySelectChecker(tuple_blocks, &checker_id)) {
 | 
| +      tmp.erase(*set_it);
 | 
| +      continue;
 | 
| +    }
 | 
| +
 | 
| +    // Populate checker / checkee maps
 | 
| +    (*this->checker_to_checkee_map_)[checker_id] = tuple;
 | 
| +    fprintf(this->pfile_, "%llx,", checker_id);
 | 
| +    auto list_it = tuple.begin();
 | 
| +    for (; list_it != tuple.end(); ++list_it) {
 | 
| +      this->is_bb_checked_map_[list_it->first] = 1;
 | 
| +      fprintf(this->pfile_, "%d * %llx,", list_it->second, list_it->first);
 | 
| +    }
 | 
| +
 | 
| +    fprintf(this->pfile_, "\n");
 | 
| +    tmp.erase(set_it);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +//
 | 
| +bool IntegrityCheckTransform::RandomlySelectChecker(
 | 
| +    std::list<uint32_t> tuple_blocks,
 | 
| +    uint64_t *checker_id) {
 | 
| +  // Randomly select checker
 | 
| +  int index = rand() % this->precomputed_hashes_->size();
 | 
| +  auto map_it = this->precomputed_hashes_->begin();
 | 
| +  std::advance(map_it, index);
 | 
| +
 | 
| +  // checker must not be in the list of checkees and preferrably does not check
 | 
| +  // other tuples as well
 | 
| +  while ((map_it != this->precomputed_hashes_->end()) &&
 | 
| +    ((std::find(tuple_blocks.begin(), tuple_blocks.end(),
 | 
| +    (uint32_t)(*map_it).first) != tuple_blocks.end()) ||
 | 
| +    (this->checker_to_checkee_map_->find((*map_it).first) !=
 | 
| +    this->checker_to_checkee_map_->end()) &&
 | 
| +    ((*this->checker_to_checkee_map_)[(*map_it).first].size() > 0)))
 | 
| +    map_it++;
 | 
| +
 | 
| +  int i = 0;
 | 
| +  // if reached end of list then start from the begining and go until index
 | 
| +  if (map_it == this->precomputed_hashes_->end()) {
 | 
| +    map_it = this->precomputed_hashes_->begin();
 | 
| +    while ((i < index) &&
 | 
| +      ((std::find(tuple_blocks.begin(), tuple_blocks.end(),
 | 
| +      (uint32_t)(*map_it).first) != tuple_blocks.end()) ||
 | 
| +      (this->checker_to_checkee_map_->find((*map_it).first) !=
 | 
| +      this->checker_to_checkee_map_->end()) &&
 | 
| +      ((*this->checker_to_checkee_map_)[(*map_it).first].size() > 0))) {
 | 
| +      map_it++;
 | 
| +      i++;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  // if all checkers are already checking some tuple then we should only avoid
 | 
| +  // selecting the checker in the list of checkees
 | 
| +  if (i >= index) {
 | 
| +    while ((map_it != this->precomputed_hashes_->end()) &&
 | 
| +      ((std::find(tuple_blocks.begin(), tuple_blocks.end(),
 | 
| +      (uint32_t)(*map_it).first) != tuple_blocks.end()))) {
 | 
| +      map_it++;
 | 
| +    }
 | 
| +
 | 
| +    int i = 0;
 | 
| +    // if reached end of list then start from the begining and go until index
 | 
| +    if (map_it == this->precomputed_hashes_->end()) {
 | 
| +      map_it = this->precomputed_hashes_->begin();
 | 
| +      while ((i < index) &&
 | 
| +        ((std::find(tuple_blocks.begin(), tuple_blocks.end(),
 | 
| +        (uint32_t)(*map_it).first) != tuple_blocks.end()))){
 | 
| +        map_it++;
 | 
| +        i++;
 | 
| +      }
 | 
| +
 | 
| +      if (i >= index) {
 | 
| +        return false; // can't find a checker that satisfies all conditions
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  DCHECK(std::find(tuple_blocks.begin(), tuple_blocks.end(),
 | 
| +    (uint32_t)(*map_it).first) == tuple_blocks.end());
 | 
| +
 | 
| +  *checker_id = (*map_it).first;
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +#if defined COMPUTE_CHECKER_SIZE
 | 
| +uint64_t total_checker_size = 0;
 | 
| +#endif
 | 
| +
 | 
| +char* MakeChunkLabel(const uint64_t chunk_bb_id, const uint32_t chunk_index,
 | 
| +                     const bool before_chunk_integrity_code_added = false){
 | 
| +  DCHECK(chunk_bb_id != MAXUINT64);
 | 
| +  char *buffersearch = new char[50];
 | 
| +
 | 
| +  //only after chunk integrity code is prepended the first chunk label is
 | 
| +  //update to n %llu %lu format. Before that the first instruction refers to
 | 
| +  //the beginning of the block, which has %llu format
 | 
| +  if (before_chunk_integrity_code_added && chunk_index == 0){
 | 
| +    sprintf_s(buffersearch, 50, "%llu", chunk_bb_id);
 | 
| +  } else {
 | 
| +    sprintf_s(buffersearch, 50, "n %llu %lu", chunk_bb_id, chunk_index);
 | 
| +  }
 | 
| +  return buffersearch;
 | 
| +}
 | 
| +
 | 
| +bool IntegrityCheckTransform::AddChunkIntegrityCheckCode(
 | 
| +    BasicCodeBlock* bb,
 | 
| +    BasicBlockSubGraph* subgraph,
 | 
| +    BlockGraph *block_graph){
 | 
| +  auto inst_iter = bb->instructions().begin();
 | 
| +  if (inst_iter == bb->instructions().end())
 | 
| +    return true;
 | 
| +
 | 
| +  BlockGraph::Label label(inst_iter->label());
 | 
| +  uint64_t bb_id = GetBasicBlockIdByLabel(label, this->id_to_label_);
 | 
| +
 | 
| +  if (bb_id == -1)
 | 
| +    return true;
 | 
| +
 | 
| +  if ((*this->checker_to_checkee_map_)[bb_id].size() < 1)
 | 
| +    return true;
 | 
| +
 | 
| +  //given that the begining of the checker block never has an absolute reference
 | 
| +  //therefore, it is the pointer for the first block chunk. So, we update it's
 | 
| +  //label to a the chunk of index zero within the block
 | 
| +  char *chunk_label = MakeChunkLabel(bb_id, 0);
 | 
| +  inst_iter->set_label(BlockGraph::Label(chunk_label, BlockGraph::CODE_LABEL));
 | 
| +  delete[] chunk_label;
 | 
| +  std::set<uint32_t> chunk_set = (*ic_chunk_checker_to_checkee_map_)[bb_id];
 | 
| +  CHECK(chunk_set.size() == this->num_chunks_per_block);
 | 
| +
 | 
| +  block_graph::BasicBlockAssembler assm(inst_iter, &bb->instructions());
 | 
| +
 | 
| +  uint32_t num_original_instr = bb->instructions().size();
 | 
| +
 | 
| +  assm.push(assm::eax);
 | 
| +  assm.push(assm::ebx);
 | 
| +  assm.push(assm::ecx);
 | 
| +  assm.push(assm::edx);
 | 
| +
 | 
| +  assm.mov(assm::ecx, block_graph::Immediate(chunk_set.size(),
 | 
| +                                             assm::ValueSize::kSize32Bit));
 | 
| +
 | 
| +  auto chunk_iter = chunk_set.begin();
 | 
| +  uint32_t num_chunks = chunk_set.size();
 | 
| +
 | 
| +  std::map<uint32_t, std::tuple<uint64_t, uint32_t>> reference_free_labels;
 | 
| +  for (uint32_t reference_index = 0; chunk_iter != chunk_set.end();
 | 
| +       ++chunk_iter, ++reference_index){
 | 
| +
 | 
| +    auto chunk_info = (*ic_block_reference_free_chunks)[*chunk_iter];
 | 
| +    uint64_t chunk_bb_id = chunk_info.block_id_;
 | 
| +    uint32_t chunk_size = chunk_info.size_;
 | 
| +    uint32_t chunk_index = chunk_info.chunk_index_;
 | 
| +
 | 
| +    //get chunk offset and block
 | 
| +    char *buffersearch = MakeChunkLabel(chunk_bb_id, chunk_index,true);
 | 
| +    auto found_label_it = label_name_to_block_->find(buffersearch);
 | 
| +    DCHECK(found_label_it != label_name_to_block_->end());
 | 
| +    delete[] buffersearch;
 | 
| +    BlockGraph::Block* chunk_block = found_label_it->second.first;
 | 
| +    uint32_t chunk_offset = found_label_it->second.second;
 | 
| +
 | 
| +    assm.push(block_graph::Immediate(chunk_info.next_instruction_size_,
 | 
| +                                     assm::ValueSize::kSize32Bit));
 | 
| +    assm.push(block_graph::Immediate(chunk_size, assm::ValueSize::kSize32Bit));
 | 
| +
 | 
| +    //keep the index of block instruction for labelling
 | 
| +    uint32_t label_instr_index = bb->instructions().size() -
 | 
| +	                             num_original_instr;
 | 
| +    reference_free_labels.insert(std::make_pair(label_instr_index,
 | 
| +                                 std::make_pair(chunk_bb_id, chunk_index)));
 | 
| +
 | 
| +    assm.push(block_graph::Immediate(chunk_block, chunk_offset));
 | 
| +  }
 | 
| +
 | 
| +
 | 
| +  assm.push(block_graph::Immediate(0, assm::kSize32Bit));
 | 
| +  assm.call(block_graph::Immediate(this->xhash_block_, 0));
 | 
| +  uint32_t no_pushed_words = 3 * num_chunks + 1;
 | 
| +  assm.add(assm::esp, block_graph::Immediate(no_pushed_words * 4));
 | 
| +  assm.push(assm::eax);
 | 
| +  //test
 | 
| +
 | 
| +  //Insert label at the beginning of the block
 | 
| +  inst_iter = bb->instructions().begin();
 | 
| +  label = BlockGraph::Label(std::to_string(bb_id),
 | 
| +                            BlockGraph::CODE_LABEL);
 | 
| +  inst_iter->set_label(label);
 | 
| +
 | 
| +
 | 
| +  uint32_t num_added_chunk_labels = 0;
 | 
| +  uint32_t label_index = 0;
 | 
| +  uint32_t new_size = 0;
 | 
| +  uint32_t num_added_instr = bb->instructions().size() - num_original_instr;
 | 
| +  for (uint32_t instruction_index = 0;
 | 
| +      inst_iter != bb->instructions().end() &&
 | 
| +      instruction_index < num_added_instr;
 | 
| +      ++instruction_index, ++inst_iter){
 | 
| +    new_size += inst_iter->size();
 | 
| +    auto label_it = reference_free_labels.find(label_index++);
 | 
| +    //add reference free labels
 | 
| +    if (label_it != reference_free_labels.end()){
 | 
| +      char  *buffer = new char[50];
 | 
| +      uint64_t chunk_bb_id = std::get <0>(label_it->second);
 | 
| +      uint32_t chunk_index = std::get<1>(label_it->second);
 | 
| +      sprintf_s(buffer, 50, "nrc %llu %lu", chunk_bb_id,
 | 
| +        chunk_index);
 | 
| +      label = BlockGraph::Label(buffer, BlockGraph::CODE_LABEL);
 | 
| +      delete[] buffer;
 | 
| +      inst_iter->set_label(label);
 | 
| +      ++num_added_chunk_labels;
 | 
| +      ++num_chunk_reference_labels;
 | 
| +    }
 | 
| +  } //end for
 | 
| +
 | 
| +
 | 
| +  //make sure all chunk block references are set
 | 
| +  DCHECK_EQ(num_added_chunk_labels, static_cast<uint32_t>(chunk_set.size()));
 | 
| +
 | 
| +
 | 
| +  //update size
 | 
| +  uint32_t old_size = (*this->basic_block_sizes_)[bb_id];
 | 
| +  (*this->basic_block_sizes_)[bb_id] = old_size + new_size;
 | 
| +#if defined COMPUTE_CHECKER_SIZE
 | 
| +  total_checker_size += old_size + new_size;
 | 
| +#endif
 | 
| +  return true;
 | 
| +}
 | 
| +void GetSizeTokenFromlabel(const std::string label,
 | 
| +                           uint64_t *checkee_id,
 | 
| +                           uint64_t *bb_id){
 | 
| +  //split the string
 | 
| +  std::istringstream iss(label);
 | 
| +  std::vector<std::string> tokens;
 | 
| +  copy(std::istream_iterator<std::string>(iss),
 | 
| +    std::istream_iterator<std::string>(),
 | 
| +    back_inserter(tokens));
 | 
| +  *checkee_id = std::stoull(tokens.at(1));
 | 
| +  *bb_id = std::stoull(tokens.at(2));
 | 
| +}
 | 
| +
 | 
| +void GetBlockIdTokenFromlabel(const std::string label, uint64_t *checkee_id){
 | 
| +  //split the string
 | 
| +  std::istringstream iss(label);
 | 
| +  std::vector<std::string> tokens;
 | 
| +  copy(std::istream_iterator<std::string>(iss),
 | 
| +    std::istream_iterator<std::string>(),
 | 
| +    back_inserter(tokens));
 | 
| +  *checkee_id = std::stoull(tokens.at(1));
 | 
| +}
 | 
| +
 | 
| +//keep track of chunk indexes to update xor hash after size changes
 | 
| +uint32_t last_visited_chunk_index = 0;
 | 
| +uint64_t last_visited_chunk_bb_id = 0;
 | 
| +
 | 
| +bool IntegrityCheckTransform::PatchBlockReferencesAndSizes(
 | 
| +    BasicCodeBlock* bb,
 | 
| +    BasicBlockSubGraph* subgraph,
 | 
| +    BlockGraph *block_graph){
 | 
| +  bool found = false;
 | 
| +
 | 
| +  auto inst_iter = bb->instructions().begin();
 | 
| +  if (inst_iter == bb->instructions().end()){
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  BlockGraph::Label label(inst_iter->label());
 | 
| +  uint64_t block_id = GetBasicBlockIdByLabel(label, this->id_to_label_);
 | 
| +
 | 
| +  std::string sizeLabel = "size ";
 | 
| +  std::string blockLabel = "block";
 | 
| +  std::string chunk_blocklabel = "nrc";
 | 
| +  std::string chunk_pointerlabel = "n ";
 | 
| +  std::string chunk_no_reference = "ref";
 | 
| +  std::string block_id_label = std::to_string(block_id);
 | 
| +  auto end_block = bb->instructions().end();
 | 
| +  for (; inst_iter != end_block; ++inst_iter)
 | 
| +  {
 | 
| +    if (!inst_iter->has_label())  continue;
 | 
| +
 | 
| +
 | 
| +    if (inst_iter->label().name()
 | 
| +        .compare(0, chunk_pointerlabel.length(), chunk_pointerlabel) == 0){
 | 
| +      // update last visited chunk index
 | 
| +      GetChunkTokensFromlabel(inst_iter->label().name(),
 | 
| +                              &last_visited_chunk_bb_id,
 | 
| +                              &last_visited_chunk_index);
 | 
| +    } else if (inst_iter->label().name()
 | 
| +               .compare(0, block_id_label.length(), block_id_label) == 0){
 | 
| +      last_visited_chunk_bb_id = block_id;
 | 
| +      last_visited_chunk_index = 0;
 | 
| +#pragma region patch_size
 | 
| +    } else if (inst_iter->label().name()
 | 
| +        .compare(0, sizeLabel.length(), sizeLabel) == 0){
 | 
| +      //extract block id for size retrieval
 | 
| +      uint64_t checkee_id = 0;
 | 
| +      uint64_t bb_id = 0;
 | 
| +      GetSizeTokenFromlabel(inst_iter->label().name(), &checkee_id, &bb_id);
 | 
| +      //modify bytes
 | 
| +      ++num_size_reference_patched_labels;
 | 
| +      auto old_data = inst_iter->GetMutableData();
 | 
| +      DCHECK(old_data[0] == 0x68);
 | 
| +      //if the block is checker then the new size must be bigger than the
 | 
| +      //old one
 | 
| +      uint32_t old_size = 0;
 | 
| +      for (int j = 0; j < sizeof(uint32_t) && old_data[j] != NULL; j++)
 | 
| +      {
 | 
| +        old_size |= old_data[j + 1] << j * 8;
 | 
| +      }
 | 
| +      uint8_t* new_data = new uint8_t[inst_iter->size()];
 | 
| +      new_data[0] = 0x68;
 | 
| +      uint32_t new_size = (*this->basic_block_sizes_)[checkee_id];
 | 
| +      for (int k = 0; k < sizeof(uint32_t); k++){
 | 
| +        uint8_t value = (new_size >> k * 8) & 0xFF;
 | 
| +        new_data[k + 1] = value;
 | 
| +      }
 | 
| +
 | 
| +      //if the block is checker then the new size must be bigger than the
 | 
| +      //old one
 | 
| +      if ((*checker_to_checkee_map_)[checkee_id].size() > 0){
 | 
| +        DCHECK_GE(new_size, old_size);
 | 
| +      }
 | 
| +
 | 
| +      if (*perform_chunk_checks_) {
 | 
| +        clock_t begin = clock();
 | 
| +        //we have to recompute chunk that inlcudes this size
 | 
| +        this->RecomputeXorChunks(bb_id, old_data, new_data,
 | 
| +            last_visited_chunk_bb_id,
 | 
| +            last_visited_chunk_index);
 | 
| +        clock_t end = clock();
 | 
| +        elapsed_secs_in_patching_chunks += double(end - begin) /
 | 
| +		                                   CLOCKS_PER_SEC;
 | 
| +      }
 | 
| +      for (uint8_t j = 0; j < inst_iter->size(); j++)
 | 
| +        old_data[j] = new_data[j];
 | 
| +
 | 
| +      //prevent multiple patching
 | 
| +      inst_iter->set_label(block_graph::BlockGraph::Label());
 | 
| +      found++;
 | 
| +      delete[] new_data;
 | 
| +#pragma endregion
 | 
| +    } else if (inst_iter->label().name() //patch block
 | 
| +               .compare(0, blockLabel.length(), blockLabel) == 0){
 | 
| +      //extract block id for offset patching
 | 
| +      uint64_t checkee_id = 0;
 | 
| +      GetBlockIdTokenFromlabel(inst_iter->label().name(), &checkee_id);
 | 
| +#pragma region patch_block
 | 
| +      auto label_itr = label_name_to_block_->find(std::to_string(checkee_id));
 | 
| +      DCHECK(label_itr != label_name_to_block_->end());
 | 
| +      PatchBlockReference(inst_iter, label_itr->second.first,
 | 
| +        label_itr->second.second);
 | 
| +#pragma endregion
 | 
| +    } else if (inst_iter->label().name().compare(0, chunk_blocklabel.size(),
 | 
| +                                                 chunk_blocklabel) == 0){
 | 
| +
 | 
| +      uint64_t checkee_id_for_patch = 0;
 | 
| +      int checkee_index_for_patch;
 | 
| +      SplitChunkReferencelabels(inst_iter->label().name(),
 | 
| +                                &checkee_id_for_patch,
 | 
| +                                &checkee_index_for_patch);
 | 
| +      CHECK(checkee_id_for_patch != 0);
 | 
| +
 | 
| +      num_chunk_reference_patched_labels++;
 | 
| +
 | 
| +      //find the offset of the reference free chunk within the checkee
 | 
| +      char  *chunk_label = MakeChunkLabel(checkee_id_for_patch,
 | 
| +                                          checkee_index_for_patch);
 | 
| +      auto label_to_block_it = label_name_to_block_->find(chunk_label);
 | 
| +      delete[] chunk_label;
 | 
| +      CHECK(label_to_block_it != label_name_to_block_->end());
 | 
| +#pragma region patch_chunk_offset
 | 
| +      //update instruction reference to the retrieved reference free
 | 
| +      //offset (label_to_block_it.second is a pair of <block,offset>)
 | 
| +      auto reference_free_block = label_to_block_it->second.first;
 | 
| +      uint32_t new_bb_ref_offset = label_to_block_it->second.second;
 | 
| +
 | 
| +      PatchBlockReference(inst_iter, reference_free_block, new_bb_ref_offset);
 | 
| +
 | 
| +#pragma endregion
 | 
| +
 | 
| +
 | 
| +    } else if (*perform_chunk_checks_ &&
 | 
| +               inst_iter->label().name().compare(0, chunk_no_reference.size(),
 | 
| +                                                 chunk_no_reference) == 0){
 | 
| +      //patch number of chunks per block
 | 
| +      uint64_t bb_id = 0;
 | 
| +      GetBlockIdTokenFromlabel(inst_iter->label().name(), &bb_id);
 | 
| +      //modify bytes
 | 
| +      ++num_no_chunk_patched_labels;
 | 
| +      auto old_data = inst_iter->GetMutableData();
 | 
| +      DCHECK(old_data[0] == 0x68);
 | 
| +
 | 
| +      uint8_t* new_data = new uint8_t[inst_iter->size()];
 | 
| +      new_data[0] = 0x68;
 | 
| +      uint32_t old_size = 0;
 | 
| +      for (int j = 0; j < sizeof(uint32_t) && old_data[j] != NULL; j++)
 | 
| +      {
 | 
| +        old_size |= old_data[j + 1] << j * 8;
 | 
| +      }
 | 
| +      uint32_t new_size = old_size + this->num_chunks_per_block;
 | 
| +      for (int k = 0; k < sizeof(uint32_t); k++){
 | 
| +        uint8_t value = (new_size >> k * 8) & 0xFF;
 | 
| +        new_data[k + 1] = value;
 | 
| +      }
 | 
| +
 | 
| +      //we have to recompute the chunk that includes this instruction(if any)
 | 
| +      this->RecomputeXorChunks(bb_id, old_data, new_data,
 | 
| +                               last_visited_chunk_bb_id,
 | 
| +                               last_visited_chunk_index);
 | 
| +
 | 
| +      for (uint8_t j = 0; j < inst_iter->size(); j++)
 | 
| +        old_data[j] = new_data[j];
 | 
| +
 | 
| +      //prevent multiple patching
 | 
| +      inst_iter->set_label(block_graph::BlockGraph::Label());
 | 
| +      found++;
 | 
| +      delete[] new_data;
 | 
| +    }
 | 
| +  } // end for
 | 
| +
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +bool IntegrityCheckTransform::RecomputeXorChunks(
 | 
| +    const uint64_t bb_id, const uint8_t old_size[],
 | 
| +    const uint8_t new_size[], const uint64_t chunk_bb_id,
 | 
| +	const uint32_t chunk_index){
 | 
| +
 | 
| +  DCHECK_EQ(bb_id, chunk_bb_id);
 | 
| +
 | 
| +  uint32_t vector_index =
 | 
| +    (*ic_block_chunk_index_map_)[GetChunkUniqueKey(chunk_bb_id,chunk_index)];
 | 
| +
 | 
| +  DCHECK_GE(vector_index, static_cast<uint32_t>(0));
 | 
| +  DCHECK_LT(vector_index, ic_block_reference_free_chunks->size());
 | 
| +
 | 
| +  auto chunk = (*ic_block_reference_free_chunks)[vector_index];
 | 
| +  DCHECK(chunk.block_id_ == chunk_bb_id && chunk.chunk_index_ == chunk_index);
 | 
| +  ////make sure we found the right chunk
 | 
| +  DCHECK(sizeof(old_size) == sizeof(new_size));
 | 
| +
 | 
| +  uint8_t new_hash = chunk.hash_;
 | 
| +  for (uint32_t i = 0; i < sizeof(old_size); i++)
 | 
| +  {
 | 
| +    //cancel out previous value
 | 
| +    new_hash ^= old_size[i];
 | 
| +    //compute new hash
 | 
| +    new_hash ^= new_size[i];
 | 
| +  }
 | 
| +
 | 
| +  chunk.hash_ = new_hash;
 | 
| +  (*ic_block_reference_free_chunks)[vector_index] = chunk;
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +bool IsSize(BasicBlock::Instructions::iterator instruction_itr){
 | 
| +  std::string size_label = "size";
 | 
| +  if (instruction_itr->has_label() &&
 | 
| +      instruction_itr->label().name()
 | 
| +      .compare(0, size_label.length(), size_label) == 0){
 | 
| +    return true;
 | 
| +  }
 | 
| +  return false;
 | 
| +}
 | 
| +bool IsPivot(BasicBlock::Instructions::iterator instruction_itr){
 | 
| +  std::string pivot_label = "Pivot:";
 | 
| +  if (instruction_itr->has_label() &&
 | 
| +      instruction_itr->label().name()
 | 
| +      .compare(0, pivot_label.length(), pivot_label) == 0){
 | 
| +    return true;
 | 
| +  }
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +bool HasAbsoluteReferences(BasicBlock::Instructions::iterator instruction_itr){
 | 
| +  if (instruction_itr->references().size() > 0){
 | 
| +    auto ref_it = instruction_itr->references().begin();
 | 
| +    for (; ref_it != instruction_itr->references().end(); ++ref_it){
 | 
| +      if (ref_it->second.reference_type() ==
 | 
| +          block_graph::BlockGraph::ReferenceType::ABSOLUTE_REF)
 | 
| +        return true;
 | 
| +    }
 | 
| +  }
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +void
 | 
| +IntegrityCheckTransform::AddChunkIntoIndexMap(const uint64_t bb_id,
 | 
| +                                              const uint32_t chunk_index,
 | 
| +                                              const uint32_t vector_index){
 | 
| +  auto unique_chunk_key = GetChunkUniqueKey(bb_id,chunk_index);
 | 
| +  //make sure the key is really unique!
 | 
| +  DCHECK(ic_block_chunk_index_map_->find(unique_chunk_key) ==
 | 
| +         ic_block_chunk_index_map_->end());
 | 
| +  (*ic_block_chunk_index_map_)[unique_chunk_key] = vector_index;
 | 
| +}
 | 
| +
 | 
| +void IntegrityCheckTransform::ComputeChunks(BasicCodeBlock* bb){
 | 
| +  auto inst_iter = bb->instructions().begin();
 | 
| +  if (inst_iter == bb->instructions().end())
 | 
| +    return;
 | 
| +
 | 
| +  BlockGraph::Label label(inst_iter->label());
 | 
| +  uint64_t bb_id = GetBasicBlockIdByLabel(label, this->id_to_label_);
 | 
| +  if (bb_id == -1)
 | 
| +    return;
 | 
| +  std::map<uint64_t, int> checkee_list =
 | 
| +    (*this->checker_to_checkee_map_)[bb_id];
 | 
| +
 | 
| +  if (checkee_list.size() < 1)
 | 
| +    return;
 | 
| +
 | 
| +  //uint32_t reference_free_start_offset = 0;
 | 
| +  uint32_t reference_free_size = 0;
 | 
| +  uint8_t reference_free_hash = 0;
 | 
| +  uint32_t reference_free_index = 0;
 | 
| +  uint16_t size_in_bytes = 0;
 | 
| +  uint8_t num_found_pivots = 0;
 | 
| +  uint32_t current_inst_size = 0;
 | 
| +  std::string bb_id_label = std::to_string(bb_id);
 | 
| +  bool has_references=false;
 | 
| +  bool has_abs_references = false;
 | 
| +  bool is_pivot=false;
 | 
| +  // Process all instructions in BB
 | 
| +  for (; inst_iter != bb->instructions().end(); ++inst_iter) {
 | 
| +
 | 
| +    current_inst_size = (*inst_iter).size();
 | 
| +    size_in_bytes += current_inst_size;
 | 
| +    const uint8_t *b2 = (*inst_iter).data();
 | 
| +
 | 
| +    uint8_t instruction_hash = 0;
 | 
| +    for (uint32_t i = 0; i < current_inst_size; ++i){
 | 
| +      instruction_hash ^= (*b2);
 | 
| +      b2++;
 | 
| +    }
 | 
| +    if (IsPivot(inst_iter)){
 | 
| +      ++num_found_pivots;
 | 
| +    }
 | 
| +    has_abs_references = HasAbsoluteReferences(inst_iter);
 | 
| +    has_references = (inst_iter->references().size() > 0);
 | 
| +
 | 
| +    is_pivot = IsPivot(inst_iter);
 | 
| +    if (!has_references && !is_pivot){
 | 
| +      //we cannot place two labels on the same instruction, so if the beginning
 | 
| +      //of the chunk has a label we skip it.
 | 
| +      //In order to keep the first instruction of the block in a chunk without
 | 
| +      //changing its label, we accept the block id label as a finger for the
 | 
| +      //beginning of the chunk.
 | 
| +      if (reference_free_size != 0 || !inst_iter->has_label()
 | 
| +          || inst_iter->label().name().compare(bb_id_label)==0){
 | 
| +        //this is the first instruction in the chunk where we place our label
 | 
| +        //we don't need to put label at the first instruction, because it has
 | 
| +        //block id label, first instruction label is detected when reference
 | 
| +        //free index equals zero
 | 
| +        if (reference_free_size == 0 && reference_free_index!=0){
 | 
| +          char  *buffer = MakeChunkLabel(bb_id, reference_free_index);
 | 
| +          auto label = BlockGraph::Label(buffer, BlockGraph::CODE_LABEL);
 | 
| +          delete[] buffer;
 | 
| +          DCHECK(!inst_iter->has_label());
 | 
| +          inst_iter->set_label(label);
 | 
| +        }
 | 
| +        //keep counting
 | 
| +        reference_free_size += current_inst_size;
 | 
| +        reference_free_hash ^= instruction_hash;
 | 
| +      }
 | 
| +    } else if (reference_free_size > 0){
 | 
| +      //add offset and size of the reference free chunk
 | 
| +      ic_block_reference_free_chunks->push_back(
 | 
| +          ChunkInfo(bb_id, reference_free_size, reference_free_hash,
 | 
| +                    reference_free_index,
 | 
| +                    has_abs_references?current_inst_size:0));
 | 
| +      AddChunkIntoIndexMap(bb_id, reference_free_index++,
 | 
| +          ic_block_reference_free_chunks->size() - 1);
 | 
| +      //once we add the chunk, we reset the size
 | 
| +      reference_free_size = 0;
 | 
| +      reference_free_hash = 0;
 | 
| +     }
 | 
| +  } //end for
 | 
| +
 | 
| +  //the last chunk of the instructions need to be added (if any)
 | 
| +  if (reference_free_size > 0) {
 | 
| +    //add offset and size of the reference free chunk
 | 
| +    ic_block_reference_free_chunks->push_back(
 | 
| +       ChunkInfo(bb_id, reference_free_size, reference_free_hash,
 | 
| +                 reference_free_index, 0));
 | 
| +      AddChunkIntoIndexMap(bb_id, reference_free_index,
 | 
| +                           ic_block_reference_free_chunks->size() - 1);
 | 
| +    //once we add the chunk, we reset the size
 | 
| +    reference_free_size = reference_free_hash = 0;
 | 
| +  }
 | 
| +
 | 
| +  //Exactly one pivot must be in each IC block
 | 
| +  DCHECK_EQ(num_found_pivots, 1);
 | 
| +}
 | 
| +
 | 
| +uint8_t IntegrityCheckTransform::PrecomputeHash(
 | 
| +    BasicCodeBlock* bb,
 | 
| +    std::list<uint32_t> *offset_sizes,
 | 
| +    BasicBlockSubGraph* subgraph) {
 | 
| +  DCHECK_NE(reinterpret_cast<BasicCodeBlock*>(NULL), bb);
 | 
| +
 | 
| +  if (bb->instructions().size() <= 0)
 | 
| +    return 0;
 | 
| +
 | 
| +  uint16_t offset_in_bytes = 0;
 | 
| +  uint16_t size_in_bytes = 0;
 | 
| +  uint64_t bb_address = GetBasicBlockId(bb, subgraph);
 | 
| +
 | 
| +  // Match and rewrite based on patterns.
 | 
| +  auto inst_iter = bb->instructions().begin();
 | 
| +  size_in_bytes = 0;
 | 
| +  uint8_t partition_key = 0;
 | 
| +  BlockGraph::Label label;
 | 
| +
 | 
| +  label = BlockGraph::Label(std::to_string(bb_address),
 | 
| +                            BlockGraph::CODE_LABEL);
 | 
| +  inst_iter->set_label(label);
 | 
| +
 | 
| +  (*this->id_to_label_)[bb_address] = label;
 | 
| +  fprintf(this->prefile_, "\n\n%llx\n", std::stoull(label.name()));
 | 
| +
 | 
| +  // Process all instructions in BB
 | 
| +  for (; inst_iter != bb->instructions().end(); ++inst_iter) {
 | 
| +    uint32_t size = (*inst_iter).size();
 | 
| +    uint8_t nr_refs_in_key = partition_key;
 | 
| +
 | 
| +    if (PopulatePartitionKey((*inst_iter), &partition_key)) {
 | 
| +      this->basic_block_has_ref_[bb_address] = true;
 | 
| +
 | 
| +      int nr_added = partition_key - nr_refs_in_key;
 | 
| +      if (nr_added == 1) {
 | 
| +        uint64_t label_nr = bb_address + ((uint64_t)size_in_bytes << 32);
 | 
| +        label = BlockGraph::Label(std::to_string(label_nr),
 | 
| +                                  BlockGraph::CODE_LABEL);
 | 
| +
 | 
| +        if (inst_iter->has_label()) {
 | 
| +          BlockGraph::Label existing_label = inst_iter->label();
 | 
| +        } else {
 | 
| +          inst_iter->set_label(label);
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    size_in_bytes += size;
 | 
| +  } // end for
 | 
| +
 | 
| +  // put the last bytes in the basic block in the list of precomputed hashes
 | 
| +  if ((size_in_bytes > 0)) { // don't put chunks of 0 size on stack
 | 
| +    uint32_t offset_size = (offset_in_bytes << 16) | size_in_bytes;
 | 
| +    offset_sizes->push_front(offset_size);
 | 
| +  }
 | 
| +
 | 
| +  // populate precomputed hashes and bb-sizes
 | 
| +  if (partition_key > 0) {
 | 
| +    std::set<uint64_t> v = this->partition_map_[partition_key];
 | 
| +    v.insert(bb_address);
 | 
| +    this->partition_map_[partition_key] = v;
 | 
| +    // save precomputed hash
 | 
| +    (*this->precomputed_hashes_)[bb_address] = 0;
 | 
| +    (*this->basic_block_sizes_)[bb_address] = size_in_bytes;
 | 
| +
 | 
| +  } else if (size_in_bytes > 0) {
 | 
| +    std::set<uint64_t> v = this->partition_map_[0];
 | 
| +    v.insert(bb_address);
 | 
| +    this->partition_map_[0] = v;
 | 
| +    // save precomputed hash
 | 
| +    (*this->precomputed_hashes_)[bb_address] = 0;
 | 
| +    (*this->basic_block_sizes_)[bb_address] = size_in_bytes;
 | 
| +  }
 | 
| +
 | 
| +  bb_address += ((uint64_t)offset_in_bytes << 32);
 | 
| +  return 1;
 | 
| +}
 | 
| +
 | 
| +bool IntegrityCheckTransform::TransformBasicBlockSubGraph(
 | 
| +    BlockGraph* bgraph,
 | 
| +    BasicBlockSubGraph* subgraph,
 | 
| +    IntegrityCheckTransform::ProcessingType step) {
 | 
| +  DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), bgraph);
 | 
| +
 | 
| +  if (step == IntegrityCheckTransform::ADD_HASH_AND_RESPONSE) {
 | 
| +    this->hash_block_ = AddHashFunction(bgraph);
 | 
| +    this->xhash_block_ = AddXorHashFunction(bgraph);
 | 
| +    this->response_block_ = AddResponseFunction(bgraph);
 | 
| +
 | 
| +    return (this->hash_block_ && this->xhash_block_ && this->response_block_);
 | 
| +
 | 
| +  } else {
 | 
| +    DCHECK_NE(reinterpret_cast<BasicBlockSubGraph*>(NULL), subgraph);
 | 
| +    std::list<uint32_t> instr_sizes;
 | 
| +    uint8_t min_instructions = 0;
 | 
| +    BasicBlockSubGraph::BBCollection& basic_blocks =
 | 
| +      subgraph->basic_blocks(); // set of BB to protect
 | 
| +
 | 
| +    // Iterate over every basic block and insert integrity-checks
 | 
| +    for (auto it = basic_blocks.begin(); it != basic_blocks.end(); ++it) {
 | 
| +      BasicCodeBlock* bb = BasicCodeBlock::Cast(*it);
 | 
| +      if ((bb == NULL) || (bb->instructions().size() < min_instructions))
 | 
| +        continue;
 | 
| +      switch (step) {
 | 
| +      case IntegrityCheckTransform::PRECOMPUTE_HASHES: {
 | 
| +        PrecomputeHash(bb, &instr_sizes, subgraph);
 | 
| +        break;
 | 
| +      }
 | 
| +      case IntegrityCheckTransform::INSERT_CHECKS: {
 | 
| +        AddIntegrityCheckCode(bb, subgraph, bgraph);
 | 
| +        break;
 | 
| +      }
 | 
| +      case IntegrityCheckTransform::COMPUTE_CHUNKS:{
 | 
| +        ComputeChunks(bb);
 | 
| +        break;
 | 
| +      }
 | 
| +      case IntegrityCheckTransform::INSERT_CHUNK_CHECKS:{
 | 
| +        AddChunkIntegrityCheckCode(bb, subgraph, bgraph);
 | 
| +        break;
 | 
| +      }
 | 
| +      case IntegrityCheckTransform::PATCH_REFERENCES_SIZES: {
 | 
| +        PatchBlockReferencesAndSizes(bb, subgraph, bgraph);
 | 
| +        break;
 | 
| +      }
 | 
| +      default:
 | 
| +        DbgRaiseAssertionFailure();
 | 
| +        break;
 | 
| +      }
 | 
| +    } // end for
 | 
| +  } // end else
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +uint8_t IntegrityCheckTransform::GetPartitionKey(uint64_t bb_id) {
 | 
| +  auto it = this->partition_map_.begin();
 | 
| +  for (; it != this->partition_map_.end(); ++it) {
 | 
| +    if (it->second.find(bb_id) != it->second.end())
 | 
| +      return it->first;
 | 
| +  }
 | 
| +
 | 
| +  return 0;
 | 
| +}
 | 
| +
 | 
| +void IntegrityCheckTransform::AddIntegrityCheckCode(
 | 
| +    BasicCodeBlock* bb,
 | 
| +    BasicBlockSubGraph* subgraph,
 | 
| +    BlockGraph *block_graph) {
 | 
| +  auto inst_iter = bb->instructions().begin();
 | 
| +  if (inst_iter == bb->instructions().end())
 | 
| +    return;
 | 
| +
 | 
| +  BlockGraph::Label label(inst_iter->label());
 | 
| +  uint64_t bb_id = GetBasicBlockIdByLabel(label, this->id_to_label_);
 | 
| +
 | 
| +  if (bb_id == -1)
 | 
| +    return;
 | 
| +
 | 
| +  uint8_t hash = 0;
 | 
| +  std::map<uint64_t, int> checkee_list =
 | 
| +    (*this->checker_to_checkee_map_)[bb_id];
 | 
| +
 | 
| +  if (checkee_list.size() < 1)
 | 
| +    return;
 | 
| +
 | 
| +  // Count number of absolute references in basic block
 | 
| +  uint8_t no_abs_references = 0;
 | 
| +  // Count number of instructions in basic block
 | 
| +  uint32_t no_bb_instructions = bb->instructions().size();
 | 
| +  uint32_t no_orig_bb_instructions = bb->instructions().size();
 | 
| +  std::map<uint32_t, uint64_t> checkee_label_map;
 | 
| +  if (this->insert_file_ != NULL){
 | 
| +    fprintf(this->insert_file_, "%s,", label.name().c_str());
 | 
| +  }
 | 
| +  // Remove old label from the beginning of the original code
 | 
| +  inst_iter->set_label(BlockGraph::Label());
 | 
| +
 | 
| +  block_graph::BasicBlockAssembler assm(inst_iter,
 | 
| +    &bb->instructions());
 | 
| +
 | 
| +  //in case we add chunk checker these pushes will be added by the chunk
 | 
| +  //checker
 | 
| +  if (!*perform_chunk_checks_){
 | 
| +    assm.push(assm::eax);
 | 
| +    assm.push(assm::ebx);
 | 
| +    assm.push(assm::ecx);
 | 
| +    assm.push(assm::edx);
 | 
| +  }
 | 
| +
 | 
| +  assm.lea(assm::ecx, block_graph::Operand(
 | 
| +                      block_graph::Displacement(checkee_list.size(),
 | 
| +                      assm::ValueSize::kSize32Bit)));
 | 
| +
 | 
| +  uint32_t *checkee_size_index = new uint32_t[checkee_list.size()];
 | 
| +  uint32_t *checkee_reference_index = new uint32_t[checkee_list.size()];
 | 
| +
 | 
| +  uint32_t pivot_instruction_index = 0;
 | 
| +  uint32_t sub_instruction_index = 0;
 | 
| +  uint32_t k = 0;
 | 
| +  uint32_t reference_index = 0;
 | 
| +  auto checkee_it = checkee_list.begin();
 | 
| +  int last_coefficient = 0;
 | 
| +  for (; checkee_it != checkee_list.end(); ++checkee_it) {
 | 
| +
 | 
| +    if (last_coefficient == checkee_it->second){
 | 
| +      LOG(INFO) << "found equal coeffs";
 | 
| +    }
 | 
| +    last_coefficient = checkee_it->second;
 | 
| +    assm.push(block_graph::Immediate(checkee_it->second,
 | 
| +                                     assm::ValueSize::kSize32Bit));
 | 
| +
 | 
| +    // push the number of checkees of the checkee
 | 
| +    uint32_t nr_of_checkees =
 | 
| +      (*this->checker_to_checkee_map_)[checkee_it->first].size();
 | 
| +    no_abs_references += nr_of_checkees + GetPartitionKey(bb_id) +
 | 
| +	                     this->num_chunks_per_block;
 | 
| +    //Here still we don't know how many chunks this checker is going to check
 | 
| +    //depending on the coverage config and total number of discovered chunks
 | 
| +    //this number should be added to the nr_of_chechees
 | 
| +    //nr_of_checkees += this->num_chunks_per_block;
 | 
| +    checkee_reference_index[reference_index++] =
 | 
| +        bb->instructions().size() - no_orig_bb_instructions;
 | 
| +    assm.push(block_graph::Immediate(nr_of_checkees,
 | 
| +                                     assm::ValueSize::kSize32Bit));
 | 
| +
 | 
| +    // Count the number of instructions added so far into the basic block
 | 
| +    // This information is used to set a label on the following push instr
 | 
| +    checkee_size_index[k++] = bb->instructions().size() - no_bb_instructions;
 | 
| +    no_bb_instructions = bb->instructions().size();
 | 
| +
 | 
| +    // push the size of the checkee
 | 
| +    uint32_t size_of_checkee = (*this->basic_block_sizes_)[checkee_it->first];
 | 
| +    assm.push(block_graph::Immediate(size_of_checkee,
 | 
| +                                     assm::ValueSize::kSize32Bit));
 | 
| +
 | 
| +    BlockGraph::Label checkee_label =
 | 
| +      (*this->id_to_label_)[checkee_it->first];
 | 
| +    std::pair<BlockGraph::Block*, uint32_t> block_offset_pair =
 | 
| +      (*this->label_name_to_block_)[checkee_label.name()];
 | 
| +    BlockGraph::Block* checkee_block = block_offset_pair.first;
 | 
| +    uint32_t checkee_offset = block_offset_pair.second;
 | 
| +
 | 
| +    DCHECK(checkee_block != NULL);
 | 
| +
 | 
| +    checkee_label_map.insert(std::make_pair(
 | 
| +      bb->instructions().size() - no_orig_bb_instructions, checkee_it->first));
 | 
| +    if (this->insert_file_ != NULL){
 | 
| +      fprintf(this->insert_file_, "%s,", checkee_label.name().c_str());
 | 
| +    }
 | 
| +    if (checkee_block->id() != subgraph->original_block()->id()) {
 | 
| +      assm.push(block_graph::Immediate(checkee_block, checkee_offset));
 | 
| +    } else { // checkee is in the same subgraph as checker
 | 
| +      BasicBlock *checkee_bb =
 | 
| +        GetBasicBlockAtOffset(subgraph, checkee_offset);
 | 
| +      DCHECK(checkee_bb != NULL);
 | 
| +      assm.push(block_graph::Immediate(checkee_bb));
 | 
| +    }
 | 
| +
 | 
| +    hash += (*this->precomputed_hashes_)[checkee_it->first] *
 | 
| +      checkee_it->second;
 | 
| +  }
 | 
| +  if (this->insert_file_ != NULL) {
 | 
| +    fprintf(this->insert_file_, "\n");
 | 
| +  }
 | 
| +
 | 
| +  // 2 stack slots holding accumulator for hash and hash of return address
 | 
| +  assm.sub(assm::esp, block_graph::Immediate(0x8));
 | 
| +
 | 
| +  // get size in bytes of the code inserted so far
 | 
| +  uint32_t call_offset = 0;
 | 
| +  uint32_t no_added_instructions = bb->instructions().size() -
 | 
| +    no_orig_bb_instructions;
 | 
| +  auto inst_iter3 = bb->instructions().begin();
 | 
| +  for (uint32_t k = 0; (inst_iter3 != bb->instructions().end()) &&
 | 
| +    (k < no_added_instructions); ++inst_iter3, ++k) {
 | 
| +    call_offset += inst_iter3->size();
 | 
| +  }
 | 
| +  this->basic_block_hash_call_offset_[bb_id] = call_offset;
 | 
| +
 | 
| +  assm.call(block_graph::Immediate(this->hash_block_, 0));
 | 
| +  //keep the index of the pivot byte/instruction
 | 
| +  pivot_instruction_index =
 | 
| +    bb->instructions().size() - no_orig_bb_instructions;
 | 
| +
 | 
| +  assm.data((uint8_t)0);
 | 
| +  //let the result be in the stack so later we can retrieve it
 | 
| +  uint32_t no_pushed_words = 4 * checkee_list.size() + 2;
 | 
| +  assm.add(assm::esp, block_graph::Immediate(no_pushed_words * 4));
 | 
| +  //checksum from the xor function must be added to the add checksum result
 | 
| +  if (*perform_chunk_checks_) {
 | 
| +    assm.pop(assm::ebx);
 | 
| +    assm.add(assm::al, assm::bl);
 | 
| +  } else {
 | 
| +    // If we are not checking chunks we don't need to pop the runtime computed
 | 
| +    // hash of the chunks. However, Syzygy loses the label added to the sub
 | 
| +    // instruction (next instruction) because it tries to disassemble the data
 | 
| +    // byte after the call to the hash function, which leads to different
 | 
| +    // instructions than during execution. Label will be misaligned. Adding
 | 
| +    // these instructions prevents runtime assertion check error about lost
 | 
| +    // labels.
 | 
| +    assm.push(block_graph::Immediate(0,assm::ValueSize::kSize32Bit));
 | 
| +    assm.pop(assm::ebx);
 | 
| +    assm.add(assm::al, assm::bl);
 | 
| +  }
 | 
| +  sub_instruction_index = bb->instructions().size() - no_orig_bb_instructions;
 | 
| +  assm.sub(assm::al, block_graph::Immediate(hash, assm::ValueSize::kSize8Bit));
 | 
| +  assm.data((uint8_t)0x66); // CBW
 | 
| +  assm.data((uint8_t)0x98);
 | 
| +  assm.xor(assm::al, assm::ah);
 | 
| +  assm.sub(assm::al, assm::ah);
 | 
| +  assm.sub(assm::al, block_graph::Immediate(no_abs_references,
 | 
| +    assm::ValueSize::kSize8Bit));
 | 
| +  assm.j(assm::ConditionCode::kAbove,
 | 
| +         block_graph::Immediate(this->response_block_, 0));
 | 
| +
 | 
| +  assm.pop(assm::edx);
 | 
| +  assm.pop(assm::ecx);
 | 
| +  assm.pop(assm::ebx);
 | 
| +  assm.pop(assm::eax);
 | 
| +
 | 
| +  // Add label to begining of integrity check
 | 
| +  label = BlockGraph::Label(std::to_string(bb_id),
 | 
| +    BlockGraph::CODE_LABEL);
 | 
| +  inst_iter = bb->instructions().begin();
 | 
| +  inst_iter->set_label(label);
 | 
| +
 | 
| +  (*this->id_to_label_)[bb_id] = label;
 | 
| +  uint32_t num_no_chunk_added = 0;
 | 
| +  uint32_t ref_instruction_index = 0;
 | 
| +  // Update the size of the basic block to include integrity check code
 | 
| +  // and add the sub instruction label
 | 
| +  uint32_t new_size = 0;
 | 
| +  for (uint32_t s = 0; inst_iter != bb->instructions().end(); ++inst_iter, s++)
 | 
| +  {
 | 
| +    new_size += inst_iter->size();
 | 
| +    auto checkee_label_iter = checkee_label_map.find(s);
 | 
| +    if (checkee_label_iter != checkee_label_map.end()){
 | 
| +      char  *buffer = new char[50];
 | 
| +      sprintf_s(buffer, 50, "block %llu %llu",
 | 
| +                checkee_label_iter->second,bb_id);
 | 
| +      //LOG(INFO) << " Assigned pivot label: " << buffer;
 | 
| +      label = BlockGraph::Label(base::StringPiece(buffer),
 | 
| +        BlockGraph::CODE_LABEL);
 | 
| +      inst_iter->set_label(label);
 | 
| +      delete[] buffer;
 | 
| +    } else if (s == pivot_instruction_index) { // add the pivot label
 | 
| +      char  *buffer = new char[50];
 | 
| +      sprintf_s(buffer, 50, "Pivot:%llu", bb_id);
 | 
| +      //LOG(INFO) << " Assigned pivot label: " << buffer;
 | 
| +      label = BlockGraph::Label(base::StringPiece(buffer),
 | 
| +        BlockGraph::CODE_LABEL);
 | 
| +      inst_iter->set_label(label);
 | 
| +      delete[] buffer;
 | 
| +    } else if (s == sub_instruction_index) { // add the pivot label
 | 
| +      char  buffer[50];
 | 
| +      sprintf_s(buffer, 50, "sub %llu", bb_id);
 | 
| +      //LOG(INFO) << " Assigned pivot label: " << buffer;
 | 
| +      label = BlockGraph::Label(buffer, BlockGraph::CODE_LABEL);
 | 
| +      inst_iter->set_label(label);
 | 
| +    }
 | 
| +    else if (*perform_chunk_checks_ &&
 | 
| +             ref_instruction_index < checkee_list.size() &&
 | 
| +             s == checkee_reference_index[ref_instruction_index]) {
 | 
| +      // add the no_checkee label
 | 
| +      ++ref_instruction_index;
 | 
| +      char  *buffer = new char[50];
 | 
| +      sprintf_s(buffer, 50, "ref %llu", bb_id);
 | 
| +      //LOG(INFO) << " Assigned num chunk label: " << s <<" "<< buffer;
 | 
| +      label = BlockGraph::Label(base::StringPiece(buffer),
 | 
| +        BlockGraph::CODE_LABEL);
 | 
| +      inst_iter->set_label(label);
 | 
| +      num_no_chunk_labels++;
 | 
| +      num_no_chunk_added++;
 | 
| +      delete[] buffer;
 | 
| +    }
 | 
| +  }
 | 
| +  uint32_t old_size = (*this->basic_block_sizes_)[bb_id];
 | 
| +  DCHECK_GT(new_size, static_cast<uint32_t>(0x49));
 | 
| +  DCHECK(old_size < new_size);
 | 
| +  if (*perform_chunk_checks_){
 | 
| +    CHECK_EQ(num_no_chunk_added, checkee_list.size());
 | 
| +  }
 | 
| +  (*this->basic_block_sizes_)[bb_id] = new_size;// - call_offset;
 | 
| +
 | 
| +  //Set iterator to the beginning of the list
 | 
| +  inst_iter = bb->instructions().begin();
 | 
| +
 | 
| +
 | 
| +  checkee_it = checkee_list.begin();
 | 
| +  // Add labels to instructions which push basic block size
 | 
| +  for (uint32_t k = 0; k < checkee_list.size(); ++k) {
 | 
| +    for (uint32_t j = 0; j < checkee_size_index[k]; ++j) {
 | 
| +      inst_iter++;
 | 
| +    }
 | 
| +    char  *buffer=new char[50];
 | 
| +    sprintf_s(buffer, 50, "size %llu %llu", checkee_it->first, bb_id);
 | 
| +    checkee_it++;
 | 
| +    label = BlockGraph::Label(base::StringPiece(buffer),
 | 
| +      BlockGraph::CODE_LABEL);
 | 
| +    inst_iter->set_label(label);
 | 
| +	  delete[] buffer;
 | 
| +    num_size_reference_labels++;
 | 
| +  }
 | 
| +
 | 
| +  delete[] checkee_size_index;
 | 
| +  delete[] checkee_reference_index;
 | 
| +  return; //remove this when you have inner BB references
 | 
| +}
 | 
| +uint32_t num_protecting_blocks = 0;
 | 
| +
 | 
| +bool IntegrityCheckTransform::ProcessAllBlocks(
 | 
| +    const TransformPolicyInterface* policy,
 | 
| +    BlockGraph* block_graph,
 | 
| +    IntegrityCheckTransform::ProcessingType step) {
 | 
| +  BlockOrdering order;
 | 
| +  FlattenCallGraphPostOrder(block_graph, &order);
 | 
| +#if defined PRINT_BLOCK_NAMES
 | 
| +  std::ofstream blocknames_file;
 | 
| +  blocknames_file.open("block_names.csv");
 | 
| +#endif
 | 
| +  auto block_iter = order.begin();
 | 
| +  for (; block_iter != order.end(); ++block_iter) {
 | 
| +    BlockGraph::Block* block = *block_iter;
 | 
| +#if defined PRINT_BLOCK_NAMES
 | 
| +    if (!policy->BlockIsSafeToBasicBlockDecompose(block))
 | 
| +      continue;
 | 
| +    blocknames_file <<block->name()<<",\n";
 | 
| +    continue;
 | 
| +#endif
 | 
| +    if (!ShouldProcessBlock(block, this->target_names_))
 | 
| +      continue;
 | 
| +    // Use the decomposition policy to skip blocks that aren't eligible for
 | 
| +    // basic-block decomposition.
 | 
| +    if (!policy->BlockIsSafeToBasicBlockDecompose(block))
 | 
| +      continue;
 | 
| +
 | 
| +    // Decompose block to basic blocks.
 | 
| +    BasicBlockSubGraph *subgraph = new BasicBlockSubGraph();
 | 
| +    BasicBlockDecomposer bb_decomposer(block, subgraph);
 | 
| +    if (!bb_decomposer.Decompose())
 | 
| +      return false;
 | 
| +
 | 
| +    if (!TransformBasicBlockSubGraph(
 | 
| +      block_graph, subgraph, step)) {
 | 
| +      return false;
 | 
| +    }
 | 
| +
 | 
| +    // Update the block-graph post transform.
 | 
| +    BlockBuilder builder(block_graph);
 | 
| +    if (!builder.Merge(subgraph)) {
 | 
| +      return false;
 | 
| +    }
 | 
| +    ++num_protecting_blocks;
 | 
| +
 | 
| +    const BlockVector& blocks = builder.new_blocks();
 | 
| +    auto new_block = blocks.begin();
 | 
| +    for (; new_block != blocks.end(); ++new_block) {
 | 
| +      // This is needed until the labels refactoring.
 | 
| +      (*new_block)->set_attribute(BlockGraph::BUILT_BY_SYZYGY);
 | 
| +
 | 
| +      if (step == INSERT_CHECKS || INSERT_CHUNK_CHECKS) {
 | 
| +        UpdateLabelToBlockMap(*new_block);
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +#if defined PRINT_BLOCK_NAMES
 | 
| +  blocknames_file.close();
 | 
| +  exit(1);
 | 
| +#endif
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +uint64_t
 | 
| +IntegrityCheckTransform::GetChunkOriginalBlockId(const ChunkInfo *chunk){
 | 
| +  if (chunk->original_block_id_ == 0){
 | 
| +    bool before_chunk_integrity_code_added = true;
 | 
| +    char* chunk_label = MakeChunkLabel(chunk->block_id_, chunk->chunk_index_,
 | 
| +                                       before_chunk_integrity_code_added);
 | 
| +    auto chunk_label_it = label_name_to_block_->find(chunk_label);
 | 
| +    CHECK(chunk_label_it != label_name_to_block_->end());
 | 
| +    delete[] chunk_label;
 | 
| +    chunk->original_block_id_ = chunk_label_it->second.first->id();
 | 
| +  }
 | 
| +  return chunk->original_block_id_;
 | 
| +}
 | 
| +
 | 
| +std::set<uint32_t> IntegrityCheckTransform:: PickChunks(
 | 
| +    const std::vector<ChunkInfo> chunks_vector,
 | 
| +    const std::vector<uint32_t> partition_indexes,
 | 
| +    const uint32_t num_picks,
 | 
| +    const uint64_t checker_block_id,
 | 
| +    const std::vector<uint32_t>::iterator end_chunk_it,
 | 
| +    std::vector<uint32_t>::iterator last_visited_chunk,
 | 
| +    std::set<uint32_t> *unused_chunks){
 | 
| +  std::set<uint32_t> picked_set;
 | 
| +
 | 
| +
 | 
| +  //attempt to pick from unused chunks
 | 
| +  for (auto unused_chunk_it = unused_chunks->begin();
 | 
| +    unused_chunk_it != unused_chunks->end() && picked_set.size() < num_picks;){
 | 
| +    uint64_t chunk_orig_block_id = GetChunkOriginalBlockId(
 | 
| +      &chunks_vector[*unused_chunk_it]);
 | 
| +    if (chunk_orig_block_id != checker_block_id){
 | 
| +      picked_set.insert(*unused_chunk_it);
 | 
| +      unused_chunks->erase(unused_chunk_it);
 | 
| +      unused_chunk_it = unused_chunks->begin();
 | 
| +    }
 | 
| +    else {
 | 
| +      ++unused_chunk_it;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  //iterate over chunks
 | 
| +  for (; last_visited_chunk != end_chunk_it && picked_set.size() < num_picks;
 | 
| +        ++last_visited_chunk){
 | 
| +    uint64_t chunk_orig_block_id = GetChunkOriginalBlockId(
 | 
| +         &chunks_vector[*last_visited_chunk]);
 | 
| +    if (chunk_orig_block_id != checker_block_id){
 | 
| +      picked_set.insert(*last_visited_chunk);
 | 
| +    } else {
 | 
| +      unused_chunks->insert(*last_visited_chunk);
 | 
| +    }
 | 
| +  }//end for
 | 
| +
 | 
| +  // if we don't have enough unique chunk, then we pick from
 | 
| +  // already visited chunks
 | 
| +  if (picked_set.size() < num_picks){
 | 
| +    for (auto index_it = partition_indexes.begin();
 | 
| +        index_it != partition_indexes.end() && picked_set.size() < num_picks;
 | 
| +        ++index_it){
 | 
| +      uint64_t chunk_orig_block_id = GetChunkOriginalBlockId(
 | 
| +          &chunks_vector[*index_it]);
 | 
| +      if (chunk_orig_block_id != checker_block_id){
 | 
| +        picked_set.insert(*index_it);
 | 
| +      }//end if
 | 
| +    }//end for
 | 
| +  }//end if
 | 
| +
 | 
| +  DCHECK_EQ(picked_set.size(), num_picks);
 | 
| +  return picked_set;
 | 
| +}
 | 
| +
 | 
| +std::map<uint64_t, std::set<uint32_t>>
 | 
| +IntegrityCheckTransform::GenerateChunkCombinations(
 | 
| +    const std::vector<ChunkInfo> chunks_vector,
 | 
| +    const float chunk_coverage, const bool enforce_unique_chunks,
 | 
| +    uint32_t *no_chunks_per_block){
 | 
| +
 | 
| +  DCHECK_GT(chunk_coverage, static_cast<float>(0));
 | 
| +  DCHECK_LE(chunk_coverage, static_cast<float>(10));
 | 
| +
 | 
| +
 | 
| +  std::vector<ChunkInfo> temp_chunk_vector = chunks_vector;
 | 
| +  std::vector<uint32_t> temp_noref_chunk_vector;
 | 
| +  std::vector<uint32_t> temp_ref_chunk_vector;
 | 
| +  int i = 0;
 | 
| +  //partition chunks based on their next instruction's absolute reference
 | 
| +  //status
 | 
| +  for (auto chunk_it = temp_chunk_vector.begin();
 | 
| +      chunk_it != temp_chunk_vector.end(); ++chunk_it,++i){
 | 
| +    if (chunk_it->next_instruction_size_ == 0)
 | 
| +      temp_noref_chunk_vector.push_back(i);
 | 
| +    else
 | 
| +      temp_ref_chunk_vector.push_back(i);
 | 
| +  }
 | 
| +
 | 
| +  //shuffle chunks to make sure that checkers check integrity of random blocks
 | 
| +  auto engine = std::default_random_engine{};
 | 
| +  std::shuffle(std::begin(temp_noref_chunk_vector),
 | 
| +               std::end(temp_noref_chunk_vector), engine);
 | 
| +
 | 
| +  std::shuffle(std::begin(temp_ref_chunk_vector),
 | 
| +               std::end(temp_ref_chunk_vector), engine);
 | 
| +
 | 
| +  //compute number of chunks according to the input coverage
 | 
| +  uint32_t total_chunk_checks = chunks_vector.size() * chunk_coverage;
 | 
| +  uint32_t num_ref_chunks = 0;
 | 
| +  int32_t num_noref_chunks = 0;
 | 
| +  //preference is to pick chunks with abs address at the end
 | 
| +  if (temp_ref_chunk_vector.size() >= total_chunk_checks) {
 | 
| +    num_ref_chunks = total_chunk_checks;
 | 
| +    num_noref_chunks = 0;
 | 
| +  } else if(chunk_coverage <= 1.0f) {
 | 
| +    num_ref_chunks = temp_ref_chunk_vector.size();
 | 
| +    num_noref_chunks = total_chunk_checks - num_ref_chunks;
 | 
| +  } else {
 | 
| +    num_ref_chunks = std::min(
 | 
| +        static_cast<uint32_t>(temp_ref_chunk_vector.size()* chunk_coverage),
 | 
| +        total_chunk_checks);
 | 
| +    num_noref_chunks = total_chunk_checks - num_ref_chunks;
 | 
| +  }
 | 
| +
 | 
| +  uint32_t no_chunks_per_checker = total_chunk_checks /
 | 
| +      checker_to_checkee_map_->size();
 | 
| +
 | 
| +  //the base address cancelation only works for even number of chunks
 | 
| +  if (no_chunks_per_checker % 2 != 0){
 | 
| +    LOG(INFO) << "current coverage does not generate even number of chunks, "
 | 
| +              << "thus the number of chunks was incremented!";
 | 
| +    no_chunks_per_checker++;
 | 
| +  }
 | 
| +
 | 
| +  LOG(INFO) << "chunk coverage:" << chunk_coverage;
 | 
| +  LOG(INFO) << "#all chunks:" << total_chunk_checks;
 | 
| +  LOG(INFO) << "#chunks per checker:" << no_chunks_per_checker;
 | 
| +  LOG(INFO) << "#+chunks (with absolute instruction):" << num_ref_chunks;
 | 
| +  LOG(INFO) << "#^chunks (no absolute instruction):" << num_noref_chunks;
 | 
| +  *no_chunks_per_block = no_chunks_per_checker;
 | 
| +
 | 
| +  DCHECK_GE(no_chunks_per_checker, static_cast<uint32_t>(1));
 | 
| +
 | 
| +  auto checker_it = checker_to_checkee_map_->begin();
 | 
| +  std::set<uint32_t> unused_noref_chunks;
 | 
| +  std::set<uint32_t> unused_ref_chunks;
 | 
| +  std::map<uint64_t, std::set<uint32_t>> temp_assignment_map;
 | 
| +  auto noref_chunk_it = temp_noref_chunk_vector.begin();
 | 
| +  auto ref_chunk_it = temp_ref_chunk_vector.begin();
 | 
| +
 | 
| +  auto noref_chunk_end_it = temp_noref_chunk_vector.end();
 | 
| +  auto ref_chunk__end_it = temp_ref_chunk_vector.end();
 | 
| +
 | 
| +  while (checker_it != checker_to_checkee_map_->end()){
 | 
| +    std::set<uint32_t> chunks;
 | 
| +    uint64_t bb_id = checker_it->first;
 | 
| +    BlockGraph::Label checker_label = (*this->id_to_label_)[bb_id];
 | 
| +    auto checker_label_it = label_name_to_block_->find(checker_label.name());
 | 
| +    CHECK(checker_label_it != label_name_to_block_->end());
 | 
| +    uint64_t checker_block_id = checker_label_it->second.first->id();
 | 
| +    //first pick from no reference partition
 | 
| +    if (num_noref_chunks > 0){
 | 
| +      chunks = PickChunks(chunks_vector, temp_noref_chunk_vector,
 | 
| +                          no_chunks_per_checker, checker_block_id,
 | 
| +                          noref_chunk_end_it, noref_chunk_it,
 | 
| +                          &unused_noref_chunks);
 | 
| +      num_noref_chunks -= no_chunks_per_checker;
 | 
| +    } else { // pick the rest of chunks from reference chunks
 | 
| +      chunks = PickChunks(chunks_vector, temp_ref_chunk_vector,
 | 
| +                          no_chunks_per_checker, checker_block_id,
 | 
| +                          ref_chunk__end_it, ref_chunk_it,
 | 
| +                          &unused_ref_chunks);
 | 
| +    }
 | 
| +    temp_assignment_map[bb_id] = chunks;
 | 
| +    ++checker_it;
 | 
| +  }
 | 
| +
 | 
| +  return temp_assignment_map;
 | 
| +}
 | 
| +
 | 
| +void IntegrityCheckTransform::GenerateBasicBlockCombinations() {
 | 
| +  int partition_num = 1;
 | 
| +  int nr_size_one = 0;
 | 
| +  srand(time(NULL));
 | 
| +
 | 
| +  FILE* part_file = NULL;
 | 
| +  fopen_s(&part_file, "partitions.csv", "w");
 | 
| +  if (part_file == NULL)
 | 
| +    LOG(INFO) << "Cannot open partition file";
 | 
| +
 | 
| +  auto it_part = this->partition_map_.begin();
 | 
| +  for (; it_part != this->partition_map_.end(); ++it_part) {
 | 
| +    LOG(INFO) << "Partition #" << partition_num << " : ";
 | 
| +    LOG(INFO) << (*it_part).second.size();
 | 
| +
 | 
| +    if ((*it_part).second.size() <= 1) {
 | 
| +      /*
 | 
| +      std::list<std::set<uint64_t>> checkOrder;
 | 
| +      checkOrder.push_back((*it_part).second);
 | 
| +      checkOrder.push_back((*it_part).second);
 | 
| +      */
 | 
| +      ++nr_size_one;
 | 
| +    } else { // there are multiple BBs in this partition
 | 
| +      PopulateCheckMaps((*it_part).second);
 | 
| +    }
 | 
| +
 | 
| +    ++partition_num;
 | 
| +  }
 | 
| +
 | 
| +  // check if any blocks are not checking anything
 | 
| +  auto checker_it = id_to_label_->begin();
 | 
| +  for (; checker_it != id_to_label_->end(); ++checker_it){
 | 
| +    auto checkee_list = (*checker_to_checkee_map_)[checker_it->first];
 | 
| +    if (checkee_list.size() == 0) { // then this BB is not checking other BBs.
 | 
| +      // Find a pair of basic blocks to check.
 | 
| +      it_part = this->partition_map_.begin();
 | 
| +      std::map<uint64_t, int> checkee_map;
 | 
| +      bool found_pair = false;
 | 
| +
 | 
| +      for (; it_part != this->partition_map_.end(); ++it_part) {
 | 
| +        if (it_part->second.size() < 2) // partition is too small
 | 
| +          continue;
 | 
| +        // Check if partition has at least 2 BBs that are not in the same block
 | 
| +        // as the checker
 | 
| +        uint32_t checker_block = (uint32_t) checker_it->first;
 | 
| +        std::set<uint64_t> bbs_in_different_block;
 | 
| +        auto part_block_it = it_part->second.begin();
 | 
| +
 | 
| +        for (; part_block_it != it_part->second.end(); ++part_block_it) {
 | 
| +          if (checker_block != ((uint32_t)*part_block_it))
 | 
| +            bbs_in_different_block.insert(*part_block_it);
 | 
| +        }
 | 
| +        if (bbs_in_different_block.size() > 1) { // use first 2 BBs
 | 
| +          auto checkee_it = bbs_in_different_block.begin();
 | 
| +          checkee_map[*checkee_it] = 1;
 | 
| +          checkee_it++;
 | 
| +          checkee_map[*checkee_it] = -1;
 | 
| +          found_pair = true;
 | 
| +          break;
 | 
| +        }
 | 
| +      }
 | 
| +
 | 
| +      DCHECK(checkee_map.size() == 2);
 | 
| +      (*checker_to_checkee_map_)[checker_it->first] = checkee_map;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  fclose(part_file);
 | 
| +
 | 
| +  LOG(INFO) << "nr_size_one : " << nr_size_one;
 | 
| +}
 | 
| +
 | 
| +bool IntegrityCheckTransform::TransformBlockGraph(
 | 
| +    const TransformPolicyInterface* policy,
 | 
| +    BlockGraph* block_graph,
 | 
| +    BlockGraph::Block* header_block) {
 | 
| +  fopen_s(&this->pfile_, "integrityChecks.csv", "w");
 | 
| +  if (this->pfile_ == NULL)
 | 
| +    LOG(INFO) << "Cannot open graph file";
 | 
| +
 | 
| +  if (!TransformBasicBlockSubGraph(
 | 
| +      block_graph, NULL,
 | 
| +      IntegrityCheckTransform::ADD_HASH_AND_RESPONSE)) {
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  fopen_s(&this->prefile_, "preChecks.csv", "w");
 | 
| +  if (this->prefile_ == NULL)
 | 
| +    LOG(INFO) << "Cannot open graph file";
 | 
| +
 | 
| +  num_protecting_blocks = 0;
 | 
| +  // Compute the hash of all basic blocks in all blocks of the block_graph.
 | 
| +  // This hash will be hard-coded inside the integrity-check-code inserted in
 | 
| +  // each basic block. It will be compared with the hash computed at runtime.
 | 
| +  if (!ProcessAllBlocks(policy, block_graph,
 | 
| +      IntegrityCheckTransform::PRECOMPUTE_HASHES))
 | 
| +    return false;
 | 
| +
 | 
| +  if(num_protecting_blocks, this->target_names_.size())
 | 
| +    LOG(INFO) << "Failed to find some targets, protected blocks:"
 | 
| +              << num_protecting_blocks << " provided:"
 | 
| +              << this->target_names_.size();
 | 
| +
 | 
| +  fclose(this->prefile_);
 | 
| +
 | 
| +  GenerateBasicBlockCombinations();
 | 
| +
 | 
| +  fclose(this->pfile_);
 | 
| +
 | 
| +  int nr_not_checked = 0;
 | 
| +  int total_number = 0;
 | 
| +  //Print all nodes not checked by any other nodes
 | 
| +  auto map_it = this->precomputed_hashes_->begin();
 | 
| +  for (; map_it != this->precomputed_hashes_->end(); ++map_it) {
 | 
| +    if (this->is_bb_checked_map_.find((*map_it).first) ==
 | 
| +        this->is_bb_checked_map_.end()) {
 | 
| +      //LOG(INFO) << "BB " << (*mapIt).first << " is not checked ";
 | 
| +      ++nr_not_checked;
 | 
| +    }
 | 
| +    ++total_number;
 | 
| +  }
 | 
| +
 | 
| +  int nr_3_combo_found = 0;
 | 
| +  LOG(INFO) << "Combo 3 Found: " << nr_3_combo_found;
 | 
| +  LOG(INFO) << "Not Checked: " << nr_not_checked;
 | 
| +  LOG(INFO) << "Total number:" << total_number;
 | 
| +
 | 
| +  fopen_s(&this->insert_file_, "inserted-integrityChecks.csv", "w");
 | 
| +  if (this->insert_file_ == NULL)
 | 
| +    LOG(INFO) << "Cannot open graph file";
 | 
| +
 | 
| +  GenerateLabelToBlockMap(block_graph);
 | 
| +
 | 
| +  // Add the assembly code representing integrity checks in each basic block
 | 
| +  // that was picked to perform a dynamic check in the combination of basic
 | 
| +  // blocks (see method GenerateBasicBlockCombinations()).
 | 
| +  if (!ProcessAllBlocks(policy, block_graph,
 | 
| +      IntegrityCheckTransform::INSERT_CHECKS))
 | 
| +    return false;
 | 
| +
 | 
| +  fclose(this->insert_file_);
 | 
| +  LOG(INFO) << "Inserting checks done";
 | 
| +
 | 
| +  fopen_s(&this->fix_file_, "fixIntegrityChecks.csv", "w");
 | 
| +  if (this->fix_file_ == NULL)
 | 
| +    LOG(INFO) << "Cannot open graph file";
 | 
| +
 | 
| +  if (*perform_chunk_checks_){
 | 
| +    if (!ProcessAllBlocks(policy, block_graph,
 | 
| +      IntegrityCheckTransform::COMPUTE_CHUNKS))
 | 
| +      return false;
 | 
| +    LOG(INFO) << "Computing integrity inter block chunks is done";
 | 
| +
 | 
| +    //Require label update
 | 
| +    GenerateLabelToBlockMap(block_graph);
 | 
| +
 | 
| +
 | 
| +    //shuffle up integrity chunks
 | 
| +    *ic_chunk_checker_to_checkee_map_ = GenerateChunkCombinations(
 | 
| +      *ic_block_reference_free_chunks,
 | 
| +      chunk_checking_coverage,
 | 
| +      kForceUniqueChunks,
 | 
| +      &num_chunks_per_block);
 | 
| +
 | 
| +    LOG(INFO) << "Shuffling integrity inter block chunks is done";
 | 
| +
 | 
| +    if (!ProcessAllBlocks(policy, block_graph, INSERT_CHUNK_CHECKS))
 | 
| +      return false;
 | 
| +    LOG(INFO) << "Inserting chunk checks is done";
 | 
| +  } else {
 | 
| +    LOG(INFO) << "Xor chunk protection is switched off.";
 | 
| +  }
 | 
| +  //Require label update
 | 
| +  GenerateLabelToBlockMap(block_graph);
 | 
| +
 | 
| +  // Patch inter block references that were broken by the insertion of
 | 
| +  // integrity checks.
 | 
| +  if (!ProcessAllBlocks(policy, block_graph,
 | 
| +      IntegrityCheckTransform::PATCH_REFERENCES_SIZES)) {
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  LOG(INFO) << "Patching block references and sizes are done";
 | 
| +  LOG(INFO) << "Elapsed seconds in patching chunks(due to size changes:"
 | 
| +  <<elapsed_secs_in_patching_chunks;
 | 
| +  CHECK_EQ(num_chunk_reference_labels , num_chunk_reference_patched_labels);
 | 
| +  CHECK_EQ(num_no_chunk_labels, num_no_chunk_patched_labels);
 | 
| +  CHECK_EQ(num_size_reference_labels, num_size_reference_patched_labels);
 | 
| +  if (num_size_reference_labels != num_size_reference_patched_labels){
 | 
| +    LOG(ERROR) << "Some size labels were not patched, total lables:" <<
 | 
| +      num_size_reference_labels << " patched:"
 | 
| +      << num_size_reference_patched_labels;
 | 
| +  }
 | 
| +
 | 
| +  //Require label update
 | 
| +  GenerateLabelToBlockMap(block_graph);
 | 
| +
 | 
| +  fclose(this->fix_file_);
 | 
| +
 | 
| +  std::map<uint64_t, uint32_t> checkee_count_checker;
 | 
| +  std::ofstream myfile;
 | 
| +  myfile.open("graph.csv");
 | 
| +  auto checker_it = this->checker_to_checkee_map_->begin();
 | 
| +  for (; checker_it != this->checker_to_checkee_map_->end();
 | 
| +       ++checker_it) {
 | 
| +	  for (auto checkee_it = checker_it->second.begin();
 | 
| +	       checkee_it != checker_it->second.end();
 | 
| +		     ++checkee_it) {
 | 
| +		  myfile << checker_it->first << "," << checkee_it->first << "\n";
 | 
| +		  ++checkee_count_checker[checkee_it->first];
 | 
| +	  }
 | 
| +  } //end for
 | 
| +  myfile.close();
 | 
| +  myfile.open("notbeingchecked.csv");
 | 
| +  checker_it = checker_to_checkee_map_->begin();
 | 
| +  for (; checker_it != this->checker_to_checkee_map_->end();
 | 
| +       ++checker_it) {
 | 
| +	  if (checkee_count_checker.find(checker_it->first) ==
 | 
| +		    checkee_count_checker.end()) {
 | 
| +		  myfile << checker_it->first << "\n";
 | 
| +	  }
 | 
| +  }
 | 
| +  myfile.close();
 | 
| +#if defined COMPUTE_CHECKER_SIZE
 | 
| +  myfile.open("checkersize.csv");
 | 
| +  myfile << "total checker size(byte):"<<total_checker_size;
 | 
| +  myfile.close();
 | 
| +#endif
 | 
| +  myfile.open("chunkinfo.csv");
 | 
| +  myfile << "total chunks:" << ic_block_reference_free_chunks->size();
 | 
| +  myfile << "total checked chunks:" << checker_to_checkee_map_->size() *
 | 
| +                                       num_chunks_per_block;
 | 
| +  myfile.close();
 | 
| +  myfile.open("chunkgraph.csv");
 | 
| +  for (auto chunk_checker_it = ic_chunk_checker_to_checkee_map_->begin();
 | 
| +       chunk_checker_it != ic_chunk_checker_to_checkee_map_->end();
 | 
| +	     ++chunk_checker_it) {
 | 
| +	  for (auto chunk_checkee_it = chunk_checker_it->second.begin();
 | 
| +	  chunk_checkee_it != chunk_checker_it->second.end();
 | 
| +		  ++chunk_checkee_it) {
 | 
| +		  myfile << chunk_checker_it->first << "," <<
 | 
| +			  (*ic_block_reference_free_chunks)[*chunk_checkee_it].block_id_
 | 
| +			  <<"\n";
 | 
| +	  }
 | 
| +  }
 | 
| +  myfile.close();
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +IntegrityCheckTransform::~IntegrityCheckTransform() {
 | 
| +  ic_block_reference_free_chunks->clear();
 | 
| +  ic_block_chunk_index_map_->clear();
 | 
| +  ic_chunk_checker_to_checkee_map_->clear();
 | 
| +  //_CrtDumpMemoryLeaks();
 | 
| +}
 | 
| +
 | 
| +// static vars
 | 
| +const char IntegrityCheckTransform::kTransformName[] =
 | 
| +"IntegrityCheckTransform";
 | 
| +
 | 
| +}// namespace protect
 | 
| 
 |