| Index: syzygy/experimental/protect/protect_lib/integrity_check_transform.h
|
| diff --git a/syzygy/experimental/protect/protect_lib/integrity_check_transform.h b/syzygy/experimental/protect/protect_lib/integrity_check_transform.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8755e06e55149b7aa40c561aee96467b94bcdda3
|
| --- /dev/null
|
| +++ b/syzygy/experimental/protect/protect_lib/integrity_check_transform.h
|
| @@ -0,0 +1,372 @@
|
| +// 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.
|
| +
|
| +#ifndef SYZYGY_PROTECT_PROTECT_LIB_INTEGRITY_CHECK_TRANSFORM_H_
|
| +#define SYZYGY_PROTECT_PROTECT_LIB_INTEGRITY_CHECK_TRANSFORM_H_
|
| +
|
| +#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS 1
|
| +
|
| +#include "syzygy/block_graph/basic_block.h"
|
| +#include "syzygy/block_graph/basic_block_subgraph.h"
|
| +#include "syzygy/block_graph/block_graph.h"
|
| +#include "syzygy/block_graph/transforms/named_transform.h"
|
| +#include "syzygy/experimental/protect/protect_lib/protect_utils.h"
|
| +
|
| +namespace protect {
|
| +
|
| +class IntegrityCheckTransform
|
| + : public block_graph::transforms::
|
| + NamedBlockGraphTransformImpl<IntegrityCheckTransform> {
|
| + public:
|
| + typedef block_graph::BlockGraph BlockGraph;
|
| + typedef block_graph::BasicCodeBlock BasicCodeBlock;
|
| + typedef block_graph::BasicBlockSubGraph BasicBlockSubGraph;
|
| + typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
|
| +
|
| + enum ProcessingType {
|
| + ADD_HASH_AND_RESPONSE,
|
| + PRECOMPUTE_HASHES,
|
| + INSERT_CHECKS,
|
| + COMPUTE_CHUNKS,
|
| + INSERT_CHUNK_CHECKS,
|
| + PATCH_REFERENCES_SIZES,
|
| + PATCH_PIVOT
|
| + };
|
| +
|
| + enum ReferenceLabelType {
|
| + Original_Block_Chunk,
|
| + //Refers to a placeholder label that only after adding all integrity checks
|
| + //it will be determined
|
| + Integrity_Block_Chunk
|
| + };
|
| +
|
| +// The transform name.
|
| + static const char kTransformName[];
|
| +
|
| +// Constructor.
|
| + explicit IntegrityCheckTransform(FlummoxConfig* config) {
|
| + for (const std::string& target : config->target_set())
|
| + target_names_[target] = false;
|
| +
|
| + this->chunk_checking_coverage = config->chunk_checking_coverage();
|
| + if (chunk_checking_coverage == 0.0f){
|
| + bool *pcc = config->perform_chunk_checks();
|
| + *pcc = false;
|
| + }
|
| + this->basic_block_sizes_ = config->basic_block_sizes();
|
| + this->checker_to_checkee_map_ = config->checker_to_checkee_map();
|
| + this->ic_block_chunk_index_map_ = config->ic_block_chunk_index_map();
|
| + this->ic_block_reference_free_chunks =
|
| + config->ic_block_reference_free_chunks();
|
| + this->ic_chunk_checker_to_checkee_map_ =
|
| + config->ic_chunk_checker_to_checkee_map();
|
| + this->id_to_label_ = config->id_to_label();
|
| + this->label_name_to_block_ = config->label_name_to_block();
|
| + this->nr_hashes_patched_ = config->nr_hashes_patched();
|
| + this->perform_chunk_checks_ = config->perform_chunk_checks();
|
| + this->precomputed_hashes_ = config->precomputed_hashes();
|
| + this->chunk_checking_coverage = config->chunk_checking_coverage();
|
| + }
|
| +
|
| +// This is the main body of the transform. The transform decomposes each
|
| +// block into a subgraph, applies the series of transform and rebuilds the
|
| +// subgraph into a block.
|
| +//
|
| +// @param policy The policy object restricting how the transform is applied.
|
| +// @param block_graph the block graph being transformed.
|
| +// @param header_block the block to process.
|
| +// @returns true on success, false otherwise.
|
| + virtual bool TransformBlockGraph(const TransformPolicyInterface* policy,
|
| + BlockGraph* block_graph,
|
| + BlockGraph::Block* header_block) override;
|
| +
|
| + ~IntegrityCheckTransform();
|
| +
|
| + protected:
|
| + // Replaces the first basic block reference inside an instruction @p with a
|
| + // reference to a new block.
|
| + // @param inst_itr the instruction that contains the basic block reference.
|
| + // @param new_block the block to which the new reference should point to.
|
| + // @param new_offset the offset to which the new reference should have.
|
| + // @param use_new_block flag indicating whether the new_block should be used.
|
| + void PatchBlockReference(
|
| + block_graph::BasicBlock::Instructions::iterator inst_itr,
|
| + block_graph::BlockGraph::Block* new_block,
|
| + block_graph::BlockGraph::Offset new_offset,
|
| + bool use_new_block);
|
| +
|
| +// Constant value defining unique chunks should be selected in the chunk
|
| +// combinator function
|
| + const bool kForceUniqueChunks = true;
|
| +
|
| +// Constant value defining the number of chunks within original block
|
| +// that each checker must check
|
| + uint32_t num_chunks_per_block = 0;
|
| +
|
| + bool* perform_chunk_checks_;
|
| + float chunk_checking_coverage =1.0f;
|
| +
|
| + // Creates a label to block map for all blocks in block graph @p.
|
| + void GenerateLabelToBlockMap(BlockGraph *bgraph);
|
| +
|
| +// Update label to block map only with changes in the given block @p.
|
| + void UpdateLabelToBlockMap(BlockGraph::Block *block);
|
| +
|
| +// Computes and writes the Q matrix to an output file. Also generates
|
| +// combinations of basic blocks such that references to absolute addresses
|
| +// cancel out. Finally it picks a random basic block to dynamically check
|
| +// if the combination of precomputed hashes matches the runtime hashes.
|
| + void GenerateBasicBlockCombinations();
|
| +
|
| +// Assigns random chunks(without absolute references) to basic blocks
|
| +//@chunks_vector - input proccessed chunks for assignment
|
| +//@assignment_map - output assigned chunks per basic block
|
| +//@no_chunks_per_checker - defines the number of chunks
|
| +// that being assigned to a checker
|
| +//@force_all_chunk_checks - This removes selected chunks from the random list
|
| +//so they cannot be picked more than once
|
| + std::map<uint64_t, std::set<uint32_t>> GenerateChunkCombinations(
|
| + const std::vector<ChunkInfo> chunks_vector,
|
| + const float chunk_coverage, const bool enforce_unique_chunks,
|
| + uint32_t *no_chunks_per_block);
|
| +
|
| +// Iterates over all blocks of the block graph and decomposes them into
|
| +// basic block subgraphs, which are then processed individually according
|
| +// to the step parameter. The file parameter is optionally used to store
|
| +// results of the processing.
|
| + bool IntegrityCheckTransform::ProcessAllBlocks(
|
| + const TransformPolicyInterface* policy,
|
| + BlockGraph* block_graph,
|
| + IntegrityCheckTransform::ProcessingType step);
|
| +
|
| +
|
| +// Adds the assembly code which performs the integrity check
|
| +// @param bb - the basic block where the integrity check will be inserted
|
| +// @param checked_bb - the basic block that is actually checked
|
| +// @param offset_sizes a list of (offset, size) pairs that indicate at which
|
| +// offset from the beginning of the BB and how many bytes to hash
|
| +// @param hash the value of the precomputed code hash
|
| +// @param placeholder_flag a flag indicating if we need to insert
|
| +// a placeholder in this basic block or not
|
| + void AddIntegrityCheckCode(BasicCodeBlock* bb,
|
| + BasicBlockSubGraph* subgraph,
|
| + BlockGraph *block_graph);
|
| +
|
| +
|
| +// Process the basic block subgraph inserting the hash function and the
|
| +// integrity-checks
|
| +// @param bgraph - block graph from where the subgraph was taken
|
| +// @param subgraph - subgraph containing basic blocks we want to transform
|
| +// @param modifyCode - flag that indicates whether the PE should be modified
|
| +// @return - true if the transformation was successfull, false otherwise
|
| + bool TransformBasicBlockSubGraph(
|
| + BlockGraph* bgraph,
|
| + BasicBlockSubGraph* subgraph,
|
| + IntegrityCheckTransform::ProcessingType step);
|
| +
|
| +// Adds reference to address
|
| +// @param bgraph - the block graph from where the subgraph was taken
|
| +// @param block - block where to make the reference
|
| +// @param offset - offset of reference in block
|
| +// @return the block containing the response function
|
| + BlockGraph::Block* AddReference(BlockGraph* bgraph, int dll_id);
|
| +
|
| +// Adds vector index of a chunk into the chunk index map
|
| +// this index map is useful in chunk patching, basically O(n) to O(log(n))
|
| +// @param bb_id - basic block id where the chunk is located
|
| +// @param chunk_index - index of the chunk within the basic block
|
| +// @param vector_index - index of the chunk within the full chunks vector
|
| + void IntegrityCheckTransform::AddChunkIntoIndexMap(
|
| + const uint64_t bb_id,
|
| + const uint32_t chunk_index,
|
| + const uint32_t vector_index);
|
| +
|
| +// Iterates over instructions and places label over reference free
|
| +// chunks. Appends discovered chunks references to
|
| +// ic_block_reference_free_chunks
|
| +// @bb_id - integrity checker block id
|
| +// @bb_instruction - reference to basic block instruction set
|
| + void ComputeChunks(BasicCodeBlock* bb);
|
| +// Retrieves the original block id that chunk is located in, this function
|
| +// relies on the label_name_to_block_ map
|
| +// @chunk - instruction chunk info to find its original block
|
| + uint64_t GetChunkOriginalBlockId(const ChunkInfo *chunk);
|
| +
|
| +// Selects chunks from the provided partition index from blocks different from
|
| +// the checker block. It tries to use unique chunks, but if not enough chunks to
|
| +// pick, it reuses the used chunks
|
| +// @chunks_vector - vector of all chunks
|
| +// @partition_indexes - the indexes that chunk can be selected from
|
| +// (partitioning)
|
| +// @num_picks - number of chunks to be picked
|
| +// @checker_block_id - original block of the checker
|
| +// @used - map of the used chunks
|
| + 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);
|
| +// Computes the hash that will be hard coded in the binary
|
| +// @param bb - basic block for which we want to compute the hash
|
| +// @param offset_sizes - list containing pairs of offsets and number of bytes
|
| +// to hash by the hash function in order to obtain the same hash at runtime
|
| +// @return - the hash value of the code
|
| + uint8_t PrecomputeHash(BasicCodeBlock* bb,
|
| + std::list<uint32_t> *offset_sizes,
|
| + BasicBlockSubGraph* subgraph);
|
| +
|
| + // Retrieves the number of absolute references in the basic block indicated
|
| + // by @p. This coincides with its index in the partition map.
|
| + uint8_t IntegrityCheckTransform::GetPartitionKey(uint64_t bb_id);
|
| +
|
| +// Adds the assembly code which performs the chunk integrity check
|
| +// @param bb - the basic block where the integrity check will be inserted
|
| +// @param bgraph - block graph from where the subgraph was taken
|
| +// @param subgraph - subgraph containing basic blocks we want to transform
|
| + bool AddChunkIntegrityCheckCode(
|
| + BasicCodeBlock* bb,
|
| + BasicBlockSubGraph* subgraph,
|
| + BlockGraph *block_graph);
|
| +
|
| +// Patches block references and sizes within the integrity checker assembly code
|
| +// @param bb - the basic block where the patching will be done
|
| +// @param bgraph - block graph from where the subgraph was taken
|
| +// @param subgraph - subgraph containing basic blocks we want to transform
|
| + bool PatchBlockReferencesAndSizes(
|
| + BasicCodeBlock* bb,
|
| + BasicBlockSubGraph* subgraph,
|
| + BlockGraph *block_graph);
|
| +
|
| +// Updates the chunk's hash corresponding to the given inputs
|
| +// with the value changes
|
| +// @param bb - the basic block where the patching will be done
|
| +// @param old_size - previous size value in included in the chunk
|
| +// @param new_size - replacement size value for the chunk
|
| +// @param chunk_bb_id - bb_id of the chunk
|
| +// @param chunk_index - index of the chunk within the basic block
|
| + bool 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);
|
| +
|
| +// Randomly picks a basic block to check-the given tuple of basic blocks.
|
| +// Outputs the id of the basic block that was picked.
|
| + bool RandomlySelectChecker(std::list<uint32_t> tuple_blocks,
|
| + uint64_t *checker_id);
|
| +
|
| +// Randomly assigns checkers to checkee tuples
|
| + void PopulateCheckMaps(std::set<uint64_t> part_block);
|
| +
|
| +// Checks if all basic blocks in the given map are protected by integrity
|
| +// checks
|
| + bool AllBasicBlocksChecked(std::map<std::set<uint64_t>, int> checkOrder);
|
| +
|
| +// Fills in the partition key multiset with names of the references.
|
| +// @param instr assembly instruction references to basic blocks.
|
| +// @param partitionKey set to fill out.
|
| +// @return true if the instruction has references, false otherwise.
|
| + bool PopulatePartitionKey(const block_graph::Instruction instr,
|
| + uint8_t *num_abs_references);
|
| +
|
| +// Reference to the block that begins the computation of code hashes
|
| + block_graph::BlockGraph::Block *hash_block_;
|
| +
|
| +// Reference to the block that begins the computation of code xor hashes
|
| + block_graph::BlockGraph::Block *xhash_block_;
|
| +
|
| +// Reference to the block where the call to the reponse function is
|
| + block_graph::BlockGraph::Block *response_block_;
|
| +
|
| +// Map of original custom basic block ID to a label
|
| + std::map<uint64_t, BlockGraph::Label>* id_to_label_;
|
| +
|
| +// Map holding partition of relocation affected blocks
|
| + std::map<uint8_t, std::set<uint64_t>> partition_map_;
|
| +
|
| +// Map holding precomputed hashes of original BB
|
| + std::map<uint64_t, uint32_t>* precomputed_hashes_;
|
| +
|
| +// Map from BB address to its size
|
| + std::map<uint64_t, uint32_t>* basic_block_sizes_;
|
| +
|
| +// Map containing the offset of the call to the hash function in the bb
|
| + std::map<uint64_t, uint32_t> basic_block_hash_call_offset_;
|
| +
|
| +// Map containing true if basic block has a refenrece to another block
|
| + std::map<uint64_t, bool> basic_block_has_ref_;
|
| +
|
| +// Map indicating which BB is checked by which other BBs
|
| + std::map<uint64_t, uint32_t> is_bb_checked_map_;
|
| +
|
| +// Map indicating which BBs will be hashed by the checker
|
| + std::map<uint64_t, std::map<uint64_t, int>>* checker_to_checkee_map_;
|
| +
|
| +// Vector indicating chunks within Integrity checker block without absolute
|
| +// references
|
| + std::vector<ChunkInfo>* ic_block_reference_free_chunks;
|
| +// Map for retrieveing chunk id(unit32) from bb_id + chunk_index
|
| +// useful in patching bb chunks
|
| + std::map<uint64_t, uint32_t>* ic_block_chunk_index_map_;
|
| +
|
| +// Map< CheckerId, set < Chunk indexes > >
|
| + std::map<uint64_t, std::set<uint32_t>>* ic_chunk_checker_to_checkee_map_;
|
| +
|
| +// File where to put the Q matrix
|
| + FILE *prefile_;
|
| + FILE *pfile_;
|
| + FILE *insert_file_= NULL;
|
| + FILE *fix_file_;
|
| +
|
| +// TODO: remove vector of BBSGs
|
| + std::vector<block_graph::BasicBlockSubGraph*> subgraph_vector_;
|
| +
|
| +// Map of label name to the number of bytes all references to it should be
|
| +// adjusted
|
| + std::map<BlockGraph::Label, uint32_t> adjust_label_by_offset_;
|
| +
|
| +// This attribute keeps track of the address range that should be protected
|
| +// by integrity-checks
|
| + std::map<std::string, bool> target_names_;
|
| +
|
| +
|
| +// Number of precomputed hash values which were patched
|
| + int* nr_hashes_patched_;
|
| +
|
| + uint32_t num_no_chunk_patched_labels = 0;
|
| + uint32_t num_no_chunk_labels = 0;
|
| + uint32_t num_chunk_reference_labels = 0;
|
| + uint32_t num_chunk_reference_patched_labels = 0;
|
| +
|
| + uint32_t num_xor_labels = 0;
|
| + uint32_t num_xor_patched_labels = 0;
|
| +
|
| + uint32_t num_size_reference_labels = 0;
|
| + uint32_t num_size_reference_patched_labels = 0;
|
| +
|
| + double elapsed_secs_in_patching_chunks = 0;
|
| +
|
| +// Map from ID of DLL to BlockReference
|
| + std::map<int, std::pair<uint32_t, size_t>> dll_id_to_block_reference_;
|
| +
|
| + std::map<std::string, std::pair<BlockGraph::Block*, uint32_t>>*
|
| + label_name_to_block_;
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(IntegrityCheckTransform);
|
| + };
|
| +
|
| +}// namespace protect
|
| +
|
| +#endif// SYZYGY_PROTECT_PROTECT_LIB_INTEGRITY_CHECK_TRANSFORM_H_
|
|
|