class_docstr: Implementation of the following white-box attacks related to PE malware crafting:
      1) Append based attacks (example paper link: https://arxiv.org/abs/1810.08280)
      2) Section insertion attacks (example paper link: https://arxiv.org/abs/2008.07125)
      3) Slack manipulation attacks (example paper link: https://arxiv.org/abs/1810.08280)
      4) DOS Header Attacks (example paper link: https://arxiv.org/abs/1901.03583)
class_docstr_tok: ["Implementation","of","the","following","white-box","attacks","related","to","PE","malware","crafting",":","1",")","Append","based","attacks","(","example","paper","link",":","https",":","\/\/arxiv.org\/abs\/1810.08280",")","2",")","Section","insertion","attacks","(","example","paper","link",":","https",":","\/\/arxiv.org\/abs\/2008.07125",")","3",")","Slack","manipulation","attacks","(","example","paper","link",":","https",":","\/\/arxiv.org\/abs\/1810.08280",")","4",")","DOS","Header","Attacks","(","example","paper","link",":","https",":","\/\/arxiv.org\/abs\/1901.03583",")"]
docstr: Based on the l0 budget and the provided allowable perturbation regions we iteratively mark regions of the PE
  file for modification until we exhaust our budget.
  
  :param input_perturb_sizes: The size of the regions we can perturb.
  :param input_perturbation_size: The total amount of perturbation allowed on a specific sample.
  :param automatically_append: If we want to automatically append unused perturbation on the end of the malware.
  :return perturbation_size: Remaining perturbation (if any)
  :return perturb_sizes: Potentially adjusted sizes of the locations in the PE file we can perturb.
docstr_tok: ["Based","on","the","l0","budget","and","the","provided","allowable","perturbation","regions","we","iteratively","mark","regions","of","the","PE","file","for","modification","until","we","exhaust","our","budget",".",":","param","input_perturb_sizes",":","The","size","of","the","regions","we","can","perturb",".",":","param","input_perturbation_size",":","The","total","amount","of","perturbation","allowed","on","a","specific","sample",".",":","param","automatically_append",":","If","we","want","to","automatically","append","unused","perturbation","on","the","end","of","the","malware",".",":","return","perturbation_size",":","Remaining","perturbation","(","if","any",")",":","return","perturb_sizes",":","Potentially","adjusted","sizes","of","the","locations","in","the","PE","file","we","can","perturb","."]
code: def compute_perturbation_regions(
      self,
      input_perturbation_size: np.ndarray,
      input_perturb_sizes: List[List[int]],
      automatically_append: bool,
  ) -> Tuple[np.ndarray, List[List[int]]]:
      """
      Based on the l0 budget and the provided allowable perturbation regions we iteratively mark regions of the PE
      file for modification until we exhaust our budget.
  
      :param input_perturb_sizes: The size of the regions we can perturb.
      :param input_perturbation_size: The total amount of perturbation allowed on a specific sample.
      :param automatically_append: If we want to automatically append unused perturbation on the end of the malware.
      :return perturbation_size: Remaining perturbation (if any)
      :return perturb_sizes: Potentially adjusted sizes of the locations in the PE file we can perturb.
      """
      perturb_sizes = input_perturb_sizes.copy()
      perturbation_size = input_perturbation_size.copy()
  
      # reduce the perturbation we add at the end if we have perturbation to add in the malware itself and reduce the
      # sizes given in input_perturb_sizes if it exceeds the total input_perturbation_size
      for i, section_sizes in enumerate(perturb_sizes):
          for j, size in enumerate(section_sizes):
              if perturbation_size[i] - size >= 0:
                  logger.info(
                      "on sample %d allocate %d in perturb region",
                      i,
                      size,
                  )
                  perturbation_size[i] = perturbation_size[i] - size
              else:  # run out of l0 budget.
                  excess = np.abs(
                      perturbation_size[i] - size
                  )  # amount of overspill
                  perturbation_size[i] = perturbation_size[i] - size
                  section_sizes[j] = size - excess
                  # update the perturb sizes
  
                  logger.info(
                      "on sample %d ran out of l0, update to %d from %d",
                      i,
                      section_sizes[j],
                      size,
                  )
  
                  perturb_sizes[i] = section_sizes
                  perturbation_size[i] = 0
      perturbation_size = np.where(
          perturbation_size < 0, 0, perturbation_size
      )
  
      if not automatically_append:
          # if we do not want to automatically append then set the remaining perturbation to 0
          perturbation_size = np.zeros_like(perturbation_size)
          # total_perturbation is now sample dependant so reassign.
          total_perturbation = np.zeros_like(perturbation_size)
          for i in range(len(perturbation_size)):
              total_perturbation[i] = np.sum(perturb_sizes[i])
          self.total_perturbation = total_perturbation
      return perturbation_size, perturb_sizes
  
imports: import json
  import random
  import logging
  from typing import Optional, Union, Tuple, List, Dict, TYPE_CHECKING
  from tqdm.auto import trange
  import numpy
  from art.estimators.estimator import BaseEstimator, NeuralNetworkMixin
  from art.estimators.classification.classifier import ClassifierMixin
  from art.attacks.attack import EvasionAttack
label_desc: Use image node_id 9 for calling the MalwareGDTensorFlow obj's underlying member method code with example usage: obj.compute_perturbation_regions(input_perturbation_size, input_perturb_sizes, automatically_append) and returns: perturbation_size,  perturb_sizes